diff --git a/src/examples/csg_primitive.cpp b/src/examples/csg_primitive.cpp
new file mode 100644
index 0000000000..ced4635556
--- /dev/null
+++ b/src/examples/csg_primitive.cpp
@@ -0,0 +1,193 @@
+/********************************************************************************
+ * *
+ * This file is part of IfcOpenShell. *
+ * *
+ * IfcOpenShell is free software: you can redistribute it and/or modify *
+ * it under the terms of the Lesser GNU General Public License as published by *
+ * the Free Software Foundation, either version 3.0 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * IfcOpenShell is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * Lesser GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the Lesser GNU General Public License *
+ * along with this program. If not, see . *
+ * *
+ ********************************************************************************/
+
+/********************************************************************************
+ * *
+ * Example that generates a Constructive Solid Geometry example *
+ * *
+ ********************************************************************************/
+
+#include
+#include
+#include
+
+#include "../ifcparse/Ifc2x3.h"
+#include "../ifcparse/IfcUtil.h"
+#include "../ifcparse/IfcHierarchyHelper.h"
+
+typedef std::string S;
+typedef IfcWrite::IfcGuidHelper guid;
+boost::none_t const null = (static_cast(0));
+
+class Node {
+private:
+ typedef enum {
+ OP_ADD, OP_SUBTRACT, OP_INTERSECT, OP_TERMINAL
+ } Op;
+ typedef enum {
+ PRIM_BOX, PRIM_CONE, PRIM_CYLINDER, PRIM_PYRAMID, PRIM_SPHERE
+ } Prim;
+
+ double x,y,z, zx,zy,zz, xx,xy,xz, a,b,c;
+ const Node *left, *right;
+
+ Op op;
+ Prim prim;
+
+ Node& operate(Op op, const Node& p) {
+ left = new Node(*this);
+ right = new Node(p);
+ this->op = op;
+ return *this;
+ }
+
+ Node(Prim p, double la, double lb=0., double lc=0.)
+ : prim(p), op(OP_TERMINAL),
+ x(0.), y(0.), z(0.),
+ zx(0.), zy(0.), zz(1.),
+ xx(1.), xy(0.), xz(0.),
+ a(la), b(lb), c(lc) {}
+public:
+ static Node Sphere(double r) {
+ return Node(PRIM_SPHERE, r);
+ }
+ static Node Box(double dx, double dy, double dz) {
+ return Node(PRIM_BOX, dx, dy, dz);
+ }
+ static Node Pyramid(double dx, double dy, double dz) {
+ return Node(PRIM_PYRAMID, dx, dy, dz);
+ }
+ static Node Cylinder(double r, double h) {
+ return Node(PRIM_CYLINDER, r, h);
+ }
+ static Node Cone(double r, double h) {
+ return Node(PRIM_CONE, r, h);
+ }
+
+ Node& move(
+ double px = 0., double py = 0., double pz = 0.,
+ double zx = 0., double zy = 0., double zz = 1.,
+ double xx = 1., double xy = 0., double xz = 0.)
+ {
+ this->x = px; this->y = py; this->z = pz;
+ this->zx = zx; this->zy = zy; this->zz = zz;
+ this->xx = xx; this->xy = xy; this->xz = xz;
+ return *this;
+ }
+
+ Node& add(const Node& p) {
+ return operate(OP_ADD, p);
+ }
+ Node& subtract(const Node& p) {
+ return operate(OP_SUBTRACT, p);
+ }
+ Node& intersect(const Node& p) {
+ return operate(OP_INTERSECT, p);
+ }
+
+ IfcSchema::IfcRepresentationItem* serialize(IfcHierarchyHelper& file) const {
+ IfcSchema::IfcRepresentationItem* my;
+ if (op == OP_TERMINAL) {
+ IfcSchema::IfcAxis2Placement3D* place = file.addPlacement3d(x,y,z,zx,zy,zz,xx,xy,xz);
+ if (prim == PRIM_SPHERE) {
+ my = new IfcSchema::IfcSphere(place, a);
+ } else if (prim == PRIM_BOX) {
+ my = new IfcSchema::IfcBlock(place, a, b, c);
+ } else if (prim == PRIM_PYRAMID) {
+ my = new IfcSchema::IfcRectangularPyramid(place, a, b, c);
+ } else if (prim == PRIM_CYLINDER) {
+ my = new IfcSchema::IfcRightCircularCylinder(place, b, a);
+ } else if (prim == PRIM_CONE) {
+ my = new IfcSchema::IfcRightCircularCone(place, b, a);
+ }
+ } else {
+ IfcSchema::IfcBooleanOperator::IfcBooleanOperator o;
+ if (op == OP_ADD) {
+ o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION;
+ } else if (op == OP_SUBTRACT) {
+ o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE;
+ } else if (op == OP_INTERSECT) {
+ o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION;
+ }
+ my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
+ }
+ file.AddEntity(my);
+ return my;
+ }
+};
+
+int main(int argc, char** argv) {
+ const char filename[] = "IfcCsgPrimitive.ifc";
+ IfcHierarchyHelper file;
+ file.filename(filename);
+
+ IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
+ Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
+ ).add(
+ Node::Pyramid(8000.,6000.,3000.).move(0,0,3000.).add(
+ Node::Cylinder(1000.,4000.).move(4000.,1000.,4000., 0.,1.,0.)
+ ).subtract(
+ Node::Pyramid(7600.,5600.,2800.).move(200.,200.,3000.)
+ ).subtract(
+ Node::Cylinder(900.,4000.).move(4000.,1000.,4000., 0.,1.,0.).intersect(
+ Node::Box(2000.,4000.,1000.).move(3000.,1000.,4000.)
+ )
+ )
+ ).serialize(file);
+
+ const double x = 1000.; const double y = -4000.;
+
+ IfcSchema::IfcRepresentationItem* csg2 = Node::Sphere(5000.).move(x,y,-4500.).intersect(
+ Node::Box(6000., 6000., 6000.).move(x-3000., y-3000., 0.)
+ ).add(
+ Node::Cone(500., 3000.).move(x,y).add(
+ Node::Cone(1500., 1000.).move(x,y, 900.).add(
+ Node::Cone(1100., 1000.).move(x,y, 1800.).add(
+ Node::Cone(750., 600.).move(x,y, 2700.)
+ )))).serialize(file);
+
+ IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
+ guid(), 0, S("IfcCsgPrimitive"), null, null, 0, 0, null, null);
+
+ file.addBuildingProduct(product);
+
+ product->setOwnerHistory(file.getSingle());
+
+ product->setObjectPlacement(file.addLocalPlacement());
+
+ IfcSchema::IfcRepresentation::list reps (new IfcTemplatedEntityList());
+ IfcSchema::IfcRepresentationItem::list items (new IfcTemplatedEntityList());
+
+ items->push(csg1);
+ items->push(csg2);
+ IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
+ file.getSingle(), S("Body"), S("CSG"), items);
+ reps->push(rep);
+
+ IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
+ file.AddEntity(rep);
+ file.AddEntity(shape);
+
+ product->setRepresentation(shape);
+
+ file.getSingle()->setName("IfcCompositeProfileDef");
+
+ std::ofstream f(filename);
+ f << file;
+}
diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h
index e427a34130..88d19f6d46 100644
--- a/src/ifcgeom/IfcGeom.h
+++ b/src/ifcgeom/IfcGeom.h
@@ -103,6 +103,7 @@ namespace IfcGeom {
void apply_tolerance(TopoDS_Shape& s, double t);
void SetValue(GeomValue var, double value);
double GetValue(GeomValue var);
+ bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es);
diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp
index 0f18ab99eb..fa9022cfc3 100644
--- a/src/ifcgeom/IfcGeomFunctions.cpp
+++ b/src/ifcgeom/IfcGeomFunctions.cpp
@@ -23,6 +23,7 @@
* *
********************************************************************************/
+#include
#include
#include
@@ -92,6 +93,11 @@
#include
#include
+#include
+#include
+#include
+#include
+
#include "../ifcgeom/IfcGeom.h"
bool IfcGeom::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
@@ -572,4 +578,100 @@ IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, do
es->push(shapedef);
return shapedef;
+}
+
+// Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex
+TopoDS_Vertex find_other(const TopoDS_Edge& edge, const TopoDS_Vertex& vertex) {
+ TopExp_Explorer exp(edge, TopAbs_VERTEX);
+ while (exp.More()) {
+ if (!exp.Current().IsSame(vertex)) {
+ return TopoDS::Vertex(exp.Current());
+ }
+ exp.Next();
+ }
+}
+
+TopoDS_Edge find_next(const TopTools_IndexedMapOfShape& edge_set, const TopTools_IndexedDataMapOfShapeListOfShape& vertex_to_edges, const TopoDS_Vertex& current, const TopoDS_Edge& previous_edge) {
+ const TopTools_ListOfShape& edges = vertex_to_edges.FindFromKey(current);
+ TopTools_ListIteratorOfListOfShape eit;
+ for (eit.Initialize(edges); eit.More(); eit.Next()) {
+ const TopoDS_Edge& edge = TopoDS::Edge(eit.Value());
+ if (edge.IsSame(previous_edge)) continue;
+ if (edge_set.Contains(edge)) {
+ return edge;
+ }
+ }
+}
+
+bool IfcGeom::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape) {
+ BRepOffsetAPI_Sewing sew;
+ sew.Add(shape);
+
+ TopTools_IndexedDataMapOfShapeListOfShape edge_to_faces;
+ TopTools_IndexedDataMapOfShapeListOfShape vertex_to_edges;
+ std::set visited;
+ TopTools_IndexedMapOfShape edge_set;
+
+ TopExp::MapShapesAndAncestors (shape, TopAbs_EDGE, TopAbs_FACE, edge_to_faces);
+
+ const int num_edges = edge_to_faces.Extent();
+ for (int i = 1; i <= num_edges; ++i) {
+ const TopTools_ListOfShape& faces = edge_to_faces.FindFromIndex(i);
+ const int count = faces.Extent();
+ // Find only the non-manifold edges: Edges that are only part of a
+ // single face and therefore part of the wire(s) we want to fill.
+ if (count == 1) {
+ const TopoDS_Shape& edge = edge_to_faces.FindKey(i);
+ TopExp::MapShapesAndAncestors (edge, TopAbs_VERTEX, TopAbs_EDGE, vertex_to_edges);
+ edge_set.Add(edge);
+ }
+ }
+
+ const int num_verts = vertex_to_edges.Extent();
+ TopoDS_Vertex first, current;
+ TopoDS_Edge previous_edge;
+
+ // Now loop over all the vertices that are part of the wire(s) to be filled
+ for (int i = 1; i <= num_verts; ++i) {
+ first = current = TopoDS::Vertex(vertex_to_edges.FindKey(i));
+ const bool isSame = first.IsSame(current);
+ // We keep track of the vertices we already used
+ if (visited.find(vertex_to_edges.FindIndex(current)) != visited.end()) {
+ continue;
+ }
+ // Given these vertices, try to find closed loops and create new
+ // wires out of them.
+ BRepBuilderAPI_MakeWire w;
+ while (true) {
+ visited.insert(vertex_to_edges.FindIndex(current));
+ // Find the edge that the current vertex is part of and points
+ // away from the previous vertex (null for the first vertex).
+ TopoDS_Edge edge = find_next(edge_set, vertex_to_edges, current, previous_edge);
+ if (edge.IsNull()) {
+ return false;
+ }
+ TopoDS_Vertex other = find_other(edge, current);
+ w.Add(edge);
+ // See if the starting point of this loop has been reached. Note that
+ // additional wires after this one potentially will be created.
+ if (other.IsSame(first)) {
+ break;
+ }
+ previous_edge = edge;
+ current = other;
+ }
+ sew.Add(BRepBuilderAPI_MakeFace(w));
+ previous_edge.Nullify();
+ }
+
+ sew.Perform();
+ shape = sew.SewedShape();
+
+ try {
+ ShapeFix_Solid solid;
+ solid.LimitTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
+ shape = solid.SolidFromShell(TopoDS::Shell(shape));
+ } catch(...) {}
+
+ return true;
}
\ No newline at end of file
diff --git a/src/ifcgeom/IfcGeomObjects.cpp b/src/ifcgeom/IfcGeomObjects.cpp
index e92c3328a4..bb65be4fe2 100644
--- a/src/ifcgeom/IfcGeomObjects.cpp
+++ b/src/ifcgeom/IfcGeomObjects.cpp
@@ -175,8 +175,11 @@ IfcGeomObjects::IfcRepresentationTriangulation::IfcRepresentationTriangulation(c
const gp_Pnt2d& uv = uvs(i);
gp_Pnt p;
gp_Vec normal_direction;
- prop.Normal(uv.X(),uv.Y(),p,normal_direction);
- gp_Dir normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
+ prop.Normal(uv.X(),uv.Y(),p,normal_direction);
+ gp_Vec normal(0., 0., 0.);
+ if (normal_direction.Magnitude() > ALMOST_ZERO) {
+ normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
+ }
_normals.push_back((float)normal.X());
_normals.push_back((float)normal.Y());
_normals.push_back((float)normal.Z());
diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp
index aeb2138d65..cf512b5b97 100644
--- a/src/ifcgeom/IfcGeomShapes.cpp
+++ b/src/ifcgeom/IfcGeomShapes.cpp
@@ -45,12 +45,17 @@
#include
#include
#include
+
#include
#include
#include
#include
+#include
#include
+#include
+#include
+
#include
#include
#include
@@ -64,10 +69,20 @@
#include
#include
+#include
+#include
+#include
+#include
+#include
+
+#include
#include
#include
#include
+
#include
+#include
+#include
#include
#include
@@ -76,7 +91,6 @@
#include
#include
-#include
#include "../ifcgeom/IfcGeom.h"
@@ -223,7 +237,7 @@ bool IfcGeom::convert(const IfcSchema::IfcShellBasedSurfaceModel::ptr l, IfcRepr
return true;
}
-bool IfcGeom::convert(const IfcSchema::IfcBooleanClippingResult::ptr l, TopoDS_Shape& shape) {
+bool IfcGeom::convert(const IfcSchema::IfcBooleanResult::ptr l, TopoDS_Shape& shape) {
TopoDS_Shape s1, s2;
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand operand1 = l->FirstOperand();
@@ -249,32 +263,76 @@ bool IfcGeom::convert(const IfcSchema::IfcBooleanClippingResult::ptr l, TopoDS_S
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity);
}
- bool valid_cut = false;
- BRepAlgoAPI_Cut brep_cut(s1,s2);
- if ( brep_cut.IsDone() ) {
- TopoDS_Shape result = brep_cut;
+ const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator();
- ShapeFix_Shape fix(result);
- fix.Perform();
- result = fix.Shape();
+ if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
+
+ bool valid_cut = false;
+ BRepAlgoAPI_Cut brep_cut(s1,s2);
+ if ( brep_cut.IsDone() ) {
+ TopoDS_Shape result = brep_cut;
+
+ ShapeFix_Shape fix(result);
+ fix.Perform();
+ result = fix.Shape();
- bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
- if ( is_valid ) {
- shape = result;
- valid_cut = true;
- }
- }
+ bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
+ if ( is_valid ) {
+ shape = result;
+ valid_cut = true;
+ }
+ }
+
+ if ( valid_cut ) {
+ const double volume_after_subtraction = shape_volume(shape);
+ if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
+ Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
+ } else {
+ Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
+ shape = s1;
+ }
+
+ return true;
+
+ } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
+
+ BRepAlgoAPI_Fuse brep_fuse(s1,s2);
+ if ( brep_fuse.IsDone() ) {
+ TopoDS_Shape result = brep_fuse;
+
+ ShapeFix_Shape fix(result);
+ fix.Perform();
+ result = fix.Shape();
+
+ bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
+ if ( is_valid ) {
+ shape = result;
+ }
+ }
+
+ return true;
+
+ } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
+
+ BRepAlgoAPI_Common brep_common(s1,s2);
+ if ( brep_common.IsDone() ) {
+ TopoDS_Shape result = brep_common;
+
+ ShapeFix_Shape fix(result);
+ fix.Perform();
+ result = fix.Shape();
+
+ bool is_valid = BRepCheck_Analyzer(result).IsValid() != 0;
+ if ( is_valid ) {
+ shape = result;
+ }
+ }
+
+ return true;
- if ( valid_cut ) {
- const double volume_after_subtraction = shape_volume(shape);
- if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
- Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l->entity);
} else {
- Logger::Message(Logger::LOG_ERROR,"Failed to process subtraction:",l->entity);
- shape = s1;
+ return false;
}
-
- return true;
}
bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet::ptr l, TopoDS_Shape& shape) {
@@ -392,4 +450,182 @@ bool IfcGeom::convert(const IfcSchema::IfcGeometricSet::ptr l, IfcRepresentation
}
}
return true;
-}
\ No newline at end of file
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcBlock::ptr l, TopoDS_Shape& shape) {
+ const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double dz = l->ZLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+
+ BRepPrimAPI_MakeBox builder(dx, dy, dz);
+ gp_Trsf trsf;
+ IfcGeom::convert(l->Position(),trsf);
+ shape = builder.Solid().Moved(trsf);
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcRectangularPyramid::ptr l, TopoDS_Shape& shape) {
+ const double dx = l->XLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double dy = l->YLength() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double dz = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+
+ BRepPrimAPI_MakeWedge builder(dx, dz, dy, dx / 2., dy / 2., dx / 2., dy / 2.);
+
+ gp_Trsf trsf1, trsf2;
+ trsf2.SetValues(1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, 1, 0, 0, Precision::Confusion(), Precision::Confusion());
+
+ IfcGeom::convert(l->Position(), trsf1);
+ shape = BRepBuilderAPI_Transform(builder.Solid(), trsf1 * trsf2);
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcRightCircularCylinder::ptr l, TopoDS_Shape& shape) {
+ const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+
+ BRepPrimAPI_MakeCylinder builder(r, h);
+ gp_Trsf trsf;
+ IfcGeom::convert(l->Position(),trsf);
+ shape = builder.Solid().Moved(trsf);
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcRightCircularCone::ptr l, TopoDS_Shape& shape) {
+ const double r = l->BottomRadius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+ const double h = l->Height() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+
+ BRepPrimAPI_MakeCone builder(r, 0., h);
+ gp_Trsf trsf;
+ IfcGeom::convert(l->Position(),trsf);
+ shape = builder.Solid().Moved(trsf);
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcSphere::ptr l, TopoDS_Shape& shape) {
+ const double r = l->Radius() * IfcGeom::GetValue(GV_LENGTH_UNIT);
+
+ BRepPrimAPI_MakeSphere builder(r);
+ gp_Trsf trsf;
+ IfcGeom::convert(l->Position(),trsf);
+ shape = builder.Solid().Moved(trsf);
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcCsgSolid::ptr l, TopoDS_Shape& shape) {
+ return IfcGeom::convert_shape(l->TreeRootExpression(), shape);
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcCurveBoundedPlane::ptr l, TopoDS_Shape& face) {
+ gp_Pln pln;
+ IfcGeom::convert(l->BasisSurface(), pln);
+
+ gp_Trsf trsf;
+ trsf.SetTransformation(pln.Position());
+
+ TopoDS_Wire outer;
+ IfcGeom::convert_wire(l->OuterBoundary(), outer);
+
+ BRepBuilderAPI_MakeFace mf (outer);
+ mf.Add(outer);
+
+ IfcSchema::IfcCurve::list inner = l->InnerBoundaries();
+
+ for (IfcSchema::IfcCurve::it it = inner->begin(); it != inner->end(); ++it) {
+ TopoDS_Wire inner;
+ IfcGeom::convert_wire(*it, inner);
+
+ mf.Add(inner);
+ }
+
+ ShapeFix_Shape sfs(mf.Face());
+ sfs.Perform();
+ face = TopoDS::Face(sfs.Shape()).Moved(trsf);
+
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcRectangularTrimmedSurface::ptr l, TopoDS_Shape& face) {
+ if (!l->BasisSurface()->is(IfcSchema::Type::IfcPlane)) {
+ // Not implemented
+ return false;
+ }
+ gp_Pln pln;
+ IfcGeom::convert((IfcSchema::IfcPlane*) l->BasisSurface(), pln);
+
+ BRepBuilderAPI_MakeFace mf(pln, l->U1(), l->U2(), l->V1(), l->V2());
+
+ face = mf.Face();
+
+ return true;
+}
+
+bool IfcGeom::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid::ptr l, TopoDS_Shape& shape) {
+ gp_Trsf trsf, axis, position;
+ TopoDS_Shape face;
+ TopoDS_Wire wire, section;
+
+ if (!IfcGeom::convert_face(l->SweptArea(), face)) {
+ return false;
+ }
+
+ if (!IfcGeom::convert_wire(l->Directrix(), wire)) {
+ return false;
+ }
+
+ axis.SetTransformation(gp_Ax3(gp::Origin(), gp::DX(), -gp::DZ()));
+ IfcGeom::convert(l->Position(), position);
+
+ if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) {
+ // Not implemented
+ return false;
+ }
+
+ gp_Pln pln;
+ IfcGeom::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln);
+
+ trsf.SetTransformation(pln.Position());
+ trsf.Invert();
+ trsf.Multiply(axis);
+
+ // NB: Note that StartParam and EndParam param are ignored and the assumption is
+ // made that the parametric range over which to be swept matches the IfcCurve in
+ // its entirety.
+ BRepOffsetAPI_MakePipeShell builder(wire);
+
+ face = BRepBuilderAPI_Transform(face, trsf);
+
+ TopExp_Explorer exp(face, TopAbs_WIRE);
+ section = TopoDS::Wire(exp.Current());
+
+ builder.Add(section);
+ builder.SetTransitionMode(BRepBuilderAPI_RightCorner);
+ builder.Build();
+
+ shape = builder.Shape();
+
+ bool succeeded = false;
+ try {
+ succeeded = IfcGeom::fill_nonmanifold_wires_with_planar_faces(shape);
+ } catch(...) {}
+ if (!succeeded) {
+ Logger::Message(Logger::LOG_WARNING, "Failed to cap solid for:", l->entity);
+ }
+
+ shape.Move(position);
+
+ return true;
+}
+
+#ifdef USE_IFC4
+
+bool IfcGeom::convert(const IfcSchema::IfcCylindricalSurface::ptr l, TopoDS_Shape& face) {
+ gp_Trsf trsf;
+ IfcGeom::convert(l->Position(),trsf);
+
+ face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), GetValue(GV_PRECISION)).Face().Moved(trsf);
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/IfcRegister.h
index b074dddcf9..152b29e1cf 100644
--- a/src/ifcgeom/IfcRegister.h
+++ b/src/ifcgeom/IfcRegister.h
@@ -53,11 +53,23 @@ SHAPES(IfcGeometricSet);
SHAPE(IfcExtrudedAreaSolid);
SHAPE(IfcRevolvedAreaSolid);
SHAPE(IfcConnectedFaceSet);
-SHAPE(IfcBooleanClippingResult);
+SHAPE(IfcBooleanResult);
SHAPE(IfcPolygonalBoundedHalfSpace);
SHAPE(IfcHalfSpaceSolid);
SHAPE(IfcSurfaceOfLinearExtrusion);
SHAPE(IfcSurfaceOfRevolution);
+SHAPE(IfcBlock);
+SHAPE(IfcRectangularPyramid);
+SHAPE(IfcRightCircularCylinder);
+SHAPE(IfcRightCircularCone);
+SHAPE(IfcSphere);
+SHAPE(IfcCsgSolid);
+SHAPE(IfcCurveBoundedPlane);
+SHAPE(IfcRectangularTrimmedSurface);
+SHAPE(IfcSurfaceCurveSweptAreaSolid);
+#ifdef USE_IFC4
+SHAPE(IfcCylindricalSurface);
+#endif
FACE(IfcArbitraryProfileDefWithVoids);
FACE(IfcArbitraryClosedProfileDef);
diff --git a/test/input/IfcCsgPrimitive.ifc b/test/input/IfcCsgPrimitive.ifc
new file mode 100644
index 0000000000..acf5e3a612
--- /dev/null
+++ b/test/input/IfcCsgPrimitive.ifc
@@ -0,0 +1,133 @@
+ISO-10303-21;
+HEADER;
+FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1');
+FILE_NAME('IfcCsgPrimitive.ifc','2014-03-17T18:28:00',(''),('',''),'IfcOpenShell 0.5.0-dev','IfcOpenShell 0.5.0-dev','');
+FILE_SCHEMA(('IFC2X3'));
+ENDSEC;
+DATA;
+#1=IFCDIRECTION((1.,0.,0.));
+#2=IFCDIRECTION((0.,0.,1.));
+#3=IFCCARTESIANPOINT((3000.,1000.,4000.));
+#4=IFCAXIS2PLACEMENT3D(#3,#2,#1);
+#5=IFCBLOCK(#4,2000.,4000.,1000.);
+#6=IFCDIRECTION((1.,0.,0.));
+#7=IFCDIRECTION((0.,1.,0.));
+#8=IFCCARTESIANPOINT((4000.,1000.,4000.));
+#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
+#10=IFCRIGHTCIRCULARCYLINDER(#9,4000.,900.);
+#11=IFCBOOLEANRESULT(.INTERSECTION.,#10,#5);
+#12=IFCDIRECTION((1.,0.,0.));
+#13=IFCDIRECTION((0.,0.,1.));
+#14=IFCCARTESIANPOINT((200.,200.,3000.));
+#15=IFCAXIS2PLACEMENT3D(#14,#13,#12);
+#16=IFCRECTANGULARPYRAMID(#15,7600.,5600.,2800.);
+#17=IFCDIRECTION((1.,0.,0.));
+#18=IFCDIRECTION((0.,1.,0.));
+#19=IFCCARTESIANPOINT((4000.,1000.,4000.));
+#20=IFCAXIS2PLACEMENT3D(#19,#18,#17);
+#21=IFCRIGHTCIRCULARCYLINDER(#20,4000.,1000.);
+#22=IFCDIRECTION((1.,0.,0.));
+#23=IFCDIRECTION((0.,0.,1.));
+#24=IFCCARTESIANPOINT((0.,0.,3000.));
+#25=IFCAXIS2PLACEMENT3D(#24,#23,#22);
+#26=IFCRECTANGULARPYRAMID(#25,8000.,6000.,3000.);
+#27=IFCBOOLEANRESULT(.UNION.,#26,#21);
+#28=IFCBOOLEANRESULT(.DIFFERENCE.,#27,#16);
+#29=IFCBOOLEANRESULT(.DIFFERENCE.,#28,#11);
+#30=IFCDIRECTION((1.,0.,0.));
+#31=IFCDIRECTION((0.,0.,1.));
+#32=IFCCARTESIANPOINT((200.,200.,200.));
+#33=IFCAXIS2PLACEMENT3D(#32,#31,#30);
+#34=IFCBLOCK(#33,7600.,5600.,2800.);
+#35=IFCDIRECTION((1.,0.,0.));
+#36=IFCDIRECTION((0.,0.,1.));
+#37=IFCCARTESIANPOINT((0.,0.,0.));
+#38=IFCAXIS2PLACEMENT3D(#37,#36,#35);
+#39=IFCBLOCK(#38,8000.,6000.,3000.);
+#40=IFCBOOLEANRESULT(.DIFFERENCE.,#39,#34);
+#41=IFCBOOLEANRESULT(.UNION.,#40,#29);
+#42=IFCDIRECTION((1.,0.,0.));
+#43=IFCDIRECTION((0.,0.,1.));
+#44=IFCCARTESIANPOINT((1000.,-4000.,2700.));
+#45=IFCAXIS2PLACEMENT3D(#44,#43,#42);
+#46=IFCRIGHTCIRCULARCONE(#45,600.,750.);
+#47=IFCDIRECTION((1.,0.,0.));
+#48=IFCDIRECTION((0.,0.,1.));
+#49=IFCCARTESIANPOINT((1000.,-4000.,1800.));
+#50=IFCAXIS2PLACEMENT3D(#49,#48,#47);
+#51=IFCRIGHTCIRCULARCONE(#50,1000.,1100.);
+#52=IFCBOOLEANRESULT(.UNION.,#51,#46);
+#53=IFCDIRECTION((1.,0.,0.));
+#54=IFCDIRECTION((0.,0.,1.));
+#55=IFCCARTESIANPOINT((1000.,-4000.,900.));
+#56=IFCAXIS2PLACEMENT3D(#55,#54,#53);
+#57=IFCRIGHTCIRCULARCONE(#56,1000.,1500.);
+#58=IFCBOOLEANRESULT(.UNION.,#57,#52);
+#59=IFCDIRECTION((1.,0.,0.));
+#60=IFCDIRECTION((0.,0.,1.));
+#61=IFCCARTESIANPOINT((1000.,-4000.,0.));
+#62=IFCAXIS2PLACEMENT3D(#61,#60,#59);
+#63=IFCRIGHTCIRCULARCONE(#62,3000.,500.);
+#64=IFCBOOLEANRESULT(.UNION.,#63,#58);
+#65=IFCDIRECTION((1.,0.,0.));
+#66=IFCDIRECTION((0.,0.,1.));
+#67=IFCCARTESIANPOINT((-2000.,-7000.,0.));
+#68=IFCAXIS2PLACEMENT3D(#67,#66,#65);
+#69=IFCBLOCK(#68,6000.,6000.,6000.);
+#70=IFCDIRECTION((1.,0.,0.));
+#71=IFCDIRECTION((0.,0.,1.));
+#72=IFCCARTESIANPOINT((1000.,-4000.,-4500.));
+#73=IFCAXIS2PLACEMENT3D(#72,#71,#70);
+#74=IFCSPHERE(#73,5000.);
+#75=IFCBOOLEANRESULT(.INTERSECTION.,#74,#69);
+#76=IFCBOOLEANRESULT(.UNION.,#75,#64);
+#77=IFCPERSON($,$,'',$,$,$,$,$);
+#78=IFCORGANIZATION($,'IfcOpenShell',$,$,$);
+#79=IFCPERSONANDORGANIZATION(#77,#78,$);
+#80=IFCAPPLICATION(#78,'0.5.0-dev','IfcOpenShell','IfcOpenShell');
+#81=IFCOWNERHISTORY(#79,#80,$,.ADDED.,$,#79,#80,1395077280);
+#82=IFCDIRECTION((0.,1.,0.));
+#83=IFCDIRECTION((1.,0.,0.));
+#84=IFCDIRECTION((0.,0.,1.));
+#85=IFCCARTESIANPOINT((0.,0.,0.));
+#86=IFCAXIS2PLACEMENT3D(#85,#84,#83);
+#87=IFCGEOMETRICREPRESENTATIONCONTEXT('Plan','Model',3,1.E-005,#86,#82);
+#88=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
+#89=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
+#90=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
+#91=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.0174533),#90);
+#92=IFCCONVERSIONBASEDUNIT(#88,.PLANEANGLEUNIT.,'Degrees',#91);
+#93=IFCUNITASSIGNMENT((#89,#92));
+#94=IFCPROJECT('0DMnBGAAP0egv6AtzWaDtb',#81,'IfcCompositeProfileDef',$,$,$,$,(#87),#93);
+#95=IFCDIRECTION((1.,0.,0.));
+#96=IFCDIRECTION((0.,0.,1.));
+#97=IFCCARTESIANPOINT((0.,0.,0.));
+#98=IFCAXIS2PLACEMENT3D(#97,#96,#95);
+#99=IFCLOCALPLACEMENT($,#98);
+#100=IFCSITE('1zP1fQSXb4cxuwjjpQU6bU',#81,$,$,$,#99,$,$,.ELEMENT.,$,$,$,$,$);
+#101=IFCRELAGGREGATES('0ZzcG2ut9F2BG7u28TPexy',#81,$,$,#94,(#100));
+#102=IFCDIRECTION((1.,0.,0.));
+#103=IFCDIRECTION((0.,0.,1.));
+#104=IFCCARTESIANPOINT((0.,0.,0.));
+#105=IFCAXIS2PLACEMENT3D(#104,#103,#102);
+#106=IFCLOCALPLACEMENT(#99,#105);
+#107=IFCBUILDING('0cM$4pWjvEFe6tscjMbee8',#81,$,$,$,#106,$,$,.ELEMENT.,$,$,$);
+#108=IFCRELAGGREGATES('0zaDy4$156SBV4NFDY$SC5',#81,$,$,#100,(#107));
+#109=IFCDIRECTION((1.,0.,0.));
+#110=IFCDIRECTION((0.,0.,1.));
+#111=IFCCARTESIANPOINT((0.,0.,0.));
+#112=IFCAXIS2PLACEMENT3D(#111,#110,#109);
+#113=IFCLOCALPLACEMENT(#106,#112);
+#114=IFCBUILDINGSTOREY('0WbxDykS94XukFPy9QwxyX',#81,$,$,$,#113,$,$,.ELEMENT.,$);
+#115=IFCRELAGGREGATES('2LJSUZqR53NhOup_TIPm5y',#81,$,$,#107,(#114));
+#116=IFCBUILDINGELEMENTPROXY('1qAWhlc9bBc9v_UZeT6Xd3',#81,'IfcCsgPrimitive',$,$,#122,#124,$,$);
+#117=IFCRELCONTAINEDINSPATIALSTRUCTURE('1SveiYYOXAmPiFhsZbsl1q',#81,$,$,(#116),#114);
+#118=IFCDIRECTION((1.,0.,0.));
+#119=IFCDIRECTION((0.,0.,1.));
+#120=IFCCARTESIANPOINT((0.,0.,0.));
+#121=IFCAXIS2PLACEMENT3D(#120,#119,#118);
+#122=IFCLOCALPLACEMENT($,#121);
+#123=IFCSHAPEREPRESENTATION(#87,'Body','CSG',(#41,#76));
+#124=IFCPRODUCTDEFINITIONSHAPE($,$,(#123));
+ENDSEC;
+END-ISO-10303-21;