diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4084d02f24..63c8712908 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -88,6 +88,12 @@ UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR) UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PCRE_LIBRARY_DIR) UNIFY_ENVVARS_AND_CACHE(PYTHON_EXECUTABLE) +UNIFY_ENVVARS_AND_CACHE(CGAL_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(CGAL_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(GMP_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(GMP_LIBRARY_DIR) +UNIFY_ENVVARS_AND_CACHE(MPFR_INCLUDE_DIR) +UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR) IF(WIN32) UNIFY_ENVVARS_AND_CACHE(THREEDS_MAX_SDK_HOME) ENDIF() @@ -193,6 +199,48 @@ foreach(lib ${OPENCASCADE_LIBRARY_NAMES}) list(APPEND OPENCASCADE_LIBRARIES "${lib_path}") endforeach() +SET(CGAL_LIBRARY_NAMES libCGAL_Core libCGAL_ImageIO libCGAL) +# Find CGAL +IF("${CGAL_INCLUDE_DIR}" STREQUAL "") + SET(CGAL_INCLUDE_DIR "/usr/include/" CACHE FILEPATH "CGAL header files") + MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}") + MESSAGE(STATUS "Use CGAL_INCLUDE_DIR to specify another directory") +ELSE() + SET(CGAL_INCLUDE_DIR ${CGAL_INCLUDE_DIR} CACHE FILEPATH "CGAL header files") + MESSAGE(STATUS "Looking for CGAL include files in: ${CGAL_INCLUDE_DIR}") +ENDIF() +IF("${CGAL_LIBRARY_DIR}" STREQUAL "") + SET(CGAL_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "CGAL library files") + MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}") + MESSAGE(STATUS "Use CGAL_LIBRARY_DIR to specify another directory") +ELSE() + SET(CGAL_LIBRARY_DIR ${CGAL_LIBRARY_DIR} CACHE FILEPATH "CGAL library files") + MESSAGE(STATUS "Looking for CGAL library files in: ${CGAL_LIBRARY_DIR}") +ENDIF() +FIND_LIBRARY(libCGAL NAMES CGAL PATHS ${CGAL_LIBRARY_DIR} NO_DEFAULT_PATH) +IF(libCGAL) + MESSAGE(STATUS "CGAL library files found") +ELSE() + MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") +ENDIF() +foreach(lib ${CGAL_LIBRARY_NAMES}) + string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}") + list(APPEND CGAL_LIBRARIES "${lib_path}") +endforeach() +FIND_LIBRARY(libGMP NAMES gmp PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH) +FIND_LIBRARY(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH) +IF(NOT libGMP) + MESSAGE(FATAL_ERROR "Unable to find GMP library files, aborting") +ENDIF() +IF(NOT libMPFR) + MESSAGE(FATAL_ERROR "Unable to find MPFR library files, aborting") +ENDIF() +list(APPEND CGAL_LIBRARIES "${libGMP}") +list(APPEND CGAL_LIBRARIES "${libMPFR}") + + + + if(MSVC) add_definitions(-DHAVE_NO_DLL) add_debug_variants(OPENCASCADE_LIBRARIES "${OPENCASCADE_LIBRARIES}" d) @@ -384,7 +432,8 @@ ElSE() ENDIF() INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS} - ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} + ${ICU_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${CGAL_INCLUDE_DIR} + ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ) function(files_for_ifc_version IFC_VERSION RESULT_NAME) @@ -517,6 +566,14 @@ if(NOT MSVC) endif() endif() +include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11) +if(COMPILER_SUPPORTS_CXX11) + add_definitions(-std=c++11) +else() + message(FATAL_ERROR "CGAL kernel requires a compiler with C++11 support") +endif() + set(IFCOPENSHELL_LIBRARIES IfcParse IfcGeom) # IfcParse @@ -548,7 +605,7 @@ set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES}) add_library(IfcGeom ${IFCGEOM_FILES}) set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS) -TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${OPENCASCADE_LIBRARIES}) +TARGET_LINK_LIBRARIES(IfcGeom IfcParse ${OPENCASCADE_LIBRARIES} ${CGAL_LIBRARIES}) # IfcConvert file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp) @@ -559,7 +616,7 @@ if (IFCCONVERT_DOUBLE_PRECISION) set_target_properties(IfcConvert PROPERTIES COMPILE_FLAGS -DIFCCONVERT_DOUBLE_PRECISION) endif() -TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES}) +TARGET_LINK_LIBRARIES(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${ICU_LIBRARIES} ${CGAL_LIBRARIES} ${Boost_LIBRARIES}) if ((NOT WIN32) AND BUILD_SHARED_LIBS) # Only set RPATHs when building shared libraries (i.e. IfcParse and # IfcGeom are dynamically linked). Not necessarily a perfect solution @@ -572,7 +629,7 @@ endif() # file(GLOB H_FILES ../src/ifcgeomserver/*.h) # set(SOURCE_FILES ${CPP_FILES} ${H_FILES}) # ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES}) -# TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES}) +# TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBRARIES} ${CGAL_LIBRARIES}) # if ((NOT WIN32) AND BUILD_SHARED_LIBS) # SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${ICU_LIBRARY_DIR}") # endif() diff --git a/nix/build-all.py b/nix/build-all.py index 9fd36bd27d..277b89f439 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -460,7 +460,7 @@ OLD_BUILD_CFG = BUILD_CFG if BUILD_CFG != "Debug": # CGAL only supports Debug and Release for CMAKE_BUILD_TYPE BUILD_CFG = "Release" -build_dependency(name="cgal", mode="cmake", build_tool_args=["-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) +build_dependency(name="cgal", mode="cmake", build_tool_args=["-DBUILD_SHARED_LIBS=Off", "-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) BUILD_CFG = OLD_BUILD_CFG build_dependency(name="icu-%s" % (ICU_VERSION,), mode="icu", build_tool_args=["--enable-static", "--disable-shared"], download_url="http://download.icu-project.org/files/icu4c/%s/" % (ICU_VERSION,), download_name="icu4c-%s-src.tgz" % (ICU_VERSION_UNDERSCORE,)) @@ -482,6 +482,14 @@ run_cmake("", cmake_args=[ "-DBOOST_ROOT=" "%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DOCC_INCLUDE_DIR=" "%s/install/oce-%s/include/oce" % (DEPS_DIR, OCE_VERSION), "-DOCC_LIBRARY_DIR=" "%s/install/oce-%s/lib" % (DEPS_DIR, OCE_VERSION), + + "-DCGAL_INCLUDE_DIR=" "%s/install/cgal/include" % (DEPS_DIR,), + "-DCGAL_LIBRARY_DIR=" "%s/install/cgal/lib" % (DEPS_DIR,), + "-DGMP_INCLUDE_DIR=" "%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), + "-DGMP_LIBRARY_DIR=" "%s/install/gmp-%s/lib" % (DEPS_DIR, GMP_VERSION), + "-DMPFR_INCLUDE_DIR=" "%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), + "-DMPFR_LIBRARY_DIR=" "%s/install/mpfr-%s/lib" % (DEPS_DIR, MPFR_VERSION), + "-DOPENCOLLADA_INCLUDE_DIR=" "%s/install/OpenCOLLADA/include/opencollada" % (DEPS_DIR,), "-DOPENCOLLADA_LIBRARY_DIR=" "%s/install/OpenCOLLADA/lib/opencollada" % (DEPS_DIR,), "-DICU_INCLUDE_DIR=" "%s/install/icu-%s/include" % (DEPS_DIR, ICU_VERSION), diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 063b4d8abf..38f9e0d457 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -23,71 +23,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers return part_succes; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { - const double height = l->Depth() * getValue(GV_LENGTH_UNIT); - if (height < getValue(GV_PRECISION)) { - Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); - return false; - } - - cgal_face_t face; - if ( !convert_face(l->SweptArea(),face) ) return false; - - cgal_placement_t trsf; - bool has_position = true; -#ifdef USE_IFC4 - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::CgalKernel::convert(l->Position(), trsf); - } - - cgal_direction_t dir; - convert(l->ExtrudedDirection(),dir); -// std::cout << "Direction: " << dir << std::endl; - - std::list face_list; - face_list.push_back(face); - - for (std::vector::const_iterator current_vertex = face.outer.begin(); - current_vertex != face.outer.end(); - ++current_vertex) { - std::vector::const_iterator next_vertex = current_vertex; - ++next_vertex; - if (next_vertex == face.outer.end()) { - next_vertex = face.outer.begin(); - } cgal_face_t side_face; - side_face.outer.push_back(*next_vertex); - side_face.outer.push_back(*current_vertex); - side_face.outer.push_back(*current_vertex+height*dir); - side_face.outer.push_back(*next_vertex+height*dir); - face_list.push_back(side_face); - } - - cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); - vertex != face.outer.rend(); - ++vertex) { - top_face.outer.push_back(*vertex+height*dir); - } face_list.push_back(top_face); - - // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); - PolyhedronBuilder builder(&face_list); - polyhedron.delegate(builder); - - // Stitch edges -// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); - if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } -// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - - shape = polyhedron; - return true; -} - bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); if (xyz.size() == 3) { @@ -209,30 +144,3 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) return true; } - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) { - const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); - const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); - - if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { - Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); - return false; - } - - cgal_placement_t trsf2d; - bool has_position = true; -#ifdef USE_IFC4 - has_position = l->hasPosition(); -#endif - if (has_position) { - IfcGeom::CgalKernel::convert(l->Position(), trsf2d); - } - - face = cgal_face_t(); - face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); - face.outer.push_back(Kernel::Point_3( x, -y, 0.0)); - face.outer.push_back(Kernel::Point_3( x, y, 0.0)); - face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); - - return true; -} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index d7c576a4e7..26d5f819c1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -81,79 +81,6 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) return success; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { - cgal_shape_t s; - const SurfaceStyle* collective_style = get_style(l); - if (convert_shape(l->Outer(),s) ) { - const SurfaceStyle* indiv_style = get_style(l->Outer()); - - IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { - voids = l->as()->Voids(); - } -#endif - - for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { -// TopoDS_Shape s2; -// /// @todo No extensive shapefixing since shells should be disjoint. -// /// @todo Awaiting generalized boolean ops module with appropriate checking -// if (convert_shape(l->Outer(), s2)) { -// s = BRepAlgoAPI_Cut(s, s2).Shape(); -// } - } - - shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); - return true; - } - return false; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { - IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); - - std::list face_list; - for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) { - bool success = false; - cgal_face_t face; - - try { - success = convert_face(*it, face); - } catch (...) {} - - if (!success) { - Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); - continue; - } - -// std::cout << "Face in ConnectedFaceSet: " << std::endl; -// for (auto &point: face.outer) { -// std::cout << "\tPoint(" << point << ")" << std::endl; -// } - - face_list.push_back(face); - } - - // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); - PolyhedronBuilder builder(&face_list); - polyhedron.delegate(builder); - - // Stitch edges -// std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); - if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { - CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } -// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - - shape = polyhedron; - return true; -} - bool IfcGeom::CgalKernel::convert_wire(const IfcBaseClass* l, cgal_wire_t& r) { #include "CgalEntityMappingWire.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); @@ -166,94 +93,6 @@ bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { return false; } -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) { - IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); - - int num_outer_bounds = 0; - - for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { - IfcSchema::IfcFaceBound* bound = *it; - if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; - } - - if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); - return false; - } - - cgal_face_t mf; - - for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { - IfcSchema::IfcFaceBound* bound = *it; - IfcSchema::IfcLoop* loop = bound->Bound(); - - const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); - - cgal_wire_t wire; - if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); - return false; - } - - if (!is_interior) { - mf.outer = wire; - } else { - mf.inner.push_back(wire); - } - } - - face = mf; - -// std::cout << "Face: " << std::endl; -// for (auto &point: face.outer) { -// std::cout << "\tPoint(" << point << ")" << std::endl; -// } - - return true; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) { - IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); - - // Parse and store the points in a sequence - cgal_wire_t polygon = std::vector(); - for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { - cgal_point_t pnt; - IfcGeom::CgalKernel::convert(*it, pnt); - polygon.push_back(pnt); - } - - // A loop should consist of at least three vertices - std::size_t original_count = polygon.size(); - if (original_count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); - return false; - } - - // TODO: Remove repeated points (and points that are too close to one another?) -// remove_duplicate_points_from_loop(polygon, true); - - std::size_t count = polygon.size(); - if (original_count - count != 0) { - std::stringstream ss; ss << (original_count - count) << " edges removed for:"; - Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); - } - - if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); - return false; - } - - result = polygon; - -// std::cout << "PolyLoop: " << std::endl; -// for (auto &point: polygon) { -// std::cout << "\tPoint(" << point << ")" << std::endl; -// } - - return true; -} - bool IfcGeom::CgalKernel::convert_curve(const IfcBaseClass* l, cgal_curve_t& r) { #include "CgalEntityMappingCurve.h" Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp new file mode 100644 index 0000000000..6cd88a434b --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -0,0 +1,74 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) { + const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); + const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + } + + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face) { + IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); + + int num_outer_bounds = 0; + + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + if (bound->is(IfcSchema::Type::IfcFaceOuterBound)) num_outer_bounds ++; + } + + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + return false; + } + + cgal_face_t mf; + + for (IfcSchema::IfcFaceBound::list::it it = bounds->begin(); it != bounds->end(); ++it) { + IfcSchema::IfcFaceBound* bound = *it; + IfcSchema::IfcLoop* loop = bound->Bound(); + + const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + + cgal_wire_t wire; + if (!convert_wire(loop, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop->entity); + return false; + } + + if (!is_interior) { + mf.outer = wire; + } else { + mf.inner.push_back(wire); + } + } + + face = mf; + + // std::cout << "Face: " << std::endl; + // for (auto &point: face.outer) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp new file mode 100644 index 0000000000..b8efaf7f18 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -0,0 +1,140 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, ConversionResults& shape) { + cgal_shape_t s; + const SurfaceStyle* collective_style = get_style(l); + if (convert_shape(l->Outer(),s) ) { + const SurfaceStyle* indiv_style = get_style(l->Outer()); + + IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); + if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#ifdef USE_IFC4 + if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + voids = l->as()->Voids(); + } +#endif + + for (IfcSchema::IfcClosedShell::list::it it = voids->begin(); it != voids->end(); ++it) { + // TopoDS_Shape s2; + // /// @todo No extensive shapefixing since shells should be disjoint. + // /// @todo Awaiting generalized boolean ops module with appropriate checking + // if (convert_shape(l->Outer(), s2)) { + // s = BRepAlgoAPI_Cut(s, s2).Shape(); + // } + } + + shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + return true; + } + return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + if (height < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); + return false; + } + + cgal_face_t face; + if ( !convert_face(l->SweptArea(),face) ) return false; + + cgal_placement_t trsf; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf); + } + + cgal_direction_t dir; + convert(l->ExtrudedDirection(),dir); + // std::cout << "Direction: " << dir << std::endl; + + std::list face_list; + face_list.push_back(face); + + for (std::vector::const_iterator current_vertex = face.outer.begin(); + current_vertex != face.outer.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == face.outer.end()) { + next_vertex = face.outer.begin(); + } cgal_face_t side_face; + side_face.outer.push_back(*next_vertex); + side_face.outer.push_back(*current_vertex); + side_face.outer.push_back(*current_vertex+height*dir); + side_face.outer.push_back(*next_vertex+height*dir); + face_list.push_back(side_face); + } + + cgal_face_t top_face; + for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); + vertex != face.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex+height*dir); + } face_list.push_back(top_face); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + shape = polyhedron; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); + + std::list face_list; + for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) { + bool success = false; + cgal_face_t face; + + try { + success = convert_face(*it, face); + } catch (...) {} + + if (!success) { + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); + continue; + } + + // std::cout << "Face in ConnectedFaceSet: " << std::endl; + // for (auto &point: face.outer) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + face_list.push_back(face); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + shape = polyhedron; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp new file mode 100644 index 0000000000..56e43432c3 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -0,0 +1,43 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& result) { + IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); + + // Parse and store the points in a sequence + cgal_wire_t polygon = std::vector(); + for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { + cgal_point_t pnt; + IfcGeom::CgalKernel::convert(*it, pnt); + polygon.push_back(pnt); + } + + // A loop should consist of at least three vertices + std::size_t original_count = polygon.size(); + if (original_count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + + // TODO: Remove repeated points (and points that are too close to one another?) + // remove_duplicate_points_from_loop(polygon, true); + + std::size_t count = polygon.size(); + if (original_count - count != 0) { + std::stringstream ss; ss << (original_count - count) << " edges removed for:"; + Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + + result = polygon; + + // std::cout << "PolyLoop: " << std::endl; + // for (auto &point: polygon) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +}