Skip to content

Commit ee32c67

Browse files
authored
Merge pull request #1629 from Creoox/ViadottoAcerno
Fix/implement IFCSECTIONEDSOLIDHORIZONTAL, IfcClothoid, IfcGradientCu…
2 parents 8887219 + 58ca1b7 commit ee32c67

File tree

13 files changed

+255675
-438
lines changed

13 files changed

+255675
-438
lines changed

src/cpp/test/dumpToThree.h

Lines changed: 596 additions & 0 deletions
Large diffs are not rendered by default.

src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp

Lines changed: 1203 additions & 344 deletions
Large diffs are not rendered by default.

src/cpp/web-ifc/geometry/IfcGeometryLoader.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#pragma once
66

7+
#include <map>
78
#include <unordered_map>
89
#include <vector>
910
#include <optional>
@@ -37,6 +38,16 @@ namespace webifc::geometry
3738
IfcProfile GetProfile3D(uint32_t expressID) const;
3839
IfcCurve GetLocalCurve(uint32_t expressID) const;
3940
IfcCurve GetCurve(uint32_t expressID, uint8_t dimensions, bool edge = false) const;
41+
42+
// Helper function to compute the total length of the curve
43+
double ComputeCurveLength(const IfcCurve& curve) const;
44+
45+
// Helper function to compute the length along the curve up to a specific point
46+
double ComputeLengthToPoint(const IfcCurve& curve, const glm::dvec3& targetPoint) const;
47+
48+
// Helper function to compute parameter for a point on the base curve
49+
double GetParameterForPoint(const IfcCurve& curve, double totalLength, const glm::dvec3& point) const;
50+
4051
bool ReadIfcCartesianPointList(const uint32_t expressID) const;
4152
std::vector<glm::dvec3> ReadIfcCartesianPointList3D(const uint32_t expressID) const;
4253
std::vector<glm::dvec2> ReadIfcCartesianPointList2D(const uint32_t expressID) const;
@@ -47,6 +58,7 @@ namespace webifc::geometry
4758
std::optional<glm::dvec4> GetColor(uint32_t expressID) const;
4859
IfcCrossSections GetCrossSections2D(uint32_t expressID) const;
4960
IfcCrossSections GetCrossSections3D(uint32_t expressID, bool scaled = false, glm::dmat4 coordination = glm::dmat4(1)) const;
61+
void getPlacementsOnCurvePoints(uint32_t curveID, std::map<double, glm::dmat4>& mapPlacements) const;
5062
IfcAlignment GetAlignment(uint32_t expressID, IfcAlignment alignment = IfcAlignment(), glm::dmat4 transform = glm::dmat4(1), uint32_t sourceExpressID = -1) const;
5163
bool GetColor(const uint32_t expressID, const glm::dvec4 &outputColor) const;
5264
const std::unordered_map<uint32_t, std::vector<uint32_t>> &GetRelVoids() const;
@@ -64,9 +76,32 @@ namespace webifc::geometry
6476
IfcProfile GetProfileByLine(uint32_t expressID) const;
6577
glm::dvec3 GetVertexPoint(uint32_t expressID) const;
6678
IfcTrimmingSelect GetTrimSelect(uint32_t DIM, std::vector<uint32_t> &tapeOffsets) const;
67-
void ComputeCurve(uint32_t expressID, IfcCurve &curve, uint8_t dimensions, bool edge, int sameSense = -1, int trimSense = -1, IfcTrimmingArguments trim = {}) const;
79+
80+
struct ComputeCurveParams {
81+
ComputeCurveParams() = default;
82+
ComputeCurveParams(const ComputeCurveParams& other) {
83+
dimensions = other.dimensions;
84+
ignorePlacement = other.ignorePlacement;
85+
edge = other.edge;
86+
sameSense = other.sameSense;
87+
hasTrim = other.hasTrim;
88+
trimStart = other.trimStart;
89+
trimEnd = other.trimEnd;
90+
trimSense = other.trimSense;
91+
}
92+
uint8_t dimensions = 2;
93+
bool ignorePlacement = false;
94+
bool edge = false;
95+
int sameSense = -1;
96+
bool hasTrim = false;
97+
IfcTrimmingSelect trimStart;
98+
IfcTrimmingSelect trimEnd;
99+
TrimSense trimSense = TRIM_SENSE_SAME;
100+
};
101+
void ComputeCurve(uint32_t expressID, IfcCurve &curve, const ComputeCurveParams& params) const;
68102
void convertAngleUnits(double &Degrees, double &Rad) const;
69103
double ReadLenghtMeasure() const;
104+
void ReadCurveMeasureSelect(IfcTrimmingSelect& trim) const;
70105
std::vector<IfcSegmentIndexSelect> ReadCurveIndices() const;
71106
const webifc::parsing::IfcLoader &_loader;
72107
const webifc::schema::IfcSchemaManager &_schemaManager;

