Refactoring

This commit is contained in:
Thomas Krijnen
2022-11-14 09:23:59 +01:00
parent 66281ec1f1
commit 9351038009
36 changed files with 1162 additions and 1605 deletions
+3 -2
View File
@@ -22,6 +22,7 @@
#include <TopoDS_Face.hxx>
#include <ShapeFix_Shape.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -31,7 +32,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAnnotationFillArea* l, TopoDS_
return false;
}
assert_closed_wire(outer_boundary);
util::assert_closed_wire(outer_boundary, getValue(GV_PRECISION));
BRepBuilderAPI_MakeFace mf(outer_boundary);
@@ -41,7 +42,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAnnotationFillArea* l, TopoDS_
for(IfcSchema::IfcCurve::list::it it = inner_boundaries->begin(); it != inner_boundaries->end(); ++it) {
TopoDS_Wire hole;
if (convert_wire(*it, hole)) {
assert_closed_wire(hole);
util::assert_closed_wire(hole, getValue(GV_PRECISION));
mf.Add(hole);
}
}
+3 -2
View File
@@ -19,6 +19,7 @@
#include <TopoDS_Wire.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -28,10 +29,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l,
return false;
}
assert_closed_wire(wire);
util::assert_closed_wire(wire, getValue(GV_PRECISION));
TopoDS_Compound f;
bool success = convert_wire_to_faces(wire, f);
bool success = util::convert_wire_to_faces(wire, f, {getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., getValue(GV_PRECISION)});
if (success) {
face = f;
}
@@ -22,6 +22,7 @@
#include <TopoDS_Face.hxx>
#include <ShapeFix_Shape.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -31,8 +32,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids*
return false;
}
assert_closed_wire(profile);
util::assert_closed_wire(profile, getValue(GV_PRECISION));
// @todo this is a discrepancy with IfcArbitraryClosedProfileDef without voids.
// wire intersection code is not triggered this way.
BRepBuilderAPI_MakeFace mf(profile);
IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves();
@@ -40,7 +43,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids*
for(IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++it) {
TopoDS_Wire hole;
if (convert_wire(*it, hole)) {
assert_closed_wire(hole);
util::assert_closed_wire(hole, getValue(GV_PRECISION));
mf.Add(hole);
}
}
+8 -8
View File
@@ -82,7 +82,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
}
if ( shape_type(operand1) == ST_SHAPELIST ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
if (!(convert_shapes(operand1, items1) && util::flatten_shape_list(items1, s1, true, getValue(GV_PRECISION)))) {
return false;
}
} else if ( shape_type(operand1) == ST_SHAPE ) {
@@ -90,7 +90,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
return false;
}
{ TopoDS_Solid temp_solid;
s1 = ensure_fit_for_subtraction(s1, temp_solid); }
s1 = util::ensure_fit_for_subtraction(s1, temp_solid, getValue(GV_PRECISION)); }
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand1);
return false;
@@ -101,7 +101,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
return true;
}
const double first_operand_volume = shape_volume(s1);
const double first_operand_volume = util::shape_volume(s1);
if (first_operand_volume <= ALMOST_ZERO) {
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
}
@@ -120,12 +120,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
{
if (shape_type(op2) == ST_SHAPELIST) {
IfcRepresentationShapeItems items2;
shape2_processed = convert_shapes(op2, items2) && flatten_shape_list(items2, s2, true);
shape2_processed = convert_shapes(op2, items2) && util::flatten_shape_list(items2, s2, true, getValue(GV_PRECISION));
} else if (shape_type(op2) == ST_SHAPE) {
shape2_processed = convert_shape(op2, s2);
if (shape2_processed) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
s2 = util::ensure_fit_for_subtraction(s2, temp_solid, getValue(GV_PRECISION));
}
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", op2);
@@ -135,7 +135,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
if (is_unbounded_halfspace) {
TopoDS_Shape temp;
double d;
if (fit_halfspace(s1, s2, temp, d)) {
if (util::fit_halfspace(s1, s2, temp, d, getValue(GV_PRECISION))) {
if (d < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", l);
continue;
@@ -151,7 +151,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
}
if (op2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class())) {
const double second_operand_volume = shape_volume(s2);
const double second_operand_volume = util::shape_volume(s2);
if (second_operand_volume <= ALMOST_ZERO) {
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", op2);
}
@@ -210,7 +210,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
// In case of a subtraction, a check on volume is performed.
if (valid_result) {
const double volume_after_subtraction = shape_volume(shape);
const double volume_after_subtraction = util::shape_volume(shape);
if ( ALMOST_THE_SAME(first_operand_volume,volume_after_subtraction) )
Logger::Message(Logger::LOG_WARNING,"Subtraction yields unchanged volume:",l);
} else {
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -52,5 +53,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCShapeProfileDef* l, TopoDS_Sh
double coords[24] = {-x,-y,x,-y,x,-y+d2,x-d1,-y+d2,x-d1,-y+d1,-x+d1,-y+d1,-x+d1,y-d1,x-d1,y-d1,x-d1,y-d2,x,y-d2,x,y,-x,y};
int fillets[8] = {0,1,4,5,6,7,10,11};
double radii[8] = {f2,f2,f1,f1,f1,f1,f2,f2};
return profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
return util::profile_helper(12,coords,doFillet ? 8 : 0,fillets,radii,trsf2d,face);
}
+2 -1
View File
@@ -24,6 +24,7 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -52,7 +53,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCircleProfileDef* l, TopoDS_Sh
w.Add(edge);
TopoDS_Face f;
bool success = convert_wire_to_face(w, f);
bool success = util::convert_wire_to_face(w, f, {false, false, 0., 0.});
if (success) face = f;
return success;
}
+10 -7
View File
@@ -17,9 +17,12 @@
* *
********************************************************************************/
#include "../ifcgeom_schema_agnostic/base_utils.h"
#include "../ifcgeom/IfcGeom.h"
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
#include <memory>
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -38,7 +41,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
points_,
loops_,
l->declaration().is(IfcSchema::IfcClosedShell::Class())
));
));
faceset_helper_ = helper_scope.get();
@@ -52,7 +55,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
bool success = false;
TopoDS_Face face;
try {
success = convert_face(*it, face);
} catch (const std::exception& e) {
@@ -78,7 +81,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
if (face_it.Value().ShapeType() == TopAbs_FACE) {
// This should really be the case. This is not asserted.
const TopoDS_Face& triangle = TopoDS::Face(face_it.Value());
if (face_area(triangle) > min_face_area) {
if (util::face_area(triangle) > min_face_area) {
face_list.Append(triangle);
} else {
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it));
@@ -86,7 +89,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
}
}
} else {
if (face_area(face) > min_face_area) {
if (util::face_area(face) > min_face_area) {
face_list.Append(face);
} else {
Logger::Message(Logger::LOG_WARNING, "Degenerate face:", (*it));
@@ -98,11 +101,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Sh
return false;
}
if (face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !create_solid_from_faces(face_list, shape)) {
if (face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !util::create_solid_from_faces(face_list, shape, getValue(GV_PRECISION))) {
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());
+2 -1
View File
@@ -18,6 +18,7 @@
********************************************************************************/
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -60,6 +61,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCraneRailAShapeProfileDef* l,
+hw / 2., +oh / 2.
};
return profile_helper(14, coords, 0, 0, 0, trsf2d, face);
return util::profile_helper(14, coords, 0, 0, 0, trsf2d, face);
}
#endif
+2 -1
View File
@@ -24,6 +24,7 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -60,7 +61,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcEllipseProfileDef* l, TopoDS_S
w.Add(edge);
TopoDS_Face f;
bool success = convert_wire_to_face(w, f);
bool success = util::convert_wire_to_face(w, f, {false, false, 0., 0.});
if (success) face = f;
return success;
}
+3 -2
View File
@@ -32,6 +32,7 @@
#include <TopExp_Explorer.hxx>
#include <BRepAlgoAPI_Cut.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/base_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -88,11 +89,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, T
TopoDS_Shape result = builder.Shape();
TopTools_ListOfShape li;
shape_to_face_list(result, li);
util::shape_to_face_list(result, li);
li.Append(BRepBuilderAPI_MakeFace(w1).Face().Reversed());
li.Append(BRepBuilderAPI_MakeFace(w2).Face().Moved(end_profile));
create_solid_from_faces(li, result, true);
util::create_solid_from_faces(li, result, true);
// @todo ugly hack
+14 -1495
View File
File diff suppressed because it is too large Load Diff
+1 -47
View File
@@ -259,68 +259,22 @@ public:
void set_offset(const std::array<double, 3>& offset);
void set_rotation(const std::array<double, 4>& rotation);
double get_wire_intersection_tolerance(const TopoDS_Wire&) const;
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
bool convert_wire_to_faces(const TopoDS_Wire& wire, TopoDS_Compound& face);
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
bool convert_shapes(const IfcUtil::IfcBaseInterface* L, IfcRepresentationShapeItems& result);
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseInterface* L);
bool convert_shape(const IfcUtil::IfcBaseInterface* L, TopoDS_Shape& result);
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse);
bool convert_wire(const IfcUtil::IfcBaseInterface* L, TopoDS_Wire& result);
bool convert_curve(const IfcUtil::IfcBaseInterface* L, Handle(Geom_Curve)& result);
bool convert_face(const IfcUtil::IfcBaseInterface* L, TopoDS_Shape& result);
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);
void assert_closed_wire(TopoDS_Wire& wire);
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<std::shared_ptr<const SurfaceStyle>>&, std::vector<double>&);
bool apply_layerset(const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<std::shared_ptr<const SurfaceStyle>>&, IfcRepresentationShapeItems&);
bool apply_folded_layerset(const IfcRepresentationShapeItems&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<std::shared_ptr<const SurfaceStyle>>&, IfcRepresentationShapeItems&);
bool fold_layers(const IfcSchema::IfcWall*, const IfcRepresentationShapeItems&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen=0.1);
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
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 shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li);
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid, bool force_sewing=false);
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);
gp_Pln plane_from_face(const TopoDS_Face& face);
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree=true);
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
void apply_tolerance(TopoDS_Shape& s, double t);
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
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);
static double shape_volume(const TopoDS_Shape& s);
static double face_area(const TopoDS_Face& f);
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
bool is_identity_transform(IfcUtil::IfcBaseInterface*);
IfcSchema::IfcRelVoidsElement::list::ptr find_openings(IfcSchema::IfcProduct* product);
+1 -1
View File
@@ -39,7 +39,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcGeometricSet* l, IfcRepresenta
TopoDS_Shape s;
if (shape_type(element) == ST_SHAPELIST) {
IfcRepresentationShapeItems items;
if (!(convert_shapes(element, items) && flatten_shape_list(items, s, false))) {
if (!(convert_shapes(element, items) && util::flatten_shape_list(items, s, false, getValue(GV_PRECISION)))) {
continue;
}
} else if (shape_type(element) == ST_SHAPE && include_solids_and_surfaces) {
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -67,5 +68,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIShapeProfileDef* l, TopoDS_Sh
double coords[24] = {-x1,-y, x1,-y, x1,-y+dy1, d1,-y+dy1, d1,y-dy2, x2,y-dy2, x2,y, -x2,y, -x2,y-dy2, -d1,y-dy2, -d1,-y+dy1, -x1,-y+dy1};
int fillets[4] = {3,4,9,10};
double radii[4] = {f1,f2,f2,f1};
return profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
return util::profile_helper(12,coords,(doFillet1||doFillet2) ? 4 : 0,fillets,radii,trsf2d,face);
}
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -94,5 +95,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcLShapeProfileDef* l, TopoDS_Sh
double coords[12] = {-x,-y, x,-y, x,-y+d-dy1, xx, xy, -x+d-dx1,y, -x,y};
int fillets[3] = {2,3,4};
double radii[3] = {f2,f1,f2};
return profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
return util::profile_helper(6,coords,doFillet ? 3 : 0,fillets,radii,trsf2d,face);
}
+2 -2
View File
@@ -48,7 +48,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
// Remove points that are too close to one another
const double eps = getValue(GV_PRECISION) * 10;
remove_duplicate_points_from_loop(polygon, true, eps);
util::remove_duplicate_points_from_loop(polygon, true, eps);
int count = polygon.Length();
if (original_count - count != 0) {
@@ -70,7 +70,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& resu
result = w.Wire();
TopTools_ListOfShape results;
if (getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(result, results, get_wire_intersection_tolerance(result), getValue(GV_PRECISION))) {
if (getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(result, results, {getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., getValue(GV_PRECISION)})) {
Logger::Error("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", l);
util::select_largest(results, result);
}
+5 -4
View File
@@ -24,6 +24,7 @@
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepAlgoAPI_Common.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -38,17 +39,17 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l,
if ( ! convert(l->Position(),trsf) ) return false;
TColgp_SequenceOfPnt points;
if (wire_to_sequence_of_point(wire, points)) {
if (util::wire_to_sequence_of_point(wire, points)) {
// Boolean subtractions not very robust for narrow operands,
// increase minimal point spacing to eliminate such shapes.
const double t = getValue(GV_PRECISION) * 10.;
remove_duplicate_points_from_loop(points, wire.Closed() != 0, t); // Note: wire always closed, as per if statement above
remove_collinear_points_from_loop(points, wire.Closed() != 0, t);
util::remove_duplicate_points_from_loop(points, wire.Closed() != 0, t); // Note: wire always closed, as per if statement above
util::remove_collinear_points_from_loop(points, wire.Closed() != 0, t);
if (points.Length() < 3) {
Logger::Message(Logger::LOG_ERROR, "Not enough points retained from:", l->PolygonalBoundary());
return false;
}
sequence_of_point_to_wire(points, wire, wire.Closed() != 0);
util::sequence_of_point_to_wire(points, wire, wire.Closed() != 0);
}
TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200));
+3 -2
View File
@@ -23,6 +23,7 @@
#include <TopoDS_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#include "../ifcgeom_schema_agnostic/base_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -117,7 +118,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalFaceSet* pfs, TopoDS_
TopTools_ListIteratorOfListOfShape it(fs);
for (; it.More(); it.Next()) {
const TopoDS_Face& tri = TopoDS::Face(it.Value());
if (face_area(tri) > getValue(GV_MINIMAL_FACE_AREA)) {
if (util::face_area(tri) > getValue(GV_MINIMAL_FACE_AREA)) {
faces.Append(tri);
}
}
@@ -127,7 +128,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalFaceSet* pfs, TopoDS_
}
}
if (faces.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !create_solid_from_faces(faces, shape)) {
if (faces.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !util::create_solid_from_faces(faces, shape, getValue(GV_PRECISION))) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
+2 -1
View File
@@ -21,6 +21,7 @@
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <TopoDS_Wire.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#define _USE_MATH_DEFINES
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -45,7 +46,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
}
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
util::remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
if (polygon.Length() < 2) {
// We somehow need to signal we fail this curve on purpose not to trigger an error.
+3 -2
View File
@@ -25,6 +25,7 @@
#include <TopExp_Explorer.hxx>
#include <ShapeFix_Shape.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -62,8 +63,8 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* l,
double radii2[4] = {r2,r2,r2,r2};
int fillets[4] = {0,1,2,3};
bool s1 = profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
bool s1 = util::profile_helper(4,coords1,fr1 ? 4 : 0,fillets,radii1,trsf2d,f1);
bool s2 = util::profile_helper(4,coords2,fr2 ? 4 : 0,fillets,radii2,trsf2d,f2);
if (!s1 || !s2) return false;
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -41,5 +42,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS
}
double coords[8] = {-x,-y,x,-y,x,y,-x,y};
return profile_helper(4,coords,0,0,0,trsf2d,face);
return util::profile_helper(4,coords,0,0,0,trsf2d,face);
}
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -44,5 +45,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* l,
double coords[8] = {-x,-y, x,-y, x,y, -x,y};
int fillets[4] = {0,1,2,3};
double radii[4] = {r,r,r,r};
return profile_helper(4,coords,4,fillets,radii,trsf2d,face);
return util::profile_helper(4,coords,4,fillets,radii,trsf2d,face);
}
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -108,5 +109,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTShapeProfileDef* l, TopoDS_Sh
double coords[16] = {d1/2.-dx2,-y, xx,xy, x,y-d2+dy2, x,y, -x,y, -x,y-d2+dy2, -xx,xy, -d1/2.+dx2,-y};
int fillets[6] = {0,1,2,5,6,7};
double radii[6] = {f2,f1,f3,f3,f1,f2};
return profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
return util::profile_helper(8, coords, (doFillet || doWebEdgeFillet || doFlangeEdgeFillet) ? 6 : 0, fillets, radii, trsf2d, face);
}
+3 -1
View File
@@ -19,6 +19,8 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -52,5 +54,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, TopoDS
-x1 + dx + w - x_offset, y,
-x1 + dx - x_offset,y
};
return profile_helper(4,coords,0,0,0,trsf2d,face);
return util::profile_helper(4,coords,0,0,0,trsf2d,face);
}
+2 -1
View File
@@ -21,6 +21,7 @@
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/base_utils.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -48,7 +49,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS
}
}
if (faces.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !create_solid_from_faces(faces, shape)) {
if (faces.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || !util::create_solid_from_faces(faces, shape, getValue(GV_PRECISION))) {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -67,5 +68,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcUShapeProfileDef* l, TopoDS_Sh
double coords[16] = {-x,-y, x,-y, x,-y+d2-dy2, -x+d1,-y+d2+dy1, -x+d1,y-d2-dy1, x,y-d2+dy2, x,y, -x,y};
int fillets[4] = {2,3,4,5};
double radii[4] = {f2,f1,f1,f2};
return profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
return util::profile_helper(8, coords, (doFillet || doEdgeFillet) ? 4 : 0, fillets, radii, trsf2d, face);
}
+2 -1
View File
@@ -19,6 +19,7 @@
#include <gp_Trsf2d.hxx>
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom_schema_agnostic/profile_helper.h"
#define Kernel MAKE_TYPE_NAME(Kernel)
@@ -58,5 +59,5 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcZShapeProfileDef* l, TopoDS_Sh
double coords[16] = {-dx,-y, x,-y, x,-y+dy, dx,-y+dy, dx,y, -x,y, -x,y-dy, -dx,y-dy};
int fillets[4] = {2,3,6,7};
double radii[4] = {f2,f1,f2,f1};
return profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
return util::profile_helper(8,coords,(doFillet || doEdgeFillet) ? 4 : 0,fillets,radii,trsf2d,face);
}
+1 -1
View File
@@ -275,7 +275,7 @@ bool IfcGeom::Kernel::faceset_helper<CP, LP>::wires(const LP& loop, TopTools_Lis
wire.Closed(true);
TopTools_ListOfShape results;
if (kernel_->getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(wire, results, kernel_->get_wire_intersection_tolerance(wire), kernel_->getValue(IfcGeom::Kernel::GV_PRECISION))) {
if (kernel_->getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(wire, results, {kernel_->getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., kernel_->getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., kernel_->getValue(GV_PRECISION)})) {
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
non_manifold_ = true;
wires = results;
+5 -6
View File
@@ -19,6 +19,7 @@
#include "IfcGeom.h"
#include "../ifcgeom_schema_agnostic/IfcGeomShapeType.h"
#include "../ifcgeom_schema_agnostic/wire_utils.h"
#include <BRepCheck_Analyzer.hxx>
@@ -68,7 +69,7 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseInterface* l, TopoDS_Shape& r)
if (st == ST_SHAPELIST) {
processed = true;
IfcRepresentationShapeItems items;
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
success = convert_shapes(l, items) && util::flatten_shape_list(items, r, false, getValue(GV_PRECISION));
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
#include "mapping_shape.i"
} else if (st == ST_FACE && include_solids_and_surfaces) {
@@ -85,22 +86,20 @@ bool IfcGeom::Kernel::convert_shape(const IfcBaseInterface* l, TopoDS_Shape& r)
processed = true;
Handle(Geom_Curve) crv;
TopoDS_Wire w;
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
success = convert_curve(l, crv) && util::convert_curve_to_wire(crv, w);
if (success) {
r = w;
}
}
if ( processed && success ) {
const double precision = getValue(GV_PRECISION);
apply_tolerance(r, precision);
#ifndef NO_CACHE
cache.Shape[id] = r;
#endif
if (Logger::LOG_DEBUG >= Logger::Verbosity()) {
BRepCheck_Analyzer ana(r);
Logger::Notice("Valid: " + std::to_string(ana.IsValid()), l);
Logger::Notice("Valid: " + std::to_string((bool) ana.IsValid()), l);
}
} else if (!ignored) {
const char* const msg = processed
@@ -115,7 +114,7 @@ bool IfcGeom::Kernel::convert_wire(const IfcBaseInterface* l, TopoDS_Wire& r) {
#include "mapping_wire.i"
Handle(Geom_Curve) curve;
if (IfcGeom::Kernel::convert_curve(l, curve)) {
return IfcGeom::Kernel::convert_curve_to_wire(curve, r);
return util::convert_curve_to_wire(curve, r);
}
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l);
return false;
@@ -20,12 +20,15 @@
#ifndef IFCSHAPELIST_H
#define IFCSHAPELIST_H
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include <gp_GTrsf.hxx>
#include <TopoDS_Shape.hxx>
#include "../ifcgeom_schema_agnostic/IfcGeomRenderStyles.h"
#include <vector>
namespace IfcGeom {
class IFC_GEOM_API IfcRepresentationShapeItem {
private:
int id;
@@ -51,6 +54,11 @@ namespace IfcGeom {
void setStyle(std::shared_ptr<const SurfaceStyle> newStyle) { style = newStyle; }
int ItemId() const { return id; }
};
typedef std::vector<IfcRepresentationShapeItem> IfcRepresentationShapeItems;
namespace util {
bool flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& shapes, TopoDS_Shape& result, bool fuse, double tol);
}
}
#endif
+587 -1
View File
@@ -1,13 +1,47 @@
#include "base_utils.h"
#include <TopTools_IndexedMapOfShape.hxx>
#include "../ifcparse/IfcLogger.h"
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <gp_GTrsf.hxx>
#include <gp_GTrsf2d.hxx>
#include <Geom_Plane.hxx>
#include <Geom_OffsetSurface.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <BRep_Tool.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepBuilderAPI_GTransform.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepPrimAPI_MakeHalfSpace.hxx>
#include <BRepOffsetAPI_Sewing.hxx>
#include <GeomAPI_IntSS.hxx>
#include <GeomAPI_IntCS.hxx>
#include <BRepGProp.hxx>
#include <BRepGProp_Face.hxx>
#include <GProp_GProps.hxx>
#include <ShapeFix_Shell.hxx>
#include <ShapeFix_Solid.hxx>
#include <ShapeFix_Shape.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
// For axis placements detect equality early in order for the
// relatively computionaly expensive gp_Trsf calculation to be skipped
bool IfcGeom::util::axis_equal(const gp_Ax3 & a, const gp_Ax3 & b, double tolerance) {
@@ -153,3 +187,555 @@ gp_Trsf IfcGeom::util::combine_offset_and_rotation(const gp_Vec & offset, const
return rotation_transform * offset_transform;
}
bool IfcGeom::util::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) {
// @todo std::unique_ptr for C++11
ShapeAnalysis_Surface* sas = 0;
Handle(Geom_Plane) pln;
if (srf->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
// Optimize projection for specific cases
pln = Handle(Geom_Plane)::DownCast(srf);
} else if (srf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface) && Handle(Geom_OffsetSurface)::DownCast(srf)->BasisSurface()->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
// For an offset planar surface the projected UV coords are the same as the basis surface
pln = Handle(Geom_Plane)::DownCast(Handle(Geom_OffsetSurface)::DownCast(srf)->BasisSurface());
} else {
sas = new ShapeAnalysis_Surface(srf);
}
u1 = v1 = +std::numeric_limits<double>::infinity();
u2 = v2 = -std::numeric_limits<double>::infinity();
gp_Pnt median;
int vertex_count = 0;
for (TopExp_Explorer exp(shp, TopAbs_VERTEX); exp.More(); exp.Next(), ++vertex_count) {
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
median.ChangeCoord() += p.XYZ();
gp_Pnt2d uv;
if (sas) {
uv = sas->ValueOfUV(p, 1e-3);
} else {
gp_Vec d = p.XYZ() - pln->Position().Location().XYZ();
uv.SetX(d.Dot(pln->Position().XDirection()));
uv.SetY(d.Dot(pln->Position().YDirection()));
}
if (uv.X() < u1) u1 = uv.X();
if (uv.Y() < v1) v1 = uv.Y();
if (uv.X() > u2) u2 = uv.X();
if (uv.Y() > v2) v2 = uv.Y();
}
if (vertex_count > 0) {
// Add a little bit of resolution so that the median is shifted towards the mass
// of the curve. This helps to find the parameter ordering for conic surfaces.
for (TopExp_Explorer exp(shp, TopAbs_EDGE); exp.More(); exp.Next(), ++vertex_count) {
const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
double a, b;
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
gp_Pnt p;
crv->D0((a + b) / 2., p);
median.ChangeCoord() += p.XYZ();
}
median.ChangeCoord().Divide(vertex_count);
gp_Pnt2d uv;
if (sas) {
uv = sas->ValueOfUV(median, 1e-3);
} else {
gp_Vec d = median.XYZ() - pln->Position().Location().XYZ();
uv.SetX(d.Dot(pln->Position().XDirection()));
uv.SetY(d.Dot(pln->Position().YDirection()));
}
if (uv.X() < u1 || uv.X() > u2) {
std::swap(u1, u2);
}
u1 -= widen;
u2 += widen;
v1 -= widen;
v2 += widen;
}
delete sas;
return vertex_count > 0;
}
TopoDS_Shape IfcGeom::util::apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) {
if (t.Form() == gp_Identity) {
return s;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if (t.ScaleFactor() != 1.) {
return BRepBuilderAPI_Transform(s, t, true);
} else {
return s.Moved(t);
}
}
}
TopoDS_Shape IfcGeom::util::apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
if (t.Form() == gp_Other) {
return BRepBuilderAPI_GTransform(s, t, true);
} else {
return apply_transformation(s, t.Trsf());
}
}
bool IfcGeom::util::fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height, double tol) {
TopExp_Explorer exp(b, TopAbs_FACE);
if (!exp.More()) {
return false;
}
TopoDS_Face face = TopoDS::Face(exp.Current());
exp.Next();
if (exp.More()) {
return false;
}
Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
// const gp_XYZ xyz = a.Location().Transformation().TranslationPart();
// std::cout << "dz " << xyz.Z() << std::endl;
if (surf->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
return false;
}
Bnd_Box bb;
BRepBndLib::Add(a, bb);
if (bb.IsVoid()) {
return false;
}
double xs[2], ys[2], zs[2];
bb.Get(xs[0], ys[0], zs[0], xs[1], ys[1], zs[1]);
gp_Pln pln = Handle(Geom_Plane)::DownCast(surf)->Pln();
gp_Pnt P = pln.Position().Location();
gp_Vec z = pln.Position().Direction();
gp_Vec x = pln.Position().XDirection();
gp_Vec y = pln.Position().YDirection();
if (face.Orientation() != TopAbs_REVERSED) {
z.Reverse();
}
double D, Umin, Umax, Vmin, Vmax;
D = 0.;
Umin = Vmin = +std::numeric_limits<double>::infinity();
Umax = Vmax = -std::numeric_limits<double>::infinity();
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
for (int k = 0; k < 2; ++k) {
gp_Pnt p(xs[i], ys[j], zs[k]);
gp_Vec d = p.XYZ() - P.XYZ();
const double u = d.Dot(x);
const double v = d.Dot(y);
const double w = d.Dot(z);
if (w > D) {
D = w;
}
if (u < Umin) {
Umin = u;
}
if (u > Umax) {
Umax = u;
}
if (v < Vmin) {
Vmin = v;
}
if (v > Vmax) {
Vmax = v;
}
}
}
}
const double eps = tol * 1000.;
BRepBuilderAPI_MakePolygon poly;
poly.Add(P.XYZ() + x.XYZ() * (Umin - eps) + y.XYZ() * (Vmin - eps));
poly.Add(P.XYZ() + x.XYZ() * (Umax + eps) + y.XYZ() * (Vmin - eps));
poly.Add(P.XYZ() + x.XYZ() * (Umax + eps) + y.XYZ() * (Vmax + eps));
poly.Add(P.XYZ() + x.XYZ() * (Umin - eps) + y.XYZ() * (Vmax + eps));
poly.Close();
BRepBuilderAPI_MakeFace mf(surf, poly.Wire(), true);
gp_Vec vec = gp_Vec(z.XYZ() * (D + eps));
BRepPrimAPI_MakePrism mp(mf.Face(), vec);
box = mp.Shape();
height = D;
return true;
}
const Handle_Geom_Curve IfcGeom::util::intersect(const Handle_Geom_Surface& a, const Handle_Geom_Surface& b) {
GeomAPI_IntSS x(a, b, 1.e-7);
if (x.IsDone() && x.NbLines() == 1) {
return x.Line(1);
} else {
return Handle_Geom_Curve();
}
}
const Handle_Geom_Curve IfcGeom::util::intersect(const Handle_Geom_Surface& a, const TopoDS_Face& b) {
return intersect(a, BRep_Tool::Surface(b));
}
const Handle_Geom_Curve IfcGeom::util::intersect(const TopoDS_Face& a, const Handle_Geom_Surface& b) {
return intersect(BRep_Tool::Surface(a), b);
}
bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Surface& b, gp_Pnt& p) {
GeomAPI_IntCS x(a, b);
if (x.IsDone() && x.NbPoints() == 1) {
p = x.Point(1);
return true;
} else {
return false;
}
}
bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const TopoDS_Face& b, gp_Pnt &c) {
return intersect(a, BRep_Tool::Surface(b), c);
}
bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& b, std::vector<gp_Pnt>& out) {
TopExp_Explorer exp(b, TopAbs_FACE);
gp_Pnt p;
for (; exp.More(); exp.Next()) {
if (intersect(a, TopoDS::Face(exp.Current()), p)) {
out.push_back(p);
}
}
return !out.empty();
}
bool IfcGeom::util::intersect(const Handle_Geom_Surface& a, const TopoDS_Shape& b, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >& out) {
TopExp_Explorer exp(b, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
const TopoDS_Face& f = TopoDS::Face(exp.Current());
const Handle_Geom_Surface& s = BRep_Tool::Surface(f);
Handle_Geom_Curve crv = intersect(a, s);
if (!crv.IsNull()) {
out.push_back(std::make_pair(s, crv));
}
}
return !out.empty();
}
bool IfcGeom::util::closest(const gp_Pnt& a, const std::vector<gp_Pnt>& b, gp_Pnt& c) {
double minimal_distance = std::numeric_limits<double>::infinity();
for (std::vector<gp_Pnt>::const_iterator it = b.begin(); it != b.end(); ++it) {
const double d = a.Distance(*it);
if (d < minimal_distance) {
minimal_distance = d;
c = *it;
}
}
return minimal_distance != std::numeric_limits<double>::infinity();
}
bool IfcGeom::util::project(const Handle_Geom_Curve& crv, const gp_Pnt& pt, gp_Pnt& p, double& u, double& d) {
ShapeAnalysis_Curve sac;
sac.Project(crv, pt, 1e-3, p, u, false);
d = pt.Distance(p);
return true;
}
double IfcGeom::util::shape_volume(const TopoDS_Shape& s) {
GProp_GProps prop;
BRepGProp::VolumeProperties(s, prop);
return prop.Mass();
}
double IfcGeom::util::face_area(const TopoDS_Face& f) {
GProp_GProps prop;
BRepGProp::SurfaceProperties(f, prop);
return prop.Mass();
}
bool IfcGeom::util::is_convex(const TopoDS_Wire& wire, double tol) {
for (TopExp_Explorer exp1(wire, TopAbs_VERTEX); exp1.More(); exp1.Next()) {
TopoDS_Vertex V1 = TopoDS::Vertex(exp1.Current());
gp_Pnt P1 = BRep_Tool::Pnt(V1);
// Store the neighboring points
std::vector<gp_Pnt> neighbors;
for (TopExp_Explorer exp3(wire, TopAbs_EDGE); exp3.More(); exp3.Next()) {
TopoDS_Edge edge = TopoDS::Edge(exp3.Current());
std::vector<gp_Pnt> edge_points;
for (TopExp_Explorer exp2(edge, TopAbs_VERTEX); exp2.More(); exp2.Next()) {
TopoDS_Vertex V2 = TopoDS::Vertex(exp2.Current());
gp_Pnt P2 = BRep_Tool::Pnt(V2);
edge_points.push_back(P2);
}
if (edge_points.size() != 2) continue;
if (edge_points[0].IsEqual(P1, tol)) neighbors.push_back(edge_points[1]);
else if (edge_points[1].IsEqual(P1, tol)) neighbors.push_back(edge_points[0]);
}
// There should be two of these
if (neighbors.size() != 2) return false;
// Now find the non neighboring points
std::vector<gp_Pnt> non_neighbors;
for (TopExp_Explorer exp2(wire, TopAbs_VERTEX); exp2.More(); exp2.Next()) {
TopoDS_Vertex V2 = TopoDS::Vertex(exp2.Current());
gp_Pnt P2 = BRep_Tool::Pnt(V2);
if (P1.IsEqual(P2, tol)) continue;
bool found = false;
for (std::vector<gp_Pnt>::const_iterator it = neighbors.begin(); it != neighbors.end(); ++it) {
if ((*it).IsEqual(P2, tol)) { found = true; break; }
}
if (!found) non_neighbors.push_back(P2);
}
// Calculate the angle between the two edges of the vertex
gp_Dir dir1(neighbors[0].XYZ() - P1.XYZ());
gp_Dir dir2(neighbors[1].XYZ() - P1.XYZ());
const double angle = acos(dir1.Dot(dir2)) + 0.0001;
// Now for the non-neighbors see whether a greater angle can be found with one of the edges
for (std::vector<gp_Pnt>::const_iterator it = non_neighbors.begin(); it != non_neighbors.end(); ++it) {
gp_Dir dir3((*it).XYZ() - P1.XYZ());
const double angle2 = acos(dir3.Dot(dir1));
const double angle3 = acos(dir3.Dot(dir2));
if (angle2 > angle || angle3 > angle) return false;
}
}
return true;
}
TopoDS_Shape IfcGeom::util::halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent) {
TopoDS_Face face = BRepBuilderAPI_MakeFace(pln).Face();
return BRepPrimAPI_MakeHalfSpace(face, cent).Solid();
}
gp_Pln IfcGeom::util::plane_from_face(const TopoDS_Face& face) {
BRepGProp_Face prop(face);
Standard_Real u1, u2, v1, v2;
prop.Bounds(u1, u2, v1, v2);
Standard_Real u = (u1 + u2) / 2.0;
Standard_Real v = (v1 + v2) / 2.0;
gp_Pnt p;
gp_Vec n;
prop.Normal(u, v, p, n);
return gp_Pln(p, n);
}
gp_Pnt IfcGeom::util::point_above_plane(const gp_Pln& pln, bool agree) {
if (agree) {
return pln.Location().Translated(pln.Axis().Direction());
} else {
return pln.Location().Translated(-pln.Axis().Direction());
}
}
bool IfcGeom::util::is_compound(const TopoDS_Shape& shape) {
bool has_solids = TopExp_Explorer(shape, TopAbs_SOLID).More() != 0;
bool has_shells = TopExp_Explorer(shape, TopAbs_SHELL).More() != 0;
bool has_compounds = TopExp_Explorer(shape, TopAbs_COMPOUND).More() != 0;
bool has_faces = TopExp_Explorer(shape, TopAbs_FACE).More() != 0;
return has_compounds && has_faces && !has_solids && !has_shells;
}
bool IfcGeom::util::shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li) {
TopExp_Explorer exp(s, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
TopoDS_Face face = TopoDS::Face(exp.Current());
li.Append(face);
}
return true;
}
bool IfcGeom::util::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape, double tol) {
TopTools_ListOfShape face_list;
shape_to_face_list(compound, face_list);
if (face_list.Extent() == 0) {
return false;
}
return create_solid_from_faces(face_list, shape, tol);
}
bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape, double tol, bool force_sewing) {
bool valid_shell = false;
if (face_list.Extent() == 1) {
shape = face_list.First();
// A bit dubious what to return here.
return true;
} else if (face_list.Extent() == 0) {
return false;
}
TopTools_ListIteratorOfListOfShape face_iterator;
bool has_shared_edges = false;
TopTools_MapOfShape edge_set;
// In case there are wire interesections or failures in non-planar wire triangulations
// the idea is to let occt do an exhaustive search of edge partners. But we have not
// found a case where this actually improves boolean ops later on.
// if (!faceset_helper_ || !faceset_helper_->non_manifold()) {
for (face_iterator.Initialize(face_list); !force_sewing && face_iterator.More(); face_iterator.Next()) {
// As soon as is detected one of the edges is shared, the assumption is made no
// additional sewing is necessary.
if (!has_shared_edges) {
TopExp_Explorer exp(face_iterator.Value(), TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
if (edge_set.Contains(exp.Current())) {
has_shared_edges = true;
break;
}
edge_set.Add(exp.Current());
}
}
}
BRepOffsetAPI_Sewing sewing_builder;
sewing_builder.SetTolerance(tol);
sewing_builder.SetMaxTolerance(tol);
sewing_builder.SetMinTolerance(tol);
BRep_Builder builder;
TopoDS_Shell shell;
builder.MakeShell(shell);
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
if (has_shared_edges) {
builder.Add(shell, face_iterator.Value());
} else {
sewing_builder.Add(face_iterator.Value());
}
}
try {
if (has_shared_edges) {
ShapeFix_Shell fix;
fix.FixFaceOrientation(shell);
shape = fix.Shape();
} else {
sewing_builder.Perform();
shape = sewing_builder.SewedShape();
}
BRepCheck_Analyzer ana(shape);
valid_shell = ana.IsValid();
if (!valid_shell) {
ShapeFix_Shape sfs(shape);
sfs.Perform();
shape = sfs.Shape();
BRepCheck_Analyzer reana(shape);
valid_shell = reana.IsValid();
}
valid_shell &= util::count(shape, TopAbs_SHELL) > 0;
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error sewing shell");
}
} catch (...) {
Logger::Error("Unknown error sewing shell");
}
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.SetMaxTolerance(tol);
TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(exp.Current()));
// @todo: BRepClass3d_SolidClassifier::PerformInfinitePoint() is done by SolidFromShell
// and this is done again, to be able to catch errors during this process.
// This is double work that should be avoided.
if (!solid_shape.IsNull()) {
try {
BRepClass3d_SolidClassifier classifier(solid_shape);
result_shape = solid_shape;
classifier.PerformInfinitePoint(tol);
if (classifier.State() == TopAbs_IN) {
shape.Reverse();
}
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error classifying solid");
}
} catch (...) {
Logger::Error("Unknown error classifying solid");
}
}
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error creating solid");
}
} catch (...) {
Logger::Error("Unknown error creating solid");
}
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::Warning("Multiple components in IfcConnectedFaceSet");
}
B.Add(complete_shape, result_shape);
}
}
TopExp_Explorer loose_faces(shape, TopAbs_FACE, TopAbs_SHELL);
for (; loose_faces.More(); loose_faces.Next()) {
BRep_Builder B;
if (complete_shape.ShapeType() != TopAbs_COMPOUND) {
TopoDS_Compound C;
B.MakeCompound(C);
B.Add(C, complete_shape);
complete_shape = C;
Logger::Warning("Loose faces in IfcConnectedFaceSet");
}
B.Add(complete_shape, loose_faces.Current());
}
shape = complete_shape;
} else {
Logger::Error("Failed to sew faceset");
}
return valid_shell;
}
+40 -1
View File
@@ -1,8 +1,19 @@
#ifndef BASE_UTILS_H
#define BASE_UTILS_H
#include <TopoDS_Shape.hxx>
#include <gp_Ax3.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <vector>
namespace IfcGeom {
namespace util {
@@ -26,6 +37,34 @@ namespace IfcGeom {
gp_Trsf combine_offset_and_rotation(const gp_Vec &offset, const gp_Quaternion& rotation);
bool is_nested_compound_of_solid(const TopoDS_Shape& s, int depth = 0);
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid, double tol);
bool shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li);
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid, double tol, bool force_sewing = false);
bool is_compound(const TopoDS_Shape& shape);
bool is_convex(const TopoDS_Wire& wire, double tol);
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent);
gp_Pln plane_from_face(const TopoDS_Face& face);
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true);
bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height, double tol);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1);
double shape_volume(const TopoDS_Shape& s);
double face_area(const TopoDS_Face& f);
TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
}
}
@@ -1357,3 +1357,16 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
bs.Append(b);
return boolean_operation(settings, a, bs, op, result, fuzziness);
}
const TopoDS_Shape& IfcGeom::util::ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid, double tol) {
const bool is_comp = is_compound(shape);
if (!is_comp) {
return solid = shape;
}
if (!create_solid_from_compound(shape, solid, tol)) {
return solid = shape;
}
return solid;
}
@@ -93,6 +93,8 @@ namespace IfcGeom {
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid, double tol);
}
}
+380 -2
View File
@@ -3,6 +3,7 @@
#include "../ifcparse/IfcLogger.h"
#include "../ifcgeom_schema_agnostic/Kernel.h"
#include "../ifcgeom_schema_agnostic/base_utils.h"
#include "../ifcgeom_schema_agnostic/boolean_utils.h"
#include "../ifcgeom_schema_agnostic/IfcGeomTree.h"
#include <TopExp.hxx>
@@ -21,6 +22,9 @@
#include <ShapeExtend_WireData.hxx>
#include <Standard_Version.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
#include <BRepOffsetAPI_Sewing.hxx>
#include <ShapeFix_Solid.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
@@ -350,7 +354,25 @@ namespace {
};
}
bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, double eps, double eps_real) {
namespace {
double get_wire_intersection_tolerance(const IfcGeom::util::wire_tolerance_settings& settings, const TopoDS_Wire& wire) {
if (settings.use_wire_intersection_tolerance) {
// This corresponds to faceset_helper::epsilon
if (settings.vertex_clustering_epsilon > 0.) {
return settings.vertex_clustering_epsilon / 3.;
} else {
return (std::min)(IfcGeom::util::min_edge_length(wire) / 2., settings.precision * 10.);
}
} else {
return 0.;
}
}
}
bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings) {
double eps = get_wire_intersection_tolerance(settings, wire);
double eps_real = settings.precision;
if (!wire.Closed()) {
wires.Append(wire);
return false;
@@ -512,7 +534,7 @@ bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfS
// @todo this is a change in behaviour with eps precomputed from the kernel
// instead of adaptively calculated for the successive iterations.
wire_intersections(sfw.Wire(), wires, eps, eps_real);
wire_intersections(sfw.Wire(), wires, settings);
}
return true;
@@ -567,4 +589,360 @@ void IfcGeom::util::select_largest(const TopTools_ListOfShape& shapes, TopoDS_Sh
largest = it.Value();
}
}
}
bool IfcGeom::util::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::util::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();
}
void IfcGeom::util::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
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 = (int)to_remove.size() - 1; i >= 0; --i) {
if (to_remove[i]) {
polygon.Remove(i + 1);
}
}
}
void IfcGeom::util::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
tol *= tol;
for (;;) {
bool removed = false;
int n = polygon.Length() - (closed ? 0 : 1);
for (int i = 1; i <= n; ++i) {
// wrap around to the first point in case of a closed loop
int j = (i % polygon.Length()) + 1;
double dist = polygon.Value(i).SquareDistance(polygon.Value(j));
if (dist < tol) {
// do not remove the first or last point to
// maintain connectivity with other wires
if ((closed && j == 1) || (!closed && j == n)) polygon.Remove(i);
else polygon.Remove(j);
removed = true;
break;
}
}
if (!removed) break;
}
}
namespace {
// 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();
}
return TopoDS_Vertex();
}
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;
}
}
return TopoDS_Edge();
}
}
bool IfcGeom::util::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape, double tol) {
BRepOffsetAPI_Sewing sew;
sew.Add(shape);
TopTools_IndexedDataMapOfShapeListOfShape edge_to_faces;
TopTools_IndexedDataMapOfShapeListOfShape vertex_to_edges;
std::set<int> 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));
// 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;
for (;;) {
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);
if (other.IsNull()) {
// Dealing with a conical edge probably, for some reason
// this works better than adding the edge directly.
double u1, u2;
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
w.Add(BRepBuilderAPI_MakeEdge(crv, u1, u2));
break;
} else {
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(tol);
shape = solid.SolidFromShell(TopoDS::Shell(shape));
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error creating solid");
}
} catch (...) {
Logger::Error("Unknown error creating solid");
}
return true;
}
bool IfcGeom::util::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) {
try {
wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(curve));
return true;
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
} else {
Logger::Error("Unknown error converting curve to wire");
}
} catch (...) {
Logger::Error("Unknown error converting curve to wire");
}
return false;
}
void IfcGeom::util::assert_closed_wire(TopoDS_Wire& wire, double tol) {
if (wire.Closed() == 0) {
TopoDS_Vertex v0, v1;
TopExp::Vertices(wire, v0, v1);
gp_Pnt p1 = BRep_Tool::Pnt(v0);
gp_Pnt p2 = BRep_Tool::Pnt(v1);
if (p1.Distance(p2) > tol) {
BRepBuilderAPI_MakeWire mw;
mw.Add(wire);
mw.Add(BRepBuilderAPI_MakeEdge(v0, v1).Edge());
wire = mw.Wire();
}
Logger::Warning("Wire not closed");
}
}
bool IfcGeom::util::convert_wire_to_face(const TopoDS_Wire& w, TopoDS_Face& face, const IfcGeom::util::wire_tolerance_settings& settings) {
TopoDS_Wire wire = w;
TopTools_ListOfShape results;
if (settings.use_wire_intersection_check && util::wire_intersections(wire, results, settings)) {
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
util::select_largest(results, wire);
}
bool is_2d = true;
TopExp_Explorer exp(wire, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
double a, b;
// @todo this does not handle fillets
Handle(Geom_Curve) crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
is_2d = false;
break;
}
Handle(Geom_Line) line = Handle(Geom_Line)::DownCast(crv);
if (line->Lin().Direction().Z() > ALMOST_ZERO) {
is_2d = false;
break;
}
}
if (!is_2d) {
// For 2d wires (e.g. profiles) a higher tolerance for plane fitting is never required.
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, settings.precision, TopAbs_WIRE);
}
BRepBuilderAPI_MakeFace mf(wire, false);
BRepBuilderAPI_FaceError er = mf.Error();
if (er != BRepBuilderAPI_FaceDone) {
Logger::Error("Failed to create face.");
return false;
}
face = mf.Face();
return true;
}
bool IfcGeom::util::convert_wire_to_faces(const TopoDS_Wire& w, TopoDS_Compound& faces, const IfcGeom::util::wire_tolerance_settings& settings) {
bool is_2d = true;
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)) {
is_2d = false;
break;
}
Handle(Geom_Line) line = Handle(Geom_Line)::DownCast(crv);
if (line->Lin().Direction().Z() > ALMOST_ZERO) {
is_2d = false;
break;
}
}
TopTools_ListOfShape results;
if (settings.use_wire_intersection_check && util::wire_intersections(w, results, settings)) {
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
} else {
results.Clear();
results.Append(w);
}
TopoDS_Compound C;
BRep_Builder B;
B.MakeCompound(faces);
std::list<std::pair<double, TopoDS_Face>> face_list;
double max_area = 0.;
TopTools_ListIteratorOfListOfShape it(results);
for (; it.More(); it.Next()) {
const TopoDS_Wire& wire = TopoDS::Wire(it.Value());
if (!is_2d) {
// For 2d wires (e.g. profiles) a higher tolerance for plane fitting is never required.
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, settings.precision, TopAbs_WIRE);
}
BRepBuilderAPI_MakeFace mf(wire, false);
BRepBuilderAPI_FaceError er = mf.Error();
if (er != BRepBuilderAPI_FaceDone) {
Logger::Error("Failed to create face.");
continue;
}
TopoDS_Face face = mf.Face();
const double m = face_area(face);
face_list.push_back({ m, face });
if (m > max_area) {
max_area = m;
}
}
for (auto& p : face_list) {
if (p.first >= max_area / 10.) {
B.Add(faces, p.second);
} else {
Logger::Warning("Ignoring self-intersection loop with area " + boost::lexical_cast<std::string>(p.first));
}
}
return true;
}
+35 -3
View File
@@ -1,5 +1,16 @@
#ifndef WIRE_UTILS_H
#define WIRE_UTILS_H
#include <gp_Pln.hxx>
#include <Geom_Curve.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Compound.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TopTools_ListOfShape.hxx>
#include <vector>
@@ -16,13 +27,34 @@ namespace IfcGeom {
TRIANGULATE_WIRE_NON_MANIFOLD,
};
struct wire_tolerance_settings {
bool use_wire_intersection_check;
bool use_wire_intersection_tolerance;
double vertex_clustering_epsilon;
double precision;
};
/// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire.
triangulate_wire_result triangulate_wire(const std::vector<TopoDS_Wire>& wires, TopTools_ListOfShape& faces);
// eps: tolerance added to wire intersection checks, can be zero
// eps_real: tolerance used to construct new edge geometry around intersection points, cannot be zero
bool wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, double eps, double eps_real);
bool wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings);
void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest);
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face, const IfcGeom::util::wire_tolerance_settings& settings);
bool convert_wire_to_faces(const TopoDS_Wire& wire, TopoDS_Compound& face, const IfcGeom::util::wire_tolerance_settings& settings);
void assert_closed_wire(TopoDS_Wire& wire, double tol);
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape, double tol);
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol);
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol);
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
}
}
#endif