More elaborate wire ordering check and shell sewing code (#147)

This commit is contained in:
Thomas Krijnen
2016-12-09 16:40:14 +01:00
committed by GitHub
parent 51409aff8f
commit 4354361a13
4 changed files with 123 additions and 65 deletions
+1
View File
@@ -197,6 +197,7 @@ public:
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 create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
bool is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire);
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln,const gp_Pnt& cent);
+43 -16
View File
@@ -91,6 +91,9 @@
#include <Standard_Version.hxx>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
@@ -143,6 +146,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
if (num_outer_bounds > 1) {
builder.MakeCompound(compound);
}
TopTools_DataMapOfShapeInteger wire_senses;
// The builder is initialized on the heap because of the various different moments
// of initialization depending on the configuration of surfaces and boundaries.
@@ -200,6 +205,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
wire.Reverse();
}
wire_senses.Bind(wire.Oriented(TopAbs_FORWARD), same_sense ? TopAbs_FORWARD : TopAbs_REVERSED);
bool flattened_wire = false;
if (!mf) {
@@ -245,25 +252,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
}
ShapeFix_Face fix(mf->Face());
fix.FixOrientation();
fix.Perform();
outer_face_bound = fix.Face();
}
// If the wires are reversed the face needs to be reversed as well in order
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
bool all_reversed = true;
TopoDS_Iterator jt(outer_face_bound, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if ((w.Orientation() != TopAbs_REVERSED) == same_sense) {
all_reversed = false;
}
}
if (all_reversed) {
outer_face_bound.Reverse();
}
if (num_outer_bounds > 1) {
builder.Add(compound, outer_face_bound);
delete mf; mf = 0;
@@ -307,11 +298,47 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
if (success) {
face = mf->Face();
}
ShapeFix_Face sfs(TopoDS::Face(face));
TopTools_DataMapOfShapeListOfShape wire_map;
sfs.FixOrientation(wire_map);
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if (wire_map.IsBound(w)) {
const TopTools_ListOfShape& shapes = wire_map.Find(w);
TopTools_ListIteratorOfListOfShape it(shapes);
for (; it.More(); it.Next()) {
// Apparently the wire got reversed, so register it with opposite orientation in the map
wire_senses.Bind(it.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
}
}
}
face = TopoDS::Face(sfs.Face());
}
}
}
if (success) {
// If the wires are reversed the face needs to be reversed as well in order
// to maintain the counter-clock-wise ordering of the bounding wire's vertices.
if (num_bounds == 1 || true) {
bool all_reversed = true;
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
if (!wire_senses.IsBound(w.Oriented(TopAbs_FORWARD)) || (w.Orientation() == wire_senses.Find(w.Oriented(TopAbs_FORWARD)))) {
all_reversed = false;
}
}
if (all_reversed) {
face.Reverse();
}
}
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(face, getValue(GV_PRECISION), TopAbs_FACE);
}
+75 -15
View File
@@ -126,6 +126,8 @@
#include <GCPnts_AbscissaPoint.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <Standard_Version.hxx>
#include "../ifcparse/IfcSIPrefix.h"
@@ -141,26 +143,81 @@
#endif
bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
TopTools_ListOfShape face_list;
TopExp_Explorer exp(compound, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
TopoDS_Face face = TopoDS::Face(exp.Current());
face_list.Append(face);
}
if (face_list.Extent() == 0) {
return false;
}
return create_solid_from_faces(face_list, shape);
}
bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) {
bool valid_shell = false;
TopTools_ListIteratorOfListOfShape face_iterator;
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopExp_Explorer exp(compound,TopAbs_FACE);
if ( ! exp.More() ) return false;
for ( ; exp.More(); exp.Next() ) {
TopoDS_Face face = TopoDS::Face(exp.Current());
builder.Add(face);
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(face_iterator.Value());
}
builder.Perform();
shape = builder.SewedShape();
if (shape.ShapeType() == TopAbs_SHELL) {
try {
ShapeFix_Solid sf_solid;
sf_solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
shape = sf_solid.SolidFromShell(TopoDS::Shell(shape));
} catch(...) {}
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid() != 0;
} catch (...) {}
if (valid_shell) {
TopoDS_Shape complete_shape;
TopExp_Explorer exp(shape, TopAbs_SHELL);
for (; exp.More(); exp.Next()) {
TopoDS_Shape result_shape = exp.Current();
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(exp.Current()));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
result_shape = solid_shape;
classifier.PerformInfinitePoint(getValue(GV_PRECISION));
if (classifier.State() == TopAbs_IN) {
shape.Reverse();
}
} catch (...) {}
}
} catch (...) {}
if (complete_shape.IsNull()) {
complete_shape = result_shape;
} else {
BRep_Builder B;
if (complete_shape.ShapeType() != TopAbs_COMPOUND) {
TopoDS_Compound C;
B.MakeCompound(C);
B.Add(C, complete_shape);
complete_shape = C;
Logger::Message(Logger::LOG_WARNING, "Multiple components in IfcConnectedFaceSet");
}
B.Add(complete_shape, result_shape);
}
}
shape = complete_shape;
} else {
Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset");
}
return true;
return valid_shell;
}
bool IfcGeom::Kernel::is_compound(const TopoDS_Shape& shape) {
@@ -176,7 +233,10 @@ const TopoDS_Shape& IfcGeom::Kernel::ensure_fit_for_subtraction(const TopoDS_Sha
if (!is_comp) {
return solid = shape;
}
create_solid_from_compound(shape, solid);
if (!create_solid_from_compound(shape, solid)) {
return solid = shape;
}
// If the SEW_SHELLS option had been set this precision had been applied
// at the end of the generic convert_shape() call.
+4 -34
View File
@@ -643,49 +643,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
if (face_list.Extent() == 0) {
return false;
}
bool valid_shell = false;
TopTools_ListIteratorOfListOfShape face_iterator;
if ( face_list.Extent() < getValue(GV_MAX_FACES_TO_SEW) ) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(face_iterator.Value());
}
try {
builder.Perform();
shape = builder.SewedShape();
valid_shell = BRepCheck_Analyzer(shape).IsValid() != 0;
} catch(...) {}
if (valid_shell) {
try {
ShapeFix_Solid solid;
solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape));
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
shape = solid_shape;
} catch (...) {}
}
} catch(...) {}
} else {
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
}
}
if (!valid_shell) {
if (face_list.Extent() > getValue(GV_MAX_FACES_TO_SEW) || !create_solid_from_faces(face_list, shape)) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
TopTools_ListIteratorOfListOfShape face_iterator;
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(compound, face_iterator.Value());
}
shape = compound;
}
return true;
}