Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu

This commit is contained in:
Thomas Krijnen
2026-07-09 13:21:39 +02:00
373 changed files with 22411 additions and 4242 deletions
+23 -8
View File
@@ -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; }
+45 -42
View File
@@ -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;
}
+14 -12
View File
@@ -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) {
+62 -62
View File
@@ -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;
}
+44 -39
View File
@@ -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 {
+22 -19
View File
@@ -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;
}
+3 -3
View File
@@ -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);
}
+55 -12
View File
@@ -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;
+19 -18
View File
@@ -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");
}
}
}
+9 -9
View File
@@ -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());
}
+1 -1
View File
@@ -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;
+12 -12
View File
@@ -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);
}
}
+50 -46
View File
@@ -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));
}
}
+11 -10
View File
@@ -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);
}
}