修改三维显示初级粒子计数和次级粒子计数问题,修复能量刻度加载时问题,修复软件标题栏问题
This commit is contained in:
parent
a72dbeebbe
commit
4291065053
|
|
@ -69,6 +69,7 @@ void EnergyScaleForm::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data
|
|||
QString baseName =QString("[%1]%2").arg(dir.dirName()).arg(fileInfo.baseName());
|
||||
ui->lineEdit_name->setText(baseName);
|
||||
ui->lineEdit_name->setReadOnly(true);
|
||||
ui->groupBox_2->hide();
|
||||
ui->pBtn_SaveAs->setText(QStringLiteral(u"保存到系统"));
|
||||
m_currentFilePath = data_filename;
|
||||
QString errorMsg;
|
||||
|
|
@ -970,7 +971,7 @@ void EnergyScaleForm::on_pBtn_SaveAs_clicked()
|
|||
systemEnble = false;
|
||||
// 选择保存路径
|
||||
QString defaultDir = QDir(qApp->applicationDirPath()).filePath("configure/EnergyScale");
|
||||
QString targetFilePath = QFileDialog::getSaveFileName(this,
|
||||
targetFilePath = QFileDialog::getSaveFileName(this,
|
||||
"另存为能量刻度文件",
|
||||
defaultDir,
|
||||
"JSON文件 (*.json);;所有文件 (*.*)");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QDir>
|
||||
#include <QList>
|
||||
#include "DeviceParamsSaveToSysDlg.h"
|
||||
|
||||
static QStringList s_addr_count_list { "256", "512", "1024", "2048", "4096", "8192", "16384" };
|
||||
|
|
@ -386,12 +387,17 @@ void DeviceParamsTableForm::onCfgChannelSelectBtnClicked()
|
|||
int num_columns = std::sqrt(32);
|
||||
if (num_columns == 0)
|
||||
num_columns = 1;
|
||||
|
||||
QList<QCheckBox*> all_checkboxes;
|
||||
|
||||
QVBoxLayout* checkbox_layout = new QVBoxLayout();
|
||||
QHBoxLayout* checkbox_column_layout = new QHBoxLayout();
|
||||
for (int row = 0; row < 32; ++row) {
|
||||
QCheckBox* check_box = new QCheckBox(QStringLiteral(u"通道%1").arg(row + 1));
|
||||
check_box->setChecked(!ui->params_cfg_table->isRowHidden(row));
|
||||
checkbox_column_layout->addWidget(check_box);
|
||||
all_checkboxes.append(check_box);
|
||||
|
||||
connect(check_box, &QCheckBox::stateChanged, [this, row](int state) {
|
||||
ui->params_cfg_table->setRowHidden(row, state == Qt::Unchecked);
|
||||
});
|
||||
|
|
@ -407,16 +413,18 @@ void DeviceParamsTableForm::onCfgChannelSelectBtnClicked()
|
|||
// 全选和反选
|
||||
QHBoxLayout* button_layout = new QHBoxLayout();
|
||||
QPushButton* btn_all_select = new QPushButton(QString(QStringLiteral(u"全选")));
|
||||
connect(btn_all_select, &QPushButton::clicked, [this]() {
|
||||
connect(btn_all_select, &QPushButton::clicked, [this, all_checkboxes]() {
|
||||
for (int row = 0; row < 32; ++row) {
|
||||
ui->params_cfg_table->setRowHidden(row, true);
|
||||
ui->params_cfg_table->setRowHidden(row, false);
|
||||
all_checkboxes[row]->setChecked(true);
|
||||
}
|
||||
});
|
||||
button_layout->addWidget(btn_all_select);
|
||||
QPushButton* btn_reserve_select = new QPushButton(QString(QStringLiteral(u"反选")));
|
||||
connect(btn_reserve_select, &QPushButton::clicked, [this]() {
|
||||
connect(btn_reserve_select, &QPushButton::clicked, [this, all_checkboxes]() {
|
||||
for (int row = 0; row < 32; ++row) {
|
||||
ui->params_cfg_table->setRowHidden(row, !ui->params_cfg_table->isRowHidden(row));
|
||||
all_checkboxes[row]->setChecked(!all_checkboxes[row]->isChecked());
|
||||
}
|
||||
});
|
||||
button_layout->addWidget(btn_reserve_select);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@
|
|||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include "DataProcessWorkPool.h"
|
||||
#include "GlobalDefine.h"
|
||||
NewMeasureAnalysisDlg::NewMeasureAnalysisDlg(QWidget *parent)
|
||||
|
|
@ -33,7 +36,9 @@ NewMeasureAnalysisDlg::~NewMeasureAnalysisDlg()
|
|||
void NewMeasureAnalysisDlg::initialization()
|
||||
{
|
||||
ui->progressBar->setVisible(false);
|
||||
|
||||
ui->comboBox_measure_param->addItem(QStringLiteral(u"无"));
|
||||
ui->comboBox_energy_scale->addItem(QStringLiteral(u"无"));
|
||||
ui->comboBox_efficiency_scale->addItem(QStringLiteral(u"无"));
|
||||
QRegExp rx(R"(^[^\\/:*?"<>|]+$)");
|
||||
QValidator *validator = new QRegExpValidator(rx, this);
|
||||
ui->lineEdit_name->setValidator(validator);
|
||||
|
|
@ -173,7 +178,8 @@ void NewMeasureAnalysisDlg::newProject(const QString& particle_data_filename)
|
|||
QString project_energy_scale_filename = QDir(project_dir_path).filePath(QStringLiteral(u"能量刻度.json"));
|
||||
QFileInfo energy_scale_file_info(energy_scale_filename);
|
||||
if (energy_scale_file_info.exists()) {
|
||||
QFile::copy(energy_scale_filename, project_energy_scale_filename);
|
||||
readJsonAsSave(energy_scale_filename,project_energy_scale_filename);
|
||||
// QFile::copy(energy_scale_filename, project_energy_scale_filename);
|
||||
}
|
||||
|
||||
bool is_measure_complete = !particle_data_filename.isEmpty();
|
||||
|
|
@ -346,3 +352,39 @@ void NewMeasureAnalysisDlg::startParticleSortTask(const QString& data_file_path,
|
|||
separate_task->SetFinishedNotifier(this, "onNewProjectFromFileFinished", project_name);
|
||||
separate_task->StartTask();
|
||||
}
|
||||
|
||||
void NewMeasureAnalysisDlg::readJsonAsSave(QString sourceFile, QString targetFile)
|
||||
{
|
||||
QFile file(sourceFile);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qDebug() << "无法打开文件:" << sourceFile;
|
||||
return ;
|
||||
}
|
||||
|
||||
QByteArray jsonData = file.readAll();
|
||||
file.close();
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
return ;
|
||||
}
|
||||
|
||||
QJsonObject rootObj = doc.object();
|
||||
|
||||
if (rootObj.contains("Remark")) {
|
||||
rootObj.remove("Remark");
|
||||
|
||||
}
|
||||
|
||||
QJsonDocument newDoc(rootObj);
|
||||
|
||||
QFile saveFile(targetFile);
|
||||
if (saveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
// 格式化输出,方便阅读
|
||||
saveFile.write(newDoc.toJson(QJsonDocument::Indented));
|
||||
saveFile.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ private:
|
|||
void startParticleSortTask(const QString& data_file_path,
|
||||
const QString& project_name,
|
||||
const QString& project_dir_path);
|
||||
void readJsonAsSave(QString sourceFile,QString targetFile);
|
||||
private slots:
|
||||
void onNewProjectFromFileFinished(bool ok, const QString& project_name, const QVariant &data);
|
||||
void on_btn_ok_clicked();
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>550</width>
|
||||
<height>278</height>
|
||||
<width>631</width>
|
||||
<height>314</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
|
|||
14
src/RegionOfInterest/RegionOfInterest.cpp
Normal file
14
src/RegionOfInterest/RegionOfInterest.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "RegionOfInterest.h"
|
||||
#include "ui_RegionOfInterest.h"
|
||||
|
||||
RegionOfInterest::RegionOfInterest(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::RegionOfInterest)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
RegionOfInterest::~RegionOfInterest()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
22
src/RegionOfInterest/RegionOfInterest.h
Normal file
22
src/RegionOfInterest/RegionOfInterest.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef REGIONOFINTEREST_H
|
||||
#define REGIONOFINTEREST_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class RegionOfInterest;
|
||||
}
|
||||
|
||||
class RegionOfInterest : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RegionOfInterest(QWidget *parent = nullptr);
|
||||
~RegionOfInterest();
|
||||
|
||||
private:
|
||||
Ui::RegionOfInterest *ui;
|
||||
};
|
||||
|
||||
#endif // REGIONOFINTEREST_H
|
||||
19
src/RegionOfInterest/RegionOfInterest.ui
Normal file
19
src/RegionOfInterest/RegionOfInterest.ui
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RegionOfInterest</class>
|
||||
<widget class="QWidget" name="RegionOfInterest">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>711</width>
|
||||
<height>505</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -38,7 +38,6 @@ QJsonObject ConformityHistoryItem::toJson() const
|
|||
obj["secondaryEnergyStart"] = secondaryEnergyStart;
|
||||
obj["secondaryEnergyEnd"] = secondaryEnergyEnd;
|
||||
|
||||
// ✅ 修复致命BUG:不再无限递归嵌套
|
||||
QJsonArray boardChannelJson;
|
||||
for (int board = 0; board < MAX_BOARD; ++board) {
|
||||
QJsonArray channelJson;
|
||||
|
|
@ -55,6 +54,24 @@ QJsonObject ConformityHistoryItem::toJson() const
|
|||
}
|
||||
obj["firstParticleData"] = firstParticleJson;
|
||||
|
||||
QJsonArray matrixJson;
|
||||
for (int pBoard = 0; pBoard < MAX_BOARD; ++pBoard) {
|
||||
QJsonArray pChannelArray;
|
||||
for (int pChannel = 0; pChannel < MAX_CHANNEL; ++pChannel) {
|
||||
QJsonArray sBoardArray;
|
||||
for (int sBoard = 0; sBoard < MAX_BOARD; ++sBoard) {
|
||||
QJsonArray sChannelArray;
|
||||
for (int sChannel = 0; sChannel < MAX_CHANNEL; ++sChannel) {
|
||||
sChannelArray.append(coincidenceMatrix[pBoard][pChannel][sBoard][sChannel]);
|
||||
}
|
||||
sBoardArray.append(sChannelArray);
|
||||
}
|
||||
pChannelArray.append(sBoardArray);
|
||||
}
|
||||
matrixJson.append(pChannelArray);
|
||||
}
|
||||
obj["coincidenceMatrix"] = matrixJson;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +87,7 @@ ConformityHistoryItem ConformityHistoryItem::fromJson(const QJsonObject& obj)
|
|||
item.secondaryEnergyStart = obj["secondaryEnergyStart"].toDouble();
|
||||
item.secondaryEnergyEnd = obj["secondaryEnergyEnd"].toDouble();
|
||||
|
||||
// 板卡通道数据
|
||||
memset(item.boardChannelData, 0, sizeof(item.boardChannelData));
|
||||
QJsonArray boardChannelJson = obj["boardChannelData"].toArray();
|
||||
for (int board = 0; board < MAX_BOARD && board < boardChannelJson.size(); ++board) {
|
||||
|
|
@ -79,12 +97,30 @@ ConformityHistoryItem ConformityHistoryItem::fromJson(const QJsonObject& obj)
|
|||
}
|
||||
}
|
||||
|
||||
// 初级粒子数据
|
||||
QJsonObject firstParticleJson = obj["firstParticleData"].toObject();
|
||||
for (const QString& key : firstParticleJson.keys()) {
|
||||
item.firstParticleData[key] = firstParticleJson[key].toInt();
|
||||
}
|
||||
|
||||
// 新增:符合矩阵数据
|
||||
memset(item.coincidenceMatrix, 0, sizeof(item.coincidenceMatrix));
|
||||
QJsonArray matrixJson = obj["coincidenceMatrix"].toArray();
|
||||
for (int pBoard = 0; pBoard < MAX_BOARD && pBoard < matrixJson.size(); ++pBoard) {
|
||||
QJsonArray pChannelArray = matrixJson[pBoard].toArray();
|
||||
for (int pChannel = 0; pChannel < MAX_CHANNEL && pChannel < pChannelArray.size(); ++pChannel) {
|
||||
QJsonArray sBoardArray = pChannelArray[pChannel].toArray();
|
||||
for (int sBoard = 0; sBoard < MAX_BOARD && sBoard < sBoardArray.size(); ++sBoard) {
|
||||
QJsonArray sChannelArray = sBoardArray[sBoard].toArray();
|
||||
for (int sChannel = 0; sChannel < MAX_CHANNEL && sChannel < sChannelArray.size(); ++sChannel) {
|
||||
item.coincidenceMatrix[pBoard][pChannel][sBoard][sChannel] = sChannelArray[sChannel].toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item.surfaceData.clear();
|
||||
item.channelSurfaceData.clear();
|
||||
return item;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +135,9 @@ ConformityCalculatedResult ConformityHistoryItem::toCalculatedResult() const
|
|||
result.secondaryEnergyStart = secondaryEnergyStart;
|
||||
result.secondaryEnergyEnd = secondaryEnergyEnd;
|
||||
memcpy(result.boardChannelData, boardChannelData, sizeof(boardChannelData));
|
||||
memcpy(result.coincidenceMatrix, coincidenceMatrix, sizeof(coincidenceMatrix));
|
||||
result.firstParticleData = firstParticleData;
|
||||
result.channelSurfaceData = channelSurfaceData;
|
||||
result.surfaceData = surfaceData;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -116,7 +154,9 @@ ConformityHistoryItem ConformityHistoryItem::fromCalculatedResult(const Conformi
|
|||
item.secondaryEnergyStart = result.secondaryEnergyStart;
|
||||
item.secondaryEnergyEnd = result.secondaryEnergyEnd;
|
||||
memcpy(item.boardChannelData, result.boardChannelData, sizeof(result.boardChannelData));
|
||||
memcpy(item.coincidenceMatrix, result.coincidenceMatrix, sizeof(result.coincidenceMatrix));
|
||||
item.firstParticleData = result.firstParticleData;
|
||||
item.channelSurfaceData = result.channelSurfaceData;
|
||||
item.surfaceData = result.surfaceData;
|
||||
return item;
|
||||
}
|
||||
|
|
@ -171,12 +211,47 @@ void ConformityAnalysis::InitViewWorkspace(const QString &project_name)
|
|||
|
||||
void ConformityAnalysis::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
|
||||
{
|
||||
if (data_files_set.isEmpty()) return;
|
||||
// if (data_files_set.isEmpty()) return;
|
||||
|
||||
// clearAllCachedData();
|
||||
// freeEventVector(_currentSpectrumData);
|
||||
// m_conformFileMap.clear();
|
||||
|
||||
// for (const QString& key : data_files_set.keys()) {
|
||||
// bool ok;
|
||||
// int cnt = key.toInt(&ok);
|
||||
// if (ok && cnt >=2 && cnt <=9) {
|
||||
// m_conformFileMap[cnt] = data_files_set[key].toString();
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (m_conformFileMap.isEmpty()) {
|
||||
// qWarning() << "[ConformityAnalysis] 未找到任何有效的符合数数据文件";
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (m_conformFileMap.contains(2)) {
|
||||
|
||||
// ConformityCalculatedResult result = streamParseAndCalculate(2, m_conformFileMap[2]);
|
||||
|
||||
// QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
// m_calculatedCache[2] = result;
|
||||
// cacheLocker.unlock();
|
||||
|
||||
// displayConformData(2);
|
||||
|
||||
// QMetaObject::invokeMethod(this, [=]() {
|
||||
// saveResultToHistory(result);
|
||||
// }, Qt::QueuedConnection);
|
||||
// }
|
||||
// m_isParsing = true;
|
||||
// parseAllConformDataInBackground();
|
||||
|
||||
if (data_files_set.isEmpty()) return;
|
||||
clearAllCachedData();
|
||||
freeEventVector(_currentSpectrumData);
|
||||
m_conformFileMap.clear();
|
||||
|
||||
// 构建符合数->文件路径映射
|
||||
for (const QString& key : data_files_set.keys()) {
|
||||
bool ok;
|
||||
int cnt = key.toInt(&ok);
|
||||
|
|
@ -190,22 +265,108 @@ void ConformityAnalysis::SetAnalyzeDataFilename(const QMap<QString, QVariant> &d
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_conformFileMap.contains(2)) {
|
||||
// 重新加载最新的历史数据
|
||||
loadHistoryFromFile();
|
||||
|
||||
ConformityCalculatedResult result = streamParseAndCalculate(2, m_conformFileMap[2]);
|
||||
// 检查每个文件是否需要重新解析
|
||||
QList<int> needParseConformCounts;
|
||||
QList<int> canUseHistoryConformCounts;
|
||||
|
||||
QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
m_calculatedCache[2] = result;
|
||||
cacheLocker.unlock();
|
||||
for (int conformCount : m_conformFileMap.keys()) {
|
||||
QString fileName = m_conformFileMap[conformCount];
|
||||
QFileInfo fileInfo(fileName);
|
||||
|
||||
displayConformData(2);
|
||||
// 查找对应的历史记录
|
||||
int historyIdx = findHistoryIndex(fileName, conformCount);
|
||||
|
||||
QMetaObject::invokeMethod(this, [=]() {
|
||||
saveResultToHistory(result);
|
||||
}, Qt::QueuedConnection);
|
||||
if (historyIdx >= 0 && fileInfo.exists()) {
|
||||
const ConformityHistoryItem& historyItem = _conformityHistoryList[historyIdx];
|
||||
// 比较文件最后修改时间和历史记录时间戳
|
||||
// 如果文件修改时间早于历史记录保存时间,说明文件未变,可以使用历史数据
|
||||
if (fileInfo.lastModified() <= historyItem.timestamp) {
|
||||
// 直接将历史数据转换为预计算结果存入缓存
|
||||
ConformityCalculatedResult result = historyItem.toCalculatedResult();
|
||||
QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
m_calculatedCache[conformCount] = result;
|
||||
canUseHistoryConformCounts.append(conformCount);
|
||||
qDebug() << "[ConformityAnalysis] " << conformCount << "重符合数据使用历史缓存,跳过解析";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 文件不存在或已修改,需要重新解析
|
||||
needParseConformCounts.append(conformCount);
|
||||
qDebug() << "[ConformityAnalysis] " << conformCount << "重符合数据需要重新解析";
|
||||
}
|
||||
m_isParsing = true;
|
||||
parseAllConformDataInBackground();
|
||||
|
||||
// 优先显示2重符合数据(如果有历史缓存)
|
||||
if (canUseHistoryConformCounts.contains(2)) {
|
||||
displayConformData(2);
|
||||
}
|
||||
|
||||
// 如果有需要解析的文件,启动后台解析
|
||||
if (!needParseConformCounts.isEmpty()) {
|
||||
m_isParsing = true;
|
||||
// 先解析2重符合(如果需要),保证界面快速显示
|
||||
if (needParseConformCounts.contains(2)) {
|
||||
ConformityCalculatedResult result = streamParseAndCalculate(2, m_conformFileMap[2]);
|
||||
QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
m_calculatedCache[2] = result;
|
||||
cacheLocker.unlock();
|
||||
displayConformData(2);
|
||||
QMetaObject::invokeMethod(this, [=]() {
|
||||
saveResultToHistory(result);
|
||||
}, Qt::QueuedConnection);
|
||||
needParseConformCounts.removeOne(2);
|
||||
}
|
||||
|
||||
// 后台解析剩余的符合数
|
||||
parseRemainingConformDataInBackground(needParseConformCounts);
|
||||
} else {
|
||||
m_isParsing = false;
|
||||
qDebug() << "[ConformityAnalysis] 所有数据均使用历史缓存,无需解析";
|
||||
}
|
||||
}
|
||||
|
||||
void ConformityAnalysis::parseRemainingConformDataInBackground(const QList<int>& conformCounts)
|
||||
{
|
||||
if (conformCounts.isEmpty()) {
|
||||
m_isParsing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QList<int> sortedCounts = conformCounts;
|
||||
std::sort(sortedCounts.begin(), sortedCounts.end());
|
||||
|
||||
auto parseTask = [this, sortedCounts]() {
|
||||
for (int conformCount : sortedCounts) {
|
||||
if (m_parseWatcher && m_parseWatcher->isCanceled())
|
||||
break;
|
||||
QString fileName = m_conformFileMap[conformCount];
|
||||
ConformityCalculatedResult result = streamParseAndCalculate(conformCount, fileName);
|
||||
QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
m_calculatedCache[conformCount] = result;
|
||||
cacheLocker.unlock();
|
||||
if (conformCount == m_currentConformCount) {
|
||||
QMetaObject::invokeMethod(this, "displayConformData", Qt::QueuedConnection,
|
||||
Q_ARG(int, conformCount));
|
||||
}
|
||||
QMetaObject::invokeMethod(this, [=]() {
|
||||
saveResultToHistory(result);
|
||||
}, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, "onSingleParseFinished", Qt::QueuedConnection, Q_ARG(int, conformCount));
|
||||
}
|
||||
};
|
||||
|
||||
if (m_parseWatcher) {
|
||||
m_parseWatcher->cancel();
|
||||
m_parseWatcher->waitForFinished();
|
||||
delete m_parseWatcher;
|
||||
}
|
||||
|
||||
m_parseWatcher = new QFutureWatcher<void>(this);
|
||||
connect(m_parseWatcher, &QFutureWatcher<void>::finished, this, &ConformityAnalysis::onAllParseFinished);
|
||||
m_parseWatcher->setFuture(QtConcurrent::run(parseTask));
|
||||
}
|
||||
|
||||
void ConformityAnalysis::parseAllConformDataInBackground()
|
||||
|
|
@ -219,21 +380,15 @@ void ConformityAnalysis::parseAllConformDataInBackground()
|
|||
for (int conformCount : conformCounts) {
|
||||
if (m_parseWatcher && m_parseWatcher->isCanceled())
|
||||
break;
|
||||
|
||||
QString fileName = m_conformFileMap[conformCount];
|
||||
|
||||
|
||||
ConformityCalculatedResult result = streamParseAndCalculate(conformCount, fileName);
|
||||
|
||||
QMutexLocker cacheLocker(&m_cacheMutex);
|
||||
m_calculatedCache[conformCount] = result;
|
||||
cacheLocker.unlock();
|
||||
|
||||
if (conformCount == m_currentConformCount) {
|
||||
QMetaObject::invokeMethod(this, "displayConformData", Qt::QueuedConnection,
|
||||
Q_ARG(int, conformCount));
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(this, [=]() {
|
||||
saveResultToHistory(result);
|
||||
}, Qt::QueuedConnection);
|
||||
|
|
@ -252,12 +407,14 @@ ConformityCalculatedResult ConformityAnalysis::streamParseAndCalculate(int confo
|
|||
ConformityCalculatedResult result;
|
||||
result.conformCount = conformCount;
|
||||
result.dataFileName = fileName;
|
||||
|
||||
memset(result.boardChannelData, 0, sizeof(result.boardChannelData));
|
||||
for (int board = 1; board <= 8; ++board) {
|
||||
for (int channel = 1; channel <= 4; ++channel) {
|
||||
memset(result.coincidenceMatrix, 0, sizeof(result.coincidenceMatrix));
|
||||
|
||||
for (int board = 1; board <= MAX_BOARD; ++board) {
|
||||
for (int channel = 1; channel <= MAX_CHANNEL; ++channel) {
|
||||
QString key = QStringLiteral(u"widget_%1_%2").arg(board).arg(channel);
|
||||
result.firstParticleData[key] = 0;
|
||||
result.channelSurfaceData[key] = QVector<SurfacePoint>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,13 +423,11 @@ ConformityCalculatedResult ConformityAnalysis::streamParseAndCalculate(int confo
|
|||
double minSecondVal = std::numeric_limits<double>::max();
|
||||
double maxSecondVal = 0.0;
|
||||
|
||||
QVector<particleCoincidenceEvent> currentEventParticles;
|
||||
int currentEventId = -1;
|
||||
float primaryEnergy = 0.0f;
|
||||
float secondaryEnergySum = 0.0f;
|
||||
int eventCount = 0;
|
||||
|
||||
if (!QFileInfo::exists(fileName)) {
|
||||
qCritical() << "[ConformityAnalysis] CSV文件不存在:" << fileName;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -294,25 +449,49 @@ ConformityCalculatedResult ConformityAnalysis::streamParseAndCalculate(int confo
|
|||
particleCoincidenceEvent event;
|
||||
while (reader.read_row(event.eventId, event.board, event.channel, event.energy, event.timeCounter)) {
|
||||
eventCount++;
|
||||
|
||||
result.boardChannelData[event.board][event.channel]++;
|
||||
|
||||
if (event.eventId != currentEventId) {
|
||||
if (currentEventId != -1) {
|
||||
SurfacePoint point;
|
||||
point.primaryEnergy = primaryEnergy;
|
||||
point.secondaryEnergySum = secondaryEnergySum;
|
||||
point.count = 1;
|
||||
result.surfaceData.append(point);
|
||||
if (currentEventId != -1 && !currentEventParticles.isEmpty()) {
|
||||
SurfacePoint globalPoint;
|
||||
const auto& primaryParticle = currentEventParticles.first();
|
||||
globalPoint.primaryEnergy = static_cast<float>(primaryParticle.energy);
|
||||
globalPoint.secondaryEnergySum = 0.0f;
|
||||
|
||||
for (int i = 1; i < currentEventParticles.size(); ++i) {
|
||||
globalPoint.secondaryEnergySum += static_cast<float>(currentEventParticles[i].energy);
|
||||
}
|
||||
globalPoint.count = 1;
|
||||
result.surfaceData.append(globalPoint);
|
||||
|
||||
int primaryBoard = primaryParticle.board;
|
||||
int primaryChannel = primaryParticle.channel;
|
||||
QString primaryKey = QStringLiteral(u"widget_%1_%2").arg(primaryBoard + 1).arg(primaryChannel + 1);
|
||||
|
||||
SurfacePoint channelPoint;
|
||||
channelPoint.primaryEnergy = static_cast<float>(primaryParticle.energy);
|
||||
channelPoint.secondaryEnergySum = 0.0f;
|
||||
|
||||
for (int secondaryIdx = 1; secondaryIdx < currentEventParticles.size(); ++secondaryIdx) {
|
||||
const auto& secondaryParticle = currentEventParticles[secondaryIdx];
|
||||
int secondaryBoard = secondaryParticle.board;
|
||||
int secondaryChannel = secondaryParticle.channel;
|
||||
|
||||
result.coincidenceMatrix[primaryBoard][primaryChannel][secondaryBoard][secondaryChannel]++;
|
||||
channelPoint.secondaryEnergySum += static_cast<float>(secondaryParticle.energy);
|
||||
}
|
||||
|
||||
channelPoint.count = 1;
|
||||
result.channelSurfaceData[primaryKey].append(channelPoint);
|
||||
}
|
||||
|
||||
currentEventId = event.eventId;
|
||||
primaryEnergy = static_cast<float>(event.energy);
|
||||
secondaryEnergySum = 0.0f;
|
||||
currentEventParticles.clear();
|
||||
currentEventParticles.append(event);
|
||||
|
||||
int boardId = event.board + 1;
|
||||
int channelId = event.channel + 1;
|
||||
if (boardId >= 1 && boardId <= 8 && channelId >= 1 && channelId <= 4) {
|
||||
if (boardId >= 1 && boardId <= MAX_BOARD && channelId >= 1 && channelId <= MAX_CHANNEL) {
|
||||
QString key = QStringLiteral(u"widget_%1_%2").arg(boardId).arg(channelId);
|
||||
result.firstParticleData[key]++;
|
||||
}
|
||||
|
|
@ -320,23 +499,48 @@ ConformityCalculatedResult ConformityAnalysis::streamParseAndCalculate(int confo
|
|||
if (event.energy < minFirstVal) minFirstVal = event.energy;
|
||||
if (event.energy > maxFirstVal) maxFirstVal = event.energy;
|
||||
} else {
|
||||
secondaryEnergySum += static_cast<float>(event.energy);
|
||||
|
||||
currentEventParticles.append(event);
|
||||
if (event.energy < minSecondVal) minSecondVal = event.energy;
|
||||
if (event.energy > maxSecondVal) maxSecondVal = event.energy;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentEventId != -1) {
|
||||
SurfacePoint point;
|
||||
point.primaryEnergy = primaryEnergy;
|
||||
point.secondaryEnergySum = secondaryEnergySum;
|
||||
point.count = 1;
|
||||
result.surfaceData.append(point);
|
||||
if (currentEventId != -1 && !currentEventParticles.isEmpty()) {
|
||||
SurfacePoint globalPoint;
|
||||
const auto& primaryParticle = currentEventParticles.first();
|
||||
globalPoint.primaryEnergy = static_cast<float>(primaryParticle.energy);
|
||||
globalPoint.secondaryEnergySum = 0.0f;
|
||||
|
||||
for (int i = 1; i < currentEventParticles.size(); ++i) {
|
||||
globalPoint.secondaryEnergySum += static_cast<float>(currentEventParticles[i].energy);
|
||||
}
|
||||
globalPoint.count = 1;
|
||||
result.surfaceData.append(globalPoint);
|
||||
|
||||
int primaryBoard = primaryParticle.board;
|
||||
int primaryChannel = primaryParticle.channel;
|
||||
QString primaryKey = QStringLiteral(u"widget_%1_%2").arg(primaryBoard + 1).arg(primaryChannel + 1);
|
||||
|
||||
SurfacePoint channelPoint;
|
||||
channelPoint.primaryEnergy = static_cast<float>(primaryParticle.energy);
|
||||
channelPoint.secondaryEnergySum = 0.0f;
|
||||
|
||||
for (int secondaryIdx = 1; secondaryIdx < currentEventParticles.size(); ++secondaryIdx) {
|
||||
const auto& secondaryParticle = currentEventParticles[secondaryIdx];
|
||||
int secondaryBoard = secondaryParticle.board;
|
||||
int secondaryChannel = secondaryParticle.channel;
|
||||
result.coincidenceMatrix[primaryBoard][primaryChannel][secondaryBoard][secondaryChannel]++;
|
||||
channelPoint.secondaryEnergySum += static_cast<float>(secondaryParticle.energy);
|
||||
}
|
||||
|
||||
channelPoint.count = 1;
|
||||
result.channelSurfaceData[primaryKey].append(channelPoint);
|
||||
}
|
||||
|
||||
result.surfaceData.squeeze();
|
||||
|
||||
for (auto& vec : result.channelSurfaceData) {
|
||||
vec.squeeze();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
qCritical() << "[ConformityAnalysis] CSV解析异常:" << e.what();
|
||||
return result;
|
||||
|
|
@ -347,19 +551,18 @@ ConformityCalculatedResult ConformityAnalysis::streamParseAndCalculate(int confo
|
|||
result.primaryEnergyEnd = maxFirstVal;
|
||||
result.secondaryEnergyStart = (minSecondVal == std::numeric_limits<double>::max()) ? 0.0 : minSecondVal;
|
||||
result.secondaryEnergyEnd = maxSecondVal;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConformityAnalysis::saveResultToHistory(const ConformityCalculatedResult& result)
|
||||
{
|
||||
|
||||
QMutexLocker locker(&m_historyMutex);
|
||||
ConformityHistoryItem item = ConformityHistoryItem::fromCalculatedResult(result);
|
||||
|
||||
// 1. 流式写入JSON(零大小限制)
|
||||
// 保存JSON元数据
|
||||
saveJsonStream(result.conformCount, item);
|
||||
// 2. 二进制保存超大曲面数据
|
||||
saveSurfaceDataToBinary(result.conformCount, item.surfaceData);
|
||||
// 保存二进制曲面数据(全局+所有通道)
|
||||
saveSurfaceDataToBinary(result.conformCount, item.surfaceData, item.channelSurfaceData);
|
||||
}
|
||||
|
||||
void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistoryItem& item)
|
||||
|
|
@ -367,13 +570,11 @@ void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistor
|
|||
QDir dir(_workspace);
|
||||
dir.mkpath(".");
|
||||
QString path = dir.filePath(QString("conformity_%1.json").arg(conformCount));
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
|
||||
qCritical() << "无法打开文件写入:" << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec("UTF-8");
|
||||
// 强制浮点数用固定小数格式,避免科学计数法
|
||||
|
|
@ -406,7 +607,6 @@ void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistor
|
|||
};
|
||||
|
||||
stream << "{" << '\n';
|
||||
|
||||
stream << " \"timestamp\": \"" << escapeJson(item.timestamp.toString(Qt::ISODate)) << "\"," << '\n';
|
||||
stream << " \"dataFileName\": \"" << escapeJson(item.dataFileName) << "\"," << '\n';
|
||||
stream << " \"conformCount\": " << item.conformCount << "," << '\n';
|
||||
|
|
@ -416,6 +616,7 @@ void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistor
|
|||
stream << " \"secondaryEnergyStart\": " << item.secondaryEnergyStart << "," << '\n';
|
||||
stream << " \"secondaryEnergyEnd\": " << item.secondaryEnergyEnd << "," << '\n';
|
||||
|
||||
// 板卡通道数据
|
||||
stream << " \"boardChannelData\": [" << '\n';
|
||||
for (int board = 0; board < MAX_BOARD; ++board) {
|
||||
stream << " [";
|
||||
|
|
@ -429,6 +630,7 @@ void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistor
|
|||
}
|
||||
stream << " ]," << '\n';
|
||||
|
||||
// 初级粒子数据
|
||||
stream << " \"firstParticleData\": {" << '\n';
|
||||
QList<QString> keys = item.firstParticleData.keys();
|
||||
for (int i = 0; i < keys.size(); ++i) {
|
||||
|
|
@ -436,26 +638,55 @@ void ConformityAnalysis::saveJsonStream(int conformCount, const ConformityHistor
|
|||
if (i < keys.size() - 1) stream << ",";
|
||||
stream << '\n';
|
||||
}
|
||||
stream << " }" << '\n';
|
||||
stream << " }," << '\n';
|
||||
|
||||
// 符合矩阵数据
|
||||
stream << " \"coincidenceMatrix\": [" << '\n';
|
||||
for (int pBoard = 0; pBoard < MAX_BOARD; ++pBoard) {
|
||||
stream << " [" << '\n';
|
||||
for (int pChannel = 0; pChannel < MAX_CHANNEL; ++pChannel) {
|
||||
stream << " [";
|
||||
for (int sBoard = 0; sBoard < MAX_BOARD; ++sBoard) {
|
||||
stream << "[";
|
||||
for (int sChannel = 0; sChannel < MAX_CHANNEL; ++sChannel) {
|
||||
stream << item.coincidenceMatrix[pBoard][pChannel][sBoard][sChannel];
|
||||
if (sChannel < MAX_CHANNEL - 1) stream << ", ";
|
||||
}
|
||||
stream << "]";
|
||||
if (sBoard < MAX_BOARD - 1) stream << ", ";
|
||||
}
|
||||
stream << "]";
|
||||
if (pChannel < MAX_CHANNEL - 1) stream << ",";
|
||||
stream << '\n';
|
||||
}
|
||||
stream << " ]";
|
||||
if (pBoard < MAX_BOARD - 1) stream << ",";
|
||||
stream << '\n';
|
||||
}
|
||||
stream << " ]" << '\n';
|
||||
|
||||
stream << "}" << '\n';
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ConformityAnalysis::saveSurfaceDataToBinary(int conformCount, const QVector<SurfacePoint>& data)
|
||||
|
||||
void ConformityAnalysis::saveSurfaceDataToBinary(int conformCount, const QVector<SurfacePoint> &globalData, const QMap<QString, QVector<SurfacePoint> > &channelData)
|
||||
{
|
||||
QDir dir(_workspace);
|
||||
QString path = dir.filePath(QString("surface_%1.bin").arg(conformCount));
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
qCritical() << "无法打开二进制文件写入:" << file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream stream(&file);
|
||||
stream << data;
|
||||
// 先保存全局曲面数据
|
||||
stream << globalData;
|
||||
// 再保存通道曲面数据数量和内容
|
||||
stream << channelData.size();
|
||||
for (auto it = channelData.begin(); it != channelData.end(); ++it) {
|
||||
stream << it.key() << it.value();
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
|
@ -465,12 +696,9 @@ void ConformityAnalysis::loadHistoryFromFile()
|
|||
for (int c = 2; c <= 9; ++c) {
|
||||
QString jsonPath = QDir(_workspace).filePath(QString("conformity_%1.json").arg(c));
|
||||
QString binPath = QDir(_workspace).filePath(QString("surface_%1.bin").arg(c));
|
||||
|
||||
if (!QFile::exists(jsonPath)) {
|
||||
// qDebug() << "[ConformityAnalysis] " << c << "重符合历史文件不存在:" << jsonPath;
|
||||
continue;
|
||||
}
|
||||
|
||||
QFile f(jsonPath);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "[ConformityAnalysis] 无法打开JSON文件:" << jsonPath;
|
||||
|
|
@ -478,7 +706,6 @@ void ConformityAnalysis::loadHistoryFromFile()
|
|||
}
|
||||
QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
|
||||
f.close();
|
||||
|
||||
ConformityHistoryItem item = ConformityHistoryItem::fromJson(doc.object());
|
||||
|
||||
if (QFile::exists(binPath)) {
|
||||
|
|
@ -486,18 +713,23 @@ void ConformityAnalysis::loadHistoryFromFile()
|
|||
if (binFile.open(QIODevice::ReadOnly)) {
|
||||
QDataStream stream(&binFile);
|
||||
stream >> item.surfaceData;
|
||||
int channelCount;
|
||||
stream >> channelCount;
|
||||
for (int i = 0; i < channelCount; ++i) {
|
||||
QString key;
|
||||
QVector<SurfacePoint> data;
|
||||
stream >> key >> data;
|
||||
item.channelSurfaceData[key] = data;
|
||||
}
|
||||
binFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
_conformityHistoryList.append(item);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 单个符合数解析完成 ====================
|
||||
void ConformityAnalysis::onSingleParseFinished(int conformCount)
|
||||
{
|
||||
qDebug() << "[ConformityAnalysis] " << conformCount << "重符合数据处理完成";
|
||||
}
|
||||
|
||||
void ConformityAnalysis::onAllParseFinished()
|
||||
|
|
@ -535,7 +767,6 @@ void ConformityAnalysis::displayConformData(int conformCount)
|
|||
setAllBoardData();
|
||||
setThreeUiData();
|
||||
ui->widget_3D->setSurfaceData(m_surfaceData);
|
||||
|
||||
}
|
||||
|
||||
void ConformityAnalysis::slot_ConformCountChanged(int index)
|
||||
|
|
@ -552,7 +783,6 @@ QVector<particleCoincidenceEvent*> ConformityAnalysis::readCsv(const QString& fi
|
|||
QVector<particleCoincidenceEvent*> dataList;
|
||||
|
||||
if (!QFileInfo::exists(fileName)) {
|
||||
qWarning() << "[ConformityAnalysis] 文件不存在:" << fileName;
|
||||
return dataList;
|
||||
}
|
||||
|
||||
|
|
@ -590,7 +820,6 @@ QVector<particleCoincidenceEvent*> ConformityAnalysis::readCsv(const QString& fi
|
|||
return dataList;
|
||||
}
|
||||
|
||||
// 释放事件数组内存
|
||||
void ConformityAnalysis::freeEventVector(QVector<particleCoincidenceEvent*>& vec)
|
||||
{
|
||||
qDeleteAll(vec);
|
||||
|
|
@ -752,46 +981,65 @@ void ConformityAnalysis::slot_ClickedBoard(int board,int channel)
|
|||
if (!m_calculatedCache.contains(m_currentConformCount)) {
|
||||
return;
|
||||
}
|
||||
QString fileName = m_calculatedCache[m_currentConformCount].dataFileName;
|
||||
const ConformityCalculatedResult& result = m_calculatedCache[m_currentConformCount];
|
||||
locker.unlock();
|
||||
|
||||
if (_currentSpectrumData.isEmpty()) {
|
||||
_currentSpectrumData = readCsv(fileName);
|
||||
QString primaryKey = QStringLiteral(u"widget_%1_%2").arg(board).arg(channel);
|
||||
if (!result.channelSurfaceData.contains(primaryKey)) {
|
||||
qWarning() << "[ConformityAnalysis] 通道数据不存在:" << primaryKey;
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<particleCoincidenceEvent*> data = handleBasicSubordinate(board, channel, _currentSpectrumData);
|
||||
if(data.size() <= 0) return;
|
||||
const QVector<SurfacePoint>& channelSurface = result.channelSurfaceData[primaryKey];
|
||||
ui->widget_3D->setSurfaceData(channelSurface);
|
||||
|
||||
QVector<SurfacePoint> tempSurface = generateSurfaceData(data);
|
||||
ui->widget_3D->setSurfaceData(tempSurface);
|
||||
|
||||
m_iComply = data.size();
|
||||
|
||||
double localFirstStart, localFirstEnd;
|
||||
double localSecondStart, localSecondEnd;
|
||||
calculateFirstSecondRange(data, localFirstStart, localFirstEnd, localSecondStart, localSecondEnd);
|
||||
|
||||
m_dFirstStart = localFirstStart;
|
||||
double localFirstStart = std::numeric_limits<double>::max();
|
||||
double localFirstEnd = 0.0;
|
||||
double localSecondStart = std::numeric_limits<double>::max();
|
||||
double localSecondEnd = 0.0;
|
||||
for (const auto& point : channelSurface) {
|
||||
if (point.primaryEnergy < localFirstStart) localFirstStart = point.primaryEnergy;
|
||||
if (point.primaryEnergy > localFirstEnd) localFirstEnd = point.primaryEnergy;
|
||||
if (point.secondaryEnergySum < localSecondStart) localSecondStart = point.secondaryEnergySum;
|
||||
if (point.secondaryEnergySum > localSecondEnd) localSecondEnd = point.secondaryEnergySum;
|
||||
}
|
||||
m_dFirstStart = (localFirstStart == std::numeric_limits<double>::max()) ? 0.0 : localFirstStart;
|
||||
m_dFirstEnd = localFirstEnd;
|
||||
m_dSecondStart = localSecondStart;
|
||||
m_dSecondStart = (localSecondStart == std::numeric_limits<double>::max()) ? 0.0 : localSecondStart;
|
||||
m_dSecondEnd = localSecondEnd;
|
||||
|
||||
m_iComply = channelSurface.size();
|
||||
setThreeUiData();
|
||||
|
||||
m_subordinate = handleSubordinate(data, board, channel);
|
||||
m_subordinate.clear();
|
||||
int maxSubordinate = 0;
|
||||
for (int val : m_subordinate.values()) {
|
||||
if (val > maxSubordinate) maxSubordinate = val;
|
||||
int primaryBoardIdx = board - 1;
|
||||
int primaryChannelIdx = channel - 1;
|
||||
|
||||
for (int sBoard = 0; sBoard < MAX_BOARD; ++sBoard) {
|
||||
for (int sChannel = 0; sChannel < MAX_CHANNEL; ++sChannel) {
|
||||
QString key = QStringLiteral(u"widget_%1_%2").arg(sBoard + 1).arg(sChannel + 1);
|
||||
int count = result.coincidenceMatrix[primaryBoardIdx][primaryChannelIdx][sBoard][sChannel];
|
||||
m_subordinate[key] = count;
|
||||
if (count > maxSubordinate) maxSubordinate = count;
|
||||
}
|
||||
}
|
||||
|
||||
ui->widget->setAllWidgetColorMaxValue(maxSubordinate);
|
||||
for (int i = 0; i < m_subordinate.keys().size();i++) {
|
||||
QString objectName =m_subordinate.keys().at(i);
|
||||
QStringList parts = objectName.split('_');
|
||||
int bd = parts[1].toInt();
|
||||
int ch = parts[2].toInt();
|
||||
ui->widget->setWidgetData(bd,ch,m_boardChannel[bd - 1][ch - 1],m_subordinate[objectName]);
|
||||
for (int sBoard = 1; sBoard <= MAX_BOARD; ++sBoard) {
|
||||
for (int sChannel = 1; sChannel <= MAX_CHANNEL; ++sChannel) {
|
||||
if (sBoard == board && sChannel == channel) {
|
||||
continue;
|
||||
}
|
||||
QString key = QStringLiteral(u"widget_%1_%2").arg(sBoard).arg(sChannel);
|
||||
int totalCount = m_boardChannel[sBoard - 1][sChannel - 1];
|
||||
int secondCount = m_subordinate[key];
|
||||
ui->widget->setWidgetData(sBoard, sChannel, totalCount, secondCount);
|
||||
}
|
||||
}
|
||||
ui->widget->setWidgetData(board,channel,m_boardChannel[board - 1][channel - 1],data.size());
|
||||
|
||||
int primaryTotalCount = m_boardChannel[primaryBoardIdx][primaryChannelIdx];
|
||||
int primaryCount = channelSurface.size();
|
||||
ui->widget->setWidgetData(board, channel, primaryTotalCount, primaryCount);
|
||||
}
|
||||
|
||||
QMap<QString, int> ConformityAnalysis::handleSubordinate(QVector<particleCoincidenceEvent*> &eventData,int Board, int Channel)
|
||||
|
|
@ -851,7 +1099,9 @@ void ConformityAnalysis::saveHistoryToFile()
|
|||
int idx = findHistoryIndex(m_conformFileMap.value(conformCount), conformCount);
|
||||
if (idx >= 0) {
|
||||
saveJsonStream(conformCount, _conformityHistoryList[idx]);
|
||||
saveSurfaceDataToBinary(conformCount, _conformityHistoryList[idx].surfaceData);
|
||||
saveSurfaceDataToBinary(conformCount,
|
||||
_conformityHistoryList[idx].surfaceData,
|
||||
_conformityHistoryList[idx].channelSurfaceData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -897,9 +1147,19 @@ int ConformityAnalysis::saveCurrentAnalysisToHistory(int conformCount)
|
|||
|
||||
int ConformityAnalysis::findHistoryIndex(const QString& fileName, int conformCount) const
|
||||
{
|
||||
// for (int i = 0; i < _conformityHistoryList.size(); ++i) {
|
||||
// const ConformityHistoryItem& item = _conformityHistoryList[i];
|
||||
// if (item.dataFileName == fileName && item.conformCount == conformCount) {
|
||||
// return i;
|
||||
// }
|
||||
// }
|
||||
// return -1;
|
||||
|
||||
QString absoluteFileName = QFileInfo(fileName).absoluteFilePath();
|
||||
for (int i = 0; i < _conformityHistoryList.size(); ++i) {
|
||||
const ConformityHistoryItem& item = _conformityHistoryList[i];
|
||||
if (item.dataFileName == fileName && item.conformCount == conformCount) {
|
||||
if (QFileInfo(item.dataFileName).absoluteFilePath() == absoluteFileName
|
||||
&& item.conformCount == conformCount) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct ConformityCalculatedResult {
|
|||
int conformCount; // 符合粒子数
|
||||
QString dataFileName; // 原始CSV文件名
|
||||
int totalEvents; // 符合事件总计数
|
||||
int totalParticles; // 总粒子数
|
||||
double primaryEnergyStart; // 初级粒子能量范围-起始
|
||||
double primaryEnergyEnd; // 初级粒子能量范围-结束
|
||||
double secondaryEnergyStart; // 次级粒子能量范围-起始
|
||||
|
|
@ -44,14 +45,23 @@ struct ConformityCalculatedResult {
|
|||
|
||||
// 板卡通道计数数据(8板×4通道)
|
||||
int boardChannelData[MAX_BOARD][MAX_CHANNEL];
|
||||
|
||||
// 初级粒子计数数据
|
||||
QMap<QString, int> firstParticleData;
|
||||
// 三维曲面数据
|
||||
|
||||
// ✅ 新增:次级粒子符合矩阵 [初级板卡][初级通道][次级板卡][次级通道] = 符合次数
|
||||
int coincidenceMatrix[MAX_BOARD][MAX_CHANNEL][MAX_BOARD][MAX_CHANNEL];
|
||||
|
||||
// ✅ 新增:每个板卡通道作为初级粒子的曲面数据
|
||||
QMap<QString, QVector<SurfacePoint>> channelSurfaceData;
|
||||
|
||||
// 三维曲面数据(全局)
|
||||
QVector<SurfacePoint> surfaceData;
|
||||
|
||||
// 构造函数
|
||||
ConformityCalculatedResult() {
|
||||
memset(boardChannelData, 0, sizeof(boardChannelData));
|
||||
memset(coincidenceMatrix, 0, sizeof(coincidenceMatrix)); // 初始化符合矩阵
|
||||
totalEvents = 0;
|
||||
primaryEnergyStart = primaryEnergyEnd = 0.0;
|
||||
secondaryEnergyStart = secondaryEnergyEnd = 0.0;
|
||||
|
|
@ -75,6 +85,13 @@ struct ConformityHistoryItem {
|
|||
int boardChannelData[MAX_BOARD][MAX_CHANNEL];
|
||||
// 初级粒子计数数据
|
||||
QMap<QString, int> firstParticleData;
|
||||
|
||||
// ✅ 新增:符合矩阵
|
||||
int coincidenceMatrix[MAX_BOARD][MAX_CHANNEL][MAX_BOARD][MAX_CHANNEL];
|
||||
|
||||
// ✅ 新增:每个通道的曲面数据
|
||||
QMap<QString, QVector<SurfacePoint>> channelSurfaceData;
|
||||
|
||||
// 三维曲面数据
|
||||
QVector<SurfacePoint> surfaceData;
|
||||
|
||||
|
|
@ -148,7 +165,8 @@ private:
|
|||
// 流式写入JSON(零大小限制)
|
||||
void saveJsonStream(int conformCount, const ConformityHistoryItem& item);
|
||||
// 二进制保存超大曲面数据
|
||||
void saveSurfaceDataToBinary(int conformCount, const QVector<SurfacePoint>& data);
|
||||
void saveSurfaceDataToBinary(int conformCount, const QVector<SurfacePoint>& globalData, const QMap<QString, QVector<SurfacePoint>>& channelData);
|
||||
|
||||
// 仅保存指定符合数的历史记录到对应文件
|
||||
void saveSingleHistoryToFile(int conformCount, const ConformityHistoryItem& item);
|
||||
int saveCurrentAnalysisToHistory(int conformCount);
|
||||
|
|
@ -167,6 +185,9 @@ private:
|
|||
QVector<particleCoincidenceEvent*> readCsv(const QString& fileName);
|
||||
// 释放事件数组内存
|
||||
void freeEventVector(QVector<particleCoincidenceEvent*>& vec);
|
||||
// 后台解析剩余的符合数数据
|
||||
void parseRemainingConformDataInBackground(const QList<int>& conformCounts);
|
||||
|
||||
|
||||
private:
|
||||
Ui::ConformityAnalysis *ui;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ DetectorStatusSummary::~DetectorStatusSummary()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
// ========== 原有接口(仅修改样式表相关部分) ==========
|
||||
void DetectorStatusSummary::setName(QString name)
|
||||
{
|
||||
ui->label_name->setText(name);
|
||||
|
|
@ -76,7 +75,6 @@ void DetectorStatusSummary::setColorMaxValue(int maxValue)
|
|||
m_nMaxValue = maxValue;
|
||||
}
|
||||
|
||||
// 关键:移除所有硬编码的样式表背景色
|
||||
void DetectorStatusSummary::setInitWidgetColor()
|
||||
{
|
||||
m_backgroundColor = QColor("#0E508A");
|
||||
|
|
|
|||
|
|
@ -209,12 +209,10 @@ void ThreeDDisplay::_updateSurfaceData()
|
|||
// m_surface->axisZ()->setRange(minSecondary, maxSecondary);
|
||||
if (flag)
|
||||
{
|
||||
qDebug()<< maxPrimary << maxSecondary;
|
||||
m_surface->axisX()->setRange(0, maxPrimary);
|
||||
m_surface->axisZ()->setRange(0, maxSecondary);
|
||||
flag = false;
|
||||
}
|
||||
qDebug()<<getMaxCount(dataMatrix);
|
||||
m_surface->axisY()->setRange(0, getMaxCount(dataMatrix));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ int main(int argc, char *argv[])
|
|||
// 设置应用信息
|
||||
app.setApplicationName("EnergySpectrumAnalyer");
|
||||
app.setApplicationVersion(QVersionNumber(1, 0, 0).toString());
|
||||
app.setApplicationDisplayName(QStringLiteral(u"符合能谱分测量析软件"));
|
||||
app.setApplicationDisplayName(QStringLiteral(u"符合能谱测量分析软件"));
|
||||
app.setOrganizationName(QStringLiteral("NINT,4,4"));
|
||||
QString app_desc = QStringLiteral(u"\
|
||||
符合能谱测量分析软件是面向核物理符合测量场景的专用分析工具,\
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ SOURCES += \
|
|||
MeasureAnalysisProjectModel.cpp \
|
||||
ParticleInjectTimeView/ParticleInjectTimeAnalysisView.cpp \
|
||||
ParticleTimeDifferenceView/ParticleTimeDifferenceView.cpp \
|
||||
RegionOfInterest/RegionOfInterest.cpp \
|
||||
VirtualTable/CsvDataSource.cpp \
|
||||
VirtualTable/SampleDataSource.cpp \
|
||||
VirtualTable/VirtualTableModel.cpp \
|
||||
|
|
@ -161,6 +162,7 @@ HEADERS += \
|
|||
MeasureAnalysisProjectModel.h \
|
||||
ParticleInjectTimeView/ParticleInjectTimeAnalysisView.h \
|
||||
ParticleTimeDifferenceView/ParticleTimeDifferenceView.h \
|
||||
RegionOfInterest/RegionOfInterest.h \
|
||||
VirtualTable/CsvDataSource.h \
|
||||
VirtualTable/DataSource.h \
|
||||
VirtualTable/SampleDataSource.h \
|
||||
|
|
@ -187,6 +189,7 @@ FORMS += \
|
|||
MeasureDeviceParamsConfigView/DeviceParamsTableForm.ui \
|
||||
ParticleCountPlotView/BatchEnergyScaleDialog.ui \
|
||||
NewMeasureAnalysisDlg.ui \
|
||||
RegionOfInterest/RegionOfInterest.ui \
|
||||
ThreeDimensionalConformityAnalysisView/DetectorStatusSummary.ui \
|
||||
ThreeDimensionalConformityAnalysisView/ParticleDataStatistics.ui \
|
||||
ThreeDimensionalConformityAnalysisView/ThreeDDisplay.ui \
|
||||
|
|
@ -203,3 +206,4 @@ contains(DEFINES, ENABLE_DEBUG) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user