Use fuzzy boolean subtraction if available

Remove collinear points from polygonal halfspace boundary
Lookup styled items on boolean operation operands

Fixes https://github.com/IfcOpenShell/IfcOpenShell/issues/6
Fixes https://sourceforge.net/p/ifcopenshell/discussion/1782717/thread/a7f99e41/?limit=25#5c36
This commit is contained in:
aothms
2016-01-22 17:27:28 +01:00
parent a0db3a3406
commit 4be7da1a43
4 changed files with 181 additions and 7 deletions
+9 -1
View File
@@ -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<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
@@ -135,6 +139,10 @@ public:
const SurfaceStyle* get_style(const IfcSchema::IfcRepresentationItem* representation_item);
template <typename T> std::pair<IfcSchema::IfcSurfaceStyle*, T*> 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
+130 -1
View File
@@ -100,6 +100,8 @@
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <Standard_Version.hxx>
#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<bool> 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 <typename P>
IfcGeom::BRepElement<P>* 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<std::string, double> IfcGeom::Kernel::initializeUnits(IfcSchema::IfcUn
}
return std::pair<std::string, double>(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;
}
+40 -3
View File
@@ -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;
+2 -2
View File
@@ -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) {