Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
596 changes: 596 additions & 0 deletions src/cpp/test/dumpToThree.h

Large diffs are not rendered by default.

1,547 changes: 1,203 additions & 344 deletions src/cpp/web-ifc/geometry/IfcGeometryLoader.cpp

Large diffs are not rendered by default.

37 changes: 36 additions & 1 deletion src/cpp/web-ifc/geometry/IfcGeometryLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include <map>
#include <unordered_map>
#include <vector>
#include <optional>
Expand Down Expand Up @@ -37,6 +38,16 @@ namespace webifc::geometry
IfcProfile GetProfile3D(uint32_t expressID) const;
IfcCurve GetLocalCurve(uint32_t expressID) const;
IfcCurve GetCurve(uint32_t expressID, uint8_t dimensions, bool edge = false) const;

// Helper function to compute the total length of the curve
double ComputeCurveLength(const IfcCurve& curve) const;

// Helper function to compute the length along the curve up to a specific point
double ComputeLengthToPoint(const IfcCurve& curve, const glm::dvec3& targetPoint) const;

// Helper function to compute parameter for a point on the base curve
double GetParameterForPoint(const IfcCurve& curve, double totalLength, const glm::dvec3& point) const;

bool ReadIfcCartesianPointList(const uint32_t expressID) const;
std::vector<glm::dvec3> ReadIfcCartesianPointList3D(const uint32_t expressID) const;
std::vector<glm::dvec2> ReadIfcCartesianPointList2D(const uint32_t expressID) const;
Expand All @@ -47,6 +58,7 @@ namespace webifc::geometry
std::optional<glm::dvec4> GetColor(uint32_t expressID) const;
IfcCrossSections GetCrossSections2D(uint32_t expressID) const;
IfcCrossSections GetCrossSections3D(uint32_t expressID, bool scaled = false, glm::dmat4 coordination = glm::dmat4(1)) const;
void getPlacementsOnCurvePoints(uint32_t curveID, std::map<double, glm::dmat4>& mapPlacements) const;
IfcAlignment GetAlignment(uint32_t expressID, IfcAlignment alignment = IfcAlignment(), glm::dmat4 transform = glm::dmat4(1), uint32_t sourceExpressID = -1) const;
bool GetColor(const uint32_t expressID, const glm::dvec4 &outputColor) const;
const std::unordered_map<uint32_t, std::vector<uint32_t>> &GetRelVoids() const;
Expand All @@ -64,9 +76,32 @@ namespace webifc::geometry
IfcProfile GetProfileByLine(uint32_t expressID) const;
glm::dvec3 GetVertexPoint(uint32_t expressID) const;
IfcTrimmingSelect GetTrimSelect(uint32_t DIM, std::vector<uint32_t> &tapeOffsets) const;
void ComputeCurve(uint32_t expressID, IfcCurve &curve, uint8_t dimensions, bool edge, int sameSense = -1, int trimSense = -1, IfcTrimmingArguments trim = {}) const;

struct ComputeCurveParams {
ComputeCurveParams() = default;
ComputeCurveParams(const ComputeCurveParams& other) {
dimensions = other.dimensions;
ignorePlacement = other.ignorePlacement;
edge = other.edge;
sameSense = other.sameSense;
hasTrim = other.hasTrim;
trimStart = other.trimStart;
trimEnd = other.trimEnd;
trimSense = other.trimSense;
}
uint8_t dimensions = 2;
bool ignorePlacement = false;
bool edge = false;
int sameSense = -1;
bool hasTrim = false;
IfcTrimmingSelect trimStart;
IfcTrimmingSelect trimEnd;
TrimSense trimSense = TRIM_SENSE_SAME;
};
void ComputeCurve(uint32_t expressID, IfcCurve &curve, const ComputeCurveParams& params) const;
void convertAngleUnits(double &Degrees, double &Rad) const;
double ReadLenghtMeasure() const;
void ReadCurveMeasureSelect(IfcTrimmingSelect& trim) const;
std::vector<IfcSegmentIndexSelect> ReadCurveIndices() const;
const webifc::parsing::IfcLoader &_loader;
const webifc::schema::IfcSchemaManager &_schemaManager;
Expand Down
84 changes: 78 additions & 6 deletions src/cpp/web-ifc/geometry/IfcGeometryProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

namespace webifc::geometry
{
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)
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)
: _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)
{
_settings._coordinateToOrigin = coordinateToOrigin;
Expand All @@ -32,9 +32,9 @@ namespace webifc::geometry
SetEpsilons(TOLERANCE_SCALAR_EQUALITY, PLANE_REFIT_ITERATIONS, BOOLEAN_UNION_THRESHOLD);
}

IfcGeometryLoader IfcGeometryProcessor::GetLoader() const
IfcGeometryLoader& IfcGeometryProcessor::GetLoader()
{
return _geometryLoader;
return _geometryLoader;
}

