From 1d457f0465edaa5f9583167f4c23432b0c4881e0 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 18 Feb 2025 17:51:52 +0200 Subject: [PATCH 1/9] replace deprecated std::wstring_convert, close shape in Extrude() --- .gitignore | 1 + src/cpp/web-ifc/geometry/nurbs.h | 8 +- .../geometry/operations/geometryutils.h | 17 ++- src/cpp/web-ifc/parsing/string_parsing.cpp | 109 ++++++++++++++++-- 4 files changed, 115 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 23f43607f..2290e1444 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ examples/nodejs/*.ifc tests/ifcfiles/private/*.ifc tests/ifcfiles/private/*.stl tests/ifcfiles/created.ifc +src/cpp/_deps/ diff --git a/src/cpp/web-ifc/geometry/nurbs.h b/src/cpp/web-ifc/geometry/nurbs.h index de7f642d9..fe4c11e0c 100644 --- a/src/cpp/web-ifc/geometry/nurbs.h +++ b/src/cpp/web-ifc/geometry/nurbs.h @@ -13,10 +13,10 @@ namespace tinynurbs{ namespace webifc::geometry{ - class IfcGeometry; - class IfcBound3D; - class BSpline; - class IfcSurface; + struct IfcGeometry; + struct IfcBound3D; + struct BSpline; + struct IfcSurface; constexpr double rotations { 6.0 }; constexpr auto pi {glm::pi()}; diff --git a/src/cpp/web-ifc/geometry/operations/geometryutils.h b/src/cpp/web-ifc/geometry/operations/geometryutils.h index f8b4565b8..a4b989e51 100644 --- a/src/cpp/web-ifc/geometry/operations/geometryutils.h +++ b/src/cpp/web-ifc/geometry/operations/geometryutils.h @@ -152,7 +152,9 @@ namespace webifc::geometry // this is bad news, as it nans the points added to the final mesh // also, it's hard to bail out now :/ // see curve.add() for more info on how this is currently "solved" +#if defined(_DEBUG) printf("NaN perp!\n"); +#endif } glm::dvec3 u1 = glm::normalize(glm::cross(n1, p)); @@ -363,7 +365,9 @@ namespace webifc::geometry // this is bad news, as it nans the points added to the final mesh // also, it's hard to bail out now :/ // see curve.add() for more info on how this is currently "solved" +#if defined(_DEBUG) printf("NaN perp!\n"); +#endif } glm::dvec3 u1 = glm::normalize(glm::cross(n1, p)); @@ -931,19 +935,22 @@ namespace webifc::geometry } uint32_t capSize = profile.curve.points.size(); - for (size_t i = 1; i < capSize; i++) + for (size_t i = 1; i <= capSize; i++) { // https://github.com/tomvandig/web-ifc/issues/5 - if (holesIndicesHash[i]) + if (i < capSize) { - continue; + if (holesIndicesHash[i]) + { + continue; + } } uint32_t bl = i - 1; - uint32_t br = i - 0; + uint32_t br = i % capSize; uint32_t tl = capSize + i - 1; - uint32_t tr = capSize + i - 0; + uint32_t tr = capSize + i % capSize; // this winding should be correct geom.AddFace(geom.GetPoint(tl), diff --git a/src/cpp/web-ifc/parsing/string_parsing.cpp b/src/cpp/web-ifc/parsing/string_parsing.cpp index ec719ca50..9e7becc3a 100644 --- a/src/cpp/web-ifc/parsing/string_parsing.cpp +++ b/src/cpp/web-ifc/parsing/string_parsing.cpp @@ -15,9 +15,44 @@ namespace webifc::parsing { bool foundRoman = false; + std::u16string utf16_from_utf8(const std::string& utf8) { + std::u16string utf16; + size_t i = 0; + + while (i < utf8.size()) { + char16_t ch = 0; + unsigned char byte = utf8[i]; + + if (byte < 0x80) { + // 1-byte character (ASCII) + ch = byte; + i += 1; + } + else if ((byte & 0xE0) == 0xC0) { + // 2-byte character + if (i + 1 >= utf8.size()) throw std::runtime_error("Invalid UTF-8 sequence"); + ch = ((byte & 0x1F) << 6) | (utf8[i + 1] & 0x3F); + i += 2; + } + else if ((byte & 0xF0) == 0xE0) { + // 3-byte character + if (i + 2 >= utf8.size()) throw std::runtime_error("Invalid UTF-8 sequence"); + ch = ((byte & 0x0F) << 12) | ((utf8[i + 1] & 0x3F) << 6) | (utf8[i + 2] & 0x3F); + i += 3; + } + else { + throw std::runtime_error("Unsupported UTF-8 sequence"); + } + + utf16.push_back(ch); + } + + return utf16; + } + void encodeCharacters(std::ostringstream &stream,std::string &data) { - std::u16string utf16 = std::wstring_convert, char16_t>{}.from_bytes(data.data()); + std::u16string utf16 = utf16_from_utf8(data); stream << "\\X2\\" << std::hex <(uC); stream << std::dec<< std::setw(0) << "\\X0\\"; @@ -53,6 +88,60 @@ namespace webifc::parsing { if (inEncode) encodeCharacters(output,tmp); } + std::string utf8_from_utf16(const std::u16string& u16str) { + std::string utf8; + for (char16_t ch : u16str) { + if (ch < 0x80) { + // 1-byte character + utf8.push_back(static_cast(ch)); + } + else if (ch < 0x800) { + // 2-byte character + utf8.push_back(static_cast(0xC0 | (ch >> 6))); + utf8.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else { + // 3-byte character + utf8.push_back(static_cast(0xE0 | (ch >> 12))); + utf8.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); + utf8.push_back(static_cast(0x80 | (ch & 0x3F))); + } + } + return utf8; + } + + std::string utf8_from_utf32(const std::u32string& u32str) { + std::string utf8; + for (char32_t ch : u32str) { + if (ch < 0x80) { + // 1-byte character + utf8.push_back(static_cast(ch)); + } + else if (ch < 0x800) { + // 2-byte character + utf8.push_back(static_cast(0xC0 | (ch >> 6))); + utf8.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else if (ch < 0x10000) { + // 3-byte character + utf8.push_back(static_cast(0xE0 | (ch >> 12))); + utf8.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); + utf8.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else if (ch <= 0x10FFFF) { + // 4-byte character + utf8.push_back(static_cast(0xF0 | (ch >> 18))); + utf8.push_back(static_cast(0x80 | ((ch >> 12) & 0x3F))); + utf8.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); + utf8.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else { + throw std::runtime_error("Invalid UTF-32 code point"); + } + } + return utf8; + } + struct P21Decoder { public: @@ -95,15 +184,14 @@ namespace webifc::parsing { { char d1 = getNextHex(); char d2 = getNextHex(); - char str[2]; - str[0] = (d1 << 4) | d2; - str[1] = 0; - auto cA = reinterpret_cast(str); + char str2[2]; + str2[0] = (d1 << 4) | d2; + str2[1] = 0; + auto cA = reinterpret_cast(str2); if (cA[0] >= 0x80 && cA[0] <= 0x9F) foundRoman = true; if (foundRoman) cA[0]=checkRomanEncoding(cA[0]); std::u16string u16str(cA, 1); - std::wstring_convert,char16_t> convert; - std::string utf8 = convert.to_bytes(u16str); + std::string utf8 = utf8_from_utf16(u16str); std::copy(utf8.begin(), utf8.end(), std::back_inserter(result)); break; } @@ -237,8 +325,7 @@ namespace webifc::parsing { bytes[i+1] = c; } std::u16string u16str(reinterpret_cast(&bytes[0]), bytes.size() / 2); - std::wstring_convert,char16_t> convert; - utf8 = convert.to_bytes(u16str); + utf8 = utf8_from_utf16(u16str); } else if (T == 4) { @@ -251,8 +338,8 @@ namespace webifc::parsing { bytes[i+2] = c; } std::u32string u32str(reinterpret_cast(&bytes[0]), bytes.size() / 4); - std::wstring_convert,char32_t> convert; - utf8 = convert.to_bytes(u32str); + + utf8 = utf8_from_utf32(u32str); } std::copy(utf8.begin(), utf8.end(), std::back_inserter(result)); } From 3241f7a4c1f4b99ead2d43e20765a89463d3d559 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 18 Feb 2025 18:11:09 +0200 Subject: [PATCH 2/9] In Extrude(), check if first point is equal to last point, otherwise the outer loop of the shape is not closed --- .../geometry/operations/geometryutils.h | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/cpp/web-ifc/geometry/operations/geometryutils.h b/src/cpp/web-ifc/geometry/operations/geometryutils.h index a4b989e51..e3a8808a3 100644 --- a/src/cpp/web-ifc/geometry/operations/geometryutils.h +++ b/src/cpp/web-ifc/geometry/operations/geometryutils.h @@ -824,6 +824,12 @@ namespace webifc::geometry IfcGeometry geom; std::vector holesIndicesHash; + // check if first point is equal to last point, otherwise the outer loop of the shape is not closed + glm::dvec3 lastToFirstPoint = profile.curve.points.front() - profile.curve.points.back(); + if (glm::length(lastToFirstPoint) > 1e-8) { + profile.curve.points.push_back(profile.curve.points.front()); + } + // build the caps { using Point = std::array; @@ -935,31 +941,28 @@ namespace webifc::geometry } uint32_t capSize = profile.curve.points.size(); - for (size_t i = 1; i <= capSize; i++) + for (size_t i = 1; i < capSize; i++) { // https://github.com/tomvandig/web-ifc/issues/5 - if (i < capSize) + if (holesIndicesHash[i]) { - if (holesIndicesHash[i]) - { - continue; - } + continue; } uint32_t bl = i - 1; - uint32_t br = i % capSize; + uint32_t br = i - 0; uint32_t tl = capSize + i - 1; - uint32_t tr = capSize + i % capSize; + uint32_t tr = capSize + i - 0; // this winding should be correct geom.AddFace(geom.GetPoint(tl), - geom.GetPoint(br), - geom.GetPoint(bl)); + geom.GetPoint(br), + geom.GetPoint(bl)); geom.AddFace(geom.GetPoint(tl), - geom.GetPoint(tr), - geom.GetPoint(br)); + geom.GetPoint(tr), + geom.GetPoint(br)); } return geom; From 1f31adb31b7c2d91f9c93ae48c788fd9b58abb82 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 18 Feb 2025 18:13:33 +0200 Subject: [PATCH 3/9] add tabs to make diff cleaner --- src/cpp/web-ifc/geometry/operations/geometryutils.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cpp/web-ifc/geometry/operations/geometryutils.h b/src/cpp/web-ifc/geometry/operations/geometryutils.h index e3a8808a3..ef25a8b20 100644 --- a/src/cpp/web-ifc/geometry/operations/geometryutils.h +++ b/src/cpp/web-ifc/geometry/operations/geometryutils.h @@ -957,12 +957,12 @@ namespace webifc::geometry // this winding should be correct geom.AddFace(geom.GetPoint(tl), - geom.GetPoint(br), - geom.GetPoint(bl)); + geom.GetPoint(br), + geom.GetPoint(bl)); geom.AddFace(geom.GetPoint(tl), - geom.GetPoint(tr), - geom.GetPoint(br)); + geom.GetPoint(tr), + geom.GetPoint(br)); } return geom; From a891211ea420e8acab9a6fa9c52c143e0150df02 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 18 Feb 2025 18:41:45 +0200 Subject: [PATCH 4/9] enable polylines as mesh for IFCGRID. add bounds checks - enable polylines as mesh for IFCGRID, IFCGRIDAXIS - add bounds checks in TriangulateRevolution --- .../web-ifc/geometry/IfcGeometryProcessor.cpp | 37 ++++++++++++++++++- .../web-ifc/geometry/operations/mesh_utils.h | 21 +++++++++-- .../geometry/representation/IfcGeometry.h | 3 +- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp index 7668dbfb0..8c1576faf 100644 --- a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp +++ b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp @@ -984,6 +984,7 @@ namespace webifc::geometry return mesh; } case schema::IFCGEOMETRICSET: + case schema::IFCGEOMETRICCURVESET: { _loader.MoveToArgumentOffset(expressID, 0); auto items = _loader.GetSetArgument(); @@ -996,11 +997,43 @@ namespace webifc::geometry return mesh; } + case schema::IFCBOUNDINGBOX: + // ignore bounding box + return mesh; + case schema::IFCCIRCLE: case schema::IFCPOLYLINE: case schema::IFCINDEXEDPOLYCURVE: case schema::IFCTRIMMEDCURVE: - // ignore polylines as meshes - return mesh; + { + // could be + // #1324059= IFCGRID('3Yls6_O6GJNv5JAJ8l_3XY',#35,'Raster 001',$,$,#1323916,#1324056,(#1323917),$,$); + // #1323917= IFCGRIDAXIS('7',#1323926,.T.); + // #1323926= IFCINDEXEDPOLYCURVE(#1323922,(IFCLINEINDEX((1,2))),$); + 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; + } default: spdlog::error("[GetMesh()] unexpected mesh type {}", expressID, lineType); break; diff --git a/src/cpp/web-ifc/geometry/operations/mesh_utils.h b/src/cpp/web-ifc/geometry/operations/mesh_utils.h index a7481c196..d1e9b7b64 100644 --- a/src/cpp/web-ifc/geometry/operations/mesh_utils.h +++ b/src/cpp/web-ifc/geometry/operations/mesh_utils.h @@ -184,10 +184,23 @@ namespace webifc::geometry for (int r = 0; r < numRots - 1; r++) { int r1 = r + 1; - for (size_t s = 0; s < newPoints[r].size() - 1; s++) - { - geometry.AddFace(newPoints[r][s], newPoints[r][s + 1], newPoints[r1][s]); - geometry.AddFace(newPoints[r1][s], newPoints[r][s + 1], newPoints[r1][s + 1]); + if (r1 >= newPoints.size()) { + break; + } + const std::vector& newPointsR = newPoints[r]; + const std::vector& newPointsR1 = newPoints[r1]; + if (newPointsR.size() > 0) { + for (size_t s = 0; s < newPointsR.size() - 1; s++) + { + if (s + 1 >= newPointsR.size()) { + break; + } + if (s + 1 >= newPointsR1.size()) { + break; + } + geometry.AddFace(newPointsR[s], newPointsR[s + 1], newPointsR1[s]); + geometry.AddFace(newPointsR1[s], newPointsR[s + 1], newPointsR1[s + 1]); + } } } } diff --git a/src/cpp/web-ifc/geometry/representation/IfcGeometry.h b/src/cpp/web-ifc/geometry/representation/IfcGeometry.h index 3186c134d..1ff3c5d53 100644 --- a/src/cpp/web-ifc/geometry/representation/IfcGeometry.h +++ b/src/cpp/web-ifc/geometry/representation/IfcGeometry.h @@ -56,7 +56,8 @@ namespace webifc::geometry { std::vector indexData; std::vector planeData; std::vector planes; - + + bool isPolygon = false; bool hasPlanes = false; uint32_t numPoints = 0; uint32_t numFaces = 0; From 9c1d98e0d102d3de445b4fb1daa4397edbfc66c9 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 18 Feb 2025 19:11:05 +0200 Subject: [PATCH 5/9] make scaling mehses optional make scaling by _geometryLoader.GetLinearScalingFactor() optional in GetFlatMesh. Alternative would be: make IfcGeometryProcessor::AddComposedMeshToFlatMesh public --- src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp | 8 ++++++-- src/cpp/web-ifc/geometry/IfcGeometryProcessor.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp index 8c1576faf..2f7cbe66b 100644 --- a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp +++ b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp @@ -1431,7 +1431,7 @@ namespace webifc::geometry return IfcSurface(); } - IfcFlatMesh IfcGeometryProcessor::GetFlatMesh(uint32_t expressID) + IfcFlatMesh IfcGeometryProcessor::GetFlatMesh(uint32_t expressID, bool applyLinearScalingFactor) { spdlog::debug("[GetFlatMesh({})]",expressID); IfcFlatMesh flatMesh; @@ -1439,7 +1439,11 @@ namespace webifc::geometry IfcComposedMesh composedMesh = GetMesh(expressID); - glm::dmat4 mat = glm::scale(glm::dvec3(_geometryLoader.GetLinearScalingFactor())); + glm::dmat4 mat = glm::dmat4(1); + if (applyLinearScalingFactor) + { + mat = glm::scale(glm::dvec3(_geometryLoader.GetLinearScalingFactor()));; + } AddComposedMeshToFlatMesh(flatMesh, composedMesh, _transformation * NormalizeIFC * mat); diff --git a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.h b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.h index 7b9652daa..7a93db8fe 100644 --- a/src/cpp/web-ifc/geometry/IfcGeometryProcessor.h +++ b/src/cpp/web-ifc/geometry/IfcGeometryProcessor.h @@ -39,7 +39,7 @@ namespace webifc::geometry IfcGeometryProcessor(const webifc::parsing::IfcLoader &loader,const webifc::schema::IfcSchemaManager &schemaManager,uint16_t circleSegments,bool coordinateToOrigin); IfcGeometry &GetGeometry(uint32_t expressID); IfcGeometryLoader GetLoader() const; - IfcFlatMesh GetFlatMesh(uint32_t expressID); + IfcFlatMesh GetFlatMesh(uint32_t expressID, bool applyLinearScalingFactor = true); IfcComposedMesh GetMesh(uint32_t expressID); void SetTransformation(const std::array &val); std::array GetFlatCoordinationMatrix() const; From fc1a599d4be00b3ed72b800fc6d0e1ad8cefffd1 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Tue, 25 Feb 2025 15:48:58 +0200 Subject: [PATCH 6/9] in VectorToAngle: add check for zero, to avoid inf values in mesh --- src/cpp/web-ifc/geometry/operations/geometryutils.h | 3 +++ src/cpp/web-ifc/schema/IfcSchemaManager.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/cpp/web-ifc/geometry/operations/geometryutils.h b/src/cpp/web-ifc/geometry/operations/geometryutils.h index ef25a8b20..6d9e7df56 100644 --- a/src/cpp/web-ifc/geometry/operations/geometryutils.h +++ b/src/cpp/web-ifc/geometry/operations/geometryutils.h @@ -1000,6 +1000,9 @@ namespace webifc::geometry inline double VectorToAngle(double x, double y) { double dd = sqrt(x * x + y * y); + if (std::abs(dd) < EPS_MINISCULE) { + return 0; + } double xx = x / dd; double yy = y / dd; diff --git a/src/cpp/web-ifc/schema/IfcSchemaManager.h b/src/cpp/web-ifc/schema/IfcSchemaManager.h index f2d052489..79f756f94 100644 --- a/src/cpp/web-ifc/schema/IfcSchemaManager.h +++ b/src/cpp/web-ifc/schema/IfcSchemaManager.h @@ -6,6 +6,7 @@ #include "ifc-schema.h" #include +#include #include #include #include From 398041443f0fd2658ad68fb02e7f52b004112861 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Fri, 28 Feb 2025 20:41:49 +0200 Subject: [PATCH 7/9] 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 | 103 +++++++++++++++++- src/cpp/web-ifc/parsing/IfcLoader.cpp | 3 +- 3 files changed, 124 insertions(+), 8 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 df044d2f8..f77afb470 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: { @@ -1031,15 +1081,56 @@ namespace webifc::geometry 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: { - // could be - // #1324059= IFCGRID('3Yls6_O6GJNv5JAJ8l_3XY',#35,'Raster 001',$,$,#1323916,#1324056,(#1323917),$,$); - // #1323917= IFCGRIDAXIS('7',#1323926,.T.); - // #1323926= IFCINDEXEDPOLYCURVE(#1323922,(IFCLINEINDEX((1,2))),$); auto lineProfileType = _loader.GetLineType(expressID); IfcCurve curve = _geometryLoader.GetCurve(expressID, 3, false); @@ -1065,6 +1156,10 @@ namespace webifc::geometry 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 196218af7..9970f1d9e 100644 --- a/src/cpp/web-ifc/parsing/IfcLoader.cpp +++ b/src/cpp/web-ifc/parsing/IfcLoader.cpp @@ -666,7 +666,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(); From 7053528ccc3ceccec495134a81983cab49c954cf Mon Sep 17 00:00:00 2001 From: ifcapps Date: Thu, 13 Mar 2025 13:36:09 +0100 Subject: [PATCH 8/9] 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 e912179ee9a7dae0b84dec435b9a03f88ae31ed5 Mon Sep 17 00:00:00 2001 From: ifcapps Date: Thu, 13 Mar 2025 13:49:54 +0100 Subject: [PATCH 9/9] update results.json --- 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 df334c66f..cc5cd6563 100644 --- a/tests/regression/results.json +++ b/tests/regression/results.json @@ -1 +1 @@ -{"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 +{"tests/ifcfiles/public/AC20-FZK-Haus.ifc":"6bf7a4d4e18776a6952914fd03acd96f81623ca5da6e5a7876fe4e64fd8df22e","tests/ifcfiles/public/C20-Institute-Var-2.ifc":"288a7ba65b562e1bdd6548f60f0e2339306578625cb445670f0bbf1c8a4560c3","tests/ifcfiles/public/FM_ARC_DigitalHub.ifc":"3f748003c12da6c4ad13df2c202a0997c7517a10cc5303b1555568e03f5b001c","tests/ifcfiles/public/ISSUE_005_haus.ifc":"6bf7a4d4e18776a6952914fd03acd96f81623ca5da6e5a7876fe4e64fd8df22e","tests/ifcfiles/public/ISSUE_021_Mini Project.ifc":"b5076f409b371d847cb453a9ab9a8d9de9d1c0eb27748ba7adc65571e0555a37","tests/ifcfiles/public/ISSUE_034_HouseZ.ifc":"ef512e88e26c916849445d3b741dd7979ee8a0dbf79ca788502092f84ea8f92b","tests/ifcfiles/public/ISSUE_044_test_IFCCOMPOSITEPROFILEDEF.ifc":"1b10710a3237960ed421ed8069bfd7ba2fa42cf15a52ef2139c8b3ed887e9b85","tests/ifcfiles/public/ISSUE_053_20181220Holter_Tower_10.ifczip":"5a7a3711e8841135cc86bf92ba0ae9acc7e97b7a069927a64678c17653d3e609","tests/ifcfiles/public/ISSUE_068_ARK_NUS_skolebygg.ifc":"cd3081a53bd5667173caf391b17c5b1878fef4bfc252ef8330556e39afbd7c0d","tests/ifcfiles/public/ISSUE_102_M3D-CON-CD.ifc":"6e9612de56c08323e96b21e8f4097e42964bdf93066d460ddb0e7c184abdd15b","tests/ifcfiles/public/ISSUE_102_M3D-CON.ifc":"c83a0f31c6a52928fb9797456689c69c63d156c5bdf53cb49a83ed10d9e5bc23","tests/ifcfiles/public/ISSUE_126_model.ifc":"78e336de53ec658f2cd8fb51d5e2797ae1b5832cdadcdc22e7d0330a275a9545","tests/ifcfiles/public/ISSUE_129_N1540_17_EXE_MOD_448200_02_09_11SMC_IGC_V17.ifc":"a36fc248e0a8012045cd11f54ad0e9ed9fd7d7e7729a100599742fa8b06b4971","tests/ifcfiles/public/ISSUE_159_kleine_Wohnung_R22.ifc":"a304e69ac97a6300ef5213254ca5ca3d8b2dd88d7daa026115138e138c5cf395","tests/ifcfiles/public/ISSUE_171_IfcSurfaceCurveSweptAreaSolid.ifc":"f2db8111ba05365cc54a6bcf8aade27764acfb615889f9302088aa1f1aa57c50","tests/ifcfiles/public/IfcOpenHouse_IFC4.ifc":"a9d854a4e47646bdc613aeca3c385474e851ac22b98bb8b7d783f7fee2f42c60","tests/ifcfiles/public/KIT-Simple-Road-Test-Web-IFC4x3_RC2.ifc":"3d8707ee9d70e2aeb67b8bebdc96016a1eceb30afd9a25e9cf6c258d978a6fe6","tests/ifcfiles/public/Office_A_20110811.ifc":"347c5e27081f0e29460124352781054ad2e00c0c09316b20f1981ae4e86a22ee","tests/ifcfiles/public/S_Office_Integrated Design Archi.ifc":"62cb878a60d880d989797a00f0faacdf5ad01a7f9ee1131e6804977366fb509a","tests/ifcfiles/public/Sample_entities.ifc":"270a55940a77ebb4f245cabf8c7429dc8fc7044baf9c9434fc747842f602d792","tests/ifcfiles/public/advanced_model.ifc":"c3247ec09d381688bb901d3bd85ae51a01dba70105cd9274b8cfd194ba94da12","tests/ifcfiles/public/dental_clinic.ifc":"757f4eccbbf9cd59806bee813e902cb13b6ace71bac106e4bce109764a79fbb2","tests/ifcfiles/public/duplex.ifc":"1da1e60682e4be608affcc697e79d24b76b984d7cc9cd465c3b97499a3a681ed","tests/ifcfiles/public/example.ifc":"4b9ab3d47e0b8e82fe2cb9a69ef452192204891528a291e989ccbc02aae27391","tests/ifcfiles/public/ifcbridge-model01.ifc":"00c016be5509e4145b3662dbdeedd67e7e60e6648ad1c247d6a41e41657b7e33","tests/ifcfiles/public/schependomlaan.ifc":"a0c7e4f336323a772f2dde464ed8919c4c5d3b3d4b62342129a4da73f5526880","tests/ifcfiles/public/tested_sample_project.ifc":"c4bf6c87a2e09795f0d854dc2c6eeb92829790c565ff86b1e03007648729bb26"} \ No newline at end of file