DYTSrouce/src/ui/Panel/SurfacePanel.cpp
2025-11-15 20:47:53 +08:00

668 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ui/Panel/SurfacePanel.h"
#include "ui/DockWidget.h"
#include "ui/DockTitleBar.h"
#include "common/SpdLogger.h"
#include <QHBoxLayout>
#include <QFileInfo>
#include <QMessageBox>
#include <Q3DCamera>
SurfacePanel::SurfacePanel(int index, const QString& filePath, QWidget* parent)
: DataPanel(index, FileEntryType::Surface, filePath, parent)
{
m_iMinX = 0; m_iMaxX = 0;
m_iMinY = 0; m_iMaxY = 0;
m_iMinZ = 0; m_iMaxZ = 0;
m_surfaceContainer = nullptr;
m_surface = nullptr;
m_p3DXAxis = nullptr;
m_p3DYAxis = nullptr;
m_p3DZAxis = nullptr;
m_pSeries = nullptr;
m_countX = 0;
m_countY = 0;
m_countZ = 0;
m_title = "";
m_xTitle = "";
m_yTitle = "";
m_zTitle = "";
m_time = -1.0;
m_thread = nullptr;
m_mutex = nullptr;
LOG_INFO("Created SurfacePanel {} for file: {}", index, filePath.toStdString());
}
SurfacePanel::SurfacePanel(int index, std::shared_ptr<FileEntrySurface> fileEntry, QWidget* parent)
: DataPanel(index, fileEntry, parent)
{
m_iMinX = 0; m_iMaxX = 0;
m_iMinY = 0; m_iMaxY = 0;
m_iMinZ = 0; m_iMaxZ = 0;
m_surfaceContainer = nullptr;
m_surface = nullptr;
m_p3DXAxis = nullptr;
m_p3DYAxis = nullptr;
m_p3DZAxis = nullptr;
m_pSeries = nullptr;
m_countX = 0;
m_countY = 0;
m_countZ = 0;
m_title = "";
m_xTitle = "";
m_yTitle = "";
m_zTitle = "";
m_time = -1.0;
m_thread = nullptr;
m_mutex = nullptr;
if (fileEntry) {
LOG_INFO("Created SurfacePanel {} for chart: {}", index, fileEntry->GetName().toStdString());
// Override the title with chart name
title_ = QString("Surface Panel %1 - %2").arg(index).arg(fileEntry->GetName());
}
else {
LOG_WARN("Created SurfacePanel {} with null chart data", index);
}
}
SurfacePanel::~SurfacePanel()
{
LOG_INFO("Destroyed SurfacePanel {}", GetIndex());
if (m_pSeries)
{
m_surface->removeSeries(m_pSeries);
m_pSeries->deleteLater();
m_pSeries = nullptr;
}
if (m_surface)
{
m_surface->deleteLater();
m_surface = nullptr;
}
if (m_surfaceContainer)
{
m_surfaceContainer->deleteLater();
m_surfaceContainer = nullptr;
}
if (auto* layout = qobject_cast<QHBoxLayout*>(this->layout()))
{
while (layout->count() > 0)
{
QLayoutItem* item = layout->takeAt(0);
if (item)
{
delete item;
}
}
}
if (m_mutex)
{
delete m_mutex;
}
if (m_thread)
{
m_thread->requestExit();
m_thread->wait();
m_thread->deleteLater();
m_thread = nullptr;
}
}
void SurfacePanel::RefreshPanel()
{
// Implement curve-specific refresh logic here
DataPanel::RefreshPanel();
if (auto fileEntry = fileEntry_->AsSurface()) {
OnDataPanelUpdated(fileEntry);
}
LOG_INFO("Refreshed TablePanel {}", GetIndex());
}
void SurfacePanel::InitUI()
{
createSurface();
QHBoxLayout* mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(m_surfaceContainer);
setLayout(mainLayout);
m_mutex = new QMutex;
}
QString SurfacePanel::GetTypeDisplayName() const
{
return "Surface";
}
void SurfacePanel::OnDataPanelUpdated(FileEntrySurface* fileEntry)
{
if (!m_surfaceContainer)
{
createSurface();
}
QString strName = fileEntry->GetName();
updateTitle(strName);
FileEntrySurface::ChartProperties propChart = fileEntry->GetChartProperties();
updateTitleAxis(propChart.xTitle, propChart.yTitle, propChart.zTitle);
updateMinMaxX(propChart.xMin, propChart.xMax, propChart.xCount);
updateMinMaxY(propChart.yMin, propChart.yMax, propChart.yCount);
updateMinMaxZ(propChart.zMin, propChart.zMax, propChart.zCount);
QString strFile = fileEntry->GetPath() + "/" + fileEntry->GetFileName();
FileEntrySurface::SurfaceProperties listCurve = fileEntry->GetSurfaceProperties();
updateParseFile(strFile, propChart.timeParam, listCurve);
}
void SurfacePanel::OnTimeChanged(double time)
{
m_time = time;
if (m_surface)
{
QMutexLocker locker(m_mutex);
if (m_data.size() > 0)
{
m_pSeries->dataProxy()->resetArray(nullptr);
QMap< double, QMap< int, QVector< QVector<QVector3D> > > >::const_iterator ite = m_data.lowerBound(time);
if (ite == m_data.end())
{
ite--;
}
QMap< int, QVector< QVector<QVector3D> > > mapData = ite.value();
for (QMap< int, QVector< QVector<QVector3D> > >::Iterator it = mapData.begin(); it != mapData.end(); it++)
{
int nIndex = it.key();
QVector< QVector<QVector3D> > listRowData = it.value();
QSurfaceDataArray* data = new QSurfaceDataArray;
for (int nI = 0; nI < listRowData.size(); nI++)
{
QSurfaceDataRow* dataRow = new QSurfaceDataRow;
QVector<QVector3D> listColData = listRowData[nI];
for (int nJ = 0; nJ < listColData.size(); nJ++)
{
QVector3D v3d = listColData[nJ];
*dataRow << v3d;
}
*data << dataRow;
}
m_pSeries->dataProxy()->resetArray(data);
}
}
m_surface->setShadowQuality(QAbstract3DGraph::ShadowQuality::ShadowQualityNone);
}
}
void SurfacePanel::updateTitle(const QString & title)
{
if (nullptr != dockWidget_)
{
m_title = title;
dockWidget_->setWindowTitle(title);
disconnect(dockWidget_, &QDockWidget::visibilityChanged,
this, &SurfacePanel::onVisibilityChanged);
connect(dockWidget_, &QDockWidget::visibilityChanged,
this, &SurfacePanel::onVisibilityChanged);
}
}
void SurfacePanel::updateTitleAxis(const QString & xTitle, const QString & yTitle, const QString & zTitle)
{
m_xTitle = xTitle;
m_yTitle = yTitle;
m_zTitle = zTitle;
m_p3DXAxis->setTitle(xTitle);
m_p3DXAxis->setTitleVisible(true);
m_p3DYAxis->setTitle(yTitle);
m_p3DYAxis->setTitleVisible(true);
m_p3DZAxis->setTitle(zTitle);
m_p3DZAxis->setTitleVisible(true);
}
void SurfacePanel::updateMinMaxX(float min, float max, int count)
{
if (max > min)
{
m_iMinX = min;
m_iMaxX = max;
if (count > 0)
{
m_countX = count;
m_p3DXAxis->setSegmentCount(count);
}
m_p3DXAxis->setRange(min, max);
}
}
void SurfacePanel::updateMinMaxY(float min, float max, int count)
{
if (max > min)
{
m_iMinY = min;
m_iMaxY = max;
if (count > 0)
{
m_countY = count;
m_p3DYAxis->setSegmentCount(count);
}
m_p3DYAxis->setRange(min, max);
}
}
void SurfacePanel::updateMinMaxZ(float min, float max, int count)
{
if (max > min)
{
m_iMinZ = min;
m_iMaxZ = max;
if (count > 0)
{
m_countZ = count;
m_p3DZAxis->setSegmentCount(count);
}
m_p3DZAxis->setRange(min, max);
}
}
void SurfacePanel::updateParseFile(const QString & strFile, int nT, FileEntrySurface::SurfaceProperties listCurve)
{
if (strFile.isEmpty())
{
QMessageBox::information(nullptr, QString::fromLocal8Bit("<EFBFBD><EFBFBD>ʾ"), QString::fromLocal8Bit("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD>"));
return;
}
{
QMutexLocker locker(m_mutex);
m_data.clear();
m_pSeries->dataProxy()->resetArray(nullptr);
}
for (int nI = 0; nI < listCurve.size(); nI++)
{
FileEntrySurface::SurfaceProperty surface = listCurve.at(nI);
m_color = surface.color;
QLinearGradient gr;
gr.setColorAt(0.0, surface.color);
gr.setColorAt(0.5, Qt::yellow);
gr.setColorAt(0.8, Qt::red);
gr.setColorAt(1.0, Qt::darkRed);
m_pSeries->setBaseGradient(gr);
m_pSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
//m_pSeries->setSingleHighlightColor(Qt::green);
}
if (m_thread)
{
m_thread->requestExit();
m_thread->wait();
m_thread->deleteLater();
m_thread = nullptr;
}
m_thread = new LoadDataThread(this, strFile, nT, listCurve);
connect(m_thread, &LoadDataThread::signalBeginLoadData,
this, &SurfacePanel::slotBeginLoadData);
connect(m_thread, &LoadDataThread::signalEndLoadData,
this, &SurfacePanel::slotEndLoadData);
m_thread->setMutex(m_mutex);
m_thread->start();
FinalParseFile();
}
void SurfacePanel::onVisibilityChanged(bool visible)
{
if (visible)
{
if (!m_surfaceContainer)
{
createSurface();
updateTitleAxis(m_xTitle, m_yTitle, m_zTitle);
if (m_iMaxX == m_iMinX)
{
m_p3DXAxis->setAutoAdjustRange(true);
}
else
{
updateMinMaxX(m_iMinX, m_iMaxX, m_countX);
}
if (m_iMaxZ == m_iMinZ)
{
m_p3DZAxis->setAutoAdjustRange(true);
}
else
{
updateMinMaxZ(m_iMinZ, m_iMaxZ, m_countZ);
}
if (m_iMaxY == m_iMinY)
{
m_p3DYAxis->setAutoAdjustRange(true);
}
else
{
updateMinMaxY(m_iMaxY, m_iMinY, m_countY);
}
{
QLinearGradient gr;
gr.setColorAt(0.0, m_color);
gr.setColorAt(0.5, Qt::yellow);
gr.setColorAt(0.8, Qt::red);
gr.setColorAt(1.0, Qt::darkRed);
m_pSeries->setBaseGradient(gr);
m_pSeries->setColorStyle(Q3DTheme::ColorStyleRangeGradient);
}
m_surface->setHorizontalAspectRatio(1.0);
QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(this->layout());
if (layout)
{
layout->addWidget(m_surfaceContainer);
}
if (m_time > -1.0)
{
OnTimeChanged(m_time);
}
}
}
else
{
if (m_pSeries)
{
m_surface->removeSeries(m_pSeries);
m_pSeries->deleteLater();
m_pSeries = nullptr;
}
if (m_surface)
{
m_surface->deleteLater();
m_surface = nullptr;
}
if (m_surfaceContainer)
{
m_surfaceContainer->deleteLater();
m_surfaceContainer = nullptr;
}
if (auto* layout = qobject_cast<QHBoxLayout*>(this->layout()))
{
while (layout->count() > 0)
{
QLayoutItem* item = layout->takeAt(0);
if (item)
{
delete item;
}
}
}
}
}
void SurfacePanel::createSurface()
{
m_surface = new Q3DSurface();
m_surface->setFlags(m_surface->flags());
m_surface->setFlipHorizontalGrid(false);
m_p3DXAxis = new QValue3DAxis;
m_p3DXAxis->setSegmentCount(10);
m_p3DXAxis->setRange(-10, 10);
m_p3DYAxis = new QValue3DAxis;
m_p3DYAxis->setSegmentCount(10);
m_p3DYAxis->setRange(-10, 10);
m_p3DZAxis = new QValue3DAxis;
m_p3DZAxis->setSegmentCount(10);
m_p3DZAxis->setRange(-10, 10);
m_surface->setAxisX(m_p3DXAxis);
m_surface->setAxisY(m_p3DYAxis);
m_surface->setAxisZ(m_p3DZAxis);
m_surface->activeTheme()->setType(Q3DTheme::Theme(2));
m_pSeries = new QSurface3DSeries;
m_pSeries->setDrawMode(QSurface3DSeries::DrawSurface);
m_surface->addSeries(m_pSeries);
m_surfaceContainer = QWidget::createWindowContainer(m_surface);
m_surfaceContainer->setAutoFillBackground(true);
m_surfaceContainer->setAttribute(Qt::WA_OpaquePaintEvent, true);
m_surfaceContainer->setAttribute(Qt::WA_NoSystemBackground, false);
m_surfaceContainer->setUpdatesEnabled(true);
m_surfaceContainer->setMinimumHeight(100);
m_pSeries->setBaseColor(Qt::green);
m_pSeries->setColorStyle(Q3DTheme::ColorStyleUniform);
m_pSeries->setSingleHighlightColor(Qt::green);
m_pSeries->setMeshSmooth(false);
m_pSeries->setFlatShadingEnabled(false);
m_surface->scene()->activeCamera()->setCameraPreset(Q3DCamera::CameraPreset(13));
}
void SurfacePanel::slotBeginLoadData()
{
if (nullptr != dockWidget_)
{
QString title = m_title + " -- " + QString(tr("Begin LoadData"));
dockWidget_->setWindowTitle(title);
}
}
void SurfacePanel::slotEndLoadData()
{
if (nullptr != dockWidget_)
{
dockWidget_->setWindowTitle(m_title);
}
}
void SurfacePanel::FinalParseFile()
{
if (m_iMaxX == m_iMinX)
{
m_p3DXAxis->setAutoAdjustRange(true);
}
if (m_iMaxZ == m_iMinZ)
{
m_p3DZAxis->setAutoAdjustRange(true);
}
if (m_iMaxY == m_iMinY)
{
m_p3DYAxis->setAutoAdjustRange(true);
}
m_surface->setHorizontalAspectRatio(1.0);
}
LoadDataThread::LoadDataThread(SurfacePanel *panel, QString file, int nT, FileEntrySurface::SurfaceProperties listCurve)
{
m_panel = panel;
m_file = file;
m_nT = nT;
m_listCurve = listCurve;
m_exit = false;
}
void LoadDataThread::run()
{
QFile file(m_file);
if (file.open(QIODevice::ReadOnly))
{
emit signalBeginLoadData();
while (!file.atEnd() && !m_exit)
{
QString strLine = file.readLine().simplified();
if (!strLine.isEmpty())
{
QStringList listLine = strLine.split(" ");
double t = listLine.at(m_nT).toDouble();
QMap< int, QVector< QVector<QVector3D> > > mapData;
for (int nI = 0; nI < m_listCurve.size(); nI++)
{
if (m_exit)
{
break;
}
FileEntrySurface::SurfaceProperty surface = m_listCurve.at(nI);
int nStart = surface.start;
int nStop = surface.stop;
if (nStart == 0)
{
nStart = 1;
}
if (nStop == 0)
{
nStop = listLine.size();
}
QString strX = surface.x;
QString strY = surface.y;
QString strZ = surface.z;
double xInput = 0;
double yInput = 0;
double zInput = 0.0;
QVector< QVector<QVector3D> > listRowData;
int nRow = 0;
int nCol = 0;
for (int nJ = nStart; nJ < nStop; nJ += 3)
{
if (m_exit)
{
break;
}
int x = listLine.at(nJ).toDouble();
int y = listLine.at(nJ + 1).toDouble();
double z = listLine.at(nJ + 2).toDouble();
if (strX == "x")
{
xInput = x;
}
else if (strX == "y")
{
xInput = y;
}
else if (strX == "z")
{
xInput = z;
}
if (strY == "x")
{
yInput = x;
}
else if (strY == "y")
{
yInput = y;
}
else if (strY == "z")
{
yInput = z;
}
if (strZ == "x")
{
zInput = x;
}
else if (strZ == "y")
{
zInput = y;
}
else if (strZ == "z")
{
zInput = z;
}
QVector3D v3d = QVector3D(xInput, yInput, zInput);
if (nRow == x)
{
int nIndex = listRowData.size() - 1;
QVector<QVector3D> listColData = listRowData[nIndex];
listColData.push_back(v3d);
listRowData.replace(nIndex, listColData);
}
else
{
QVector<QVector3D> listColData;
listColData.push_back(v3d);
listRowData.push_back(listColData);
}
nRow = x;
nCol = y;
}
mapData.insert(nI, listRowData);
}
{
QMutexLocker locker(m_mutex);
m_panel->m_data.insert(t, mapData);
}
}
}
file.close();
emit signalEndLoadData();
}
}