Track time; fixes for wall connectivity check

This commit is contained in:
Thomas Krijnen
2020-01-29 14:57:49 +01:00
parent e448312d41
commit b91a34c8c6
7 changed files with 225 additions and 38 deletions
+9 -4
View File
@@ -946,14 +946,14 @@ void write_log(bool header) {
}
#include <boost/algorithm/string/predicate.hpp>
#include <chrono>
bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file, bool no_progress, bool mmap) {
time_t start, end;
std::clock_t c_start = std::clock();
// Prevent IfcFile::Init() prints by setting output to null temporarily
if (no_progress) { Logger::SetOutput(NULL, &log_stream); }
time(&start);
#ifdef USE_MMAP
ifc_file = new IfcParse::IfcFile(filename, mmap);
#else
@@ -970,10 +970,15 @@ bool init_input_file(const std::string& filename, IfcParse::IfcFile*& ifc_file,
Logger::Error("Unable to parse input file '" + filename + "'");
return false;
}
time(&end);
std::clock_t c_end = std::clock();
if (no_progress) { Logger::SetOutput(&cout_, &log_stream); }
else { Logger::Status("Parsing input file took " + format_duration(start, end)); }
else {
std::stringstream ss;
ss << std::setprecision(14) << (c_end - c_start) / (double)CLOCKS_PER_SEC;
Logger::Status("total_ifc_parse_time " + ss.str());
}
return true;
+105 -9
View File
@@ -1,25 +1,111 @@
#include "validation_utils.h"
using namespace ifcopenshell::geometry;
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
typedef Kernel_::FT FT;
typedef Kernel_::Point_3 Point;
typedef Kernel_::Segment_3 Segment;
typedef CGAL::Polyhedron_3<Kernel_> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
typedef CGAL::AABB_traits<Kernel_, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall", "IfcSpace" }, no_progress, quiet, stderr_progress);
intersection_validator v(f, { "IfcWall", "IfcSpace" }, 1.e-5, no_progress, quiet, stderr_progress);
auto rels = f.instances_by_type("IfcRelSpaceBoundary");
std::map<std::pair<const IfcUtil::IfcBaseClass*, const IfcUtil::IfcBaseClass*>, const IfcUtil::IfcBaseClass*> rel_by_space_elem;
if (rels) {
std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const IfcUtil::IfcBaseClass* rel) {
auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingSpace");
try {
auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedBuildingElement");
rel_by_space_elem.insert({ { x,y }, rel });
} catch (IfcParse::IfcException&) {
// RelatedBuildingElement can be NULL
}
});
}
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
IfcParse::IfcFile f2("boundaries-triangulated.ifc");
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);
ifcopenshell::geometry::Converter c("cgal", &f2, settings);
std::map<std::set<std::string>, std::vector<Kernel_::Point_3>> elem_to_space_boundary_coords;
for (auto& i : *f2.instances_by_type("IfcProduct")) {
auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value<std::string>("Name");
auto g1 = n.substr(0, 22);
auto g2 = n.substr(23);
auto item = c.mapping()->map(i);
auto shell = (taxonomy::shell*) ((taxonomy::collection*)((taxonomy::collection*) item)->children[0])->children[0];
for (auto& f : shell->children) {
auto face = (taxonomy::face*) f;
for (auto& w : face->children) {
auto wire = (taxonomy::loop*) w;
for (auto& e : wire->children) {
auto edge = (taxonomy::edge*) e;
auto p3 = boost::get<taxonomy::point3>(edge->start);
auto p4 = ((taxonomy::geom_item*)item)->matrix.components * p3.components.homogeneous();
Kernel_::Point_3 P(p4(0), p4(1), p4(2));
elem_to_space_boundary_coords[{g1, g2}].emplace_back(P);
}
}
}
}
v([](const intersection_validator::Box& a, const intersection_validator::Box& b) {
v([&rel_by_space_elem, &elem_to_space_boundary_coords](const intersection_validator::Box& a, const intersection_validator::Box& b) {
std::ostringstream ss;
// ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl;
// auto x = id_map[a.id()]->second * id_map[b.id()]->second;
ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl;
auto x = a.handle()->second * b.handle()->second;
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
auto A = a.handle()->first;
auto B = b.handle()->first;
CGAL::Polygon_mesh_processing::triangulate_faces(x_poly);
auto Aguid = A->get_value<std::string>("GlobalId");
auto Bguid = B->get_value<std::string>("GlobalId");
auto vs = vertices(x_poly);
if (std::distance(vs.begin(), vs.end()) == 0) {
int space_count = 0;
if (A->declaration().name() == "IfcSpace") {
space_count += 1;
}
if (B->declaration().name() == "IfcSpace") {
space_count += 1;
}
if (space_count != 1) {
return;
}
ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl;
auto x = a.handle()->second * b.handle()->second;
if (x.is_empty()) {
// std::wcout << "empty" << std::endl;
return;
}
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
auto s0 = a.handle()->first->declaration().name();
auto s1 = b.handle()->first->declaration().name();
auto i0 = a.handle()->first->data().id();
@@ -30,6 +116,16 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
std::swap(i0, i1);
}
Tree tree(faces(x_poly).first, faces(x_poly).second, x_poly);
tree.accelerate_distance_queries();
for (auto& p : elem_to_space_boundary_coords[{Aguid, Bguid}]) {
auto d = std::sqrt(CGAL::to_double(tree.squared_distance(p)));
std::wcout << d << std::endl;
}
return;
{
auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "sb.off";
+17 -7
View File
@@ -46,12 +46,14 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
return get_elevation(a) < get_elevation(b);
});
/*
std::wcout << "Storeys ";
for (auto& s : storeys_sorted) {
auto n = ((IfcUtil::IfcBaseEntity*)s)->get_value<std::string>("Name");
std::wcout << n.c_str() << " ";
}
std::wcout << std::endl;
*/
std::vector<double> elevations;
std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation);
@@ -69,13 +71,14 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
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) {
std::wcout << p.first << " - " << p.second << std::endl;
// std::wcout << p.first << " - " << p.second << std::endl;
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);
return ifcopenshell::geometry::utils::create_nef_polyhedron(poly);
});
/*
for (auto& n : nefs) {
auto poly = ifcopenshell::geometry::utils::create_polyhedron(n);
auto bounds = CGAL::Polygon_mesh_processing::bbox_3(poly);
@@ -87,6 +90,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
}
std::wcout << "---" << std::endl;
}
*/
if (!context_iterator.initialize()) {
return;
@@ -108,13 +112,15 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
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;
// std::wcout << "not associated to storey" << std::endl;
continue;
}
@@ -140,6 +146,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
vertex->point() = vertex->point().transform(trsf).transform(trsf2);
}
/*
{
auto bounds = CGAL::Polygon_mesh_processing::bbox_3(s);
for (int i = 0; i < 3; ++i) {
@@ -150,11 +157,12 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
}
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;
// std::wcout << "not simple" << std::endl;
continue;
}
@@ -166,18 +174,20 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
});
}
/*
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;
auto s = geom_object->product()->get_value<std::string>("GlobalId");
auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[idx])->get_value<std::string>("GlobalId");
auto s2 = ((IfcUtil::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value<std::string>("GlobalId");
Logger::Error("Element " + s + " contained in " + s2 + " located on " + s1);
}
if (!no_progress) {
+52 -15
View File
@@ -1,11 +1,14 @@
#include "validation_utils.h"
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <algorithm>
using namespace ifcopenshell::geometry;
void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall" }, no_progress, quiet, stderr_progress);
intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress);
ifcopenshell::geometry::settings settings;
@@ -31,7 +34,10 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
v([&c, &rel_by_elem, &rels_encounted](const intersection_validator::Box& a, const intersection_validator::Box& b) {
double total_nef_intersection_time = 0.;
double conversion_to_poly = 0.;
v([&c, &rel_by_elem, &rels_encounted, &total_nef_intersection_time, &conversion_to_poly](const intersection_validator::Box& a, const intersection_validator::Box& b) {
auto A = a.handle()->first;
auto B = b.handle()->first;
@@ -72,13 +78,33 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
std::ostringstream ss;
ss << A->data().toString() << "x" << B->data().toString() << std::endl;
std::clock_t intersection_begin = std::clock();
auto x = a.handle()->second * b.handle()->second;
std::clock_t intersection_end = std::clock();
total_nef_intersection_time += (intersection_end - intersection_begin) / (double) CLOCKS_PER_SEC;
if (x.is_empty()) {
return;
}
std::clock_t poly_begin = std::clock();
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
std::clock_t poly_end = std::clock();
conversion_to_poly += (poly_end - poly_begin) / (double)CLOCKS_PER_SEC;
auto dza = a.bbox().zmax() - a.bbox().zmin();
auto dzb = b.bbox().zmax() - b.bbox().zmin();
auto bb = CGAL::Polygon_mesh_processing::bbox_3(x_poly);
if (bb.zmax() - bb.zmin() < std::min(dza, dzb) / 3.) {
return;
}
CGAL::Polygon_mesh_processing::triangulate_faces(x_poly);
if (CGAL::Polygon_mesh_processing::area(x_poly) > 2.0) {
return;
}
auto get_axis_parameter_min_max = [&c, &x_poly](IfcUtil::IfcBaseEntity* inst) {
auto item = c.mapping()->map(inst);
@@ -86,13 +112,13 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
auto loop = ((taxonomy::collection*) shaperep)->children[0];
if (loop->kind() != taxonomy::LOOP) {
std::wcout << "no suitable axis" << std::endl;
// std::wcout << "no suitable axis" << std::endl;
} else {
auto first_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.front())->start;
auto last_vertex = ((taxonomy::edge*) ((taxonomy::loop*) loop)->children.back())->end;
if (first_vertex.which() != 0 || last_vertex.which() != 0) {
std::wcout << "trims not supported" << std::endl;
// std::wcout << "trims not supported" << std::endl;
} else {
auto p0 = boost::get<taxonomy::point3>(first_vertex);
auto p1 = boost::get<taxonomy::point3>(last_vertex);
@@ -114,7 +140,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
});
auto pit = std::minmax_element(parameters.begin(), parameters.end());
return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.first)));
return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.second)));
}
}
const auto& nan = std::numeric_limits<double>::quiet_NaN();
@@ -122,9 +148,9 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
};
auto qualify_connection_type = [](double l, const std::pair<double, double>& p) {
if (p.first < 1.e-5) {
if (p.first < 1.e-3) {
return "ATSTART";
} else if (p.second > l - 1.e-5) {
} else if (p.second > l - 1.e-3) {
return "ATEND";
} else {
return "ATPATH";
@@ -141,21 +167,32 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
if (a_type != atype_computed || b_type != btype_computed) {
if (rel) {
auto rel_str = rel->data().toString();
std::wcout << "ERROR: " << rel_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl;
Logger::Error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel);
} else {
auto A_str = A->data().toString();
auto B_str = B->data().toString();
std::wcout << "ERROR: no rel " << A_str.c_str() << " x " << B_str.c_str() << " " << atype_computed << " " << btype_computed << std::endl;
auto A_str = A->get_value<std::string>("GlobalId");
auto B_str = B->get_value<std::string>("GlobalId");
Logger::Error("No connection for adjacent " + A_str + " " + B_str);
}
}
});
std::for_each(rels->begin(), rels->end(), [&rels_encounted](const IfcUtil::IfcBaseClass* rel) {
std::for_each(rels->begin(), rels->end(), [&rels_encounted, &v](const IfcUtil::IfcBaseClass* rel) {
if (rels_encounted.find(rel) == rels_encounted.end()) {
auto rel_str = rel->data().toString();
std::wcout << "ERROR: " << rel_str.c_str() << " not found" << std::endl;
auto x = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
auto y = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedElement");
if (v.succesfully_processed.find(x) != v.succesfully_processed.end() && v.succesfully_processed.find(y) != v.succesfully_processed.end()) {
Logger::Error("Connection for non-adjacent walls", rel);
}
}
});
std::wcout << std::setprecision(14);
std::wcout << "total_map_time " << v.total_map_time << std::endl;
std::wcout << "total_geom_time " << v.total_geom_time << std::endl;
std::wcout << "total_nef_time " << v.total_nef_time << std::endl;
std::wcout << "total_minkowsky_time " << v.total_minkowsky_time << std::endl;
std::wcout << "total_box_time " << v.total_box_time << std::endl;
std::wcout << "total_nef_intersection_time " << total_nef_intersection_time << std::endl;
std::wcout << "total_conversion_to_poly_time " << conversion_to_poly << std::endl;
}
+24 -3
View File
@@ -421,7 +421,15 @@ struct intersection_validator {
std::vector<Box> boxes;
nefs_t nefs;
intersection_validator(IfcParse::IfcFile& f, std::initializer_list<std::string> entities, bool no_progress, bool quiet, bool stderr_progress) {
double total_map_time = 0.;
double total_geom_time = 0.;
double total_nef_time = 0.;
double total_minkowsky_time = 0.;
double total_box_time = 0.;
std::set<IfcUtil::IfcBaseEntity*> succesfully_processed;
intersection_validator(IfcParse::IfcFile& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::settings settings;
settings.set(ifcopenshell::geometry::settings::USE_WORLD_COORDS, false);
@@ -441,8 +449,7 @@ struct intersection_validator {
return;
}
auto kernel = (ifcopenshell::geometry::kernels::CgalKernel*) context_iterator.converter().kernel();
auto cube = kernel->precision_cube();
auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(ifcopenshell::geometry::utils::create_cube(eps));
size_t num_created = 0;
int old_progress = quiet ? 0 : -1;
@@ -485,13 +492,21 @@ struct intersection_validator {
vertex->point() = vertex->point().transform(trsf).transform(trsf2);
}
std::clock_t nef_begin = std::clock();
CGAL::Nef_polyhedron_3<Kernel_> nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s);
std::clock_t nef_end = std::clock();
total_nef_time += (nef_end - nef_begin) / (double) CLOCKS_PER_SEC;
if (nef.is_empty()) {
std::wcout << "Failed to create nef" << std::endl;
continue;
}
succesfully_processed.insert(geom_object->product());
nef = CGAL::minkowski_sum_3(nef, cube);
std::clock_t minkowski_end = std::clock();
total_minkowsky_time += (minkowski_end - nef_end) / (double) CLOCKS_PER_SEC;
std::wcout << "product: " << geom_object->product() << std::endl;
nefs.push_back({ geom_object->product(), nef });
@@ -550,10 +565,16 @@ struct intersection_validator {
" objects ");
}
total_geom_time = context_iterator.converter().total_geom_time;
total_map_time = context_iterator.converter().total_map_time;
}
template <typename Fn>
void operator()(Fn fn) {
std::clock_t box_overlap_begin = std::clock();
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), [](auto& x, auto& y) {});
std::clock_t box_overlap_end = std::clock();
total_box_time += (box_overlap_end - box_overlap_begin) / (double) CLOCKS_PER_SEC;
CGAL::box_self_intersection_d(boxes.begin(), boxes.end(), fn);
}
};
+10
View File
@@ -44,11 +44,16 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create
}
*/
std::clock_t map_start = std::clock();
// @todo how to combine product_node and rep_item?
auto product_node = (taxonomy::geom_item*) mapping_->map(product);
if (product_node == nullptr) {
return nullptr;
}
std::clock_t geom_start = std::clock();
auto place = taxonomy::matrix4();
std::swap(place, product_node->matrix);
@@ -57,6 +62,11 @@ ifcopenshell::geometry::NativeElement* ifcopenshell::geometry::Converter::create
shape = new ifcopenshell::geometry::Representation::BRep(s, representation_id_builder.str(), shapes);
std::clock_t geom_end = std::clock();
total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC;
total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC;
return new NativeElement(
product->data().id(),
parent_id,
+8
View File
@@ -76,10 +76,18 @@ namespace ifcopenshell { namespace geometry {
}
*/
double total_map_time = 0.;
double total_geom_time = 0.;
ifcopenshell::geometry::ConversionResults convert(IfcUtil::IfcBaseClass* item) {
std::clock_t map_start = std::clock();
auto geom_item = mapping_->map(item);
std::clock_t geom_start = std::clock();
ifcopenshell::geometry::ConversionResults results;
kernel_->convert(geom_item, results);
std::clock_t geom_end = std::clock();
total_map_time += (geom_start - map_start) / (double) CLOCKS_PER_SEC;
total_geom_time += (geom_end - geom_start) / (double) CLOCKS_PER_SEC;
return results;
}