From 71ea63620649088284fcd142eb99b7c029dbf89b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Sat, 22 Mar 2014 10:31:51 +0000 Subject: [PATCH] Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface. Add CSG example. --- src/examples/csg_primitive.cpp | 193 +++++++++++++++++++++ src/ifcgeom/IfcGeom.h | 1 + src/ifcgeom/IfcGeomFunctions.cpp | 102 +++++++++++ src/ifcgeom/IfcGeomObjects.cpp | 7 +- src/ifcgeom/IfcGeomShapes.cpp | 284 ++++++++++++++++++++++++++++--- src/ifcgeom/IfcRegister.h | 14 +- test/input/IfcCsgPrimitive.ifc | 133 +++++++++++++++ 7 files changed, 707 insertions(+), 27 deletions(-) create mode 100644 src/examples/csg_primitive.cpp create mode 100644 test/input/IfcCsgPrimitive.ifc 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;