diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 09c10dd964..8db95bdd7a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -841,7 +841,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell: bool OpenCascadeKernel::convert(const taxonomy::matrix4* matrix, gp_GTrsf& trsf) { // @todo check for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, matrix->components(i, j)); } } @@ -1415,14 +1415,42 @@ OpenCascadeKernel::faceset_helper::~faceset_helper() { kernel_->faceset_helper_ = nullptr; } +#include "IfcGeomTree.h" + +namespace { + void find_neighbours(ifcopenshell::geometry::impl::tree& tree, std::vector>& pnts, std::set& visited, int p, double eps) { + visited.insert(p); + + Bnd_Box b; + b.Set(*pnts[p].get()); + b.Enlarge(eps); + + std::vector js = tree.select_box(b, false); + for (int j : js) { + visited.insert(j); +#ifdef FACESET_HELPER_RECURSIVE + if (visited.find(j) == visited.end()) { + // @todo, making this recursive removes the dependence on the initial ordering, but will + // likely result in empty results when all vertices are within 1 eps from another point. + find_neighbours(tree, pnts, visited, j, eps); + } +#endif + } + } +} + OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell* shell) : kernel_(kernel) , non_manifold_(false) { kernel->faceset_helper_ = this; + // @todo use pointers? std::vector points; + std::vector loops; + for (auto& f : shell->children_as()) { for (auto& l : f->children_as()) { + loops.push_back(l); for (auto& e : l->children_as()) { // @todo make sure only cartesian points are provided here points.push_back(boost::get(e->start)); @@ -1434,22 +1462,17 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con std::vector vertices(pnts.size()); // @todo - /* - IfcGeom::impl::tree tree; + impl::tree tree; BRep_Builder B; Bnd_Box box; - for (size_t i = 0; i < points->size(); ++i) { - gp_Pnt* p = new gp_Pnt(); - if (kernel->convert(*(points->begin() + i), *p)) { - pnts[i].reset(p); - B.MakeVertex(vertices[i], *p, Precision::Confusion()); - tree.add(i, vertices[i]); - box.Add(*p); - } else { - delete p; - } + for (size_t i = 0; i < points.size(); ++i) { + gp_Pnt* p = new gp_Pnt(convert_xyz(points[i])); + pnts[i].reset(p); + B.MakeVertex(vertices[i], *p, Precision::Confusion()); + tree.add(i, vertices[i]); + box.Add(*p); } // Use the bbox diagonal to influence local epsilon @@ -1469,19 +1492,18 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con double bdiff = std::numeric_limits::infinity(); for (size_t i = 0; i < 3; ++i) { const double d = bmax[i] - bmin[i]; - if (d > kernel->getValue(GV_PRECISION) * 10. && d < bdiff) { + if (d > kernel->precision_ * 10. && d < bdiff) { bdiff = d; } } - eps_ = kernel->getValue(GV_PRECISION) * 10. * (std::min)(1.0, bdiff); + eps_ = kernel->precision_ * 10. * (std::min)(1.0, bdiff); // @todo, there a tiny possibility that the duplicate faces are triggered // for an internal boundary, that is also present as an external boundary. // This will result in non-manifold configuration then, but this is deemed // such as corner-case that it is not considered. - IfcSchema::IfcPolyLoop::list::ptr loops = IfcParse::traverse((IfcUtil::IfcBaseClass*)l)->as(); - + size_t loops_removed, non_manifold, duplicate_faces; std::map, int> edge_use; @@ -1512,9 +1534,9 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con find_neighbours(tree, pnts, vs, i, eps_); for (int v : vs) { - auto pt = *(points->begin() + v); + auto& pt = points[v]; // NB: insert() ignores duplicate keys - vertex_mapping_.insert({ pt->data().id() , i }); + vertex_mapping_.insert({ pt.instance->data().id() , i }); } } } @@ -1523,20 +1545,18 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con typedef std::set edge_set_t; std::set edge_sets; - for (auto& loop : *loops) { - auto ps = loop->Polygon(); - + for (auto& loop : loops) { std::vector > segments; edge_set_t segment_set; - loop_(ps, [&segments, &segment_set](int C, int D, bool) { + loop_(loop, [&segments, &segment_set](int C, int D, bool) { segment_set.insert({ { C, D } }); segments.push_back({ C, D }); }); if (edge_sets.find(segment_set) != edge_sets.end()) { duplicate_faces++; - duplicates_.insert(loop); + duplicates_.insert(loop->instance->data().id()); continue; } edge_sets.insert(segment_set); @@ -1567,8 +1587,7 @@ OpenCascadeKernel::faceset_helper::faceset_helper(OpenCascadeKernel* kernel, con } } - if (loops_removed || (non_manifold && l->declaration().is(IfcSchema::IfcClosedShell::Class()))) { - Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", l); + if (loops_removed || (non_manifold && shell->closed.get_value_or(false))) { + Logger::Warning(boost::lexical_cast(duplicate_faces) + " duplicate faces removed, " + boost::lexical_cast(loops_removed) + " loops removed and " + boost::lexical_cast(non_manifold) + " non-manifold edges for:", shell->instance); } - */ } \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 73869ae50c..060217a2c7 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -23,7 +23,7 @@ #include "../../../ifcparse/IfcFile.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomIterator.h" -#include "../../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../../ifcgeom/schema_agnostic/Converter.h" #include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" #include @@ -33,7 +33,7 @@ #include #include -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { namespace impl { template @@ -259,30 +259,30 @@ namespace IfcGeom { tree() {}; tree(IfcParse::IfcFile& f) { - add_file(f, IfcGeom::IteratorSettings()); + add_file(f, ifcopenshell::geometry::settings()); } - tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { + tree(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) { add_file(f, settings); } - void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { - IfcGeom::IteratorSettings settings_ = settings; - settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); - settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); + void add_file(IfcParse::IfcFile& f, const ifcopenshell::geometry::settings& settings) { + ifcopenshell::geometry::settings settings_ = settings; + settings_.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true); + settings_.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, true); + settings_.set(ifcopenshell::geometry::settings::SEW_SHELLS, true); - IfcGeom::Iterator it(settings_, &f); + Iterator it(settings_, &f); if (it.initialize()) { do { - IfcGeom::NativeElement* elem = (IfcGeom::NativeElement*)it.get(); + NativeElement* elem = (NativeElement*)it.get(); add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape()); } while (it.next()); } } }; -} +}} #endif diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 6e45b00859..6d11395d79 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -12,7 +12,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const settings& setti // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 689a539f27..ecfef11143 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -163,7 +163,9 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcFaceBasedSurfaceModel* ins } taxonomy::item* mapping::map_impl(const IfcSchema::IfcConnectedFaceSet* inst) { - return map_to_collection(this, inst->CfsFaces()); + auto shell = map_to_collection(this, inst->CfsFaces()); + shell->closed = inst->declaration().is(IfcSchema::IfcClosedShell::Class()); + return shell; } taxonomy::item* mapping::map_impl(const IfcSchema::IfcFace* inst) { diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index 28605992df..91465eabd4 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -96,7 +96,7 @@ ifcopenshell::geometry::ConversionResultShape* ifcopenshell::geometry::Represent // @todo, check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, it->Placement().components(i, j)); } } @@ -241,7 +241,7 @@ bool ifcopenshell::geometry::Representation::BRep::calculate_projected_surface_a // @todo check gp_GTrsf trsf; for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 4; ++i) { + for (int j = 0; j < 4; ++j) { trsf.SetValue(i + 1, j + 1, place.components(i, j)); } } diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 3be8ec2f6d..b657d4ae32 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -193,6 +193,8 @@ struct collection : public geom_item { }; struct shell : public collection { + boost::optional closed; + virtual item* clone() const { return new shell(*this); } virtual kinds kind() const { return SHELL; } };