ifcviewer: add stage 3+4 data model and compose helpers to Federation

Adds the structs that were briefly in src/ifcviewer/Federation.{h,cpp}
two commits ago, now folded into the merged Federation alongside the
file persistence layer:

  - FederationConfig: federation-wide unit ({prefix, name}).  Default
    METRE; one-of an IfcSIUnit name with optional prefix or an
    IfcConversionBasedUnit name.
  - FederationOrigin: stage 3 — XYZ in federation unit + Z-rot.
    Composes to R_z · T(-xyz_meters), nominating a point as origin.
  - AFrame + ModelTransform: stage 4 intent — A (model project or
    map unit, per a_frame), B and pivot (federation unit), full
    intrinsic-XYZ Euler rotation in degrees.
  - ModelUnits: per-model project_length_to_meters / map_unit_to_meters
    cached at load time.

Free functions composeFederationOrigin and composeModelTransform
return Eigen::Matrix4d in metres.  composeModelTransform takes the
model's stage-2 georef matrix so it can lift `a` into metres when
authored in ModelLocal.

Federation gains config_, origin_ members + setters that emit
dirtyChanged.  Each Model carries a transform_intent.  JSON I/O
emits config / origin always; transform_intent only when non-default.
Schema stays "ifcfed/1" — additive, optional, sane defaults.

Five new tests: round-trip of the new fields, default-omission
behaviour, two compose smoke tests for FederationOrigin, and one
verifying the "pivot at B preserves A→B" invariant of
composeModelTransform.  All 36 ctest cases pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-05-01 15:15:37 +10:00
parent ecf0a5a4e1
commit 5386c9ec69
4 changed files with 417 additions and 10 deletions
+8
View File
@@ -53,9 +53,15 @@ add_ifcviewer_unit_test(test_instanced_geometry)
# enable AUTOMOC for the Q_OBJECT moc-generation.
find_package(Qt${QT_VERSION} COMPONENTS Core Gui Test REQUIRED PATHS ${QT_DIR})
find_package(Eigen3 REQUIRED)
add_executable(test_federation
test_federation.cpp
${IFCVIEWER_SRC}/Federation.cpp
# Federation pulls in Unit::convert for federation_unit_to_meters; compile
# Unit.cpp directly so the test doesn't have to link the whole IfcViewer
# library (which would drag in Qt6::OpenGL, OpenCASCADE, etc.).
${IFCVIEWER_SRC}/Unit.cpp
)
set_target_properties(test_federation PROPERTIES AUTOMOC ON)
target_include_directories(test_federation PRIVATE ${IFCVIEWER_SRC})
@@ -64,5 +70,7 @@ target_link_libraries(test_federation PRIVATE
Qt${QT_VERSION}::Core
Qt${QT_VERSION}::Gui # Federation::HomeView uses QVector3D from QtGui
Qt${QT_VERSION}::Test # QSignalSpy
Eigen3::Eigen # Federation.h: composed matrices use Eigen
IfcParse # Unit.cpp uses express::Base / file APIs
)
catch_discover_tests(test_federation)