From 7f641810ccf18e54f2adf5ecb7c5330f82c2746c Mon Sep 17 00:00:00 2001 From: ifcapps Date: Fri, 28 Feb 2025 20:41:49 +0200 Subject: [PATCH 1/4] add IFCTOPOLOGYREPRESENTATION, add IFCFACESURFACE, IFCEDGE and IFCCARTESIANPOINT as geometric item IFCFACESURFACE, IFCEDGE and IFCCARTESIANPOINT are derived from IfcRepresentationItem, so they could appear as geometric item In IfcGeometryLoader::GetColor: add check for curveColour because it is optional --- .../web-ifc/geometry/IfcGeometryLoader.cpp | 26 +++- .../web-ifc/geometry/IfcGeometryProcessor.cpp | 132 +++++++++++++++++- src/cpp/web-ifc/parsing/IfcLoader.cpp | 3 +- 3 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp b/src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp index e165bda6a..e5a2a837d 100644 --- a/src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp +++ b/src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp @@ -909,9 +909,15 @@ namespace webifc::geometry case schema::IFCCURVESTYLE: { _loader.MoveToArgumentOffset(expressID, 3); - auto foundColor = GetColor(_loader.GetRefArgument()); - if (foundColor) - return foundColor; + // argument 3 (CurveColour) is optional, so check if it is set + auto tt = _loader.GetTokenType(); + if (tt == parsing::REF) + { + _loader.StepBack(); + auto foundColor = GetColor(_loader.GetRefArgument()); + if (foundColor) + return foundColor; + } return {}; } case schema::IFCFILLAREASTYLEHATCHING: @@ -1322,6 +1328,20 @@ namespace webifc::geometry switch (lineType) { + + case schema::IFCEDGE: + { + _loader.MoveToArgumentOffset(expressID, 0); + glm::dvec3 p1 = GetVertexPoint(_loader.GetRefArgument()); + _loader.MoveToArgumentOffset(expressID, 1); + glm::dvec3 p2 = GetVertexPoint(_loader.GetRefArgument()); + + IfcCurve curve; + curve.points.push_back(p1); + curve.points.push_back(p2); + + return curve; + } case schema::IFCEDGECURVE: { IfcTrimmingArguments ts; diff --git a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp index 0217b280c..a4fe910e5 100644 --- a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp +++ b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp @@ -641,8 +641,10 @@ namespace webifc::geometry return mesh; } + case schema::IFCTOPOLOGYREPRESENTATION: case schema::IFCSHAPEREPRESENTATION: { + // IFCTOPOLOGYREPRESENTATION and IFCSHAPEREPRESENTATION are identical in attributes layout _loader.MoveToArgumentOffset(expressID, 1); auto type = _loader.GetStringArgument(); @@ -695,6 +697,54 @@ namespace webifc::geometry return mesh; } + case schema::IFCFACESURFACE: + { + IfcGeometry geometry; + _loader.MoveToArgumentOffset(expressID, 0); + auto bounds = _loader.GetSetArgument(); + + std::vector bounds3D(bounds.size()); + + for (size_t i = 0; i < bounds.size(); i++) + { + uint32_t boundID = _loader.GetRefArgument(bounds[i]); + bounds3D[i] = _geometryLoader.GetBound(boundID); + } + + TriangulateBounds(geometry, bounds3D, expressID); + + _loader.MoveToArgumentOffset(expressID, 1); + auto surfRef = _loader.GetRefArgument(); + + auto surface = GetSurface(surfRef); + + if (surface.BSplineSurface.Active) + { + TriangulateBspline(geometry, bounds3D, surface, _geometryLoader.GetLinearScalingFactor()); + } + else if (surface.CylinderSurface.Active) + { + TriangulateCylindricalSurface(geometry, bounds3D, surface, _circleSegments); + } + else if (surface.RevolutionSurface.Active) + { + TriangulateRevolution(geometry, bounds3D, surface, _circleSegments); + } + else if (surface.ExtrusionSurface.Active) + { + TriangulateExtrusion(geometry, bounds3D, surface); + } + else + { + TriangulateBounds(geometry, bounds3D, expressID); + } + + _expressIDToGeometry[expressID] = geometry; + mesh.expressID = expressID; + mesh.hasGeometry = true; + + break; + } case schema::IFCTRIANGULATEDIRREGULARNETWORK: case schema::IFCTRIANGULATEDFACESET: { @@ -1027,11 +1077,89 @@ namespace webifc::geometry return mesh; } + case schema::IFCBOUNDINGBOX: + // ignore bounding box + return mesh; + + case schema::IFCCARTESIANPOINT: + { + // IfcCartesianPoint is derived from IfcRepresentationItem and can be used as representation item directly + IfcGeometry geom; + auto point = _geometryLoader.GetCartesianPoint3D(expressID); + geom.vertexData.push_back(point.x); + geom.vertexData.push_back(point.y); + geom.vertexData.push_back(point.z); + geom.vertexData.push_back(0); // needs to be 6 values per vertex + geom.vertexData.push_back(0); + geom.vertexData.push_back(1); + geom.indexData.push_back(0); + + geom.numPoints = 1; + geom.isPolygon = true; + mesh.hasGeometry = true; + _expressIDToGeometry[expressID] = geom; + + return mesh; + } + case schema::IFCEDGE: + { + // IfcEdge is derived from IfcRepresentationItem and can be used as representation item directly + IfcCurve edge = _geometryLoader.GetEdge(expressID); + IfcGeometry geom; + + for (uint32_t i = 0; i < edge.points.size(); i++) + { + auto vert = edge.points[i]; + geom.vertexData.push_back(vert.x); + geom.vertexData.push_back(vert.y); + geom.vertexData.push_back(vert.z); + geom.vertexData.push_back(0); // needs to be 6 values per vertex + geom.vertexData.push_back(0); + geom.vertexData.push_back(1); + geom.indexData.push_back(i); + } + geom.numPoints = edge.points.size(); + geom.isPolygon = true; + mesh.hasGeometry = true; + _expressIDToGeometry[expressID] = geom; + + return mesh; + } + case schema::IFCCIRCLE: case schema::IFCPOLYLINE: case schema::IFCINDEXEDPOLYCURVE: case schema::IFCTRIMMEDCURVE: - // ignore polylines as meshes - return mesh; + { + auto lineProfileType = _loader.GetLineType(expressID); + IfcCurve curve = _geometryLoader.GetCurve(expressID, 3, false); + + if (curve.points.size() > 0) { + IfcGeometry geom; + + for (uint32_t i = 0; i < curve.points.size(); i++) + { + auto vert = curve.points[i]; + geom.vertexData.push_back(vert.x); + geom.vertexData.push_back(vert.y); + geom.vertexData.push_back(vert.z); + geom.vertexData.push_back(0); // needs to be 6 values per vertex + geom.vertexData.push_back(0); + geom.vertexData.push_back(1); + geom.indexData.push_back(i); + } + geom.numPoints = curve.points.size(); + geom.isPolygon = true; + mesh.hasGeometry = true; + _expressIDToGeometry[expressID] = geom; + } + + return mesh; + } + case schema::IFCTEXTLITERAL: + case schema::IFCTEXTLITERALWITHEXTENT: + // TODO: save string of the text literal in IfcComposedMesh + return mesh; + default: spdlog::error("[GetMesh()] unexpected mesh type {}", expressID, lineType); break; diff --git a/src/cpp/web-ifc/parsing/IfcLoader.cpp b/src/cpp/web-ifc/parsing/IfcLoader.cpp index e1e951d1b..08a2d3e47 100644 --- a/src/cpp/web-ifc/parsing/IfcLoader.cpp +++ b/src/cpp/web-ifc/parsing/IfcLoader.cpp @@ -666,8 +666,7 @@ namespace webifc::parsing { if (t==SET_BEGIN) { StepBack(); GetSetArgument(); - noArguments++; - continue; + continue; } if (t == IfcTokenType::STRING || t == IfcTokenType::INTEGER || t == IfcTokenType::REAL || t == IfcTokenType::LABEL || t == IfcTokenType::ENUM) { uint16_t length = _tokenStream->Read(); From 0f7fa9843c63bf7c72b289f298912aacd991a213 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Wed, 12 Mar 2025 20:42:25 +0100 Subject: [PATCH 2/4] In IfcGeometry: add member bool isPolygon = false; to indicate if a geometry is a polygon, for example IfcGridAxis or general axis representations --- src/cpp/web-ifc/geometry/representation/IfcGeometry.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpp/web-ifc/geometry/representation/IfcGeometry.h b/src/cpp/web-ifc/geometry/representation/IfcGeometry.h index 3186c134d..3841958e2 100644 --- a/src/cpp/web-ifc/geometry/representation/IfcGeometry.h +++ b/src/cpp/web-ifc/geometry/representation/IfcGeometry.h @@ -58,6 +58,7 @@ namespace webifc::geometry { std::vector planes; bool hasPlanes = false; + bool isPolygon = false; uint32_t numPoints = 0; uint32_t numFaces = 0; From 70646f4ead5e923b863fc621dfe412476f7338ae Mon Sep 17 00:00:00 2001 From: ifcapps Date: Thu, 13 Mar 2025 13:39:18 +0100 Subject: [PATCH 3/4] update after running "npm run regression-update" --- tests/regression/results.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/results.json b/tests/regression/results.json index d6ca94829..df334c66f 100644 --- a/tests/regression/results.json +++ b/tests/regression/results.json @@ -1 +1 @@ -{"tests/ifcfiles/public/AC20-FZK-Haus.ifc":"19ee5b853d0cf32018f54c1f778514a8834b6cb01261dc9825cb4a48f67a5fae","tests/ifcfiles/public/C20-Institute-Var-2.ifc":"ac98b82c88cc8e27dbafece628e5e278b3fdfdfc1e460f679d563ca13c6df5c9","tests/ifcfiles/public/FM_ARC_DigitalHub.ifc":"607320d14e4eaf3fc40a83a6148348f645a78c3bf8da19bddcfcf2f35c909147","tests/ifcfiles/public/ISSUE_005_haus.ifc":"19ee5b853d0cf32018f54c1f778514a8834b6cb01261dc9825cb4a48f67a5fae","tests/ifcfiles/public/ISSUE_021_Mini Project.ifc":"ec105fd04e6f7cc87f5aff2346c3e9d3e94f2a35b28cad59f7d8051d9567a03d","tests/ifcfiles/public/ISSUE_034_HouseZ.ifc":"b599ca9f82ad21d05f9c9b8921d14ca5e9635ca8937fca6eba40272cd7f2e1c4","tests/ifcfiles/public/ISSUE_044_test_IFCCOMPOSITEPROFILEDEF.ifc":"ce7582a288480a545b2dcda2e6d8570b669827b0c221cfbc31185d5553563b7a","tests/ifcfiles/public/ISSUE_053_20181220Holter_Tower_10.ifczip":"6b8dc638fd01a04fc0816f9e2c935fab766c04d385475d42262e8b70d962724d","tests/ifcfiles/public/ISSUE_068_ARK_NUS_skolebygg.ifc":"453492a320187a30fc03aefa036502a364c97af62eee921f69cebfd631e67c03","tests/ifcfiles/public/ISSUE_102_M3D-CON-CD.ifc":"aae6cae8ccd12efb9a90da6678423601f73ae0b4b878d63f9b85d8619f450ca6","tests/ifcfiles/public/ISSUE_102_M3D-CON.ifc":"fb22b6e733f1c5ad9719d86e81c2f45c79a954d56c0d779a56ef03bd14161c10","tests/ifcfiles/public/ISSUE_126_model.ifc":"bfad187b873a34ec386b8c4a47a02233839373a8bb9d7ef1c7a3972fae0f56a7","tests/ifcfiles/public/ISSUE_129_N1540_17_EXE_MOD_448200_02_09_11SMC_IGC_V17.ifc":"3ef60977b10937a410cc3074c7cc87b99de9ddf761867624bc78a47210104f51","tests/ifcfiles/public/ISSUE_159_kleine_Wohnung_R22.ifc":"820adfaa6ecb5883dd889b6f920724b77666bd4ddd116abcccce4bbc613dce67","tests/ifcfiles/public/ISSUE_171_IfcSurfaceCurveSweptAreaSolid.ifc":"c5bb45f57ca83a19d4a3146c41e4e42b4a08208c400ce490d9bfc23c7ff575e8","tests/ifcfiles/public/IfcOpenHouse_IFC4.ifc":"25c6b335a66e56de318997be5aae3c9f9774517e39a36b520fe69ce637a15fe6","tests/ifcfiles/public/KIT-Simple-Road-Test-Web-IFC4x3_RC2.ifc":"168971a85b62fe14900dc9ac5eab3a7d9268833078a313d1ae98785b69bbe64e","tests/ifcfiles/public/Office_A_20110811.ifc":"28b4a6a8645ab2b23c0f0050c6225c545cdb25c4b9d9968ed4a90d71f0ee281f","tests/ifcfiles/public/S_Office_Integrated Design Archi.ifc":"3ac8c503dec4cf6dd31806a82269c28f34b44b245dba0b66d0b7d9199a66c064","tests/ifcfiles/public/Sample_entities.ifc":"69d08b09e343a03031c8f912fbf0671f5ceabd5bf87a842ba7f39254e746d587","tests/ifcfiles/public/advanced_model.ifc":"a9d75d26b6d911513b3410a1e0332ad2639975e3ba4de2e8d0be6cda0f0518ab","tests/ifcfiles/public/dental_clinic.ifc":"019e6a09d8a215e75608f9cff79ca34bcfb2d930aa610a6ecb3a2403b5394acd","tests/ifcfiles/public/duplex.ifc":"ad9d46748eabacda99f85bcec2ffd6eb168c1602aedb9ff387c3d0230499f472","tests/ifcfiles/public/example.ifc":"52767e9f48a4d42a3ee43f3d84df35f8bcdd8226c1ef4a48f8da86a054217511","tests/ifcfiles/public/ifcbridge-model01.ifc":"1c0d30b936ced88ea0377ec117d3e5376d63dc9634baca281a35b42035860ce7","tests/ifcfiles/public/schependomlaan.ifc":"ffda1eefcab37c83da6685b89c1b30066216cc6ee655a0a93ceb6145550c1ca3","tests/ifcfiles/public/tested_sample_project.ifc":"b670ba3155f8a813037f94bfba59cdd24b8eeb693f21663a68aaff4bb0167094"} \ No newline at end of file +{"tests/ifcfiles/public/AC20-FZK-Haus.ifc":"8b105d1195fd451f71d647cf7bc348a9d52a605bad5657451211612dbcec4d4e","tests/ifcfiles/public/advanced_model.ifc":"a1bcdbb6b3f43c908d4fbd527cdde8a8c837fbe1fce93f69409fd23d73c23f8c","tests/ifcfiles/public/C20-Institute-Var-2.ifc":"3590224aeb587d5c71d6a0f21b58f94bcad2121d21a96d2460d042f2aac5d6fd","tests/ifcfiles/public/dental_clinic.ifc":"0a8b20f428a3969fbae73927660749da96cb75a0aacb3dd676dd443ad7f9d13d","tests/ifcfiles/public/duplex.ifc":"ee36d2543254cdbc22af335fb58cc547607381f5b2b10d8809e4c11a14f1503e","tests/ifcfiles/public/example.ifc":"bffef52d7f62969741d98f0c8f6014feb4b1ce17d0c4700e5f27098d5b3261be","tests/ifcfiles/public/FM_ARC_DigitalHub.ifc":"c199de49f74b724fe327f8e53209b583d59cbcd982258f255c272921a4fda88f","tests/ifcfiles/public/ifcbridge-model01.ifc":"00c016be5509e4145b3662dbdeedd67e7e60e6648ad1c247d6a41e41657b7e33","tests/ifcfiles/public/IfcOpenHouse_IFC4.ifc":"eaa998f4a4405ed1b19135d9bd73f6bcb47849a2a064d7fa9830f60b3244f4f2","tests/ifcfiles/public/ISSUE_005_haus.ifc":"8b105d1195fd451f71d647cf7bc348a9d52a605bad5657451211612dbcec4d4e","tests/ifcfiles/public/ISSUE_021_Mini Project.ifc":"4a51c550481378a786649d874a2a4ca55f4a8b7a98aa8dcc2d3d2d64aac39cdb","tests/ifcfiles/public/ISSUE_034_HouseZ.ifc":"3893a181d08faf08dd0b8e298375651fbf6deab2ecc64a190e869722bd986dce","tests/ifcfiles/public/ISSUE_044_test_IFCCOMPOSITEPROFILEDEF.ifc":"837c919e53f51643e10add9b6084e79a8482c99be52768bb95bb11b07ac1db05","tests/ifcfiles/public/ISSUE_053_20181220Holter_Tower_10.ifczip":"dd90516483e397988d02ca7f07d571b52724bdec6fdb04a5c77de804b514e567","tests/ifcfiles/public/ISSUE_068_ARK_NUS_skolebygg.ifc":"f4289a376884cfb623d318828d6de1d6b53c12c5ed01d3f28ac34be8a0784546","tests/ifcfiles/public/ISSUE_102_M3D-CON-CD.ifc":"0f5aa3354cd63a364c46199e396200df38a5c29deba9083d331203d28124b0d6","tests/ifcfiles/public/ISSUE_102_M3D-CON.ifc":"c83a0f31c6a52928fb9797456689c69c63d156c5bdf53cb49a83ed10d9e5bc23","tests/ifcfiles/public/ISSUE_126_model.ifc":"033cb29d5b5c32761ca411ad732071cec27723a782fa0976537ab8c900715b64","tests/ifcfiles/public/ISSUE_129_N1540_17_EXE_MOD_448200_02_09_11SMC_IGC_V17.ifc":"e43a88137ccb99cb056c7835acb9d0476885ab0e2cfcbf9de3276e63ec8e64e9","tests/ifcfiles/public/ISSUE_159_kleine_Wohnung_R22.ifc":"cf0fcfc7e440fe9c4bb013571f6623a045c4689b288c7192797030bcd3629ed7","tests/ifcfiles/public/ISSUE_171_IfcSurfaceCurveSweptAreaSolid.ifc":"d3e96446342815ff8b1d79cca4ef45a6d9dba6f21eb514c07fa14f6d303a4f45","tests/ifcfiles/public/KIT-Simple-Road-Test-Web-IFC4x3_RC2.ifc":"3d8707ee9d70e2aeb67b8bebdc96016a1eceb30afd9a25e9cf6c258d978a6fe6","tests/ifcfiles/public/Office_A_20110811.ifc":"a1da7b63ab89206143a1a74b9347c397d101951221662f46a14a591044f4d99f","tests/ifcfiles/public/Sample_entities.ifc":"270a55940a77ebb4f245cabf8c7429dc8fc7044baf9c9434fc747842f602d792","tests/ifcfiles/public/schependomlaan.ifc":"417a5f59a4f20eeca6fcbdd08737c05eddf437d63c65374b0a922372f9824f10","tests/ifcfiles/public/S_Office_Integrated Design Archi.ifc":"2cd3e092483017e432703fcb36d15617a90317758e38122d89b71de1a7e688c7","tests/ifcfiles/public/tested_sample_project.ifc":"bc11a6ad31e490d7391781875c1e7b25ac5f69e42cbbab440474d3d76a3c5a43"} \ No newline at end of file From 4417cb884562076e4e37fa3bf9d94dd62a909256 Mon Sep 17 00:00:00 2001 From: Tom Beach Date: Sat, 15 Mar 2025 09:08:56 +0000 Subject: [PATCH 4/4] Update IfcLoader.cpp --- src/cpp/web-ifc/parsing/IfcLoader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cpp/web-ifc/parsing/IfcLoader.cpp b/src/cpp/web-ifc/parsing/IfcLoader.cpp index 1075ce1da..cda0a0d88 100644 --- a/src/cpp/web-ifc/parsing/IfcLoader.cpp +++ b/src/cpp/web-ifc/parsing/IfcLoader.cpp @@ -671,7 +671,8 @@ namespace webifc::parsing { if (t==SET_BEGIN) { StepBack(); GetSetArgument(); - continue; + noArguments++; + continue; } if (t == IfcTokenType::STRING || t == IfcTokenType::INTEGER || t == IfcTokenType::REAL || t == IfcTokenType::LABEL || t == IfcTokenType::ENUM) { uint16_t length = _tokenStream->Read();