DYTSrouce/src/ui/Panel/SurfacePanel.cpp

668 lines
14 KiB
C++
Raw Normal View History

2025-10-27 12:39:49 +00:00
#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)
2025-10-27 14:09:22 +00:00
: DataPanel(index, FileEntryType::Surface, filePath, parent)
2025-10-27 12:39:49 +00:00
{
m_iMinX = 0; m_iMaxX = 0;
m_iMinY = 0; m_iMaxY = 0;
m_iMinZ = 0; m_iMaxZ = 0;
2025-11-11 09:44:56 +00:00
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;
2025-11-15 12:47:53 +00:00
m_title = "";
2025-11-11 09:44:56 +00:00
m_xTitle = "";
m_yTitle = "";
m_zTitle = "";
m_time = -1.0;
m_thread = nullptr;
2025-11-15 12:47:53 +00:00
m_mutex = nullptr;
2025-11-11 09:44:56 +00:00
2025-10-27 12:39:49 +00:00
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;
2025-11-11 09:44:56 +00:00
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;
2025-11-15 12:47:53 +00:00
m_title = "";
2025-11-11 09:44:56 +00:00
m_xTitle = "";
m_yTitle = "";
m_zTitle = "";
m_time = -1.0;
m_thread = nullptr;
2025-11-15 12:47:53 +00:00
m_mutex = nullptr;
2025-11-11 09:44:56 +00:00
2025-10-27 12:39:49 +00:00
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());
2025-11-11 09:44:56 +00:00
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;
}
2025-10-27 12:39:49 +00:00
}
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()
{
2025-11-11 09:44:56 +00:00
createSurface();
2025-10-27 12:39:49 +00:00
QHBoxLayout* mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
2025-11-11 09:44:56 +00:00
mainLayout->addWidget(m_surfaceContainer);
2025-10-27 12:39:49 +00:00
setLayout(mainLayout);
2025-11-11 09:44:56 +00:00
m_mutex = new QMutex;
2025-10-27 12:39:49 +00:00
}
QString SurfacePanel::GetTypeDisplayName() const
{
return "Surface";
}
void SurfacePanel::OnDataPanelUpdated(FileEntrySurface* fileEntry)
{
2025-11-15 12:47:53 +00:00
if (!m_surfaceContainer)
{
createSurface();
}
2025-10-27 12:39:49 +00:00
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)
{
2025-11-11 09:44:56 +00:00
m_time = time;
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
if (m_surface)
{
QMutexLocker locker(m_mutex);
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
if (m_data.size() > 0)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
m_pSeries->dataProxy()->resetArray(nullptr);
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
QMap< double, QMap< int, QVector< QVector<QVector3D> > > >::const_iterator ite = m_data.lowerBound(time);
if (ite == m_data.end())
{
ite--;
}
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
QMap< int, QVector< QVector<QVector3D> > > mapData = ite.value();
for (QMap< int, QVector< QVector<QVector3D> > >::Iterator it = mapData.begin(); it != mapData.end(); it++)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
int nIndex = it.key();
QVector< QVector<QVector3D> > listRowData = it.value();
QSurfaceDataArray* data = new QSurfaceDataArray;
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
for (int nI = 0; nI < listRowData.size(); nI++)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
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;
2025-10-27 12:39:49 +00:00
}
2025-11-11 09:44:56 +00:00
m_pSeries->dataProxy()->resetArray(data);
2025-10-27 12:39:49 +00:00
}
}
2025-11-11 09:44:56 +00:00
m_surface->setShadowQuality(QAbstract3DGraph::ShadowQuality::ShadowQualityNone);
}
2025-10-27 12:39:49 +00:00
}
void SurfacePanel::updateTitle(const QString & title)
{
if (nullptr != dockWidget_)
{
2025-11-15 12:47:53 +00:00
m_title = title;
2025-10-27 12:39:49 +00:00
dockWidget_->setWindowTitle(title);
2025-11-11 09:44:56 +00:00
2025-11-15 12:47:53 +00:00
disconnect(dockWidget_, &QDockWidget::visibilityChanged,
this, &SurfacePanel::onVisibilityChanged);
2025-11-11 09:44:56 +00:00
connect(dockWidget_, &QDockWidget::visibilityChanged,
this, &SurfacePanel::onVisibilityChanged);
2025-10-27 12:39:49 +00:00
}
}
void SurfacePanel::updateTitleAxis(const QString & xTitle, const QString & yTitle, const QString & zTitle)
{
2025-11-11 09:44:56 +00:00
m_xTitle = xTitle;
m_yTitle = yTitle;
m_zTitle = zTitle;
2025-10-27 12:39:49 +00:00
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)
{
2025-11-11 09:44:56 +00:00
m_countX = count;
2025-10-27 12:39:49 +00:00
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)
{
2025-11-11 09:44:56 +00:00
m_countY = count;
2025-10-27 12:39:49 +00:00
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)
{
2025-11-11 09:44:56 +00:00
m_countZ = count;
2025-10-27 12:39:49 +00:00
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;
}
2025-11-11 09:44:56 +00:00
{
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);
2025-11-02 03:36:10 +00:00
2025-11-11 09:44:56 +00:00
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);
2025-11-15 12:47:53 +00:00
connect(m_thread, &LoadDataThread::signalBeginLoadData,
this, &SurfacePanel::slotBeginLoadData);
connect(m_thread, &LoadDataThread::signalEndLoadData,
this, &SurfacePanel::slotEndLoadData);
2025-11-11 09:44:56 +00:00
m_thread->setMutex(m_mutex);
m_thread->start();
FinalParseFile();
}
void SurfacePanel::onVisibilityChanged(bool visible)
{
if (visible)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
if (!m_surfaceContainer)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
createSurface();
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
updateTitleAxis(m_xTitle, m_yTitle, m_zTitle);
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
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);
}
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
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)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
m_surface->deleteLater();
m_surface = nullptr;
2025-10-27 12:39:49 +00:00
}
2025-11-11 09:44:56 +00:00
if (m_surfaceContainer)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
m_surfaceContainer->deleteLater();
m_surfaceContainer = nullptr;
2025-10-27 12:39:49 +00:00
}
2025-11-11 09:44:56 +00:00
if (auto* layout = qobject_cast<QHBoxLayout*>(this->layout()))
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
while (layout->count() > 0)
{
QLayoutItem* item = layout->takeAt(0);
if (item)
{
delete item;
}
}
2025-10-27 12:39:49 +00:00
}
2025-11-11 09:44:56 +00:00
}
}
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);
2025-10-27 12:39:49 +00:00
2025-11-11 09:44:56 +00:00
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));
}
2025-11-15 12:47:53 +00:00
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);
}
}
2025-11-11 09:44:56 +00:00
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))
{
2025-11-15 12:47:53 +00:00
emit signalBeginLoadData();
2025-11-11 09:44:56 +00:00
while (!file.atEnd() && !m_exit)
2025-10-27 12:39:49 +00:00
{
QString strLine = file.readLine().simplified();
if (!strLine.isEmpty())
{
QStringList listLine = strLine.split(" ");
2025-11-11 09:44:56 +00:00
double t = listLine.at(m_nT).toDouble();
2025-10-27 12:39:49 +00:00
QMap< int, QVector< QVector<QVector3D> > > mapData;
2025-11-11 09:44:56 +00:00
for (int nI = 0; nI < m_listCurve.size(); nI++)
2025-10-27 12:39:49 +00:00
{
2025-11-11 09:44:56 +00:00
if (m_exit)
{
break;
}
FileEntrySurface::SurfaceProperty surface = m_listCurve.at(nI);
2025-10-27 12:39:49 +00:00
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)
{
2025-11-11 09:44:56 +00:00
if (m_exit)
{
break;
}
2025-10-27 12:39:49 +00:00
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);
}
2025-11-11 09:44:56 +00:00
{
QMutexLocker locker(m_mutex);
m_panel->m_data.insert(t, mapData);
}
}
2025-10-27 12:39:49 +00:00
}
file.close();
2025-11-15 12:47:53 +00:00
emit signalEndLoadData();
2025-10-27 12:39:49 +00:00
}
}