mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 05:14:30 +00:00
Project wires onto a plane if non-planar. Fixes #57.
This commit is contained in:
@@ -128,6 +128,8 @@ public:
|
|||||||
void remove_collinear_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&);
|
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||||
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||||
|
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&);
|
||||||
|
bool flatten_wire(TopoDS_Wire&);
|
||||||
|
|
||||||
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
std::pair<std::string, double> initializeUnits(IfcSchema::IfcUnitAssignment*);
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,11 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
|||||||
ShapeFix_ShapeTolerance FTol;
|
ShapeFix_ShapeTolerance FTol;
|
||||||
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
|
||||||
|
|
||||||
|
bool flattened_wire = false;
|
||||||
|
|
||||||
if (!mf) {
|
if (!mf) {
|
||||||
|
process_wire:
|
||||||
|
|
||||||
if (face_surface.IsNull()) {
|
if (face_surface.IsNull()) {
|
||||||
mf = new BRepBuilderAPI_MakeFace(wire);
|
mf = new BRepBuilderAPI_MakeFace(wire);
|
||||||
} else {
|
} else {
|
||||||
@@ -264,9 +268,16 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
|||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity);
|
const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar;
|
||||||
delete mf;
|
delete mf;
|
||||||
return false;
|
if (!non_planar || flattened_wire || !flatten_wire(wire)) {
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary", bound->entity);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Logger::Message(Logger::LOG_ERROR, "Flattening face boundary", bound->entity);
|
||||||
|
flattened_wire = true;
|
||||||
|
goto process_wire;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -75,6 +75,8 @@
|
|||||||
#include <BRepAlgoAPI_Cut.hxx>
|
#include <BRepAlgoAPI_Cut.hxx>
|
||||||
#include <BRepAlgoAPI_Fuse.hxx>
|
#include <BRepAlgoAPI_Fuse.hxx>
|
||||||
|
|
||||||
|
#include <BRepAlgo_NormalProjection.hxx>
|
||||||
|
|
||||||
#include <ShapeFix_Shape.hxx>
|
#include <ShapeFix_Shape.hxx>
|
||||||
#include <ShapeFix_ShapeTolerance.hxx>
|
#include <ShapeFix_ShapeTolerance.hxx>
|
||||||
#include <ShapeFix_Solid.hxx>
|
#include <ShapeFix_Solid.hxx>
|
||||||
@@ -94,6 +96,7 @@
|
|||||||
|
|
||||||
#include <BRepMesh_IncrementalMesh.hxx>
|
#include <BRepMesh_IncrementalMesh.hxx>
|
||||||
#include <BRepTools.hxx>
|
#include <BRepTools.hxx>
|
||||||
|
#include <BRepTools_WireExplorer.hxx>
|
||||||
|
|
||||||
#include <Poly_Triangulation.hxx>
|
#include <Poly_Triangulation.hxx>
|
||||||
#include <Poly_Array1OfTriangle.hxx>
|
#include <Poly_Array1OfTriangle.hxx>
|
||||||
@@ -1301,3 +1304,74 @@ const IfcSchema::IfcRepresentationItem* IfcGeom::Kernel::find_item_carrying_styl
|
|||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane) {
|
||||||
|
// Newell's Method is used for the normal calculation
|
||||||
|
// as a simple edge cross product can give opposite results
|
||||||
|
// for a concave face boundary.
|
||||||
|
// Reference: Graphics Gems III p. 231
|
||||||
|
|
||||||
|
double x = 0, y = 0, z = 0;
|
||||||
|
gp_Pnt current, previous, first;
|
||||||
|
gp_XYZ center;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
BRepTools_WireExplorer exp(wire);
|
||||||
|
|
||||||
|
for (;; exp.Next()) {
|
||||||
|
const bool has_more = exp.More();
|
||||||
|
if (has_more) {
|
||||||
|
const TopoDS_Vertex& v = exp.CurrentVertex();
|
||||||
|
current = BRep_Tool::Pnt(v);
|
||||||
|
center += current.XYZ();
|
||||||
|
} else {
|
||||||
|
current = first;
|
||||||
|
}
|
||||||
|
if (n) {
|
||||||
|
const double& xn = previous.X();
|
||||||
|
const double& yn = previous.Y();
|
||||||
|
const double& zn = previous.Z();
|
||||||
|
const double& xn1 = current.X();
|
||||||
|
const double& yn1 = current.Y();
|
||||||
|
const double& zn1 = current.Z();
|
||||||
|
x += (yn - yn1)*(zn + zn1);
|
||||||
|
y += (xn + xn1)*(zn - zn1);
|
||||||
|
z += (xn - xn1)*(yn + yn1);
|
||||||
|
} else {
|
||||||
|
first = current;
|
||||||
|
}
|
||||||
|
if (!has_more) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previous = current;
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane = gp_Pln(center / n, gp_Dir(x, y, z));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IfcGeom::Kernel::flatten_wire(TopoDS_Wire& wire) {
|
||||||
|
gp_Pln pln;
|
||||||
|
if (!approximate_plane_through_wire(wire, pln)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TopoDS_Face face = BRepBuilderAPI_MakeFace(pln).Face();
|
||||||
|
BRepAlgo_NormalProjection proj(face);
|
||||||
|
proj.Add(wire);
|
||||||
|
proj.Build();
|
||||||
|
if (!proj.IsDone()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TopTools_ListOfShape list;
|
||||||
|
proj.BuildWire(list);
|
||||||
|
if (list.Extent() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wire = TopoDS::Wire(list.First());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user