mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Refactoring
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1
-47
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user