From 8cf7d4346d2d90b586922691e8b0fb5fa78e8392 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 5 Jun 2026 15:37:47 +1000 Subject: [PATCH] ifcviewer: move volume readout helpers into ViewportCore (#84-j) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tiny followup to #84-i — move the const-lookup volume helpers used by bonsai's measurement HUD: double volumeOfObjects(const std::vector&) const vector> volumesPerObject( const std::vector&) const The det3OfPlacement static helper moves with them into ViewportCore.cpp's anonymous namespace (the original kept its mirror in ViewportWindow.cpp; ViewportWindow's own internal callers are gone now since these methods moved). Pure read of models_gpu_ + mesh_local_volumes — all in core already. Trivial transplant. Builds: desktop / bonsai / web all green. Tests 100/100. --- src/ifcviewer/ViewportCore.cpp | 54 ++++++++++++++++++++++++++++++++ src/ifcviewer/ViewportCore.h | 13 ++++++++ src/ifcviewer/ViewportWindow.cpp | 35 ++------------------- 3 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/ifcviewer/ViewportCore.cpp b/src/ifcviewer/ViewportCore.cpp index e853f9c042..453dea768c 100644 --- a/src/ifcviewer/ViewportCore.cpp +++ b/src/ifcviewer/ViewportCore.cpp @@ -489,3 +489,57 @@ bool ViewportCore::computeObjectAabb(uint32_t object_id, mx = Eigen::Vector3f(fmax[0], fmax[1], fmax[2]); return true; } + +// |det| of the 3×3 linear part of a column-major double[16] placement +// matrix. Picks up uniform scale + mirror so a 2× clone of a 1m³ mesh +// reports 8m³. Used by the volume readout below. +namespace { +double det3OfPlacement(const double M[16]) { + const double m00 = M[0], m10 = M[1], m20 = M[2]; + const double m01 = M[4], m11 = M[5], m21 = M[6]; + const double m02 = M[8], m12 = M[9], m22 = M[10]; + return m00 * (m11 * m22 - m12 * m21) + - m01 * (m10 * m22 - m12 * m20) + + m02 * (m10 * m21 - m11 * m20); +} +} // namespace + +double ViewportCore::volumeOfObjects( + const std::vector& object_ids) const { + if (object_ids.empty()) return 0.0; + double total = 0.0; + for (uint32_t oid : object_ids) { + for (const auto& [mid, m] : models_gpu_) { + auto it = m.object_id_to_instance.find(oid); + if (it == m.object_id_to_instance.end()) continue; + const InstanceCpu& inst = m.instances[it->second]; + if (inst.mesh_id >= m.mesh_local_volumes.size()) break; + const double v_local = m.mesh_local_volumes[inst.mesh_id]; + const double det = std::abs(det3OfPlacement(inst.placement_transformation)); + total += v_local * det; + break; // object_id is globally unique → at most one hit + } + } + return total; +} + +std::vector> +ViewportCore::volumesPerObject( + const std::vector& object_ids) const { + std::vector> out; + if (object_ids.empty()) return out; + out.reserve(object_ids.size()); + for (uint32_t oid : object_ids) { + for (const auto& [mid, m] : models_gpu_) { + auto it = m.object_id_to_instance.find(oid); + if (it == m.object_id_to_instance.end()) continue; + const InstanceCpu& inst = m.instances[it->second]; + if (inst.mesh_id >= m.mesh_local_volumes.size()) break; + const double v_local = m.mesh_local_volumes[inst.mesh_id]; + const double det = std::abs(det3OfPlacement(inst.placement_transformation)); + out.emplace_back(oid, v_local * det); + break; + } + } + return out; +} diff --git a/src/ifcviewer/ViewportCore.h b/src/ifcviewer/ViewportCore.h index 6e3ef003ec..6ad25e1cf5 100644 --- a/src/ifcviewer/ViewportCore.h +++ b/src/ifcviewer/ViewportCore.h @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "BufferPool.h" #include "InstanceCompose.h" @@ -158,6 +160,17 @@ public: bool computeObjectAabb(uint32_t object_id, Eigen::Vector3f& mn, Eigen::Vector3f& mx) const; + // Sum of mesh-local volumes (m³) of every instance whose object_id + // is in `object_ids`. Each instance is scaled by |det(placement_3x3)| + // to pick up mapped-item scale/mirror; signed-tetrahedra absolute + // value means winding is ignored. Volumes are precomputed at + // applyCachedModel — this call is just lookups + multiplies. + double volumeOfObjects(const std::vector& object_ids) const; + // 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> + volumesPerObject(const std::vector& object_ids) const; + // Friend access for ViewportWindow's reference proxies. As each // render method moves into ViewportCore it stops needing these // (it touches the fields directly); once everything has migrated diff --git a/src/ifcviewer/ViewportWindow.cpp b/src/ifcviewer/ViewportWindow.cpp index 493030276c..0b0bb8a341 100644 --- a/src/ifcviewer/ViewportWindow.cpp +++ b/src/ifcviewer/ViewportWindow.cpp @@ -3547,44 +3547,15 @@ void ViewportWindow::setToolMode(ToolMode m) { if (isExposed()) requestUpdate(); } +// volumeOfObjects / volumesPerObject moved to ViewportCore (#84-j). double ViewportWindow::volumeOfObjects( const std::vector& object_ids) const { - if (object_ids.empty()) return 0.0; - double total = 0.0; - for (uint32_t oid : object_ids) { - for (const auto& [mid, m] : models_gpu_) { - auto it = m.object_id_to_instance.find(oid); - if (it == m.object_id_to_instance.end()) continue; - const InstanceCpu& inst = m.instances[it->second]; - if (inst.mesh_id >= m.mesh_local_volumes.size()) break; - const double v_local = m.mesh_local_volumes[inst.mesh_id]; - const double det = std::abs(det3OfPlacement(inst.placement_transformation)); - total += v_local * det; - break; // object_id is globally unique → at most one hit - } - } - return total; + return core_.volumeOfObjects(object_ids); } - std::vector> ViewportWindow::volumesPerObject( const std::vector& object_ids) const { - std::vector> out; - if (object_ids.empty()) return out; - out.reserve(object_ids.size()); - for (uint32_t oid : object_ids) { - for (const auto& [mid, m] : models_gpu_) { - auto it = m.object_id_to_instance.find(oid); - if (it == m.object_id_to_instance.end()) continue; - const InstanceCpu& inst = m.instances[it->second]; - if (inst.mesh_id >= m.mesh_local_volumes.size()) break; - const double v_local = m.mesh_local_volumes[inst.mesh_id]; - const double det = std::abs(det3OfPlacement(inst.placement_transformation)); - out.emplace_back(oid, v_local * det); - break; - } - } - return out; + return core_.volumesPerObject(object_ids); } void ViewportWindow::updateVolumeReadout() {