mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
More elaborate wire ordering check and shell sewing code (#147)
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user