Merge branch 'v0.6.0' into v0.7.0

# Conflicts:
#	cmake/CMakeLists.txt
#	src/ifcconvert/IfcConvert.cpp
#	src/ifcgeom/IfcGeomRepresentation.h
#	src/ifcgeom/IfcRepresentationShapeItem.h
#	src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp
#	src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp
#	src/ifcgeom/schema_agnostic/Kernel.cpp
#	src/ifcgeom/schema_agnostic/Kernel.h
#	src/ifcgeomserver/IfcGeomServer.cpp
#	src/serializers/schema_dependent/XmlSerializer.cpp
This commit is contained in:
Thomas Krijnen
2019-04-26 15:07:50 +02:00
51 changed files with 10815 additions and 7568 deletions
+6 -1
View File
@@ -126,6 +126,7 @@ private:
std::map<int, int> vertex_mapping_;
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
double eps_;
bool non_manifold_;
template <typename Fn>
void loop_(IfcSchema::IfcCartesianPoint::list::ptr& ps, const Fn& callback) {
@@ -153,6 +154,9 @@ private:
~faceset_helper();
bool non_manifold() const { return non_manifold_; }
bool& non_manifold() { return non_manifold_; }
bool edge(const IfcSchema::IfcCartesianPoint* a, const IfcSchema::IfcCartesianPoint* b, TopoDS_Edge& e) {
int A = vertex_mapping_[a->data().id()];
int B = vertex_mapping_[b->data().id()];
@@ -194,6 +198,7 @@ private:
if (kernel_->wire_intersections(wire, results)) {
Logger::Warning("Self-intersections with " + boost::lexical_cast<std::string>(results.Extent()) + " cycles detected", loop);
kernel_->select_largest(results, wire);
non_manifold_ = true;
}
return true;
@@ -295,7 +300,7 @@ public:
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&);
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&, double eps=-1.);
bool flatten_wire(TopoDS_Wire&);
bool triangulate_wire(const TopoDS_Wire&, TopTools_ListOfShape&);
bool wire_intersections(const TopoDS_Wire & wire, TopTools_ListOfShape & wires);
@@ -95,6 +95,8 @@
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <BRepLib_FindSurface.hxx>
#ifdef USE_IFC4
#include <Geom_BSplineSurface.hxx>
#include <TColgp_Array2OfPnt.hxx>
@@ -212,8 +214,6 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
for (; exp.More(); exp.Next(), count++) {
if (count < 2) {
edges[count] = TopoDS::Edge(exp.Current());
} else {
break;
}
}
@@ -258,22 +258,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
// @todo is this still relevant considering the code above
mf = new BRepBuilderAPI_MakeFace(pln, wire, true);
} else {
mf = new BRepBuilderAPI_MakeFace(wire);
BRepLib_FindSurface fs(wire, getValue(GV_PRECISION), true, true);
if (fs.Found()) {
mf = new BRepBuilderAPI_MakeFace(fs.Surface(), wire);
ShapeFix_ShapeTolerance ftol;
ftol.SetTolerance(wire, fs.ToleranceReached(), TopAbs_WIRE);
}
}
} else {
/// @todo check necessity of false here
mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false);
}
mf = new BRepBuilderAPI_MakeFace(face_surface, wire, false);
}
/* BRepBuilderAPI_FaceError er = mf->Error();
if (er == BRepBuilderAPI_NotPlanar) {
ShapeFix_ShapeTolerance FTol;
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
delete mf;
mf = new BRepBuilderAPI_MakeFace(wire);
} */
if (mf->IsDone()) {
if (mf && mf->IsDone()) {
TopoDS_Face outer_face_bound = mf->Face();
// In case of (non-planar) face surface, p-curves need to be computed.
@@ -315,11 +312,12 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
success = true;
}
} else {
const bool non_planar = mf->Error() == BRepBuilderAPI_NotPlanar;
// if mf == nullptr, it means we failed to find a surface earlier using BRepLib_FindSurface
const bool non_planar = mf == nullptr || mf->Error() == BRepBuilderAPI_NotPlanar;
delete mf;
if (non_planar && bounds->size() == 1 && face_surface.IsNull()) {
Logger::Message(Logger::LOG_ERROR, "Triangulating face boundary", bound);
Logger::Message(Logger::LOG_WARNING, "Triangulating face boundary", bound);
// When creating a solid, flatting the boundary only postpones the issue to
// creating a topological manifold out of the individual faces.
@@ -101,12 +101,15 @@
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_ShapeTolerance.hxx>
#include <ShapeFix_Solid.hxx>
#include <ShapeFix_Shell.hxx>
#include <ShapeAnalysis_Curve.hxx>
#include <ShapeAnalysis_Wire.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <ShapeAnalysis_ShapeTolerance.hxx>
#include <ShapeUpgrade_UnifySameDomain.hxx>
#include <BRepFilletAPI_MakeFillet2d.hxx>
#include <TopLoc_Location.hxx>
@@ -139,6 +142,7 @@
#include <GCPnts_AbscissaPoint.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
@@ -313,6 +317,124 @@ namespace {
return M;
}
class points_on_planar_face_generator {
private:
const TopoDS_Face& f_;
Handle(Geom_Surface) plane_;
BRepTopAdaptor_FClass2d cls_;
double u0, u1, v0, v1;
int i, j;
static const int N = 10;
public:
points_on_planar_face_generator(const TopoDS_Face& f)
: f_(f)
, plane_(BRep_Tool::Surface(f_))
, cls_(f_, BRep_Tool::Tolerance(f_))
, i(0), j(0)
{
BRepTools::UVBounds(f_, u0, u1, v0, v1);
}
void reset() {
i = j = 0;
}
bool operator()(gp_Pnt& p) {
while (j < N) {
double u = u0 + (u1 - u0) * i / N;
double v = v0 + (v1 - v0) * j / N;
i++;
if (i == N) {
i = 0;
j++;
}
// Specifically does not consider ON
if (cls_.Perform(gp_Pnt2d(u, v)) == TopAbs_IN) {
plane_->D0(u, v, p);
return true;
}
}
return false;
}
};
double min_face_face_distance(const TopoDS_Shape& a, double max_search) {
/*
NB: This is currently only implemented for planar surfaces.
*/
double M = std::numeric_limits<double>::infinity();
TopTools_IndexedMapOfShape faces;
TopExp::MapShapes(a, TopAbs_FACE, faces);
IfcGeom::impl::tree<int> tree;
// Add edges to tree
for (int i = 1; i <= faces.Extent(); ++i) {
if (BRep_Tool::Surface(TopoDS::Face(faces(i)))->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
tree.add(i, faces(i));
}
}
for (int j = 1; j <= faces.Extent(); ++j) {
const TopoDS_Face& f = TopoDS::Face(faces(j));
const Handle(Geom_Surface)& fs = BRep_Tool::Surface(f);
if (fs->DynamicType() != STANDARD_TYPE(Geom_Plane)) {
continue;
}
points_on_planar_face_generator pgen(f);
Bnd_Box b;
BRepBndLib::AddClose(f, b);
b.Enlarge(max_search);
std::vector<int> edge_idxs = tree.select_box(b, false);
std::vector<int>::const_iterator it = edge_idxs.begin();
for (; it != edge_idxs.end(); ++it) {
if (*it == j) {
continue;
}
const TopoDS_Face& g = TopoDS::Face(faces(*it));
const Handle(Geom_Surface)& gs = BRep_Tool::Surface(g);
auto p0 = Handle(Geom_Plane)::DownCast(fs);
auto p1 = Handle(Geom_Plane)::DownCast(gs);
if (p0->Position().IsCoplanar(p1->Position(), max_search, asin(max_search))) {
pgen.reset();
BRepTopAdaptor_FClass2d cls(g, BRep_Tool::Tolerance(g));
gp_Pnt test;
while (pgen(test)) {
gp_Vec d = test.XYZ() - p1->Position().Location().XYZ();
double u = d.Dot(p1->Position().XDirection());
double v = d.Dot(p1->Position().YDirection());
if (cls.Perform(gp_Pnt2d(u, v)) == TopAbs_IN) {
gp_Pnt test2;
p1->D0(u, v, test2);
double w = gp_Vec(p1->Position().Direction().XYZ()).Dot(test2.XYZ() - test.XYZ());
if (w < M) {
M = w;
}
}
}
}
}
}
return M;
}
void bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c) {
Bnd_Box A;
BRepBndLib::Add(a, A);
@@ -335,6 +457,17 @@ namespace {
}
}
}
#ifdef UNIFY_OPERANDS
TopoDS_Shape unify(const TopoDS_Shape& s) {
ShapeUpgrade_UnifySameDomain usd(s);
usd.SetLinearTolerance(Precision::Confusion() * 10.);
usd.SetAngularTolerance(Precision::Angular() * 10.);
usd.Build();
return usd.Shape();
}
#endif
}
namespace {
@@ -375,32 +508,71 @@ bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_l
return false;
}
TopTools_ListIteratorOfListOfShape face_iterator;
TopTools_ListIteratorOfListOfShape face_iterator;
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_PRECISION));
builder.SetMaxTolerance(getValue(GV_PRECISION));
builder.SetMinTolerance(getValue(GV_PRECISION));
bool has_shared_edges = false;
TopTools_MapOfShape edge_set;
// In case there are wire interesections or failures in non-planar wire triangulations
// the idea is to let occt do an exhaustive search of edge partners. But we have not
// found a case where this actually improves boolean ops later on.
// if (!faceset_helper_ || !faceset_helper_->non_manifold()) {
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
builder.Add(face_iterator.Value());
// As soon as is detected one of the edges is shared, the assumption is made no
// additional sewing is necessary.
if (!has_shared_edges) {
TopExp_Explorer exp(face_iterator.Value(), TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
if (edge_set.Contains(exp.Current())) {
has_shared_edges = true;
break;
}
edge_set.Add(exp.Current());
}
}
}
BRepOffsetAPI_Sewing sewing_builder;
sewing_builder.SetTolerance(getValue(GV_PRECISION));
sewing_builder.SetMaxTolerance(getValue(GV_PRECISION));
sewing_builder.SetMinTolerance(getValue(GV_PRECISION));
BRep_Builder builder;
TopoDS_Shell shell;
builder.MakeShell(shell);
for (face_iterator.Initialize(face_list); face_iterator.More(); face_iterator.Next()) {
if (has_shared_edges) {
builder.Add(shell, face_iterator.Value());
} else {
sewing_builder.Add(face_iterator.Value());
}
}
try {
builder.Perform();
shape = builder.SewedShape();
if (has_shared_edges) {
ShapeFix_Shell fix;
fix.FixFaceOrientation(shell);
shape = fix.Shape();
} else {
sewing_builder.Perform();
shape = sewing_builder.SewedShape();
}
BRepCheck_Analyzer ana(shape);
valid_shell = ana.IsValid();
{
BRepCheck_Analyzer ana(shape);
if (!ana.IsValid()) {
ShapeFix_Shape sfs(shape);
sfs.Perform();
shape = sfs.Shape();
}
if (!valid_shell) {
ShapeFix_Shape sfs(shape);
sfs.Perform();
shape = sfs.Shape();
BRepCheck_Analyzer reana(shape);
valid_shell = reana.IsValid();
}
BRepCheck_Analyzer ana(shape);
valid_shell = ana.IsValid() != 0 && count_occt(shape, TopAbs_SHELL) > 0;
valid_shell &= count_occt(shape, TopAbs_SHELL) > 0;
} catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
Logger::Error(e.GetMessageString());
@@ -2276,12 +2448,15 @@ bool IfcGeom::Kernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) {
}
}
bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane) {
bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps) {
// Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
const double eps_ = eps < 1. ? getValue(GV_PRECISION) : eps;
const double eps2 = eps_ * eps_;
double x = 0, y = 0, z = 0;
gp_Pnt current, previous, first;
gp_XYZ center;
@@ -2321,8 +2496,18 @@ bool IfcGeom::Kernel::approximate_plane_through_wire(const TopoDS_Wire& wire, gp
if (n < 3) {
return false;
}
plane = gp_Pln(center / n, gp_Dir(x, y, z));
exp.Init(wire);
for (; exp.More(); exp.Next()) {
const TopoDS_Vertex& v = exp.CurrentVertex();
current = BRep_Tool::Pnt(v);
if (plane.SquareDistance(current) > eps2) {
return false;
}
}
return true;
}
@@ -2355,12 +2540,16 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS
// alternatively we use the regular OCCT incremental mesher on a new face
// created from the UV coordinates of the original wire. Pray to our gods
// that the vertex coordinates are unaffected by the meshing algorithm and
// map them back to 3d coordinates when iterating over the mesh triangles.
// map them back to 3d coordinates when iterating over the mesh triangles.
// In addition, to maintain a manifold shell, we need to make sure that
// every edge from the input wire is used exactly once in the list of
// resulting faces. And that other internal edges are used twice.
typedef std::pair<double, double> uv_node;
gp_Pln pln;
if (!approximate_plane_through_wire(wire, pln)) {
if (!approximate_plane_through_wire(wire, pln, std::numeric_limits<double>::infinity())) {
return false;
}
@@ -2370,15 +2559,35 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS
BRepTools_WireExplorer exp(wire);
BRepBuilderAPI_MakePolygon mp;
std::map<uv_node, gp_Pnt> mapping;
std::map<uv_node, TopoDS_Vertex> mapping;
std::map<std::pair<uv_node, uv_node>, TopoDS_Edge> existing_edges, new_edges;
// Add UV coordinates to a newly created polygon
for (; exp.More(); exp.Next()) {
gp_Pnt p = BRep_Tool::Pnt(exp.CurrentVertex());
// Project onto plane
const TopoDS_Vertex& V = exp.CurrentVertex();
gp_Pnt p = BRep_Tool::Pnt(V);
double u = (p.XYZ() - pnt).Dot(udir);
double v = (p.XYZ() - pnt).Dot(vdir);
mp.Add(gp_Pnt(u, v, 0));
mapping.insert(std::make_pair(std::make_pair(u, v), p));
mp.Add(gp_Pnt(u, v, 0.));
mapping.insert(std::make_pair(std::make_pair(u, v), V));
// Store existing edges in a map so that triangles can
// actually reference the preexisting edges.
const TopoDS_Edge& e = exp.Current();
TopoDS_Vertex V0, V1;
TopExp::Vertices(e, V0, V1, true);
gp_Pnt p0 = BRep_Tool::Pnt(V0);
gp_Pnt p1 = BRep_Tool::Pnt(V1);
double u0 = (p0.XYZ() - pnt).Dot(udir);
double v0 = (p0.XYZ() - pnt).Dot(vdir);
double u1 = (p1.XYZ() - pnt).Dot(udir);
double v1 = (p1.XYZ() - pnt).Dot(vdir);
uv_node uv0 = std::make_pair(u0, v0);
uv_node uv1 = std::make_pair(u1, v1);
existing_edges.insert(std::make_pair(std::make_pair(uv0, uv1), e));
existing_edges.insert(std::make_pair(std::make_pair(uv1, uv0), TopoDS::Edge(e.Reversed())));
}
// Not closed by default
@@ -2391,7 +2600,7 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS
int n123[3];
TopLoc_Location loc;
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
if (!tri.IsNull()) {
const TColgp_Array1OfPnt& nodes = tri->Nodes();
@@ -2402,20 +2611,49 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS
else triangles(i).Get(n123[0], n123[1], n123[2]);
// Create polygons from the mesh vertices
BRepBuilderAPI_MakePolygon mp2;
BRepBuilderAPI_MakeWire mp2;
for (int j = 0; j < 3; ++j) {
const gp_Pnt& uv = nodes.Value(n123[j]);
uv_node key = std::make_pair(uv.X(), uv.Y());
uv_node uvnodes[2];
TopoDS_Vertex vs[2];
if (mapping.find(key) == mapping.end()) {
Logger::Error("Internal error: unable to unproject uv-mesh");
return false;
for (int k = 0; k < 2; ++k) {
const gp_Pnt& uv = nodes.Value(n123[(j + k) % 3]);
uvnodes[k] = std::make_pair(uv.X(), uv.Y());
auto it = mapping.find(uvnodes[k]);
if (it == mapping.end()) {
Logger::Error("Internal error: unable to unproject uv-mesh");
return false;
}
vs[k] = it->second;
}
const gp_Pnt& p = mapping.find(key)->second;
mp2.Add(p);
auto it = existing_edges.find(std::make_pair(uvnodes[0], uvnodes[1]));
if (it != existing_edges.end()) {
// This is a boundary edge, reuse existing edge from wire
mp2.Add(it->second);
} else {
auto jt = new_edges.find(std::make_pair(uvnodes[0], uvnodes[1]));
if (jt != new_edges.end()) {
// We have already added the reverse as part of another
// triangle, reuse this edge.
mp2.Add(TopoDS::Edge(jt->second));
} else {
// This is a new internal edge. Register the reverse
// for reuse later. We need to be sure to reuse vertices
// for the edge construction because otherwise the wire
// builder will use geometrical proximity for vertex
// connections in which case the edge will be copied
// and no longer partner with other edges from the shell.
TopoDS_Edge ne = BRepBuilderAPI_MakeEdge(vs[0], vs[1]);
mp2.Add(ne);
// Store the reverse to be picked up later.
new_edges.insert(std::make_pair(std::make_pair(uvnodes[1], uvnodes[0]), TopoDS::Edge(ne.Reversed())));
}
}
}
mp2.Close();
BRepBuilderAPI_MakeFace mf(mp2.Wire());
if (mf.IsDone()) {
@@ -2428,6 +2666,42 @@ bool IfcGeom::Kernel::triangulate_wire(const TopoDS_Wire& wire, TopTools_ListOfS
}
}
faces.Append(triangle_face);
} else {
Logger::Error("Internal error: missing face");
return false;
}
}
}
TopTools_IndexedDataMapOfShapeListOfShape mape, mapn;
TopExp::MapShapesAndAncestors(wire, TopAbs_EDGE, TopAbs_WIRE, mape);
TopTools_ListIteratorOfListOfShape it(faces);
for (; it.More(); it.Next()) {
TopExp::MapShapesAndAncestors(it.Value(), TopAbs_EDGE, TopAbs_WIRE, mapn);
}
// Validation
for (int i = 1; i <= mape.Extent(); ++i) {
TopTools_ListOfShape val;
if (!mapn.FindFromKey(mape.FindKey(i), val)) {
// All existing edges need to exist in the new faces
Logger::Error("Internal error, missing edge from triangulation");
if (faceset_helper_ != nullptr) {
faceset_helper_->non_manifold() = true;
}
}
}
for (int i = 1; i <= mapn.Extent(); ++i) {
const TopoDS_Shape& v = mapn.FindKey(i);
int n = mapn.FindFromIndex(i).Extent();
// 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");
if (faceset_helper_ != nullptr) {
faceset_helper_->non_manifold() = true;
}
}
}
@@ -2876,7 +3150,23 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopoDS_Shap
return succesful;
}
#else
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) {
#ifdef UNIFY_OPERANDS
TopoDS_Shape a = unify(a_);
TopTools_ListOfShape b_;
{
TopTools_ListIteratorOfListOfShape it(b__);
for (; it.More(); it.Next()) {
b_.Append(unify(it.Value()));
}
}
#else
const TopoDS_Shape& a = a_;
const TopTools_ListOfShape& b_ = b__;
#endif
bool success = false;
BRepAlgoAPI_BooleanOperation* builder;
TopTools_ListOfShape B, b;
@@ -2954,14 +3244,25 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
// 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_lengh_result = (std::min)(min_edge_length(r), min_vertex_edge_distance(r, getValue(GV_PRECISION), fuzziness * 10.));
success = min_lengh_result <= min_length_orig || min_lengh_result > fuzziness * 10.;
int reason = 0;
double v;
if ((v = min_edge_length(r)) < fuzziness * 10.) {
reason = 0;
success = false;
} else if ((v = min_vertex_edge_distance(r, getValue(GV_PRECISION), fuzziness * 10.)) < fuzziness * 10.) {
reason = 1;
success = false;
} else if ((v = min_face_face_distance(r, fuzziness * 10.)) < fuzziness * 10.) {
reason = 2;
success = false;
}
if (success) {
result = r;
} else {
static const char* const reason_strings[] = { "edge length", "vertex-edge", "face-face" };
std::stringstream str;
str << "Boolean operation result failing interference check, with fuzziness " << fuzziness << " min length " << min_lengh_result << " originally " << min_length_orig;
str << "Boolean operation result failing " << reason_strings[reason] << " interference check, with fuzziness " << fuzziness << " with length " << v;
Logger::Notice(str.str());
}
} else {
@@ -2975,16 +3276,21 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
#if OCC_VERSION_HEX >= 0x70000
builder->DumpErrors(str);
#else
str << "Error code :" << builder->ErrorStatus();
str << "Error code: " << builder->ErrorStatus();
#endif
Logger::Notice(str.str());
std::string str_str = str.str();
if (str_str.size()) {
Logger::Notice(str_str);
}
}
delete builder;
if (!success) {
const double new_fuzziness = fuzziness * 10.;
if (new_fuzziness + 1e-15 <= getValue(GV_PRECISION) * 1000. && new_fuzziness < min_length_orig) {
if (new_fuzziness - 1e-15 <= getValue(GV_PRECISION) * 10000. && new_fuzziness < min_length_orig) {
return boolean_operation(a, b, op, result, new_fuzziness);
}
} else {
Logger::Notice("No longer attempting boolean operation with higher fuzziness");
}
}
return success;
}
@@ -3024,6 +3330,7 @@ IfcGeom::Kernel::faceset_helper::~faceset_helper() {
IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema::IfcConnectedFaceSet* l)
: kernel_(kernel)
, non_manifold_(false)
{
kernel->faceset_helper_ = this;
@@ -3048,6 +3355,9 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema:
}
}
// Use the bbox diagonal to influence local epsilon
// double bdiff = std::sqrt(box.SquareExtent());
// Find the minimal bounding box edge
double bmin[3], bmax[3];
box.Get(bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2]);
@@ -3060,6 +3370,12 @@ IfcGeom::Kernel::faceset_helper::faceset_helper(Kernel* kernel, const IfcSchema:
}
eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff);
if (eps_ < Precision::Confusion()) {
// occt uses some hard coded precision values, don't go smaller than that.
// @todo, can be reset though with BRepLib::Precision(double)
eps_ = Precision::Confusion();
}
std::map<std::pair<int, int>, int> edge_use;
@@ -163,15 +163,38 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(),o);
bool hasRef = l->hasRefDirection();
if ( l->hasAxis() ) IfcGeom::Kernel::convert(l->Axis(),axis);
if ( hasRef ) IfcGeom::Kernel::convert(l->RefDirection(),refDirection);
gp_Ax3 ax3;
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
else ax3 = gp_Ax3(o,axis);
IN_CACHE(IfcAxis2Placement3D, l, gp_Trsf, trsf)
gp_Pnt o;
gp_Dir axis(0, 0, 1);
gp_Dir refDirection;
IfcGeom::Kernel::convert(l->Location(), o);
const bool hasAxis = l->hasAxis();
const bool hasRef = l->hasRefDirection();
if (hasAxis != hasRef) {
Logger::Warning("Axis and RefDirection should be specified together", l);
}
if (hasAxis) {
IfcGeom::Kernel::convert(l->Axis(), axis);
}
if (hasRef) {
IfcGeom::Kernel::convert(l->RefDirection(), refDirection);
} else {
if (!axis.IsParallel(gp::DX(), 1.e-5)) {
refDirection = gp::DX();
} else {
refDirection = gp::DZ();
}
gp_Vec Xvec = axis.Dot(refDirection) * axis;
gp_Vec Xaxis = refDirection.XYZ() - Xvec.XYZ();
refDirection = Xaxis;
}
gp_Ax3 ax3(o, axis, refDirection);
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
trsf.SetTransformation(ax3, gp::XOY());
@@ -482,8 +482,46 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
TopoDS_Wire boundary_wire;
IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand();
IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand();
bool is_halfspace = operand2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class());
bool is_unbounded_halfspace = is_halfspace && !operand2->declaration().is(IfcSchema::IfcPolygonalBoundedHalfSpace::Class());
bool has_halfspace_operand = false;
BOPAlgo_Operation occ_op;
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
occ_op = BOPAlgo_CUT;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
occ_op = BOPAlgo_COMMON;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
occ_op = BOPAlgo_FUSE;
} else {
return false;
}
std::vector<IfcSchema::IfcBooleanOperand*> second_operands;
second_operands.push_back(operand2);
if (occ_op == BOPAlgo_CUT) {
bool process_as_list = true;
while (true) {
auto res1 = operand1->as<IfcSchema::IfcBooleanResult>();
if (res1) {
if (res1->Operator() == op) {
operand1 = res1->FirstOperand();
second_operands.push_back(res1->SecondOperand());
} else {
process_as_list = false;
break;
}
} else {
break;
}
}
if (!process_as_list) {
operand1 = l->FirstOperand();
second_operands = { operand2 };
}
}
if ( shape_type(operand1) == ST_SHAPELIST ) {
if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) {
@@ -501,49 +539,60 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
}
const double first_operand_volume = shape_volume(s1);
if ( first_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand());
bool shape2_processed = false;
if ( shape_type(operand2) == ST_SHAPELIST ) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else if ( shape_type(operand2) == ST_SHAPE ) {
shape2_processed = convert_shape(operand2,s2);
if (shape2_processed && !is_halfspace) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
} else {
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
if (first_operand_volume <= ALMOST_ZERO) {
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", l->FirstOperand());
}
if (!shape2_processed) {
shape = s1;
Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l);
return true;
}
TopTools_ListOfShape second_operand_shapes;
if (!is_halfspace) {
const double second_operand_volume = shape_volume(s2);
if ( second_operand_volume <= ALMOST_ZERO )
Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2);
}
for (auto& operand2 : second_operands) {
bool shape2_processed = false;
if (is_unbounded_halfspace) {
TopoDS_Shape temp;
double d;
if (fit_halfspace(s1, s2, temp, d)) {
if (d < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_WARNING, "Subtraction yields unchanged volume:", l);
shape = s1;
return true;
bool is_halfspace = operand2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class());
bool is_unbounded_halfspace = is_halfspace && !operand2->declaration().is(IfcSchema::IfcPolygonalBoundedHalfSpace::Class());
has_halfspace_operand |= is_halfspace;
{
if (shape_type(operand2) == ST_SHAPELIST) {
shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true);
} else if (shape_type(operand2) == ST_SHAPE) {
shape2_processed = convert_shape(operand2, s2);
if (shape2_processed) {
TopoDS_Solid temp_solid;
s2 = ensure_fit_for_subtraction(s2, temp_solid);
}
} else {
s2 = temp;
Logger::Message(Logger::LOG_ERROR, "Invalid representation item for boolean operation", operand2);
}
}
}
const IfcSchema::IfcBooleanOperator::Value op = l->Operator();
if (is_unbounded_halfspace) {
TopoDS_Shape temp;
double d;
if (fit_halfspace(s1, s2, temp, d)) {
if (d < getValue(GV_PRECISION)) {
Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", l);
continue;
} else {
s2 = temp;
}
}
}
if (!shape2_processed) {
Logger::Message(Logger::LOG_ERROR, "Failed to convert SecondOperand:", operand2);
continue;
}
if (operand2->declaration().is(IfcSchema::IfcHalfSpaceSolid::Class())) {
const double second_operand_volume = shape_volume(s2);
if (second_operand_volume <= ALMOST_ZERO) {
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", operand2);
}
}
second_operand_shapes.Append(s2);
}
/*
// TK: A little debugging trick to output both operands for visual inspection
@@ -555,24 +604,13 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcBooleanResult* l, TopoDS_Shape
builder.Add(compound, s2);
shape = compound;
return true;
*/
BOPAlgo_Operation occ_op;
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
occ_op = BOPAlgo_CUT;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) {
occ_op = BOPAlgo_COMMON;
} else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) {
occ_op = BOPAlgo_FUSE;
} else {
return false;
}
*/
#if OCC_VERSION_HEX < 0x60900
bool valid_result = boolean_operation(s1, s2, occ_op, shape);
#else
const double fuzz = is_halfspace ? getValue(GV_PRECISION) * 10. : -1.;
bool valid_result = boolean_operation(s1, s2, occ_op, shape, fuzz);
const double fuzz = has_halfspace_operand ? getValue(GV_PRECISION) * 10. : -1.;
bool valid_result = boolean_operation(s1, second_operand_shapes, occ_op, shape, fuzz);
#endif
if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) {
@@ -893,7 +931,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangularTrimmedSurface* l,
}
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) {
gp_Trsf directrix, position;
gp_Trsf directrix;
TopoDS_Shape face;
TopoDS_Wire wire, section;
@@ -972,7 +1010,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l,
if (has_position) {
// IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D
// and therefore has a unit scale factor
shape.Move(position);
shape.Move(trsf);
}
return true;
@@ -1121,9 +1159,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCylindricalSurface* l, TopoDS_
// IfcElementarySurface.Position has unit scale factor
#if OCC_VERSION_HEX < 0x60502
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius())).Face().Moved(trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT))).Face().Moved(trsf);
#else
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius()), getValue(GV_PRECISION)).Face().Moved(trsf);
face = BRepBuilderAPI_MakeFace(new Geom_CylindricalSurface(gp::XOY(), l->Radius() * getValue(GV_LENGTH_UNIT)), getValue(GV_PRECISION)).Face().Moved(trsf);
#endif
return true;
}
@@ -875,45 +875,53 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcIndexedPolyCurve* l, TopoDS_Wi
BRepBuilderAPI_MakeWire w;
IfcEntityList::ptr segments = l->Segments();
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
IfcUtil::IfcBaseClass* segment = *it;
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
std::vector<int> indices = *line;
gp_Pnt previous;
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
if (*jt < 1 || *jt > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
if(l->hasSegments()) {
IfcEntityList::ptr segments = l->Segments();
for (IfcEntityList::it it = segments->begin(); it != segments->end(); ++it) {
IfcUtil::IfcBaseClass* segment = *it;
if (segment->declaration().is(IfcSchema::IfcLineIndex::Class())) {
IfcSchema::IfcLineIndex* line = (IfcSchema::IfcLineIndex*) segment;
std::vector<int> indices = *line;
gp_Pnt previous;
for (std::vector<int>::const_iterator jt = indices.begin(); jt != indices.end(); ++jt) {
if (*jt < 1 || *jt > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(*jt));
}
const gp_Pnt& current = points[*jt - 1];
if (jt != indices.begin()) {
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
}
previous = current;
}
const gp_Pnt& current = points[*jt - 1];
if (jt != indices.begin()) {
w.Add(BRepBuilderAPI_MakeEdge(previous, current));
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
std::vector<int> indices = *arc;
if (indices.size() != 3) {
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
}
previous = current;
}
} else if (segment->declaration().is(IfcSchema::IfcArcIndex::Class())) {
IfcSchema::IfcArcIndex* arc = (IfcSchema::IfcArcIndex*) segment;
std::vector<int> indices = *arc;
if (indices.size() != 3) {
throw IfcParse::IfcException("Invalid IfcArcIndex encountered");
}
for (int i = 0; i < 3; ++i) {
const int& idx = indices[i];
if (idx < 1 || idx > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
for (int i = 0; i < 3; ++i) {
const int& idx = indices[i];
if (idx < 1 || idx > max_index) {
throw IfcParse::IfcException("IfcIndexedPolyCurve index out of bounds for index " + boost::lexical_cast<std::string>(idx));
}
}
const gp_Pnt& a = points[indices[0] - 1];
const gp_Pnt& b = points[indices[1] - 1];
const gp_Pnt& c = points[indices[2] - 1];
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
} else {
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + segment->declaration().name());
}
const gp_Pnt& a = points[indices[0] - 1];
const gp_Pnt& b = points[indices[1] - 1];
const gp_Pnt& c = points[indices[2] - 1];
Handle(Geom_Circle) circ = GC_MakeCircle(a, b, c).Value();
w.Add(BRepBuilderAPI_MakeEdge(circ, a, c));
} else {
throw IfcParse::IfcException("Unexpected IfcIndexedPolyCurve segment of type " + segment->declaration().name());
}
}
} else if (points.begin() < points.end()) {
std::vector<gp_Pnt>::const_iterator previous = points.begin();
for (std::vector<gp_Pnt>::const_iterator current = previous+1; current < points.end(); ++current){
w.Add(BRepBuilderAPI_MakeEdge(*previous, *current));
previous = current;
}
}
result = w.Wire();
return true;
}
@@ -85,7 +85,7 @@ namespace IfcGeom {
const ConversionResultPlacement* Placement() const { return placement; }
bool hasStyle() const { return style != 0; }
const SurfaceStyle& Style() const { return *style; }
void setStyle(const SurfaceStyle* style) { this->style = style; }
void setStyle(const SurfaceStyle* newStyle) { style = newStyle; }
int ItemId() const { return id; }
};
+13 -10
View File
@@ -40,14 +40,17 @@ namespace IfcGeom {
/// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
struct filter {
filter() : include(false), traverse(false) {}
filter(bool incl, bool trav) : include(incl), traverse(trav) {}
struct filter
{
filter() : include(false), traverse(false), traverse_openings(false) {}
filter(bool incl, bool trav, bool trav_openings = false) : include(incl), traverse(trav), traverse_openings(trav_openings) {}
/// Should the product be included (true) or excluded (false).
bool include;
/// If traversal requested, traverse to the parents to see if they satisfy the criteria. E.g. we might be looking for
/// children of a storey named "Level 20", or children of entities that have no representation, e.g. IfcCurtainWall.
bool traverse;
/// Include opening relationships as part of traversal.
bool traverse_openings;
/// Optional description for the filtering criteria of this filter.
std::string description;
@@ -59,9 +62,10 @@ namespace IfcGeom {
return is_match == include;
}
static bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) {
IfcUtil::IfcBaseEntity* parent, *current = prod;
while ((parent = IfcGeom::Kernel::get_decomposing_entity(current)) != nullptr) {
bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const
{
IfcUtil::IfcBaseEntity* parent, *current = prod;
while ((parent = IfcGeom::Kernel::get_decomposing_entity(current, traverse_openings)) != nullptr) {
if (pred(parent)) {
return true;
}
@@ -139,8 +143,7 @@ namespace IfcGeom {
}
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
// @note bind1st() and mem_fun() deprecated in C++11, use bind() and mem_fn() when migrating to C++11.
return filter::match(prod, std::bind1st(std::mem_fun(&attribute_filter::match), this));
return filter::match(prod, std::bind(&attribute_filter::match, this, std::placeholders::_1));
}
void update_description() {
@@ -172,7 +175,7 @@ namespace IfcGeom {
}
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
return filter::match(prod, std::bind1st(std::mem_fun(&layer_filter::match), this));
return filter::match(prod, std::bind(&layer_filter::match, this, std::placeholders::_1));
}
struct wildcards_match {
@@ -215,7 +218,7 @@ namespace IfcGeom {
}
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
return filter::match(prod, std::bind1st(std::mem_fun(&entity_filter::match), this));
return filter::match(prod, std::bind(&entity_filter::match, this, std::placeholders::_1));
}
void update_description() {
@@ -86,7 +86,7 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) {
}
}
IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound() const {
IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const {
TopoDS_Compound compound;
BRep_Builder builder;
builder.MakeCompound(compound);
@@ -98,7 +98,7 @@ IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound() con
trsf = ((OpenCascadePlacement*)it->Placement())->trsf();
}
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
gp_Trsf scale;
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
trsf.PreMultiply(scale);
@@ -60,7 +60,7 @@ namespace IfcGeom {
IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); }
const IfcGeom::ConversionResults& shapes() const { return shapes_; }
const std::string& id() const { return id_; }
ConversionResultShape* as_compound() const;
ConversionResultShape* as_compound(bool force_meters = false) const;
bool calculate_volume(double&) const;
bool calculate_surface_area(double&) const;
+6 -23
View File
@@ -91,11 +91,11 @@ IfcGeom::Kernel* IfcGeom::impl::KernelFactoryImplementation::construct(const std
#define CREATE_GET_DECOMPOSING_ENTITY(IfcSchema) \
\
IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product) { \
IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduct* product, bool include_openings) {\
IfcSchema::IfcObjectDefinition* parent = 0; \
\
/* In case of an opening element, parent to the RelatingBuildingElement */ \
if (product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \
if (include_openings && product->declaration().is(IfcSchema::IfcOpeningElement::Class())) { \
IfcSchema::IfcOpeningElement* opening = (IfcSchema::IfcOpeningElement*)product; \
IfcSchema::IfcRelVoidsElement::list::ptr voids = opening->VoidsElements(); \
if (voids->size()) { \
@@ -106,7 +106,7 @@ IfcSchema::IfcObjectDefinition* get_decomposing_entity_impl(IfcSchema::IfcProduc
IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product; \
IfcSchema::IfcRelFillsElement::list::ptr fills = element->FillsVoids(); \
/* In case of a RelatedBuildingElement parent to the opening element */ \
if (fills->size()) { \
if (fills->size() && include_openings) { \
for (IfcSchema::IfcRelFillsElement::list::it it = fills->begin(); it != fills->end(); ++it) { \
IfcSchema::IfcRelFillsElement* fill = *it; \
IfcSchema::IfcObjectDefinition* ifc_objectdef = fill->RelatingOpeningElement(); \
@@ -158,26 +158,17 @@ namespace {
CREATE_GET_DECOMPOSING_ENTITY(Ifc4);
}
IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst) {
IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) {
if (inst->as<Ifc2x3::IfcProduct>()) {
return get_decomposing_entity_impl(inst->as<Ifc2x3::IfcProduct>());
return get_decomposing_entity_impl(inst->as<Ifc2x3::IfcProduct>(), include_openings);
} else if (inst->as<Ifc4::IfcProduct>()) {
return get_decomposing_entity_impl(inst->as<Ifc4::IfcProduct>());
return get_decomposing_entity_impl(inst->as<Ifc4::IfcProduct>(), include_openings);
} else {
throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name());
}
}
namespace {
// LayerAssignments renamed from plural to singular, LayerAssignment, so work around that
IfcEntityList::ptr getLayerAssignments(Ifc2x3::IfcRepresentationItem* item) {
return item->LayerAssignments()->generalize();
}
IfcEntityList::ptr getLayerAssignments(Ifc4::IfcRepresentationItem* item) {
return item->LayerAssignment()->generalize();
}
template <typename Schema>
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers_impl(typename Schema::IfcProduct* prod) {
std::map<std::string, IfcUtil::IfcBaseEntity*> layers;
@@ -190,14 +181,6 @@ namespace {
layers[(*jt)->Name()] = *jt;
}
}
typename Schema::IfcRepresentationItem::list::ptr items = r->template as<typename Schema::IfcRepresentationItem>();
for (typename Schema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) {
typename Schema::IfcPresentationLayerAssignment::list::ptr a = getLayerAssignments(*it)->template as<typename Schema::IfcPresentationLayerAssignment>();
for (typename Schema::IfcPresentationLayerAssignment::list::it jt = a->begin(); jt != a->end(); ++jt) {
layers[(*jt)->Name()] = *jt;
}
}
}
return layers;
}
+1 -1
View File
@@ -78,7 +78,7 @@ namespace IfcGeom {
static int surface_genus(const ConversionResultShape*);
static bool is_manifold(const ConversionResultShape*);
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*);
static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*, bool include_openings=true);
static std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*);
static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product);
};
@@ -72,6 +72,7 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
if (!default_materials_initialized) InitDefaultMaterials();
default_materials.clear();
// @todo this will probably need to be updated for UTF-8 paths on Windows
pt::ptree root;
pt::read_json(json_file, root);