fix(3d): 异常绘制提示中文乱码(改 QLabel 浮层) + 列表切到别对象清切片选中
1) 提示"乱码":vtkTextActor 用 VTK 内置字体不含中文字形 → 中文渲染不出(只剩 ASCII)。 移除 VTK 文本提示,改 app 层右上角 QLabel 浮层:Qt 渲染中文 + QSS(深底/accent描边/圆角), 绘制开始按形态显示结束方式、结束/取消隐藏;不挡画布鼠标。 2) 列表选中切片后切到别的对象(三维体/异常),VTK 切片仍高亮:datasetSelected 选非切片对象时 未清切片选中。加 InteractionManager::deselectSlice();选异常/其它对象均清切片高亮(异常↔切片互斥)。 测试:439/439 通过
This commit is contained in:
parent
9782a2b93e
commit
f230ca8dd1
|
|
@ -398,6 +398,17 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
viewToolbar->move(12, 12);
|
||||
viewToolbar->raise();
|
||||
viewToolbar->show();
|
||||
// 异常绘制操作提示:右上角 QLabel 浮层(VTK 内置字体不含中文字形,故用 Qt 渲染中文 + QSS 美化)。
|
||||
// 深底 + accent 描边;不挡画布鼠标事件;绘制开始显示、结束/取消隐藏(见 onSliceContextMenuRequested)。
|
||||
auto* anomalyHint = new QLabel(vtkWidget);
|
||||
anomalyHint->setObjectName(QStringLiteral("anomalyHint"));
|
||||
anomalyHint->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
geopro::app::applyTokenizedStyleSheet(
|
||||
anomalyHint,
|
||||
QStringLiteral("QLabel#anomalyHint{background:rgba(10,18,30,0.85);color:#E6ECF5;"
|
||||
"border:1px solid {{accent/primary}};border-radius:8px;padding:8px 12px;}"));
|
||||
anomalyHint->hide();
|
||||
|
||||
// 坐标轴设置抽屉面板:叠加 vtkWidget、工具条右侧滑出,默认隐藏(点设置 toggle)。
|
||||
auto* axesPanel = new geopro::app::AxesSettingsPanel(vtkWidget);
|
||||
axesPanel->hide();
|
||||
|
|
@ -506,7 +517,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
// 正视/翻转/关闭=接现有交互(关闭已保存切片→onSliceClosed 取消列表勾选);创建异常=占位(#4)。
|
||||
interactionMgr->onSliceContextMenuRequested =
|
||||
[&window, &cmdRepo, &nav, interactionMgr, sceneView, scene3dRepo, refreshAnalysis,
|
||||
refreshAnomalies, drawer, anomalyDrawTool, renderWindowPtr]() {
|
||||
refreshAnomalies, drawer, anomalyDrawTool, renderWindowPtr, anomalyHint, vtkWidget]() {
|
||||
QMenu menu(&window);
|
||||
QMenu* anomMenu = menu.addMenu(QStringLiteral("创建异常")); // → 点/线/面 子菜单
|
||||
QAction* aAnoPoint = anomMenu->addAction(QStringLiteral("点"));
|
||||
|
|
@ -543,6 +554,16 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
const ri::Vec3 e1{{p1[0] - o[0], p1[1] - o[1], p1[2] - o[2]}};
|
||||
const ri::Vec3 e2{{p2[0] - o[0], p2[1] - o[1], p2[2] - o[2]}};
|
||||
const ri::Vec3 normal = ri::normalize(ri::cross(e1, e2));
|
||||
// 操作提示浮层(右上角):按形态显示结束方式;绘制结束/取消隐藏。
|
||||
anomalyHint->setText(
|
||||
shape == 1 ? QStringLiteral("标注点\n左键单击落点即完成\nEsc 取消")
|
||||
: shape == 2
|
||||
? QStringLiteral("标注线\n左键逐点 · 双击结束\nBackspace 撤点 · Esc 取消")
|
||||
: QStringLiteral("标注面\n左键逐点 · 点回起点闭合\nBackspace 撤点 · Esc 取消"));
|
||||
anomalyHint->adjustSize();
|
||||
anomalyHint->move(vtkWidget->width() - anomalyHint->width() - 12, 12); // 右上角
|
||||
anomalyHint->show();
|
||||
anomalyHint->raise();
|
||||
// 多体并发:异常挂到"选中切片所属体"(非 currentVolume),无选中切片回退当前体。
|
||||
std::string volId = interactionMgr->selectedSliceVolumeDsId();
|
||||
if (volId.empty()) volId = sceneView->currentVolumeDsId();
|
||||
|
|
@ -551,8 +572,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
anomalyDrawTool->start(
|
||||
mode, o, normal,
|
||||
[&window, &cmdRepo, &nav, interactionMgr, sceneView, scene3dRepo, renderWindowPtr,
|
||||
refreshAnomalies, refreshAnalysis, volId, savedSliceId, normal, o, p1, p2,
|
||||
shape](const std::vector<ri::Vec3>& worldPts) {
|
||||
refreshAnomalies, refreshAnalysis, volId, savedSliceId, normal, o, p1, p2, shape,
|
||||
anomalyHint](const std::vector<ri::Vec3>& worldPts) {
|
||||
anomalyHint->hide(); // 绘制结束 → 隐藏操作提示
|
||||
// 草稿异常:先临时渲染(让用户在对话框前看到所画,且截图含异常)。
|
||||
geopro::core::Anomaly a;
|
||||
a.markType = static_cast<geopro::core::AnomalyMarkType>(shape);
|
||||
|
|
@ -632,7 +654,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
QString::fromStdString(m));
|
||||
});
|
||||
},
|
||||
[]() { /* onCancel:放弃,无需处理 */ });
|
||||
[anomalyHint]() { anomalyHint->hide(); }); // 取消(Esc)→隐藏提示
|
||||
return;
|
||||
}
|
||||
if (aSave != nullptr && chosen == aSave) {
|
||||
|
|
@ -991,12 +1013,16 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
[sceneView, interactionMgr, renderWindowPtr](const QString& dsId,
|
||||
const QString& ddCode) {
|
||||
const std::string id = dsId.toStdString();
|
||||
// 选中项决定高亮:异常↔切片互斥,选其它对象两者都清(否则切到别的对象后切片/异常仍高亮)。
|
||||
if (ddCode == QStringLiteral("dd_anomaly")) {
|
||||
sceneView->setSelectedAnomaly(id);
|
||||
} else {
|
||||
sceneView->setSelectedAnomaly(std::string{}); // 选中非异常对象→清异常高亮
|
||||
if (ddCode == QStringLiteral("dd_slice"))
|
||||
interactionMgr->deselectSlice();
|
||||
} else if (ddCode == QStringLiteral("dd_slice")) {
|
||||
sceneView->setSelectedAnomaly(std::string{});
|
||||
interactionMgr->selectSavedSlice(id); // 选中已渲染的该切片(高亮)
|
||||
} else {
|
||||
sceneView->setSelectedAnomaly(std::string{});
|
||||
interactionMgr->deselectSlice();
|
||||
}
|
||||
renderWindowPtr->Render();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
#include <vtkProperty.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkRenderer.h>
|
||||
#include <vtkTextActor.h>
|
||||
#include <vtkTextProperty.h>
|
||||
|
||||
namespace geopro::render::interact {
|
||||
|
||||
|
|
@ -55,34 +53,9 @@ void AnomalyDrawTool::start(DrawMode mode, const Vec3& planeOrigin, const Vec3&
|
|||
hasCursor_ = false;
|
||||
active_ = true;
|
||||
installObservers();
|
||||
|
||||
// 屏幕操作提示(右上角,避开左侧工具条):标题 + 当前形态的结束方式 + 取消,分行排版。
|
||||
if (renderer_) {
|
||||
const char* tip =
|
||||
mode_ == DrawMode::Point
|
||||
? "标注点\n左键单击落点即完成\nEsc 取消"
|
||||
: (mode_ == DrawMode::Line
|
||||
? "标注线\n左键逐点 · 双击结束\nBackspace 撤点 · Esc 取消"
|
||||
: "标注面\n左键逐点 · 点回起点闭合\nBackspace 撤点 · Esc 取消");
|
||||
hint_ = vtkSmartPointer<vtkTextActor>::New();
|
||||
hint_->SetInput(tip);
|
||||
auto* tp = hint_->GetTextProperty();
|
||||
tp->SetFontSize(15);
|
||||
tp->SetLineSpacing(1.3);
|
||||
tp->SetColor(0.90, 0.94, 1.0); // 近白(canvas-text)
|
||||
tp->SetJustificationToRight(); // 右对齐,贴右上
|
||||
tp->SetVerticalJustificationToTop();
|
||||
tp->SetBackgroundColor(0.04, 0.07, 0.12); // 深底
|
||||
tp->SetBackgroundOpacity(0.66);
|
||||
tp->SetFrame(1);
|
||||
tp->SetFrameColor(0.37, 0.55, 0.96); // accent 描边
|
||||
tp->SetFrameWidth(1);
|
||||
hint_->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
|
||||
hint_->GetPositionCoordinate()->SetValue(0.985, 0.975); // 右上角
|
||||
renderer_->AddViewProp(hint_);
|
||||
// 操作提示由 app 层 QLabel 浮层承担(VTK 内置字体不含中文字形 → vtkTextActor 渲染不出中文)。
|
||||
if (interactor_) interactor_->Render();
|
||||
}
|
||||
}
|
||||
|
||||
void AnomalyDrawTool::cancel() {
|
||||
if (!active_) return;
|
||||
|
|
@ -97,11 +70,9 @@ void AnomalyDrawTool::teardownActive() {
|
|||
if (renderer_) {
|
||||
if (preview_) renderer_->RemoveViewProp(preview_);
|
||||
if (rubber_) renderer_->RemoveViewProp(rubber_);
|
||||
if (hint_) renderer_->RemoveViewProp(hint_);
|
||||
}
|
||||
preview_ = nullptr;
|
||||
rubber_ = nullptr;
|
||||
hint_ = nullptr;
|
||||
active_ = false;
|
||||
hasCursor_ = false;
|
||||
pts_.clear();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
class vtkRenderWindowInteractor;
|
||||
class vtkRenderer;
|
||||
class vtkActor;
|
||||
class vtkTextActor;
|
||||
class vtkCallbackCommand;
|
||||
|
||||
namespace geopro::render::interact {
|
||||
|
|
@ -61,7 +60,6 @@ private:
|
|||
|
||||
vtkSmartPointer<vtkActor> preview_; // 已点几何(顶点圆点 + 实线折线)
|
||||
vtkSmartPointer<vtkActor> rubber_; // 末点→光标 虚线橡皮筋
|
||||
vtkSmartPointer<vtkTextActor> hint_; // 屏幕操作提示
|
||||
Vec3 cursorPt_{{0, 0, 0}}; // 当前鼠标在切面上的投影点
|
||||
bool hasCursor_ = false;
|
||||
bool cursorNearStart_ = false; // 面模式光标邻近起点 → 橡皮筋指向起点预览闭合
|
||||
|
|
|
|||
|
|
@ -206,6 +206,13 @@ bool InteractionManager::selectSavedSlice(const std::string& dsId) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void InteractionManager::deselectSlice() {
|
||||
if (selected_ < 0) return;
|
||||
selected_ = -1;
|
||||
updateSelectionVisual(); // 清高亮(无选中切片)
|
||||
safeRender();
|
||||
}
|
||||
|
||||
void InteractionManager::selectByTool(const SliceTool* tool) {
|
||||
int idx = -1;
|
||||
for (std::size_t i = 0; i < slices_.size(); ++i)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ public:
|
|||
std::vector<std::string> shownSavedSliceIds() const; // 当前已显示的已保存切片 dsId 列表
|
||||
// 选中已显示的某 dsId 切片(列表操作定位到对应渲染切片);找到返回 true。
|
||||
bool selectSavedSlice(const std::string& dsId);
|
||||
// 清除切片选中(列表选中切到别的对象/异常时调用,否则 VTK 切片仍高亮,用户反馈)。
|
||||
void deselectSlice();
|
||||
|
||||
// 关闭选中切片(E56)。无选中则忽略。
|
||||
void closeSelected();
|
||||
|
|
|
|||
Loading…
Reference in New Issue