ifcviewer: auto-guess FederatedFalseOrigin on first model added

When the user adds a model into a fresh, untitled federation that still
has the default (0,0,0, no rotation) FederatedFalseOrigin, derive an
origin from the first instance's placement_transformation (lifted
through CoordinateOperation when enabled) and the helmert grid-north
baked into ModelGeoref::coordinate_operation_meters.  Multi-file batches
naturally settle: whichever load finishes first anchors the federation,
the rest see a non-default origin and skip.  Saved .ifcfeds keep their
authoritative origin.

Adds Placement.{h,cpp} (port of util/placement.py — a2p,
get_axis2placement, get_local_placement) so Geolocation no longer needs
its own anonymous getAxis2Placement, and xaxis2angleDeg in Geolocation
mirroring util/geolocation.xaxis2angle.

SceneLoader captures the first instance's placement_transformation from
either the sidecar's InstanceCpu[0] or the streamer's first
InstanceChunk, so the guess works on both load paths without re-reading
the IFC.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-03 10:04:39 +10:00
parent 8ffdb8f0b9
commit f7add7f412
10 changed files with 333 additions and 55 deletions
+14
View File
@@ -72,6 +72,14 @@ public:
// sidecar-hit path before the data-source thread populates the streamer).
const ModelGeoref* modelGeoref(uint32_t mid);
// The placement_transformation (in metres, column-major 4x4) of the
// first instance the loader saw for `mid` — captured from the streamer's
// first InstanceChunk during a stream load, or from the cached
// InstanceCpu[0] on a sidecar hit. Returns nullptr until at least one
// instance has been observed. Used by the federation false-origin
// auto-guess to anchor the model without re-parsing the IFC.
const Eigen::Matrix4d* firstPlacement(uint32_t mid) const;
signals:
void progressChanged(int percent);
void loadStarted(uint32_t mid, QString display_name);
@@ -125,6 +133,12 @@ private:
// streamer has its IFC file loaded.
ModelGeoref georef;
bool has_georef = false;
// The first instance's placement_transformation (in metres) — set
// once per model from either the sidecar's InstanceCpu[0] or the
// streamer's first InstanceChunk.
Eigen::Matrix4d first_placement = Eigen::Matrix4d::Identity();
bool has_first_placement = false;
};
void startNextLoad();