mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 14:48:02 +00:00
ifcviewer: move volume readout helpers into ViewportCore (#84-j)
Tiny followup to #84-i — move the const-lookup volume helpers used by
bonsai's measurement HUD:
double volumeOfObjects(const std::vector<uint32_t>&) const
vector<pair<uint32_t, double>> volumesPerObject(
const std::vector<uint32_t>&) 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.
This commit is contained in:
@@ -489,3 +489,57 @@ bool ViewportCore::computeObjectAabb(uint32_t object_id,
|
|||||||
mx = Eigen::Vector3f(fmax[0], fmax[1], fmax[2]);
|
mx = Eigen::Vector3f(fmax[0], fmax[1], fmax[2]);
|
||||||
return true;
|
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<uint32_t>& 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<std::pair<uint32_t, double>>
|
||||||
|
ViewportCore::volumesPerObject(
|
||||||
|
const std::vector<uint32_t>& object_ids) const {
|
||||||
|
std::vector<std::pair<uint32_t, double>> 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "BufferPool.h"
|
#include "BufferPool.h"
|
||||||
#include "InstanceCompose.h"
|
#include "InstanceCompose.h"
|
||||||
@@ -158,6 +160,17 @@ public:
|
|||||||
bool computeObjectAabb(uint32_t object_id,
|
bool computeObjectAabb(uint32_t object_id,
|
||||||
Eigen::Vector3f& mn, Eigen::Vector3f& mx) const;
|
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<uint32_t>& 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<std::pair<uint32_t, double>>
|
||||||
|
volumesPerObject(const std::vector<uint32_t>& object_ids) const;
|
||||||
|
|
||||||
// Friend access for ViewportWindow's reference proxies. As each
|
// Friend access for ViewportWindow's reference proxies. As each
|
||||||
// render method moves into ViewportCore it stops needing these
|
// render method moves into ViewportCore it stops needing these
|
||||||
// (it touches the fields directly); once everything has migrated
|
// (it touches the fields directly); once everything has migrated
|
||||||
|
|||||||
@@ -3547,44 +3547,15 @@ void ViewportWindow::setToolMode(ToolMode m) {
|
|||||||
if (isExposed()) requestUpdate();
|
if (isExposed()) requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// volumeOfObjects / volumesPerObject moved to ViewportCore (#84-j).
|
||||||
double ViewportWindow::volumeOfObjects(
|
double ViewportWindow::volumeOfObjects(
|
||||||
const std::vector<uint32_t>& object_ids) const {
|
const std::vector<uint32_t>& object_ids) const {
|
||||||
if (object_ids.empty()) return 0.0;
|
return core_.volumeOfObjects(object_ids);
|
||||||
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<std::pair<uint32_t, double>>
|
std::vector<std::pair<uint32_t, double>>
|
||||||
ViewportWindow::volumesPerObject(
|
ViewportWindow::volumesPerObject(
|
||||||
const std::vector<uint32_t>& object_ids) const {
|
const std::vector<uint32_t>& object_ids) const {
|
||||||
std::vector<std::pair<uint32_t, double>> out;
|
return core_.volumesPerObject(object_ids);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportWindow::updateVolumeReadout() {
|
void ViewportWindow::updateVolumeReadout() {
|
||||||
|
|||||||
Reference in New Issue
Block a user