src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
namespace webifc::geometry
2121
{
22-
IfcGeometryProcessor::IfcGeometryProcessor(const webifc::parsing::IfcLoader &loader, const webifc::schema::IfcSchemaManager &schemaManager, uint16_t circleSegments, bool coordinateToOrigin, double TOLERANCE_PLANE_INTERSECTION, double TOLERANCE_PLANE_DEVIATION, double TOLERANCE_BACK_DEVIATION_DISTANCE, double TOLERANCE_INSIDE_OUTSIDE_PERIMETER, double TOLERANCE_SCALAR_EQUALITY, double PLANE_REFIT_ITERATIONS, double BOOLEAN_UNION_THRESHOLD)
22+
IfcGeometryProcessor::IfcGeometryProcessor(webifc::parsing::IfcLoader &loader, const webifc::schema::IfcSchemaManager &schemaManager, uint16_t circleSegments, bool coordinateToOrigin, double TOLERANCE_PLANE_INTERSECTION, double TOLERANCE_PLANE_DEVIATION, double TOLERANCE_BACK_DEVIATION_DISTANCE, double TOLERANCE_INSIDE_OUTSIDE_PERIMETER, double TOLERANCE_SCALAR_EQUALITY, double PLANE_REFIT_ITERATIONS, double BOOLEAN_UNION_THRESHOLD)
2323
: _geometryLoader(loader, schemaManager, circleSegments, TOLERANCE_PLANE_INTERSECTION, TOLERANCE_PLANE_DEVIATION, TOLERANCE_BACK_DEVIATION_DISTANCE, TOLERANCE_INSIDE_OUTSIDE_PERIMETER, TOLERANCE_SCALAR_EQUALITY, PLANE_REFIT_ITERATIONS, BOOLEAN_UNION_THRESHOLD), _loader(loader), _schemaManager(schemaManager)
2424
{
2525
_settings._coordinateToOrigin = coordinateToOrigin;
@@ -32,9 +32,9 @@ namespace webifc::geometry
3232
SetEpsilons(TOLERANCE_SCALAR_EQUALITY, PLANE_REFIT_ITERATIONS, BOOLEAN_UNION_THRESHOLD);
3333
}
3434

35-
IfcGeometryLoader IfcGeometryProcessor::GetLoader() const
35+
IfcGeometryLoader& IfcGeometryProcessor::GetLoader()
3636
{
37-
return _geometryLoader;
37+
return _geometryLoader;
3838
}
3939

4040
void IfcGeometryProcessor::SetTransformation(const std::array<double, 16> &val)
@@ -329,8 +329,9 @@ namespace webifc::geometry
329329
case schema::IFCSECTIONEDSURFACE:
330330
{
331331
auto geom = SectionedSurface(_geometryLoader.GetCrossSections3D(expressID),EPS_SMALL);
332+
332333
mesh.transformation = glm::dmat4(1);
333-
// TODO: this is getting problematic.....
334+
334335
_expressIDToGeometry[expressID] = geom;
335336
mesh.hasGeometry = true;
336337

@@ -880,11 +881,49 @@ namespace webifc::geometry
880881

881882
return mesh;
882883
}
883-
case schema::IFCSWEPTDISKSOLID:
884+
case schema::IFCFIXEDREFERENCESWEPTAREASOLID:
884885
{
886+
_loader.MoveToArgumentOffset(expressID, 0);
887+
uint32_t profileID = _loader.GetRefArgument();
888+
uint32_t placementID = _loader.GetOptionalRefArgument();
889+
uint32_t directrixRef = _loader.GetRefArgument();
890+
uint32_t fixedReferenceID = _loader.GetRefArgument();
885891

886-
// TODO: prevent self intersections in Sweep function still not working properly
892+
// Retrieve profile, placement, directrix, and fixed reference direction
893+
IfcProfile profile = _geometryLoader.GetProfile(profileID);
894+
glm::dmat4 placement = placementID ? _geometryLoader.GetLocalPlacement(placementID) : glm::dmat4(1.0);
895+
IfcCurve directrix = _geometryLoader.GetCurve(directrixRef, 3);
896+
glm::dvec3 fixedReference = _geometryLoader.GetCartesianPoint3D(fixedReferenceID);
897+
898+
// Check for valid profile and directrix
899+
if (profile.curve.points.empty() || directrix.points.empty()) {
900+
spdlog::error("[GetMesh()] Invalid profile or directrix for IFCFIXEDREFERENCESWEPTAREASOLID {}", expressID);
901+
return mesh;
902+
}
887903

904+
// Determine if the sweep is closed
905+
bool closed = glm::distance(directrix.points[0], directrix.points[directrix.points.size() - 1]) < EPS_SMALL;
906+
907+
// Generate geometry by sweeping the profile with fixed orientation
908+
IfcGeometry geom = SweepFixedReference(
909+
_geometryLoader.GetLinearScalingFactor(),
910+
closed,
911+
profile,
912+
directrix,
913+
fixedReference
914+
);
915+
916+
// Store the geometry and update mesh
917+
_expressIDToGeometry[expressID] = geom;
918+
mesh.expressID = expressID;
919+
mesh.hasGeometry = true;
920+
mesh.transformation = placement;
921+
922+
return mesh;
923+
}
924+
case schema::IFCSWEPTDISKSOLID:
925+
{
926+
// TODO: prevent self intersections in Sweep function still not working properly
888927
bool closed = false;
889928

890929
_loader.MoveToArgumentOffset(expressID, 0);
@@ -1072,6 +1111,37 @@ namespace webifc::geometry
10721111

10731112
return mesh;
10741113
}
1114+
case schema::IFCRIGHTCIRCULARCYLINDER:
1115+
{
1116+
_loader.MoveToArgumentOffset(expressID, 0);
1117+
uint32_t placementID = _loader.GetRefArgument();
1118+
double height = _loader.GetDoubleArgument();
1119+
double radius = _loader.GetDoubleArgument();
1120+
1121+
// Create a circular profile
1122+
IfcProfile profile;
1123+
profile.isConvex = true;
1124+
profile.curve = GetCircleCurve(radius, _settings._circleSegments);
1125+
1126+
// Extrude along Z-axis
1127+
glm::dvec3 extrusionDir = glm::dvec3(0, 0, 1);
1128+
IfcGeometry geom = Extrude(profile, extrusionDir, height);
1129+
1130+
// Set transformation
1131+
if (placementID)
1132+
{
1133+
mesh.transformation = _geometryLoader.GetLocalPlacement(placementID);
1134+
}
1135+
1136+
#ifdef CSG_DEBUG_OUTPUT
1137+
io::DumpIfcGeometry(geom, "IFCRIGHTCIRCULARCYLINDER_geom.obj");
1138+
#endif
1139+
1140+
_expressIDToGeometry[expressID] = geom;
1141+
mesh.expressID = expressID;
1142+
mesh.hasGeometry = true;
1143+
return mesh;
1144+
}
10751145
case schema::IFCGEOMETRICSET:
10761146
case schema::IFCGEOMETRICCURVESET:
10771147
{
@@ -1135,9 +1205,11 @@ namespace webifc::geometry
11351205
return mesh;
11361206
}
11371207
case schema::IFCCIRCLE:
1208+
case schema::IFCCOMPOSITECURVE:
11381209
case schema::IFCPOLYLINE:
11391210
case schema::IFCINDEXEDPOLYCURVE:
11401211
case schema::IFCTRIMMEDCURVE:
1212+
case schema::IFCGRADIENTCURVE:
11411213
{
11421214
auto lineProfileType = _loader.GetLineType(expressID);
11431215
IfcCurve curve = _geometryLoader.GetCurve(expressID, 3, false);

src/cpp/web-ifc/geometry/IfcGeometryProcessor.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ namespace webifc::geometry
5050
class IfcGeometryProcessor
5151
{
5252
public:
53-
IfcGeometryProcessor(const webifc::parsing::IfcLoader &loader, const webifc::schema::IfcSchemaManager &schemaManager, uint16_t circleSegments, bool coordinateToOrigin, double TOLERANCE_PLANE_INTERSECTION, double TOLERANCE_PLANE_DEVIATION, double TOLERANCE_BACK_DEVIATION_DISTANCE, double TOLERANCE_INSIDE_OUTSIDE_PERIMETER, double TOLERANCE_SCALAR_EQUALITY, double PLANE_REFIT_ITERATIONS, double BOOLEAN_UNION_THRESHOLD);
53+
IfcGeometryProcessor(webifc::parsing::IfcLoader &loader, const webifc::schema::IfcSchemaManager &schemaManager, uint16_t circleSegments, bool coordinateToOrigin, double TOLERANCE_PLANE_INTERSECTION, double TOLERANCE_PLANE_DEVIATION, double TOLERANCE_BACK_DEVIATION_DISTANCE, double TOLERANCE_INSIDE_OUTSIDE_PERIMETER, double TOLERANCE_SCALAR_EQUALITY, double PLANE_REFIT_ITERATIONS, double BOOLEAN_UNION_THRESHOLD);
5454
IfcGeometry &GetGeometry(uint32_t expressID);
55-
IfcGeometryLoader GetLoader() const;
55+
IfcGeometryLoader& GetLoader();
5656
IfcFlatMesh GetFlatMesh(uint32_t expressID, bool applyLinearScalingFactor = true);
5757
IfcComposedMesh GetMesh(uint32_t expressID);
5858
void SetTransformation(const std::array<double, 16> &val);
@@ -70,7 +70,7 @@ namespace webifc::geometry
7070
IfcGeometry BoolProcess(const std::vector<IfcGeometry> &firstGroups, std::vector<IfcGeometry> &secondGroups, std::string op, IfcGeometrySettings _settings);
7171
std::unordered_map<uint32_t, IfcGeometry> _expressIDToGeometry;
7272
IfcSurface GetSurface(uint32_t expressID);
73-
const IfcGeometryLoader _geometryLoader;
73+
IfcGeometryLoader _geometryLoader;
7474
glm::dmat4 _transformation = glm::dmat4(1.0);
7575
const parsing::IfcLoader &_loader;
7676
booleanManager _boolEngine;

src/cpp/web-ifc/geometry/operations/bim-geometry/utils.h

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,52 +1231,73 @@ namespace bimGeometry
12311231
{
12321232
Geometry geom;
12331233

1234-
// Iterate over each profile, and create a surface by connecting the corresponding points with faces.
1234+
// Check for insufficient profiles
1235+
if (profiles.size() < 2)
1236+
{
1237+
//spdlog::warn("SectionedSurface: Fewer than 2 profiles provided ({}), returning empty geometry.", profiles.size());
1238+
return geom;
1239+
}
1240+
1241+
// Iterate over each pair of consecutive profiles
12351242
for (size_t i = 0; i < profiles.size() - 1; i++)
12361243
{
1237-
std::vector<glm::dvec3> &profile1 = profiles[i];
1238-
std::vector<glm::dvec3> &profile2 = profiles[i + 1];
1244+
std::vector<glm::dvec3>& profile1 = profiles[i];
1245+
std::vector<glm::dvec3>& profile2 = profiles[i + 1];
12391246

1240-
// Check that the profiles have the same number of points
1247+
// Check that profiles have the same number of points and are non-empty
1248+
if (profile1.empty() || profile2.empty())
1249+
{
1250+
//spdlog::warn("SectionedSurface: Empty profile at index {}, skipping.", i);
1251+
continue;
1252+
}
12411253
if (profile1.size() != profile2.size())
12421254
{
1255+
//spdlog::warn("SectionedSurface: Profile {} has {} points, but profile {} has {} points, skipping.", i, profile1.size(), i + 1, profile2.size());
1256+
continue;
12431257
}
12441258

12451259
std::vector<uint32_t> indices;
12461260

1247-
// Create faces by connecting corresponding points from the two profiles
1261+
// Add points and compute normals
12481262
for (size_t j = 0; j < profile1.size(); j++)
12491263
{
1250-
glm::dvec3 &p1 = profile1[j];
1251-
int j2 = 0;
1252-
if (profile1.size() > 1)
1253-
{
1254-
double pr = (double)j / (double)(profile1.size() - 1);
1255-
j2 = pr * (profile2.size() - 1);
1256-
}
1257-
glm::dvec3 &p2 = profile2[j2];
1264+
glm::dvec3& p1 = profile1[j];
1265+
glm::dvec3& p2 = profile2[j]; // Direct correspondence, assuming equal sizes
12581266

1259-
glm::dvec3 normal = glm::dvec3(0.0, 0.0, 1.0);
1260-
1261-
if (glm::distance(p1, p2) > 1E-5)
1267+
// Compute normal
1268+
glm::dvec3 normal(0.0, 0.0, 1.0); // Default normal
1269+
glm::dvec3 edge = p2 - p1;
1270+
if (glm::length(edge) > eps)
12621271
{
1263-
normal = glm::normalize(glm::cross(p2 - p1, glm::cross(p2 - p1, glm::dvec3(0.0, 0.0, 1.0))));
1272+
glm::dvec3 crossVec = glm::cross(edge, glm::dvec3(0.0, 0.0, 1.0));
1273+
if (glm::length(crossVec) > eps)
1274+
{
1275+
normal = glm::normalize(glm::cross(edge, crossVec));
1276+
}
1277+
else
1278+
{
1279+
//spdlog::warn("SectionedSurface: Degenerate normal at profile {}, point {}, using default normal.", i, j);
1280+
}
12641281
}
12651282

1283+
// Add points to geometry with computed normal
12661284
geom.AddPoint(p1, normal);
12671285
geom.AddPoint(p2, normal);
12681286

1269-
indices.push_back(geom.numPoints - 2);
1270-
indices.push_back(geom.numPoints - 1);
1287+
indices.push_back(geom.numPoints - 2); // Index of p1
1288+
indices.push_back(geom.numPoints - 1); // Index of p2
12711289
}
12721290

1273-
// Create the faces
1274-
if (indices.size() > 0)
1291+
// Create triangular faces
1292+
for (size_t j = 0; j < indices.size() - 2; j += 2)
12751293
{
1276-
for (size_t j = 0; j < indices.size() - 2; j += 4)
1294+
if (j + 3 < indices.size()) // Ensure enough indices for two triangles
12771295
{
1278-
geom.AddFace(indices[j], indices[j + 1], indices[j + 2], UINT32_MAX);
1279-
geom.AddFace(indices[j + 2], indices[j + 1], indices[j + 3], UINT32_MAX);
1296+
// Form two triangles for each quad (p1[j], p2[j], p1[j+1], p2[j+1])
1297+
// Triangle 1: p1[j], p2[j], p1[j+1]
1298+
geom.AddFace(indices[j], indices[j + 1], indices[j + 2], -1);
1299+
// Triangle 2: p2[j], p2[j+1], p1[j+1]
1300+
geom.AddFace(indices[j + 1], indices[j + 3], indices[j + 2], -1);
12801301
}
12811302
}
12821303
}
@@ -1366,8 +1387,6 @@ namespace bimGeometry
13661387
return geom;
13671388
}
13681389

1369-
///
1370-
13711390
inline Curve GetRectangleCurve(double xdim, double ydim, glm::dmat4 placement = glm::dmat4(1), int numSegments = 12, double radius = 0)
13721391
{
13731392
if (radius == 0)

src/cpp/web-ifc/geometry/operations/curve-utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#pragma once
66

77
#include <cstdint>
8+
#include <glm/glm.hpp>
9+
#include <glm/gtc/matrix_transform.hpp>
810
#include "../representation/IfcCurve.h"
911

1012
namespace webifc::geometry {
@@ -533,5 +535,4 @@ inline IfcCurve Build3DArc3Pt(const glm::dvec3 &p1, const glm::dvec3 &p2, const
533535

534536
return curve;
535537
}
536-
537538
}

0 commit comments

Comments
 (0)