diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 94f6f51290..c593fbab95 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -109,6 +109,7 @@ public: bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcRepresentationShapeItems& cut_shapes); IfcSchema::IfcSurfaceStyleShading* get_surface_style(IfcSchema::IfcRepresentationItem* item); + const IfcSchema::IfcRepresentationItem* find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item); bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid); bool is_compound(const TopoDS_Shape& shape); bool is_convex(const TopoDS_Wire& wire); @@ -123,7 +124,10 @@ public: void setValue(GeomValue var, double value); double getValue(GeomValue var) const; bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); - void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); + bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); + void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); std::pair initializeUnits(IfcSchema::IfcUnitAssignment*); @@ -135,6 +139,10 @@ public: const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item); template std::pair get_surface_style(const IfcSchema::IfcRepresentationItem* representation_item) { + // For certain representation items, most notably boolean operands, + // a style definition might reside on one of its operands. + representation_item = find_item_carrying_style(representation_item); + IfcSchema::IfcStyledItem::list::ptr styled_items = representation_item->StyledByItem(); for (IfcSchema::IfcStyledItem::list::it jt = styled_items->begin(); jt != styled_items->end(); ++jt) { #ifdef USE_IFC4 diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index ecf9e2b3b9..b1e3dabc98 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -100,6 +100,8 @@ #include #include +#include + #include "../ifcparse/IfcSIPrefix.h" #include "../ifcgeom/IfcGeom.h" @@ -232,7 +234,21 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons TopExp_Explorer exp(entity_shape, TopAbs_SOLID); for (; exp.More(); exp.Next()) { + +#if OCC_VERSION_HEX < 0x60900 BRepAlgoAPI_Cut brep_cut(exp.Current(), opening_shape); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(exp.Current()); + TopTools_ListOfShape s2s; + s2s.Append(opening_shape); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif + bool added = false; if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; @@ -257,7 +273,19 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons entity_shape = compound; } else { +#if OCC_VERSION_HEX < 0x60900 BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(entity_shape); + TopTools_ListOfShape s2s; + s2s.Append(opening_shape); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; @@ -354,7 +382,20 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf()); } +#if OCC_VERSION_HEX < 0x60900 BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(entity_shape); + TopTools_ListOfShape s2s; + s2s.Append(opening_compound); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif + bool is_valid = false; if ( brep_cut.IsDone() ) { TopoDS_Shape brep_cut_result = brep_cut; @@ -836,7 +877,7 @@ bool IfcGeom::Kernel::flatten_shape_list(const IfcGeom::IfcRepresentationShapeIt return success; } -void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { +void IfcGeom::Kernel::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE); tol *= tol; @@ -860,6 +901,69 @@ void IfcGeom::Kernel::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& po } } +void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { + if (tol <= 0.) tol = getValue(GV_POINT_EQUALITY_TOLERANCE); + const int start = closed ? 1 : 2; + const int end = polygon.Length() - (closed ? 0 : 1); + std::vector to_remove(polygon.Length(), false); + for (int i = start; i <= end; ++i) { + const gp_Pnt& a = polygon.Value(((i - 2 + polygon.Length()) % polygon.Length()) + 1); + const gp_Pnt& b = polygon.Value(i); + const gp_Pnt& c = polygon.Value((i % polygon.Length()) + 1); + const gp_Vec d1 = c.XYZ() - a.XYZ(); + const gp_Vec d2 = b.XYZ() - a.XYZ(); + const double dt = d2.Dot(d1) / d1.Dot(d1); + const gp_Vec d3 = d1.Scaled(dt); + const gp_Pnt b2 = a.XYZ() + d3.XYZ(); + if (b.Distance(b2) < tol) { + to_remove[i-1] = true; + } + } + for (int i = to_remove.size() - 1; i >= 0; --i) { + if (to_remove[i]) { + polygon.Remove(i+1); + } + } +} + +bool IfcGeom::Kernel::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) { + TopExp_Explorer exp(w, TopAbs_EDGE); + for (; exp.More(); exp.Next()) { + double a, b; + Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b); + if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) { + return false; + } + } + + exp.ReInit(); + + int i = 0; + for (; exp.More(); exp.Next(), ++i) { + TopoDS_Vertex v1, v2; + TopExp::Vertices(TopoDS::Edge(exp.Current()), v1, v2, true); + if (exp.More()) { + if (i == 0) { + p.Append(BRep_Tool::Pnt(v1)); + } + p.Append(BRep_Tool::Pnt(v2)); + } + } + + return true; +} + +void IfcGeom::Kernel::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) { + BRepBuilderAPI_MakePolygon builder; + for (int i = 1; i <= p.Length(); ++i) { + builder.Add(p.Value(i)); + } + if (close) { + builder.Close(); + } + w = builder.Wire(); +} + template IfcGeom::BRepElement

* IfcGeom::Kernel::create_brep_for_representation_and_product(const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product) { IfcGeom::Representation::BRep* shape; @@ -1083,4 +1187,29 @@ std::pair IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn } return std::pair(unit_name, unit_magnitude); +} + +const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationItem* item) { + IfcSchema::IfcStyledItem::list::ptr styles = item->StyledByItem(); + if (styles->size()) { + return item; + } + + while (item->is(IfcSchema::Type::IfcBooleanClippingResult)) { + // All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of + // IfcGeometricRepresentationItem + item = (IfcSchema::IfcGeometricRepresentationItem*) ((IfcSchema::IfcBooleanClippingResult*) item)->FirstOperand(); + + IfcSchema::IfcStyledItem::list::ptr styles = item->StyledByItem(); + if (styles->size()) { + return item; + } + } + + // TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well. + // But neither are these very prevalent, nor does the current IfcOpenShell style + // mechanism enable to conveniently style subshapes, which would be necessary for + // distinctly styled union operands. + + return item; } \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index af74b4369f..0e1b0747cb 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -249,10 +249,20 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, TopoDS_Shap bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; + TopoDS_Wire wire; - if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; + if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; + gp_Trsf trsf; - convert(l->Position(),trsf); + if ( ! convert(l->Position(),trsf) ) return false; + + TColgp_SequenceOfPnt points; + if (wire_to_sequence_of_point(wire, points)) { + remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above + remove_collinear_points_from_loop(points, wire.Closed()); + sequence_of_point_to_wire(points, wire, wire.Closed()); + } + TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); prism.Move(trsf*down); @@ -277,6 +287,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, Ifc } bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape& shape) { + TopoDS_Shape s1, s2; IfcRepresentationShapeItems items1, items2; TopoDS_Wire boundary_wire; @@ -330,10 +341,36 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + /* + // TK: A little debugging trick to output both operands for visual inspection + + BRep_Builder builder; + TopoDS_Compound compound; + builder.MakeCompound(compound); + builder.Add(compound, s1); + builder.Add(compound, s2); + shape = compound; + return true; + */ + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { bool valid_cut = false; - BRepAlgoAPI_Cut brep_cut(s1,s2); + +#if OCC_VERSION_HEX < 0x60900 + BRepAlgoAPI_Cut brep_cut(s1, s2); +#else + BRepAlgoAPI_Cut brep_cut; + TopTools_ListOfShape s1s; + s1s.Append(s1); + TopTools_ListOfShape s2s; + s2s.Append(s2); + brep_cut.SetFuzzyValue(getValue(GV_PRECISION)); + brep_cut.SetArguments(s1s); + brep_cut.SetTools(s2s); + brep_cut.Build(); +#endif + if ( brep_cut.IsDone() ) { TopoDS_Shape result = brep_cut; diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/IfcGeomWires.cpp index 058302222b..99cdbff85b 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -284,7 +284,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu } // Remove points that are too close to one another - remove_redundant_points_from_loop(polygon, false); + remove_duplicate_points_from_loop(polygon, false); BRepBuilderAPI_MakePolygon w; for (int i = 1; i <= polygon.Length(); ++i) { @@ -314,7 +314,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu } // Remove points that are too close to one another - remove_redundant_points_from_loop(polygon, true); + remove_duplicate_points_from_loop(polygon, true); int count = polygon.Length(); if (original_count - count != 0) {