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:
Thomas Krijnen
2018-09-17 17:46:13 +02:00
5 changed files with 143 additions and 14 deletions
+17
View File
@@ -80,6 +80,23 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
#include INCLUDE_PARENT_DIR(IfcSchema)
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) {
public:
+3 -1
View File
@@ -341,7 +341,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
TopoDS_Iterator jt(face, false);
for (; jt.More(); jt.Next()) {
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);
TopTools_ListIteratorOfListOfShape it(shapes);
for (; it.More(); it.Next()) {
+113 -11
View File
@@ -44,6 +44,9 @@
#include <gp_Pln.hxx>
#include <gp_Circ.hxx>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
@@ -144,6 +147,7 @@
#include "../ifcparse/IfcSIPrefix.h"
#include "../ifcparse/IfcFile.h"
#include "../ifcgeom/IfcGeom.h"
#include "../ifcgeom/IfcGeomTree.h"
#if OCC_VERSION_HEX < 0x60900
#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 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;
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_PRECISION));
builder.SetMaxTolerance(getValue(GV_PRECISION));
builder.SetMinTolerance(getValue(GV_PRECISION));
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(face_iterator.Value());
}
@@ -1368,6 +1383,7 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
}
IfcGeom::IfcRepresentationShapeItems opened_shapes;
bool caught_error = false;
try {
#if OCC_VERSION_HEX < 0x60900
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 {
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(...) {
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)) {
for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
it->prepend(trsf);
@@ -2852,10 +2876,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
}
int n = count(wire, TopAbs_EDGE);
if (n < 3 || n > 128) {
if (n > 128) {
Logger::Notice("Too many segments for detection of self-intersections");
}
if (n < 3) {
wires.Append(wire);
return false;
}
@@ -2865,8 +2886,24 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
// ... to be sure to get consecutive edges
BRepTools_WireExplorer exp(wire);
IfcGeom::impl::tree<int> tree;
int edge_idx = 0;
for (; exp.More(); exp.Next()) {
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;
@@ -2874,13 +2911,37 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
// tfk: Extrema on infinite curves proved to be more robust.
// TopoDS_Face face = BRepBuilderAPI_MakeFace(wire, true).Face();
// ShapeAnalysis_Wire saw(wd, face, getValue(GV_PRECISION));
for (int i = 2; i < n; ++i) {
for (int j = 0; j < i - 1; ++j) {
if (i == n - 1 && j == 0) continue;
const double eps = getValue(GV_PRECISION) * 10.;
for (int i = 2; i < n; ++i) {
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;
bool unbounded_intersects;
const double eps = getValue(GV_PRECISION) * 10.;
double u11, u12, u21, u22, U1, U2;
GeomAPI_ExtremaCurveCurve ecc(
@@ -3041,6 +3102,10 @@ bool IfcGeom::Kernel::fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b
Bnd_Box bb;
BRepBndLib::Add(a, bb);
if (bb.IsVoid()) {
return false;
}
double xs[2], ys[2], zs[2];
bb.Get(xs[0], ys[0], zs[0], xs[1], ys[1], zs[1]);
@@ -3226,7 +3291,7 @@ namespace {
TopoDS_Vertex v1, v2;
TopExp::Vertices(e, v1, v2);
if (v.IsEqual(v1) || v.IsEqual(v2)) {
if (v.IsSame(v1) || v.IsSame(v2)) {
continue;
}
@@ -3248,6 +3313,30 @@ namespace {
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) {
@@ -3307,7 +3396,20 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
success = BRepCheck_Analyzer(r).IsValid() != 0;
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;
+5 -1
View File
@@ -494,7 +494,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
}
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) {
// tfk: note 1-based
polygon.Remove(polygon.Length());
@@ -502,6 +502,10 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
// Remove points that are too close to one another
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
if (polygon.Length() < 2) {
return false;
}
BRepBuilderAPI_MakePolygon w;
for (int i = 1; i <= polygon.Length(); ++i) {
+5 -1
View File
@@ -45,7 +45,11 @@ namespace {
}
os << message << std::endl;
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;
}
}