diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index bd7730cd15..14e2f2e3ae 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -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) diff --git a/src/ifcconvert/CMakeLists.txt b/src/ifcconvert/CMakeLists.txt index 4a889a57bf..24c525f638 100644 --- a/src/ifcconvert/CMakeLists.txt +++ b/src/ifcconvert/CMakeLists.txt @@ -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) diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp deleted file mode 100644 index a26c963e7f..0000000000 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#ifdef IFOPSH_WITH_CGAL - -#include "validation_utils.h" - -using namespace ifcopenshell::geometry; - -#include -#include -#include -#include - -typedef Kernel_::FT FT; -typedef Kernel_::Point_3 Point; -typedef Kernel_::Segment_3 Segment; -typedef CGAL::Polyhedron_3 Polyhedron; -typedef CGAL::AABB_face_graph_triangle_primitive Primitive; -typedef CGAL::AABB_traits Traits; -typedef CGAL::AABB_tree 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, 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("RelatingSpace"); - try { - auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value("RelatedBuildingElement"); - rel_by_space_elem.insert({ { x,y }, rel }); - } catch (ifcopenshell::exception&) { - // RelatedBuildingElement can be NULL - } - }); - } - - std::set rels_encounted; - - ifcopenshell::file f2("boundaries-triangulated.ifc"); - if (!f2.good()) { - return; - } - - ifcopenshell::geometry::Settings settings; - - settings.get().value = false; - settings.get().value = false; - settings.get().value = true; - settings.get().value = true; - settings.get().value = ifcopenshell::geometry::settings::NATIVE; - settings.get().value = true; - - ifcopenshell::geometry::Converter c("cgal", &f2, settings); - - std::map, std::vector> elem_to_space_boundary_coords; - - for (auto& i : *f2.instances_by_type("IfcProduct")) { - auto n = ((ifcopenshell::IfcBaseEntity*)i)->get_value("Name"); - auto g1 = n.substr(0, 22); - auto g2 = n.substr(23); - auto item = c.mapping()->map(i); - if (taxonomy::cast(item)->children[0] == nullptr) { - continue; - } - auto shell = taxonomy::cast(taxonomy::cast(taxonomy::cast(item)->children[0])->children[0]); - for (auto& face : shell->children) { - for (auto& wire : face->children) { - for (auto& edge : wire->children) { - auto p3 = boost::get(edge->start); - auto p4 = taxonomy::cast(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 > 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("GlobalId"); - auto Bguid = B->get_value("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 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("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 diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp deleted file mode 100644 index 39c5df0176..0000000000 --- a/src/ifcconvert/validate_storey_containment.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#ifdef IFOPSH_WITH_CGAL - -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#include "../ifcgeom/IfcGeomFilter.h" -#include "../ifcgeom/Iterator.h" - -#include -#include - -#include - -void fix_storeycontainment(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) { - ifcopenshell::geometry::Settings settings; - - settings.get().value = false; - settings.get().value = false; - settings.get().value = true; - settings.get().value = true; - settings.get().value = ifcopenshell::geometry::settings::NATIVE; - settings.get().value = true; - - std::vector 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("Elevation", 0.); - }; - - // latebound inverse attribute lookup not working - auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure"); - std::map elem_to_storey; - std::for_each(rels->begin(), rels->end(), [&elem_to_storey](ifcopenshell::IfcBaseClass* r) { - auto elems = ((ifcopenshell::IfcBaseEntity*)r)->get_value("RelatedElements"); - auto storey = ((ifcopenshell::IfcBaseEntity*)r)->get_value("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 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("Name"); - std::wcout << n.c_str() << " "; - } - std::wcout << std::endl; - */ - - std::vector elevations; - std::transform(storeys_sorted.begin(), storeys_sorted.end(), std::back_inserter(elevations), get_elevation); - - double LARGE = 1e4; - - std::vector> 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& p) { - p.first -= 0.3; - p.second += 0.3; - }); - - std::vector> nefs; - std::transform(elevation_slices.begin(), elevation_slices.end(), std::back_inserter(nefs), [&LARGE](const std::pair& 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 intersection_volumes(nefs.size()); - - for (auto& g : geom_object->geometry()) { - auto s = std::static_pointer_cast(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 part_nef = ifcopenshell::geometry::utils::create_nef_polyhedron(s); - - if (!part_nef.is_simple()) { - // std::wcout << "not simple" << std::endl; - continue; - } - - std::vector::iterator accumulator = intersection_volumes.begin(); - std::for_each(nefs.begin(), nefs.end(), [&accumulator, &part_nef](const CGAL::Nef_polyhedron_3& 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("GlobalId"); - auto s1 = ((ifcopenshell::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value("GlobalId"); - auto s2 = ((ifcopenshell::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value("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(num_created) + - " objects "); - } -} - -#endif diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp deleted file mode 100644 index ba068a8bd9..0000000000 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#ifdef IFOPSH_WITH_CGAL - -#include "validation_utils.h" - -#include -#include - -#include - -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().value = false; - settings.get().value = false; - settings.get().value = true; - settings.get().value = true; - settings.get().value = ifcopenshell::geometry::settings::NATIVE; - settings.get().value = true; - - settings.get().value = true; - settings.get().value = false; - - ifcopenshell::geometry::Converter c("cgal", &f, settings); - - auto rels = f.instances_by_type("IfcRelConnectsPathElements"); - std::map, 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("RelatingElement"); - auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value("RelatedElement"); - rel_by_elem.insert({{ x,y }, rel}); - }); - - std::set 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("RelatingElement"); - a_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value("RelatingConnectionType"); - b_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value("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(item)->children[0]; - auto loop = taxonomy::dcast(taxonomy::cast(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(first_vertex); - auto p1 = boost::get(last_vertex); - - auto v0 = taxonomy::cast(item)->matrix->ccomponents() * p0->ccomponents().homogeneous(); - auto v1 = taxonomy::cast(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 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::quiet_NaN(); - return std::make_pair(nan, std::make_pair(nan, nan)); - }; - - auto qualify_connection_type = [](double l, const std::pair& 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("GlobalId"); - auto B_str = B->get_value("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("RelatingElement"); - auto y = (ifcopenshell::IfcBaseEntity*)((ifcopenshell::IfcBaseEntity*)rel)->get_value("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 diff --git a/src/ifcconvert/validation_utils.cpp b/src/ifcconvert/validation_utils.cpp deleted file mode 100644 index e4e591f853..0000000000 --- a/src/ifcconvert/validation_utils.cpp +++ /dev/null @@ -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 diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h deleted file mode 100644 index 47af806975..0000000000 --- a/src/ifcconvert/validation_utils.h +++ /dev/null @@ -1,602 +0,0 @@ -#ifdef IFOPSH_WITH_CGAL - -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#include "../ifcgeom/IfcGeomFilter.h" -#include "../ifcgeom/Iterator.h" - -#include -#include - -#include -#if CGAL_VERSION_NR >= 1060000000 -#include -#else -#include -#endif -#include -#include - -#include -#include - -#if CGAL_VERSION_NR >= 1060000000 -#define variant_get std::get_if -#else -#define variant_get boost::get -#endif - -template -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 -struct Build_Offset : public CGAL::Modifier_base { - std::list input; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 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 -std::list connected_faces(cgal_shape_t::Facet_handle f, const Ts& excluded) { - std::set fs = { f }; - - std::function 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(fs.begin(), fs.end()); -} - -template -struct Builder_With_Map : public CGAL::Modifier_base { - std::list input; - std::map mapping; - - void operator()(HDS& hds) { - // Postcondition: hds is a valid polyhedral surface. - CGAL::Polyhedron_incremental_builder_3 B(hds); - - std::set 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 Polyhedron; - typedef CGAL::AABB_face_graph_triangle_primitive Primitive; -#if CGAL_VERSION_NR >= 1060000000 - typedef CGAL::AABB_traits_3 AAbbTraits; -#else - typedef CGAL::AABB_traits AAbbTraits; -#endif - typedef CGAL::AABB_tree Tree; - typedef boost::optional::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 non_degenerate, degenerate, longitudinal; - std::set 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 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 face_normals; - boost::associative_property_map> 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 intersections; - tree.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - for (auto& intersection : intersections) { - if (variant_get(&(intersection->first))) { - const Point* p = variant_get(&(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::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 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 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 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 intersections; - tree2.all_intersections(ray, std::back_inserter(intersections)); - double N = std::numeric_limits::infinity(); - Point P; - - bool used_intersection = false; - - if (intersections.size()) { - for (auto& intersection : intersections) { - if (variant_get(&(intersection->first))) { - const Point* p = variant_get(&(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 longi(longitudinal.begin(), longitudinal.end()); - std::set 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 b2; - b2.input = connected; - b2.mapping = new_points; - - flattened.delegate(b2); - } -}; - - -struct intersection_validator { - typedef std::list> > nefs_t; - typedef CGAL::Box_intersection_d::Box_with_handle_d Box; - - std::vector 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 successfully_processed; - - intersection_validator(ifcopenshell::file& f, std::initializer_list entities, double eps, bool no_progress, bool quiet, bool stderr_progress) { - - ifcopenshell::geometry::Settings settings; - settings.get().value = false; - settings.get().value = false; - settings.get().value = true; - settings.get().value = true; - settings.get().value = ifcopenshell::geometry::settings::NATIVE; - settings.get().value = true; - - std::vector 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(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 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(num_created) + - " objects "); - } - - /* - // @todo - total_geom_time = context_iterator.converter().total_geom_time; - total_map_time = context_iterator.converter().total_map_time; - */ - } - - template - 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 \ No newline at end of file diff --git a/src/ifcgeom/CMakeLists.txt b/src/ifcgeom/CMakeLists.txt index 7e560fb424..1c35ba53bb 100644 --- a/src/ifcgeom/CMakeLists.txt +++ b/src/ifcgeom/CMakeLists.txt @@ -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} diff --git a/src/ifcgeom/Iterator.cpp b/src/ifcgeom/Iterator.cpp index 914673dc54..eab7744e48 100644 --- a/src/ifcgeom/Iterator.cpp +++ b/src/ifcgeom/Iterator.cpp @@ -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; diff --git a/src/ifcgeom/Iterator.h b/src/ifcgeom/Iterator.h index fb7ace7768..61c369cb0a 100644 --- a/src/ifcgeom/Iterator.h +++ b/src/ifcgeom/Iterator.h @@ -68,10 +68,6 @@ #include "../ifcgeom/abstract_mapping.h" #include "../ifcgeom/GeometrySerializer.h" -#ifdef IFOPSH_WITH_OPENCASCADE -#include -#endif - #include #include diff --git a/src/ifcgeom/Serialization/CMakeLists.txt b/src/ifcgeom/Serialization/CMakeLists.txt index 454de685a6..7aff8993f1 100644 --- a/src/ifcgeom/Serialization/CMakeLists.txt +++ b/src/ifcgeom/Serialization/CMakeLists.txt @@ -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) diff --git a/src/ifcgeom/Serialization/ifc_geomserialization_api.h b/src/ifcgeom/Serialization/ifc_geomserialization_api.h index 93058cf04f..939d5feff0 100644 --- a/src/ifcgeom/Serialization/ifc_geomserialization_api.h +++ b/src/ifcgeom/Serialization/ifc_geomserialization_api.h @@ -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 diff --git a/src/ifcgeom/ifc_geom_api.h b/src/ifcgeom/ifc_geom_api.h index af3171fcfe..18b4a9f87b 100644 --- a/src/ifcgeom/ifc_geom_api.h +++ b/src/ifcgeom/ifc_geom_api.h @@ -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 diff --git a/src/ifcgeom/kernel_plugin.cpp b/src/ifcgeom/kernel_plugin.cpp new file mode 100644 index 0000000000..6df0e14836 --- /dev/null +++ b/src/ifcgeom/kernel_plugin.cpp @@ -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 . * + * * + ********************************************************************************/ + +#include "kernel_plugin.h" + +#ifndef _WIN32 +#include +#else +#include +#endif + +#include + +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(&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(&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(kernel_plugin_registration_symbol()); + register_plugin(registry, module); + } +} diff --git a/src/ifcgeom/kernel_plugin.h b/src/ifcgeom/kernel_plugin.h new file mode 100644 index 0000000000..5a72beb433 --- /dev/null +++ b/src/ifcgeom/kernel_plugin.h @@ -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 . * + * * + ********************************************************************************/ + +#ifndef IFCOPENSHELL_KERNEL_PLUGIN_H +#define IFCOPENSHELL_KERNEL_PLUGIN_H + +#include "../ifcgeom/kernel_registry.h" + +#include + +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 diff --git a/src/ifcgeom/kernel_registry.cpp b/src/ifcgeom/kernel_registry.cpp index 7fc8d04817..c390cc9464 100644 --- a/src/ifcgeom/kernel_registry.cpp +++ b/src/ifcgeom/kernel_registry.cpp @@ -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 #include -#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 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; } diff --git a/src/ifcgeom/kernels/CMakeLists.txt b/src/ifcgeom/kernels/CMakeLists.txt index ec1a8c1d74..4973758444 100644 --- a/src/ifcgeom/kernels/CMakeLists.txt +++ b/src/ifcgeom/kernels/CMakeLists.txt @@ -1,7 +1,7 @@ -find_package(Eigen3 REQUIRED) - message(STATUS "GEOMETRY_KERNELS ${GEOMETRY_KERNELS}") +set(kernel_plugin_runtime_dir "${CMAKE_BINARY_DIR}/ifcgeom/$") + 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} diff --git a/src/ifcgeom/kernels/cgal/plugin.cpp b/src/ifcgeom/kernels/cgal/plugin.cpp new file mode 100644 index 0000000000..53d197c269 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/plugin.cpp @@ -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 . * + * * + ********************************************************************************/ + +#include "../../kernel_plugin.h" +#include "CgalKernel.h" + +#include + +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) diff --git a/src/ifcgeom/kernels/ifc_geomlibrary_api.h b/src/ifcgeom/kernels/ifc_geomlibrary_api.h index 91aeda7364..5f44d31169 100644 --- a/src/ifcgeom/kernels/ifc_geomlibrary_api.h +++ b/src/ifcgeom/kernels/ifc_geomlibrary_api.h @@ -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 diff --git a/src/ifcgeom/kernels/manifold/plugin.cpp b/src/ifcgeom/kernels/manifold/plugin.cpp new file mode 100644 index 0000000000..6f7dd2d744 --- /dev/null +++ b/src/ifcgeom/kernels/manifold/plugin.cpp @@ -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 . * + * * + ********************************************************************************/ + +#include "../../kernel_plugin.h" +#include "ManifoldKernel.h" + +#include + +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) diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 70a6259a60..0f49a96246 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -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); diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h index 001aaa656b..5e9952b335 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -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"); diff --git a/src/ifcgeom/kernels/opencascade/boolean_utils.h b/src/ifcgeom/kernels/opencascade/boolean_utils.h index 80a9b49998..118df92a54 100644 --- a/src/ifcgeom/kernels/opencascade/boolean_utils.h +++ b/src/ifcgeom/kernels/opencascade/boolean_utils.h @@ -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& interval); + IFC_GEOMLIBRARY_API bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair& 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 \ No newline at end of file +#endif diff --git a/src/ifcgeom/kernels/opencascade/plugin.cpp b/src/ifcgeom/kernels/opencascade/plugin.cpp new file mode 100644 index 0000000000..2c934fe9ba --- /dev/null +++ b/src/ifcgeom/kernels/opencascade/plugin.cpp @@ -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 . * + * * + ********************************************************************************/ + +#include "../../kernel_plugin.h" +#include "OpenCascadeKernel.h" + +#include + +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) diff --git a/src/ifcgeom/kernels/passthrough/plugin.cpp b/src/ifcgeom/kernels/passthrough/plugin.cpp new file mode 100644 index 0000000000..34e8f877a7 --- /dev/null +++ b/src/ifcgeom/kernels/passthrough/plugin.cpp @@ -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 . * + * * + ********************************************************************************/ + +#include "../../kernel_plugin.h" +#include "PassthroughKernel.h" + +#include + +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) diff --git a/src/ifcgeomserver/CMakeLists.txt b/src/ifcgeomserver/CMakeLists.txt index ff56607ff2..ddd9358532 100644 --- a/src/ifcgeomserver/CMakeLists.txt +++ b/src/ifcgeomserver/CMakeLists.txt @@ -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) diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index a888c3ebe1..25d7d5e0eb 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -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 #endif @@ -605,7 +605,7 @@ int main () { settings.get().value = deflection; file = new ifcopenshell::file(data, (int)len); - iterator = new IfcGeom::Iterator(std::unique_ptr(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); diff --git a/src/ifcparse/ifc_parse_api.h b/src/ifcparse/ifc_parse_api.h index d4aa823fda..70d600b733 100644 --- a/src/ifcparse/ifc_parse_api.h +++ b/src/ifcparse/ifc_parse_api.h @@ -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 diff --git a/src/ifcwrap/CMakeLists.txt b/src/ifcwrap/CMakeLists.txt index d752cc6650..32f472af16 100644 --- a/src/ifcwrap/CMakeLists.txt +++ b/src/ifcwrap/CMakeLists.txt @@ -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() diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp index a12dcbd943..7f8c290dba 100644 --- a/src/plugin/plugin.cpp +++ b/src/plugin/plugin.cpp @@ -19,14 +19,17 @@ #include "plugin.h" +#include #include +#include +#include #include #include 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& ifcopenshell::plugin::manager::search_ return search_paths_; } +std::vector ifcopenshell::plugin::manager::discover(const std::string& basename_prefix) const { + std::vector 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(path, boost::dll::load_mode::default_mode); auto abi = library->get_alias("ifcopenshell_plugin_abi_v1")(); diff --git a/src/plugin/plugin.h b/src/plugin/plugin.h index 7ada44fe63..68d2110498 100644 --- a/src/plugin/plugin.h +++ b/src/plugin/plugin.h @@ -22,6 +22,8 @@ #include "plugin_api.h" +#include + #include #include #include @@ -68,11 +70,17 @@ public: bool is_dynamic() const; bool is_loaded() const; + template + decltype(auto) get_alias(const char* name) const { + return library().get_alias(name); + } + private: struct data; std::shared_ptr data_; explicit module(std::shared_ptr 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& search_paths() const; + std::vector discover(const std::string& basename_prefix) const; module load(const std::filesystem::path& path) const; private: diff --git a/src/plugin/plugin_api.h b/src/plugin/plugin_api.h index ca87e9ada5..17eb1f0198 100644 --- a/src/plugin/plugin_api.h +++ b/src/plugin/plugin_api.h @@ -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 diff --git a/src/serializers/CMakeLists.txt b/src/serializers/CMakeLists.txt index b5e8ad8ae0..0ed46dcfb1 100644 --- a/src/serializers/CMakeLists.txt +++ b/src/serializers/CMakeLists.txt @@ -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} diff --git a/src/serializers/serializers_api.h b/src/serializers/serializers_api.h index 0e37f59442..c11b099419 100644 --- a/src/serializers/serializers_api.h +++ b/src/serializers/serializers_api.h @@ -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 diff --git a/src/svgfill/src/svgfill.h b/src/svgfill/src/svgfill.h index 5c2a68834f..903b7f1c3b 100644 --- a/src/svgfill/src/svgfill.h +++ b/src/svgfill/src/svgfill.h @@ -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 #include