feat/vtk-3d-view #7

Merged
gaozheng merged 301 commits from feat/vtk-3d-view into main 2026-06-27 18:43:52 +08:00
3 changed files with 47 additions and 20 deletions
Showing only changes of commit c6756aafc5 - Show all commits

View File

@ -4,28 +4,23 @@
#include "EmptyAwareComboBox.hpp"
#include <QFormLayout>
#include <QJsonArray>
#include <QJsonObject>
#include <QLabel>
#include <QLineEdit>
#include <QPixmap>
#include <QPlainTextEdit>
#include <QPointer>
#include "FormKit.hpp"
#include "Theme.hpp"
#include "repo/IDatasetCommandRepository.hpp"
namespace geopro::app {
namespace {
// 异常类型 mock 列表label, id。真实 exceptionType 端点只读、后续接。
struct TypeItem { const char* label; const char* id; };
const TypeItem kMockTypes[] = {
{"断层", "mock-fault"},
{"破碎带", "mock-fracture"},
{"含水构造", "mock-water"},
{"其它", "mock-other"},
};
} // namespace
AnomalySaveDialog::AnomalySaveDialog(const QString& screenshotPath, int shotW, int shotH,
geopro::data::IDatasetCommandRepository* cmdRepo,
const QString& projectId, int remarkSourceType,
QWidget* parent)
: QDialog(parent) {
setWindowTitle(QStringLiteral("保存异常"));
@ -42,10 +37,9 @@ AnomalySaveDialog::AnomalySaveDialog(const QString& screenshotPath, int shotW, i
form->addRow(formkit::editLabel(QStringLiteral("名称")), name_);
type_ = new EmptyAwareComboBox();
for (const auto& t : kMockTypes)
type_->addItem(QString::fromUtf8(t.label), QString::fromUtf8(t.id));
formkit::capField(type_);
form->addRow(formkit::editLabel(QStringLiteral("异常类型")), type_);
loadTypes(cmdRepo, projectId, remarkSourceType); // 异步拉平台异常类型填充(与平台一致)
remark_ = new QPlainTextEdit();
remark_->setFixedHeight(geopro::app::scaledPx(60));
@ -69,6 +63,23 @@ AnomalySaveDialog::AnomalySaveDialog(const QString& screenshotPath, int shotW, i
formkit::addDialogButtons(root, this);
}
void AnomalySaveDialog::loadTypes(geopro::data::IDatasetCommandRepository* cmdRepo,
const QString& projectId, int remarkSourceType) {
if (cmdRepo == nullptr || projectId.isEmpty()) return; // 无仓储/项目 → 下拉留空(空态提示)
QPointer<AnomalySaveDialog> self(this);
cmdRepo->listExceptionTypes(
projectId, QString::number(remarkSourceType),
[self](bool ok, QJsonArray list, const QString&) {
if (!self || !ok) return; // 对话框已关 / 失败 → 留空
for (const QJsonValue& v : list) {
const QJsonObject o = v.toObject();
// 平台响应项:{label:类型名, value:类型id}(实测扁平 data 数组net 层已归一 value
self->type_->addItem(o.value(QStringLiteral("label")).toString(),
o.value(QStringLiteral("value")).toString());
}
});
}
QString AnomalySaveDialog::anomalyName() const {
const QString n = name_->text().trimmed();
return n.isEmpty() ? QStringLiteral("异常") : n;

View File

@ -7,15 +7,23 @@ class QComboBox;
class QPlainTextEdit;
class QLabel;
namespace geopro::data {
class IDatasetCommandRepository;
}
namespace geopro::app {
// 异常保存对话框(#4b需求 R50名称 + 异常类型 + 备注 + 截图预览/大小。
// 异常类型本期 mock 列表(真实 exceptionType 端点只读、后续可接。accept 后取 name/typeName/typeId/remark。
// 异常类型从平台按标注形态(remarkSourceType)异步拉取,与平台保持一致。accept 后取 name/typeName/typeId/remark。
class AnomalySaveDialog : public QDialog {
Q_OBJECT
public:
// screenshotPath圈定结束截图的本地路径为空则不显示预览w/h截图像素尺寸R50「确定截图大小」
AnomalySaveDialog(const QString& screenshotPath, int shotW, int shotH, QWidget* parent = nullptr);
// cmdRepo/projectId异步拉取平台异常类型填充下拉与平台一致remarkSourceType标注形态 1点/2线/3面
// 决定查询哪一类平台异常类型。cmdRepo 为空则下拉留空(空态由 EmptyAwareComboBox 提示)。
AnomalySaveDialog(const QString& screenshotPath, int shotW, int shotH,
geopro::data::IDatasetCommandRepository* cmdRepo, const QString& projectId,
int remarkSourceType, QWidget* parent = nullptr);
QString anomalyName() const;
QString typeName() const;
@ -23,6 +31,10 @@ public:
QString remark() const;
private:
// 异步拉平台异常类型(label→显示, value→id)填充下拉;空/失败时下拉留空EmptyAwareComboBox 提示)。
void loadTypes(geopro::data::IDatasetCommandRepository* cmdRepo, const QString& projectId,
int remarkSourceType);
QLineEdit* name_ = nullptr;
QComboBox* type_ = nullptr;
QPlainTextEdit* remark_ = nullptr;

View File

@ -503,8 +503,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
// 保存=按"未保存/已保存"分派(新建+链接+自动勾选 / 覆盖位姿)导出统一为「导出▸图片·dat」
// 正视/翻转/关闭=接现有交互(关闭已保存切片→onSliceClosed 取消列表勾选);创建异常=占位(#4)。
interactionMgr->onSliceContextMenuRequested =
[&window, interactionMgr, sceneView, scene3dRepo, refreshAnalysis, refreshAnomalies, drawer,
anomalyDrawTool, renderWindowPtr]() {
[&window, &cmdRepo, &nav, interactionMgr, sceneView, scene3dRepo, refreshAnalysis,
refreshAnomalies, drawer, anomalyDrawTool, renderWindowPtr]() {
QMenu menu(&window);
QAction* aAnomaly = menu.addAction(QStringLiteral("创建异常"));
QAction* aSave = menu.addAction(QStringLiteral("保存"));
@ -537,8 +537,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
const std::string savedSliceId = interactionMgr->selectedSliceDsId();
anomalyDrawTool->start(
o, normal,
[&window, sceneView, scene3dRepo, renderWindowPtr, refreshAnomalies, refreshAnalysis,
volId, savedSliceId, normal, o, p1, p2](const std::vector<ri::Vec3>& worldPts) {
[&window, &cmdRepo, &nav, sceneView, scene3dRepo, renderWindowPtr, refreshAnomalies,
refreshAnalysis, volId, savedSliceId, normal, o, p1,
p2](const std::vector<ri::Vec3>& worldPts) {
// 草稿异常:先临时渲染(让用户在对话框前看到所画,且截图含异常)。
geopro::core::Anomaly a;
a.markType = geopro::core::AnomalyMarkType::Polygon;
@ -575,7 +576,10 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
const double minExt = 0.25 * std::min(e1, e2); // 点/线退化框景半径
geopro::app::captureFramedRegionPng(renderWindowPtr, rb, 1.4, minExt,
shot.toStdString(), sw, sh);
geopro::app::AnomalySaveDialog dlg(shot, sw, sh, &window);
// 异常类型按标注形态拉平台类型(与平台一致)。当前仅面(Polygon)→remarkSourceType=3
// P2 接入点/线后由菜单形态决定 1/2/3。
geopro::app::AnomalySaveDialog dlg(shot, sw, sh, &cmdRepo,
nav.currentProjectId(), 3, &window);
if (dlg.exec() != QDialog::Accepted) {
sceneView->removeAnomaly(draftId);
renderWindowPtr->Render();