feat/vtk-3d-view #7
|
|
@ -42,6 +42,13 @@ When your changes create orphans:
|
||||||
|
|
||||||
The test: Every changed line should trace directly to the user's request.
|
The test: Every changed line should trace directly to the user's request.
|
||||||
|
|
||||||
|
**Exception — Tech debt must be fixed, not deferred:** When you discover a real bug,
|
||||||
|
broken behavior, or technical debt while working (even if it predates this change and
|
||||||
|
you didn't introduce it), fix it — do not use "not introduced by this round / pre-existing"
|
||||||
|
as a reason to leave it. Surface it, then handle it. (User directive, 2026-06-25, binding.)
|
||||||
|
This overrides the "don't fix what isn't broken" bias above *for genuine defects* — it does
|
||||||
|
not license cosmetic refactors or unrequested rewrites.
|
||||||
|
|
||||||
## 4. Goal-Driven Execution
|
## 4. Goal-Driven Execution
|
||||||
|
|
||||||
**Define success criteria. Loop until verified.**
|
**Define success criteria. Loop until verified.**
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,15 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
|
||||||
unit_->addItems({QStringLiteral("米"), QStringLiteral("英尺")});
|
unit_->addItems({QStringLiteral("米"), QStringLiteral("英尺")});
|
||||||
v->addWidget(unit_);
|
v->addWidget(unit_);
|
||||||
|
|
||||||
// X / Y / Z 三轴(各:显示开关 + 最小值/最大值)。
|
// X / Y / Z 三轴(各:显示开关 + 最小值/最大值)。与上方单位组留间距。
|
||||||
|
v->addSpacing(space::kSm);
|
||||||
x_ = addAxisRow(v, QStringLiteral("X轴"), {true, -500, 500});
|
x_ = addAxisRow(v, QStringLiteral("X轴"), {true, -500, 500});
|
||||||
y_ = addAxisRow(v, QStringLiteral("Y轴"), {true, -500, 500});
|
y_ = addAxisRow(v, QStringLiteral("Y轴"), {true, -500, 500});
|
||||||
z_ = addAxisRow(v, QStringLiteral("Z轴"), {true, 0, 200});
|
z_ = addAxisRow(v, QStringLiteral("Z轴"), {true, 0, 200});
|
||||||
|
|
||||||
// 放大系数(=垂直夸张):滑块 1~10×(恢复重构前的拖动交互)。拖动实时改标签,
|
// 放大系数(=垂直夸张):滑块 1~10×。仅改面板内数值/标签,点「应用」才统一生效(不再实时)。
|
||||||
// 松手(sliderReleased)才发信号触发一次重建——VE 改的是几何,必须重建,但不在拖动中连续重建。
|
// 与上方坐标轴组留出间距(用户反馈:滑块离上面项目太近)。
|
||||||
|
v->addSpacing(space::kMd);
|
||||||
auto* scaleRow = new QHBoxLayout();
|
auto* scaleRow = new QHBoxLayout();
|
||||||
auto* scaleLbl = new QLabel(QStringLiteral("放大系数"), this);
|
auto* scaleLbl = new QLabel(QStringLiteral("放大系数"), this);
|
||||||
scaleLbl->setStyleSheet(QStringLiteral("border:none;"));
|
scaleLbl->setStyleSheet(QStringLiteral("border:none;"));
|
||||||
|
|
@ -66,12 +68,12 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
|
||||||
scaleSlider_->setMinimum(1);
|
scaleSlider_->setMinimum(1);
|
||||||
scaleSlider_->setMaximum(10);
|
scaleSlider_->setMaximum(10);
|
||||||
scaleSlider_->setValue(1);
|
scaleSlider_->setValue(1);
|
||||||
|
scaleSlider_->setSingleStep(1);
|
||||||
|
scaleSlider_->setPageStep(1); // 点击轨道按 1 步移动(默认 pageStep=10 → 点一下直接跳到 10 的 bug)
|
||||||
scaleLabel_ = new QLabel(QStringLiteral("1.0×"), this);
|
scaleLabel_ = new QLabel(QStringLiteral("1.0×"), this);
|
||||||
scaleLabel_->setStyleSheet(QStringLiteral("border:none;color:#888;min-width:36px;"));
|
scaleLabel_->setStyleSheet(QStringLiteral("border:none;color:#888;min-width:36px;"));
|
||||||
connect(scaleSlider_, &QSlider::valueChanged, this,
|
connect(scaleSlider_, &QSlider::valueChanged, this,
|
||||||
[this](int v) { scaleLabel_->setText(QStringLiteral("%1.0×").arg(v)); });
|
[this](int v) { scaleLabel_->setText(QStringLiteral("%1.0×").arg(v)); });
|
||||||
connect(scaleSlider_, &QSlider::sliderReleased, this,
|
|
||||||
[this] { emit verticalExaggerationChanged(static_cast<double>(scaleSlider_->value())); });
|
|
||||||
scaleRow->addWidget(scaleSlider_, 1);
|
scaleRow->addWidget(scaleSlider_, 1);
|
||||||
scaleRow->addWidget(scaleLabel_);
|
scaleRow->addWidget(scaleLabel_);
|
||||||
v->addLayout(scaleRow);
|
v->addLayout(scaleRow);
|
||||||
|
|
@ -88,7 +90,8 @@ AxesSettingsPanel::AxesSettingsPanel(QWidget* parent) : QFrame(parent) {
|
||||||
auto rd = [](const Row& r) {
|
auto rd = [](const Row& r) {
|
||||||
return AxisRange{r.show->isChecked(), r.lo->value(), r.hi->value()};
|
return AxisRange{r.show->isChecked(), r.lo->value(), r.hi->value()};
|
||||||
};
|
};
|
||||||
emit applied(rd(x_), rd(y_), rd(z_), unit_->currentIndex());
|
emit applied(rd(x_), rd(y_), rd(z_), unit_->currentIndex(),
|
||||||
|
static_cast<double>(scaleSlider_->value()));
|
||||||
});
|
});
|
||||||
btns->addStretch(1);
|
btns->addStretch(1);
|
||||||
btns->addWidget(cancel);
|
btns->addWidget(cancel);
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,9 @@ public:
|
||||||
void setValues(AxisRange x, AxisRange y, AxisRange z, int unitIdx, double scale);
|
void setValues(AxisRange x, AxisRange y, AxisRange z, int unitIdx, double scale);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// 「应用」:仅坐标轴(显示方式/单位/per-axis 可见性·范围);走增量重建,不重绘数据。
|
// 「应用」一次性下发:坐标轴(显示方式/单位/per-axis 可见性·范围) + 放大系数(scale=垂直夸张)。
|
||||||
void applied(AxisRange x, AxisRange y, AxisRange z, int unitIdx);
|
// 放大系数滑块仅改面板内数值,点「应用」才统一生效(与面板其余项一致,不再实时)。
|
||||||
// 放大系数(=垂直夸张)滑块:拖动实时改数值标签,松手才发此信号触发一次重建。
|
void applied(AxisRange x, AxisRange y, AxisRange z, int unitIdx, double scale);
|
||||||
void verticalExaggerationChanged(double ve);
|
|
||||||
void closed(); // × 或 取消
|
void closed(); // × 或 取消
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -317,13 +317,15 @@ void VtkSceneView::rebuildAxes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneView::render(bool is2D) {
|
void VtkSceneView::render(bool is2D, bool resetCamera) {
|
||||||
// 视图区背景永远深色(规范 §0.5:不随明暗切换),让色阶数据更突出。
|
// 视图区背景永远深色(规范 §0.5:不随明暗切换),让色阶数据更突出。
|
||||||
double bgR, bgG, bgB;
|
double bgR, bgG, bgB;
|
||||||
geopro::app::vtkBackground(bgR, bgG, bgB);
|
geopro::app::vtkBackground(bgR, bgG, bgB);
|
||||||
scene_.renderer()->SetBackground(bgR, bgG, bgB);
|
scene_.renderer()->SetBackground(bgR, bgG, bgB);
|
||||||
// 坐标轴仅三维视图显示(2D 俯视测线不需要立体坐标轴)。
|
// 坐标轴仅三维视图显示(2D 俯视测线不需要立体坐标轴)。
|
||||||
if (!is2D) rebuildAxes();
|
if (!is2D) rebuildAxes();
|
||||||
|
// 相机预设(朝向)只在取景时应用——保留相机的重建(改放大系数)不重设朝向,否则也会跳视角。
|
||||||
|
if (resetCamera) {
|
||||||
if (is2D)
|
if (is2D)
|
||||||
geopro::render::applyTop2D(scene_.renderer());
|
geopro::render::applyTop2D(scene_.renderer());
|
||||||
else
|
else
|
||||||
|
|
@ -333,9 +335,10 @@ void VtkSceneView::render(bool is2D) {
|
||||||
scene_.renderer()->ResetCamera(bounds); // 取景到数据(不含底图,否则数据缩成小点)
|
scene_.renderer()->ResetCamera(bounds); // 取景到数据(不含底图,否则数据缩成小点)
|
||||||
else
|
else
|
||||||
scene_.renderer()->ResetCamera();
|
scene_.renderer()->ResetCamera();
|
||||||
|
}
|
||||||
scene_.renderer()->ResetCameraClippingRange(); // 裁剪面含底图 → 不被"蒙版"切掉
|
scene_.renderer()->ResetCameraClippingRange(); // 裁剪面含底图 → 不被"蒙版"切掉
|
||||||
if (renderWindow_) renderWindow_->Render();
|
if (renderWindow_) renderWindow_->Render();
|
||||||
if (onCameraChanged) onCameraChanged(); // 取景后 → 底图按新视锥重算覆盖
|
if (onCameraChanged) onCameraChanged(); // 相机/数据变了 → 底图按新视锥重算覆盖
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneView::renderIncremental() {
|
void VtkSceneView::renderIncremental() {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public:
|
||||||
void applyCameraView(geopro::controller::ViewDir dir) override;
|
void applyCameraView(geopro::controller::ViewDir dir) override;
|
||||||
void zoom(double factor) override;
|
void zoom(double factor) override;
|
||||||
void fitView() override;
|
void fitView() override;
|
||||||
void render(bool is2D) override;
|
void render(bool is2D, bool resetCamera = true) override;
|
||||||
void renderIncremental() override;
|
void renderIncremental() override;
|
||||||
|
|
||||||
// ── P3 切片交互:暴露当前体素 image(含 VE 烤入的 origin/spacing)供切片附着 ──
|
// ── P3 切片交互:暴露当前体素 image(含 VE 烤入的 origin/spacing)供切片附着 ──
|
||||||
|
|
|
||||||
|
|
@ -761,15 +761,24 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 三维体段右键删除:切片→deleteSlice / 异常→deleteAnomaly,删后刷新树。
|
// 三维体段右键删除:切片→deleteSlice / 异常→deleteAnomaly,删后刷新树。
|
||||||
|
// 异常删除须同时 refreshAnomalies(重载异常 actor)——否则列表行没了但场景里异常仍渲染(技术债,已修)。
|
||||||
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::deleteDatasetRequested, &window,
|
QObject::connect(analysisTab, &geopro::app::CategoryAnalysisTab::deleteDatasetRequested, &window,
|
||||||
[scene3dRepo, refreshAnalysis](const QString& dsId, const QString& ddCode) {
|
[scene3dRepo, refreshAnalysis, refreshAnomalies](const QString& dsId,
|
||||||
|
const QString& ddCode) {
|
||||||
const std::string id = dsId.toStdString();
|
const std::string id = dsId.toStdString();
|
||||||
auto ok = [refreshAnalysis]() { refreshAnalysis(); };
|
if (ddCode == QStringLiteral("dd_slice")) {
|
||||||
auto err = [](const std::string&) {};
|
scene3dRepo->deleteSlice(
|
||||||
if (ddCode == QStringLiteral("dd_slice"))
|
id, [refreshAnalysis]() { refreshAnalysis(); },
|
||||||
scene3dRepo->deleteSlice(id, ok, err);
|
[](const std::string&) {});
|
||||||
else if (ddCode == QStringLiteral("dd_anomaly"))
|
} else if (ddCode == QStringLiteral("dd_anomaly")) {
|
||||||
scene3dRepo->deleteAnomaly(id, ok, err);
|
scene3dRepo->deleteAnomaly(
|
||||||
|
id,
|
||||||
|
[refreshAnalysis, refreshAnomalies]() {
|
||||||
|
refreshAnalysis(); // 刷三维体段列表(异常行消失)
|
||||||
|
refreshAnomalies(); // 重载异常 actor(场景同步移除)
|
||||||
|
},
|
||||||
|
[](const std::string&) {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// (O点位置/字体、旧栏「生成三维体」「勾选→渲染」接线均已退役——分别由 analysisTab 的
|
// (O点位置/字体、旧栏「生成三维体」「勾选→渲染」接线均已退役——分别由 analysisTab 的
|
||||||
// generateVolumeRequested / checkedDatasetsChanged 接管。)
|
// generateVolumeRequested / checkedDatasetsChanged 接管。)
|
||||||
|
|
@ -943,11 +952,15 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
|
// 垂直夸张:地形须与剖面用同一 VE 才对齐(都按真实高程×VE)。单一来源 kVerticalExaggeration 下发
|
||||||
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
|
// 控制器(上方)/底图;运行时 VE 改由坐标轴设置抽屉「应用」下发(旧三维数据集栏滑块已退役)。
|
||||||
basemap->setVerticalExaggeration(kVerticalExaggeration);
|
basemap->setVerticalExaggeration(kVerticalExaggeration);
|
||||||
// 坐标轴设置抽屉「应用」:仅轴显示开关 + 单位 + per-axis 范围 → 走 setAxesConfig(已改增量重建,
|
// 坐标轴设置抽屉「应用」:一次性下发 轴显示/单位/范围(增量重建,不重绘数据)+ 放大系数(VE)。
|
||||||
// 不再清场景重绘数据)。放大系数=垂直夸张改由滑块独立信号下发(见下)。
|
// VE 改几何须重建,但走保留相机的重建(setVerticalExaggeration 内 preserveCamera)→ 当前视角直接
|
||||||
|
// 重绘,不再先跳远视角;底图同步 VE。仅在 VE 实际变化时下发,避免无谓重建。
|
||||||
|
auto lastVE = std::make_shared<double>(kVerticalExaggeration);
|
||||||
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::applied, &window,
|
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::applied, &window,
|
||||||
[axesPanel, sceneCtrl](geopro::app::AxisRange x, geopro::app::AxisRange y,
|
[axesPanel, sceneCtrl, basemap, lastVE](geopro::app::AxisRange x,
|
||||||
geopro::app::AxisRange z, int unitIdx) {
|
geopro::app::AxisRange y,
|
||||||
|
geopro::app::AxisRange z, int unitIdx,
|
||||||
|
double scale) {
|
||||||
const bool anyShow = x.show || y.show || z.show;
|
const bool anyShow = x.show || y.show || z.show;
|
||||||
// 每轴:可见性=显示开关;自定义范围=面板 min/max(按当前单位),真正改刻度。
|
// 每轴:可见性=显示开关;自定义范围=面板 min/max(按当前单位),真正改刻度。
|
||||||
auto cfg = [](const geopro::app::AxisRange& a) {
|
auto cfg = [](const geopro::app::AxisRange& a) {
|
||||||
|
|
@ -958,15 +971,13 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
unitIdx == 1 ? geopro::controller::AxesUnit::Feet
|
unitIdx == 1 ? geopro::controller::AxesUnit::Feet
|
||||||
: geopro::controller::AxesUnit::Meter,
|
: geopro::controller::AxesUnit::Meter,
|
||||||
cfg(x), cfg(y), cfg(z));
|
cfg(x), cfg(y), cfg(z));
|
||||||
|
if (scale > 0 && scale != *lastVE) { // 放大系数变化 → 保留相机重建 + 底图同步
|
||||||
|
*lastVE = scale;
|
||||||
|
sceneCtrl->setVerticalExaggeration(scale);
|
||||||
|
basemap->setVerticalExaggeration(scale);
|
||||||
|
}
|
||||||
axesPanel->hide();
|
axesPanel->hide();
|
||||||
});
|
});
|
||||||
// 放大系数滑块(=垂直夸张):松手即下发控制器 + 底图(VE 改几何须一次重建,但不在拖动中连续重建)。
|
|
||||||
QObject::connect(axesPanel, &geopro::app::AxesSettingsPanel::verticalExaggerationChanged, &window,
|
|
||||||
[sceneCtrl, basemap](double ve) {
|
|
||||||
if (ve <= 0) return;
|
|
||||||
sceneCtrl->setVerticalExaggeration(ve);
|
|
||||||
basemap->setVerticalExaggeration(ve);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ── 中央“空状态”引导浮层:未接入真实 sections 时,引导首次使用者从左侧入手。──
|
// ── 中央“空状态”引导浮层:未接入真实 sections 时,引导首次使用者从左侧入手。──
|
||||||
// 透明背景 + 鼠标穿透(不挡 QVTK 交互);CenterOverlay 随视口尺寸保持居中;
|
// 透明背景 + 鼠标穿透(不挡 QVTK 交互);CenterOverlay 随视口尺寸保持居中;
|
||||||
|
|
|
||||||
|
|
@ -81,16 +81,13 @@ public:
|
||||||
p->fillRect(QRect(opt.rect.left(), opt.rect.top(), 2, opt.rect.height()),
|
p->fillRect(QRect(opt.rect.left(), opt.rect.top(), 2, opt.rect.height()),
|
||||||
geopro::app::tokenColor("accent/primary"));
|
geopro::app::tokenColor("accent/primary"));
|
||||||
|
|
||||||
// 可勾选项:左侧画复选框(用当前 style 的指示器),文本整体右移。
|
// 可勾选项:左侧画复选框(用当前 style 的指示器),文本整体右移。容器节点(项目/GS/TM)不画
|
||||||
// 容器节点(项目/GS/TM)虽不画复选框,也保留同宽复选框列——否则其子级(带复选框)相对容器的
|
// 复选框、名称紧跟展开图标(左留白小,与对象树容器一致;勿为对齐子级而预留空复选框列,
|
||||||
// 视觉缩进 = 树级缩进 + 复选框列宽,比「子带框→孙带框」的缩进大一截(用户实测 #6:三维体段
|
// 否则容器名与展开图标间出现大段空白,见用户 #2 反馈)。
|
||||||
// 体相对 TM 缩进过大)。保留同宽列后各级缩进只差一个树级,与对象树一致。
|
|
||||||
const int box = 16;
|
|
||||||
const int checkColPad = 12 + box + 8; // 复选框列总宽(复选框 + 两侧留白)
|
|
||||||
int textLeftPad = 6;
|
int textLeftPad = 6;
|
||||||
const bool checkable = (idx.flags() & Qt::ItemIsUserCheckable);
|
const bool checkable = (idx.flags() & Qt::ItemIsUserCheckable);
|
||||||
const bool isContainer = idx.data(kDsDdCodeRole).toString() == QStringLiteral("container");
|
|
||||||
if (checkable) {
|
if (checkable) {
|
||||||
|
const int box = 16;
|
||||||
QRect checkRect(r.left() + 12, r.top() + (r.height() - box) / 2, box, box);
|
QRect checkRect(r.left() + 12, r.top() + (r.height() - box) / 2, box, box);
|
||||||
const auto cs = static_cast<Qt::CheckState>(idx.data(Qt::CheckStateRole).toInt());
|
const auto cs = static_cast<Qt::CheckState>(idx.data(Qt::CheckStateRole).toInt());
|
||||||
QStyleOptionViewItem o(opt);
|
QStyleOptionViewItem o(opt);
|
||||||
|
|
@ -100,9 +97,7 @@ public:
|
||||||
const QWidget* w = opt.widget;
|
const QWidget* w = opt.widget;
|
||||||
QStyle* st = w ? w->style() : QApplication::style();
|
QStyle* st = w ? w->style() : QApplication::style();
|
||||||
st->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &o, p, w);
|
st->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &o, p, w);
|
||||||
textLeftPad = checkColPad; // 复选框右侧留白后再放文本
|
textLeftPad = 12 + box + 8; // 复选框右侧留白后再放文本
|
||||||
} else if (isContainer) {
|
|
||||||
textLeftPad = checkColPad; // 容器保留同宽列(不画框),使子级缩进与对象树一致
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString title = disp, meta;
|
QString title = disp, meta;
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ DateRangeEdit::DateRangeEdit(QWidget* parent) : QWidget(parent) {
|
||||||
btn_, QStringLiteral(
|
btn_, QStringLiteral(
|
||||||
"QToolButton{background-color:{{bg/panel}};color:{{text/primary}};"
|
"QToolButton{background-color:{{bg/panel}};color:{{text/primary}};"
|
||||||
"border:1px solid {{border/default}};border-radius:4px;"
|
"border:1px solid {{border/default}};border-radius:4px;"
|
||||||
"padding:6px 24px 6px 8px;min-height:16px;text-align:left;"
|
"padding:6px 22px 6px 8px;min-height:16px;text-align:left;"
|
||||||
"background-image:url(:/icons/chevron-down.svg);background-repeat:no-repeat;"
|
"background-image:url(:/icons/chevron-down.svg);background-repeat:no-repeat;"
|
||||||
"background-position:right 8px center;}"
|
"background-origin:padding;background-position:right center;}"
|
||||||
"QToolButton:hover{border-color:{{border/strong}};}"));
|
"QToolButton:hover{border-color:{{border/strong}};}"));
|
||||||
connect(btn_, &QToolButton::clicked, this, &DateRangeEdit::openPopup);
|
connect(btn_, &QToolButton::clicked, this, &DateRangeEdit::openPopup);
|
||||||
lay->addWidget(btn_);
|
lay->addWidget(btn_);
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,9 @@ public:
|
||||||
// 适配全览(P2):ResetCamera 并提交渲染。
|
// 适配全览(P2):ResetCamera 并提交渲染。
|
||||||
virtual void fitView() = 0;
|
virtual void fitView() = 0;
|
||||||
|
|
||||||
// 应用相机预设(2D 俯视 / 3D 自由)并提交渲染(全量重建用,会 ResetCamera)。
|
// 应用相机预设(2D 俯视 / 3D 自由)并提交渲染(全量重建用)。resetCamera=true 时 ResetCamera 取景到
|
||||||
virtual void render(bool is2D) = 0;
|
// 数据;false 时保留当前相机(如改放大系数全量重建但要原地重绘,不跳远视角)。
|
||||||
|
virtual void render(bool is2D, bool resetCamera = true) = 0;
|
||||||
// 增量提交渲染:重建坐标轴并刷新,但不动相机(勾选/取消单个 ds 时视角不跳)。
|
// 增量提交渲染:重建坐标轴并刷新,但不动相机(勾选/取消单个 ds 时视角不跳)。
|
||||||
virtual void renderIncremental() = 0;
|
virtual void renderIncremental() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,12 @@ void VtkSceneController::setLayer(SceneLayer layer, bool on) {
|
||||||
|
|
||||||
void VtkSceneController::setVerticalExaggeration(double ve) {
|
void VtkSceneController::setVerticalExaggeration(double ve) {
|
||||||
verticalExaggeration_ = ve;
|
verticalExaggeration_ = ve;
|
||||||
|
// VE 烤进帘面 SetScale / 体素 image / 地形几何,须全量重建;但保留当前相机 → 原地按新夸张重绘,
|
||||||
|
// 不先跳远视角再回(用户反馈)。重建中 fitOnArrival_ 也置 false(见 rebuildInternal),
|
||||||
|
// 异步到场数据经 renderIncremental 在当前相机下显示。
|
||||||
|
preserveCameraOnRebuild_ = true;
|
||||||
rebuildInternal();
|
rebuildInternal();
|
||||||
|
preserveCameraOnRebuild_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneController::rebuild() { rebuildInternal(); }
|
void VtkSceneController::rebuild() { rebuildInternal(); }
|
||||||
|
|
@ -292,7 +297,7 @@ void VtkSceneController::rebuildInternal() {
|
||||||
// 坐标轴设置在 clear 后下发:render 末尾据当前场景包围盒重建坐标轴 prop。
|
// 坐标轴设置在 clear 后下发:render 末尾据当前场景包围盒重建坐标轴 prop。
|
||||||
view_.setAxes(axesMode_, axesUnit_, kAxesFontSize);
|
view_.setAxes(axesMode_, axesUnit_, kAxesFontSize);
|
||||||
view_.setAxesRanges(axisX_, axisY_, axisZ_);
|
view_.setAxesRanges(axisX_, axisY_, axisZ_);
|
||||||
fitOnArrival_ = true; // 全量重建:到场数据自动取景
|
fitOnArrival_ = !preserveCameraOnRebuild_; // 保留相机重建(改VE):到场数据不自动取景,留当前视角
|
||||||
|
|
||||||
// 坏 dsId(loadGrid/loadColorScale 抛异常)= best-effort 跳过:emit loadFailed 但不中断。
|
// 坏 dsId(loadGrid/loadColorScale 抛异常)= best-effort 跳过:emit loadFailed 但不中断。
|
||||||
try {
|
try {
|
||||||
|
|
@ -322,7 +327,8 @@ void VtkSceneController::rebuildInternal() {
|
||||||
emit loadFailed(QString::fromStdString(e.what()));
|
emit loadFailed(QString::fromStdString(e.what()));
|
||||||
}
|
}
|
||||||
|
|
||||||
view_.render(is2D); // 设背景/相机预设/坐标轴 + ResetCamera(数据到场再由 onDatasetArrived 取景)
|
// 保留相机重建(改VE):不 ResetCamera,原地按新夸张重绘。
|
||||||
|
view_.render(is2D, /*resetCamera=*/!preserveCameraOnRebuild_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace geopro::controller
|
} // namespace geopro::controller
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ private:
|
||||||
bool showVoxel_ = false;
|
bool showVoxel_ = false;
|
||||||
bool showTerrain_ = false;
|
bool showTerrain_ = false;
|
||||||
double verticalExaggeration_ = 1.0;
|
double verticalExaggeration_ = 1.0;
|
||||||
|
bool preserveCameraOnRebuild_ = false; // 改放大系数等:全量重建但保留当前相机(不跳远视角)
|
||||||
|
|
||||||
// 坐标轴设置(P2):默认标准 + 米;字号固定 12(字体设置待 1.0 确认)。
|
// 坐标轴设置(P2):默认标准 + 米;字号固定 12(字体设置待 1.0 确认)。
|
||||||
AxesMode axesMode_ = AxesMode::Standard;
|
AxesMode axesMode_ = AxesMode::Standard;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue