mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
ifcviewer-full: length tool (2/3/4+ point distance, angle, polygon area)
ViewportWindow trades the area_tool_active_ bool for an enum ToolMode
{None, Area, Length}; the existing surfacePickedInTool signal carries
both, the app dispatches on toolMode(). Esc exits any active tool;
Backspace/Delete in length mode emits toolBackspacePressed which the
length tool uses to remove the last point.
LengthMeasurement collects clicked world-space points and adapts the
readout: 2pt → distance + axis-aligned ΔX/ΔY/ΔZ, 3pt → angle at the
middle vertex + triangle area, 4+pt → best-fit-plane PCA + shoelace
when planar (RMS plane distance / bbox diag < 1e-3) else fan
triangulation, with the chosen method labelled in the readout. Per-
segment lengths float at each midpoint.
OverlayRenderer grows three new pipelines to support this:
- point sprite shader: gl_PointCoord-based outlined disc with
fwidth-smoothed inner/stroke bands, a single draw call.
- line shader: CPU-expand each segment to 6 verts carrying both
endpoints + (side, along) corner index; vertex shader computes
the screen-space perpendicular and offsets accordingly. Real
outlined lines independent of the driver's glLineWidth clamp.
- screen-space rect shader: HUD + label backgrounds drawn as raw
GL quads in NDC. QPainter::fillRect on QOpenGLPaintDevice was
silently dropping fills across drivers; bypassing it entirely
via this shader makes backgrounds reliable. Cull-face is also
explicitly disabled here — GL_TRIANGLES respects it but the
line/point primitives don't, so this was the one path needing
the fix.
setOverlayLines / setOverlayPoints take an inner color, an outline
color, and an extra-pixels-per-side stroke amount. Lines + points
draw with GL_ALWAYS so measurement annotations stay visible through
geometry; highlight tris stay depth-aware (GL_LEQUAL) so area
shading still tints the surface in place.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1690,12 +1690,19 @@ void ViewportWindow::keyPressEvent(QKeyEvent* event) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Esc also exits the area tool.
|
||||
if (area_tool_active_
|
||||
&& key == Qt::Key_Escape
|
||||
&& !event->isAutoRepeat()) {
|
||||
toggleAreaTool();
|
||||
return;
|
||||
// Esc exits any active measurement tool. Backspace/Delete in length
|
||||
// mode removes the last point — emitted as a signal because the
|
||||
// library doesn't track per-tool semantic state.
|
||||
if (tool_mode_ != ToolMode::None && !event->isAutoRepeat()) {
|
||||
if (key == Qt::Key_Escape) {
|
||||
setToolMode(ToolMode::None);
|
||||
return;
|
||||
}
|
||||
if (tool_mode_ == ToolMode::Length
|
||||
&& (key == Qt::Key_Backspace || key == Qt::Key_Delete)) {
|
||||
emit toolBackspacePressed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QWindow::keyPressEvent(event);
|
||||
}
|
||||
@@ -3492,7 +3499,7 @@ void ViewportWindow::handleMouseRelease(QMouseEvent* e) {
|
||||
if (active_button_ == Qt::LeftButton
|
||||
&& !section_tool_active_
|
||||
&& (e->pos() - last_mouse_pos_).manhattanLength() < 5) {
|
||||
if (area_tool_active_) {
|
||||
if (tool_mode_ != ToolMode::None) {
|
||||
emit surfacePickedInTool(e->pos().x(), e->pos().y(),
|
||||
int(e->modifiers()));
|
||||
} else {
|
||||
@@ -3868,9 +3875,18 @@ bool ViewportWindow::pickMeshLocalAt(int x, int y, MeshLocalPick& out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewportWindow::setToolMode(ToolMode mode) {
|
||||
if (tool_mode_ == mode) return;
|
||||
tool_mode_ = mode;
|
||||
emit toolModeChanged(mode);
|
||||
}
|
||||
|
||||
void ViewportWindow::toggleAreaTool() {
|
||||
area_tool_active_ = !area_tool_active_;
|
||||
emit areaToolToggled(area_tool_active_);
|
||||
setToolMode(tool_mode_ == ToolMode::Area ? ToolMode::None : ToolMode::Area);
|
||||
}
|
||||
|
||||
void ViewportWindow::toggleLengthTool() {
|
||||
setToolMode(tool_mode_ == ToolMode::Length ? ToolMode::None : ToolMode::Length);
|
||||
}
|
||||
|
||||
void ViewportWindow::setHighlightTriangles(const std::vector<float>& world_xyz,
|
||||
@@ -3881,6 +3897,35 @@ void ViewportWindow::setHighlightTriangles(const std::vector<float>& world_xyz,
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::setOverlayLines(const std::vector<float>& world_xyz,
|
||||
float r, float g, float b, float a,
|
||||
float line_width,
|
||||
float sr, float sg, float sb, float sa,
|
||||
float stroke_extra) {
|
||||
if (!gl_initialized_) return;
|
||||
context_->makeCurrent(this);
|
||||
overlay_renderer_.setOverlayLines(world_xyz, r, g, b, a, line_width,
|
||||
sr, sg, sb, sa, stroke_extra);
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::setOverlayPoints(const std::vector<float>& world_xyz,
|
||||
float r, float g, float b, float a,
|
||||
float pixel_size,
|
||||
float sr, float sg, float sb, float sa,
|
||||
float stroke_extra) {
|
||||
if (!gl_initialized_) return;
|
||||
context_->makeCurrent(this);
|
||||
overlay_renderer_.setOverlayPoints(world_xyz, r, g, b, a, pixel_size,
|
||||
sr, sg, sb, sa, stroke_extra);
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::setOverlayLabels(const std::vector<OverlayRenderer::Label>& labels) {
|
||||
overlay_renderer_.setOverlayLabels(labels);
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::setHudText(const QString& text) {
|
||||
overlay_renderer_.setHudText(text);
|
||||
requestUpdate();
|
||||
|
||||
Reference in New Issue
Block a user