First start plug-in architecture

This commit is contained in:
Thomas Krijnen
2026-04-15 18:07:28 +02:00
parent aa10784154
commit 3824e7b449
35 changed files with 533 additions and 1459 deletions
+10 -10
View File
@@ -55,7 +55,7 @@ option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter fr
option(WASM_BUILD "Build a WebAssembly binary." OFF)
option(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." ON)
option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF)
option(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
option(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
@@ -81,7 +81,6 @@ option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
option(WITH_RELATIONSHIP_VALIDATION "Build IfcConvert with option to validate geometrical relationships." OFF)
option(WITH_ROCKSDB "Support a RocksDB key-value store as a file backend in IfcOpenShell" OFF)
option(WITH_ZSTD "Use Zstd compression in RocksDB writes" OFF)
@@ -121,6 +120,10 @@ if(MINIMAL_BUILD)
set(USD_SUPPORT OFF)
endif()
if(NOT BUILD_SHARED_LIBS)
message(FATAL_ERROR "IfcOpenShell now requires BUILD_SHARED_LIBS=ON.")
endif()
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM))
message(STATUS "'IfcGeom' is required with current outputs")
set(BUILD_IFCGEOM ON)
@@ -170,14 +173,11 @@ if(NOT IS_ABSOLUTE ${INCLUDEDIR})
endif()
message(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
if(BUILD_SHARED_LIBS)
add_definitions(-DIFC_SHARED_BUILD)
if(MSVC)
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
add_definitions(-wd4251)
endif()
if(MSVC)
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
add_definitions(-wd4251)
endif()
UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT)
+1 -12
View File
@@ -1,17 +1,6 @@
# IfcConvert
if(WITH_RELATIONSHIP_VALIDATION)
file(GLOB IFCCONVERT_CPP_FILES *.cpp)
file(GLOB IFCCONVERT_H_FILES *.h)
else()
file(GLOB IFCCONVERT_CPP_FILES IfcConvert.cpp)
file(GLOB IFCCONVERT_H_FILES)
endif()
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
add_executable(IfcConvert ${IFCCONVERT_FILES})
add_executable(IfcConvert IfcConvert.cpp)
target_link_libraries(IfcConvert IfcGeom IfcParse Serializers ${OpenCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES})
if(WITH_RELATIONSHIP_VALIDATION)
set_property(TARGET IfcConvert APPEND_STRING PROPERTY COMPILE_FLAGS " -DWITH_RELATIONSHIP_VALIDATION")
endif()
install(TARGETS IfcConvert)
@@ -1,186 +0,0 @@
#ifdef IFOPSH_WITH_CGAL
#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(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall", "IfcSpace", "IfcSlab", "IfcCovering" }, 1.e-5, no_progress, quiet, stderr_progress);
auto rels = f.instances_by_type("IfcRelSpaceBoundary");
std::map<std::pair<const ifcopenshell::IfcBaseClass*, const ifcopenshell::IfcBaseClass*>, const ifcopenshell::IfcBaseClass*> rel_by_space_elem;
if (rels) {
std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const ifcopenshell::IfcBaseClass* rel) {
auto x = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingSpace");
try {
auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedBuildingElement");
rel_by_space_elem.insert({ { x,y }, rel });
} catch (ifcopenshell::exception&) {
// RelatedBuildingElement can be NULL
}
});
}
std::set<const ifcopenshell::IfcBaseClass*> rels_encounted;
ifcopenshell::file f2("boundaries-triangulated.ifc");
if (!f2.good()) {
return;
}
ifcopenshell::geometry::Settings settings;
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
settings.get<ifcopenshell::geometry::settings::WeldVertices>().value = false;
settings.get<ifcopenshell::geometry::settings::ReorientShells>().value = true;
settings.get<ifcopenshell::geometry::settings::ConvertBackUnits>().value = true;
settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
settings.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().value = 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 = ((ifcopenshell::IfcBaseEntity*)i)->get_value<std::string>("Name");
auto g1 = n.substr(0, 22);
auto g2 = n.substr(23);
auto item = c.mapping()->map(i);
if (taxonomy::cast<taxonomy::collection>(item)->children[0] == nullptr) {
continue;
}
auto shell = taxonomy::cast<taxonomy::shell>(taxonomy::cast<taxonomy::collection>(taxonomy::cast<taxonomy::collection>(item)->children[0])->children[0]);
for (auto& face : shell->children) {
for (auto& wire : face->children) {
for (auto& edge : wire->children) {
auto p3 = boost::get<taxonomy::point3::ptr>(edge->start);
auto p4 = taxonomy::cast<taxonomy::geom_item>(item)->matrix->ccomponents() * p3->ccomponents().homogeneous();
Kernel_::Point_3 P(p4(0), p4(1), p4(2));
elem_to_space_boundary_coords[{g1, g2}].emplace_back(P);
}
}
}
}
std::set< std::set<std::string> > guid_pairs_visited;
v([&rel_by_space_elem, &elem_to_space_boundary_coords, &guid_pairs_visited](const intersection_validator::Box& a, const intersection_validator::Box& b) {
std::ostringstream ss;
// ss << id_map[a.id()]->first->data().to_string() << "x" << id_map[b.id()]->first->data().to_string() << std::endl;
// auto x = id_map[a.id()]->second * id_map[b.id()]->second;
auto A = a.handle()->first;
auto B = b.handle()->first;
auto Aguid = A->get_value<std::string>("GlobalId");
auto Bguid = B->get_value<std::string>("GlobalId");
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().to_string() << "x" << a.handle()->first->data().to_string() << std::endl;
auto x = a.handle()->second * b.handle()->second;
if (x.is_empty()) {
return;
}
guid_pairs_visited.insert({ Aguid, Bguid });
cgal_shape_t x_poly;
x.convert_to_polyhedron(x_poly);
{
std::string fn = "computed_boundaries_" + Aguid + "_" + Bguid + ".off";
std::ofstream computed_boundaries(fn.c_str());
computed_boundaries.precision(17);
computed_boundaries << x_poly;
}
Tree tree(faces(x_poly).first, faces(x_poly).second, x_poly);
tree.accelerate_distance_queries();
auto itelem = elem_to_space_boundary_coords.find({ Aguid, Bguid });
if (itelem == elem_to_space_boundary_coords.end()) {
logger::error("Missing space boundary relationship " + Aguid + " " + Bguid);
return;
}
const auto& coords = itelem->second;
std::vector<double> distances;
std::transform(coords.begin(), coords.end(), std::back_inserter(distances), [&tree](const Kernel_::Point_3& p) {
return std::sqrt(CGAL::to_double(tree.squared_distance(p)));
});
bool valid = *std::max_element(distances.begin(), distances.end()) < 0.4;
if (!valid) {
logger::error("Wrong connection geometry " + Aguid + " " + Bguid);
}
/*{
remove_thickness r(x_poly);
std::string fn = "thin_computed_boundaries_" + Aguid + "_" + Bguid + ".off";
std::ofstream computed_boundaries(fn.c_str());
computed_boundaries.precision(17);
computed_boundaries << r.flattened;
}*/
/*
{
auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-sides-sb.off";
std::ofstream os(FN.c_str());
os.precision(17);
os << r.polyhedron2;
}
{
auto FN = s0 + "-" + s1 + "-" + std::to_string(i0) + "-" + std::to_string(i1) + "-flat-sb.off";
std::ofstream os(FN.c_str());
os.precision(17);
os << r.flattened;
}
*/
});
auto is_wall_space_or_slab = [&f](const std::string& g) {
auto decl = f.instance_by_guid(g)->declaration();
return decl.is("IfcWall") || decl.is("IfcSpace") || decl.is("IfcSlab");
};
for (auto& i : *f2.instances_by_type("IfcProduct")) {
auto n = ((ifcopenshell::IfcBaseEntity*)i)->get_value<std::string>("Name");
auto g1 = n.substr(0, 22);
auto g2 = n.substr(23);
if (is_wall_space_or_slab(g1) && is_wall_space_or_slab(g2) && guid_pairs_visited.find({ g1, g2 }) == guid_pairs_visited.end()) {
logger::error("Space boundary for non-bounding geometry " + g1 + " " + g2);
}
}
}
#endif
@@ -1,238 +0,0 @@
#ifdef IFOPSH_WITH_CGAL
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#include "../ifcgeom/IfcGeomFilter.h"
#include "../ifcgeom/Iterator.h"
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <algorithm>
void fix_storeycontainment(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::Settings settings;
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
settings.get<ifcopenshell::geometry::settings::WeldVertices>().value = false;
settings.get<ifcopenshell::geometry::settings::ReorientShells>().value = true;
settings.get<ifcopenshell::geometry::settings::ConvertBackUnits>().value = true;
settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
settings.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().value = true;
std::vector<ifcopenshell::geometry::filter_t> no_openings_and_spaces = {
IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"})
};
IfcGeom::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces, 1);
auto get_elevation = [](const ifcopenshell::IfcBaseClass* a) {
return ((const ifcopenshell::IfcBaseEntity*)a)->get_value<double>("Elevation", 0.);
};
// latebound inverse attribute lookup not working
auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure");
std::map<const ifcopenshell::IfcBaseClass*, const ifcopenshell::IfcBaseClass*> elem_to_storey;
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](ifcopenshell::IfcBaseClass* r) {
auto elems = ((ifcopenshell::IfcBaseEntity*)r)->get_value<aggregate_of_instance::ptr>("RelatedElements");
auto storey = ((ifcopenshell::IfcBaseEntity*)r)->get_value<ifcopenshell::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<const ifcopenshell::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](const ifcopenshell::IfcBaseClass* a, const ifcopenshell::IfcBaseClass* b) {
return get_elevation(a) < get_elevation(b);
});
/*
std::wcout << "Storeys ";
for (auto& s : storeys_sorted) {
auto n = ((ifcopenshell::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);
double LARGE = 1e4;
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::for_each(elevation_slices.begin(), elevation_slices.end(), [](std::pair<double, double>& p) {
p.first -= 0.3;
p.second += 0.3;
});
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;
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);
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.min(i) << std::endl;
}
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.max(i) << std::endl;
}
std::wcout << "---" << std::endl;
}
*/
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();
}
IfcGeom::BRepElement* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (!geom_object) {
break;
}
/*
std::stringstream ss;
ss << geom_object->product()->data().to_string();
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;
}
std::vector<double> intersection_volumes(nefs.size());
for (auto& g : geom_object->geometry()) {
auto s = std::static_pointer_cast<ifcopenshell::geometry::CgalShape>(g.Shape())->poly();
const auto& m = g.Placement()->ccomponents();
const auto& n = geom_object->transformation().data()->ccomponents();
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 bounds = CGAL::Polygon_mesh_processing::bbox_3(s);
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.min(i) << std::endl;
}
for (int i = 0; i < 3; ++i) {
std::wcout << bounds.max(i) << std::endl;
}
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::vector<double>::iterator accumulator = intersection_volumes.begin();
std::for_each(nefs.begin(), nefs.end(), [&accumulator, &part_nef](const CGAL::Nef_polyhedron_3<Kernel_>& storey_nef) {
auto poly = ifcopenshell::geometry::utils::create_polyhedron(part_nef * storey_nef);
CGAL::Polygon_mesh_processing::triangulate_faces(poly);
*accumulator += CGAL::to_double(CGAL::Polygon_mesh_processing::volume(poly));
accumulator++;
});
}
/*
std::wcout << "volumes: ";
for (auto& v : intersection_volumes) {
std::wcout << v << " ";
}
std::wcout << std::endl;
*/
auto calc_idx = std::max_element(intersection_volumes.begin(), intersection_volumes.end()) - intersection_volumes.begin();
auto calc_overlap = intersection_volumes[calc_idx];
auto assigned_idx = std::distance(storeys_sorted.begin(), std::find(storeys_sorted.begin(), storeys_sorted.end(), elem_to_storey[geom_object->product()]));
auto assigned_overlap = intersection_volumes[assigned_idx];
if (calc_overlap > 0 && assigned_overlap < calc_overlap * 0.9) {
auto s = geom_object->product()->get_value<std::string>("GlobalId");
auto s1 = ((ifcopenshell::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value<std::string>("GlobalId");
auto s2 = ((ifcopenshell::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) {
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::progress_bar(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 ");
}
}
#endif
@@ -1,201 +0,0 @@
#ifdef IFOPSH_WITH_CGAL
#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(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress);
ifcopenshell::geometry::Settings settings;
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
settings.get<ifcopenshell::geometry::settings::WeldVertices>().value = false;
settings.get<ifcopenshell::geometry::settings::ReorientShells>().value = true;
settings.get<ifcopenshell::geometry::settings::ConvertBackUnits>().value = true;
settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
settings.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().value = true;
settings.get<ifcopenshell::geometry::settings::IncludeCurves>().value = true;
settings.get<ifcopenshell::geometry::settings::IncludeSurfaces>().value = false;
ifcopenshell::geometry::Converter c("cgal", &f, settings);
auto rels = f.instances_by_type("IfcRelConnectsPathElements");
std::map<std::set<const ifcopenshell::IfcBaseClass*>, const ifcopenshell::IfcBaseClass*> rel_by_elem;
std::for_each(rels->begin(), rels->end(), [&rel_by_elem](const ifcopenshell::IfcBaseClass* rel) {
auto x = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedElement");
rel_by_elem.insert({{ x,y }, rel});
});
std::set<const ifcopenshell::IfcBaseClass*> rels_encounted;
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;
const ifcopenshell::IfcBaseClass* rel = nullptr;
std::string a_type, b_type;
auto rit = rel_by_elem.find({ A, B });
if (rit != rel_by_elem.end()) {
rel = rit->second;
const bool a_is_relating = A == ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
a_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<std::string>("RelatingConnectionType");
b_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<std::string>("RelatedConnectionType");
if (!a_is_relating) {
std::swap(a_type, b_type);
}
}
#if 0
auto a_poly = ifcopenshell::geometry::utils::create_polyhedron(a.handle()->second);
auto b_poly = ifcopenshell::geometry::utils::create_polyhedron(b.handle()->second);
std::wcout << "a" << std::endl;
for (auto& v : vertices(a_poly)) {
for (int i = 0; i < 3; ++i) {
std::wcout << CGAL::to_double(v->point().cartesian(i)) << " ";
}
std::wcout << std::endl;
}
std::wcout << "b" << std::endl;
for (auto& v : vertices(b_poly)) {
for (int i = 0; i < 3; ++i) {
std::wcout << CGAL::to_double(v->point().cartesian(i)) << " ";
}
std::wcout << std::endl;
}
#endif
std::ostringstream ss;
ss << A->data().to_string() << "x" << B->data().to_string() << 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(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) > 4.0) {
return;
}
auto get_axis_parameter_min_max = [&c, &x_poly](const ifcopenshell::IfcBaseEntity* inst) {
auto item = c.mapping()->map(inst);
auto shaperep = taxonomy::cast<taxonomy::collection>(item)->children[0];
auto loop = taxonomy::dcast<taxonomy::loop>(taxonomy::cast<taxonomy::collection>(shaperep)->children[0]);
if (!loop) {
// std::wcout << "no suitable axis" << std::endl;
} else {
auto first_vertex = loop->children.front()->start;
auto last_vertex = loop->children.back()->end;
if (first_vertex.which() != 0 || last_vertex.which() != 0) {
// std::wcout << "trims not supported" << std::endl;
} else {
auto p0 = boost::get<taxonomy::point3::ptr>(first_vertex);
auto p1 = boost::get<taxonomy::point3::ptr>(last_vertex);
auto v0 = taxonomy::cast<taxonomy::geom_item>(item)->matrix->ccomponents() * p0->ccomponents().homogeneous();
auto v1 = taxonomy::cast<taxonomy::geom_item>(item)->matrix->ccomponents() * p1->ccomponents().homogeneous();
auto P0 = Kernel_::Point_3(v0(0), v0(1), v0(2));
auto P1 = Kernel_::Point_3(v1(0), v1(1), v1(2));
auto D = P1 - P0;
auto len = std::sqrt(CGAL::to_double(D.squared_length()));
D /= len;
std::vector<Kernel_::FT> parameters;
std::transform(vertices(x_poly).begin(), vertices(x_poly).end(), std::back_inserter(parameters), [&P0, D](cgal_vertex_descriptor_t& v) {
return (v->point() - P0) * D;
});
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.second)));
}
}
const auto& nan = std::numeric_limits<double>::quiet_NaN();
return std::make_pair(nan, std::make_pair(nan, nan));
};
auto qualify_connection_type = [](double l, const std::pair<double, double>& p) {
if (p.first < 1.e-3) {
return "ATSTART";
} else if (p.second > l - 1.e-3) {
return "ATEND";
} else {
return "ATPATH";
}
};
auto alu0u1 = get_axis_parameter_min_max(A);
auto blu0u1 = get_axis_parameter_min_max(B);
auto atype_computed = qualify_connection_type(alu0u1.first, alu0u1.second);
auto btype_computed = qualify_connection_type(blu0u1.first, blu0u1.second);
rels_encounted.insert(rel);
if (a_type != atype_computed || b_type != btype_computed) {
if (rel) {
logger::error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel);
} else {
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, &v](const ifcopenshell::IfcBaseClass* rel) {
if (rels_encounted.find(rel) == rels_encounted.end()) {
auto x = (ifcopenshell::IfcBaseEntity*)((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
auto y = (ifcopenshell::IfcBaseEntity*)((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedElement");
if (v.successfully_processed.find(x) != v.successfully_processed.end() && v.successfully_processed.find(y) != v.successfully_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;
}
#endif
-32
View File
@@ -1,32 +0,0 @@
#ifdef IFOPSH_WITH_CGAL
#include "validation_utils.h"
double facet_area(const cgal_shape_t::Facet_handle& f) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
return std::sqrt(CGAL::to_double(CGAL::cross_product(p0 - p1, p2 - p1).squared_length()));
}
void dump_facet(const cgal_shape_t::Facet_handle& f) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
auto V = CGAL::cross_product(p0 - p1, p2 - p1);
auto d = std::sqrt(CGAL::to_double(V.squared_length()));
if (d > 1.e-20) {
V /= d;
}
std::ostringstream oss;
oss.precision(8);
oss << "Facet with area " << facet_area(f) << " and normal ("
<< CGAL::to_double(V.cartesian(0)) << " " << CGAL::to_double(V.cartesian(1)) << " "
<< CGAL::to_double(V.cartesian(2)) << ")";
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
}
#endif
-602
View File
@@ -1,602 +0,0 @@
#ifdef IFOPSH_WITH_CGAL
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#include "../ifcgeom/IfcGeomFilter.h"
#include "../ifcgeom/Iterator.h"
#include <CGAL/box_intersection_d.h>
#include <CGAL/minkowski_sum_3.h>
#include <CGAL/AABB_tree.h>
#if CGAL_VERSION_NR >= 1060000000
#include <CGAL/AABB_traits_3.h>
#else
#include <CGAL/AABB_traits.h>
#endif
#include <CGAL/Polyhedron_3.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <fstream>
#include <iostream>
#if CGAL_VERSION_NR >= 1060000000
#define variant_get std::get_if
#else
#define variant_get boost::get
#endif
template <typename T>
T enlarge(const T& t, double d = 1.e-5) {
typename T::NT min[3];
typename T::NT max[3];
for (int i = 0; i < t.dimension(); ++i) {
min[i] = t.min_coord(i) - d;
max[i] = t.max_coord(i) + d;
}
return T(min, max, t.handle());
}
template <class HDS>
struct Build_Offset : public CGAL::Modifier_base<HDS> {
std::list<cgal_shape_t::Facet_handle> input;
void operator()(HDS& hds) {
// Postcondition: hds is a valid polyhedral surface.
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds);
int Nv = 0, Nf = 0;
for (auto& f : input) {
Nv += 3;
Nf += 1;
}
B.begin_surface(Nv, Nf);
for (auto& f : input) {
auto p0 = f->facet_begin()->vertex()->point();
auto p1 = f->facet_begin()->next()->vertex()->point();
auto p2 = f->facet_begin()->next()->next()->vertex()->point();
auto O = CGAL::centroid(p0, p1, p2);
Kernel_::Point_3* p012[3] = { &p0, &p1, &p2 };
for (int i = 0; i < 3; ++i) {
*p012[i] = CGAL::ORIGIN + (((*(p012[i])) - CGAL::ORIGIN) + ((*(p012[i])) - O));
B.add_vertex(*p012[i]);
}
}
Nv = 0;
for (int i = 0; i < Nf; ++i) {
B.begin_facet();
B.add_vertex_to_facet(Nv++);
B.add_vertex_to_facet(Nv++);
B.add_vertex_to_facet(Nv++);
B.end_facet();
}
B.end_surface();
}
};
template <typename Ts>
std::list<cgal_shape_t::Facet_handle> connected_faces(cgal_shape_t::Facet_handle f, const Ts& excluded) {
std::set<cgal_shape_t::Facet_handle> fs = { f };
std::function<void(cgal_shape_t::Facet_handle& f)> process;
process = [&fs, &process, &excluded](cgal_shape_t::Facet_handle& f) {
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto ff = circ->opposite()->facet();
if (excluded.find(ff) == excluded.end()) {
auto p = fs.insert(ff);
if (p.second) {
process(ff);
}
}
} while (++circ != end);
};
process(f);
return std::list<cgal_shape_t::Facet_handle>(fs.begin(), fs.end());
}
template <class HDS>
struct Builder_With_Map : public CGAL::Modifier_base<HDS> {
std::list<cgal_shape_t::Facet_handle> input;
std::map<Kernel_::Point_3, Kernel_::Point_3> mapping;
void operator()(HDS& hds) {
// Postcondition: hds is a valid polyhedral surface.
CGAL::Polyhedron_incremental_builder_3<HDS> B(hds);
std::set<Kernel_::Point_3> used_points;
for (auto& f : input) {
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto P = circ->vertex()->point();
auto it = mapping.find(P);
if (it == mapping.end()) {
std::wcout << "WARNING unprojected point :(" << std::endl;
} else {
P = it->second;
}
used_points.insert(P);
} while (++circ != end);
}
B.begin_surface(used_points.size(), input.size());
for (auto& p : used_points) {
B.add_vertex(p);
}
for (auto& f : input) {
B.begin_facet();
cgal_shape_t::Halfedge_around_facet_circulator circ = f->facet_begin(), end(circ);
do {
auto P = circ->vertex()->point();
auto it = mapping.find(P);
if (it == mapping.end()) {
std::wcout << "WARNING unprojected point :(" << std::endl;
} else {
P = it->second;
}
auto jt = used_points.find(P);
if (jt == used_points.end()) {
throw std::runtime_error("Unable to map point");
}
size_t idx = std::distance(used_points.begin(), jt);
std::wcout << "idx " << idx << std::endl;
B.add_vertex_to_facet(idx);
} while (++circ != end);
B.end_facet();
}
B.end_surface();
}
};
double facet_area(const cgal_shape_t::Facet_handle& f);
void dump_facet(const cgal_shape_t::Facet_handle& f);
struct remove_thickness {
typedef Kernel_::Point_3 Point;
typedef Kernel_::Plane_3 Plane;
typedef Kernel_::Vector_3 Vector;
typedef Kernel_::Segment_3 Segment;
typedef Kernel_::Ray_3 Ray;
typedef CGAL::Polyhedron_3<Kernel_> Polyhedron;
typedef CGAL::AABB_face_graph_triangle_primitive<Polyhedron> Primitive;
#if CGAL_VERSION_NR >= 1060000000
typedef CGAL::AABB_traits_3<Kernel_, Primitive> AAbbTraits;
#else
typedef CGAL::AABB_traits<Kernel_, Primitive> AAbbTraits;
#endif
typedef CGAL::AABB_tree<AAbbTraits> Tree;
typedef boost::optional<Tree::Intersection_and_primitive_id<Ray>::Type> Ray_intersection;
cgal_shape_t polyhedron, polyhedron2, flattened;
remove_thickness(const cgal_shape_t& p)
// edge_collapse(p) still does not work :(
: polyhedron(p)
, polyhedron2(p) {
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron2);
std::list<cgal_shape_t::Facet_handle> non_degenerate, degenerate, longitudinal;
std::set<cgal_shape_t::Facet_iterator> thin_sides;
std::wcout << "ALL FACES:" << std::endl;
for (auto& f : faces(polyhedron)) {
dump_facet(f);
if (facet_area(f) > 1.e-20) {
non_degenerate.push_back(f);
} else {
degenerate.push_front(f);
std::wcout << "Degenerate, area: " << facet_area(f) << std::endl;
}
}
std::wcout << "NON DEGENERATE:" << std::endl;
for (auto& f : non_degenerate) {
dump_facet(f);
}
cgal_shape_t enlarged_non_degenerate_triangles;
Build_Offset<cgal_shape_t::HDS> bo;
bo.input = non_degenerate;
enlarged_non_degenerate_triangles.delegate(bo);
// @todo, first on non-enlarged faces, then on enlarged; to fix projection on concave surfaces where the enlarging operation shortens projection distances.
Tree tree(faces(enlarged_non_degenerate_triangles).first, faces(enlarged_non_degenerate_triangles).second, enlarged_non_degenerate_triangles);
std::map<cgal_face_descriptor_t, Kernel_::Vector_3> face_normals;
boost::associative_property_map<std::map<cgal_face_descriptor_t, Kernel_::Vector_3>> face_normals_map(face_normals);
CGAL::Polygon_mesh_processing::compute_face_normals(polyhedron, face_normals_map);
for (auto& f : non_degenerate) {
auto O = CGAL::centroid(
f->facet_begin()->vertex()->point(),
f->facet_begin()->next()->vertex()->point(),
f->facet_begin()->next()->next()->vertex()->point()
);
Ray ray(O, -face_normals_map[f]);
std::list<Ray_intersection> intersections;
tree.all_intersections(ray, std::back_inserter(intersections));
double N = std::numeric_limits<double>::infinity();
Point P;
for (auto& intersection : intersections) {
if (variant_get<Point>(&(intersection->first))) {
const Point* p = variant_get<Point>(&(intersection->first));
const double d = std::sqrt(CGAL::to_double((*p - O).squared_length()));
if (d > 1.e-20 && d < N) {
N = d;
}
}
}
if (N != std::numeric_limits<double>::infinity() && N > 1.e-4) {
thin_sides.insert(f);
}
}
std::wcout << "THIN SIDES:" << std::endl;
for (auto& f : thin_sides) {
dump_facet(f);
}
for (auto& f : non_degenerate) {
if (thin_sides.find(f) == thin_sides.end()) {
longitudinal.push_back(f);
}
}
std::wcout << "LONGITUDONAL:" << std::endl;
for (auto& f : longitudinal) {
dump_facet(f);
}
std::wcout << "faces " << faces(polyhedron).size() << "long " << longitudinal.size() << "thin " << thin_sides.size() << "non-degen " << non_degenerate.size() << std::endl;
cgal_shape_t enlarged_indiv_triangles;
Build_Offset<cgal_shape_t::HDS> bo2;
bo2.input = longitudinal;
enlarged_indiv_triangles.delegate(bo2);
{
std::ofstream ofs("enlarged.off");
ofs.precision(17);
ofs << enlarged_indiv_triangles;
}
Tree tree2(faces(enlarged_indiv_triangles).begin(), faces(enlarged_indiv_triangles).end(), enlarged_indiv_triangles);
std::map<Kernel_::Point_3, Kernel_::Point_3> new_points;
for (Polyhedron::Facet_iterator fit = polyhedron.facets_begin();
fit != polyhedron.facets_end();
++fit) {
if (CGAL::collinear(
fit->halfedge()->vertex()->point(),
fit->halfedge()->next()->vertex()->point(),
fit->halfedge()->opposite()->vertex()->point())) {
std::wcout << "degenerate triangle" << std::endl;
}
}
for (auto& v : vertices(polyhedron)) {
auto O = v->point();
Kernel_::Vector_3 norm;
Kernel_::Vector_3 accum;
int count = 0;
CGAL::Face_around_target_circulator<cgal_shape_t> it(v->halfedge(), polyhedron), end(it);
do {
cgal_shape_t::Facet_handle fh = (*it)->halfedge()->facet();
auto jt = std::find(non_degenerate.begin(), non_degenerate.end(), fh);
std::wcout << "non degen: " << (jt != non_degenerate.end()) << std::endl;
auto kt = std::find(thin_sides.begin(), thin_sides.end(), fh);
std::wcout << "thin side: " << (kt != thin_sides.end()) << std::endl;
if (jt != non_degenerate.end() && kt == thin_sides.end()) {
// else degenerate, prevent div by zero, do not incorporate in vnorm.
// or else part of thin side
auto p0 = (*it)->facet_begin()->vertex()->point();
auto p1 = (*it)->facet_begin()->next()->vertex()->point();
auto p2 = (*it)->facet_begin()->next()->next()->vertex()->point();
{
std::ostringstream oss;
oss.precision(8);
oss << "p0 " << p0.cartesian(0) << " " << p0.cartesian(1) << " " << p0.cartesian(2) << "\n";
oss << "p1 " << p1.cartesian(0) << " " << p1.cartesian(1) << " " << p1.cartesian(2) << "\n";
oss << "p2 " << p2.cartesian(0) << " " << p2.cartesian(1) << " " << p2.cartesian(2) << "\n";
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
}
auto fnorm = CGAL::cross_product(p0 - p1, p2 - p1);
fnorm /= std::sqrt(CGAL::to_double(fnorm.squared_length()));
// const auto& fnorm = face_normals_map_2[*it];
std::ostringstream oss;
oss.precision(8);
oss << fnorm.cartesian(0) << " " << fnorm.cartesian(1) << " " << fnorm.cartesian(2);
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
accum += fnorm;
++count;
}
++it;
} while (it != end);
norm = accum / count;
std::wcout << "count " << count << std::endl;
if (count == 0) {
// part of only degenerate or only thin sides
continue;
}
// v->vertex_begin();
Ray ray(O, norm);
std::ostringstream oss;
oss.precision(8);
oss << O << " -> " << norm;
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
std::list<Ray_intersection> intersections;
tree2.all_intersections(ray, std::back_inserter(intersections));
double N = std::numeric_limits<double>::infinity();
Point P;
bool used_intersection = false;
if (intersections.size()) {
for (auto& intersection : intersections) {
if (variant_get<Point>(&(intersection->first))) {
const Point* p = variant_get<Point>(&(intersection->first));
const double d = std::sqrt(CGAL::to_double((*p - O).squared_length()));
if (d < N && d > 1.e-20) {
N = d;
P = *p;
std::wcout << "intersection @ " << d << std::endl;
}
}
}
std::wcout << "-----------" << std::endl;
// average the new point
new_points[O] = CGAL::ORIGIN + (((O - CGAL::ORIGIN) + (P - CGAL::ORIGIN))) / 2;
used_intersection = true;
}
if (!used_intersection) {
std::wcout << "no intersection :(" << std::endl;
}
}
auto thin_sides_degenerate = thin_sides;
thin_sides_degenerate.insert(degenerate.begin(), degenerate.end());
// @todo choose connected / connected_opposing based on largest combined area of facets?
if (longitudinal.size() == 0) {
std::wcout << "no longitudinal faces detected :(" << std::endl;
return;
}
auto connected = connected_faces(*longitudinal.begin(), thin_sides_degenerate);
decltype(connected) connected_opposing;
for (auto& f : longitudinal) {
if (std::find(connected.begin(), connected.end(), f) == connected.end()) {
connected_opposing = connected_faces(f, thin_sides_degenerate);
std::set<cgal_shape_t::Facet_handle> longi(longitudinal.begin(), longitudinal.end());
std::set<cgal_shape_t::Facet_handle> both_sides(connected.begin(), connected.end());
both_sides.insert(connected_opposing.begin(), connected_opposing.end());
if (longi == both_sides) {
std::wcout << "Facet connection functioning properly" << std::endl;
} else {
std::wcout << "Facet connection functioning incorrectly" << std::endl;
}
break;
}
}
Builder_With_Map<cgal_shape_t::HDS> b2;
b2.input = connected;
b2.mapping = new_points;
flattened.delegate(b2);
}
};
struct intersection_validator {
typedef std::list<std::pair<const ifcopenshell::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
typedef CGAL::Box_intersection_d::Box_with_handle_d<double, 3, nefs_t::value_type*> Box;
std::vector<Box> boxes;
nefs_t nefs;
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<const ifcopenshell::IfcBaseEntity*> successfully_processed;
intersection_validator(ifcopenshell::file& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
ifcopenshell::geometry::Settings settings;
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
settings.get<ifcopenshell::geometry::settings::WeldVertices>().value = false;
settings.get<ifcopenshell::geometry::settings::ReorientShells>().value = true;
settings.get<ifcopenshell::geometry::settings::ConvertBackUnits>().value = true;
settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
settings.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().value = true;
std::vector<ifcopenshell::geometry::filter_t> spaces_and_walls = {
IfcGeom::entity_filter(true, false, entities)
};
IfcGeom::Iterator context_iterator("cgal", settings, &f, spaces_and_walls, 1);
if (!context_iterator.initialize()) {
return;
}
auto polycube = ifcopenshell::geometry::utils::create_cube(eps);
auto cube = ifcopenshell::geometry::utils::create_nef_polyhedron(polycube);
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();
}
IfcGeom::BRepElement* geom_object = nullptr;
if (has_more) {
geom_object = context_iterator.get_native();
}
if (!geom_object) {
break;
}
std::stringstream ss;
geom_object->product()->to_string(ss);
auto sss = ss.str();
std::wcout << sss.c_str() << std::endl;
for (auto& g : geom_object->geometry()) {
cgal_shape_t s = *std::static_pointer_cast<ifcopenshell::geometry::CgalShape>(g.Shape());
const auto& m = g.Placement()->ccomponents();
const auto& n = geom_object->transformation().data()->ccomponents();
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);
}
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;
}
successfully_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 });
Box b(&*(nefs.rbegin()));
// id_map[b.id()] = ;
for (auto &vertex : vertices(s)) {
double p[3] = {
CGAL::to_double(vertex->point().cartesian(0)),
CGAL::to_double(vertex->point().cartesian(1)),
CGAL::to_double(vertex->point().cartesian(2))
};
b.extend(p);
}
boxes.push_back(enlarge(b));
/*
std::ostringstream ss;
ss << geom_object->product()->data().to_string() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl;
auto sss = ss.str();
std::wcout << sss.c_str();
*/
}
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::progress_bar(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 ");
}
/*
// @todo
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(), [](Box& x, Box& 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);
}
};
#endif
+11 -10
View File
@@ -1,11 +1,3 @@
add_subdirectory(kernels)
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
if((BUILD_CONVERT OR BUILD_IFCPYTHON) AND WITH_OPENCASCADE)
add_subdirectory(Serialization)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
endif()
add_subdirectory(mapping)
# IfcGeom (schema agnostic)
@@ -16,6 +8,7 @@ set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
add_library(geometry ALIAS IfcGeom)
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
target_compile_definitions(IfcGeom PRIVATE BOOST_DLL_USE_STD_FS)
if(UNIX)
find_package(Threads)
@@ -23,10 +16,18 @@ endif()
find_package(Eigen3 REQUIRED)
add_subdirectory(kernels)
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
if(WASM_BUILD)
target_link_libraries(IfcGeom plugin ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin ${Boost_LIBRARIES} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
else()
target_link_libraries(IfcGeom plugin IfcParse ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin IfcParse ${Boost_LIBRARIES} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
endif()
if((BUILD_CONVERT OR BUILD_IFCPYTHON) AND WITH_OPENCASCADE)
add_subdirectory(Serialization)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
endif()
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
-19
View File
@@ -621,15 +621,6 @@ const IfcGeom::Element* IfcGeom::Iterator::get_object(int id) {
} catch (const std::exception& e) {
logger::error(e);
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
logger::error(e.GetMessageString());
} else {
logger::error("Unknown error returning product");
}
}
#endif
catch (...) {
logger::error("Unknown error returning product");
}
@@ -646,16 +637,6 @@ express::Base IfcGeom::Iterator::create() {
logger::error(e);
had_error_processing_elements_ = true;
}
#ifdef IFOPSH_WITH_OPENCASCADE
catch (const Standard_Failure& e) {
if (e.GetMessageString() && strlen(e.GetMessageString())) {
logger::error(e.GetMessageString());
} else {
logger::error("Unknown error creating geometry");
}
had_error_processing_elements_ = true;
}
#endif
catch (...) {
logger::error("Unknown error creating geometry");
had_error_processing_elements_ = true;
-4
View File
@@ -68,10 +68,6 @@
#include "../ifcgeom/abstract_mapping.h"
#include "../ifcgeom/GeometrySerializer.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include <Standard_Failure.hxx>
#endif
#include <boost/algorithm/string.hpp>
#include <map>
+2 -1
View File
@@ -3,7 +3,8 @@ add_subdirectory(schema)
add_library(geometry_serializer Serialization.cpp)
add_library(opencascade_geometry_ifc_writer ALIAS geometry_serializer)
set_target_properties(geometry_serializer PROPERTIES COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS")
target_link_libraries(geometry_serializer plugin ${geometry_serializer_libraries} IfcParse)
target_link_libraries(geometry_serializer plugin ${geometry_serializer_libraries} IfcGeom IfcParse)
target_link_libraries(geometry_serializer geometry_kernel_opencascade)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer" ${geometry_serializer_libraries})
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
@@ -20,7 +20,6 @@
#ifndef IFC_GEOMSERIALIZATION_API_H
#define IFC_GEOMSERIALIZATION_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef IFC_GEOMSERIALIZATION_EXPORTS
#define IFC_GEOMSERIALIZATION_API __declspec(dllexport)
@@ -30,8 +29,5 @@
#else // simply assume *nix + GCC-like compiler
#define IFC_GEOMSERIALIZATION_API __attribute__((visibility("default")))
#endif
#else
#define IFC_GEOMSERIALIZATION_API
#endif
#endif
+6 -10
View File
@@ -20,18 +20,14 @@
#ifndef IFC_GEOM_API_H
#define IFC_GEOM_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef IFC_GEOM_EXPORTS
#define IFC_GEOM_API __declspec(dllexport)
#else
#define IFC_GEOM_API __declspec(dllimport)
#endif
#else // simply assume *nix + GCC-like compiler
#define IFC_GEOM_API __attribute__((visibility("default")))
#ifdef _WIN32
#ifdef IFC_GEOM_EXPORTS
#define IFC_GEOM_API __declspec(dllexport)
#else
#define IFC_GEOM_API __declspec(dllimport)
#endif
#else
#define IFC_GEOM_API
#define IFC_GEOM_API __attribute__((visibility("default")))
#endif
#endif
+85
View File
@@ -0,0 +1,85 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "kernel_plugin.h"
#ifndef _WIN32
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#include <stdexcept>
namespace {
constexpr const char* kernel_plugin_prefix = "geometry.kernel.";
}
const char* ifcopenshell::geometry::kernels::kernel_plugin_registration_symbol() {
return "ifcopenshell_register_kernel_plugin_v1";
}
ifcopenshell::plugin::metadata ifcopenshell::geometry::kernels::kernel_plugin_metadata(const std::string& plugin_name) {
plugin::metadata metadata;
metadata.kind_ = plugin::kind::kernel;
metadata.id = kernel_plugin_prefix + plugin_name;
return metadata;
}
std::filesystem::path ifcopenshell::geometry::kernels::kernel_plugin_directory() {
#ifdef _WIN32
HMODULE module_handle = nullptr;
if (!GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&ifcopenshell::geometry::kernels::load_kernel_plugins),
&module_handle)) {
throw std::runtime_error("Unable to resolve IfcGeom module path");
}
wchar_t buffer[MAX_PATH];
const DWORD length = GetModuleFileNameW(module_handle, buffer, MAX_PATH);
if (length == 0) {
throw std::runtime_error("Unable to read IfcGeom module filename");
}
return std::filesystem::path(std::wstring(buffer, length)).parent_path();
#else
Dl_info info;
if (dladdr(reinterpret_cast<const void*>(&ifcopenshell::geometry::kernels::load_kernel_plugins), &info) == 0 || !info.dli_fname) {
throw std::runtime_error("Unable to resolve IfcGeom module path");
}
return std::filesystem::path(info.dli_fname).parent_path();
#endif
}
void ifcopenshell::geometry::kernels::load_kernel_plugins(kernel_registry& registry) {
plugin::manager manager;
manager.add_search_path(kernel_plugin_directory());
for (const auto& path : manager.discover(kernel_plugin_prefix)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::kernel) {
continue;
}
auto register_plugin = module.get_alias<register_kernel_plugin_fn>(kernel_plugin_registration_symbol());
register_plugin(registry, module);
}
}
+42
View File
@@ -0,0 +1,42 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef IFCOPENSHELL_KERNEL_PLUGIN_H
#define IFCOPENSHELL_KERNEL_PLUGIN_H
#include "../ifcgeom/kernel_registry.h"
#include <filesystem>
namespace ifcopenshell {
namespace geometry {
namespace kernels {
typedef void register_kernel_plugin_fn(kernel_registry&, const plugin::module&);
IFC_GEOM_API const char* kernel_plugin_registration_symbol();
IFC_GEOM_API plugin::metadata kernel_plugin_metadata(const std::string& plugin_name);
IFC_GEOM_API std::filesystem::path kernel_plugin_directory();
IFC_GEOM_API void load_kernel_plugins(kernel_registry& registry);
}
}
}
#endif
+2 -58
View File
@@ -19,6 +19,7 @@
#include "kernel_registry.h"
#include "../ifcgeom/kernel_plugin.h"
#include "../ifcgeom/hybrid_kernel.h"
#include "../ifcparse/file.h"
@@ -27,68 +28,11 @@
#include <cstring>
#include <mutex>
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
#undef Handle
#endif
#ifdef IFOPSH_WITH_CGAL
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#undef CGAL_KERNEL_H
#undef CGALCONVERSIONRESULT_H
#define IFOPSH_SIMPLE_KERNEL
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
#undef CgalKernel
#undef IFOPSH_SIMPLE_KERNEL
#endif
#ifdef IFOPSH_WITH_MANIFOLD
#include "../ifcgeom/kernels/manifold/ManifoldKernel.h"
#endif
#include "../ifcgeom/kernels/passthrough/PassthroughKernel.h"
namespace {
std::string kernel_key(const std::string& backend_id) {
return boost::to_lower_copy(backend_id);
}
ifcopenshell::plugin::module builtin_kernel_module(const std::string& backend_id) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::kernel;
metadata.id = "geometry.kernel." + kernel_key(backend_id);
return ifcopenshell::plugin::module::builtin(metadata);
}
void register_builtin_kernels(ifcopenshell::geometry::kernels::kernel_registry& registry) {
#ifdef IFOPSH_WITH_OPENCASCADE
ifcopenshell::geometry::kernels::kernel_info opencascade_info;
opencascade_info.backend_id = "opencascade";
opencascade_info.supports_boolean_operations = true;
registry.bind(opencascade_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new IfcGeom::OpenCascadeKernel(settings); }, builtin_kernel_module("opencascade"));
#endif
#ifdef IFOPSH_WITH_CGAL
ifcopenshell::geometry::kernels::kernel_info cgal_info;
cgal_info.backend_id = "cgal";
cgal_info.supports_boolean_operations = true;
registry.bind(cgal_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::CgalKernel(settings); }, builtin_kernel_module("cgal"));
ifcopenshell::geometry::kernels::kernel_info cgal_simple_info;
cgal_simple_info.backend_id = "cgal-simple";
cgal_simple_info.supports_boolean_operations = false;
registry.bind(cgal_simple_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::SimpleCgalKernel(settings); }, builtin_kernel_module("cgal-simple"));
#endif
#ifdef IFOPSH_WITH_MANIFOLD
ifcopenshell::geometry::kernels::kernel_info manifold_info;
manifold_info.backend_id = "manifold";
manifold_info.supports_boolean_operations = true;
registry.bind(manifold_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::ManifoldKernel(settings); }, builtin_kernel_module("manifold"));
#endif
ifcopenshell::geometry::kernels::kernel_info passthrough_info;
passthrough_info.backend_id = "passthrough";
passthrough_info.supports_boolean_operations = false;
registry.bind(passthrough_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::PassthroughKernel(settings); }, builtin_kernel_module("passthrough"));
}
}
void ifcopenshell::geometry::kernels::kernel_registry::bind(const kernel_info& info, create_fn create, const plugin::module& module) {
@@ -122,7 +66,7 @@ std::vector<ifcopenshell::geometry::kernels::kernel_info> ifcopenshell::geometry
ifcopenshell::geometry::kernels::kernel_registry& ifcopenshell::geometry::kernels::kernel_registry_instance() {
static kernel_registry registry;
static std::once_flag once;
std::call_once(once, register_builtin_kernels, std::ref(registry));
std::call_once(once, load_kernel_plugins, std::ref(registry));
return registry;
}
+20 -11
View File
@@ -1,7 +1,7 @@
find_package(Eigen3 REQUIRED)
message(STATUS "GEOMETRY_KERNELS ${GEOMETRY_KERNELS}")
set(kernel_plugin_runtime_dir "${CMAKE_BINARY_DIR}/ifcgeom/$<CONFIG>")
foreach(kernel ${GEOMETRY_KERNELS})
string(TOUPPER ${kernel} KERNEL_UPPER)
file(GLOB IFCGEOM_H_FILES ${kernel}/*.h)
@@ -9,25 +9,34 @@ foreach(kernel ${GEOMETRY_KERNELS})
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
set(KERNEL_TARGET "geometry_kernel_${kernel}")
add_library(${KERNEL_TARGET} OBJECT ${IFCGEOM_FILES})
set_property(TARGET ${KERNEL_TARGET} APPEND PROPERTY COMPILE_FLAGS "-DIFC_GEOM_EXPORTS")
add_library(${KERNEL_TARGET} SHARED ${IFCGEOM_FILES})
set_target_properties(${KERNEL_TARGET} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
OUTPUT_NAME "geometry.kernel.${kernel}"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
list(APPEND kernel_libraries ${KERNEL_TARGET})
target_link_libraries(${KERNEL_TARGET} ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
target_link_libraries(${KERNEL_TARGET} PRIVATE plugin IfcGeom ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
install(TARGETS ${KERNEL_TARGET})
if(${kernel} STREQUAL "cgal")
set_property(TARGET ${KERNEL_TARGET} APPEND_STRING PROPERTY COMPILE_FLAGS " -DCGAL_HAS_THREADS")
set(KERNEL_TARGET_SIMPLE "${KERNEL_TARGET}_simple")
add_library(${KERNEL_TARGET_SIMPLE} OBJECT ${IFCGEOM_FILES})
set_target_properties(${KERNEL_TARGET_SIMPLE} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS")
add_library(${KERNEL_TARGET_SIMPLE} SHARED ${IFCGEOM_FILES})
set_target_properties(${KERNEL_TARGET_SIMPLE} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS"
OUTPUT_NAME "geometry.kernel.cgalsimple"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
list(APPEND kernel_libraries ${KERNEL_TARGET_SIMPLE})
target_link_libraries(${KERNEL_TARGET_SIMPLE} ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
target_link_libraries(${KERNEL_TARGET_SIMPLE} PRIVATE plugin IfcGeom ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
install(TARGETS ${KERNEL_TARGET_SIMPLE})
elseif(${kernel} STREQUAL "opencascade")
target_link_libraries(${KERNEL_TARGET} ${OpenCASCADE_LIBRARIES})
target_link_libraries(${KERNEL_TARGET} PRIVATE ${OpenCASCADE_LIBRARIES})
endif()
install(FILES ${IFCGEOM_H_FILES}
+68
View File
@@ -0,0 +1,68 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../kernel_plugin.h"
#include "CgalKernel.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace kernels {
namespace cgal_plugin {
#ifdef IFOPSH_SIMPLE_KERNEL
constexpr const char* plugin_name = "cgalsimple";
constexpr const char* backend_id = "cgal-simple";
constexpr bool supports_boolean_operations = false;
using kernel_type = SimpleCgalKernel;
#else
constexpr const char* plugin_name = "cgal";
constexpr const char* backend_id = "cgal";
constexpr bool supports_boolean_operations = true;
using kernel_type = CgalKernel;
#endif
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return kernel_plugin_metadata(plugin_name);
}
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
return new kernel_type(settings);
}
void register_plugin(kernel_registry& registry, const plugin::module& module) {
kernel_info info;
info.backend_id = backend_id;
info.supports_boolean_operations = supports_boolean_operations;
registry.bind(info, create_kernel, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
+1 -5
View File
@@ -20,9 +20,8 @@
#ifndef IFC_GEOMLIBRARY_API_H
#define IFC_GEOMLIBRARY_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef IFC_GEOM_EXPORTS
#ifdef IFC_GEOMLIBRARY_EXPORTS
#define IFC_GEOMLIBRARY_API __declspec(dllexport)
#else
#define IFC_GEOMLIBRARY_API __declspec(dllimport)
@@ -30,8 +29,5 @@
#else // simply assume *nix + GCC-like compiler
#define IFC_GEOMLIBRARY_API __attribute__((visibility("default")))
#endif
#else
#define IFC_GEOMLIBRARY_API
#endif
#endif
+56
View File
@@ -0,0 +1,56 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../kernel_plugin.h"
#include "ManifoldKernel.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace kernels {
namespace manifold_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return kernel_plugin_metadata("manifold");
}
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
return new ManifoldKernel(settings);
}
void register_plugin(kernel_registry& registry, const plugin::module& module) {
kernel_info info;
info.backend_id = "manifold";
info.supports_boolean_operations = true;
registry.bind(info, create_kernel, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
@@ -47,6 +47,28 @@ namespace {
}
}
ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape(const TopoDS_Shape& shape)
: shape_(shape) {}
ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape(TopoDS_Shape&& shape)
: shape_(std::move(shape)) {}
const TopoDS_Shape& ifcopenshell::geometry::OpenCascadeShape::shape() const {
return shape_;
}
ifcopenshell::geometry::OpenCascadeShape::operator const TopoDS_Shape& () {
return shape_;
}
std::string_view ifcopenshell::geometry::OpenCascadeShape::backend_id() const {
return "opencascade";
}
IfcGeom::ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::clone() const {
return new OpenCascadeShape(shape_);
}
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
// @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4::ptr matrix, gp_GTrsf& trsf);
@@ -45,21 +45,17 @@ namespace ifcopenshell {
class IFC_GEOMLIBRARY_API OpenCascadeShape : public IfcGeom::ConversionResultShape {
public:
OpenCascadeShape(const TopoDS_Shape& shape)
: shape_(shape) {}
OpenCascadeShape(TopoDS_Shape&& shape)
: shape_(std::move(shape)) {}
OpenCascadeShape(const TopoDS_Shape& shape);
OpenCascadeShape(TopoDS_Shape&& shape);
const TopoDS_Shape& shape() const { return shape_; }
operator const TopoDS_Shape& () { return shape_; }
virtual std::string_view backend_id() const { return "opencascade"; }
const TopoDS_Shape& shape() const;
operator const TopoDS_Shape& ();
virtual std::string_view backend_id() const;
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
virtual IfcGeom::ConversionResultShape* clone() const {
return new OpenCascadeShape(shape_);
}
virtual IfcGeom::ConversionResultShape* clone() const;
virtual double bounding_box(void*&) const {
throw std::runtime_error("Not implemented");
+17 -17
View File
@@ -35,13 +35,13 @@
namespace IfcGeom {
namespace util {
void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r);
IFC_GEOMLIBRARY_API void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r);
TopoDS_Shape copy_operand(const TopoDS_Shape& s);
IFC_GEOMLIBRARY_API TopoDS_Shape copy_operand(const TopoDS_Shape& s);
double min_edge_length(const TopoDS_Shape& a);
IFC_GEOMLIBRARY_API double min_edge_length(const TopoDS_Shape& a);
double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search);
IFC_GEOMLIBRARY_API double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search);
class points_on_planar_face_generator {
private:
@@ -69,35 +69,35 @@ namespace IfcGeom {
bool operator()(gp_Pnt& p);
};
bool faces_overlap(const TopoDS_Face& f, const TopoDS_Face& g);
IFC_GEOMLIBRARY_API bool faces_overlap(const TopoDS_Face& f, const TopoDS_Face& g);
double min_face_face_distance(const TopoDS_Shape& a, double max_search);
IFC_GEOMLIBRARY_API double min_face_face_distance(const TopoDS_Shape& a, double max_search);
int bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c);
IFC_GEOMLIBRARY_API int bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c);
bool get_edge_axis(const TopoDS_Edge& e, gp_Ax1& ax);
IFC_GEOMLIBRARY_API bool get_edge_axis(const TopoDS_Edge& e, gp_Ax1& ax);
bool is_subset(const TopTools_IndexedMapOfShape& lhs, const TopTools_IndexedMapOfShape& rhs);
IFC_GEOMLIBRARY_API bool is_subset(const TopTools_IndexedMapOfShape& lhs, const TopTools_IndexedMapOfShape& rhs);
bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair<double, double>& interval);
IFC_GEOMLIBRARY_API bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair<double, double>& interval);
int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const TopTools_ListOfShape& bs, TopTools_ListOfShape& c);
IFC_GEOMLIBRARY_API int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const TopTools_ListOfShape& bs, TopTools_ListOfShape& c);
int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c);
IFC_GEOMLIBRARY_API int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c);
bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps);
IFC_GEOMLIBRARY_API bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps);
struct boolean_settings {
bool debug, attempt_2d;
double precision;
};
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
TopoDS_Shape ensure_fit_for_subtraction(const TopoDS_Shape& shape, double tol);
IFC_GEOMLIBRARY_API TopoDS_Shape ensure_fit_for_subtraction(const TopoDS_Shape& shape, double tol);
}
}
#endif
#endif
@@ -0,0 +1,56 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../kernel_plugin.h"
#include "OpenCascadeKernel.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace kernels {
namespace opencascade_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return kernel_plugin_metadata("opencascade");
}
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
return new IfcGeom::OpenCascadeKernel(settings);
}
void register_plugin(kernel_registry& registry, const plugin::module& module) {
kernel_info info;
info.backend_id = "opencascade";
info.supports_boolean_operations = true;
registry.bind(info, create_kernel, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::opencascade_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::opencascade_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::opencascade_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
@@ -0,0 +1,56 @@
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "../../kernel_plugin.h"
#include "PassthroughKernel.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace kernels {
namespace passthrough_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return kernel_plugin_metadata("passthrough");
}
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
return new PassthroughKernel(settings);
}
void register_plugin(kernel_registry& registry, const plugin::module& module) {
kernel_info info;
info.backend_id = "passthrough";
info.supports_boolean_operations = false;
registry.bind(info, create_kernel, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::passthrough_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::passthrough_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::passthrough_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
+4 -1
View File
@@ -3,6 +3,9 @@ find_package(Boost REQUIRED)
file(GLOB CPP_FILES *.cpp)
set(SOURCE_FILES ${CPP_FILES})
add_executable(IfcGeomServer ${SOURCE_FILES})
target_link_libraries(IfcGeomServer IfcGeom ${kernel_libraries} ${OpenCASCADE_LIBRARIES})
target_link_libraries(IfcGeomServer IfcGeom ${OpenCASCADE_LIBRARIES})
if(WITH_OPENCASCADE)
target_link_libraries(IfcGeomServer geometry_kernel_opencascade)
endif()
install(TARGETS IfcGeomServer)
+3 -3
View File
@@ -43,11 +43,11 @@
#include "../ifcgeom/Iterator.h"
#include "../ifcgeom/IfcGeomElement.h"
#include "../ifcgeom/kernel_registry.h"
#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include "../ifcparse/file.h"
#include "../ifcparse/logger.h"
#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
#if USE_VLD
#include <vld.h>
#endif
@@ -605,7 +605,7 @@ int main () {
settings.get<ifcopenshell::geometry::settings::MesherLinearDeflection>().value = deflection;
file = new ifcopenshell::file(data, (int)len);
iterator = new IfcGeom::Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>(new IfcGeom::OpenCascadeKernel(settings)), settings, file);
iterator = new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, "opencascade", settings), settings, file);
has_more = iterator->initialize();
More(has_more).write(std::cout);
-4
View File
@@ -20,7 +20,6 @@
#ifndef IFC_PARSE_API_H
#define IFC_PARSE_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef IFC_PARSE_EXPORTS
#define IFC_PARSE_API __declspec(dllexport)
@@ -30,8 +29,5 @@
#else // simply assume *nix + GCC-like compiler
#define IFC_PARSE_API __attribute__((visibility("default")))
#endif
#else
#define IFC_PARSE_API
#endif
#endif
+1 -1
View File
@@ -147,7 +147,7 @@ target_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${O
else()
target_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${LIBSVGFILL})
endif()
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
if(NOT WIN32)
SET_INSTALL_RPATHS(ifcopenshell_wrapper "${IFCDIRS};${OCC_LIBRARY_DIR}")
endif()
+45 -2
View File
@@ -19,14 +19,17 @@
#include "plugin.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/dll/shared_library.hpp>
#include <algorithm>
#include <filesystem>
#include <sstream>
#include <stdexcept>
namespace {
using plugin_abi_fn = ifcopenshell::plugin::abi_info(*)();
using plugin_metadata_fn = ifcopenshell::plugin::metadata(*)();
using plugin_abi_fn = ifcopenshell::plugin::abi_info();
using plugin_metadata_fn = ifcopenshell::plugin::metadata();
std::string compiler_id() {
#if defined(_MSC_VER)
@@ -101,6 +104,13 @@ bool ifcopenshell::plugin::module::is_loaded() const {
return data_->library_ && data_->library_->is_loaded();
}
boost::dll::shared_library& ifcopenshell::plugin::module::library() const {
if (!data_->library_) {
throw std::runtime_error("Plugin module is not dynamic");
}
return *data_->library_;
}
ifcopenshell::plugin::manager::manager() = default;
void ifcopenshell::plugin::manager::add_search_path(const std::filesystem::path& path) {
@@ -111,6 +121,39 @@ const std::vector<std::filesystem::path>& ifcopenshell::plugin::manager::search_
return search_paths_;
}
std::vector<std::filesystem::path> ifcopenshell::plugin::manager::discover(const std::string& basename_prefix) const {
std::vector<std::filesystem::path> result;
const auto suffix = boost::dll::shared_library::suffix().string();
const auto prefixed_basename = "lib" + basename_prefix;
for (const auto& search_path : search_paths_) {
if (!std::filesystem::exists(search_path) || !std::filesystem::is_directory(search_path)) {
continue;
}
for (const auto& entry : std::filesystem::directory_iterator(search_path)) {
if (!entry.is_regular_file()) {
continue;
}
const auto filename = entry.path().filename().string();
if (!boost::algorithm::iends_with(filename, suffix)) {
continue;
}
if (!boost::algorithm::istarts_with(filename, basename_prefix) &&
!boost::algorithm::istarts_with(filename, prefixed_basename)) {
continue;
}
result.push_back(entry.path());
}
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
return result;
}
ifcopenshell::plugin::module ifcopenshell::plugin::manager::load(const std::filesystem::path& path) const {
auto library = std::make_shared<boost::dll::shared_library>(path, boost::dll::load_mode::default_mode);
auto abi = library->get_alias<plugin_abi_fn>("ifcopenshell_plugin_abi_v1")();
+9
View File
@@ -22,6 +22,8 @@
#include "plugin_api.h"
#include <boost/dll/shared_library.hpp>
#include <cstdint>
#include <filesystem>
#include <memory>
@@ -68,11 +70,17 @@ public:
bool is_dynamic() const;
bool is_loaded() const;
template <typename T>
decltype(auto) get_alias(const char* name) const {
return library().get_alias<T>(name);
}
private:
struct data;
std::shared_ptr<data> data_;
explicit module(std::shared_ptr<data> data);
boost::dll::shared_library& library() const;
friend class manager;
};
@@ -84,6 +92,7 @@ public:
void add_search_path(const std::filesystem::path& path);
const std::vector<std::filesystem::path>& search_paths() const;
std::vector<std::filesystem::path> discover(const std::string& basename_prefix) const;
module load(const std::filesystem::path& path) const;
private:
-4
View File
@@ -20,7 +20,6 @@
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef PLUGIN_EXPORTS
#define PLUGIN_API __declspec(dllexport)
@@ -30,8 +29,5 @@
#else
#define PLUGIN_API __attribute__((visibility("default")))
#endif
#else
#define PLUGIN_API
#endif
#endif
+4
View File
@@ -24,6 +24,10 @@ target_link_libraries(Serializers
IfcGeom ${OpenCASCADE_LIBRARIES} IfcParse
)
if(WITH_OPENCASCADE)
target_link_libraries(Serializers PRIVATE geometry_kernel_opencascade)
endif()
install(TARGETS Serializers)
install(FILES ${SERIALIZERS_H_FILES}
+6 -10
View File
@@ -20,18 +20,14 @@
#ifndef IFC_SERIALIZERS_API_H
#define IFC_SERIALIZERS_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef SERIALIZERS_EXPORTS
#define SERIALIZERS_API __declspec(dllexport)
#else
#define SERIALIZERS_API __declspec(dllimport)
#endif
#else // simply assume *nix + GCC-like compiler
#define SERIALIZERS_API __attribute__((visibility("default")))
#ifdef _WIN32
#ifdef SERIALIZERS_EXPORTS
#define SERIALIZERS_API __declspec(dllexport)
#else
#define SERIALIZERS_API __declspec(dllimport)
#endif
#else
#define SERIALIZERS_API
#define SERIALIZERS_API __attribute__((visibility("default")))
#endif
#endif
-4
View File
@@ -21,7 +21,6 @@
#ifndef SVGFILL_H
#define SVGFILL_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef svgfill_EXPORTS
#define SVGFILL_API __declspec(dllexport)
@@ -31,9 +30,6 @@
#else // simply assume *nix + GCC-like compiler
#define SVGFILL_API __attribute__((visibility("default")))
#endif
#else
#define SVGFILL_API
#endif
#include <array>
#include <string>