mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-31 08:56:34 +00:00
Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu
This commit is contained in:
@@ -37,7 +37,14 @@
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <BRepClass3d_SolidClassifier.hxx>
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <Standard_Integer.hxx>
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <NCollection_DataMap.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepExtrema_ExtPF.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
@@ -121,7 +128,7 @@ namespace IfcGeom {
|
||||
while (exp.More()) {
|
||||
is_closed = true;
|
||||
TopoDS_Shell shell = TopoDS::Shell(exp.Current());
|
||||
TopTools_IndexedDataMapOfShapeListOfShape edgeFaceMap;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> edgeFaceMap;
|
||||
TopExp::MapShapesAndAncestors(s, TopAbs_EDGE, TopAbs_FACE, edgeFaceMap);
|
||||
|
||||
for (int i = 1; i <= edgeFaceMap.Extent(); ++i) {
|
||||
@@ -1437,13 +1444,13 @@ namespace IfcGeom {
|
||||
, bounds_(b)
|
||||
{}
|
||||
|
||||
Standard_Boolean Reject(const Bnd_Box& b) const {
|
||||
bool Reject(const Bnd_Box& b) const {
|
||||
return bounds_.IsOut(b);
|
||||
}
|
||||
|
||||
Standard_Boolean Accept(const T& o) {
|
||||
bool Accept(const T& o) {
|
||||
results_.push_back(o);
|
||||
return Standard_True;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<T>& results() const {
|
||||
@@ -1679,11 +1686,15 @@ namespace IfcGeom {
|
||||
std::vector<gp_Vec> original_normals;
|
||||
|
||||
// Attempt to copy exactly what BRepExtrema_TriangleSet is doing under the hood.
|
||||
const auto builder = new BVH_LinearBuilder<Standard_Real, 3>(BVH_Constants_LeafNodeSizeDefault, BVH_Constants_MaxTreeDepth);
|
||||
BVH_Triangulation<Standard_Real, 3> triangulation(builder);
|
||||
const auto builder = new BVH_LinearBuilder<double, 3>(BVH_Constants_LeafNodeSizeDefault, BVH_Constants_MaxTreeDepth);
|
||||
BVH_Triangulation<double, 3> triangulation(builder);
|
||||
|
||||
for (int i = 0; i < elem_verts.size(); i += 3) {
|
||||
#if OCC_VERSION_HEX >= 0x80000
|
||||
triangulation.Vertices.Append(BVH_Vec3d(elem_verts[i], elem_verts[i + 1], elem_verts[i + 2]));
|
||||
#else
|
||||
triangulation.Vertices.push_back(BVH_Vec3d(elem_verts[i], elem_verts[i + 1], elem_verts[i + 2]));
|
||||
#endif
|
||||
verts.push_back(gp_Pnt(elem_verts[i], elem_verts[i + 1], elem_verts[i + 2]));
|
||||
}
|
||||
|
||||
@@ -1695,7 +1706,11 @@ namespace IfcGeom {
|
||||
gp_Vec dir2(v1_pnt, v3_pnt);
|
||||
gp_Vec cross_product = dir1.Crossed(dir2);
|
||||
if (cross_product.Magnitude() > Precision::Confusion()) {
|
||||
#if OCC_VERSION_HEX >= 0x80000
|
||||
triangulation.Elements.Append(BVH_Vec4i(
|
||||
#else
|
||||
triangulation.Elements.push_back(BVH_Vec4i(
|
||||
#endif
|
||||
elem_faces[i], elem_faces[i + 1], elem_faces[i + 2], original_tris_index
|
||||
));
|
||||
original_tris_index++;
|
||||
@@ -1842,7 +1857,7 @@ namespace IfcGeom {
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef TopTools_DataMapOfShapeInteger face_style_map_t;
|
||||
typedef NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher> face_style_map_t;
|
||||
|
||||
face_style_map_t face_styles_;
|
||||
std::vector<ifcopenshell::geometry::taxonomy::style::ptr> styles_;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
using IfcGeom::OpaqueNumber;
|
||||
using IfcGeom::OpaqueCoordinate;
|
||||
using IfcGeom::NumberNativeDouble;
|
||||
using IfcGeom::ConversionResultShape;
|
||||
|
||||
namespace {
|
||||
@@ -69,7 +68,7 @@ IfcGeom::ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::clone(
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
|
||||
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id, Logger& logger) const {
|
||||
|
||||
// @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4::ptr matrix, gp_GTrsf& trsf);
|
||||
// above can be static?
|
||||
@@ -109,7 +108,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(shape_, settings.get<settings::MesherLinearDeflection>().get(), false, settings.get<settings::MesherAngularDeflection>().get());
|
||||
} catch (...) {
|
||||
logger::message(logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 183, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -132,10 +131,10 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
std::vector<std::tuple<int, int, int>> triangle_indices;
|
||||
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
opencascade::handle<Poly_Triangulation> tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (tri.IsNull()) {
|
||||
logger::message(logger::LOG_ERROR, "Triangulation missing for face");
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 184, "Triangulation missing for face");
|
||||
} else {
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
@@ -168,7 +167,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
normal = normal_direction;
|
||||
}
|
||||
} else {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(face);
|
||||
opencascade::handle<Geom_Surface> surf = BRep_Tool::Surface(face);
|
||||
// Special case the normal at the poles of a spherical surface
|
||||
if (surf->DynamicType() == STANDARD_TYPE(Geom_SphericalSurface)) {
|
||||
if (fabs(fabs(uv.Y()) - M_PI / 2.) < 1.e-9) {
|
||||
@@ -188,7 +187,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
const NCollection_Array1<Poly_Triangle>& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
@@ -196,7 +195,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
if (dict[n1] == dict[n2] || dict[n2] == dict[n3] || dict[n3] == dict[n1]) {
|
||||
logger::warning("Mesher generated a degenerate triangle, ignoring");
|
||||
logger.Warning("GEO", 185, "Mesher generated a degenerate triangle, ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -267,7 +266,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
|
||||
TopTools_ListOfShape edges;
|
||||
NCollection_List<TopoDS_Shape> edges;
|
||||
// First collect edges part of wire in order
|
||||
for (TopExp_Explorer texp(shape_, TopAbs_WIRE); texp.More(); texp.Next()) {
|
||||
BRepTools_WireExplorer wexp(TopoDS::Wire(texp.Current()));
|
||||
@@ -281,7 +280,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
edges.Append(texp.Current());
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape texp(edges); texp.More(); texp.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator texp(edges); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Value()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings.get<settings::MesherLinearDeflection>().get());
|
||||
int n = tessellater.NbPoints();
|
||||
@@ -407,28 +406,28 @@ int ifcopenshell::geometry::OpenCascadeShape::num_faces() const
|
||||
return IfcGeom::util::count(shape_, TopAbs_FACE);
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape::length()
|
||||
OpaqueNumber ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape::length()
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::LinearProperties(shape_, prop);
|
||||
double l = prop.Mass();
|
||||
return new NumberNativeDouble(l);
|
||||
return OpaqueNumber(l);
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::OpenCascadeShape::area()
|
||||
OpaqueNumber ifcopenshell::geometry::OpenCascadeShape::area()
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(shape_, prop);
|
||||
double l = prop.Mass();
|
||||
return new NumberNativeDouble(l);
|
||||
return OpaqueNumber(l);
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::OpenCascadeShape::volume()
|
||||
OpaqueNumber ifcopenshell::geometry::OpenCascadeShape::volume()
|
||||
{
|
||||
GProp_GProps prop;
|
||||
BRepGProp::VolumeProperties(shape_, prop);
|
||||
double l = prop.Mass();
|
||||
return new NumberNativeDouble(l);
|
||||
return OpaqueNumber(l);
|
||||
}
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
@@ -441,9 +440,9 @@ OpaqueCoordinate<3> ifcopenshell::geometry::OpenCascadeShape::position()
|
||||
if (plane) {
|
||||
auto loc = plane->Location();
|
||||
return OpaqueCoordinate<3>(
|
||||
new NumberNativeDouble(loc.X()),
|
||||
new NumberNativeDouble(loc.Y()),
|
||||
new NumberNativeDouble(loc.Z())
|
||||
OpaqueNumber(loc.X()),
|
||||
OpaqueNumber(loc.Y()),
|
||||
OpaqueNumber(loc.Z())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -458,9 +457,9 @@ OpaqueCoordinate<3> ifcopenshell::geometry::OpenCascadeShape::axis()
|
||||
if (plane) {
|
||||
auto dir = plane->Axis().Direction();
|
||||
return OpaqueCoordinate<3>(
|
||||
new NumberNativeDouble(dir.X()),
|
||||
new NumberNativeDouble(dir.Y()),
|
||||
new NumberNativeDouble(dir.Z())
|
||||
OpaqueNumber(dir.X()),
|
||||
OpaqueNumber(dir.Y()),
|
||||
OpaqueNumber(dir.Z())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -476,10 +475,10 @@ OpaqueCoordinate<4> ifcopenshell::geometry::OpenCascadeShape::plane_equation()
|
||||
double a, b, c, d;
|
||||
plane->Pln().Coefficients(a, b, c, d);
|
||||
return OpaqueCoordinate<4>(
|
||||
new NumberNativeDouble(a),
|
||||
new NumberNativeDouble(b),
|
||||
new NumberNativeDouble(c),
|
||||
new NumberNativeDouble(d)
|
||||
OpaqueNumber(a),
|
||||
OpaqueNumber(b),
|
||||
OpaqueNumber(c),
|
||||
OpaqueNumber(d)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -517,7 +516,7 @@ ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::wrap_in_compoun
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::OpenCascadeShape::vertices()
|
||||
{
|
||||
TopTools_IndexedMapOfShape map;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapes(shape_, TopAbs_VERTEX, map);
|
||||
std::vector<ConversionResultShape*> vec;
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
@@ -528,7 +527,7 @@ std::vector<ConversionResultShape*> ifcopenshell::geometry::OpenCascadeShape::ve
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::OpenCascadeShape::edges()
|
||||
{
|
||||
TopTools_IndexedMapOfShape map;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapes(shape_, TopAbs_EDGE, map);
|
||||
std::vector<ConversionResultShape*> vec;
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
@@ -539,7 +538,7 @@ std::vector<ConversionResultShape*> ifcopenshell::geometry::OpenCascadeShape::ed
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::OpenCascadeShape::facets()
|
||||
{
|
||||
TopTools_IndexedMapOfShape map;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapes(shape_, TopAbs_FACE, map);
|
||||
std::vector<ConversionResultShape*> vec;
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
@@ -641,7 +640,7 @@ namespace {
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, tol);
|
||||
} catch (...) {
|
||||
logger::message(logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 186, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
meshed = true;
|
||||
@@ -657,7 +656,7 @@ namespace {
|
||||
coords.push_back(tri->Node(i).Transformed(loc).XYZ());
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
const NCollection_Array1<Poly_Triangle>& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
|
||||
@@ -718,10 +717,10 @@ bool ifcopenshell::geometry::OpenCascadeShape::surface_area_along_direction(doub
|
||||
return true;
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::OpenCascadeShape::map(OpaqueCoordinate<4>&, OpaqueCoordinate<4>&) {
|
||||
std::size_t ifcopenshell::geometry::OpenCascadeShape::map(OpaqueCoordinate<4>&, OpaqueCoordinate<4>&) {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::OpenCascadeShape::map(const std::vector<OpaqueCoordinate<4>>&, const std::vector<OpaqueCoordinate<4>>&) {
|
||||
std::size_t ifcopenshell::geometry::OpenCascadeShape::map(const std::vector<OpaqueCoordinate<4>>&, const std::vector<OpaqueCoordinate<4>>&) {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
@@ -45,14 +42,18 @@ namespace ifcopenshell {
|
||||
|
||||
class IFC_GEOMLIBRARY_API OpenCascadeShape : public IfcGeom::ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape);
|
||||
OpenCascadeShape(TopoDS_Shape&& shape);
|
||||
std::string type() const override { return "OpenCascadeShape"; }
|
||||
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape) {}
|
||||
OpenCascadeShape(TopoDS_Shape&& shape)
|
||||
: shape_(std::move(shape)) {}
|
||||
|
||||
const TopoDS_Shape& shape() const;
|
||||
operator const TopoDS_Shape& ();
|
||||
virtual std::string_view backend_id() const;
|
||||
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id, Logger& logger = Logger::Root()) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
|
||||
|
||||
virtual IfcGeom::ConversionResultShape* clone() const;
|
||||
@@ -75,9 +76,9 @@ namespace ifcopenshell {
|
||||
// @todo this must be something with a virtual dtor so that we can delete it.
|
||||
virtual std::pair<OpaqueCoordinate<3>, OpaqueCoordinate<3>> bounding_box() const;
|
||||
|
||||
virtual OpaqueNumber* length();
|
||||
virtual OpaqueNumber* area();
|
||||
virtual OpaqueNumber* volume();
|
||||
virtual OpaqueNumber length();
|
||||
virtual OpaqueNumber area();
|
||||
virtual OpaqueNumber volume();
|
||||
|
||||
virtual OpaqueCoordinate<3> position();
|
||||
virtual OpaqueCoordinate<3> axis();
|
||||
@@ -98,8 +99,8 @@ namespace ifcopenshell {
|
||||
virtual ConversionResultShape* intersect(ConversionResultShape*);
|
||||
virtual ConversionResultShape* concat(ConversionResultShape*);
|
||||
|
||||
virtual void map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to);
|
||||
virtual void map(const std::vector<OpaqueCoordinate<4>>& from, const std::vector<OpaqueCoordinate<4>>& to);
|
||||
virtual std::size_t map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to);
|
||||
virtual std::size_t map(const std::vector<OpaqueCoordinate<4>>& from, const std::vector<OpaqueCoordinate<4>>& to);
|
||||
virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const;
|
||||
|
||||
virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const;
|
||||
|
||||
@@ -120,7 +120,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const express::Base& entity, c
|
||||
|
||||
auto it3_shape = std::static_pointer_cast<OpenCascadeShape>(it3->Shape())->shape();
|
||||
if (it3_shape.IsNull()) {
|
||||
logger::error("Null operand");
|
||||
logger_.Error("GEO", 187, "Null operand");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -140,42 +140,40 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const express::Base& entity, c
|
||||
|
||||
if (!is_manifold) {
|
||||
// force sewing, edge identity might have been mudied by FixAdvFace.FixOrientation.MSG5 to fix interior loop winding order
|
||||
TopTools_ListOfShape list;
|
||||
IfcGeom::util::shape_to_face_list(entity_part, list);
|
||||
IfcGeom::util::create_solid_from_faces(list, entity_part, settings_.get<settings::Precision>().get(), true);
|
||||
is_manifold = util::is_manifold(entity_part);
|
||||
if (is_manifold) {
|
||||
logger::warning("Successfully sewed non-manifold first operand", entity);
|
||||
}
|
||||
NCollection_List<TopoDS_Shape> list;
|
||||
IfcGeom::util::shape_to_face_list(entity_part, list);
|
||||
IfcGeom::util::create_solid_from_faces(list, entity_part, settings_.get<settings::Precision>().get(), true);
|
||||
is_manifold = util::is_manifold(entity_part);
|
||||
if (is_manifold) {
|
||||
logger_.Warning("GEO", 188, "Successfully sewed non-manifold first operand");
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_manifold) {
|
||||
if (settings_.get<settings::MakeVolume>().get()) {
|
||||
BOPAlgo_MakerVolume mv;
|
||||
mv.AddArgument(entity_part);
|
||||
mv.SetAvoidInternalShapes(true);
|
||||
// mv.SetFuzzyValue(settings_.get<settings::Precision>().get());
|
||||
std::optional<std::string> failure;
|
||||
try {
|
||||
mv.Perform();
|
||||
auto entity_part_2 = mv.Shape();
|
||||
if (mv.HasErrors()) {
|
||||
failure = "BOPAlgo_MakerVolume reported errors";
|
||||
} else if (IfcGeom::util::count(entity_part_2, TopAbs_FACE) == 0) {
|
||||
failure = "Empty result (no faces) for BOPAlgo_MakerVolume; original was " + std::to_string(IfcGeom::util::count(entity_part, TopAbs_FACE));
|
||||
if (settings_.get<settings::MakeVolume>().get()) {
|
||||
BOPAlgo_MakerVolume mv;
|
||||
mv.AddArgument(entity_part);
|
||||
mv.SetAvoidInternalShapes(true);
|
||||
// mv.SetFuzzyValue(settings_.get<settings::Precision>().get());
|
||||
std::optional<std::string> failure;
|
||||
try {
|
||||
mv.Perform();
|
||||
auto entity_part_2 = mv.Shape();
|
||||
if (IfcGeom::util::count(entity_part_2, TopAbs_FACE) == 0) {
|
||||
failure = "Empty result (no faces) for BOPAlgo_MakerVolume; original was " + std::to_string(IfcGeom::util::count(entity_part, TopAbs_FACE));
|
||||
} else {
|
||||
is_manifold = util::is_manifold(entity_part_2);
|
||||
logger::warning(std::string("Successfully detected exterior volume to non-manifold first operand; shape is now ") + (is_manifold ? std::string("manifold") : std::string("non-manifold")), entity);
|
||||
entity_part = entity_part_2;
|
||||
is_manifold = util::is_manifold(entity_part_2);
|
||||
logger_.Warning("GEO", 189, std::string("Sucessfully detected exterior volume to non-manifold first operand; shape is now ") + (is_manifold ? std::string("manifold") : std::string("non-manifold")));
|
||||
entity_part = entity_part_2;
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
failure.emplace(e.GetMessageString());
|
||||
}
|
||||
if (failure) {
|
||||
logger::warning("MakeVolume failed: " + *failure, entity);
|
||||
}
|
||||
} else {
|
||||
logger::warning("Non-manifold first operand, use --make-volume to try and make manifold", entity);
|
||||
} catch (const Standard_Failure& e) {
|
||||
failure.emplace(e.GetMessageString());
|
||||
}
|
||||
if (failure) {
|
||||
logger_.Warning("GEO", 190, "MakeVolume failed: " + *failure, entity);
|
||||
}
|
||||
} else {
|
||||
logger_.Warning("GEO", 191, "Non-manifold first operand, use --make-volume to try and make manifold");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +207,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const express::Base& entity, c
|
||||
for (;; ++it) {
|
||||
if (it == opening_vector.end() || jt->first / it->first > 10.) {
|
||||
|
||||
TopTools_ListOfShape opening_list;
|
||||
NCollection_List<TopoDS_Shape> opening_list;
|
||||
for (auto kt = jt; kt < it; ++kt) {
|
||||
opening_list.Append(kt->second);
|
||||
}
|
||||
@@ -218,7 +216,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const express::Base& entity, c
|
||||
if (util::boolean_operation(bst, result, opening_list, BOPAlgo_CUT, intermediate_result)) {
|
||||
result = intermediate_result;
|
||||
} else {
|
||||
logger::message(logger::LOG_ERROR, "Opening subtraction failed for " + boost::lexical_cast<std::string>(std::distance(jt, it)) + " openings", entity);
|
||||
logger_.Message(Logger::LOG_ERROR, "GEO", 192, "Opening subtraction failed for " + boost::lexical_cast<std::string>(std::distance(jt, it)) + " openings", entity);
|
||||
}
|
||||
|
||||
jt = it;
|
||||
@@ -239,7 +237,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const express::Base& entity, c
|
||||
// where we keep the first operand as is (a compound of faces probably,
|
||||
// unless --orient-shells was activated in which case we're already lost).
|
||||
if (!is_manifold) {
|
||||
logger::warning("Retrying boolean operation on individual faces");
|
||||
logger_.Warning("GEO", 193, "Retrying boolean operation on individual faces");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
@@ -105,21 +103,21 @@ private:
|
||||
bool edge(int A, int B, TopoDS_Edge& e);
|
||||
|
||||
bool wire(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopoDS_Wire& wire);
|
||||
bool wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopTools_ListOfShape& wires);
|
||||
bool wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, NCollection_List<TopoDS_Shape>& wires);
|
||||
};
|
||||
|
||||
faceset_helper* faceset_helper_;
|
||||
|
||||
double precision_;
|
||||
public:
|
||||
OpenCascadeKernel(const ifcopenshell::geometry::Settings& settings)
|
||||
: AbstractKernel("opencascade", settings)
|
||||
OpenCascadeKernel(const ifcopenshell::geometry::Settings& settings, Logger& logger = Logger::Root())
|
||||
: AbstractKernel("opencascade", settings, logger)
|
||||
, faceset_helper_(nullptr)
|
||||
, precision_(settings.get<ifcopenshell::geometry::settings::Precision>().get())
|
||||
{}
|
||||
|
||||
virtual AbstractKernel* clone() const {
|
||||
return new OpenCascadeKernel(settings());
|
||||
virtual AbstractKernel* clone(Logger& logger) const {
|
||||
return new OpenCascadeKernel(settings(), logger);
|
||||
}
|
||||
|
||||
virtual bool supports_boolean_operations() const { return true; }
|
||||
|
||||
@@ -48,7 +48,9 @@
|
||||
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <NCollection_IndexedMap.hxx>
|
||||
|
||||
#include <ShapeUpgrade_UnifySameDomain.hxx>
|
||||
|
||||
@@ -73,7 +75,7 @@ bool IfcGeom::util::axis_equal(const gp_Ax2d & a, const gp_Ax2d & b, double tole
|
||||
|
||||
int IfcGeom::util::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) {
|
||||
if (unique) {
|
||||
TopTools_IndexedMapOfShape map;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapes(s, t, map);
|
||||
return map.Extent();
|
||||
} else {
|
||||
@@ -108,7 +110,7 @@ bool IfcGeom::util::is_manifold(const TopoDS_Shape& a) {
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map);
|
||||
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
@@ -199,17 +201,17 @@ gp_Trsf IfcGeom::util::combine_offset_and_rotation(const gp_Vec & offset, const
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::project(const Handle_Geom_Surface& srf, const TopoDS_Shape& shp, double& u1, double& v1, double& u2, double& v2, double widen) {
|
||||
bool IfcGeom::util::project(const opencascade::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;
|
||||
opencascade::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)) {
|
||||
pln = opencascade::handle<Geom_Plane>::DownCast(srf);
|
||||
} else if (srf->DynamicType() == STANDARD_TYPE(Geom_OffsetSurface) && opencascade::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());
|
||||
pln = opencascade::handle<Geom_Plane>::DownCast(opencascade::handle<Geom_OffsetSurface>::DownCast(srf)->BasisSurface());
|
||||
} else {
|
||||
sas = new ShapeAnalysis_Surface(srf);
|
||||
}
|
||||
@@ -246,7 +248,7 @@ bool IfcGeom::util::project(const Handle_Geom_Surface& srf, const TopoDS_Shape&
|
||||
const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
|
||||
|
||||
double a, b;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, a, b);
|
||||
gp_Pnt p;
|
||||
crv->D0((a + b) / 2., p);
|
||||
|
||||
@@ -449,24 +451,25 @@ bool IfcGeom::util::fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b,
|
||||
}
|
||||
|
||||
|
||||
const Handle_Geom_Curve IfcGeom::util::intersect(const Handle_Geom_Surface& a, const Handle_Geom_Surface& b) {
|
||||
const opencascade::handle<Geom_Curve> IfcGeom::util::intersect(const opencascade::handle<Geom_Surface>& a, const opencascade::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();
|
||||
return opencascade::handle<Geom_Curve>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const Handle_Geom_Curve IfcGeom::util::intersect(const Handle_Geom_Surface& a, const TopoDS_Face& b) {
|
||||
const opencascade::handle<Geom_Curve> IfcGeom::util::intersect(const opencascade::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) {
|
||||
const opencascade::handle<Geom_Curve> IfcGeom::util::intersect(const TopoDS_Face& a, const opencascade::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) {
|
||||
bool IfcGeom::util::intersect(const opencascade::handle<Geom_Curve>& a, const opencascade::handle<Geom_Surface>& b, gp_Pnt& p) {
|
||||
GeomAPI_IntCS x(a, b);
|
||||
if (x.IsDone() && x.NbPoints() == 1) {
|
||||
p = x.Point(1);
|
||||
@@ -476,11 +479,11 @@ bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const Handle_Geom_Surf
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const TopoDS_Face& b, gp_Pnt &c) {
|
||||
bool IfcGeom::util::intersect(const opencascade::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) {
|
||||
bool IfcGeom::util::intersect(const opencascade::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()) {
|
||||
@@ -491,12 +494,12 @@ bool IfcGeom::util::intersect(const Handle_Geom_Curve& a, const TopoDS_Shape& b,
|
||||
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) {
|
||||
bool IfcGeom::util::intersect(const opencascade::handle<Geom_Surface>& a, const TopoDS_Shape& b, std::vector< std::pair<opencascade::handle<Geom_Surface>, opencascade::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);
|
||||
const opencascade::handle<Geom_Surface>& s = BRep_Tool::Surface(f);
|
||||
opencascade::handle<Geom_Curve> crv = intersect(a, s);
|
||||
if (!crv.IsNull()) {
|
||||
out.push_back(std::make_pair(s, crv));
|
||||
}
|
||||
@@ -516,7 +519,7 @@ bool IfcGeom::util::closest(const gp_Pnt& a, const std::vector<gp_Pnt>& b, gp_Pn
|
||||
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) {
|
||||
bool IfcGeom::util::project(const opencascade::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);
|
||||
@@ -589,10 +592,10 @@ TopoDS_Shape IfcGeom::util::halfspace_from_plane(const gp_Pln& pln, const gp_Pnt
|
||||
|
||||
gp_Pln IfcGeom::util::plane_from_face(const TopoDS_Face& face) {
|
||||
BRepGProp_Face prop(face);
|
||||
Standard_Real u1, u2, v1, v2;
|
||||
double u1, u2, v1, v2;
|
||||
prop.Bounds(u1, u2, v1, v2);
|
||||
Standard_Real u = (u1 + u2) / 2.0;
|
||||
Standard_Real v = (v1 + v2) / 2.0;
|
||||
double u = (u1 + u2) / 2.0;
|
||||
double v = (v1 + v2) / 2.0;
|
||||
gp_Pnt p;
|
||||
gp_Vec n;
|
||||
prop.Normal(u, v, p, n);
|
||||
@@ -615,7 +618,7 @@ bool IfcGeom::util::is_compound_of_faces(const TopoDS_Shape& shape) {
|
||||
return has_compounds && has_faces && !has_solids && !has_shells;
|
||||
}
|
||||
|
||||
bool IfcGeom::util::shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li) {
|
||||
bool IfcGeom::util::shape_to_face_list(const TopoDS_Shape& s, NCollection_List<TopoDS_Shape>& li) {
|
||||
TopExp_Explorer exp(s, TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
@@ -625,7 +628,7 @@ bool IfcGeom::util::shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfSha
|
||||
}
|
||||
|
||||
bool IfcGeom::util::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape, double tol) {
|
||||
TopTools_ListOfShape face_list;
|
||||
NCollection_List<TopoDS_Shape> face_list;
|
||||
shape_to_face_list(compound, face_list);
|
||||
if (face_list.Extent() == 0) {
|
||||
return false;
|
||||
@@ -633,7 +636,7 @@ bool IfcGeom::util::create_solid_from_compound(const TopoDS_Shape& compound, Top
|
||||
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 IfcGeom::util::create_solid_from_faces(const NCollection_List<TopoDS_Shape>& face_list, TopoDS_Shape& shape, double tol, bool force_sewing) {
|
||||
bool valid_shell = false;
|
||||
|
||||
if (face_list.Extent() == 1) {
|
||||
@@ -644,10 +647,10 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
return false;
|
||||
}
|
||||
|
||||
TopTools_ListIteratorOfListOfShape face_iterator;
|
||||
NCollection_List<TopoDS_Shape>::Iterator face_iterator;
|
||||
|
||||
bool has_shared_edges = false;
|
||||
TopTools_MapOfShape edge_set;
|
||||
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> edge_set;
|
||||
|
||||
// In case there are wire intersections or failures in non-planar wire triangulations
|
||||
// the idea is to let occt do an exhaustive search of edge partners. But we have not
|
||||
@@ -711,12 +714,12 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
valid_shell &= util::count(shape, TopAbs_SHELL) > 0;
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
Logger::Root().Error("GEO", 106, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error sewing shell");
|
||||
Logger::Root().Error("GEO", 107, "Unknown error sewing shell");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error sewing shell");
|
||||
Logger::Root().Error("GEO", 108, "Unknown error sewing shell");
|
||||
}
|
||||
|
||||
if (valid_shell) {
|
||||
@@ -744,22 +747,22 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
Logger::Root().Error("GEO", 109, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error classifying solid");
|
||||
Logger::Root().Error("GEO", 110, "Unknown error classifying solid");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error classifying solid");
|
||||
Logger::Root().Error("GEO", 111, "Unknown error classifying solid");
|
||||
}
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
Logger::Root().Error("GEO", 112, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error creating solid");
|
||||
Logger::Root().Error("GEO", 113, "Unknown error creating solid");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error creating solid");
|
||||
Logger::Root().Error("GEO", 114, "Unknown error creating solid");
|
||||
}
|
||||
|
||||
if (complete_shape.IsNull()) {
|
||||
@@ -771,7 +774,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
B.MakeCompound(C);
|
||||
B.Add(C, complete_shape);
|
||||
complete_shape = C;
|
||||
logger::warning("Multiple components in IfcConnectedFaceSet");
|
||||
Logger::Root().Warning("GEO", 115, "Multiple components in IfcConnectedFaceSet");
|
||||
}
|
||||
B.Add(complete_shape, result_shape);
|
||||
}
|
||||
@@ -786,7 +789,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
B.MakeCompound(C);
|
||||
B.Add(C, complete_shape);
|
||||
complete_shape = C;
|
||||
logger::warning("Loose faces in IfcConnectedFaceSet");
|
||||
Logger::Root().Warning("GEO", 116, "Loose faces in IfcConnectedFaceSet");
|
||||
}
|
||||
B.Add(complete_shape, loose_faces.Current());
|
||||
}
|
||||
@@ -794,7 +797,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
shape = complete_shape;
|
||||
|
||||
} else {
|
||||
logger::error("Failed to sew faceset");
|
||||
Logger::Root().Error("GEO", 117, "Failed to sew faceset");
|
||||
}
|
||||
|
||||
return valid_shell;
|
||||
@@ -875,7 +878,7 @@ bool IfcGeom::util::validate_shape(const TopoDS_Shape& s) {
|
||||
std::function<void(const TopoDS_Shape&)> dump;
|
||||
dump = [&ana, &str, &dump, &any_emitted](const TopoDS_Shape& s) {
|
||||
if (!ana.Result(s).IsNull()) {
|
||||
BRepCheck_ListIteratorOfListOfStatus itl;
|
||||
NCollection_List<BRepCheck_Status>::Iterator itl;
|
||||
itl.Initialize(ana.Result(s)->Status());
|
||||
for (; itl.More(); itl.Next()) {
|
||||
if (itl.Value() != BRepCheck_NoError) {
|
||||
@@ -898,7 +901,7 @@ bool IfcGeom::util::validate_shape(const TopoDS_Shape& s) {
|
||||
|
||||
dump(s);
|
||||
|
||||
logger::warning(str.str());
|
||||
Logger::Root().Warning("GEO", 118, str.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
@@ -49,8 +51,8 @@ namespace IfcGeom {
|
||||
// Creates a solid from a compound of faces. When there are multiple connected components,
|
||||
// a compound of solids is returned.
|
||||
IFC_GEOMLIBRARY_API bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid, double tol);
|
||||
IFC_GEOMLIBRARY_API bool shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li);
|
||||
IFC_GEOMLIBRARY_API bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid, double tol, bool force_sewing = false);
|
||||
IFC_GEOMLIBRARY_API bool shape_to_face_list(const TopoDS_Shape& s, NCollection_List<TopoDS_Shape>& li);
|
||||
IFC_GEOMLIBRARY_API bool create_solid_from_faces(const NCollection_List<TopoDS_Shape>& face_list, TopoDS_Shape& solid, double tol, bool force_sewing = false);
|
||||
IFC_GEOMLIBRARY_API bool is_compound_of_faces(const TopoDS_Shape& shape);
|
||||
IFC_GEOMLIBRARY_API bool is_convex(const TopoDS_Wire& wire, double tol);
|
||||
IFC_GEOMLIBRARY_API TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent);
|
||||
@@ -58,16 +60,16 @@ namespace IfcGeom {
|
||||
IFC_GEOMLIBRARY_API gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height, double tol);
|
||||
IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
|
||||
IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
|
||||
IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
|
||||
IFC_GEOMLIBRARY_API const opencascade::handle<Geom_Curve> intersect(const opencascade::handle<Geom_Surface>&, const opencascade::handle<Geom_Surface>&);
|
||||
IFC_GEOMLIBRARY_API const opencascade::handle<Geom_Curve> intersect(const opencascade::handle<Geom_Surface>&, const TopoDS_Face&);
|
||||
IFC_GEOMLIBRARY_API const opencascade::handle<Geom_Curve> intersect(const TopoDS_Face&, const opencascade::handle<Geom_Surface>&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const opencascade::handle<Geom_Curve>&, const opencascade::handle<Geom_Surface>&, gp_Pnt&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const opencascade::handle<Geom_Curve>&, const TopoDS_Face&, gp_Pnt&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const opencascade::handle<Geom_Curve>&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
IFC_GEOMLIBRARY_API bool intersect(const opencascade::handle<Geom_Surface>&, const TopoDS_Shape&, std::vector< std::pair<opencascade::handle<Geom_Surface>, opencascade::handle<Geom_Curve> > >&);
|
||||
IFC_GEOMLIBRARY_API bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
|
||||
IFC_GEOMLIBRARY_API bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
IFC_GEOMLIBRARY_API bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1);
|
||||
IFC_GEOMLIBRARY_API bool project(const opencascade::handle<Geom_Curve>&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
IFC_GEOMLIBRARY_API bool project(const opencascade::handle<Geom_Surface>&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1);
|
||||
|
||||
IFC_GEOMLIBRARY_API double shape_volume(const TopoDS_Shape& s);
|
||||
IFC_GEOMLIBRARY_API double face_area(const TopoDS_Face& f);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace {
|
||||
for (;; ++it) {
|
||||
if (it == opening_vector.end() || jt->first / it->first > 10.) {
|
||||
|
||||
TopTools_ListOfShape opening_list;
|
||||
NCollection_List<TopoDS_Shape> opening_list;
|
||||
for (auto kt = jt; kt < it; ++kt) {
|
||||
opening_list.Append(kt->second);
|
||||
}
|
||||
@@ -90,7 +90,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
const double tol = settings_.get<settings::Precision>().get();
|
||||
|
||||
TopoDS_Shape a;
|
||||
TopTools_ListOfShape b;
|
||||
NCollection_List<TopoDS_Shape> b;
|
||||
|
||||
taxonomy::style::ptr first_item_style;
|
||||
|
||||
@@ -118,14 +118,14 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
|
||||
const double first_operand_volume = util::shape_volume(a);
|
||||
if (first_operand_volume <= ALMOST_ZERO) {
|
||||
logger::message(logger::LOG_WARNING, "Empty solid for:", c->instance);
|
||||
Logger::Root().Message(Logger::LOG_WARNING, "GEO", 119, "Empty solid for:", c->instance);
|
||||
}
|
||||
} else {
|
||||
|
||||
for (auto& r : cr) {
|
||||
auto S = std::static_pointer_cast<OpenCascadeShape>(r.Shape())->shape();
|
||||
if (S.IsNull()) {
|
||||
logger::error("Null operand");
|
||||
Logger::Root().Error("GEO", 120, "Null operand");
|
||||
continue;
|
||||
}
|
||||
gp_GTrsf trsf;
|
||||
@@ -140,7 +140,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
// #2665 we also set a precision-independent threshold, because in the boolean op routine
|
||||
// the working fuzziness might still be increased.
|
||||
if (d < tol * 20. || d < 0.00002) {
|
||||
logger::message(logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", c->instance);
|
||||
Logger::Root().Message(Logger::LOG_WARNING, "GEO", 121, "Halfspace subtraction yields unchanged volume:", c->instance);
|
||||
continue;
|
||||
} else {
|
||||
S = result;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <BOPAlgo_Alerts.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepCheck_ListIteratorOfListOfStatus.hxx>
|
||||
#include <BRepCheck.hxx>
|
||||
#include <ShapeAnalysis_Edge.hxx>
|
||||
#include <Bnd_OBB.hxx>
|
||||
@@ -31,7 +30,7 @@
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
void IfcGeom::util::copy_operand(const TopTools_ListOfShape & l, TopTools_ListOfShape & r) {
|
||||
void IfcGeom::util::copy_operand(const NCollection_List<TopoDS_Shape>& l, NCollection_List<TopoDS_Shape>& r) {
|
||||
#if OCC_VERSION_HEX < 0x70000
|
||||
r.Clear();
|
||||
TopTools_ListIteratorOfListOfShape it(l);
|
||||
@@ -81,7 +80,7 @@ double IfcGeom::util::min_edge_length(const TopoDS_Shape & a) {
|
||||
double IfcGeom::util::min_vertex_edge_distance(const TopoDS_Shape & a, double min_search, double max_search) {
|
||||
double M = std::numeric_limits<double>::infinity();
|
||||
|
||||
TopTools_IndexedMapOfShape vertices, edges;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> vertices, edges;
|
||||
|
||||
TopExp::MapShapes(a, TopAbs_VERTEX, vertices);
|
||||
TopExp::MapShapes(a, TopAbs_EDGE, edges);
|
||||
@@ -161,7 +160,7 @@ double IfcGeom::util::min_face_face_distance(const TopoDS_Shape & a, double max_
|
||||
*/
|
||||
double M = std::numeric_limits<double>::infinity();
|
||||
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> faces;
|
||||
|
||||
TopExp::MapShapes(a, TopAbs_FACE, faces);
|
||||
|
||||
@@ -230,7 +229,7 @@ double IfcGeom::util::min_face_face_distance(const TopoDS_Shape & a, double max_
|
||||
return M;
|
||||
}
|
||||
|
||||
int IfcGeom::util::bounding_box_overlap(double p, const TopoDS_Shape & a, const TopTools_ListOfShape & b, TopTools_ListOfShape & c) {
|
||||
int IfcGeom::util::bounding_box_overlap(double p, const TopoDS_Shape & a, const NCollection_List<TopoDS_Shape> & b, NCollection_List<TopoDS_Shape> & c) {
|
||||
int N = 0;
|
||||
|
||||
Bnd_Box A;
|
||||
@@ -240,7 +239,7 @@ int IfcGeom::util::bounding_box_overlap(double p, const TopoDS_Shape & a, const
|
||||
return 0;
|
||||
}
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b);
|
||||
for (; it.More(); it.Next()) {
|
||||
Bnd_Box B;
|
||||
BRepBndLib::Add(it.Value(), B);
|
||||
@@ -263,8 +262,8 @@ bool IfcGeom::util::get_edge_axis(const TopoDS_Edge & e, gp_Ax1 & ax) {
|
||||
double _, __;
|
||||
|
||||
auto crv = BRep_Tool::Curve(e, _, __);
|
||||
auto line = Handle_Geom_Line::DownCast(crv);
|
||||
auto bsple = Handle_Geom_BSplineCurve::DownCast(crv);
|
||||
auto line = opencascade::handle<Geom_Line>::DownCast(crv);
|
||||
auto bsple = opencascade::handle<Geom_BSplineCurve>::DownCast(crv);
|
||||
|
||||
if (line) {
|
||||
ax = line->Position();
|
||||
@@ -280,7 +279,7 @@ bool IfcGeom::util::get_edge_axis(const TopoDS_Edge & e, gp_Ax1 & ax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::util::is_subset(const TopTools_IndexedMapOfShape & lhs, const TopTools_IndexedMapOfShape & rhs) {
|
||||
bool IfcGeom::util::is_subset(const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& lhs, const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& rhs) {
|
||||
if (rhs.Extent() < lhs.Extent()) {
|
||||
return false;
|
||||
}
|
||||
@@ -297,12 +296,12 @@ bool IfcGeom::util::is_extrusion(const gp_Vec & v, const TopoDS_Shape & s, TopoD
|
||||
// This assumes UnifySameDomain has been processed on s, so that
|
||||
// the extrusion top and bottom are a single face.
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape mapping;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> mapping;
|
||||
TopExp::MapShapesAndAncestors(s, TopAbs_EDGE, TopAbs_FACE, mapping);
|
||||
TopExp::MapShapesAndAncestors(s, TopAbs_VERTEX, TopAbs_FACE, mapping);
|
||||
|
||||
TopTools_ListOfShape parallel;
|
||||
TopTools_IndexedMapOfShape curved_orthogonal;
|
||||
NCollection_List<TopoDS_Shape> parallel;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> curved_orthogonal;
|
||||
gp_Ax1 ax;
|
||||
gp_Ax1 V(gp::Origin(), v);
|
||||
|
||||
@@ -333,9 +332,9 @@ bool IfcGeom::util::is_extrusion(const gp_Vec & v, const TopoDS_Shape & s, TopoD
|
||||
|
||||
// Select the two faces for which their edges are subsets
|
||||
// of the ortho/curved edges
|
||||
TopTools_IndexedMapOfShape ortho_faces;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> ortho_faces;
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
TopTools_IndexedMapOfShape face_edges;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> face_edges;
|
||||
TopExp::MapShapes(exp.Current(), TopAbs_EDGE, face_edges);
|
||||
if (is_subset(face_edges, curved_orthogonal)) {
|
||||
ortho_faces.Add(exp.Current());
|
||||
@@ -349,18 +348,18 @@ bool IfcGeom::util::is_extrusion(const gp_Vec & v, const TopoDS_Shape & s, TopoD
|
||||
|
||||
// For the parallel edges assert that its two vertices are part
|
||||
// of both the basis and the top face.
|
||||
for (TopTools_ListIteratorOfListOfShape it(parallel);
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(parallel);
|
||||
it.More(); it.Next()) {
|
||||
TopoDS_Vertex v01[2];
|
||||
TopExp::Vertices(TopoDS::Edge(it.Value()), v01[0], v01[1]);
|
||||
|
||||
TopTools_IndexedMapOfShape v_ortho_faces;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> v_ortho_faces;
|
||||
int nb_ortho_faces[2] = { 0,0 };
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto& faces = mapping.FindFromKey(v01[i]);
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape jt(faces);
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator jt(faces);
|
||||
jt.More(); jt.Next()) {
|
||||
if (ortho_faces.Contains(jt.Value())) {
|
||||
nb_ortho_faces[i] ++;
|
||||
@@ -406,9 +405,9 @@ bool IfcGeom::util::is_extrusion(const gp_Vec & v, const TopoDS_Shape & s, TopoD
|
||||
return true;
|
||||
}
|
||||
|
||||
int IfcGeom::util::eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c) {
|
||||
int IfcGeom::util::eliminate_narrow_operands(double prec, const NCollection_List<TopoDS_Shape>& bs, NCollection_List<TopoDS_Shape> & c) {
|
||||
int N = 0;
|
||||
TopTools_ListIteratorOfListOfShape it(bs);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(bs);
|
||||
for (; it.More(); it.Next()) {
|
||||
|
||||
Bnd_OBB box;
|
||||
@@ -419,7 +418,7 @@ int IfcGeom::util::eliminate_narrow_operands(double prec, const TopTools_ListOfS
|
||||
|
||||
bool is_narrow = min_dimension < prec;
|
||||
|
||||
logger::notice("Min OBB dimension of operand = " + std::to_string(min_dimension));
|
||||
Logger::Root().Notice("GEO", 122, "Min OBB dimension of operand = " + std::to_string(min_dimension));
|
||||
|
||||
if (!is_narrow) {
|
||||
c.Append(it.Value());
|
||||
@@ -430,8 +429,8 @@ int IfcGeom::util::eliminate_narrow_operands(double prec, const TopTools_ListOfS
|
||||
return N;
|
||||
}
|
||||
|
||||
int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape & a, const TopTools_ListOfShape & bs, TopTools_ListOfShape & c) {
|
||||
TopTools_IndexedMapOfShape a_faces;
|
||||
int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape & a, const NCollection_List<TopoDS_Shape> & bs, NCollection_List<TopoDS_Shape> & c) {
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> a_faces;
|
||||
TopExp::MapShapes(a, TopAbs_FACE, a_faces);
|
||||
|
||||
// Check if any of the faces in a are non-planar, which is
|
||||
@@ -443,7 +442,7 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_IndexedMapOfShape a_vertices;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> a_vertices;
|
||||
TopExp::MapShapes(a, TopAbs_VERTEX, a_vertices);
|
||||
|
||||
IfcGeom::impl::tree<int> tree;
|
||||
@@ -455,13 +454,13 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
|
||||
int N = 0;
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(bs);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(bs);
|
||||
for (; it.More(); it.Next()) {
|
||||
bool is_touching = false;
|
||||
|
||||
auto& b = it.Value();
|
||||
|
||||
TopTools_IndexedMapOfShape b_faces;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> b_faces;
|
||||
TopExp::MapShapes(b, TopAbs_FACE, b_faces);
|
||||
|
||||
// Check if any of the faces in b are non-planar, which is
|
||||
@@ -479,7 +478,7 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
continue;
|
||||
}
|
||||
|
||||
TopTools_IndexedMapOfShape b_vertices;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> b_vertices;
|
||||
TopExp::MapShapes(b, TopAbs_VERTEX, b_vertices);
|
||||
|
||||
for (int k = 1; k <= b_faces.Extent(); ++k) {
|
||||
@@ -491,7 +490,7 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
for (auto& i : tree.select_box(B, false)) {
|
||||
const TopoDS_Face& f_a = TopoDS::Face(a_faces(i));
|
||||
|
||||
TopTools_IndexedMapOfShape f_a_vertices;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> f_a_vertices;
|
||||
TopExp::MapShapes(f_a, TopAbs_VERTEX, f_a_vertices);
|
||||
|
||||
BRepGProp_Face prop_a(f_a);
|
||||
@@ -532,7 +531,7 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
// Check if faces are co-planar
|
||||
if (std::abs((p_b.XYZ() - p_a.XYZ()).Dot(v_a.XYZ())) <= prec) {
|
||||
|
||||
TopTools_IndexedMapOfShape f_b_vertices;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> f_b_vertices;
|
||||
TopExp::MapShapes(f_b, TopAbs_VERTEX, f_b_vertices);
|
||||
|
||||
bool all_vertices_behind_f_b = true;
|
||||
@@ -574,13 +573,13 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape &
|
||||
return N;
|
||||
}
|
||||
|
||||
bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_input, const TopTools_ListOfShape & b_input, TopoDS_Shape & result, double eps) {
|
||||
bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_input, const NCollection_List<TopoDS_Shape> & b_input, TopoDS_Shape & result, double eps) {
|
||||
IfcGeom::impl::tree<int> edge_tree;
|
||||
|
||||
TopTools_ListOfShape ab_input = b_input;
|
||||
NCollection_List<TopoDS_Shape> ab_input = b_input;
|
||||
ab_input.Prepend(a_input);
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(ab_input);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(ab_input);
|
||||
int shape_index = 0;
|
||||
int edge_index = 0;
|
||||
std::map<int, int> edge_index_to_shape_index;
|
||||
@@ -679,10 +678,10 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
// to see whether inside tolerance. Current DY is hardcoded. The sensible default
|
||||
// for walls.
|
||||
gp_Vec vec(p1, p2);
|
||||
Standard_Real d = vec.Dot(gp::DY());
|
||||
double d = vec.Dot(gp::DY());
|
||||
gp_Vec projected = d * gp::DY();
|
||||
gp_Vec ortho_remainder = vec - projected;
|
||||
Standard_Real ortho_distance = ortho_remainder.Magnitude();
|
||||
double ortho_distance = ortho_remainder.Magnitude();
|
||||
|
||||
const bool unbounded_intersects = ortho_distance < eps;
|
||||
if (unbounded_intersects) {
|
||||
@@ -704,7 +703,7 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
if (u11 < U1 && U1 < u12 && u21 < U2 && U2 < u22) {
|
||||
// Edge curves belonging to different operands intersect, don't process
|
||||
// using builder.
|
||||
logger::notice("Intersecting boundaries");
|
||||
Logger::Root().Notice("GEO", 123, "Intersecting boundaries");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -722,15 +721,15 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
std::vector<TopoDS_Face> wire_faces;
|
||||
wire_faces.reserve(wires.size());
|
||||
|
||||
std::vector<BRepTopAdaptor_FClass2d> wire_clss;
|
||||
wire_clss.reserve(wires.size());
|
||||
std::vector<std::unique_ptr<BRepTopAdaptor_FClass2d>> wire_clss;
|
||||
wire_clss.reserve(wires.size());
|
||||
|
||||
std::vector<std::unique_ptr<ShapeAnalysis_Surface>> sass;
|
||||
sass.reserve(wires.size());
|
||||
|
||||
for (auto& w : wires) {
|
||||
wire_faces.push_back(BRepBuilderAPI_MakeFace(w).Face());
|
||||
wire_clss.emplace_back(wire_faces.back(), eps);
|
||||
wire_clss.emplace_back(std::make_unique<BRepTopAdaptor_FClass2d>(wire_faces.back(), eps));
|
||||
sass.push_back(std::make_unique<ShapeAnalysis_Surface>(BRep_Tool::Surface(wire_faces.back())));
|
||||
}
|
||||
|
||||
@@ -746,12 +745,12 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
|
||||
auto pnt = BRep_Tool::Pnt(v);
|
||||
auto p2d = sass[0]->ValueOfUV(pnt, eps);
|
||||
if (wire_clss[0].Perform(p2d) != TopAbs_IN) {
|
||||
if (wire_clss[0]->Perform(p2d) != TopAbs_IN) {
|
||||
// A wire is not contained in the outer wire, it's a subtraction without
|
||||
// any effect and marked as redundant. Feeding it to the builder algo
|
||||
// will likely cause problems.
|
||||
redundant[std::distance(wires.begin(), it)] = true;
|
||||
logger::notice("Subtraction operand outside of outer bound");
|
||||
Logger::Root().Notice("GEO", 124, "Subtraction operand outside of outer bound");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,10 +787,10 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
|
||||
auto pnt = BRep_Tool::Pnt(v);
|
||||
auto p2d = sass[wire_index]->ValueOfUV(pnt, eps);
|
||||
if (wire_clss[wire_index].Perform(p2d) == TopAbs_IN) {
|
||||
if (wire_clss[wire_index]->Perform(p2d) == TopAbs_IN) {
|
||||
// A wire is contained within another operand
|
||||
redundant[other_index] = true;
|
||||
logger::notice("Subtraction operand contained in other");
|
||||
Logger::Root().Notice("GEO", 125, "Subtraction operand contained in other");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -833,7 +832,7 @@ bool IfcGeom::util::points_on_planar_face_generator::operator()(gp_Pnt& p) {
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
|
||||
bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const TopoDS_Shape& a_input, const NCollection_List<TopoDS_Shape>& b_input, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
|
||||
using namespace std::string_literals;
|
||||
|
||||
const bool do_unify = true;
|
||||
@@ -849,7 +848,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
std::stringstream ss;
|
||||
ss << "bool-" << std::this_thread::get_id() << "-" << (operation_counter_++);
|
||||
debug_identifier = ss.str();
|
||||
logger::notice("Boolean debug identifier: " + debug_identifier);
|
||||
Logger::Root().Notice("GEO", 126, "Boolean debug identifier: " + debug_identifier);
|
||||
}
|
||||
|
||||
if (fuzziness < 0.) {
|
||||
@@ -878,15 +877,15 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
// @todo, it does seem a bit odd, we first triangulate non-planar faces
|
||||
// to later unify them again. Can we make this a bit more intelligent?
|
||||
TopoDS_Shape a;
|
||||
TopTools_ListOfShape b;
|
||||
NCollection_List<TopoDS_Shape> b;
|
||||
|
||||
if (do_unify) {
|
||||
PERF("boolean operation: unifying operands");
|
||||
|
||||
a = unify(a_input, fuzziness * 1000.);
|
||||
|
||||
logger::message(
|
||||
logger::LOG_DEBUG,
|
||||
Logger::Root().Message(
|
||||
Logger::LOG_DEBUG, "GEO", 127,
|
||||
"Simplified operand A from "s +
|
||||
std::to_string(count(a_input, TopAbs_FACE)) +
|
||||
" to "s +
|
||||
@@ -894,11 +893,11 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
);
|
||||
|
||||
{
|
||||
TopTools_ListIteratorOfListOfShape it(b_input);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b_input);
|
||||
for (; it.More(); it.Next()) {
|
||||
b.Append(unify(it.Value(), fuzziness));
|
||||
logger::message(
|
||||
logger::LOG_DEBUG,
|
||||
Logger::Root().Message(
|
||||
Logger::LOG_DEBUG, "GEO", 128,
|
||||
"Simplified operand B from "s +
|
||||
std::to_string(count(it.Value(), TopAbs_FACE)) +
|
||||
" to "s +
|
||||
@@ -915,7 +914,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
bool success = false;
|
||||
std::unique_ptr<BRepAlgoAPI_BooleanOperation> builder;
|
||||
TopTools_ListOfShape b_tmp;
|
||||
NCollection_List<TopoDS_Shape> b_tmp;
|
||||
|
||||
if (op == BOPAlgo_CUT) {
|
||||
builder.reset(new BRepAlgoAPI_Cut());
|
||||
@@ -925,7 +924,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
auto N = bounding_box_overlap(fuzziness, a, b, b_tmp);
|
||||
if (N) {
|
||||
logger::notice("Eliminated " + std::to_string(N) + " disjoint operands");
|
||||
Logger::Root().Notice("GEO", 129, "Eliminated " + std::to_string(N) + " disjoint operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -936,7 +935,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
b_tmp.Clear();
|
||||
auto N = eliminate_touching_operands(fuzziness, a, b, b_tmp);
|
||||
if (N) {
|
||||
logger::notice("Eliminated " + std::to_string(N) + " touching operands");
|
||||
Logger::Root().Notice("GEO", 130, "Eliminated " + std::to_string(N) + " touching operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -947,7 +946,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
b_tmp.Clear();
|
||||
auto N = eliminate_narrow_operands(fuzziness, b, b_tmp);
|
||||
if (N) {
|
||||
logger::notice("Eliminated " + std::to_string(N) + " narrow operands");
|
||||
Logger::Root().Notice("GEO", 131, "Eliminated " + std::to_string(N) + " narrow operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -961,21 +960,21 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (b.Extent() == 0) {
|
||||
logger::warning("No other operands remaining, using first operand");
|
||||
Logger::Root().Warning("GEO", 132, "No other operands remaining, using first operand");
|
||||
result = a;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_2d && logger::LOG_NOTICE >= logger::verbosity()) {
|
||||
if (!is_2d && Logger::LOG_NOTICE >= Logger::Root().Verbosity()) {
|
||||
PERF("preliminary manifoldness check");
|
||||
|
||||
if (!a.IsNull()) {
|
||||
logger::notice("Operand A is " + (is_manifold(a) ? ""s : "non-"s) + "manifold");
|
||||
Logger::Root().Notice("GEO", 133, "Operand A is " + (is_manifold(a) ? ""s : "non-"s) + "manifold");
|
||||
}
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b);
|
||||
for (int i = 0; it.More(); it.Next(), ++i) {
|
||||
logger::notice("Operand B " + std::to_string(i) + " is " + (is_manifold(it.Value()) ? ""s : "non-"s) + "manifold");
|
||||
Logger::Root().Notice("GEO", 134, "Operand B " + std::to_string(i) + " is " + (is_manifold(it.Value()) ? ""s : "non-"s) + "manifold");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -987,7 +986,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
PERF("boolean operation: min edge length");
|
||||
|
||||
min_length_orig = min_edge_length(a);
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b);
|
||||
for (; it.More(); it.Next()) {
|
||||
double d = min_edge_length(it.Value());
|
||||
if (d < min_length_orig) {
|
||||
@@ -1004,7 +1003,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
min_length_orig = d;
|
||||
}
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b);
|
||||
for (; it.More(); it.Next()) {
|
||||
d = min_vertex_edge_distance(it.Value(), settings.precision, min_length_orig);
|
||||
if (d < min_length_orig) {
|
||||
@@ -1015,19 +1014,19 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
const double fuzz = (std::min)(min_length_orig / 3., fuzziness);
|
||||
|
||||
logger::notice("Used fuzziness: " + std::to_string(fuzz));
|
||||
Logger::Root().Notice("GEO", 135, "Used fuzziness: " + std::to_string(fuzz));
|
||||
|
||||
const double new_fuzziness = fuzziness * 10.;
|
||||
const bool allow_retry = new_fuzziness - 1e-15 <= settings.precision * 10000. && new_fuzziness < min_length_orig;
|
||||
|
||||
TopTools_ListOfShape s1s;
|
||||
NCollection_List<TopoDS_Shape> s1s;
|
||||
s1s.Append(copy_operand(a));
|
||||
|
||||
if (debug) {
|
||||
TopTools_ListOfShape* lists[2] = { &s1s, &b };
|
||||
NCollection_List<TopoDS_Shape>* lists[2] = {&s1s, &b};
|
||||
static std::string operand_names[2] = { "a", "b" };
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
TopTools_ListIteratorOfListOfShape it(*lists[i]);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(*lists[i]);
|
||||
for (int j = 0; it.More(); it.Next(), ++j) {
|
||||
std::string fn = debug_identifier + "-" + operand_names[i] + "-" + std::to_string(j) + ".brep";
|
||||
BRepTools::Write(it.Value(), fn.c_str());
|
||||
@@ -1039,7 +1038,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
TopoDS_Face a_face;
|
||||
std::pair<double, double> a_interval;
|
||||
|
||||
TopTools_ListOfShape b_faces, b_remainder_3d;
|
||||
NCollection_List<TopoDS_Shape> b_faces, b_remainder_3d;
|
||||
|
||||
bool is_extrusion_a = false;
|
||||
if (do_attempt_2d_boolean) {
|
||||
@@ -1049,9 +1048,9 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (is_extrusion_a) {
|
||||
logger::notice("Operand A 1/1 is an extrusion");
|
||||
Logger::Root().Notice("GEO", 136, "Operand A 1/1 is an extrusion");
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(b);
|
||||
for (int nb = 1; it.More(); it.Next(), ++nb) {
|
||||
bool process_2d = false;
|
||||
TopoDS_Face b_face;
|
||||
@@ -1065,10 +1064,10 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (is_extrusion_b) {
|
||||
logger::notice("Operand B " + std::to_string(nb) + "/" + std::to_string(b.Extent()) + " is an extrusion");
|
||||
Logger::Root().Notice("GEO", 137, "Operand B " + std::to_string(nb) + "/" + std::to_string(b.Extent()) + " is an extrusion");
|
||||
|
||||
if (b_interval.first < a_interval.first + (fuzz * 100.) && b_interval.second > a_interval.second - (fuzz * 100.)) {
|
||||
logger::notice("Operand B creates a through hole");
|
||||
Logger::Root().Notice("GEO", 138, "Operand B creates a through hole");
|
||||
|
||||
// Align b with a operand
|
||||
gp_Trsf trsf;
|
||||
@@ -1108,23 +1107,23 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
BRepPrimAPI_MakePrism mp(face_result, gp_Vec(gp::DY()) * (a_interval.second - a_interval.first));
|
||||
if (mp.IsDone()) {
|
||||
if (b_remainder_3d.Extent()) {
|
||||
logger::notice(std::to_string(b_remainder_3d.Extent()) + " operands remaining to process in 3D");
|
||||
Logger::Root().Notice("GEO", 139, std::to_string(b_remainder_3d.Extent()) + " operands remaining to process in 3D");
|
||||
b = b_remainder_3d;
|
||||
s1s.Clear();
|
||||
s1s.Append(mp.Shape());
|
||||
} else {
|
||||
logger::notice("Processed fully in 2D");
|
||||
Logger::Root().Notice("GEO", 140, "Processed fully in 2D");
|
||||
result = mp.Shape();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
logger::notice("Failed to extrude 2D boolean result. Retrying in 3D.");
|
||||
Logger::Root().Notice("GEO", 141, "Failed to extrude 2D boolean result. Retrying in 3D.");
|
||||
}
|
||||
} else {
|
||||
logger::notice("Failed to perform 2D boolean operation. Retrying in 3D.");
|
||||
Logger::Root().Notice("GEO", 142, "Failed to perform 2D boolean operation. Retrying in 3D.");
|
||||
}
|
||||
} else {
|
||||
logger::notice("No second operands can be processed as 2D inner bounds. Retrying in 3D.");
|
||||
Logger::Root().Notice("GEO", 143, "No second operands can be processed as 2D inner bounds. Retrying in 3D.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1146,7 +1145,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
if (builder->IsDone()) {
|
||||
if (false && builder->DSFiller()->HasWarning(STANDARD_TYPE(BOPAlgo_AlertAcquiredSelfIntersection))) {
|
||||
logger::notice("Builder reports self-intersection in output");
|
||||
Logger::Root().Notice("GEO", 144, "Builder reports self-intersection in output");
|
||||
success = false;
|
||||
|
||||
/*
|
||||
@@ -1160,7 +1159,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
*/
|
||||
} else if(builder->DSFiller()->HasWarning(STANDARD_TYPE(BOPAlgo_AlertBadPositioning)) && !TopoDS_Iterator(*builder).More()) {
|
||||
logger::notice("Builder reports bad positioning and result is empty");
|
||||
Logger::Root().Notice("GEO", 145, "Builder reports bad positioning and result is empty");
|
||||
success = false;
|
||||
} else {
|
||||
TopoDS_Shape r = *builder;
|
||||
@@ -1174,7 +1173,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
fix.Perform();
|
||||
r = fix.Shape();
|
||||
} catch (...) {
|
||||
logger::error("Shape healing failed on boolean result");
|
||||
Logger::Root().Error("GEO", 146, "Shape healing failed on boolean result");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,7 +1184,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
success = ana.IsValid() != 0;
|
||||
|
||||
if (!success) {
|
||||
logger::notice("Boolean operation yields invalid result");
|
||||
Logger::Root().Notice("GEO", 147, "Boolean operation yields invalid result");
|
||||
|
||||
std::stringstream str;
|
||||
bool any_emitted = false;
|
||||
@@ -1193,7 +1192,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
std::function<void(const TopoDS_Shape&)> dump;
|
||||
dump = [&ana, &str, &dump, &any_emitted](const TopoDS_Shape& s) {
|
||||
if (!ana.Result(s).IsNull()) {
|
||||
BRepCheck_ListIteratorOfListOfStatus itl;
|
||||
NCollection_List<BRepCheck_Status>::Iterator itl;
|
||||
itl.Initialize(ana.Result(s)->Status());
|
||||
for (; itl.More(); itl.Next()) {
|
||||
if (itl.Value() != BRepCheck_NoError) {
|
||||
@@ -1215,7 +1214,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
dump(r);
|
||||
|
||||
logger::notice(str.str());
|
||||
Logger::Root().Notice("GEO", 148, str.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1233,9 +1232,9 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
// An exemption for the requirement to be manifold: When the cut operands have overlapping edge belonging to faces that do not overlap.
|
||||
bool operands_nonmanifold = false;
|
||||
if (op == BOPAlgo_CUT) {
|
||||
TopTools_IndexedMapOfShape edges;
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
for (TopTools_ListIteratorOfListOfShape it2(b); it2.More(); it2.Next()) {
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> edges;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it2(b); it2.More(); it2.Next()) {
|
||||
auto& bb = it2.Value();
|
||||
TopExp::MapShapes(bb, TopAbs_EDGE, edges);
|
||||
TopExp::MapShapesAndAncestors(bb, TopAbs_EDGE, TopAbs_FACE, map);
|
||||
@@ -1262,9 +1261,9 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
auto faces_i = map.FindFromKey(edges.FindKey(i));
|
||||
auto faces_j = map.FindFromKey(edges.FindKey(j));
|
||||
bool overlap = false;
|
||||
for (TopTools_ListIteratorOfListOfShape it4(faces_i); it4.More(); it4.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it4(faces_i); it4.More(); it4.Next()) {
|
||||
auto& fi = it4.Value();
|
||||
for (TopTools_ListIteratorOfListOfShape it2(faces_j); it2.More(); it2.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it2(faces_j); it2.More(); it2.Next()) {
|
||||
auto& fj = it2.Value();
|
||||
if (faces_overlap(TopoDS::Face(fi), TopoDS::Face(fj))) {
|
||||
overlap = true;
|
||||
@@ -1316,7 +1315,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (has_open_shells) {
|
||||
TopTools_IndexedMapOfShape faces;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> faces;
|
||||
TopExp::MapShapes(r, TopAbs_FACE, faces);
|
||||
for (TopExp_Explorer exp(a, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
auto& f = TopoDS::Face(exp.Current());
|
||||
@@ -1335,7 +1334,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
if (op == BOPAlgo_CUT && has_open_shells && all_faces_included_in_result && result_n_faces > first_op_n_faces) {
|
||||
success = false;
|
||||
logger::notice("Boolean result discarded because subtractions results in only the addition of faces");
|
||||
Logger::Root().Notice("GEO", 149, "Boolean result discarded because subtractions results in only the addition of faces");
|
||||
} else {
|
||||
// when there are edges or vertex-edge distances close to the used fuzziness, the
|
||||
// output is not trusted and the operation is attempted with a higher fuzziness.
|
||||
@@ -1381,7 +1380,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
static const char* const reason_strings[] = { "edge length", "vertex-edge", "face-face" };
|
||||
std::stringstream str;
|
||||
str << "Boolean operation result failing " << reason_strings[reason] << " interference check, with fuzziness " << fuzziness << " with length " << v;
|
||||
logger::notice(str.str());
|
||||
Logger::Root().Notice("GEO", 150, str.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1390,7 +1389,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
} else {
|
||||
logger::notice("Boolean operation yields non-manifold result");
|
||||
Logger::Root().Notice("GEO", 151, "Boolean operation yields non-manifold result");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1400,7 +1399,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
#if OCC_VERSION_HEX >= 0x70200
|
||||
|
||||
if (builder->HasError(STANDARD_TYPE(BOPAlgo_AlertBOPNotAllowed))) {
|
||||
logger::error("Invalid operands. Using first operand");
|
||||
Logger::Root().Error("GEO", 152, "Invalid operands. Using first operand");
|
||||
result = a;
|
||||
success = true;
|
||||
}
|
||||
@@ -1413,21 +1412,21 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
#endif
|
||||
std::string str_str = str.str();
|
||||
if (str_str.size()) {
|
||||
logger::notice(str_str);
|
||||
Logger::Root().Notice("GEO", 153, str_str);
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
if (allow_retry) {
|
||||
return boolean_operation(settings, a, b, op, result, new_fuzziness);
|
||||
} else {
|
||||
logger::notice("No longer attempting boolean operation with higher fuzziness");
|
||||
Logger::Root().Notice("GEO", 154, "No longer attempting boolean operation with higher fuzziness");
|
||||
}
|
||||
}
|
||||
return success && !result.IsNull();
|
||||
}
|
||||
|
||||
bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const TopoDS_Shape& a, const TopoDS_Shape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
|
||||
TopTools_ListOfShape bs;
|
||||
NCollection_List<TopoDS_Shape> bs;
|
||||
bs.Append(b);
|
||||
return boolean_operation(settings, a, bs, op, result, fuzziness);
|
||||
}
|
||||
|
||||
@@ -21,13 +21,18 @@
|
||||
#define BOOLEAN_UTILS_H
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <NCollection_IndexedMap.hxx>
|
||||
|
||||
#include <Geom_Surface.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <BRepTopAdaptor_FClass2d.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <TopTools_IndexedMapOfShape.hxx>
|
||||
|
||||
#include <BOPAlgo_Operation.hxx>
|
||||
|
||||
#include "../ifc_geomlibrary_api.h"
|
||||
@@ -35,7 +40,7 @@
|
||||
namespace IfcGeom {
|
||||
namespace util {
|
||||
|
||||
IFC_GEOMLIBRARY_API void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r);
|
||||
IFC_GEOMLIBRARY_API void copy_operand(const NCollection_List<TopoDS_Shape>& l, NCollection_List<TopoDS_Shape>& r);
|
||||
|
||||
IFC_GEOMLIBRARY_API TopoDS_Shape copy_operand(const TopoDS_Shape& s);
|
||||
|
||||
@@ -73,26 +78,26 @@ namespace IfcGeom {
|
||||
|
||||
IFC_GEOMLIBRARY_API double min_face_face_distance(const TopoDS_Shape& a, double max_search);
|
||||
|
||||
IFC_GEOMLIBRARY_API int bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c);
|
||||
IFC_GEOMLIBRARY_API int bounding_box_overlap(double p, const TopoDS_Shape& a, const NCollection_List<TopoDS_Shape>& b, NCollection_List<TopoDS_Shape>& c);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool get_edge_axis(const TopoDS_Edge& e, gp_Ax1& ax);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool is_subset(const TopTools_IndexedMapOfShape& lhs, const TopTools_IndexedMapOfShape& rhs);
|
||||
IFC_GEOMLIBRARY_API bool is_subset(const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& lhs, const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& rhs);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair<double, double>& interval);
|
||||
|
||||
IFC_GEOMLIBRARY_API int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const TopTools_ListOfShape& bs, TopTools_ListOfShape& c);
|
||||
IFC_GEOMLIBRARY_API int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const NCollection_List<TopoDS_Shape>& bs, NCollection_List<TopoDS_Shape>& c);
|
||||
|
||||
IFC_GEOMLIBRARY_API int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c);
|
||||
IFC_GEOMLIBRARY_API int eliminate_narrow_operands(double prec, const NCollection_List<TopoDS_Shape>& bs, NCollection_List<TopoDS_Shape> & c);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps);
|
||||
IFC_GEOMLIBRARY_API bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const NCollection_List<TopoDS_Shape>& b_input, TopoDS_Shape& result, double eps);
|
||||
|
||||
struct boolean_settings {
|
||||
bool debug, attempt_2d;
|
||||
double precision;
|
||||
};
|
||||
|
||||
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const NCollection_List<TopoDS_Shape>&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ using namespace IfcGeom;
|
||||
bool OpenCascadeKernel::convert(const taxonomy::bspline_surface::ptr bs, Handle(Geom_Surface) surf) {
|
||||
const bool is_rational = !!bs->weights;
|
||||
|
||||
TColgp_Array2OfPnt Poles(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
TColStd_Array2OfReal Weights(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)bs->knots[0].size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)bs->knots[1].size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)bs->multiplicities[0].size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)bs->multiplicities[1].size() - 1);
|
||||
Standard_Integer UDegree = bs->degree[0];
|
||||
Standard_Integer VDegree = bs->degree[1];
|
||||
NCollection_Array2<gp_Pnt> Poles(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
NCollection_Array2<double> Weights(0, (int)bs->control_points.size() - 1, 0, (int)(*bs->control_points.begin()).size() - 1);
|
||||
NCollection_Array1<double> UKnots(0, (int)bs->knots[0].size() - 1);
|
||||
NCollection_Array1<double> VKnots(0, (int)bs->knots[1].size() - 1);
|
||||
NCollection_Array1<int> UMults(0, (int)bs->multiplicities[0].size() - 1);
|
||||
NCollection_Array1<int> VMults(0, (int)bs->multiplicities[1].size() - 1);
|
||||
int UDegree = bs->degree[0];
|
||||
int VDegree = bs->degree[1];
|
||||
|
||||
int i = 0, j;
|
||||
for (auto it = bs->control_points.begin(); it != bs->control_points.end(); ++it, ++i) {
|
||||
|
||||
@@ -43,7 +43,7 @@ bool is_intersect_ray_box(const struct ray *ray, const struct box *box) {
|
||||
// More reading: https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
||||
bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
|
||||
Standard_Real& at, Standard_Real& au, Standard_Real& av,
|
||||
double& at, double& au, double& av,
|
||||
bool cull, float enlarge) {
|
||||
// Find vectors for two edges sharing vert0
|
||||
const gp_Vec edge1 = vert1 - vert0;
|
||||
@@ -53,7 +53,7 @@ bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
const gp_Vec pvec = dir.Crossed(edge2); // error ~ |v2-v0|
|
||||
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
const Standard_Real det = edge1.Dot(pvec); // error ~ |v2-v0|*|v1-v0|
|
||||
const double det = edge1.Dot(pvec); // error ~ |v2-v0|*|v1-v0|
|
||||
|
||||
if(cull)
|
||||
{
|
||||
@@ -64,11 +64,11 @@ bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
const gp_Vec tvec = orig - vert0;
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
const Standard_Real u = tvec.Dot(pvec);
|
||||
const double u = tvec.Dot(pvec);
|
||||
|
||||
const Standard_Real enlargeCoeff = enlarge*det;
|
||||
const Standard_Real uvlimit = -enlargeCoeff;
|
||||
const Standard_Real uvlimit2 = det + enlargeCoeff;
|
||||
const double enlargeCoeff = enlarge*det;
|
||||
const double uvlimit = -enlargeCoeff;
|
||||
const double uvlimit2 = det + enlargeCoeff;
|
||||
|
||||
if(u<uvlimit || u>uvlimit2)
|
||||
return false;
|
||||
@@ -77,14 +77,14 @@ bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
const gp_Vec qvec = tvec.Crossed(edge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const Standard_Real v = dir.Dot(qvec);
|
||||
const double v = dir.Dot(qvec);
|
||||
if(v<uvlimit || (u+v)>uvlimit2)
|
||||
return false;
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
const Standard_Real t = edge2.Dot(qvec);
|
||||
const double t = edge2.Dot(qvec);
|
||||
|
||||
const Standard_Real inv_det = 1.0f / det;
|
||||
const double inv_det = 1.0f / det;
|
||||
at = t*inv_det;
|
||||
au = u*inv_det;
|
||||
av = v*inv_det;
|
||||
@@ -95,26 +95,26 @@ bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
if(std::abs(det)<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
return false;
|
||||
|
||||
const Standard_Real inv_det = 1.0f / det;
|
||||
const double inv_det = 1.0 / det;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
const gp_Vec tvec = orig - vert0; // error ~ |orig-v0|
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
const Standard_Real u = tvec.Dot(pvec) * inv_det;
|
||||
if(u<-enlarge || u>1.0f+enlarge)
|
||||
const double u = tvec.Dot(pvec) * inv_det;
|
||||
if(u<-enlarge || u>1.0+enlarge)
|
||||
return false;
|
||||
|
||||
// prepare to test V parameter
|
||||
const gp_Vec qvec = tvec.Crossed(edge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const Standard_Real v = dir.Dot(qvec) * inv_det;
|
||||
if(v<-enlarge || (u+v)>1.0f+enlarge)
|
||||
const double v = dir.Dot(qvec) * inv_det;
|
||||
if(v<-enlarge || (u+v)>1.0+enlarge)
|
||||
return false;
|
||||
|
||||
// Calculate t, ray intersects triangle
|
||||
const Standard_Real t = edge2.Dot(qvec) * inv_det;
|
||||
const double t = edge2.Dot(qvec) * inv_det;
|
||||
|
||||
at = t;
|
||||
au = u;
|
||||
@@ -142,45 +142,45 @@ void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points
|
||||
// u parameterizes ray (q, b)
|
||||
|
||||
// Compute t for the closest point on ray (p, a) to ray (q, b)
|
||||
const Standard_Real Denom = ADotA*BDotB - ADotB*ADotB;
|
||||
const double Denom = ADotA*BDotB - ADotB*ADotB;
|
||||
|
||||
Standard_Real t; // We will clamp result so t is on the segment (p, a)
|
||||
if(Denom!=0.0f)
|
||||
double t; // We will clamp result so t is on the segment (p, a)
|
||||
if(Denom!=0.0)
|
||||
t = ios_clamp((ADotT*BDotB - BDotT*ADotB) / Denom, 0.0, 1.0);
|
||||
else
|
||||
t = 0.0f;
|
||||
t = 0.0;
|
||||
|
||||
// find u for point on ray (q, b) closest to point at t
|
||||
Standard_Real u;
|
||||
if(BDotB!=0.0f)
|
||||
double u;
|
||||
if(BDotB!=0.0)
|
||||
{
|
||||
u = (t*ADotB - BDotT) / BDotB;
|
||||
|
||||
// if u is on segment (q, b), t and u correspond to closest points, otherwise, clamp u, recompute and clamp t
|
||||
if(u<0.0f)
|
||||
if(u<0.0)
|
||||
{
|
||||
u = 0.0f;
|
||||
if(ADotA!=0.0f)
|
||||
u = 0.0;
|
||||
if(ADotA!=0.0)
|
||||
t = ios_clamp(ADotT / ADotA, 0.0, 1.0);
|
||||
else
|
||||
t = 0.0f;
|
||||
t = 0.0;
|
||||
}
|
||||
else if(u > 1.0f)
|
||||
else if(u > 1.0)
|
||||
{
|
||||
u = 1.0f;
|
||||
if(ADotA!=0.0f)
|
||||
u = 1.0;
|
||||
if(ADotA!=0.0)
|
||||
t = ios_clamp((ADotB + ADotT) / ADotA, 0.0, 1.0);
|
||||
else
|
||||
t = 0.0f;
|
||||
t = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u = 0.0f;
|
||||
if(ADotA!=0.0f)
|
||||
u = 0.0;
|
||||
if(ADotA!=0.0)
|
||||
t = ios_clamp(ADotT / ADotA, 0.0, 1.0);
|
||||
else
|
||||
t = 0.0f;
|
||||
t = 0.0;
|
||||
}
|
||||
|
||||
x = p + a * t;
|
||||
@@ -191,7 +191,7 @@ void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/distance/GuDistanceTriangleTriangle.cpp
|
||||
// With minor modifications to use gp_Vec type.
|
||||
float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<gp_Vec, 3> p, const std::array<gp_Vec, 3> q)
|
||||
double distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<gp_Vec, 3> p, const std::array<gp_Vec, 3> q)
|
||||
{
|
||||
std::array<gp_Vec, 3> Sv;
|
||||
Sv[0] = p[1] - p[0];
|
||||
@@ -206,7 +206,7 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
gp_Vec minP, minQ;
|
||||
bool shown_disjoint = false;
|
||||
|
||||
float mindd = PX_MAX_F32;
|
||||
double mindd = PX_MAX_F32;
|
||||
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
{
|
||||
edgeEdgeDist(cp, cq, p[i], Sv[i], q[j], Tv[j]);
|
||||
const gp_Vec V = cq - cp;
|
||||
const float dd = V.Dot(V);
|
||||
const double dd = V.Dot(V);
|
||||
|
||||
if(dd<=mindd)
|
||||
{
|
||||
@@ -226,12 +226,12 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
if(id>=3)
|
||||
id-=3;
|
||||
gp_Vec Z = p[id] - cp;
|
||||
float a = Z.Dot(V);
|
||||
double a = Z.Dot(V);
|
||||
id = j+2;
|
||||
if(id>=3)
|
||||
id-=3;
|
||||
Z = q[id] - cq;
|
||||
float b = Z.Dot(V);
|
||||
double b = Z.Dot(V);
|
||||
|
||||
if((a<=0.0f) && (b>=0.0f))
|
||||
return V.Dot(V);
|
||||
@@ -246,7 +246,7 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
}
|
||||
|
||||
gp_Vec Sn = Sv[0].Crossed(Sv[1]);
|
||||
float Snl = Sn.Dot(Sn);
|
||||
double Snl = Sn.Dot(Sn);
|
||||
|
||||
if(Snl>1e-15f)
|
||||
{
|
||||
@@ -294,7 +294,7 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
}
|
||||
|
||||
gp_Vec Tn = Tv[0].Crossed(Tv[1]);
|
||||
float Tnl = Tn.Dot(Tn);
|
||||
double Tnl = Tn.Dot(Tn);
|
||||
|
||||
if(Tnl>1e-15f)
|
||||
{
|
||||
@@ -359,8 +359,8 @@ float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<g
|
||||
namespace {
|
||||
struct Interval
|
||||
{
|
||||
Standard_Real min;
|
||||
Standard_Real max;
|
||||
double min;
|
||||
double max;
|
||||
gp_Vec minPoint;
|
||||
gp_Vec maxPoint;
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace {
|
||||
return result;
|
||||
}
|
||||
|
||||
void include(Standard_Real d, const gp_Vec& p)
|
||||
void include(double d, const gp_Vec& p)
|
||||
{
|
||||
if (d < min) { min = d; minPoint = p; }
|
||||
if (d > max) { max = d; maxPoint = p; }
|
||||
@@ -407,7 +407,7 @@ namespace {
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/intersection/GuIntersectionTriangleTriangle.cpp
|
||||
// With minor modifications to use gp_Vec type.
|
||||
static Interval computeInterval(Standard_Real distanceA, Standard_Real distanceB, Standard_Real distanceC, const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, const gp_Vec& dir)
|
||||
static Interval computeInterval(double distanceA, double distanceB, double distanceC, const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, const gp_Vec& dir)
|
||||
{
|
||||
Interval i;
|
||||
|
||||
@@ -441,7 +441,7 @@ static Interval computeInterval(Standard_Real distanceA, Standard_Real distanceB
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/intersection/GuIntersectionTriangleTriangle.cpp
|
||||
// With minor modifications to use gp_Vec type.
|
||||
Standard_Real orient2d(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, PxU32 x, PxU32 y)
|
||||
double orient2d(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, PxU32 x, PxU32 y)
|
||||
{
|
||||
return (a.Coord(y) - c.Coord(y)) * (b.Coord(x) - c.Coord(x)) - (a.Coord(x) - c.Coord(x)) * (b.Coord(y) - c.Coord(y));
|
||||
}
|
||||
@@ -450,11 +450,11 @@ Standard_Real orient2d(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, PxU32
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/intersection/GuIntersectionTriangleTriangle.cpp
|
||||
// With minor modifications to use gp_Vec type.
|
||||
Standard_Real pointInTriangle(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, const gp_Vec& point, PxU32 x, PxU32 y)
|
||||
double pointInTriangle(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c, const gp_Vec& point, PxU32 x, PxU32 y)
|
||||
{
|
||||
const Standard_Real ab = orient2d(a, b, point, x, y);
|
||||
const Standard_Real bc = orient2d(b, c, point, x, y);
|
||||
const Standard_Real ca = orient2d(c, a, point, x, y);
|
||||
const double ab = orient2d(a, b, point, x, y);
|
||||
const double bc = orient2d(b, c, point, x, y);
|
||||
const double ca = orient2d(c, a, point, x, y);
|
||||
|
||||
if ((ab >= 0) == (bc >= 0) && (ab >= 0) == (ca >= 0))
|
||||
return true;
|
||||
@@ -466,16 +466,16 @@ Standard_Real pointInTriangle(const gp_Vec& a, const gp_Vec& b, const gp_Vec& c,
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md
|
||||
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/intersection/GuIntersectionTriangleTriangle.cpp
|
||||
// With minor modifications to use gp_Vec type.
|
||||
Standard_Real linesIntersect(const gp_Vec& startA, const gp_Vec& endA, const gp_Vec& startB, const gp_Vec& endB, PxU32 x, PxU32 y)
|
||||
double linesIntersect(const gp_Vec& startA, const gp_Vec& endA, const gp_Vec& startB, const gp_Vec& endB, PxU32 x, PxU32 y)
|
||||
{
|
||||
const Standard_Real aaS = orient2d(startA, endA, startB, x, y);
|
||||
const Standard_Real aaE = orient2d(startA, endA, endB, x, y);
|
||||
const double aaS = orient2d(startA, endA, startB, x, y);
|
||||
const double aaE = orient2d(startA, endA, endB, x, y);
|
||||
|
||||
if ((aaS >= 0) == (aaE >= 0))
|
||||
return false;
|
||||
|
||||
const Standard_Real bbS = orient2d(startB, endB, startA, x, y);
|
||||
const Standard_Real bbE = orient2d(startB, endB, endA, x, y);
|
||||
const double bbS = orient2d(startB, endB, startA, x, y);
|
||||
const double bbE = orient2d(startB, endB, endA, x, y);
|
||||
|
||||
if ((bbS >= 0) == (bbE >= 0))
|
||||
return false;
|
||||
@@ -521,7 +521,7 @@ bool trianglesIntersectCoplanar(const gp_Vec& p1_n, const gp_Vec& a1, const gp_V
|
||||
PxU32 y = 0;
|
||||
getProjectionIndices(p1_n, x, y);
|
||||
|
||||
const Standard_Real third = (1.0f / 3.0f);
|
||||
const double third = (1.0 / 3.0);
|
||||
|
||||
//A bit of the computations done inside the following functions could be shared but it's kept simple since the
|
||||
//difference is not very big and the coplanar case is not expected to be the most common case
|
||||
@@ -541,14 +541,14 @@ bool trianglesIntersectCoplanar(const gp_Vec& p1_n, const gp_Vec& a1, const gp_V
|
||||
// Also with minor modification to return intersection points.
|
||||
bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, const gp_Vec& a2, const gp_Vec& b2, const gp_Vec& c2/*, Segment* intersection*/, gp_Vec& int1, gp_Vec& int2, bool ignoreCoplanar)
|
||||
{
|
||||
const Standard_Real tolerance = 1e-8f;
|
||||
const double tolerance = 1e-8f;
|
||||
|
||||
gp_Vec p1_n((b1 - a1).Crossed(c1 - a1).Normalized());
|
||||
double p1_d = -a1.Dot(p1_n);
|
||||
// const PxPlane p1(a1, b1, c1);
|
||||
const Standard_Real p1ToA = a2.Dot(p1_n) + p1_d;
|
||||
const Standard_Real p1ToB = b2.Dot(p1_n) + p1_d;
|
||||
const Standard_Real p1ToC = c2.Dot(p1_n) + p1_d;
|
||||
const double p1ToA = a2.Dot(p1_n) + p1_d;
|
||||
const double p1ToB = b2.Dot(p1_n) + p1_d;
|
||||
const double p1ToC = c2.Dot(p1_n) + p1_d;
|
||||
|
||||
if(std::abs(p1ToA) < tolerance && std::abs(p1ToB) < tolerance &&std::abs(p1ToC) < tolerance)
|
||||
return ignoreCoplanar ? false : trianglesIntersectCoplanar(p1_n, a1, b1, c1, a2, b2, c2); //Coplanar triangles
|
||||
@@ -559,15 +559,15 @@ bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, co
|
||||
gp_Dir p2_n((b2 - a2).Crossed(c2 - a2).Normalized());
|
||||
double p2_d = -a2.Dot(p2_n);
|
||||
// const PxPlane p2(a2, b2, c2);
|
||||
const Standard_Real p2ToA = a1.Dot(p2_n) + p2_d;
|
||||
const Standard_Real p2ToB = b1.Dot(p2_n) + p2_d;
|
||||
const Standard_Real p2ToC = c1.Dot(p2_n) + p2_d;
|
||||
const double p2ToA = a1.Dot(p2_n) + p2_d;
|
||||
const double p2ToB = b1.Dot(p2_n) + p2_d;
|
||||
const double p2ToC = c1.Dot(p2_n) + p2_d;
|
||||
|
||||
if ((p2ToA > 0) == (p2ToB > 0) && (p2ToA > 0) == (p2ToC > 0))
|
||||
return false; //All points of triangle 1 on same side of triangle 2 -> no intersection
|
||||
|
||||
gp_Vec intersectionDirection = p1_n.Crossed(p2_n);
|
||||
const Standard_Real l2 = intersectionDirection.SquareMagnitude();
|
||||
const double l2 = intersectionDirection.SquareMagnitude();
|
||||
intersectionDirection *= 1.0f / std::sqrt(l2);
|
||||
|
||||
const Interval i1 = computeInterval(p2ToA, p2ToB, p2ToC, a1, b1, c1, intersectionDirection);
|
||||
|
||||
@@ -19,13 +19,13 @@ IFC_GEOMLIBRARY_API bool is_intersect_ray_box(const struct ray *ray, const struc
|
||||
|
||||
IFC_GEOMLIBRARY_API bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
|
||||
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
|
||||
Standard_Real& at, Standard_Real& au, Standard_Real& av,
|
||||
double& at, double& au, double& av,
|
||||
bool cull, float enlarge=0.0f);
|
||||
|
||||
IFC_GEOMLIBRARY_API void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points
|
||||
const gp_Vec& p, const gp_Vec& a, // seg 1 origin, vector
|
||||
const gp_Vec& q, const gp_Vec& b); // seg 2 origin, vector
|
||||
|
||||
IFC_GEOMLIBRARY_API float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<gp_Vec, 3> p, const std::array<gp_Vec, 3> q);
|
||||
IFC_GEOMLIBRARY_API double distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<gp_Vec, 3> p, const std::array<gp_Vec, 3> q);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, const gp_Vec& a2, const gp_Vec& b2, const gp_Vec& c2/*, Segment* intersection*/, gp_Vec& int1, gp_Vec& int2, bool ignoreCoplanar);
|
||||
|
||||
@@ -10,7 +10,7 @@ bool OpenCascadeKernel::convert(const taxonomy::extrusion::ptr extrusion, TopoDS
|
||||
const double& height = extrusion->depth;
|
||||
|
||||
if (height < settings_.get<settings::Precision>().get()) {
|
||||
logger::error("Non-positive extrusion height encountered for:", extrusion->instance);
|
||||
Logger::Root().Error("GEO", 89, "Non-positive extrusion height encountered for:", extrusion->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,12 @@
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopTools_DataMapOfShapeInteger.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <NCollection_DataMap.hxx>
|
||||
|
||||
#include <BRepLib_FindSurface.hxx>
|
||||
#include <ShapeExtend_MsgRegistrator.hxx>
|
||||
#include <Message_Msg.hxx>
|
||||
@@ -79,13 +84,13 @@ namespace {
|
||||
auto& umults = bs->multiplicities[0];
|
||||
auto& vmults = bs->multiplicities[1];
|
||||
|
||||
TColgp_Array2OfPnt Poles(0, (int)cps.size() - 1, 0, (int)cps[0].size() - 1);
|
||||
TColStd_Array1OfReal UKnots(0, (int)uknots.size() - 1);
|
||||
TColStd_Array1OfReal VKnots(0, (int)vknots.size() - 1);
|
||||
TColStd_Array1OfInteger UMults(0, (int)umults.size() - 1);
|
||||
TColStd_Array1OfInteger VMults(0, (int)vmults.size() - 1);
|
||||
Standard_Integer UDegree = bs->degree[0];
|
||||
Standard_Integer VDegree = bs->degree[1];
|
||||
NCollection_Array2<gp_Pnt> Poles(0, (int)cps.size() - 1, 0, (int)cps[0].size() - 1);
|
||||
NCollection_Array1<double> UKnots(0, (int)uknots.size() - 1);
|
||||
NCollection_Array1<double> VKnots(0, (int)vknots.size() - 1);
|
||||
NCollection_Array1<int> UMults(0, (int)umults.size() - 1);
|
||||
NCollection_Array1<int> VMults(0, (int)vmults.size() - 1);
|
||||
int UDegree = bs->degree[0];
|
||||
int VDegree = bs->degree[1];
|
||||
|
||||
int i = 0, j;
|
||||
for (auto it = cps.begin(); it != cps.end(); ++it, ++i) {
|
||||
@@ -169,8 +174,8 @@ namespace {
|
||||
} else if (crv_or_wire.index() == 2) {
|
||||
// @todo
|
||||
const double precision_ = 1.e-5;
|
||||
logger::warning("Approximating BasisCurve due to possible discontinuities", i->instance);
|
||||
const auto& w = std::get<TopoDS_Wire>(crv_or_wire);
|
||||
Logger::Root().Warning("GEO", 156, "Approximating BasisCurve due to possible discontinuities", i->instance);
|
||||
const auto& w = boost::get<TopoDS_Wire>(crv_or_wire);
|
||||
#if OCC_VERSION_HEX < 0x70600
|
||||
BRepAdaptor_CompCurve cc(w, true);
|
||||
Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc));
|
||||
@@ -275,7 +280,7 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
fd.surface() = convert_surface(face->basis);
|
||||
}
|
||||
|
||||
const int num_bounds = face->children.size();
|
||||
const size_t num_bounds = face->children.size();
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (auto& bound : face->children) {
|
||||
@@ -289,16 +294,16 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
// the face will still be processed as long as there are no holes. A compound of faces
|
||||
// is returned in that case.
|
||||
if (num_bounds > 1 && num_outer_bounds > 1 && num_bounds != num_outer_bounds) {
|
||||
logger::message(logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance);
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 157, "Invalid configuration of boundaries for:", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_outer_bounds > 1) {
|
||||
logger::message(logger::LOG_WARNING, "Multiple outer boundaries for:", face->instance);
|
||||
Logger::Root().Message(Logger::LOG_WARNING, "GEO", 158, "Multiple outer boundaries for:", face->instance);
|
||||
fd.all_outer() = true;
|
||||
}
|
||||
|
||||
TopTools_DataMapOfShapeInteger wire_senses;
|
||||
NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher> wire_senses;
|
||||
|
||||
for (int process_interior = 0; process_interior <= 1; ++process_interior) {
|
||||
for (auto& bound : face->children) {
|
||||
@@ -315,11 +320,11 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
TopoDS_Wire wire;
|
||||
if (faceset_helper_ && bound->is_polyhedron()) {
|
||||
if (!faceset_helper_->wire(bound, wire)) {
|
||||
logger::message(logger::LOG_WARNING, "Face boundary loop not included", bound->instance);
|
||||
Logger::Root().Message(Logger::LOG_WARNING, "GEO", 159, "Face boundary loop not included", bound->instance);
|
||||
continue;
|
||||
}
|
||||
} else if (!convert(bound, wire)) {
|
||||
logger::message(logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance);
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 160, "Failed to process face boundary loop", bound->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -334,9 +339,9 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
0.,
|
||||
settings_.get<settings::Precision>().get()
|
||||
};
|
||||
TopTools_ListOfShape results;
|
||||
NCollection_List<TopoDS_Shape> 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");
|
||||
Logger::Root().Warning("GEO", 161, "Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
util::select_largest(results, wire);
|
||||
}
|
||||
|
||||
@@ -347,7 +352,7 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
}
|
||||
|
||||
if (fd.wires().empty()) {
|
||||
logger::warning("Face with no boundaries", face->instance);
|
||||
Logger::Root().Warning("GEO", 162, "Face with no boundaries", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -400,15 +405,15 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
NCollection_List<TopoDS_Shape> face_list;
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// The set of wires is triangulated in case no surface can be found
|
||||
logger::message(logger::LOG_WARNING, "Triangulating face boundaries for face", face->instance);
|
||||
Logger::Root().Message(Logger::LOG_WARNING, "GEO", 163, "Triangulating face boundaries for face", face->instance);
|
||||
|
||||
if (fd.all_outer()) {
|
||||
for (const auto& w : fd.wires()) {
|
||||
TopTools_ListOfShape fl;
|
||||
NCollection_List<TopoDS_Shape> fl;
|
||||
auto r = triangulate_wire({ w }, fl);
|
||||
if (r == util::TRIANGULATE_WIRE_FAIL) {
|
||||
continue;
|
||||
@@ -449,15 +454,15 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
sfs.SetMsgRegistrator(msg);
|
||||
sfs.Perform();
|
||||
|
||||
ShapeExtend_DataMapIteratorOfDataMapOfShapeListOfMsg jt(msg->MapShape());
|
||||
NCollection_DataMap<TopoDS_Shape, NCollection_List<Message_Msg>, TopTools_ShapeMapHasher>::Iterator jt(msg->MapShape());
|
||||
for (; jt.More(); jt.Next()) {
|
||||
Message_ListIteratorOfListOfMsg kt(jt.Value());
|
||||
NCollection_List<Message_Msg>::Iterator kt(jt.Value());
|
||||
for (; kt.More(); kt.Next()) {
|
||||
char* c = new char[kt.Value().Original().LengthOfCString() + 1];
|
||||
kt.Value().Original().ToUTF8CString(c);
|
||||
std::string message = c;
|
||||
delete[] c;
|
||||
logger::warning(message, face->instance);
|
||||
Logger::Root().Warning("GEO", 164, message, face->instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,17 +474,17 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
if (it.Value().ShapeType() == TopAbs_FACE) {
|
||||
face_list.Append(it.Value());
|
||||
} else {
|
||||
logger::error("Unsupported output from face healing");
|
||||
Logger::Root().Error("UNS", 7, "Unsupported output from face healing");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger::error("Unsupported output from face healing");
|
||||
Logger::Root().Error("UNS", 8, "Unsupported output from face healing");
|
||||
}
|
||||
} else {
|
||||
face_list.Append(f);
|
||||
}
|
||||
} else {
|
||||
logger::error("Internal error in face creation");
|
||||
Logger::Root().Error("GEO", 165, "Internal error in face creation");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -500,7 +505,7 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
// In case of (non-planar) face surface, p-curves need to be computed.
|
||||
// For planar faces, Open Cascade generates p-curves on the fly.
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(face_list); it.More(); it.Next()) {
|
||||
ShapeFix_Shape sfs(it.Value());
|
||||
|
||||
Handle(ShapeExtend_MsgRegistrator) msg;
|
||||
@@ -510,9 +515,9 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
sfs.Perform();
|
||||
it.Value() = sfs.Shape();
|
||||
|
||||
ShapeExtend_DataMapIteratorOfDataMapOfShapeListOfMsg jt(msg->MapShape());
|
||||
NCollection_DataMap<TopoDS_Shape, NCollection_List<Message_Msg>, TopTools_ShapeMapHasher>::Iterator jt(msg->MapShape());
|
||||
for (; jt.More(); jt.Next()) {
|
||||
Message_ListIteratorOfListOfMsg kt(jt.Value());
|
||||
NCollection_List<Message_Msg>::Iterator kt(jt.Value());
|
||||
for (; kt.More(); kt.Next()) {
|
||||
char* c = new char[kt.Value().Original().LengthOfCString() + 1];
|
||||
kt.Value().Original().ToUTF8CString(c);
|
||||
@@ -520,24 +525,24 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
delete[] c;
|
||||
#if OCC_VERSION_MAJOR==7 && OCC_VERSION_MINOR >= 7
|
||||
if (!reversed_surface && !fd.surface().IsNull() && fd.surface()->IsUPeriodic() && message == "Unknown message invoked with the keyword FixAdvFace.FixOrientation.MSG0") {
|
||||
logger::notice("Detected reversed wire, reattempting with reversed basis surface");
|
||||
Logger::Root().Notice("GEO", 166, "Detected reversed wire, reattempting with reversed basis surface");
|
||||
TopoDS_Face reversed_result;
|
||||
convert(face, reversed_result, true);
|
||||
result = reversed_result;
|
||||
return true;
|
||||
} else
|
||||
#endif
|
||||
logger::warning(message, face->instance);
|
||||
Logger::Root().Warning("GEO", 167, message, face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(face_list); it.More(); it.Next()) {
|
||||
const TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
|
||||
ShapeFix_Face sfs(TopoDS::Face(occ_face));
|
||||
TopTools_DataMapOfShapeListOfShape wire_map;
|
||||
NCollection_DataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> wire_map;
|
||||
sfs.FixOrientation(wire_map);
|
||||
|
||||
TopoDS_Iterator jt(occ_face, false);
|
||||
@@ -546,8 +551,8 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
// tfk: @todo if wire_map contains w, I would assume wire_senses also contains w,
|
||||
// this is not the case in github issue #405.
|
||||
if (wire_map.IsBound(w) && wire_senses.IsBound(w)) {
|
||||
const TopTools_ListOfShape& shapes = wire_map.Find(w);
|
||||
TopTools_ListIteratorOfListOfShape kt(shapes);
|
||||
const NCollection_List<TopoDS_Shape>& shapes = wire_map.Find(w);
|
||||
NCollection_List<TopoDS_Shape>::Iterator kt(shapes);
|
||||
for (; kt.More(); kt.Next()) {
|
||||
// Apparently the wire got reversed, so register it with opposite orientation in the map
|
||||
wire_senses.Bind(kt.Value(), wire_senses.Find(w) == TopAbs_FORWARD ? TopAbs_REVERSED : TopAbs_FORWARD);
|
||||
@@ -558,7 +563,7 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
it.Value() = sfs.Face();
|
||||
}
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
|
||||
bool all_reversed = true;
|
||||
@@ -582,7 +587,7 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (TopTools_ListIteratorOfListOfShape it(face_list); it.More(); it.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(face_list); it.More(); it.Next()) {
|
||||
TopoDS_Face& occ_face = TopoDS::Face(it.Value());
|
||||
builder.Add(compound, occ_face);
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
||||
auto num_retained = std::count(retained.begin(), retained.end(), true);
|
||||
|
||||
if (unique.size() != num_retained) {
|
||||
logger::notice("Collapsed vertices from " + std::to_string(pnts.size()) + " (" + std::to_string(unique.size()) + " unique) to " + std::to_string(num_retained));
|
||||
Logger::Root().Notice("GEO", 168, "Collapsed vertices from " + std::to_string(pnts.size()) + " (" + std::to_string(unique.size()) + " unique) to " + std::to_string(num_retained));
|
||||
}
|
||||
|
||||
typedef std::array<int, 2> edge_t;
|
||||
@@ -171,12 +171,12 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
||||
segments.push_back(std::make_pair(C, D));
|
||||
});
|
||||
|
||||
if (edge_sets.find({loop->external.value_or(false), segment_set}) != edge_sets.end()) {
|
||||
if (edge_sets.find({loop->external.get_value_or(false), segment_set}) != edge_sets.end()) {
|
||||
duplicate_faces++;
|
||||
duplicates_.insert(loop->identity());
|
||||
continue;
|
||||
}
|
||||
edge_sets.insert({loop->external.value_or(false), segment_set});
|
||||
edge_sets.insert({loop->external.get_value_or(false), segment_set});
|
||||
|
||||
if (segments.size() >= 3) {
|
||||
for (auto& p : segments) {
|
||||
@@ -204,8 +204,8 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
||||
}
|
||||
}
|
||||
|
||||
if (duplicates_.size() || loops_removed || (non_manifold && shell->closed.value_or(false))) {
|
||||
logger::warning(boost::lexical_cast<std::string>(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast<std::string>(loops_removed) + " degenerate loops eliminated and " + boost::lexical_cast<std::string>(non_manifold) + " non-manifold edges");
|
||||
if (duplicates_.size() || loops_removed || (non_manifold && shell->closed.get_value_or(false))) {
|
||||
Logger::Root().Warning("GEO", 169, boost::lexical_cast<std::string>(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast<std::string>(loops_removed) + " degenerate loops eliminated and " + boost::lexical_cast<std::string>(non_manifold) + " non-manifold edges");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::edge(int A, int B, TopoDS_Edge&
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopoDS_Wire& w) {
|
||||
TopTools_ListOfShape ws;
|
||||
NCollection_List<TopoDS_Shape> ws;
|
||||
if (!wires(loop, ws)) {
|
||||
return false;
|
||||
}
|
||||
@@ -249,7 +249,7 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const ifcopenshell::geomet
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopTools_ListOfShape& wires) {
|
||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, NCollection_List<TopoDS_Shape>& wires) {
|
||||
if (duplicates_.find(loop->identity()) != duplicates_.end()) {
|
||||
return false;
|
||||
}
|
||||
@@ -270,13 +270,13 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geome
|
||||
if (count >= 3) {
|
||||
wire.Closed(true);
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
NCollection_List<TopoDS_Shape> results;
|
||||
if (!kernel_->settings().get<ifcopenshell::geometry::settings::NoWireIntersectionCheck>().get() && util::wire_intersections(wire, results, {
|
||||
!kernel_->settings().get<ifcopenshell::geometry::settings::NoWireIntersectionCheck>().get(),
|
||||
!kernel_->settings().get<ifcopenshell::geometry::settings::NoWireIntersectionTolerance>().get(), 0.,
|
||||
kernel_->settings().get<ifcopenshell::geometry::settings::Precision>().get()}))
|
||||
{
|
||||
logger::warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
Logger::Root().Warning("GEO", 170, "Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
non_manifold_ = true;
|
||||
wires = results;
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
#include <TopoDS_Shell.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
|
||||
@@ -43,14 +46,14 @@ namespace {
|
||||
}
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x70200
|
||||
bool split(const TopoDS_Shape& input, const TopTools_ListOfShape& operands, double eps, std::vector<TopoDS_Shape>& slices) {
|
||||
bool split(const TopoDS_Shape& input, const NCollection_List<TopoDS_Shape>& operands, double eps, std::vector<TopoDS_Shape>& slices) {
|
||||
if (operands.Extent() < 2) {
|
||||
// Needs to have at least two cutting surfaces for the ordering based on surface containment to work.
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepAlgoAPI_Splitter split;
|
||||
TopTools_ListOfShape input_list;
|
||||
NCollection_List<TopoDS_Shape> input_list;
|
||||
input_list.Append(input);
|
||||
split.SetArguments(input_list);
|
||||
split.SetTools(operands);
|
||||
@@ -66,7 +69,7 @@ namespace {
|
||||
|
||||
// NB 1, since first surface has been excluded
|
||||
int i = 1;
|
||||
for (TopTools_ListIteratorOfListOfShape it(operands); it.More(); it.Next(), ++i) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(operands); it.More(); it.Next(), ++i) {
|
||||
TopExp_Explorer exp(it.Value(), TopAbs_FACE);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
surfaces.insert(std::make_pair(BRep_Tool::Surface(TopoDS::Face(exp.Current())).get(), i));
|
||||
@@ -129,7 +132,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
logger::error("Unable to map layer geometry to material index");
|
||||
Logger::Root().Error("GEO", 171, "Unable to map layer geometry to material index");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -164,21 +167,21 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const std::vector< std::vector<Handle_Geom_Surface> >& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles, ConversionResults& result, double tol) {
|
||||
bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const std::vector< std::vector<opencascade::handle<Geom_Surface>>>& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles, ConversionResults& result, double tol) {
|
||||
Bnd_Box bb;
|
||||
TopoDS_Shape input;
|
||||
flatten_shape_list(items, input, false, false, tol);
|
||||
|
||||
typedef std::vector< std::vector<Handle_Geom_Surface> > folded_surfaces_t;
|
||||
typedef std::vector< std::vector<opencascade::handle<Geom_Surface>> > folded_surfaces_t;
|
||||
typedef std::vector< std::pair< TopoDS_Face, std::pair<gp_Pnt, gp_Pnt> > > faces_with_mass_t;
|
||||
|
||||
TopTools_ListOfShape shells;
|
||||
NCollection_List<TopoDS_Shape> shells;
|
||||
|
||||
for (folded_surfaces_t::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) {
|
||||
if (it->empty()) {
|
||||
continue;
|
||||
} else if (it->size() == 1) {
|
||||
const Handle_Geom_Surface& surface = (*it)[0];
|
||||
const opencascade::handle<Geom_Surface>& surface = (*it)[0];
|
||||
double u1, v1, u2, v2;
|
||||
if (!project(surface, input, u1, v1, u2, v2)) {
|
||||
continue;
|
||||
@@ -187,7 +190,7 @@ bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const
|
||||
} else {
|
||||
faces_with_mass_t solids;
|
||||
for (folded_surfaces_t::value_type::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
|
||||
const Handle_Geom_Surface& surface = *jt;
|
||||
const opencascade::handle<Geom_Surface>& surface = *jt;
|
||||
double u1, v1, u2, v2;
|
||||
if (!project(surface, input, u1, v1, u2, v2)) {
|
||||
continue;
|
||||
@@ -234,7 +237,7 @@ bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const
|
||||
if (s.ShapeType() == TopAbs_SHELL) {
|
||||
shells.Append(TopoDS::Shell(s));
|
||||
} else {
|
||||
logger::error("Expected shell type in layerset processing");
|
||||
Logger::Root().Error("GEO", 172, "Expected shell type in layerset processing");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -281,7 +284,7 @@ bool IfcGeom::util::apply_folded_layerset(const ConversionResults& items, const
|
||||
|
||||
}
|
||||
|
||||
bool IfcGeom::util::apply_layerset(const ConversionResults& items, const std::vector<Handle_Geom_Surface>& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles, ConversionResults& result, double tol) {
|
||||
bool IfcGeom::util::apply_layerset(const ConversionResults& items, const std::vector<opencascade::handle<Geom_Surface>>& surfaces, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles, ConversionResults& result, double tol) {
|
||||
if (surfaces.size() < 3) {
|
||||
|
||||
return false;
|
||||
@@ -336,7 +339,7 @@ bool IfcGeom::util::apply_layerset(const ConversionResults& items, const std::ve
|
||||
const TopoDS_Shape& s = std::static_pointer_cast<OpenCascadeShape>(it->Shape())->shape();
|
||||
TopoDS_Shape sld = ensure_fit_for_subtraction(s, tol);
|
||||
|
||||
TopTools_ListOfShape operands;
|
||||
NCollection_List<TopoDS_Shape> operands;
|
||||
for (unsigned i = 1; i < surfaces.size() - 1; ++i) {
|
||||
double u1, v1, u2, v2;
|
||||
if (!project(surfaces[i], sld, u1, v1, u2, v2)) {
|
||||
@@ -370,7 +373,7 @@ bool IfcGeom::util::apply_layerset(const ConversionResults& items, const std::ve
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::split_solid_by_surface(const TopoDS_Shape& input, const Handle_Geom_Surface& surface, TopoDS_Shape& front, TopoDS_Shape& back, double tol) {
|
||||
bool IfcGeom::util::split_solid_by_surface(const TopoDS_Shape& input, const opencascade::handle<Geom_Surface>& surface, TopoDS_Shape& front, TopoDS_Shape& back, double tol) {
|
||||
// Use an unbounded surface, that isolate part of the input shape,
|
||||
// to split this shape into two parts. Make sure that the addition
|
||||
// of the two result volumes matches that of the input.
|
||||
@@ -406,7 +409,7 @@ bool IfcGeom::util::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS
|
||||
}
|
||||
|
||||
#if OCC_VERSION_HEX >= 0x70300
|
||||
TopTools_ListOfShape shapes;
|
||||
NCollection_List<TopoDS_Shape> shapes;
|
||||
#else
|
||||
BOPCol_ListOfShape shapes;
|
||||
#endif
|
||||
@@ -433,12 +436,12 @@ bool IfcGeom::util::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
Logger::Root().Error("GEO", 173, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error performing fixes");
|
||||
Logger::Root().Error("GEO", 174, "Unknown error performing fixes");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error performing fixes");
|
||||
Logger::Root().Error("GEO", 175, "Unknown error performing fixes");
|
||||
}
|
||||
BRepCheck_Analyzer analyser(shape);
|
||||
bool is_valid = analyser.IsValid() != 0;
|
||||
@@ -448,7 +451,7 @@ bool IfcGeom::util::split_solid_by_shell(const TopoDS_Shape& input, const TopoDS
|
||||
}
|
||||
|
||||
if (is_null[0] || is_null[1]) {
|
||||
logger::message(logger::LOG_ERROR, "Null result obtained from layerset slicing");
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 176, "Null result obtained from layerset slicing");
|
||||
if (is_null[0] && is_null[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace util {
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>&, ConversionResults&, double tol);
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<opencascade::handle<Geom_Surface>>&, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>&, ConversionResults&, double tol);
|
||||
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>&, ConversionResults&, double tol);
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector<std::vector<opencascade::handle<Geom_Surface>>>&, const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>&, ConversionResults&, double tol);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&, double tol);
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const opencascade::handle<Geom_Surface>&, TopoDS_Shape&, TopoDS_Shape&, double tol);
|
||||
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&, double tol);
|
||||
}
|
||||
|
||||
@@ -82,16 +82,47 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re
|
||||
}
|
||||
|
||||
if (non_polygonal) {
|
||||
if (loft->children.size() == 2) {
|
||||
BRep_Builder BB;
|
||||
TopoDS_Shell comp;
|
||||
BB.MakeShell(comp);
|
||||
if (loft->children.size() < 2) {
|
||||
Logger::Root().Error("GEO", 177, "Not enough sections to loft");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TopoDS_Shape f0, f1;
|
||||
if (!convert(std::static_pointer_cast<taxonomy::face>(loft->children.front()), f0) ||
|
||||
!convert(std::static_pointer_cast<taxonomy::face>(loft->children.back()), f1))
|
||||
{
|
||||
TopoDS_Shape f0, f1;
|
||||
|
||||
// Convert all children to vectors of wires
|
||||
for (const auto& child : loft->children) {
|
||||
TopoDS_Shape shape;
|
||||
if (!convert(std::static_pointer_cast<taxonomy::face>(child), shape)) {
|
||||
return false;
|
||||
}
|
||||
if (shape.ShapeType() != TopAbs_FACE) {
|
||||
return false;
|
||||
}
|
||||
// At least make sure to have outer wire consistent, but in reality
|
||||
// this is probably not a concern given how to build up these faces
|
||||
auto f = TopoDS::Face(shape);
|
||||
|
||||
if (child == loft->children.front()) {
|
||||
f0 = f;
|
||||
} else if (child == loft->children.back()) {
|
||||
f1 = f;
|
||||
}
|
||||
|
||||
auto outer = BRepTools::OuterWire(f);
|
||||
sections.emplace_back();
|
||||
sections.back().push_back(outer);
|
||||
for (TopoDS_Iterator it(f); it.More(); it.Next()) {
|
||||
if (outer != it.Value()) {
|
||||
sections.back().push_back(TopoDS::Wire(it.Value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto first_wire_count = sections.front().size();
|
||||
for (auto& section : sections) {
|
||||
if (section.size() != first_wire_count) {
|
||||
Logger::Root().Error("GEO", 178, "Inconsistent number of wires in sections");
|
||||
return false;
|
||||
}
|
||||
if (f0.ShapeType() != TopAbs_FACE || f1.ShapeType() != TopAbs_FACE) {
|
||||
@@ -127,7 +158,7 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_ListOfShape faces;
|
||||
NCollection_List<TopoDS_Shape> faces;
|
||||
TopoDS_Compound comp;
|
||||
BRep_Builder BB;
|
||||
BB.MakeCompound(comp);
|
||||
@@ -237,6 +268,18 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re
|
||||
return true;
|
||||
*/
|
||||
|
||||
if (shps.size() < 2) {
|
||||
Logger::Root().Error("GEO", 179, "Not enough sections to loft");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (shps[0].ShapeType() == TopAbs_FACE) {
|
||||
// When processing a sectioned *surface* there are no
|
||||
// begin and end caps that need to be added.
|
||||
BB.Add(comp, shps.front().Reversed());
|
||||
BB.Add(comp, shps.back());
|
||||
}
|
||||
|
||||
// @todo this approach is
|
||||
// potentially incorrect as there is no guarantee that the wires for
|
||||
// subsequently placed profiles are traversed from an equivalent start vertex.
|
||||
@@ -284,7 +327,7 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re
|
||||
all_tags.begin() + std::distance(shps.begin(), jt)};
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape ancestors;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> ancestors;
|
||||
const auto& wire = wp[i];
|
||||
auto& result = profile_points[i];
|
||||
|
||||
@@ -305,9 +348,9 @@ bool OpenCascadeKernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape& re
|
||||
break;
|
||||
}
|
||||
|
||||
const TopTools_ListOfShape& incidentEdges = ancestors.FindFromKey(curr);
|
||||
const NCollection_List<TopoDS_Shape>& incidentEdges = ancestors.FindFromKey(curr);
|
||||
|
||||
for (TopTools_ListIteratorOfListOfShape it(incidentEdges); it.More(); it.Next()) {
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator it(incidentEdges); it.More(); it.Next()) {
|
||||
const TopoDS_Edge& e = TopoDS::Edge(it.Value());
|
||||
|
||||
TopoDS_Vertex ev0, ev1;
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
|
||||
@@ -39,12 +40,12 @@ namespace {
|
||||
|
||||
const bool is_rational = !!bc->weights;
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, bc->control_points.size() - 1);
|
||||
TColStd_Array1OfReal Weights(0, bc->control_points.size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)bc->knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)bc->knots.size() - 1);
|
||||
Standard_Integer Degree = bc->degree;
|
||||
Standard_Boolean Periodic = false;
|
||||
NCollection_Array1<gp_Pnt> Poles(0, (int)bc->control_points.size() - 1);
|
||||
NCollection_Array1<double> Weights(0, (int)bc->control_points.size() - 1);
|
||||
NCollection_Array1<double> Knots(0, (int)bc->knots.size() - 1);
|
||||
NCollection_Array1<int> Mults(0, (int)bc->knots.size() - 1);
|
||||
int Degree = bc->degree;
|
||||
bool Periodic = false;
|
||||
// @tfk: it appears to be wrong to expect a period curve when the curve is closed, see #586
|
||||
// Standard_Boolean Periodic = l->ClosedCurve();
|
||||
|
||||
@@ -129,8 +130,8 @@ namespace {
|
||||
} else {
|
||||
// @todo
|
||||
const double precision_ = 1.e-5;
|
||||
logger::warning("Approximating BasisCurve due to possible discontinuities", e->instance);
|
||||
const auto& w = std::get<TopoDS_Wire>(crv_or_wire);
|
||||
Logger::Root().Warning("GEO", 180, "Approximating BasisCurve due to possible discontinuities", e->instance);
|
||||
const auto& w = boost::get<TopoDS_Wire>(crv_or_wire);
|
||||
#if OCC_VERSION_HEX < 0x70600
|
||||
BRepAdaptor_CompCurve cc(w, true);
|
||||
Handle(Adaptor3d_HCurve) hcc = Handle(Adaptor3d_HCurve)(new BRepAdaptor_HCompCurve(cc));
|
||||
@@ -233,7 +234,7 @@ OpenCascadeKernel::curve_creation_visitor_result_type OpenCascadeKernel::convert
|
||||
#include "../../../ifcparse/file.h"
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::loop::ptr loop, TopoDS_Wire& wire) {
|
||||
TopTools_ListOfShape converted_segments;
|
||||
NCollection_List<TopoDS_Shape> converted_segments;
|
||||
|
||||
/*
|
||||
if (loop->tags) {
|
||||
@@ -283,14 +284,14 @@ bool OpenCascadeKernel::convert(const taxonomy::loop::ptr loop, TopoDS_Wire& wir
|
||||
}
|
||||
|
||||
if (converted_segments.Extent() == 0) {
|
||||
logger::message(logger::LOG_ERROR, "No segment successfully converted:", loop->instance);
|
||||
Logger::Root().Message(Logger::LOG_ERROR, "GEO", 181, "No segment successfully converted:", loop->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(converted_segments);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(converted_segments);
|
||||
|
||||
bool force_close = false;
|
||||
if (loop->instance && loop->instance.as<express::Entity>()) {
|
||||
@@ -304,10 +305,10 @@ bool OpenCascadeKernel::convert(const taxonomy::loop::ptr loop, TopoDS_Wire& wir
|
||||
shape_pair_enumerate(it, bld, force_close);
|
||||
wire = bld.wire();
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
|
||||
TopTools_IndexedMapOfShape edges_to_tesselate;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> edges_to_tesselate;
|
||||
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
auto& edges = map.FindFromIndex(i);
|
||||
@@ -348,7 +349,7 @@ bool OpenCascadeKernel::convert(const taxonomy::loop::ptr loop, TopoDS_Wire& wir
|
||||
|
||||
if (ang < 0.0314) {
|
||||
edges_to_tesselate.Add(crv1->DynamicType() == STANDARD_TYPE(Geom_Circle) ? edges.First() : edges.Last());
|
||||
logger::notice("Sharp circular corner detecting, substituting with linear approximation");
|
||||
Logger::Root().Notice("GEO", 182, "Sharp circular corner detecting, substituting with linear approximation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap
|
||||
? (faceset_helper_->epsilon() * faceset_helper_->epsilon() / 20.)
|
||||
: minimal_face_area;
|
||||
|
||||
TopTools_ListOfShape face_list;
|
||||
NCollection_List<TopoDS_Shape> face_list;
|
||||
for (auto& face : l->children) {
|
||||
bool success = false;
|
||||
TopoDS_Face occ_face;
|
||||
@@ -46,19 +46,19 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap
|
||||
try {
|
||||
success = convert(face, occ_face);
|
||||
} catch (const std::exception& e) {
|
||||
logger::error(e);
|
||||
logger_.Error("GEO", 194, e);
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
logger_.Error("GEO", 195, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error creating face");
|
||||
logger_.Error("GEO", 196, "Unknown error creating face");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error creating face");
|
||||
logger_.Error("GEO", 197, "Unknown error creating face");
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
logger::message(logger::LOG_WARNING, "Failed to convert face:", face->instance);
|
||||
logger_.Message(Logger::LOG_WARNING, "GEO", 198, "Failed to convert face:", face->instance);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap
|
||||
if (face_area(triangle) > min_face_area) {
|
||||
face_list.Append(triangle);
|
||||
} else {
|
||||
logger::message(logger::LOG_WARNING, "Degenerate face:", face->instance);
|
||||
logger_.Message(Logger::LOG_WARNING, "GEO", 199, "Degenerate face:", face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap
|
||||
if (face_area(occ_face) > min_face_area) {
|
||||
face_list.Append(occ_face);
|
||||
} else {
|
||||
logger::message(logger::LOG_WARNING, "Degenerate face:", face->instance);
|
||||
logger_.Message(Logger::LOG_WARNING, "GEO", 200, "Degenerate face:", face->instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
TopTools_ListIteratorOfListOfShape face_iterator;
|
||||
NCollection_List<TopoDS_Shape>::Iterator face_iterator;
|
||||
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
|
||||
builder.Add(compound, face_iterator.Value());
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ bool OpenCascadeKernel::convert(const taxonomy::solid::ptr solid, TopoDS_Shape&
|
||||
throw std::runtime_error("Unexpected configuration of subshapes");
|
||||
}
|
||||
} else {
|
||||
logger::warning("Ignored shell", s->instance);
|
||||
logger_.Warning("GEO", 201, "Ignored shell", s->instance);
|
||||
}
|
||||
}
|
||||
if (!S.IsNull()) {
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace {
|
||||
bool wire_is_c1_continuous(const TopoDS_Wire& w, double tol) {
|
||||
// NB Note that c0 continuity is NOT checked!
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
const auto& li = map.FindFromIndex(i);
|
||||
@@ -129,8 +129,8 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
|
||||
}
|
||||
|
||||
auto w = convert_curve(scs->curve);
|
||||
if (w.index() != 2) {
|
||||
logger::error("Unsupported directrix");
|
||||
if (w.which() != 2) {
|
||||
logger_.Error("UNS", 9, "Unsupported directrix");
|
||||
return false;
|
||||
}
|
||||
TopoDS_Shape face_;
|
||||
@@ -178,7 +178,7 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
|
||||
for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) {
|
||||
if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) {
|
||||
directrix_on_plane = false;
|
||||
logger::message(logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", scs->instance);
|
||||
logger_.Message(Logger::LOG_WARNING, "GEO", 202, "The Directrix does not lie on the ReferenceSurface", scs->instance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
|
||||
{
|
||||
TopoDS_Vertex v0, v1;
|
||||
TopExp::Vertices(wire, v0, v1);
|
||||
TopTools_IndexedDataMapOfShapeListOfShape m;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> m;
|
||||
TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, m);
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(m.FindFromKey(v0).First());
|
||||
double u0, u1;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
bool IfcGeom::util::wire_is_c1_continuous(const TopoDS_Wire & w, double tol) {
|
||||
// NB Note that c0 continuity is NOT checked!
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
const auto& li = map.FindFromIndex(i);
|
||||
@@ -66,7 +66,7 @@ bool IfcGeom::util::wire_to_ax(const TopoDS_Wire & wire, gp_Ax2 & directrix) {
|
||||
// Find first edge
|
||||
TopoDS_Vertex v0, v1;
|
||||
TopExp::Vertices(wire, v0, v1);
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
if (v0.IsSame(v1) && map.Contains(v0) && map.FindFromKey(v0).Extent() == 2) {
|
||||
// Closed wire, with more than 1 edges
|
||||
@@ -97,7 +97,7 @@ bool IfcGeom::util::wire_to_ax(const TopoDS_Wire & wire, gp_Ax2 & directrix) {
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1);
|
||||
crv->D1(u0, directrix_origin, directrix_tangent);
|
||||
} else {
|
||||
logger::error("Unable to locate first edge");
|
||||
Logger::Root().Error("GEO", 203, "Unable to locate first edge");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ bool IfcGeom::util::is_single_linear_edge(const TopoDS_Wire & wire) {
|
||||
return false;
|
||||
}
|
||||
double u, v;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, u, v);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, u, v);
|
||||
return crv->DynamicType() == STANDARD_TYPE(Geom_Line);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ bool IfcGeom::util::is_single_circular_edge(const TopoDS_Wire & wire) {
|
||||
return false;
|
||||
}
|
||||
double u, v;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, u, v);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, u, v);
|
||||
return crv->DynamicType() == STANDARD_TYPE(Geom_Circle);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ void IfcGeom::util::process_sweep_as_extrusion(const TopoDS_Wire & wire, const T
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
TopoDS_Edge e = TopoDS::Edge(exp.Current());
|
||||
double u, v;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, u, v);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, u, v);
|
||||
const auto& dir = Handle(Geom_Line)::DownCast(crv)->Position().Direction();
|
||||
// OCCT line is normalized so diff in parametric coords equals length
|
||||
const double depth = std::abs(u - v);
|
||||
@@ -153,7 +153,7 @@ void IfcGeom::util::process_sweep_as_revolution(const TopoDS_Wire & wire, const
|
||||
TopExp_Explorer exp(wire, TopAbs_EDGE);
|
||||
TopoDS_Edge e = TopoDS::Edge(exp.Current());
|
||||
double u, v;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, u, v);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, u, v);
|
||||
auto circ = Handle(Geom_Circle)::DownCast(crv);
|
||||
// @todo we could be extruding the wire only when we know this is an intermediate edge.
|
||||
const double depth = std::abs(u - v);
|
||||
@@ -182,12 +182,12 @@ void IfcGeom::util::process_sweep_as_pipe(const TopoDS_Wire & wire, const TopoDS
|
||||
}
|
||||
|
||||
void IfcGeom::util::sort_edges(const TopoDS_Wire & wire, std::vector<TopoDS_Edge>& sorted_edges) {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(wire, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
|
||||
for (int i = 1; i <= map.Extent(); ++i) {
|
||||
if (map.FindFromIndex(i).Extent() > 2) {
|
||||
logger::warning("Self-intersecting Directrix");
|
||||
Logger::Root().Warning("GEO", 204, "Self-intersecting Directrix");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,9 +209,9 @@ void IfcGeom::util::sort_edges(const TopoDS_Wire & wire, std::vector<TopoDS_Edge
|
||||
if (!map.Contains(v0)) {
|
||||
throw std::runtime_error("Disconnected vertex");
|
||||
}
|
||||
const TopTools_ListOfShape& es = map.FindFromKey(v0);
|
||||
const NCollection_List<TopoDS_Shape>& es = map.FindFromKey(v0);
|
||||
TopoDS_Vertex ve0, ve1;
|
||||
TopTools_ListIteratorOfListOfShape it(es);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(es);
|
||||
bool added = false;
|
||||
for (; it.More(); it.Next()) {
|
||||
const TopoDS_Edge& e = TopoDS::Edge(it.Value());
|
||||
@@ -269,7 +269,7 @@ void IfcGeom::util::segment_adjacent_non_linear(const TopoDS_Wire & wire, std::v
|
||||
|
||||
for (int i = 0; i < (int)sorted_edges.size() - 1; ++i) {
|
||||
const auto& e = sorted_edges[i];
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, u, v);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, u, v);
|
||||
const bool is_linear = crv->DynamicType() == STANDARD_TYPE(Geom_Line);
|
||||
|
||||
const auto& f = sorted_edges[i + 1];
|
||||
|
||||
@@ -18,20 +18,21 @@
|
||||
TopoDS_Edge IfcGeom::util::first_edge(const TopoDS_Wire & w) {
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(w, v1, v2);
|
||||
TopTools_IndexedDataMapOfShapeListOfShape wm;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> wm;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, wm);
|
||||
return TopoDS::Edge(wm.FindFromKey(v1).First());
|
||||
}
|
||||
|
||||
// Returns new wire with the edge replaced by a linear edge with the vertex v moved to p
|
||||
TopoDS_Wire IfcGeom::util::adjust(const TopoDS_Wire & w, const TopoDS_Vertex & v, const gp_Pnt & p) {
|
||||
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> map;
|
||||
TopExp::MapShapesAndAncestors(w, TopAbs_VERTEX, TopAbs_EDGE, map);
|
||||
|
||||
bool all_linear = true, single_circle = false, first = true;
|
||||
|
||||
const TopTools_ListOfShape& edges = map.FindFromKey(v);
|
||||
TopTools_ListIteratorOfListOfShape it(edges);
|
||||
const NCollection_List<TopoDS_Shape>& edges = map.FindFromKey(v);
|
||||
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(edges);
|
||||
for (; it.More(); it.Next()) {
|
||||
const TopoDS_Edge& e = TopoDS::Edge(it.Value());
|
||||
double _, __;
|
||||
@@ -81,7 +82,7 @@ double IfcGeom::util::deflection_for_approximating_circle(double radius, double
|
||||
return -radius * std::cos(1. / 2. * param) * std::cos(param) - radius * std::sin(1. / 2. * param) * std::sin(param) + radius;
|
||||
}
|
||||
|
||||
bool IfcGeom::util::create_edge_over_curve_with_log_messages(const Handle_Geom_Curve & crv, const double eps, const gp_Pnt & p1, const gp_Pnt & p2, TopoDS_Edge & result) {
|
||||
bool IfcGeom::util::create_edge_over_curve_with_log_messages(const opencascade::handle<Geom_Curve>& crv, const double eps, const gp_Pnt& p1, const gp_Pnt& p2, TopoDS_Edge& result) {
|
||||
if (crv->IsClosed() && p1.Distance(p2) <= eps) {
|
||||
BRepBuilderAPI_MakeEdge me(crv);
|
||||
if (me.IsDone()) {
|
||||
@@ -116,12 +117,12 @@ bool IfcGeom::util::create_edge_over_curve_with_log_messages(const Handle_Geom_C
|
||||
}
|
||||
}
|
||||
if (dmin == std::numeric_limits<double>::infinity()) {
|
||||
logger::error("No extrema for point");
|
||||
Logger::Root().Error("GEO", 205, "No extrema for point");
|
||||
} else if (dmin > eps2) {
|
||||
logger::error("Distance of " + boost::lexical_cast<std::string>(std::sqrt(dmin)) + " exceeds tolerance");
|
||||
Logger::Root().Error("GEO", 206, "Distance of " + boost::lexical_cast<std::string>(std::sqrt(dmin)) + " exceeds tolerance");
|
||||
}
|
||||
} else {
|
||||
logger::error("Failed to calculate extrema for point");
|
||||
Logger::Root().Error("GEO", 207, "Failed to calculate extrema for point");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,19 +172,19 @@ void IfcGeom::util::wire_builder::operator()(const TopoDS_Shape& a, const TopoDS
|
||||
if (dist > 1000. * p_) {
|
||||
mw_.Add(w1);
|
||||
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
logger::warning("Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
Logger::Root().Warning("GEO", 208, "Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
goto check;
|
||||
}
|
||||
|
||||
{
|
||||
TopTools_IndexedDataMapOfShapeListOfShape wmap1, wmap2;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> wmap1, wmap2;
|
||||
|
||||
// Find edges connected to end- and begin vertex
|
||||
TopExp::MapShapesAndAncestors(w1, TopAbs_VERTEX, TopAbs_EDGE, wmap1);
|
||||
TopExp::MapShapesAndAncestors(w2, TopAbs_VERTEX, TopAbs_EDGE, wmap2);
|
||||
|
||||
const TopTools_ListOfShape& last_edges = wmap1.FindFromKey(w12);
|
||||
const TopTools_ListOfShape& first_edges = wmap2.FindFromKey(w21);
|
||||
const NCollection_List<TopoDS_Shape>& last_edges = wmap1.FindFromKey(w12);
|
||||
const NCollection_List<TopoDS_Shape>& first_edges = wmap2.FindFromKey(w21);
|
||||
|
||||
double _, __;
|
||||
if (last_edges.Extent() == 1 && first_edges.Extent() == 1) {
|
||||
@@ -199,28 +200,28 @@ void IfcGeom::util::wire_builder::operator()(const TopoDS_Shape& a, const TopoDS
|
||||
// Preferably adjust the segment that is linear
|
||||
if (is_line1 || (is_circle1 && !is_line2)) {
|
||||
mw_.Add(adjust(w1, w12, p2));
|
||||
logger::notice("Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
Logger::Root().Notice("GEO", 209, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
} else if ((is_line2 || is_circle2) && !last) {
|
||||
mw_.Add(w1);
|
||||
override_next_ = true;
|
||||
next_override_ = p1;
|
||||
logger::notice("Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
Logger::Root().Notice("GEO", 210, "Adjusted edge end-point with distance " + boost::lexical_cast<std::string>(dist) + " on:", inst_);
|
||||
} else {
|
||||
// In all other cases an edge is added
|
||||
mw_.Add(w1);
|
||||
mw_.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
logger::warning("Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
Logger::Root().Warning("GEO", 211, "Added additional segment to close gap with length " + boost::lexical_cast<std::string>(dist) + " to:", inst_);
|
||||
}
|
||||
} else {
|
||||
logger::error("Internal error, inconsistent wire segments", inst_);
|
||||
Logger::Root().Error("GEO", 212, "Internal error, inconsistent wire segments", inst_);
|
||||
mw_.Add(w1);
|
||||
}
|
||||
}
|
||||
|
||||
check:
|
||||
if (mw_.Error() == BRepBuilderAPI_NonManifoldWire) {
|
||||
logger::error("Non-manifold curve segments:", inst_);
|
||||
Logger::Root().Error("GEO", 213, "Non-manifold curve segments:", inst_);
|
||||
} else if (mw_.Error() == BRepBuilderAPI_DisconnectedWire) {
|
||||
logger::error("Failed to join curve segments:", inst_);
|
||||
Logger::Root().Error("GEO", 214, "Failed to join curve segments:", inst_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
template <typename Fn>
|
||||
void shape_pair_enumerate(TopTools_ListIteratorOfListOfShape& it, Fn& fn, bool closed) {
|
||||
void shape_pair_enumerate(NCollection_List<TopoDS_Shape>::Iterator& it, Fn& fn, bool closed) {
|
||||
bool is_first = true;
|
||||
TopoDS_Shape first, previous, current;
|
||||
for (; it.More(); it.Next(), is_first = false) {
|
||||
@@ -98,7 +98,7 @@ namespace IfcGeom {
|
||||
|
||||
double deflection_for_approximating_circle(double radius, double param);
|
||||
|
||||
bool create_edge_over_curve_with_log_messages(const Handle_Geom_Curve& crv, const double eps, const gp_Pnt& p1, const gp_Pnt& p2, TopoDS_Edge& result);
|
||||
bool create_edge_over_curve_with_log_messages(const opencascade::handle<Geom_Curve>& crv, const double eps, const gp_Pnt& p1, const gp_Pnt& p2, TopoDS_Edge& result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,11 @@
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
|
||||
#include <ShapeExtend_WireData.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include <GeomAPI_ExtremaCurveCurve.hxx>
|
||||
@@ -86,7 +90,7 @@ bool IfcGeom::util::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_P
|
||||
// obtaining a 2d points for the Delaunay, infinity is passed here, so this
|
||||
// can't for assessing degenerativeness.
|
||||
if (v.Magnitude() < 1.e-7) {
|
||||
logger::warning("Degenerate face boundary in normal estimation");
|
||||
Logger::Root().Warning("GEO", 215, "Degenerate face boundary in normal estimation");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,7 +120,7 @@ bool IfcGeom::util::flatten_wire(TopoDS_Wire& wire, double eps) {
|
||||
if (!proj.IsDone()) {
|
||||
return false;
|
||||
}
|
||||
TopTools_ListOfShape list;
|
||||
NCollection_List<TopoDS_Shape> list;
|
||||
proj.BuildWire(list);
|
||||
if (list.Extent() != 1) {
|
||||
return false;
|
||||
@@ -125,7 +129,7 @@ bool IfcGeom::util::flatten_wire(TopoDS_Wire& wire, double eps) {
|
||||
return true;
|
||||
}
|
||||
|
||||
IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std::vector<TopoDS_Wire>& wires, TopTools_ListOfShape& faces) {
|
||||
IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std::vector<TopoDS_Wire>& wires, NCollection_List<TopoDS_Shape>& faces) {
|
||||
// This is a bit of a precarious approach, but seems to work for the
|
||||
// versions of OCCT tested for. OCCT has a Delaunay triangulation function
|
||||
// BRepMesh_Delaun, but it is notoriously hard to interpret the results
|
||||
@@ -210,11 +214,11 @@ IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std
|
||||
|
||||
int n123[3];
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
opencascade::handle<Poly_Triangulation> tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
const NCollection_Array1<Poly_Triangle>& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
triangles(i).Get(n123[2], n123[1], n123[0]);
|
||||
@@ -233,7 +237,7 @@ IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std
|
||||
|
||||
auto it = mapping.find(uvnodes[k]);
|
||||
if (it == mapping.end()) {
|
||||
logger::error("Internal error: unable to unproject uv-mesh");
|
||||
Logger::Root().Error("GEO", 216, "Internal error: unable to unproject uv-mesh");
|
||||
return TRIANGULATE_WIRE_FAIL;
|
||||
}
|
||||
|
||||
@@ -277,17 +281,17 @@ IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std
|
||||
}
|
||||
faces.Append(triangle_face);
|
||||
} else {
|
||||
logger::error("Internal error: missing face");
|
||||
Logger::Root().Error("GEO", 217, "Internal error: missing face");
|
||||
return TRIANGULATE_WIRE_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape mape, mapn;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> mape, mapn;
|
||||
for (auto& wire : wires) {
|
||||
TopExp::MapShapesAndAncestors(wire, TopAbs_EDGE, TopAbs_WIRE, mape);
|
||||
}
|
||||
TopTools_ListIteratorOfListOfShape it(faces);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(faces);
|
||||
for (; it.More(); it.Next()) {
|
||||
TopExp::MapShapesAndAncestors(it.Value(), TopAbs_EDGE, TopAbs_WIRE, mapn);
|
||||
}
|
||||
@@ -297,18 +301,18 @@ IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std
|
||||
|
||||
for (int i = 1; i <= mape.Extent(); ++i) {
|
||||
#if OCC_VERSION_HEX >= 0x70000
|
||||
TopTools_ListOfShape val;
|
||||
NCollection_List<TopoDS_Shape> val;
|
||||
if (!mapn.FindFromKey(mape.FindKey(i), val)) {
|
||||
#else
|
||||
bool contains = false;
|
||||
try {
|
||||
TopTools_ListOfShape val = mapn.FindFromKey(mape.FindKey(i));
|
||||
NCollection_List<TopoDS_Shape> val = mapn.FindFromKey(mape.FindKey(i));
|
||||
contains = true;
|
||||
} catch (Standard_NoSuchObject&) {}
|
||||
if (!contains) {
|
||||
#endif
|
||||
// All existing edges need to exist in the new faces
|
||||
logger::error("Internal error, missing edge from triangulation");
|
||||
Logger::Root().Error("GEO", 218, "Internal error, missing edge from triangulation");
|
||||
non_manifold = true;
|
||||
}
|
||||
}
|
||||
@@ -319,7 +323,7 @@ IfcGeom::util::triangulate_wire_result IfcGeom::util::triangulate_wire(const std
|
||||
// Existing edges are boundaries with use 1
|
||||
// New edges are internal with use 2
|
||||
if (n != (mape.Contains(v) ? 1 : 2)) {
|
||||
logger::error("Internal error, non-manifold result from triangulation");
|
||||
Logger::Root().Error("GEO", 219, "Internal error, non-manifold result from triangulation");
|
||||
non_manifold = true;
|
||||
}
|
||||
}
|
||||
@@ -374,7 +378,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings) {
|
||||
bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, NCollection_List<TopoDS_Shape>& wires, const wire_tolerance_settings& settings) {
|
||||
double eps = get_wire_intersection_tolerance(settings, wire);
|
||||
double eps_real = settings.precision;
|
||||
|
||||
@@ -508,7 +512,7 @@ bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfS
|
||||
// Substitute with a new edge from/to the intersection point
|
||||
if (p1.Distance(p2) > eps_real * 2) {
|
||||
double _, __;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, _, __);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(e, _, __);
|
||||
BRepBuilderAPI_MakeEdge me(crv, p1, p2);
|
||||
TopoDS_Edge ed = me.Edge();
|
||||
mw.Add(ed);
|
||||
@@ -557,9 +561,9 @@ bool IfcGeom::util::wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfS
|
||||
return intersected;
|
||||
}
|
||||
|
||||
void IfcGeom::util::select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest) {
|
||||
void IfcGeom::util::select_largest(const NCollection_List<TopoDS_Shape>& shapes, TopoDS_Shape& largest) {
|
||||
double mass = 0.;
|
||||
TopTools_ListIteratorOfListOfShape it(shapes);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(shapes);
|
||||
for (; it.More(); it.Next()) {
|
||||
/*
|
||||
// tfk: bounding box is more efficient probably
|
||||
@@ -597,11 +601,11 @@ void IfcGeom::util::select_largest(const TopTools_ListOfShape& shapes, TopoDS_Sh
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_SequenceOfPnt& p) {
|
||||
bool IfcGeom::util::wire_to_sequence_of_point(const TopoDS_Wire& w, NCollection_Sequence<gp_Pnt>& 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);
|
||||
opencascade::handle<Geom_Curve> crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
return false;
|
||||
}
|
||||
@@ -624,7 +628,7 @@ bool IfcGeom::util::wire_to_sequence_of_point(const TopoDS_Wire& w, TColgp_Seque
|
||||
return true;
|
||||
}
|
||||
|
||||
void IfcGeom::util::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, TopoDS_Wire& w, bool close) {
|
||||
void IfcGeom::util::sequence_of_point_to_wire(const NCollection_Sequence<gp_Pnt>& p, TopoDS_Wire& w, bool close) {
|
||||
BRepBuilderAPI_MakePolygon builder;
|
||||
for (int i = 1; i <= p.Length(); ++i) {
|
||||
builder.Add(p.Value(i));
|
||||
@@ -635,7 +639,7 @@ void IfcGeom::util::sequence_of_point_to_wire(const TColgp_SequenceOfPnt& p, Top
|
||||
w = builder.Wire();
|
||||
}
|
||||
|
||||
void IfcGeom::util::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||
void IfcGeom::util::remove_collinear_points_from_loop(NCollection_Sequence<gp_Pnt>& 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);
|
||||
@@ -659,7 +663,7 @@ void IfcGeom::util::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& poly
|
||||
}
|
||||
}
|
||||
|
||||
void IfcGeom::util::remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
|
||||
void IfcGeom::util::remove_duplicate_points_from_loop(NCollection_Sequence<gp_Pnt>& polygon, bool closed, double tol) {
|
||||
tol *= tol;
|
||||
|
||||
for (;;) {
|
||||
@@ -697,9 +701,9 @@ namespace {
|
||||
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;
|
||||
TopoDS_Edge find_next(const NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>& edge_set, const NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher>& vertex_to_edges, const TopoDS_Vertex& current, const TopoDS_Edge& previous_edge) {
|
||||
const NCollection_List<TopoDS_Shape>& edges = vertex_to_edges.FindFromKey(current);
|
||||
NCollection_List<TopoDS_Shape>::Iterator eit;
|
||||
for (eit.Initialize(edges); eit.More(); eit.Next()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(eit.Value());
|
||||
if (edge.IsSame(previous_edge)) continue;
|
||||
@@ -716,16 +720,16 @@ bool IfcGeom::util::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape
|
||||
BRepOffsetAPI_Sewing sew;
|
||||
sew.Add(shape);
|
||||
|
||||
TopTools_IndexedDataMapOfShapeListOfShape edge_to_faces;
|
||||
TopTools_IndexedDataMapOfShapeListOfShape vertex_to_edges;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> edge_to_faces;
|
||||
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> vertex_to_edges;
|
||||
std::set<int> visited;
|
||||
TopTools_IndexedMapOfShape edge_set;
|
||||
NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher> 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 NCollection_List<TopoDS_Shape>& 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.
|
||||
@@ -790,30 +794,30 @@ bool IfcGeom::util::fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape
|
||||
shape = solid.SolidFromShell(TopoDS::Shell(shape));
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
logger::error(e.GetMessageString());
|
||||
Logger::Root().Error("GEO", 220, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error creating solid");
|
||||
Logger::Root().Error("GEO", 221, "Unknown error creating solid");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error creating solid");
|
||||
Logger::Root().Error("GEO", 222, "Unknown error creating solid");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IfcGeom::util::convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire) {
|
||||
bool IfcGeom::util::convert_curve_to_wire(const opencascade::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());
|
||||
Logger::Root().Error("GEO", 223, e.GetMessageString());
|
||||
} else {
|
||||
logger::error("Unknown error converting curve to wire");
|
||||
Logger::Root().Error("GEO", 224, "Unknown error converting curve to wire");
|
||||
}
|
||||
} catch (...) {
|
||||
logger::error("Unknown error converting curve to wire");
|
||||
Logger::Root().Error("GEO", 225, "Unknown error converting curve to wire");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -834,17 +838,17 @@ void IfcGeom::util::assert_closed_wire(TopoDS_Wire& wire, double tol) {
|
||||
wire = mw.Wire();
|
||||
}
|
||||
|
||||
logger::warning("Wire not closed");
|
||||
Logger::Root().Warning("GEO", 226, "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;
|
||||
NCollection_List<TopoDS_Shape> 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");
|
||||
Logger::Root().Warning("GEO", 227, "Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
util::select_largest(results, wire);
|
||||
}
|
||||
|
||||
@@ -875,7 +879,7 @@ bool IfcGeom::util::convert_wire_to_face(const TopoDS_Wire& w, TopoDS_Face& face
|
||||
BRepBuilderAPI_FaceError er = mf.Error();
|
||||
|
||||
if (er != BRepBuilderAPI_FaceDone) {
|
||||
logger::error("Failed to create face.");
|
||||
Logger::Root().Error("GEO", 228, "Failed to create face.");
|
||||
return false;
|
||||
}
|
||||
face = mf.Face();
|
||||
@@ -900,9 +904,9 @@ bool IfcGeom::util::convert_wire_to_faces(const TopoDS_Wire& w, TopoDS_Compound&
|
||||
}
|
||||
}
|
||||
|
||||
TopTools_ListOfShape results;
|
||||
NCollection_List<TopoDS_Shape> 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");
|
||||
Logger::Root().Warning("GEO", 229, "Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected");
|
||||
} else {
|
||||
results.Clear();
|
||||
results.Append(w);
|
||||
@@ -915,7 +919,7 @@ bool IfcGeom::util::convert_wire_to_faces(const TopoDS_Wire& w, TopoDS_Compound&
|
||||
std::list<std::pair<double, TopoDS_Face>> face_list;
|
||||
double max_area = 0.;
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(results);
|
||||
NCollection_List<TopoDS_Shape>::Iterator it(results);
|
||||
for (; it.More(); it.Next()) {
|
||||
const TopoDS_Wire& wire = TopoDS::Wire(it.Value());
|
||||
if (!is_2d) {
|
||||
@@ -928,7 +932,7 @@ bool IfcGeom::util::convert_wire_to_faces(const TopoDS_Wire& w, TopoDS_Compound&
|
||||
BRepBuilderAPI_FaceError er = mf.Error();
|
||||
|
||||
if (er != BRepBuilderAPI_FaceDone) {
|
||||
logger::error("Failed to create face.");
|
||||
Logger::Root().Error("GEO", 230, "Failed to create face.");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -945,7 +949,7 @@ bool IfcGeom::util::convert_wire_to_faces(const TopoDS_Wire& w, TopoDS_Compound&
|
||||
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));
|
||||
Logger::Root().Warning("GEO", 231, "Ignoring self-intersection loop with area " + boost::lexical_cast<std::string>(p.first));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <NCollection_Sequence.hxx>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -37,11 +38,11 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
/// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire.
|
||||
IFC_GEOMLIBRARY_API triangulate_wire_result triangulate_wire(const std::vector<TopoDS_Wire>& wires, TopTools_ListOfShape& faces);
|
||||
IFC_GEOMLIBRARY_API triangulate_wire_result triangulate_wire(const std::vector<TopoDS_Wire>& wires, NCollection_List<TopoDS_Shape>& faces);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings);
|
||||
IFC_GEOMLIBRARY_API bool wire_intersections(const TopoDS_Wire& wire, NCollection_List<TopoDS_Shape>& wires, const wire_tolerance_settings& settings);
|
||||
|
||||
IFC_GEOMLIBRARY_API void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest);
|
||||
IFC_GEOMLIBRARY_API void select_largest(const NCollection_List<TopoDS_Shape>& shapes, TopoDS_Shape& largest);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face, const IfcGeom::util::wire_tolerance_settings& settings);
|
||||
|
||||
@@ -50,12 +51,12 @@ namespace IfcGeom {
|
||||
IFC_GEOMLIBRARY_API void assert_closed_wire(TopoDS_Wire& wire, double tol);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape, double tol);
|
||||
IFC_GEOMLIBRARY_API void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol);
|
||||
IFC_GEOMLIBRARY_API void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol);
|
||||
IFC_GEOMLIBRARY_API bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||
IFC_GEOMLIBRARY_API void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||
IFC_GEOMLIBRARY_API void remove_duplicate_points_from_loop(NCollection_Sequence<gp_Pnt>& polygon, bool closed, double tol);
|
||||
IFC_GEOMLIBRARY_API void remove_collinear_points_from_loop(NCollection_Sequence<gp_Pnt>& polygon, bool closed, double tol);
|
||||
IFC_GEOMLIBRARY_API bool wire_to_sequence_of_point(const TopoDS_Wire&, NCollection_Sequence<gp_Pnt>&);
|
||||
IFC_GEOMLIBRARY_API void sequence_of_point_to_wire(const NCollection_Sequence<gp_Pnt>&, TopoDS_Wire&, bool closed);
|
||||
|
||||
IFC_GEOMLIBRARY_API bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
IFC_GEOMLIBRARY_API bool convert_curve_to_wire(const opencascade::handle<Geom_Curve>& curve, TopoDS_Wire& wire);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user