containment check

This commit is contained in:
Thomas Krijnen
2020-01-21 16:26:00 +01:00
parent 487be4b65e
commit 3575aded90
6 changed files with 1410 additions and 1098 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,242 @@
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#include "../ifcgeom/schema_agnostic/IfcGeomFilter.h"
#include "../ifcgeom/schema_agnostic/IfcGeomIterator.h"
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <algorithm>
void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
settings.set(ifcopenshell::geometry::settings::WELD_VERTICES, false);
settings.set(ifcopenshell::geometry::settings::SEW_SHELLS, true);
settings.set(ifcopenshell::geometry::settings::CONVERT_BACK_UNITS, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_TRIANGULATION, true);
settings.set(ifcopenshell::geometry::settings::DISABLE_OPENING_SUBTRACTIONS, true);
std::vector<ifcopenshell::geometry::filter_t> no_openings_and_spaces = {
IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"})
};
ifcopenshell::geometry::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces);
auto get_elevation = [](IfcUtil::IfcBaseClass* a) {
return ((IfcUtil::IfcBaseEntity*)a)->get_value_or<double>("Elevation", 0.);
};
// latebound inverse attribute lookup not working
auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure");
std::map<IfcUtil::IfcBaseClass*, IfcUtil::IfcBaseClass*> elem_to_storey;
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](IfcUtil::IfcBaseClass* r) {
auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcEntityList::ptr>("RelatedElements");
auto storey = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcUtil::IfcBaseClass*>("RelatingStructure");
if (storey->declaration().name() == "IfcBuildingStorey") {
for (auto it = elems->begin(); it != elems->end(); ++it) {
elem_to_storey[*it] = storey;
}
}
});
auto storeys = f.instances_by_type("IfcBuildingStorey");
std::vector<IfcUtil::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](IfcUtil::IfcBaseClass* a, IfcUtil::IfcBaseClass* b) {
return get_elevation(a) < get_elevation(b);
});
std::vector<double> elevations;
std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation);
double LARGE = 100;
std::vector<std::pair<double, double>> elevation_slices;
for (size_t i = 0; i < elevations.size(); ++i) {
elevation_slices.push_back({
i == 0 ? -LARGE : elevations[i],
i + 1 == elevations.size() ? LARGE : elevations[i + 1]
});
}
std::vector<CGAL::Nef_polyhedron_3<Kernel_>> nefs;
std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair<double, double>& p) {
Kernel_::Point_3 p1(-LARGE, -LARGE, p.first);
Kernel_::Point_3 p2(+LARGE, +LARGE, p.second);
auto poly = ifcopenshell::geometry::utils::create_cube(p1, p2);
auto bb = CGAL::Polygon_mesh_processing::bbox(poly);
std::wcout << "storey ";
for (int i = 0; i < 3; ++i) {
std::wcout << bb.min(i) << " ";
}
std::wcout << "- ";
for (int i = 0; i < 3; ++i) {
std::wcout << bb.max(i) << " ";
}
std::wcout << std::endl;
std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
auto nef = ifcopenshell::geometry::utils::create_nef_polyhedron(poly);
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(nef);
std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
return nef;
});
if (!context_iterator.initialize()) {
return;
}
size_t num_created = 0;
int old_progress = quiet ? 0 : -1;
for (;; ++num_created) {
bool has_more = true;
if (num_created) {
has_more = context_iterator.next();
}
ifcopenshell::geometry::NativeElement* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (!geom_object) {
break;
}
std::stringstream ss;
ss << geom_object->product()->data().toString();
auto sss = ss.str();
std::wcout << sss.c_str() << std::endl;
if (elem_to_storey.find(geom_object->product()) == elem_to_storey.end()) {
std::wcout << "not associated to storey" << std::endl;
continue;
}
for (auto& g : geom_object->geometry()) {
auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape();
const auto& m = g.Placement().components;
const auto& n = geom_object->transformation().data().components;
if (!m.isIdentity()) {
const cgal_placement_t trsf(
m(0, 0), m(0, 1), m(0, 2), m(0, 3),
m(1, 0), m(1, 1), m(1, 2), m(1, 3),
m(2, 0), m(2, 1), m(2, 2), m(2, 3));
const cgal_placement_t trsf2(
n(0, 0), n(0, 1), n(0, 2), n(0, 3),
n(1, 0), n(1, 1), n(1, 2), n(1, 3),
n(2, 0), n(2, 1), n(2, 2), n(2, 3));
// Apply transformation
for (auto &vertex : vertices(s)) {
vertex->point() = vertex->point().transform(trsf).transform(trsf2);
}
}
auto bb = CGAL::Polygon_mesh_processing::bbox(s);
std::wcout << "elem ";
for (int i = 0; i < 3; ++i) {
std::wcout << bb.min(i) << " ";
}
std::wcout << "- ";
for (int i = 0; i < 3; ++i) {
std::wcout << bb.max(i) << " ";
}
std::wcout << std::endl;
CGAL::Nef_polyhedron_3<Kernel_> part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s);
if (!part_nef.is_simple()) {
std::wcout << "not simple" << std::endl;
continue;
}
std::wcout << "volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(s)) << std::endl;
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef);
std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
std::vector<double> intersection_volumes;
std::transform(nefs.begin(), nefs.end(), std::back_inserter(intersection_volumes), [&part_nef](const CGAL::Nef_polyhedron_3<Kernel_>& storey_nef) {
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(storey_nef);
std::wcout << " storey faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef);
std::wcout << " part faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef + storey_nef);
std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef - storey_nef);
std::wcout << " faces " << faces(poly).size() << " volume " << CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly)) << std::endl;
}
{
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef);
std::wcout << " faces " << faces(poly).size();
return CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly));
}
});
std::wcout << "volumes: ";
for (auto& v : intersection_volumes) {
std::wcout << v << " ";
}
std::wcout << std::endl;
auto idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin();
if (storeys_sorted[idx] != elem_to_storey[geom_object->product()]) {
auto s = geom_object->product()->data().toString();
auto s1 = storeys_sorted[idx]->data().toString();
auto s2 = elem_to_storey[geom_object->product()]->data().toString();
std::wcout << "Mismatch on " << s.c_str() << ": " << s1.c_str() << " vs " << s2.c_str() << std::endl;
}
}
if (!no_progress) {
if (quiet) {
const int progress = context_iterator.progress();
for (; old_progress < progress; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
const int progress = context_iterator.progress() / 2;
if (old_progress != progress) Logger::ProgressBar(progress);
old_progress = progress;
}
}
}
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
std::cout << ".";
if (stderr_progress)
std::cerr << ".";
}
std::cout << std::flush;
if (stderr_progress)
std::cerr << std::flush;
} else {
Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
" objects ");
}
}
+69 -13
View File
@@ -37,7 +37,7 @@ void CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) {
}
}
CGAL::Polyhedron_3<Kernel_> CgalKernel::create_polyhedron(std::list<cgal_face_t> &face_list) {
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(std::list<cgal_face_t> &face_list) {
// Naive creation
CGAL::Polyhedron_3<Kernel_> polyhedron;
@@ -65,7 +65,7 @@ CGAL::Polyhedron_3<Kernel_> CgalKernel::create_polyhedron(std::list<cgal_face_t>
return polyhedron;
}
CGAL::Polyhedron_3<Kernel_> CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron) {
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_>& nef_polyhedron) {
if (nef_polyhedron.is_simple()) {
try {
CGAL::Polyhedron_3<Kernel_> polyhedron;
@@ -81,7 +81,7 @@ CGAL::Polyhedron_3<Kernel_> CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3
}
}
CGAL::Nef_polyhedron_3<Kernel_> CgalKernel::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
CGAL::Polyhedron_3<Kernel_> polyhedron = create_polyhedron(face_list);
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
@@ -89,11 +89,11 @@ CGAL::Nef_polyhedron_3<Kernel_> CgalKernel::create_nef_polyhedron(std::list<cgal
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
return nef_polyhedron;
} return nef_polyhedron;
}
return nef_polyhedron;
}
CGAL::Nef_polyhedron_3<Kernel_> CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
if (polyhedron.is_valid()) {
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
@@ -101,8 +101,8 @@ CGAL::Nef_polyhedron_3<Kernel_> CgalKernel::create_nef_polyhedron(CGAL::Polyhedr
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
return nef_polyhedron;
} return nef_polyhedron;
}
return nef_polyhedron;
} else {
Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
return CGAL::Nef_polyhedron_3<Kernel_>();
@@ -134,7 +134,7 @@ bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) {
face_list.push_back(face);
}
shape = create_polyhedron(face_list);
shape = utils::create_polyhedron(face_list);
return true;
}
@@ -337,12 +337,12 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha
} face_list.push_back(top_face);
if (bottom_face.inner.empty()) {
shape = create_polyhedron(face_list);
shape = utils::create_polyhedron(face_list);
// if (has_position) for (auto &vertex : vertices(shape)) vertex->point() = vertex->point().transform(trsf);
return true;
}
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = create_nef_polyhedron(face_list);
CGAL::Nef_polyhedron_3<Kernel_> nef_shape = utils::create_nef_polyhedron(face_list);
// Inner
// TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction
@@ -378,7 +378,7 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha
} face_list.push_back(hole_top_face);
try {
nef_shape -= create_nef_polyhedron(face_list);
nef_shape -= utils::create_nef_polyhedron(face_list);
} catch (...) {
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", extrusion->instance);
return false;
@@ -401,7 +401,7 @@ bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &sha
}
CGAL::Polyhedron_3<Kernel_> CgalKernel::create_cube(double d) {
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_cube(double d) {
cgal_face_t bottom_face;
bottom_face.outer.push_back(Kernel_::Point_3(-d, -d, -d));
bottom_face.outer.push_back(Kernel_::Point_3(+d, -d, -d));
@@ -447,6 +447,62 @@ CGAL::Polyhedron_3<Kernel_> CgalKernel::create_cube(double d) {
return create_polyhedron(face_list);
}
CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper) {
cgal_face_t bottom_face;
auto& a0 = lower.cartesian(0);
auto& a1 = lower.cartesian(1);
auto& a2 = lower.cartesian(2);
auto& b0 = upper.cartesian(0);
auto& b1 = upper.cartesian(1);
auto& b2 = upper.cartesian(2);
bottom_face.outer.push_back(Kernel_::Point_3(a0, a1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(b0, a1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(b0, b1, a2));
bottom_face.outer.push_back(Kernel_::Point_3(a0, b1, a2));
cgal_direction_t dir(0, 0, b2 - a2);
std::list<cgal_face_t> face_list = { bottom_face };
for (std::vector<Kernel_::Point_3>::const_iterator current_vertex = bottom_face.outer.begin();
current_vertex != bottom_face.outer.end();
++current_vertex)
{
std::vector<Kernel_::Point_3>::const_iterator next_vertex = current_vertex;
++next_vertex;
if (next_vertex == bottom_face.outer.end()) {
next_vertex = bottom_face.outer.begin();
}
cgal_face_t side_face;
side_face.outer.push_back(*next_vertex);
side_face.outer.push_back(*current_vertex);
side_face.outer.push_back(*current_vertex + dir);
side_face.outer.push_back(*next_vertex + dir);
face_list.push_back(side_face);
}
cgal_face_t top_face;
for (std::vector<Kernel_::Point_3>::const_reverse_iterator vertex = bottom_face.outer.rbegin();
vertex != bottom_face.outer.rend();
++vertex)
{
top_face.outer.push_back(*vertex + dir);
}
face_list.push_back(top_face);
return create_polyhedron(face_list);
}
bool CgalKernel::thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result) {
// @todo this should be possible as a minkowski sum of facet & cube. rather than a set of boolean ops.
+10 -7
View File
@@ -89,6 +89,15 @@ public:
namespace ifcopenshell {
namespace geometry {
namespace utils {
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(double d);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
IFC_GEOM_API CGAL::Polyhedron_3<Kernel_> create_polyhedron(const CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
IFC_GEOM_API CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
}
namespace kernels {
class IFC_GEOM_API CgalKernel : public AbstractKernel {
@@ -97,7 +106,6 @@ namespace kernels {
size_t circle_segments_;
CGAL::Nef_polyhedron_3<Kernel_> precision_cube_;
CGAL::Polyhedron_3<Kernel_> create_cube(double d);
bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, bool dilate);
bool thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result);
public:
@@ -108,17 +116,12 @@ namespace kernels {
, precision_(1.e-5)
, circle_segments_(16)
{
auto cc = create_cube(precision_);
auto cc = utils::create_cube(precision_);
precision_cube_ = CGAL::Nef_polyhedron_3<Kernel_>(cc);
}
void remove_duplicate_points_from_loop(cgal_wire_t& polygon);
CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
CGAL::Polyhedron_3<Kernel_> create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron);
bool convert(const taxonomy::extrusion*, cgal_shape_t&);
bool convert(const taxonomy::face*, cgal_face_t&);
bool convert(const taxonomy::loop*, cgal_wire_t&);