mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-12 14:33:28 +00:00
Merge branch 'master' into v0.6.0
# Conflicts: # nix/build-all.py # src/ifcgeom/IfcGeomFunctions.cpp # src/ifcparse/IfcLogger.cpp
This commit is contained in:
@@ -80,6 +80,23 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
|
|||||||
#include INCLUDE_PARENT_DIR(IfcSchema)
|
#include INCLUDE_PARENT_DIR(IfcSchema)
|
||||||
|
|
||||||
namespace IfcGeom {
|
namespace IfcGeom {
|
||||||
|
class IFC_PARSE_API geometry_exception : public std::exception {
|
||||||
|
protected:
|
||||||
|
std::string message;
|
||||||
|
public:
|
||||||
|
geometry_exception(const std::string& m)
|
||||||
|
: message(m) {}
|
||||||
|
virtual ~geometry_exception() throw () {}
|
||||||
|
virtual const char* what() const throw() {
|
||||||
|
return message.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IFC_PARSE_API too_many_faces_exception : public geometry_exception {
|
||||||
|
public:
|
||||||
|
too_many_faces_exception()
|
||||||
|
: geometry_exception("Too many faces for operation") {}
|
||||||
|
};
|
||||||
|
|
||||||
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
|
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -341,7 +341,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
|
|||||||
TopoDS_Iterator jt(face, false);
|
TopoDS_Iterator jt(face, false);
|
||||||
for (; jt.More(); jt.Next()) {
|
for (; jt.More(); jt.Next()) {
|
||||||
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
|
||||||
if (wire_map.IsBound(w)) {
|
// 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);
|
const TopTools_ListOfShape& shapes = wire_map.Find(w);
|
||||||
TopTools_ListIteratorOfListOfShape it(shapes);
|
TopTools_ListIteratorOfListOfShape it(shapes);
|
||||||
for (; it.More(); it.Next()) {
|
for (; it.More(); it.Next()) {
|
||||||
|
|||||||
@@ -44,6 +44,9 @@
|
|||||||
#include <gp_Pln.hxx>
|
#include <gp_Pln.hxx>
|
||||||
#include <gp_Circ.hxx>
|
#include <gp_Circ.hxx>
|
||||||
|
|
||||||
|
#include <boost/range/irange.hpp>
|
||||||
|
#include <boost/range/algorithm_ext/push_back.hpp>
|
||||||
|
|
||||||
#include <TColgp_Array1OfPnt.hxx>
|
#include <TColgp_Array1OfPnt.hxx>
|
||||||
#include <TColgp_Array1OfPnt2d.hxx>
|
#include <TColgp_Array1OfPnt2d.hxx>
|
||||||
#include <TColStd_Array1OfReal.hxx>
|
#include <TColStd_Array1OfReal.hxx>
|
||||||
@@ -144,6 +147,7 @@
|
|||||||
#include "../ifcparse/IfcSIPrefix.h"
|
#include "../ifcparse/IfcSIPrefix.h"
|
||||||
#include "../ifcparse/IfcFile.h"
|
#include "../ifcparse/IfcFile.h"
|
||||||
#include "../ifcgeom/IfcGeom.h"
|
#include "../ifcgeom/IfcGeom.h"
|
||||||
|
#include "../ifcgeom/IfcGeomTree.h"
|
||||||
|
|
||||||
#if OCC_VERSION_HEX < 0x60900
|
#if OCC_VERSION_HEX < 0x60900
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -233,12 +237,23 @@ bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, T
|
|||||||
bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) {
|
bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) {
|
||||||
bool valid_shell = false;
|
bool valid_shell = false;
|
||||||
|
|
||||||
|
|
||||||
|
int max_faces = getValue(GV_MAX_FACES_TO_SEW);
|
||||||
|
if (max_faces == -1) {
|
||||||
|
max_faces = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (face_list.Extent() > max_faces) {
|
||||||
|
throw too_many_faces_exception();
|
||||||
|
}
|
||||||
|
|
||||||
TopTools_ListIteratorOfListOfShape face_iterator;
|
TopTools_ListIteratorOfListOfShape face_iterator;
|
||||||
|
|
||||||
BRepOffsetAPI_Sewing builder;
|
BRepOffsetAPI_Sewing builder;
|
||||||
builder.SetTolerance(getValue(GV_PRECISION));
|
builder.SetTolerance(getValue(GV_PRECISION));
|
||||||
builder.SetMaxTolerance(getValue(GV_PRECISION));
|
builder.SetMaxTolerance(getValue(GV_PRECISION));
|
||||||
builder.SetMinTolerance(getValue(GV_PRECISION));
|
builder.SetMinTolerance(getValue(GV_PRECISION));
|
||||||
|
|
||||||
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
|
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
|
||||||
builder.Add(face_iterator.Value());
|
builder.Add(face_iterator.Value());
|
||||||
}
|
}
|
||||||
@@ -1368,6 +1383,7 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
|
|||||||
}
|
}
|
||||||
|
|
||||||
IfcGeom::IfcRepresentationShapeItems opened_shapes;
|
IfcGeom::IfcRepresentationShapeItems opened_shapes;
|
||||||
|
bool caught_error = false;
|
||||||
try {
|
try {
|
||||||
#if OCC_VERSION_HEX < 0x60900
|
#if OCC_VERSION_HEX < 0x60900
|
||||||
const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS);
|
const bool faster_booleans = settings.get(IteratorSettings::FASTER_BOOLEANS);
|
||||||
@@ -1387,9 +1403,17 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
|
|||||||
} else {
|
} else {
|
||||||
convert_openings(product,openings,shapes,trsf,opened_shapes);
|
convert_openings(product,openings,shapes,trsf,opened_shapes);
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
Logger::Message(Logger::LOG_ERROR, std::string("Error processing openings for: ") + e.what() + ":", product);
|
||||||
|
caught_error = true;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product);
|
Logger::Message(Logger::LOG_ERROR,"Error processing openings for:",product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (caught_error && opened_shapes.size() < shapes.size()) {
|
||||||
|
opened_shapes = shapes;
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
|
||||||
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
|
||||||
it->prepend(trsf);
|
it->prepend(trsf);
|
||||||
@@ -2852,10 +2876,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
|
|||||||
}
|
}
|
||||||
|
|
||||||
int n = count(wire, TopAbs_EDGE);
|
int n = count(wire, TopAbs_EDGE);
|
||||||
if (n < 3 || n > 128) {
|
if (n < 3) {
|
||||||
if (n > 128) {
|
|
||||||
Logger::Notice("Too many segments for detection of self-intersections");
|
|
||||||
}
|
|
||||||
wires.Append(wire);
|
wires.Append(wire);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2865,8 +2886,24 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
|
|||||||
|
|
||||||
// ... to be sure to get consecutive edges
|
// ... to be sure to get consecutive edges
|
||||||
BRepTools_WireExplorer exp(wire);
|
BRepTools_WireExplorer exp(wire);
|
||||||
|
IfcGeom::impl::tree<int> tree;
|
||||||
|
|
||||||
|
int edge_idx = 0;
|
||||||
for (; exp.More(); exp.Next()) {
|
for (; exp.More(); exp.Next()) {
|
||||||
wd->Add(exp.Current());
|
wd->Add(exp.Current());
|
||||||
|
if (n > 64) {
|
||||||
|
// tfk: indices in tree are 0-based vd 1-based in wiredata
|
||||||
|
tree.add(edge_idx++, exp.Current());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wd->NbEdges() != n) {
|
||||||
|
// If the number of edges differs, BRepTools_WireExplorer did not
|
||||||
|
// reach every edge, probably due to loops exactly at vertex locations.
|
||||||
|
// This is not supported by this algorithm which only elimates loops
|
||||||
|
// due to edge crossings.
|
||||||
|
|
||||||
|
throw geometry_exception("Invalid loop");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool intersected = false;
|
bool intersected = false;
|
||||||
@@ -2875,12 +2912,36 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
|
|||||||
// TopoDS_Face face = BRepBuilderAPI_MakeFace(wire, true).Face();
|
// TopoDS_Face face = BRepBuilderAPI_MakeFace(wire, true).Face();
|
||||||
// ShapeAnalysis_Wire saw(wd, face, getValue(GV_PRECISION));
|
// ShapeAnalysis_Wire saw(wd, face, getValue(GV_PRECISION));
|
||||||
|
|
||||||
|
const double eps = getValue(GV_PRECISION) * 10.;
|
||||||
|
|
||||||
for (int i = 2; i < n; ++i) {
|
for (int i = 2; i < n; ++i) {
|
||||||
for (int j = 0; j < i - 1; ++j) {
|
|
||||||
|
std::vector<int> js;
|
||||||
|
if (n > 64) {
|
||||||
|
Bnd_Box b;
|
||||||
|
BRepBndLib::Add(wd->Edge(i + 1), b);
|
||||||
|
b.Enlarge(eps);
|
||||||
|
js = tree.select_box(b, false);
|
||||||
|
} else {
|
||||||
|
boost::push_back(js, boost::irange(0, i - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::vector<int>::const_iterator it = js.begin(); it != js.end(); ++it) {
|
||||||
|
int j = *it;
|
||||||
|
|
||||||
|
if (n > 64) {
|
||||||
|
if (j > i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((std::max)(i, j) - (std::min)(i, j) <= 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only check non-consecutive edges
|
||||||
if (i == n - 1 && j == 0) continue;
|
if (i == n - 1 && j == 0) continue;
|
||||||
|
|
||||||
bool unbounded_intersects;
|
bool unbounded_intersects;
|
||||||
const double eps = getValue(GV_PRECISION) * 10.;
|
|
||||||
|
|
||||||
double u11, u12, u21, u22, U1, U2;
|
double u11, u12, u21, u22, U1, U2;
|
||||||
GeomAPI_ExtremaCurveCurve ecc(
|
GeomAPI_ExtremaCurveCurve ecc(
|
||||||
@@ -3041,6 +3102,10 @@ bool IfcGeom::Kernel::fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b
|
|||||||
Bnd_Box bb;
|
Bnd_Box bb;
|
||||||
BRepBndLib::Add(a, bb);
|
BRepBndLib::Add(a, bb);
|
||||||
|
|
||||||
|
if (bb.IsVoid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
double xs[2], ys[2], zs[2];
|
double xs[2], ys[2], zs[2];
|
||||||
bb.Get(xs[0], ys[0], zs[0], xs[1], ys[1], zs[1]);
|
bb.Get(xs[0], ys[0], zs[0], xs[1], ys[1], zs[1]);
|
||||||
|
|
||||||
@@ -3226,7 +3291,7 @@ namespace {
|
|||||||
TopoDS_Vertex v1, v2;
|
TopoDS_Vertex v1, v2;
|
||||||
TopExp::Vertices(e, v1, v2);
|
TopExp::Vertices(e, v1, v2);
|
||||||
|
|
||||||
if (v.IsEqual(v1) || v.IsEqual(v2)) {
|
if (v.IsSame(v1) || v.IsSame(v2)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3248,6 +3313,30 @@ namespace {
|
|||||||
return M;
|
return M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_manifold(const TopoDS_Shape& a) {
|
||||||
|
TopTools_IndexedDataMapOfShapeListOfShape map;
|
||||||
|
TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map);
|
||||||
|
|
||||||
|
for (int i = 1; i <= map.Extent(); ++i) {
|
||||||
|
if (map.FindFromIndex(i).Extent() != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_manifold(const TopTools_ListOfShape& l) {
|
||||||
|
TopTools_ListOfShape r;
|
||||||
|
TopTools_ListIteratorOfListOfShape it(l);
|
||||||
|
for (; it.More(); it.Next()) {
|
||||||
|
if (!is_manifold(it.Value())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_ListOfShape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
|
bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_ListOfShape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
|
||||||
@@ -3307,7 +3396,20 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
|
|||||||
success = BRepCheck_Analyzer(r).IsValid() != 0;
|
success = BRepCheck_Analyzer(r).IsValid() != 0;
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
result = r;
|
|
||||||
|
success = !is_manifold(a) || is_manifold(r);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
double min_len_check = (std::min)(min_edge_length(r), min_vertex_edge_distance(r, getValue(GV_PRECISION)));
|
||||||
|
success = min_len_check > fuzziness * 10.;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
result = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete builder;
|
delete builder;
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double eps = getValue(GV_PRECISION) * 10;
|
const double eps = getValue(GV_PRECISION) * 10;
|
||||||
const bool closed_by_proximity = polygon.Length() >= 2 && polygon.First().Distance(polygon.Last()) < eps;
|
const bool closed_by_proximity = polygon.Length() >= 3 && polygon.First().Distance(polygon.Last()) < eps;
|
||||||
if (closed_by_proximity) {
|
if (closed_by_proximity) {
|
||||||
// tfk: note 1-based
|
// tfk: note 1-based
|
||||||
polygon.Remove(polygon.Length());
|
polygon.Remove(polygon.Length());
|
||||||
@@ -503,6 +503,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
|
|||||||
// Remove points that are too close to one another
|
// Remove points that are too close to one another
|
||||||
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
|
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
|
||||||
|
|
||||||
|
if (polygon.Length() < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BRepBuilderAPI_MakePolygon w;
|
BRepBuilderAPI_MakePolygon w;
|
||||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||||
w.Add(polygon.Value(i));
|
w.Add(polygon.Value(i));
|
||||||
|
|||||||
@@ -45,7 +45,11 @@ namespace {
|
|||||||
}
|
}
|
||||||
os << message << std::endl;
|
os << message << std::endl;
|
||||||
if (instance) {
|
if (instance) {
|
||||||
os << instance->data().toString() << std::endl;
|
std::string instance_string = instance->data().toString();
|
||||||
|
if (instance_string.size() > 259) {
|
||||||
|
instance_string = instance_string.substr(0, 256) + "...";
|
||||||
|
}
|
||||||
|
os << instance_string << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user