feat/vtk-3d-view #7
|
|
@ -27,6 +27,7 @@ constexpr double kEps = 1e-9;
|
|||
constexpr double kObserverPriority = 5.0; // 高于切片 widget 与右键菜单(1.0),绘制期独占
|
||||
constexpr double kDoubleClickMs = 350.0; // 左键双击闭合阈值
|
||||
constexpr int kClickSlopPx = 6; // 双击位置相近阈值(px)
|
||||
constexpr int kCloseSnapPx = 12; // 面:光标/点击邻近起点的吸附阈值(px)
|
||||
|
||||
double nowMs() {
|
||||
return std::chrono::duration<double, std::milli>(
|
||||
|
|
@ -60,10 +61,10 @@ void AnomalyDrawTool::start(DrawMode mode, const Vec3& planeOrigin, const Vec3&
|
|||
if (renderer_) {
|
||||
const char* tip =
|
||||
mode_ == DrawMode::Point
|
||||
? "标注点:左键落点 · 再点可重定位 · 双击/回车确认 · Esc 取消"
|
||||
? "标注点:左键单击落点即完成 · Esc 取消"
|
||||
: (mode_ == DrawMode::Line
|
||||
? "标注线:左键逐点 · Backspace 撤点 · 双击/回车完成 · Esc 取消"
|
||||
: "标注面:左键逐点 · Backspace 撤点 · 双击/回车闭合 · Esc 取消");
|
||||
? "标注线:左键逐点 · 双击完成 · Backspace 撤点 · Esc 取消"
|
||||
: "标注面:左键逐点 · 点回起点闭合 · Backspace 撤点 · Esc 取消");
|
||||
hint_ = vtkSmartPointer<vtkTextActor>::New();
|
||||
hint_->SetInput(tip);
|
||||
hint_->GetTextProperty()->SetFontSize(16);
|
||||
|
|
@ -123,6 +124,15 @@ Vec3 AnomalyDrawTool::pickOnPlane() const {
|
|||
return Vec3{{nearP[0] + t * dir[0], nearP[1] + t * dir[1], nearP[2] + t * dir[2]}};
|
||||
}
|
||||
|
||||
bool AnomalyDrawTool::nearFirstVertex(int sx, int sy) const {
|
||||
if (pts_.empty() || !renderer_) return false;
|
||||
renderer_->SetWorldPoint(pts_.front()[0], pts_.front()[1], pts_.front()[2], 1.0);
|
||||
renderer_->WorldToDisplay();
|
||||
double d[3];
|
||||
renderer_->GetDisplayPoint(d);
|
||||
return std::abs(d[0] - sx) <= kCloseSnapPx && std::abs(d[1] - sy) <= kCloseSnapPx;
|
||||
}
|
||||
|
||||
void AnomalyDrawTool::addVertex() {
|
||||
// 点模式:单点,再次左键 = 重定位(微调),不累积;线/面模式:累积顶点。
|
||||
if (mode_ == DrawMode::Point && !pts_.empty())
|
||||
|
|
@ -185,12 +195,13 @@ void AnomalyDrawTool::updateRubber() {
|
|||
if (interactor_) interactor_->Render();
|
||||
return;
|
||||
}
|
||||
// 末点 → 当前光标投影点 的虚线橡皮筋(跟手反馈)。
|
||||
// 末点 → 光标 的虚线橡皮筋(跟手反馈);面模式光标邻近起点 → 指向起点,预览闭合。
|
||||
const Vec3& a = pts_.back();
|
||||
const Vec3 endP = cursorNearStart_ ? pts_.front() : cursorPt_;
|
||||
vtkNew<vtkPoints> points;
|
||||
points->SetNumberOfPoints(2);
|
||||
points->SetPoint(0, a[0], a[1], a[2]);
|
||||
points->SetPoint(1, cursorPt_[0], cursorPt_[1], cursorPt_[2]);
|
||||
points->SetPoint(1, endP[0], endP[1], endP[2]);
|
||||
vtkNew<vtkPolyData> poly;
|
||||
poly->SetPoints(points);
|
||||
vtkNew<vtkPolyLine> line;
|
||||
|
|
@ -237,6 +248,9 @@ void AnomalyDrawTool::installObservers() {
|
|||
// 鼠标移动:更新末点→光标的虚线橡皮筋(跟手反馈)。不 abort,不干扰其它悬停。
|
||||
self->cursorPt_ = self->pickOnPlane();
|
||||
self->hasCursor_ = true;
|
||||
const int* mp = self->interactor_->GetEventPosition();
|
||||
self->cursorNearStart_ = self->mode_ == DrawMode::Face && self->pts_.size() >= 3 &&
|
||||
self->nearFirstVertex(mp[0], mp[1]);
|
||||
self->updateRubber();
|
||||
return;
|
||||
}
|
||||
|
|
@ -245,9 +259,21 @@ void AnomalyDrawTool::installObservers() {
|
|||
if (self->cmd_) self->cmd_->SetAbortFlag(1);
|
||||
switch (eid) {
|
||||
case vtkCommand::LeftButtonPressEvent: {
|
||||
// 左键双连击 = 闭合(标准多边形交互);否则加顶点。
|
||||
// 点:单击即落点并完成(业界通用,无需双击/回车)。
|
||||
if (self->mode_ == DrawMode::Point) {
|
||||
self->addVertex();
|
||||
self->finish();
|
||||
break;
|
||||
}
|
||||
const double now = nowMs();
|
||||
const int* p = self->interactor_->GetEventPosition();
|
||||
// 面:点回起点(屏幕邻近)闭合(≥3点),不加点。
|
||||
if (self->mode_ == DrawMode::Face && self->pts_.size() >= 3 &&
|
||||
self->nearFirstVertex(p[0], p[1])) {
|
||||
self->finish();
|
||||
break;
|
||||
}
|
||||
// 线:左键双连击 = 完成;否则加顶点。
|
||||
const bool dbl = self->lastClickMs_ >= 0.0 &&
|
||||
(now - self->lastClickMs_) < kDoubleClickMs &&
|
||||
std::abs(p[0] - self->lastClickX_) <= kClickSlopPx &&
|
||||
|
|
@ -256,7 +282,7 @@ void AnomalyDrawTool::installObservers() {
|
|||
self->lastClickX_ = p[0];
|
||||
self->lastClickY_ = p[1];
|
||||
if (dbl) {
|
||||
// 隔离单/双击:回滚"双击第一下"那次加点/移点(否则点会移、线多一段、面多一条边),再完成。
|
||||
// 隔离单/双击:回滚"双击第一下"那次加点(否则线多一段、面多一条边),再完成。
|
||||
self->pts_ = self->ptsBeforeClick_;
|
||||
self->updatePreview();
|
||||
self->finish();
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ private:
|
|||
void addVertex(); // 左键:加顶点
|
||||
void updatePreview(); // 重建已点几何(顶点圆点 + 实线折线;单点也可见)
|
||||
void updateRubber(); // 鼠标移动:末点→光标的虚线橡皮筋
|
||||
void finish(); // 右键/双击/回车:闭合
|
||||
void finish(); // 双击/回车/(面)点起点:完成
|
||||
Vec3 pickOnPlane() const; // 当前鼠标屏幕点 → 射线与平面交点
|
||||
bool nearFirstVertex(int sx, int sy) const; // 屏幕点是否邻近起点(面闭合判定/提示)
|
||||
|
||||
void installObservers();
|
||||
void removeObservers();
|
||||
|
|
@ -64,6 +65,7 @@ private:
|
|||
vtkSmartPointer<vtkTextActor> hint_; // 屏幕操作提示
|
||||
Vec3 cursorPt_{{0, 0, 0}}; // 当前鼠标在切面上的投影点
|
||||
bool hasCursor_ = false;
|
||||
bool cursorNearStart_ = false; // 面模式光标邻近起点 → 橡皮筋指向起点预览闭合
|
||||
vtkSmartPointer<vtkCallbackCommand> cmd_;
|
||||
unsigned long tagLeft_ = 0, tagMove_ = 0, tagRight_ = 0, tagKey_ = 0, tagDbl_ = 0;
|
||||
// 双击闭合检测(左键两连击):记上次左键时刻 + 屏幕位置。
|
||||
|
|
|
|||
Loading…
Reference in New Issue