mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
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:
@@ -81,6 +81,12 @@ const ModelGeoref* SceneLoader::modelGeoref(uint32_t mid) {
|
||||
return &m.georef;
|
||||
}
|
||||
|
||||
const Eigen::Matrix4d* SceneLoader::firstPlacement(uint32_t mid) const {
|
||||
auto it = models_.find(mid);
|
||||
if (it == models_.end() || !it->second.has_first_placement) return nullptr;
|
||||
return &it->second.first_placement;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> SceneLoader::addFiles(const QStringList& paths) {
|
||||
std::vector<uint32_t> assigned;
|
||||
assigned.reserve(paths.size());
|
||||
@@ -214,6 +220,14 @@ void SceneLoader::applySidecarData(uint32_t mid, SidecarData data) {
|
||||
model.has_georef = true;
|
||||
}
|
||||
|
||||
if (!data.instances.empty() && !model.has_first_placement) {
|
||||
using Mat4fCol = Eigen::Matrix<float, 4, 4, Eigen::ColMajor>;
|
||||
model.first_placement =
|
||||
Eigen::Map<const Mat4fCol>(data.instances[0].placement_transformation)
|
||||
.cast<double>();
|
||||
model.has_first_placement = true;
|
||||
}
|
||||
|
||||
std::vector<PackedElementInfo> elements = std::move(data.elements);
|
||||
std::string stbl = std::move(data.string_table);
|
||||
|
||||
@@ -302,6 +316,15 @@ void SceneLoader::onStreamerMeshReady(MeshChunk chunk) {
|
||||
}
|
||||
|
||||
void SceneLoader::onStreamerInstanceReady(InstanceChunk chunk) {
|
||||
if (loading_model_id_ != 0) {
|
||||
auto it = models_.find(loading_model_id_);
|
||||
if (it != models_.end() && !it->second.has_first_placement) {
|
||||
using Mat4fCol = Eigen::Matrix<float, 4, 4, Eigen::ColMajor>;
|
||||
it->second.first_placement =
|
||||
Eigen::Map<const Mat4fCol>(chunk.transform).cast<double>();
|
||||
it->second.has_first_placement = true;
|
||||
}
|
||||
}
|
||||
viewport_->uploadInstanceChunk(chunk);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user