Repository navigation
fix: place IFC geometry in world coordinates and export GLB in metres, +Y up - #35
Merged
Merged
Conversation
…, +Y up IfcModel.Open ignored object placements, so every element was read at its local origin and GLB/OBJ exports collapsed around 0,0,0. Reader: - resolve IfcLocalPlacement chains (PlacementRelTo) relative to the WorldCoordinateSystem of the 3D Model context - apply IfcMappedItem MappingOrigin and MappingTarget (IfcCartesianTransformationOperator 2D/3D, non-uniform scale, mirroring) - apply the full Position of extruded/revolved solids and rotated profile positions, including the first operand of boolean/clipping results - merge all Body items; read IfcFaceBasedSurfaceModel and IfcShellBasedSurfaceModel - read the length unit from IfcUnitAssignment (SI prefixes, conversion-based units) - read IFC2x3 MEP flow elements and IFC4 pipe/duct fittings - resolve IfcDistributionPort world position and direction - throw InvalidDataException on placement or mapped item cycles GLB export writes metres with +Y up, vertices relative to the model centre carried as the root node translation to keep float precision at georeferenced offsets. OBJ keeps model units and Z up.
Nested IfcMappedItems multiply geometry: a small file with a few levels of representation maps, each holding many instances of the previous one, expands into exponentially many vertices and exhausts memory. The depth limit alone does not prevent this. IfcModel.Open now charges every materialised representation item against a budget of 1,000,000 + 256 vertices per STEP entity and throws InvalidDataException when it is exceeded, so expansion stays linear in the input size.
- Files whose length unit has no IfcLengthUnit value (e.g. centimetres) are read in metres, but parametric solids stayed in file units and the writer prefers them, so Open -> Save -> Open rescaled those elements. Parametric solids are no longer kept when geometry is rescaled; the metre mesh is written instead. - With no reference direction, IfcFirstProjAxis defaults to (1,0,0), or (0,1,0) when the Z axis is (1,0,0). The fallback used (0,0,1) there, rotating and mirroring placements and mapped items with Z = +X.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
IfcModel.Opennever appliedObjectPlacement, so every element was read at its local origin. On a real MEP model, GLB/OBJ exports showed a heap of fragments around 0,0,0 plus long strips fanning out in every direction (pipes extruded along global Z because the rotation of the extrusionPositionwas dropped). GLB was also written in millimetres and Z-up, while glTF requires metres and +Y up. IFC2x3 pipes and fittings (IfcFlowSegment,IfcFlowFitting, ...) were not read at all.What changed
Reader (
IfcModel.Open)IfcLocalPlacementchains (PlacementRelTo) iteratively, relative to theWorldCoordinateSystemof the 3DModelcontext.IfcMappedItem:MappingTarget * MappingOrigin(IfcCartesianTransformationOperator2D/3D, non-uniform scale, mirroring perIfcSecondProjAxis).IfcAxis2Placement3Dof extruded/revolved solids, rotated profile positions and non-+Z extrusion directions; the first operand of boolean/clipping results honours a rotatedPosition(kept asFirstMesh).Bodyrepresentation; readsIfcFaceBasedSurfaceModelandIfcShellBasedSurfaceModel.IfcUnitAssignment(any SI prefix, conversion-based units). Units without anIfcLengthUnitvalue (e.g. cm) are converted to metres for geometry and storey elevations.IfcPipeFitting/IfcDuctFitting.IfcDistributionPortposition/direction come from its world placement (were always origin / +Z).InvalidDataException.GLB export: metres, +Y up (
(x, y, z) -> (x, z, -y)). Vertices are stored relative to the model centre, which is the root nodetranslation, so georeferenced models keep millimetre precision in float32 (about 8 mm is lost at 100 km otherwise).OBJ export: code unchanged; model units and Z-up, now with world-placed geometry.
Public API is unchanged (
IfcTransformis internal). Behaviour changes are listed inCHANGELOG.mdunder [Unreleased].Notes for reviewers
IfcElement.Solid/RevolvedSolid/BooleanResultkeep their previous meaning (first body item in its own coordinates); onlyMeshis world-placed. Writing a read model back therefore still places parametric solids without the element placement, as before.Positionis translation-only, its mesh comes from the parametric solid's ownToMesh, so files written by IfcIO read back unchanged. This differs from strict IFC for non-+Z extrusion directions and off-origin revolution axes (markedshortcut:in code).IfcModel's writer declares DEGREE but writes revolved angles in radians, so angles are still read as radians. Known existing issues, not addressed here: the writer emits Foot/Inch as METRE; the built-in HTML viewer does not recentre and uses 16-bit indices.IfcRepresentationMap(instancing). Planned as a follow-up.Testing
dotnet build IfcIO.slnx -c Release(warnings as errors): 0 warnings, 0 errors.dotnet test tests/IfcIO.Tests/IfcIO.Tests.csproj -c Release: 146 passed.PlacementGeometryTests(14) use a synthetic IFC2X3 fixture: nested placements with rotation and offset, rotated extrusion + rotated profile, a representation map used three times (one mirrored), a clipped beam, WCS offset, ports, a placement cycle, mm/m/ft/cm units, and world vertex coordinates checked in GLB and OBJ output. All 13 tests present before the last review round fail onmain.