diff --git a/src/ifcviewer/ViewportCore.cpp b/src/ifcviewer/ViewportCore.cpp index bc9d168839..8026507ecf 100644 --- a/src/ifcviewer/ViewportCore.cpp +++ b/src/ifcviewer/ViewportCore.cpp @@ -24,6 +24,41 @@ ViewportCore::ViewportCore(ViewportHost* host) : host_(host) {} ViewportCore::~ViewportCore() = default; +bool ViewportCore::findInstance(uint32_t object_id, + InstanceCompose::InstanceLookup& out) const { + return InstanceCompose::findInstanceInModels(object_id, models_gpu_, out); +} + +bool ViewportCore::firstGeometryPointWorldM(uint32_t model_id, + Eigen::Vector3d& out) const { + auto it = models_gpu_.find(model_id); + if (it == models_gpu_.end()) return false; + const ModelGpuData& m = it->second; + if (m.instances.empty()) return false; + + const InstanceCpu& inst0 = m.instances[0]; + if (inst0.mesh_id >= m.meshes.size()) return false; + const MeshInfo& mesh0 = m.meshes[inst0.mesh_id]; + + // Mesh-local AABB centre — a point that's actually on the geometry. + // Using AABB centre (vs. literal vertex 0) gives a centroid-like + // anchor rather than a corner, which is more representative of where + // the mesh "is" for the false-origin guess. + const Eigen::Vector3d local_center_m( + 0.5 * (double(mesh0.local_aabb_min[0]) + double(mesh0.local_aabb_max[0])), + 0.5 * (double(mesh0.local_aabb_min[1]) + double(mesh0.local_aabb_max[1])), + 0.5 * (double(mesh0.local_aabb_min[2]) + double(mesh0.local_aabb_max[2]))); + + // placement_transformation is double[16] column-major in metres, + // pre-CoordinateOperation / FederatedFalseOrigin / ModelTransformation + // (same convention as InstanceLookup above). + using Mat4dCol = Eigen::Matrix; + const Eigen::Matrix4d P = + Eigen::Map(inst0.placement_transformation); + out = (P * local_center_m.homogeneous()).head<3>(); + return true; +} + void ViewportCore::composeInstanceFromPlacement(InstanceCpu& inst, const ModelGpuData& m) const { if (inst.mesh_id < m.meshes.size()) { diff --git a/src/ifcviewer/ViewportCore.h b/src/ifcviewer/ViewportCore.h index 52ce2ef7a8..604a4c31c8 100644 --- a/src/ifcviewer/ViewportCore.h +++ b/src/ifcviewer/ViewportCore.h @@ -41,6 +41,7 @@ #include #include "BufferPool.h" +#include "InstanceCompose.h" #include "InstancedGeometry.h" #include "ModelGpuData.h" #include "StreamingThread.h" @@ -68,6 +69,18 @@ public: void composeInstanceFromPlacement(InstanceCpu& inst, const ModelGpuData& m) const; + // Cross-model object_id lookup. Delegates to + // InstanceCompose::findInstanceInModels; the wrapper exists so + // callers don't have to know about the underlying map of models. + bool findInstance(uint32_t object_id, + InstanceCompose::InstanceLookup& out) const; + + // A point that actually lies on the model's first instance — used + // by the federation false-origin guess on first geometry. Pure + // read of models_gpu_; no GPU touch. + bool firstGeometryPointWorldM(uint32_t model_id, + Eigen::Vector3d& out) 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 71f3e5f7ce..a92e29ec72 100644 --- a/src/ifcviewer/ViewportWindow.cpp +++ b/src/ifcviewer/ViewportWindow.cpp @@ -1427,37 +1427,12 @@ void ViewportWindow::recomposeAndUploadModel(uint32_t model_id) { } bool ViewportWindow::findInstance(uint32_t object_id, InstanceLookup& out) const { - return InstanceCompose::findInstanceInModels(object_id, models_gpu_, out); + return core_.findInstance(object_id, out); } bool ViewportWindow::firstGeometryPointWorldM(uint32_t model_id, - Eigen::Vector3d& out) const { - auto it = models_gpu_.find(model_id); - if (it == models_gpu_.end()) return false; - const ModelGpuData& m = it->second; - if (m.instances.empty()) return false; - - const InstanceCpu& inst0 = m.instances[0]; - if (inst0.mesh_id >= m.meshes.size()) return false; - const MeshInfo& mesh0 = m.meshes[inst0.mesh_id]; - - // Mesh-local AABB centre — a point that's actually on the geometry. - // Using AABB centre (vs. literal vertex 0) gives a centroid-like - // anchor rather than a corner, which is more representative of where - // the mesh "is" for the false-origin guess. - const Eigen::Vector3d local_center_m( - 0.5 * (double(mesh0.local_aabb_min[0]) + double(mesh0.local_aabb_max[0])), - 0.5 * (double(mesh0.local_aabb_min[1]) + double(mesh0.local_aabb_max[1])), - 0.5 * (double(mesh0.local_aabb_min[2]) + double(mesh0.local_aabb_max[2]))); - - // placement_transformation is double[16] column-major in metres, - // pre-CoordinateOperation / FederatedFalseOrigin / ModelTransformation - // (same convention as InstanceLookup above). - using Mat4dCol = Eigen::Matrix; - const Eigen::Matrix4d P = - Eigen::Map(inst0.placement_transformation); - out = (P * local_center_m.homogeneous()).head<3>(); - return true; + Eigen::Vector3d& out) const { + return core_.firstGeometryPointWorldM(model_id, out); } void ViewportWindow::frameOnFederatedOrigin(uint32_t model_id,