mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 14:22:33 +00:00
wgpu: area measurement tool (A hotkey, BFS coplanar patch + cyan highlight)
Ports Bonsai's AreaMeasurement onto WgpuViewportWindow as a new WgpuAreaMeasurement class. Each LMB pick resolves to (instance, triangle), BFS-expands the coplanar patch (dot(normal, seed_normal) > 0.9999, ~0.81° tolerance), and toggles it in/out of the running set. Alt+LMB skips BFS for single-triangle accumulate. Connected-components sweep over the selected set produces one "X.XXXX m²" label per patch at its area-weighted centroid in world space; HUD shows the running total + triangle count. Dependencies layered in: - WgpuOverlayRenderer.setHighlightTriangles / encodeHighlightTriangles: translucent world-space triangle list (cyan @ 0.45 alpha), depth- tested but depth-write off so the corner gizmo + labels still sit on top. - WgpuViewportWindow.pickMeshLocalAt: reuses pickSurfaceAt for the world hit, then inverts the instance's composed transform to express it in mesh-local space — what the BFS needs. Uses the live map key (`mid`) rather than InstanceCpu.model_id, which is whatever the GL streamer wrote at sidecar-write time and goes stale across sessions. - WgpuViewportWindow.readbackMeshTriangles: CPU mesh shadow lookup. The shadow itself is populated during the same dequant pass that computes mesh-local volume — applyCachedModel for full loads and applyStreamedChunk for streaming, so the BFS has data the moment the user can pick it. WgpuModelGpuData gains a MeshTriangles vector indexed by mesh_id; doubles per-vertex CPU memory (12 B/vert) but skips wgpu mapAsync plumbing for now. Bounds-check at pick time gracefully no-ops when a stale sidecar field is out of range. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
@@ -282,6 +283,7 @@ private:
|
||||
void clearSectionPlanes();
|
||||
int sectionPlaneCount() const { return int(section_planes_.size()); }
|
||||
|
||||
public:
|
||||
// Overlay primitives. Mirror GL ViewportWindow so the Measurement +
|
||||
// dimension tools can target either backend through one API.
|
||||
// Empty inputs clears the corresponding set.
|
||||
@@ -294,14 +296,44 @@ private:
|
||||
float stroke_extra);
|
||||
void setOverlayLabels(const std::vector<WgpuOverlayRenderer::Label>& labels);
|
||||
void setHudText(const QString& text);
|
||||
// Translucent world-space triangle overlay (Area-tool patch shading).
|
||||
// Empty list disables; color is RGBA in [0, 1].
|
||||
void setHighlightTriangles(const std::vector<float>& world_xyz,
|
||||
float r, float g, float b, float a);
|
||||
|
||||
// CPU mesh shadow: positions (3 floats/vert, mesh-local) + indices
|
||||
// (LOD0). Populated at applyCachedModel / applyStreamedChunk —
|
||||
// returns false if the mesh isn't loaded yet (streaming) or the
|
||||
// (model_id, mesh_id) pair doesn't resolve. Matches the GL
|
||||
// ViewportWindow::MeshTriangles + readbackMeshTriangles shape so
|
||||
// the measure tools port verbatim.
|
||||
using MeshTriangles = WgpuModelGpuData::MeshTriangles;
|
||||
bool readbackMeshTriangles(uint32_t model_id, uint32_t mesh_id,
|
||||
MeshTriangles& out) const;
|
||||
|
||||
// Pick + resolve to mesh-local space. Runs pickSurfaceAt to get the
|
||||
// world-space hit, then inverts the instance's composed transform
|
||||
// to express the hit in the mesh's own coordinates — what
|
||||
// readbackMeshTriangles returns. Returns false on miss.
|
||||
struct MeshLocalPick {
|
||||
uint32_t object_id = 0;
|
||||
uint32_t model_id = 0;
|
||||
uint32_t mesh_id = 0;
|
||||
float mesh_local [3] = {0, 0, 0};
|
||||
float world_pos [3] = {0, 0, 0};
|
||||
float world_normal[3] = {0, 0, 0};
|
||||
float composed_transform[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
};
|
||||
bool pickMeshLocalAt(int x, int y, MeshLocalPick& out);
|
||||
|
||||
// Measurement tools. Mirrors GL ViewportWindow::ToolMode. Volume is
|
||||
// the first ported tool — selection-driven (LMB pick / marquee /
|
||||
// Shift/Ctrl set ops drive the readout), no clicks-to-place. V
|
||||
// toggles, Esc exits.
|
||||
// selection-driven (LMB / marquee). Area is click-to-accumulate:
|
||||
// each LMB picks a triangle and either adds or removes its
|
||||
// coplanar patch via BFS over shared edges; Alt+LMB skips the BFS.
|
||||
// V/A toggle, Esc exits.
|
||||
// NoTool (not None) because X11/X.h #define's None as 0L; including
|
||||
// it transitively via Qt's xcb back-end breaks any enum named None.
|
||||
enum class ToolMode { NoTool, Volume };
|
||||
enum class ToolMode { NoTool, Volume, Area };
|
||||
ToolMode toolMode() const { return tool_mode_; }
|
||||
void setToolMode(ToolMode m);
|
||||
|
||||
@@ -311,6 +343,7 @@ private:
|
||||
// value means winding is ignored. Volumes are precomputed at
|
||||
// applyCachedModel — this call is just lookups + multiplies.
|
||||
double volumeOfObjects(const std::vector<uint32_t>& object_ids) const;
|
||||
private:
|
||||
// Per-object variant. Used by the Volume tool to drive both the
|
||||
// total HUD and the per-object overlay labels at AABB centres.
|
||||
std::vector<std::pair<uint32_t, double>>
|
||||
@@ -499,6 +532,13 @@ private:
|
||||
// after entering Volume mode this primes the overlay.
|
||||
void updateVolumeReadout();
|
||||
|
||||
// Area tool state lives in WgpuAreaMeasurement (header below). The
|
||||
// viewport owns it for the session and routes LMB picks in Area
|
||||
// mode through onAreaPick.
|
||||
std::unique_ptr<class WgpuAreaMeasurement> area_tool_;
|
||||
void onAreaPick(int x_phys, int y_phys, bool alt);
|
||||
void updateAreaHud();
|
||||
|
||||
// Pick pass (stage 4). Single-sample R32UInt target + depth, vertex-
|
||||
// pulled from the same visible_draws / instances buffers as the main
|
||||
// pass — pick fragment outputs the instance's object_id. The pick
|
||||
|
||||
Reference in New Issue
Block a user