void IfcGeometryProcessor::SetTransformation(const std::array<double, 16> &val)
Expand Down Expand Up @@ -329,8 +329,9 @@ namespace webifc::geometry
case schema::IFCSECTIONEDSURFACE:
{
auto geom = SectionedSurface(_geometryLoader.GetCrossSections3D(expressID),EPS_SMALL);

mesh.transformation = glm::dmat4(1);
// TODO: this is getting problematic.....

_expressIDToGeometry[expressID] = geom;
mesh.hasGeometry = true;

Expand Down Expand Up @@ -880,11 +881,49 @@ namespace webifc::geometry

return mesh;
}
case schema::IFCSWEPTDISKSOLID:
case schema::IFCFIXEDREFERENCESWEPTAREASOLID:
{
_loader.MoveToArgumentOffset(expressID, 0);
uint32_t profileID = _loader.GetRefArgument();
uint32_t placementID = _loader.GetOptionalRefArgument();
uint32_t directrixRef = _loader.GetRefArgument();
uint32_t fixedReferenceID = _loader.GetRefArgument();

// TODO: prevent self intersections in Sweep function still not working properly
// Retrieve profile, placement, directrix, and fixed reference direction
IfcProfile profile = _geometryLoader.GetProfile(profileID);
glm::dmat4 placement = placementID ? _geometryLoader.GetLocalPlacement(placementID) : glm::dmat4(1.0);
IfcCurve directrix = _geometryLoader.GetCurve(directrixRef, 3);
glm::dvec3 fixedReference = _geometryLoader.GetCartesianPoint3D(fixedReferenceID);

// Check for valid profile and directrix
if (profile.curve.points.empty() || directrix.points.empty()) {
spdlog::error("[GetMesh()] Invalid profile or directrix for IFCFIXEDREFERENCESWEPTAREASOLID {}", expressID);
return mesh;
}

// Determine if the sweep is closed
bool closed = glm::distance(directrix.points[0], directrix.points[directrix.points.size() - 1]) < EPS_SMALL;

// Generate geometry by sweeping the profile with fixed orientation
IfcGeometry geom = SweepFixedReference(
_geometryLoader.GetLinearScalingFactor(),
closed,
profile,
directrix,
fixedReference
);

// Store the geometry and update mesh
_expressIDToGeometry[expressID] = geom;
mesh.expressID = expressID;
mesh.hasGeometry = true;
mesh.transformation = placement;

return mesh;
}
case schema::IFCSWEPTDISKSOLID:
{
// TODO: prevent self intersections in Sweep function still not working properly
bool closed = false;

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

return mesh;
}
case schema::IFCRIGHTCIRCULARCYLINDER:
{
_loader.MoveToArgumentOffset(expressID, 0);
uint32_t placementID = _loader.GetRefArgument();
double height = _loader.GetDoubleArgument();
double radius = _loader.GetDoubleArgument();

// Create a circular profile
IfcProfile profile;
profile.isConvex = true;
profile.curve = GetCircleCurve(radius, _settings._circleSegments);

// Extrude along Z-axis
glm::dvec3 extrusionDir = glm::dvec3(0, 0, 1);
IfcGeometry geom = Extrude(profile, extrusionDir, height);

// Set transformation
if (placementID)
{
mesh.transformation = _geometryLoader.GetLocalPlacement(placementID);
}

#ifdef CSG_DEBUG_OUTPUT
io::DumpIfcGeometry(geom, "IFCRIGHTCIRCULARCYLINDER_geom.obj");
#endif

_expressIDToGeometry[expressID] = geom;
mesh.expressID = expressID;
mesh.hasGeometry = true;
return mesh;
}
case schema::IFCGEOMETRICSET:
case schema::IFCGEOMETRICCURVESET:
{
Expand Down Expand Up @@ -1135,9 +1205,11 @@ namespace webifc::geometry
return mesh;
}
case schema::IFCCIRCLE:
case schema::IFCCOMPOSITECURVE:
case schema::IFCPOLYLINE:
case schema::IFCINDEXEDPOLYCURVE:
case schema::IFCTRIMMEDCURVE:
case schema::IFCGRADIENTCURVE:
{
auto lineProfileType = _loader.GetLineType(expressID);
IfcCurve curve = _geometryLoader.GetCurve(expressID, 3, false);
Expand Down
6 changes: 3 additions & 3 deletions src/cpp/web-ifc/geometry/IfcGeometryProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ namespace webifc::geometry
class IfcGeometryProcessor
{
public:
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);
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);
IfcGeometry &GetGeometry(uint32_t expressID);
IfcGeometryLoader GetLoader() const;
IfcGeometryLoader& GetLoader();
IfcFlatMesh GetFlatMesh(uint32_t expressID, bool applyLinearScalingFactor = true);
IfcComposedMesh GetMesh(uint32_t expressID);
void SetTransformation(const std::array<double, 16> &val);
Expand All @@ -70,7 +70,7 @@ namespace webifc::geometry
IfcGeometry BoolProcess(const std::vector<IfcGeometry> &firstGroups, std::vector<IfcGeometry> &secondGroups, std::string op, IfcGeometrySettings _settings);
std::unordered_map<uint32_t, IfcGeometry> _expressIDToGeometry;
IfcSurface GetSurface(uint32_t expressID);
const IfcGeometryLoader _geometryLoader;
IfcGeometryLoader _geometryLoader;
glm::dmat4 _transformation = glm::dmat4(1.0);
const parsing::IfcLoader &_loader;
booleanManager _boolEngine;
Expand Down
71 changes: 45 additions & 26 deletions src/cpp/web-ifc/geometry/operations/bim-geometry/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -1231,52 +1231,73 @@ namespace bimGeometry
{
Geometry geom;

// Iterate over each profile, and create a surface by connecting the corresponding points with faces.
// Check for insufficient profiles
if (profiles.size() < 2)
{
//spdlog::warn("SectionedSurface: Fewer than 2 profiles provided ({}), returning empty geometry.", profiles.size());
return geom;
}

// Iterate over each pair of consecutive profiles
for (size_t i = 0; i < profiles.size() - 1; i++)
{
std::vector<glm::dvec3> &profile1 = profiles[i];
std::vector<glm::dvec3> &profile2 = profiles[i + 1];
std::vector<glm::dvec3>& profile1 = profiles[i];
std::vector<glm::dvec3>& profile2 = profiles[i + 1];

// Check that the profiles have the same number of points
// Check that profiles have the same number of points and are non-empty
if (profile1.empty() || profile2.empty())
{
//spdlog::warn("SectionedSurface: Empty profile at index {}, skipping.", i);
continue;
}
if (profile1.size() != profile2.size())
{
//spdlog::warn("SectionedSurface: Profile {} has {} points, but profile {} has {} points, skipping.", i, profile1.size(), i + 1, profile2.size());
continue;
}

std::vector<uint32_t> indices;

// Create faces by connecting corresponding points from the two profiles
// Add points and compute normals
for (size_t j = 0; j < profile1.size(); j++)
{
glm::dvec3 &p1 = profile1[j];
int j2 = 0;
if (profile1.size() > 1)
{
double pr = (double)j / (double)(profile1.size() - 1);
j2 = pr * (profile2.size() - 1);
}
glm::dvec3 &p2 = profile2[j2];
glm::dvec3& p1 = profile1[j];
glm::dvec3& p2 = profile2[j]; // Direct correspondence, assuming equal sizes

glm::dvec3 normal = glm::dvec3(0.0, 0.0, 1.0);

if (glm::distance(p1, p2) > 1E-5)
// Compute normal
glm::dvec3 normal(0.0, 0.0, 1.0); // Default normal
glm::dvec3 edge = p2 - p1;
if (glm::length(edge) > eps)
{
normal = glm::normalize(glm::cross(p2 - p1, glm::cross(p2 - p1, glm::dvec3(0.0, 0.0, 1.0))));
glm::dvec3 crossVec = glm::cross(edge, glm::dvec3(0.0, 0.0, 1.0));
if (glm::length(crossVec) > eps)
{
normal = glm::normalize(glm::cross(edge, crossVec));
}
else
{
//spdlog::warn("SectionedSurface: Degenerate normal at profile {}, point {}, using default normal.", i, j);
}
}

// Add points to geometry with computed normal
geom.AddPoint(p1, normal);
geom.AddPoint(p2, normal);

indices.push_back(geom.numPoints - 2);
indices.push_back(geom.numPoints - 1);
indices.push_back(geom.numPoints - 2); // Index of p1
indices.push_back(geom.numPoints - 1); // Index of p2
}

// Create the faces
if (indices.size() > 0)
// Create triangular faces
for (size_t j = 0; j < indices.size() - 2; j += 2)
{
for (size_t j = 0; j < indices.size() - 2; j += 4)
if (j + 3 < indices.size()) // Ensure enough indices for two triangles
{
geom.AddFace(indices[j], indices[j + 1], indices[j + 2], UINT32_MAX);
geom.AddFace(indices[j + 2], indices[j + 1], indices[j + 3], UINT32_MAX);
// Form two triangles for each quad (p1[j], p2[j], p1[j+1], p2[j+1])
// Triangle 1: p1[j], p2[j], p1[j+1]
geom.AddFace(indices[j], indices[j + 1], indices[j + 2], -1);
// Triangle 2: p2[j], p2[j+1], p1[j+1]
geom.AddFace(indices[j + 1], indices[j + 3], indices[j + 2], -1);
}
}
}
Expand Down Expand Up @@ -1366,8 +1387,6 @@ namespace bimGeometry
return geom;
}

///

inline Curve GetRectangleCurve(double xdim, double ydim, glm::dmat4 placement = glm::dmat4(1), int numSegments = 12, double radius = 0)
{
if (radius == 0)
Expand Down
3 changes: 2 additions & 1 deletion src/cpp/web-ifc/geometry/operations/curve-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#pragma once

#include <cstdint>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "../representation/IfcCurve.h"

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

return curve;
}

}
Loading