diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 6eeefff91f..7a31f62eff 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -264,15 +264,23 @@ ENDIF() FIND_LIBRARY(libCGAL NAMES CGAL PATHS ${CGAL_LIBRARY_DIR} NO_DEFAULT_PATH) IF(libCGAL) MESSAGE(STATUS "CGAL library files found") + foreach(lib ${CGAL_LIBRARY_NAMES}) + string(REPLACE libCGAL "${lib}" lib_path "${libCGAL}") + list(APPEND CGAL_LIBRARIES "${lib_path}") + endforeach() ELSE() - MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") + FILE(GLOB CGAL_LIBRARIES ${CGAL_LIBRARY_DIR}/CGAL*.lib) + LIST(LENGTH CGAL_LIBRARY_NAMES num_cgal_library_names) + LIST(LENGTH CGAL_LIBRARIES num_cgal_libraries) + LINK_DIRECTORIES("${CGAL_LIBRARY_DIR}") + if(NOT "${num_cgal_library_names}" STREQUAL "${num_cgal_library_names}") + MESSAGE(FATAL_ERROR "Unable to find CGAL library files, aborting") + endif() + MESSAGE(STATUS "CGAL library files found") 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) +# TODO: Remove hardcoded version numbers for windows +FIND_LIBRARY(libGMP NAMES gmp "libgmp-10" PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH) +FIND_LIBRARY(libMPFR NAMES mpfr "libmpfr-4" PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH) IF(NOT libGMP) MESSAGE(FATAL_ERROR "Unable to find GMP library files, aborting") ENDIF() diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index c09f8e5810..026b491b88 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -1,241 +1,115 @@ #include "CgalKernel.h" -#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" -#define CgalKernel MAKE_TYPE_NAME(CgalKernel) - -// @todo two distinct uses of the word Kernel is getting confusing -typedef Kernel Kernel_; - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) { - IfcSchema::IfcRepresentationItem::list::ptr items = l->Items(); - bool part_succes = false; - if (items->size()) { - for (IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { - IfcSchema::IfcRepresentationItem* representation_item = *it; - if (shape_type(representation_item) == ST_SHAPELIST) { - part_succes |= convert_shapes(*it, shapes); - } else { - cgal_shape_t s; - if (convert_shape(representation_item, s)) { - shapes.push_back(ConversionResult(representation_item->data().id(), new CgalShape(s))); - part_succes |= true; - } - } - } - } - return part_succes; +bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) { + face.outer = wire; + return true; } -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); - return false; +void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon) { + std::set points; + for (int i = 0; i < polygon.size(); ++i) { + if (points.count(polygon[i])) { + polygon.erase(polygon.begin()+i); + --i; + } else points.insert(polygon[i]); } - - 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); +CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list &face_list) { // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron; 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; + // 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) { - point = Kernel_::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, - xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f, - xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f); -// std::cout << "Converted Point(" << point << ")" << std::endl; - return true; - } else { - throw std::runtime_error("Point without 3 coordinates"); - } -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { -// IN_CACHE(IfcDirection,l,cgal_direction_t,dir) - std::vector xyz = l->DirectionRatios(); - dir = Kernel_::Vector_3(xyz.size() ? xyz[0] : 0.0f, - xyz.size() > 1 ? xyz[1] : 0.0f, - xyz.size() > 2 ? xyz[2] : 0.0f); -// CACHE(IfcDirection,l,dir) - return true; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) { - // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) - cgal_point_t o; - cgal_direction_t axis = Kernel_::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0); // TODO: Put identity for now. Check? - IfcGeom::CgalKernel::convert(l->Location(),o); - bool hasRef = l->hasRefDirection(); - if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); - - // TODO: From Thomas' email. Should be checked. - Kernel_::Vector_3 y = CGAL::cross_product(Kernel_::Vector_3(0.0, 0.0, 1.0), refDirection); - trsf = Kernel_::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), - refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1), - 0.0, y.cartesian(2), 1.0, 0.0); - - // CACHE(IfcAxis2Placement3D,l,trsf) - return true; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_placement_t& trsf) { -// IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) - cgal_point_t o; - cgal_direction_t axis = Kernel_::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel_::Vector_3(1,0,0); // TODO: Put identity for now. Check? - IfcGeom::CgalKernel::convert(l->Location(),o); - bool hasRef = l->hasRefDirection(); - if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); - if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); - -// std::cout << "Ref direction: " << refDirection << std::endl; -// std::cout << "Axis: " << axis << std::endl; -// std::cout << "Origin: " << o << std::endl; - - // TODO: From Thomas' email. Should be checked. - Kernel_::Vector_3 y = CGAL::cross_product(axis, refDirection); - trsf = Kernel_::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), - refDirection.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), - refDirection.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2)); - -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } - -// CACHE(IfcAxis2Placement3D,l,trsf) - return true; -} - -bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { - // TODO: These macros don't work for the CGAL types. Need to check why. -// IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) - if ( ! l->as() ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); - return false; - } - -// std::cout << "initial trsf (identity?)" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } - - IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; - for (;;) { - cgal_placement_t trsf2; - - IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); - if ( relplacement->as() ) { - IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); - -// std::cout << "trsf2" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << trsf2.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } - - trsf = trsf * trsf2; // TODO: I think it's fine, but maybe should it be the other way around? - -// std::cout << "trsf (after multiplication)" << std::endl; -// for (int i = 0; i < 3; ++i) { -// for (int j = 0; j < 4; ++j) { -// std::cout << trsf.cartesian(i, j) << " "; -// } std::cout << std::endl; -// } + if (!polyhedron.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!"); + // std::ofstream fresult; + // fresult.open("/Users/ken/Desktop/invalid.off"); + // fresult << polyhedron << std::endl; + // fresult.close(); + return CGAL::Polyhedron_3(); + } if (polyhedron.is_closed()) { + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); } - if ( current->hasPlacementRelTo() ) { - IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); - if ( relto->as() ) - current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); - else break; - } else break; } -// CACHE(IfcObjectPlacement,l,trsf) - return true; + + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + return polyhedron; } -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); - return false; +CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { + if (nef_polyhedron.is_simple()) { + try { + CGAL::Polyhedron_3 polyhedron; + nef_polyhedron.convert_to_polyhedron(polyhedron); + return polyhedron; + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!"); + return CGAL::Polyhedron_3(); + } + } else { + Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!"); + return CGAL::Polyhedron_3(); } - - 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; } + +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(std::list &face_list) { + CGAL::Polyhedron_3 polyhedron = create_polyhedron(face_list); + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); + return nef_polyhedron; + } return nef_polyhedron; +} + +CGAL::Nef_polyhedron_3 IfcGeom::CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron) { + if (polyhedron.is_valid()) { + CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron); + CGAL::Nef_polyhedron_3 nef_polyhedron; + try { + nef_polyhedron = CGAL::Nef_polyhedron_3(polyhedron); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!"); + return nef_polyhedron; + } return nef_polyhedron; + } else { + Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!"); + return CGAL::Nef_polyhedron_3(); + } +} + +//CGAL::Polyhedron_3 IfcGeom::CgalKernel::triangulate_faces(CGAL::Polyhedron_3 &polyhedron) { +// std::list face_list; +// +// for (CGAL::Polyhedron_3::Facet_const_iterator current_facet = polyhedron.facets_begin(); +// current_facet != polyhedron.facets_end(); +// ++current_facet) { +// +// // Triangle +// if (current_facet->is_triangle()) { +// face_list.push_back(cgal_face_t()); +// CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = current_facet->facet_begin(); +// do { +// face_list.back().outer.push_back(current_halfedge->vertex()->point()); +// ++current_halfedge; +// } while (current_halfedge != current_facet->facet_begin()); +// } +// +// // Polygon +// else { +// std::list points_in_polygon; +// +// } +// } +// +// return create_polyhedron(face_list); +//} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index 9f9a01684e..26d5f819c1 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -17,27 +17,28 @@ * * ********************************************************************************/ +#include "../../../ifcgeom/IfcGeomShapeType.h" +#include "../../../ifcgeom/IfcGeom.h" + #include "CgalKernel.h" +#include "CgalConversionResult.h" -#define CgalKernel MAKE_TYPE_NAME(CgalKernel) - -// @todo two distinct uses of the word Kernel is getting confusing -typedef Kernel Kernel_; - +using namespace IfcSchema; using namespace IfcUtil; + bool IfcGeom::CgalKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) { if (shape_type(l) != ST_SHAPELIST) { cgal_shape_t shp; if (convert_shape(l, shp)) { - r.push_back(IfcGeom::ConversionResult(l->data().id(), new CgalShape(shp))); + r.push_back(IfcGeom::ConversionResult(new CgalShape(shp), get_style(l->as()))); return true; } return false; } #include "CgalEntityMappingShapes.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:", l); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } @@ -47,7 +48,7 @@ IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) { } bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) { - const unsigned int id = l->data().id(); + const unsigned int id = l->entity->id(); bool success = false; bool processed = false; bool ignored = false; @@ -75,186 +76,25 @@ bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) const char* const msg = processed ? "Failed to convert:" : "No operation defined for:"; - Logger::Message(Logger::LOG_ERROR, msg, l); + Logger::Message(Logger::LOG_ERROR, msg, l->entity); } 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->as()) { - voids = l->as()->Voids(); - } -#ifdef USE_IFC4 - if (l->as()) { - 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(l->data().id(), 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); - 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); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } bool IfcGeom::CgalKernel::convert_face(const IfcBaseClass* l, cgal_face_t& r) { #include "CgalEntityMappingFace.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:", l); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); 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->as()) num_outer_bounds ++; - } - - if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l); - 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->as(); - - cgal_wire_t wire; - if (!convert_wire(loop, wire)) { - Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop); - 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); - 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); - } - - if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); - 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); + Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 6cb7f60437..51874f1550 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -27,23 +27,95 @@ #include "../../../ifcparse/IfcParse.h" +SHAPES(IfcShellBasedSurfaceModel); +SHAPES(IfcFaceBasedSurfaceModel); SHAPES(IfcRepresentation); +SHAPES(IfcMappedItem); // IfcFacetedBrep included // IfcAdvancedBrep included // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); +SHAPES(IfcGeometricSet); +#ifdef USE_IFC4 +//SHAPE(IfcCylindricalSurface); +//SHAPE(IfcAdvancedBrep); +//SHAPE(IfcBSplineSurfaceWithKnots); +SHAPE(IfcTriangulatedFaceSet); +SHAPE(IfcExtrudedAreaSolidTapered); +#endif +//SHAPE(IfcPlane); SHAPE(IfcExtrudedAreaSolid); +//SHAPE(IfcRevolvedAreaSolid); SHAPE(IfcConnectedFaceSet); +SHAPE(IfcBooleanResult); +//SHAPE(IfcPolygonalBoundedHalfSpace); +SHAPE(IfcHalfSpaceSolid); +//SHAPE(IfcSurfaceOfLinearExtrusion); +//SHAPE(IfcSurfaceOfRevolution); +SHAPE(IfcBlock); +SHAPE(IfcRectangularPyramid); +SHAPE(IfcRightCircularCylinder); +SHAPE(IfcRightCircularCone); +SHAPE(IfcSphere); +SHAPE(IfcCsgSolid); +//SHAPE(IfcCurveBoundedPlane); +//SHAPE(IfcRectangularTrimmedSurface); +//SHAPE(IfcSurfaceCurveSweptAreaSolid); +//SHAPE(IfcSweptDiskSolid); -FACE(IfcFace); +FACE(IfcArbitraryProfileDefWithVoids); +FACE(IfcArbitraryClosedProfileDef); +FACE(IfcRoundedRectangleProfileDef); +FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); +FACE(IfcTrapeziumProfileDef) +FACE(IfcCShapeProfileDef); +// IfcAsymmetricIShapeProfileDef included +FACE(IfcIShapeProfileDef); +FACE(IfcLShapeProfileDef); +FACE(IfcTShapeProfileDef); +FACE(IfcUShapeProfileDef); +FACE(IfcZShapeProfileDef); +FACE(IfcCircleHollowProfileDef); +FACE(IfcCircleProfileDef); +FACE(IfcEllipseProfileDef); +//FACE(IfcCenterLineProfileDef); +//FACE(IfcCompositeProfileDef); +FACE(IfcDerivedProfileDef); +// IfcFaceSurface included +// IfcAdvancedFace included in case of IFC4 +FACE(IfcFace); +//WIRE(IfcEdgeCurve); +//WIRE(IfcSubedge); +WIRE(IfcOrientedEdge); +WIRE(IfcEdge); +WIRE(IfcEdgeLoop); +WIRE(IfcPolyline); WIRE(IfcPolyLoop); +WIRE(IfcCompositeCurve); +WIRE(IfcTrimmedCurve); +//WIRE(IfcArbitraryOpenProfileDef); + +CURVE(IfcCircle); +CURVE(IfcEllipse); +CURVE(IfcLine); +#ifdef USE_IFC4 +// IfcRationalBSplineCurveWithKnots included +//CURVE(IfcBSplineCurveWithKnots); +#endif CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); +CLASS(IfcAxis1Placement,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator2DnonUniform,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator2D,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); +CLASS(IfcVector,cgal_vector_t); +CLASS(IfcPlane,cgal_plane_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp new file mode 100644 index 0000000000..536bc74b66 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp @@ -0,0 +1,75 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircle* l, cgal_curve_t& curve) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + if ( r < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity); + return false; + } + cgal_placement_t trsf; + IfcSchema::IfcAxis2Placement* placement = l->Position(); + if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + cgal_placement_t trsf2d; + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d); + trsf = trsf2d; + } + + const int segments = 12; + + curve = cgal_curve_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + curve.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + for (auto &vertex: curve) { + vertex = vertex.transform(trsf); + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipse* l, cgal_curve_t& curve) { + double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); + if (x < ALMOST_ZERO || y < ALMOST_ZERO) { + Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity); + return false; + } + cgal_placement_t trsf; + IfcSchema::IfcAxis2Placement* placement = l->Position(); + if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + cgal_placement_t trsf2d; + convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d); + trsf = trsf2d; + } + + const int segments = 12; + + curve = cgal_curve_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + curve.push_back(Kernel::Point_3(x*cos(current_angle), y*sin(current_angle), 0)); + } + + for (auto &vertex: curve) { + vertex = vertex.transform(trsf); + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLine* l, cgal_curve_t& curve) { + cgal_point_t pnt; + cgal_direction_t vec; + convert(l->Pnt(),pnt); + convert(l->Dir(),vec); + curve = cgal_curve_t(); + curve.push_back(pnt); + curve.push_back(pnt+vec); + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp new file mode 100644 index 0000000000..e1a4383dc4 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -0,0 +1,988 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, cgal_face_t& face) { + cgal_wire_t wire; + if ( ! convert_wire(l->OuterCurve(),wire) ) return false; + + cgal_face_t f; + bool success = convert_wire_to_face(wire, f); + if (success) face = f; + return success; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* l, cgal_face_t& face) { + cgal_wire_t profile; + if ( ! convert_wire(l->OuterCurve(),profile) ) return false; + cgal_face_t mf; + mf.outer = profile; + IfcSchema::IfcCurve::list::ptr voids = l->InnerCurves(); + for( IfcSchema::IfcCurve::list::it it = voids->begin(); it != voids->end(); ++ it ) { + cgal_wire_t hole; + if ( convert_wire(*it,hole) ) { + mf.inner.push_back(hole); + } + } face = mf; + 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 + + 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)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* 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); + const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT); + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < 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 + + const int segments = 3; + + if (r == 0.0) { + 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)); + } + + else { + face = cgal_face_t(); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r+r*cos(current_angle), y-r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r+r*cos(current_angle), y-r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r+r*cos(current_angle), -y+r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r+r*cos(current_angle), -y+r+r*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* 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); + const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT); + + const bool fr1 = l->hasOuterFilletRadius(); + const bool fr2 = l->hasInnerFilletRadius(); + + const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.; + const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.; + + 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 + + const int segments = 3; + + if (!fr1 || r1 == 0.0) { + 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)); + } + + else { + face = cgal_face_t(); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0)); + } + } + + if (!fr2 || r2 == 0.0) { + face.inner.push_back(cgal_wire_t()); + face.inner.back().push_back(Kernel::Point_3(-x+d, -y+d, 0.0)); + face.inner.back().push_back(Kernel::Point_3( x-d, -y+d, 0.0)); + face.inner.back().push_back(Kernel::Point_3( x-d, y-d, 0.0)); + face.inner.back().push_back(Kernel::Point_3(-x+d, y-d, 0.0)); + } + + else { + face.inner.push_back(cgal_wire_t()); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(x-d-r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(-x+d+r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(-x+d+r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(x-d-r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } for (auto &inner: face.inner) { + for (auto &vertex: inner) { + vertex = vertex.transform(trsf2d); + } + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cgal_face_t& face) { + const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT); + const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT); + const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT); + const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); + + if ( x1 < ALMOST_ZERO || w < 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 + + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(dx+w-x1, y, 0.0)); + face.outer.push_back(Kernel::Point_3(dx-x1, y, 0.0)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_face_t& face) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + if ( r == 0.0f ) { + 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 + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, cgal_face_t& face) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT); + + if ( r == 0.0f || t == 0.0f ) { + 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 + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + face.inner.push_back(cgal_wire_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3((r-t)*cos(current_angle), (r-t)*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } for (auto &inner: face.inner) { + for (auto &vertex: inner) { + vertex = vertex.transform(trsf2d); + } + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal_face_t& face) { + double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); + + if ( rx < ALMOST_ZERO || ry < 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 + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(rx*cos(current_angle), ry*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + 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; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_face_t& face) { + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT); + const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT); + bool doFillet = l->hasInternalFilletRadius(); + double f1 = 0; + double f2 = 0; + if ( doFillet ) { + f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT); + f2 = f1 + d1; + } + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < 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 + + const int segments = 3; + + if (!doFillet || f1 == 0.0) { + 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+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d1, 0.0)); + face.outer.push_back(Kernel::Point_3(-x+d1, -y+d1, 0.0)); + face.outer.push_back(Kernel::Point_3(-x+d1, y-d1, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, y-d1, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, y-d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x, y-d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + } + + else { + face = cgal_face_t(); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); + } + face.outer.push_back(Kernel::Point_3(x, -y+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d2, 0.0)); + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0)); + } + face.outer.push_back(Kernel::Point_3(x-d1, y-d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x, y-d2, 0.0)); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcLShapeProfileDef* l, cgal_face_t& face) { + const bool hasSlope = l->hasLegSlope(); + const bool doEdgeFillet = l->hasEdgeRadius(); + const bool doFillet = l->hasFilletRadius(); + + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT); + const double d = l->Thickness() * getValue(GV_LENGTH_UNIT); + const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; + + double f1 = 0.0f; + double f2 = 0.0f; + if (doFillet) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + if ( doEdgeFillet) { + f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT); + } + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + double xx = -x+d; + double xy = -y+d; + double dy1 = 0.; + double dy2 = 0.; + double dx1 = 0.; + double dx2 = 0.; + if (hasSlope) { + dy1 = tan(slope) * x; + dy2 = tan(slope) * (x - d); + dx1 = tan(slope) * y; + dx2 = tan(slope) * (y - d); + + const double x1s = x; const double y1s = -y + d - dy1; + const double x1e = -x + d; const double y1e = -y + d + dy2; + const double x2s = -x + d - dx1; const double y2s = y; + const double x2e = -x + d + dx2; const double y2e = -y + d; + + const double a1 = y1e - y1s; + const double b1 = x1s - x1e; + const double c1 = a1*x1s + b1*y1s; + + const double a2 = y2e - y2s; + const double b2 = x2s - x2e; + const double c2 = a2*x2s + b2*y2s; + + const double det = a1*b2 - a2*b1; + + if (ALMOST_THE_SAME(det, 0.)) { + Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity); + return false; + } + + xx = (b2*c1 - b1*c2) / det; + xy = (a1*c2 - a2*c1) / det; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 3; + + 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)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(x, -y+d-dy1, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+d-dy1-f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(xx, xy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(xx+f1+f1*cos(current_angle), xy+f1+f1*sin(current_angle), 0)); + } + } if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x+d-dx1, y, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+d-dx1-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +// TODO: Untested +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_face_t& face) { + const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT); + const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT); + + bool doFillet1 = l->hasFilletRadius(); + double f1 = 0.; + if ( doFillet1 ) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + + bool doFillet2 = doFillet1; + double x2 = x1, dy2 = dy1, f2 = f1; + + if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) { + IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l; + x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT); + doFillet2 = assym->hasTopFlangeFilletRadius(); + if (doFillet2) { + f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT); + } + if (assym->hasTopFlangeThickness()) { + dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT); + } + } + + if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < 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 + + const int segments = 3; + + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(x1, -y+dy1, 0.0)); + if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(d1, -y+dy1, 0.0)); + face.outer.push_back(Kernel::Point_3(d1, y-dy2, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(d1+f1+f1*cos(current_angle), -y+dy1+f1+f1*sin(current_angle), 0)); + } for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(d1+f1+f1*cos(current_angle), y-dy2-f1+f1*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(x2, y-dy2, 0.0)); + face.outer.push_back(Kernel::Point_3(x2, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x2, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x2, y-dy2, 0.0)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-d1, y-dy2, 0.0)); + face.outer.push_back(Kernel::Point_3(-d1, -y+dy1, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-d1-f2+f2*cos(current_angle), y-dy2-f2+f2*sin(current_angle), 0)); + } for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-d1-f2+f2*cos(current_angle), -y+dy1+f2+f2*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(-x1, -y+dy1, 0.0)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTShapeProfileDef* l, cgal_face_t& face) { + const bool doFlangeEdgeFillet = l->hasFlangeEdgeRadius(); + const bool doWebEdgeFillet = l->hasWebEdgeRadius(); + const bool doFillet = l->hasFilletRadius(); + const bool hasFlangeSlope = l->hasFlangeSlope(); + const bool hasWebSlope = l->hasWebSlope(); + + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT); + const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT); + const double flangeSlope = hasFlangeSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; + const double webSlope = hasWebSlope ? (l->WebSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + double dy1 = 0.0f; + double dy2 = 0.0f; + double dx1 = 0.0f; + double dx2 = 0.0f; + double f1 = 0.0f; + double f2 = 0.0f; + double f3 = 0.0f; + + if (doFillet) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + if (doWebEdgeFillet) { + f2 = l->WebEdgeRadius() * getValue(GV_LENGTH_UNIT); + } + if (doFlangeEdgeFillet) { + f3 = l->FlangeEdgeRadius() * getValue(GV_LENGTH_UNIT); + } + + double xx, xy; + if (hasFlangeSlope) { + dy1 = (x / 2. - d1) * tan(flangeSlope); + dy2 = x / 2. * tan(flangeSlope); + } + if (hasWebSlope) { + dx1 = (y - d2) * tan(webSlope); + dx2 = y * tan(webSlope); + } + if (hasWebSlope || hasFlangeSlope) { + const double x1s = d1/2. - dx2; const double y1s = -y; + const double x1e = d1/2. + dx1; const double y1e = y - d2; + const double x2s = x; const double y2s = y - d2 + dy2; + const double x2e = d1/2.; const double y2e = y - d2 - dy1; + + const double a1 = y1e - y1s; + const double b1 = x1s - x1e; + const double c1 = a1*x1s + b1*y1s; + + const double a2 = y2e - y2s; + const double b2 = x2s - x2e; + const double c2 = a2*x2s + b2*y2s; + + const double det = a1*b2 - a2*b1; + + if (ALMOST_THE_SAME(det, 0.)) { + Logger::Message(Logger::LOG_NOTICE, "Web and flange do not intersect for:",l->entity); + return false; + } + + xx = (b2*c1 - b1*c2) / det; + xy = (a1*c2 - a2*c1) / det; + } else { + xx = d1 / 2; + xy = y - d2; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 3; + + face = cgal_face_t(); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(d1/2.-dx2, -y, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(d1/2.-dx2-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(xx, xy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(xx+f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0)); + } + } if (f3 == 0.0) { + face.outer.push_back(Kernel::Point_3(x, y-d2+dy2, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(x, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + if (f3 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x, y-d2+dy2, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f3+f3*cos(current_angle), y-d2+dy2+f3+f3*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(-xx, xy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-xx-f1+f1*cos(current_angle), xy-f1+f1*sin(current_angle), 0)); + } + } if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-d1/2.+dx2, -y, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-d1/2.+dx2+f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcUShapeProfileDef* l, cgal_face_t& face) { + const bool doEdgeFillet = l->hasEdgeRadius(); + const bool doFillet = l->hasFilletRadius(); + const bool hasSlope = l->hasFlangeSlope(); + + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = l->FlangeWidth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WebThickness() * getValue(GV_LENGTH_UNIT); + const double d2 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT); + const double slope = hasSlope ? (l->FlangeSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; + + double dy1 = 0.0f; + double dy2 = 0.0f; + double f1 = 0.0f; + double f2 = 0.0f; + + if (doFillet) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + if (doEdgeFillet) { + f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT); + } + + if (hasSlope) { + dy1 = (x - d1) * tan(slope); + dy2 = x * tan(slope); + } + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < 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 + + const int segments = 3; + + 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)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(x, -y+d2-dy2, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+d2-dy2-f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x+d1, -y+d2+dy1, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+d1+f1+f1*cos(current_angle), -y+d2+dy1+f1+f1*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x+d1, y-d2-dy1, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+d1+f1+f1*cos(current_angle), y-d2-dy1-f1+f1*sin(current_angle), 0)); + } + } if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(x,y-d2+dy2, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), y-d2+dy2+f2+f2*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(x,y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x,y, 0.0)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcZShapeProfileDef* l, cgal_face_t& face) { + const double x = l->FlangeWidth() * getValue(GV_LENGTH_UNIT); + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double dx = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT); + const double dy = l->FlangeThickness() * getValue(GV_LENGTH_UNIT); + + bool doFillet = l->hasFilletRadius(); + bool doEdgeFillet = l->hasEdgeRadius(); + + double f1 = 0.; + double f2 = 0.; + + if ( doFillet ) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + if ( doEdgeFillet ) { + f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT); + } + + if ( x == 0.0f || y == 0.0f || dx == 0.0f || dy == 0.0f ) { + 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 + + const int segments = 3; + + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-dx, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(x, -y, 0.0)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(x, -y+dy, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f2*cos(current_angle), -y+dy-f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(dx, -y+dy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(dx+f1+f1*cos(current_angle), -y+dy+f1+f1*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(dx, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x, y-dy, 0.0)); + } else { + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f2*cos(current_angle), y-dy+f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(-dx, y-dy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-dx-f1+f1*cos(current_angle), y-dy-f1+f1*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDerivedProfileDef* l, cgal_face_t& face) { + cgal_face_t f; + cgal_placement_t trsf2d; + if (convert_face(l->ParentProfile(), f) && IfcGeom::CgalKernel::convert(l->Operator(), trsf2d)) { + cgal_placement_t trsf = trsf2d; + for (auto &vertex: f.outer) vertex = vertex.transform(trsf); + for (auto &ring: f.inner) { + for (auto &vertex: ring) vertex = vertex.transform(trsf); + } face = f; + return true; + } else { + return false; + } +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp new file mode 100644 index 0000000000..f91617f8f3 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp @@ -0,0 +1,320 @@ +#include "CgalKernel.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { + std::vector xyz = l->Coordinates(); + point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, + xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f, + xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f); + // std::cout << "Converted Point(" << point << ")" << std::endl; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_direction_t& dir) { + // IN_CACHE(IfcDirection,l,cgal_direction_t,dir) + std::vector xyz = l->DirectionRatios(); + dir = Kernel::Vector_3(xyz.size() ? xyz[0] : 0.0f, + xyz.size() > 1 ? xyz[1] : 0.0f, + xyz.size() > 2 ? xyz[2] : 0.0f); + // CACHE(IfcDirection,l,dir) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcVector* l, cgal_vector_t& v) { + // IN_CACHE(IfcVector,l,cgal_vector_t,v) + cgal_direction_t d; + IfcGeom::CgalKernel::convert(l->Orientation(),d); + v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d; + // CACHE(IfcVector,l,v) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& plane) { + // IN_CACHE(IfcPlane,pln,gp_Pln,plane) + IfcSchema::IfcAxis2Placement3D* l = pln->Position(); + cgal_point_t o; + cgal_direction_t axis = Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); + IfcGeom::CgalKernel::convert(l->Location(),o); + bool hasRef = l->hasRefDirection(); + if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); + if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); + Kernel::Vector_3 x = CGAL::cross_product(y, axis); + + cgal_plane_t ax3; + if ( hasRef ) ax3 = Kernel::Plane_3(o,o+x,o+y); + else ax3 = Kernel::Plane_3(o,axis); + plane = ax3; + + // std::cout << "IfcPlane C = " << o << std::endl; + // std::cout << "IfcPlane z (axis, exact) = " << axis << std::endl; + // std::cout << "IfcPlane x (refDirection, approximate) = " << refDirection << std::endl; + // std::cout << "IfcPlane y (computed, exact) = " << y << std::endl; + // std::cout << "IfcPlane x (computed, exact) = " << x << std::endl; + // + // std::cout << "Plane_3 o = " << o << std::endl; + // std::cout << "Plane_3 o+x = " << o+x << std::endl; + // std::cout << "Plane_3 o+y = " << o+y << std::endl; + + // ax + by + cz + d = 0 + // std::cout << "Plane: a = " << plane.a() << ", b = " << plane.b() << ", c = " << plane.c() << ", d = " << plane.d() << std::endl; + + // std::ofstream fresult; + // fresult.open("/Users/ken/Desktop/plane.obj"); + // // x = -5, y = -5, z = (5a +5b -d)/c + // fresult << "v -5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; + // // x = -5, y = +5, z = (5a -5b -d)/c + // fresult << "v -5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; + // // x = 5, y = -5, z = (-5a +5b -d)/c + // fresult << "v 5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; + // // x = 5, y = +5, z = (-5a -5b -d)/c + // fresult << "v 5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; + // fresult << "f 1 2 3" << std::endl; + // fresult << "f 4 3 2" << std::endl; + // fresult.close(); + + // CACHE(IfcPlane,pln,plane) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) + cgal_point_t o; + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); + IfcGeom::CgalKernel::convert(l->Location(),o); + bool hasRef = l->hasRefDirection(); + if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + cgal_direction_t y = Kernel::Vector_3(-refDirection.y(), refDirection.x(), 0.0); + + const double tolerance = 0.01; + if (refDirection.squared_length() < 1.0-tolerance || refDirection.squared_length() > 1.0+tolerance || + y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance) { + std::cout << "Ref direction (x): " << refDirection << " squared length: " << refDirection.squared_length() << std::endl; + std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl; + std::cout << "Origin: " << o << std::endl; + } + + // TODO: Should be checked. + trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), + refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1), + 0.0, 0.0, 1.0, 0.0); + + // CACHE(IfcAxis2Placement3D,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) + cgal_point_t o; + cgal_direction_t axis = Kernel::Vector_3(0,0,1); + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); + IfcGeom::CgalKernel::convert(l->Location(),o); + bool hasRef = l->hasRefDirection(); + if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); + if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); + Kernel::Vector_3 y = CGAL::cross_product(axis, refDirection); + Kernel::Vector_3 x = CGAL::cross_product(y, axis); + + const double tolerance = 0.01; + if (x.squared_length() < 1.0-tolerance || x.squared_length() > 1.0+tolerance || + y.squared_length() < 1.0-tolerance || y.squared_length() > 1.0+tolerance || + axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) { + std::cout << "Ref direction: " << refDirection << " squared length: " << refDirection.squared_length() << std::endl; + std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl; + std::cout << "y: " << y << " squared length: " << y.squared_length() << std::endl; + std::cout << "x: " << x << " squared length: " << x.squared_length() << std::endl; + std::cout << "Origin: " << o << std::endl; + } + + // TODO: Should be checked. + trsf = Kernel::Aff_transformation_3(x.cartesian(0), y.cartesian(0), axis.cartesian(0), o.cartesian(0), + x.cartesian(1), y.cartesian(1), axis.cartesian(1), o.cartesian(1), + x.cartesian(2), y.cartesian(2), axis.cartesian(2), o.cartesian(2)); + + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << trsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + // CACHE(IfcAxis2Placement3D,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis1Placement* l, cgal_placement_t& ax) { +// IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax) + cgal_point_t o; + cgal_direction_t axis = Kernel::Vector_3(0,0,1); + IfcGeom::CgalKernel::convert(l->Location(),o); + if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(), axis); + + const double tolerance = 0.01; + if (axis.squared_length() < 1.0-tolerance || axis.squared_length() > 1.0+tolerance) { + std::cout << "Axis (z): " << axis << " squared length: " << axis.squared_length() << std::endl; + std::cout << "Origin: " << o << std::endl; + } + + // TODO: Should be checked. + ax = Kernel::Aff_transformation_3(1.0, 0.0, axis.cartesian(0), o.cartesian(0), + 0.0, 1.0, axis.cartesian(1), o.cartesian(1), + 0.0, 0.0, axis.cartesian(2), o.cartesian(2)); + +// CACHE(IfcAxis1Placement,l,ax) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcObjectPlacement,l,cgal_placement_t,trsf) + if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + return false; + } + + // std::cout << "initial trsf (identity?)" << std::endl; + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << trsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l; + for (;;) { + cgal_placement_t trsf2; + + IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); + if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); + + // std::cout << "trsf2" << std::endl; + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << trsf2.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + trsf = trsf2 * trsf; + + // std::cout << "trsf (after multiplication)" << std::endl; + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << trsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + } + if ( current->hasPlacementRelTo() ) { + IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); + if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) + current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); + else break; + } else break; + } + // CACHE(IfcObjectPlacement,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcCartesianTransformationOperator2D,l,cgal_placement_t,trsf) + + cgal_point_t origin; + cgal_direction_t axis1 (1.,0.,0.); + cgal_direction_t axis2 (0.,1.,0.); + + IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin); + if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2); + double scale = 1.0; + if (l->hasScale()) { + scale = l->Scale(); + } + + // TODO: Untested + trsf = Kernel::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0), + axis1.cartesian(1), scale*axis2.cartesian(1), 0.0, origin.cartesian(1), + 0.0, 0.0, 1.0, 0.0); + + // CACHE(IfcCartesianTransformationOperator2D,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,cgal_placement_t,gtrsf) + + cgal_point_t origin; + cgal_direction_t axis1 (1.,0.,0.); + cgal_direction_t axis2 (0.,1.,0.); + + IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin); + if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2); + + const double scale1 = l->hasScale() ? l->Scale() : 1.0f; + const double scale2 = l->hasScale2() ? l->Scale2() : scale1; + + // TODO: Untested + trsf = Kernel::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), 0.0, origin.cartesian(0), + axis1.cartesian(1), scale2*axis2.cartesian(1), 0.0, origin.cartesian(1), + 0.0, 0.0, 1.0, 0.0); + + // CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, cgal_placement_t& trsf) { + // IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf) + cgal_point_t origin; + IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin); + cgal_direction_t axis1 (1.,0.,0.); + cgal_direction_t axis2 (0.,1.,0.); + cgal_direction_t axis3 (0.,0.,1.); + if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2); + if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3); + double scale = 1.0; + if (l->hasScale()) { + scale = l->Scale(); + } + + // TODO: Untested + trsf = Kernel::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0), + axis1.cartesian(1), scale*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1), + axis1.cartesian(2), axis2.cartesian(2), scale*axis3.cartesian(2), origin.cartesian(2)); + + // std::cout << std::endl; + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << trsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + // CACHE(IfcCartesianTransformationOperator3D,l,trsf) + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, cgal_placement_t& gtrsf) { + // IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf) + cgal_point_t origin; + IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin); + cgal_direction_t axis1 (1.,0.,0.); + cgal_direction_t axis2 (0.,1.,0.); + cgal_direction_t axis3 (0.,0.,1.); + if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2); + if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3); + const double scale1 = l->hasScale() ? l->Scale() : 1.0f; + const double scale2 = l->hasScale2() ? l->Scale2() : scale1; + const double scale3 = l->hasScale3() ? l->Scale3() : scale1; + + // TODO: Untested + gtrsf = Kernel::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0), + axis1.cartesian(1), scale2*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1), + axis1.cartesian(2), axis2.cartesian(2), scale3*axis3.cartesian(2), origin.cartesian(2)); + + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << gtrsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + // CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf) + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp new file mode 100644 index 0000000000..f6af7fc884 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -0,0 +1,916 @@ +#include "CgalKernel.h" + +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; + } + + // Outer + cgal_face_t bottom_face; + if ( !convert_face(l->SweptArea(),bottom_face) ) return false; +// std::cout << "Face vertices: " << face.outer.size() << std::endl; + + 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(bottom_face); + + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == bottom_face.outer.end()) { + next_vertex = bottom_face.outer.begin(); + } cgal_face_t side_face; + side_face.outer.push_back(*next_vertex); + side_face.outer.push_back(*current_vertex); + side_face.outer.push_back(*current_vertex+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 = bottom_face.outer.rbegin(); + vertex != bottom_face.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex+height*dir); + } face_list.push_back(top_face); + + if (bottom_face.inner.empty()) { + shape = create_polyhedron(face_list); + if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; + } + + CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); + + // Inner + // TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction + for (auto &inner: bottom_face.inner) { +// std::cout << "Inner wire" << std::endl; + face_list.clear(); + + cgal_face_t hole_bottom_face; + hole_bottom_face.outer = inner; + remove_duplicate_points_from_loop(hole_bottom_face.outer); + face_list.push_back(hole_bottom_face); + + for (std::vector::const_iterator current_vertex = inner.begin(); + current_vertex != inner.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == inner.end()) { + next_vertex = inner.begin(); + } cgal_face_t hole_side_face; + hole_side_face.outer.push_back(*next_vertex); + hole_side_face.outer.push_back(*current_vertex); + hole_side_face.outer.push_back(*current_vertex+height*dir); + hole_side_face.outer.push_back(*next_vertex+height*dir); + face_list.push_back(hole_side_face); + } + + cgal_face_t hole_top_face; + for (std::vector::const_reverse_iterator vertex = inner.rbegin(); + vertex != inner.rend(); + ++vertex) { + hole_top_face.outer.push_back(*vertex+height*dir); + } face_list.push_back(hole_top_face); + + try { + nef_shape -= create_nef_polyhedron(face_list); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", l->entity); + return false; + } + } + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", l->entity); + return false; + } + +} + +#ifdef USE_IFC4 +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* 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 face1, face2; + if (!convert_face(l->SweptArea(), face1)) return false; + if (!convert_face(l->EndSweptArea(), face2)) 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); + + for (auto &vertex: face2.outer) vertex = vertex + height*dir; + for (auto &ring: face2.inner) { + for (auto &vertex: ring) vertex = vertex + height*dir; + } + + // Outer + std::list face_list; + face_list.push_back(face1); + + std::vector::const_iterator current_face1_vertex = face1.outer.begin(); + std::vector::const_iterator current_face2_vertex = face2.outer.begin(); + while (current_face1_vertex != face1.outer.end() && + current_face2_vertex != face2.outer.end()) { + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::const_iterator next_face2_vertex = current_face2_vertex; + ++next_face1_vertex; + ++next_face2_vertex; + if (next_face1_vertex == face1.outer.end()) next_face1_vertex = face1.outer.begin(); + if (next_face2_vertex == face2.outer.end()) next_face2_vertex = face2.outer.begin(); + cgal_face_t side_face; + side_face.outer.push_back(*next_face1_vertex); + side_face.outer.push_back(*current_face1_vertex); + side_face.outer.push_back(*current_face2_vertex); + side_face.outer.push_back(*next_face2_vertex); + face_list.push_back(side_face); + ++current_face1_vertex; + ++current_face2_vertex; + } + + cgal_face_t top_face; + for (std::vector::const_reverse_iterator vertex = face2.outer.rbegin(); + vertex != face2.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex); + } face_list.push_back(top_face); + + if (face1.inner.empty() || face2.inner.empty()) { + shape = create_polyhedron(face_list); + if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; + } + +// std::ofstream f1; +// CGAL::Polyhedron_3 outer_polyhedron; +// PolyhedronBuilder builder(&face_list); +// outer_polyhedron.delegate(builder); +// f1.open("/Users/ken/Desktop/outer.off"); +// f1 << outer_polyhedron << std::endl; +// f1.close(); + + CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); + + // Inner + // TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction + std::vector::iterator inner_face1 = face1.inner.begin(); + std::vector::iterator inner_face2 = face2.inner.begin(); + while (inner_face1 != face1.inner.end() && + inner_face2 != face2.inner.end()) { + face_list.clear(); + + cgal_face_t hole_face1; + hole_face1.outer = *inner_face1; + remove_duplicate_points_from_loop(hole_face1.outer); + face_list.push_back(hole_face1); + + cgal_face_t hole_face2; + hole_face2.outer = *inner_face2; + remove_duplicate_points_from_loop(hole_face2.outer); + + current_face1_vertex = hole_face1.outer.begin(); + current_face2_vertex = hole_face2.outer.begin(); + while (current_face1_vertex != hole_face1.outer.end() && + current_face2_vertex != hole_face2.outer.end()) { + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::const_iterator next_face2_vertex = current_face2_vertex; + ++next_face1_vertex; + ++next_face2_vertex; + if (next_face1_vertex == hole_face1.outer.end()) next_face1_vertex = hole_face1.outer.begin(); + if (next_face2_vertex == hole_face2.outer.end()) next_face2_vertex = hole_face2.outer.begin(); + cgal_face_t side_face; + side_face.outer.push_back(*next_face1_vertex); + side_face.outer.push_back(*current_face1_vertex); + side_face.outer.push_back(*current_face2_vertex); + side_face.outer.push_back(*next_face2_vertex); + face_list.push_back(side_face); + ++current_face1_vertex; + ++current_face2_vertex; + } + + cgal_face_t top_hole_face; + for (std::vector::const_reverse_iterator vertex = hole_face2.outer.rbegin(); + vertex != hole_face2.outer.rend(); + ++vertex) { + top_hole_face.outer.push_back(*vertex); + } face_list.push_back(top_hole_face); + +// std::ofstream f2; +// CGAL::Polyhedron_3 inner_polyhedron; +// PolyhedronBuilder builder(&face_list); +// inner_polyhedron.delegate(builder); +// f2.open("/Users/ken/Desktop/inner.off"); +// f2 << inner_polyhedron << std::endl; +// f2.close(); + + try { + nef_shape -= create_nef_polyhedron(face_list); + } catch (...) { + std::cout << "IfcExtrudedAreaSolidTapered: cannot subtract opening for:" << std::endl; + return false; + } + + ++inner_face1; + ++inner_face2; + } + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcExtrudedAreaSolidTapered: cannot convert Nef to polyhedron!" << std::endl; + return false; + } +} +#endif + +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); + } + + shape = create_polyhedron(face_list); + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCsgSolid* l, cgal_shape_t& shape) { + return convert_shape(l->TreeRootExpression(), shape); +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // x = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + + // x = dx + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + + // y = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + + // y = dy + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + + // z = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // z = dz + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_shape_t& shape) { + + cgal_shape_t s1, s2; + ConversionResults items1, items2; + cgal_wire_t boundary_wire; + IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); + IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); + bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); + + if ( shape_type(operand1) == ST_SHAPELIST ) { + Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1->entity); +// if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { + return false; +// } + } else if ( shape_type(operand1) == ST_SHAPE ) { + if (!convert_shape(operand1, s1) ) { + return false; + } + } else { + Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); + return false; + } + +// const double first_operand_volume = shape_volume(s1); +// if ( first_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); + + bool shape2_processed = false; + if ( shape_type(operand2) == ST_SHAPELIST ) { + Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1->entity); +// shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); + } else if ( shape_type(operand2) == ST_SHAPE ) { + shape2_processed = convert_shape(operand2,s2); + } else { + Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2->entity); + } + + if (!shape2_processed) { + shape = s1; + Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); + return true; + } + +// if (!is_halfspace) { +// const double second_operand_volume = shape_volume(s2); +// if ( second_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); +// } + + const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + + if (!s1.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "s1: Not valid?", operand1->entity); + return false; + } else { +// std::ofstream f1; +// CGAL::Polyhedron_3 p1; +// s1.convert_to_Polyhedron(p1); +// f1.open("/Users/ken/Desktop/s1.off"); +// f1 << p1 << std::endl; +// f1.close(); + } + + bool is_plane = false; + cgal_plane_t plane; + if (!s2.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "s2: Not valid?", operand2->entity); + return false; + } else if (is_halfspace) { + // std::cout << "s2: halfspace" << std::endl; + IfcSchema::IfcHalfSpaceSolid *hss = static_cast(operand2); + IfcSchema::IfcSurface* surface = hss->BaseSurface(); + if (surface->is(IfcSchema::Type::IfcPlane) ) { + is_plane = true; + IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane *)surface, plane); + if (hss->AgreementFlag()) plane = plane.opposite(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/s2.off"); +// fresult << "OFF" << std::endl << "4 2 4" << std::endl; +// // x = -5, y = -5, z = (5a +5b -d)/c +// fresult << "-5 -5 " << (5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; +// // x = -5, y = +5, z = (5a -5b -d)/c +// fresult << "-5 5 " << (5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; +// // x = 5, y = -5, z = (-5a +5b -d)/c +// fresult << "5 -5 " << (-5.0*CGAL::to_double(plane.a())+5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; +// // x = 5, y = +5, z = (-5a -5b -d)/c +// fresult << "5 5 " << (-5.0*CGAL::to_double(plane.a())-5.0*CGAL::to_double(plane.b())-CGAL::to_double(plane.d()))/CGAL::to_double(plane.c()) << std::endl; +// fresult << "3 0 1 2" << std::endl; +// fresult << "3 3 2 1" << std::endl; +// fresult.close(); + } + } else { +// std::ofstream f2; +// CGAL::Polyhedron_3 p2; +// s2.convert_to_Polyhedron(p2); +// f2.open("/Users/ken/Desktop/s2.off"); +// f2 << p2 << std::endl; +// f2.close(); + } + + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + +// std::cout << "Difference" << std::endl; + CGAL::Nef_polyhedron_3 nef_result; + try { + nef_result = CGAL::Nef_polyhedron_3(s1); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "s1: cannot convert to Nef?", operand1->entity); + return false; + } if (is_halfspace) { + if (is_plane) nef_result = nef_result.intersection(plane, CGAL::Nef_polyhedron_3::Intersection_mode::CLOSED_HALFSPACE); + } else { + CGAL::Nef_polyhedron_3 nef_s2; + try { + nef_s2 = CGAL::Nef_polyhedron_3(s2); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "s2: cannot convert to Nef?", operand2->entity); + } nef_result -= nef_s2; + } + if (!nef_result.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s2: not simple?", operand2->entity); + return false; + } else { +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + +// std::cout << "Union" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)+CGAL::Nef_polyhedron_3(s2); + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } else { +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + +// std::cout << "Intersection" << std::endl; + CGAL::Nef_polyhedron_3 nef_result = CGAL::Nef_polyhedron_3(s1)*CGAL::Nef_polyhedron_3(s2); + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } else { +// CGAL::Polyhedron_3 result; +// nef_result.convert_to_polyhedron(result); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } + } return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + + // Make icosahedron + float golden_ratio = (1.0+sqrtf(5.0))/2.0; + float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0); + std::vector icosahedron_vertices; + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + + std::list face_list; + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + const unsigned int refinements = 2; + for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { + std::list refined_face_list; + for (auto &face: face_list) { + Kernel::Point_3 vertex0 = face.outer[0]; + Kernel::Point_3 vertex1 = face.outer[1]; + Kernel::Point_3 vertex2 = face.outer[2]; + + Kernel::Point_3 midpoint01 = CGAL::midpoint(vertex0, vertex1); + Kernel::Point_3 midpoint12 = CGAL::midpoint(vertex1, vertex2); + Kernel::Point_3 midpoint20 = CGAL::midpoint(vertex2, vertex0); + + double midpoint01_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint01, Kernel::Point_3(0, 0, 0)))); + midpoint01 = Kernel::Point_3(midpoint01.x()/midpoint01_distance_to_origin, + midpoint01.y()/midpoint01_distance_to_origin, + midpoint01.z()/midpoint01_distance_to_origin); + double midpoint12_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint12, Kernel::Point_3(0, 0, 0)))); + midpoint12 = Kernel::Point_3(midpoint12.x()/midpoint12_distance_to_origin, + midpoint12.y()/midpoint12_distance_to_origin, + midpoint12.z()/midpoint12_distance_to_origin); + double midpoint20_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint20, Kernel::Point_3(0, 0, 0)))); + midpoint20 = Kernel::Point_3(midpoint20.x()/midpoint20_distance_to_origin, + midpoint20.y()/midpoint20_distance_to_origin, + midpoint20.z()/midpoint20_distance_to_origin); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex0); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint20); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex1); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint01); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex2); + refined_face_list.back().outer.push_back(midpoint20); + refined_face_list.back().outer.push_back(midpoint12); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint20); + } face_list = refined_face_list; + } + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) { + vertex->point() = Kernel::Point_3(r*vertex->point().x(), + r*vertex->point().y(), + r*vertex->point().z()); + vertex->point() = vertex->point().transform(trsf); + } + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // Base + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // Lateral faces + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 12; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), h)); + } + + // Top + face_list.push_back(cgal_face_t()); + for (int current_segment = segments-1; current_segment >= 0; --current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + } + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal_shape_t& shape) { + const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 12; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, h)); + } + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + shape = create_polyhedron(face_list); + for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; +} + +#ifdef USE_IFC4 +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); + const std::vector< std::vector > coordinates = point_list->CoordList(); + std::vector points; + points.reserve(coordinates.size()); + for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { + const std::vector& coords = *it; + if (coords.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l->entity); + return false; + } + points.push_back(Kernel::Point_3(coords[0] * getValue(GV_LENGTH_UNIT), + coords[1] * getValue(GV_LENGTH_UNIT), + coords[2] * getValue(GV_LENGTH_UNIT))); + } + + std::vector< std::vector > indices = l->CoordIndex(); + + std::list face_list; + + for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { + const std::vector& tri = *it; + if (tri.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l->entity); + return false; + } + + const int min_index = *std::min_element(tri.begin(), tri.end()); + const int max_index = *std::max_element(tri.begin(), tri.end()); + + if (min_index < 1 || max_index > (int) points.size()) { + Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l->entity); + return false; + } + + const Kernel::Point_3& a = points[tri[0] - 1]; // account for zero- vs + const Kernel::Point_3& b = points[tri[1] - 1]; // one-based indices in + const Kernel::Point_3& c = points[tri[2] - 1]; // c++ and express + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(a); + face_list.back().outer.push_back(b); + face_list.back().outer.push_back(c); + } + + shape = create_polyhedron(face_list); + return true; +} +#endif + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) { + IfcSchema::IfcSurface* surface = l->BaseSurface(); + if ( ! surface->is(IfcSchema::Type::IfcPlane) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity); + return false; + } + cgal_plane_t pln; + IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln); + + // TODO: Don't fully understand the logic here. Might be incorrect. + if (l->AgreementFlag()) pln = pln.opposite(); +// const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); +// shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); + + // TODO: For now we do nothing and process halfspaces in IfcBooleanResult, which likely doesn't capture all cases. + // Find a better solution later (with an abstract shape class?) + shape = CGAL::Polyhedron_3(); + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp new file mode 100644 index 0000000000..c28d6ee8e2 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp @@ -0,0 +1,163 @@ +#include "CgalKernel.h" +#include "CgalConversionResult.h" + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, ConversionResults& shapes) { + IfcSchema::IfcRepresentationItem::list::ptr items = l->Items(); + bool part_succes = false; + if (items->size()) { + for (IfcSchema::IfcRepresentationItem::list::it it = items->begin(); it != items->end(); ++it) { + IfcSchema::IfcRepresentationItem* representation_item = *it; + if (shape_type(representation_item) == ST_SHAPELIST) { + part_succes |= convert_shapes(*it, shapes); + } else { + cgal_shape_t s; + if (convert_shape(representation_item, s)) { + shapes.push_back(ConversionResult(new CgalShape(s), get_style(representation_item))); + part_succes |= true; + } + } + } + } + return part_succes; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcGeometricSet* l, ConversionResults& shapes) { + IfcEntityList::ptr elements = l->Elements(); + if ( !elements->size() ) return false; + bool part_succes = false; + const IfcGeom::SurfaceStyle* parent_style = get_style(l); + for ( IfcEntityList::it it = elements->begin(); it != elements->end(); ++ it ) { + IfcSchema::IfcGeometricSetSelect* element = *it; + cgal_shape_t s; + if (convert_shape(element, s)) { + part_succes = true; + const IfcGeom::SurfaceStyle* style = 0; + if (element->is(IfcSchema::Type::IfcPoint)) { + style = get_style((IfcSchema::IfcPoint*) element); + } else if (element->is(IfcSchema::Type::IfcCurve)) { + style = get_style((IfcSchema::IfcCurve*) element); + } else if (element->is(IfcSchema::Type::IfcSurface)) { + style = get_style((IfcSchema::IfcSurface*) element); + } + shapes.push_back(ConversionResult(new CgalShape(s), style ? style : parent_style)); + } + } + return part_succes; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcShellBasedSurfaceModel* l, ConversionResults& shapes) { + IfcEntityList::ptr shells = l->SbsmBoundary(); + const SurfaceStyle* collective_style = get_style(l); + for( IfcEntityList::it it = shells->begin(); it != shells->end(); ++ it ) { + cgal_shape_t s; + const SurfaceStyle* shell_style = 0; + if ((*it)->is(IfcSchema::Type::IfcRepresentationItem)) { + shell_style = get_style((IfcSchema::IfcRepresentationItem*)*it); + } + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(new CgalShape(s), shell_style ? shell_style : collective_style)); + } + } + return true; +} + +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) ) { + CGAL::Nef_polyhedron_3 nef_s = create_nef_polyhedron(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) { + cgal_shape_t s2; + // TODO: This looks weird. Aren't we removing the outer shell again and again? + // Maybe it should be + // if (convert_shape(*it, s2)) { + if (convert_shape(l->Outer(), s2)) { + nef_s -= CGAL::Nef_polyhedron_3(s2); + } + } + + s = create_polyhedron(nef_s); + shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + return true; + } + return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { + cgal_placement_t gtrsf; + IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); + if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,gtrsf); + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + cgal_placement_t trsf; + if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + cgal_placement_t trsf_2d; + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); + trsf = trsf_2d; + } + + // TODO: Check + gtrsf = trsf * gtrsf; + + // std::cout << std::endl; + // for (int i = 0; i < 3; ++i) { + // for (int j = 0; j < 4; ++j) { + // std::cout << gtrsf.cartesian(i, j) << " "; + // } std::cout << std::endl; + // } + + const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l); + + const size_t previous_size = shapes.size(); + bool b = convert_shapes(map->MappedRepresentation(), shapes); + + for (size_t i = previous_size; i < shapes.size(); ++ i ) { + IfcGeom::CgalPlacement place(gtrsf); + shapes[i].prepend(&place); + + // Apply styles assigned to the mapped item only if on + // a more granular level no styles have been applied + if (!shapes[i].hasStyle()) { + shapes[i].setStyle(mapped_item_style); + } + } + + return b; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, ConversionResults& shapes) { + bool part_success = false; + IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces(); + const SurfaceStyle* collective_style = get_style(l); + for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) { + cgal_shape_t s; + const SurfaceStyle* shell_style = get_style(*it); + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(new CgalShape(s), shell_style ? shell_style : collective_style)); + part_success |= true; + } + } + return part_success; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp new file mode 100644 index 0000000000..08a947efd6 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -0,0 +1,333 @@ +// For MSVC to have M_PI +#define _USE_MATH_DEFINES +#include + +#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; + } + + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon); + + 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(const IfcSchema::IfcPolyline* l, cgal_wire_t& result) { + IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); + + // 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); + } + + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon); + + result = polygon; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdgeLoop* l, cgal_wire_t& result) { + IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList(); + cgal_wire_t mw; + for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) { + cgal_wire_t w; + if (convert_wire(*it, w)) { + // TODO: What to do here? Add some points only? +// mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value())); + return false; + } + } + result = mw; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire_t& result) { + if (convert_wire(l->EdgeElement(), result)) { + if (!l->Orientation()) { + std::reverse(result.begin(),result.end()); + } + return true; + } else { + return false; + } +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdge* l, cgal_wire_t& result) { + if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity); + return false; + } + + IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry(); + IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry(); + if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) { + Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity); + return false; + } + + cgal_point_t p1, p2; + if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) || + !convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2)) + { + return false; + } + + cgal_wire_t mw; + mw.push_back(p1); + mw.push_back(p2); + + result = mw; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wire_t& wire) { + if ( getValue(GV_PLANEANGLE_UNIT)<0 ) { + Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity); + + // Temporarily pretend we do have unit information + setValue(GV_PLANEANGLE_UNIT,1.0); + + bool succes_radians = false; + bool succes_degrees = false; + bool use_radians = false; + bool use_degrees = false; + + // First try radians + cgal_wire_t wire_radians, wire_degrees; + try { + succes_radians = IfcGeom::CgalKernel::convert(l,wire_radians); + } catch (...) {} + + // Now try degrees + setValue(GV_PLANEANGLE_UNIT,0.0174532925199433); + try { + succes_degrees = IfcGeom::CgalKernel::convert(l,wire_degrees); + } catch (...) {} + + // Restore to unknown unit state + setValue(GV_PLANEANGLE_UNIT,-1.0); + + if ( succes_degrees && ! succes_radians ) { + use_degrees = true; + } else if ( succes_radians && ! succes_degrees ) { + use_radians = true; + } else if ( succes_radians && succes_degrees ) { + if ( wire_degrees.back() == wire_degrees.front() && wire_radians.back() != wire_radians.front() ) { + use_degrees = true; + } else if ( wire_radians.back() == wire_radians.front() && wire_degrees.back() != wire_degrees.front() ) { + use_radians = true; + } else { + // No heuristic left to prefer the one over the other, + // apparently both variants are equally succesful. + // The curve might be composed of only straight segments. + // Let's go with the wire created using radians as that + // at least is a SI unit. + use_radians = true; + } + } + + if ( use_radians ) { + Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve"); + wire = wire_radians; + } else if ( use_degrees ) { + Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve"); + wire = wire_degrees; + } + + return use_radians || use_degrees; + } + IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments(); + cgal_wire_t w; + //TopoDS_Vertex last_vertex; + for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) { + IfcSchema::IfcCurve* curve = (*it)->ParentCurve(); + cgal_wire_t wire2; + if ( !convert_wire(curve,wire2) ) { + Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity); + continue; + } + if ( ! (*it)->SameSense() ) std::reverse(wire2.begin(),wire2.end()); + + if (wire2.empty()) { + continue; + } else if (w.empty()) { + w = wire2; + } else if (w.back() == w.front()) { + std::vector::const_iterator vertex = wire2.begin(); + ++vertex; + while (vertex != wire2.end()) { + w.push_back(*vertex); + ++vertex; + } + } else { + for (auto &vertex: wire2) w.push_back(vertex); + } + } + + remove_duplicate_points_from_loop(w); + + wire = w; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrimmedCurve* l, cgal_wire_t& wire) { + IfcSchema::IfcCurve* basis_curve = l->BasisCurve(); + bool isConic = basis_curve->is(IfcSchema::Type::IfcConic); + double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT); + cgal_curve_t curve; + if ( !convert_curve(basis_curve,curve) ) return false; + bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN; + IfcEntityList::ptr trims1 = l->Trim1(); + IfcEntityList::ptr trims2 = l->Trim2(); + unsigned sense_agreement = l->SenseAgreement() ? 0 : 1; + double flts[2]; + cgal_point_t pnts[2]; + bool has_flts[2] = {false,false}; + bool has_pnts[2] = {false,false}; + cgal_wire_t w; + for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) { + IfcUtil::IfcBaseClass* i = *it; + if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] ); + has_pnts[sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[sense_agreement] = value * parameterFactor; + has_flts[sense_agreement] = true; + } + } + for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) { + IfcUtil::IfcBaseClass* i = *it; + if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] ); + has_pnts[1-sense_agreement] = true; + } else if ( i->is(IfcSchema::Type::IfcParameterValue) ) { + const double value = *((IfcSchema::IfcParameterValue*)i); + flts[1-sense_agreement] = value * parameterFactor; + has_flts[1-sense_agreement] = true; + } + } + trim_cartesian &= has_pnts[0] && has_pnts[1]; + bool trim_cartesian_failed = !trim_cartesian; + if ( trim_cartesian ) { + // TODO: Project points to closest point in curve? + if ( CGAL::squared_distance(pnts[0], pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE) ) { + Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity); + return false; + } + if (l->SenseAgreement()) { + bool found = false; + int loops_to_go = 2; + std::vector::const_iterator point = curve.begin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.end()) { + point = curve.begin(); + --loops_to_go; + } + } while (point != curve.begin() && loops_to_go > 0); + } else { + bool found = false; + int loops_to_go = 2; + std::vector::const_reverse_iterator point = curve.rbegin(); + do { + if (!found) { + if (CGAL::squared_distance(*point, pnts[0]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + found = true; + w.push_back(*point); + } + } else { + w.push_back(*point); + if (CGAL::squared_distance(*point, pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE)*getValue(GV_WIRE_CREATION_TOLERANCE)) { + break; + } + } ++point; + if (point == curve.rend() && loops_to_go > 0) point = curve.rbegin(); + } while (point != curve.rbegin()); + } + } + if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) { + // The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine + // is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because + // the vector is normalised when passed to Geom_Line constructor the magnitude + // needs to be factored in with the IfcParameterValue here. + if ( basis_curve->is(IfcSchema::Type::IfcLine) ) { + IfcSchema::IfcLine* line = static_cast(basis_curve); + const double magnitude = line->Dir()->Magnitude(); + flts[0] *= magnitude; flts[1] *= magnitude; + } + if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) { + for (auto &point: curve) w.push_back(point); + } else { + const int segments_of_full_curve = 12; + double segment_angle = 2.0*3.141592653589793/segments_of_full_curve; + if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) { + IfcSchema::IfcEllipse* ellipse = static_cast(basis_curve); + double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT); + for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) { + w.push_back(Kernel::Point_3(x*cos(current_angle), y*sin(current_angle), 0)); + } w.push_back(Kernel::Point_3(x*cos(flts[1]), y*sin(flts[1]), 0)); + } if ( basis_curve->is(IfcSchema::Type::IfcCircle) ) { + IfcSchema::IfcCircle* circle = static_cast(basis_curve); + double r = circle->Radius() * getValue(GV_LENGTH_UNIT); + for (double current_angle = flts[0]; current_angle < flts[1]; current_angle += segment_angle) { + w.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } w.push_back(Kernel::Point_3(r*cos(flts[1]), r*sin(flts[1]), 0)); + } + } + } else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) { + w.push_back(pnts[0]); + w.push_back(pnts[1]); + } + wire = w; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index e796e39f01..e1f149dd85 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -89,6 +89,167 @@ bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* produ } bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { - throw std::runtime_error("not implemented"); + std::list opening_shapelist; + + for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) { + IfcSchema::IfcRelVoidsElement* v = *it; + IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement(); + if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) { + if (!fes->hasRepresentation()) continue; + + // Convert the IfcRepresentation of the IfcOpeningElement + cgal_placement_t opening_trsf; + if (fes->hasObjectPlacement()) { + try { + convert(fes->ObjectPlacement(),opening_trsf); + } catch (...) {} + } + + // Move the opening into the coordinate system of the IfcProduct + opening_trsf = entity_trsf.inverse() * opening_trsf; + + IfcSchema::IfcProductRepresentation* prodrep = fes->Representation(); + IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations(); + + IfcGeom::ConversionResults opening_shapes; + + for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) { + convert_shapes(*it2,opening_shapes); + } + + for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) { + cgal_placement_t gtrsf; + if (opening_shapes[i].Placement()) { + gtrsf = *(CgalPlacement*)opening_shapes[i].Placement(); + } + gtrsf = opening_trsf * gtrsf; + cgal_shape_t opening_shape(((CgalShape*)opening_shapes[i].Shape())->shape()); + for (auto &vertex: vertices(opening_shape)) vertex->point() = vertex->point().transform(gtrsf); + opening_shapelist.push_back(opening_shape); + } + + } + } + + // Iterate over the shapes of the IfcProduct + for ( IfcGeom::ConversionResults::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) { + const cgal_shape_t& entity_shape_unlocated(((CgalShape*)it3->Shape())->shape()); + cgal_shape_t entity_shape(entity_shape_unlocated); + if (it3->Placement()) { + const cgal_placement_t& entity_shape_gtrsf = *(CgalPlacement*)it3->Placement(); + for (auto &vertex: vertices(entity_shape)) vertex->point() = vertex->point().transform(entity_shape_gtrsf); + } + + cgal_shape_t original_entity_shape(entity_shape); + + if (!entity_shape.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid entity:", entity->entity); + return false; + } + + if (!entity_shape.is_closed()) { + // TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable... + Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed entity:", entity->entity); + return false; + } + + bool success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of entity crashed:", entity->entity); + return false; + } + + if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of entity failed:", entity->entity); + return false; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting entity:", entity->entity); + return false; + } + + CGAL::Nef_polyhedron_3 nef_brep_cut_result; + + try { + nef_brep_cut_result = CGAL::Nef_polyhedron_3(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert entity to Nef:", entity->entity); + return false; + } + + try { + cgal_shape_t brep_cut_result; + nef_brep_cut_result.convert_to_polyhedron(brep_cut_result); + } catch (...) { + Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert entity from Nef:", entity->entity); + } + + for (auto &opening: opening_shapelist) { + + cgal_shape_t original_opening_shape(opening); + if (!opening.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid opening in entity:", entity->entity); + return false; + } if (!opening.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in entity:", entity->entity); + return false; + } + + success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(opening); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of entity crashed:", entity->entity); + return false; + } + + if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of entity failed:", entity->entity); + return false; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting opening of entity:", entity->entity); + } + + CGAL::Nef_polyhedron_3 nef_opening; + + try { + nef_opening = CGAL::Nef_polyhedron_3(opening); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert opening of entity to Nef:", entity->entity); + return false; + } + + try { + cgal_shape_t opening_shape; + nef_opening.convert_to_polyhedron(opening_shape); + } catch (...) { + Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert opening of entity from Nef:", entity->entity); + // return false; + } + + try { + nef_brep_cut_result -= nef_opening; + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of entity:", entity->entity); + return false; + } + } + + try { + nef_brep_cut_result.convert_to_polyhedron(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert entity with openings from Nef:", entity->entity); + return false; + } + + cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(entity_shape), &it3->Style())); + + } return true; } - diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 6519b0ad68..fdd2b020d5 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -120,8 +120,18 @@ namespace IfcGeom { bool convert_wire(const IfcUtil::IfcBaseClass* L, cgal_wire_t& result); bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); + + bool convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face); + + void remove_duplicate_points_from_loop(cgal_wire_t& polygon); - // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); + bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const cgal_placement_t& entity_trsf, ConversionResults& cut_shapes); + +// CGAL::Polyhedron_3 triangulate_faces(CGAL::Polyhedron_3 &polyhedron); + CGAL::Polyhedron_3 create_polyhedron(std::list &face_list); + CGAL::Polyhedron_3 create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); void purge_cache() { // Rather hack-ish, but a stopgap solution to keep memory under control diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp index 8651236af9..24d3ed83c6 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp @@ -17,24 +17,44 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator vertex->point() = vertex->point().transform(trsf); } + if (!s.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)"); + return; + } + // Triangulate the shape and compute the normals - std::map vertex_normals; - boost::associative_property_map> vertex_normals_map(vertex_normals); +// std::map vertex_normals; +// boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { -// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; - } else { - Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); + bool success = false; + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(s); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation crashed"); return; } - - CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); - - // Iterates over the faces of the shape - int num_faces = 0, num_vertices = 0; + + if (!success) { + Logger::Message(Logger::LOG_ERROR, return; +"Triangulation failed"); + } + // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; + + if (!s.is_valid()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)"); + return; + } + +// CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map); + for (auto &face: faces(s)) { + if (!face->is_triangle()) { + std::cout << "Warning: non-triangular face!" << std::endl; + continue; + } CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); do { t->addVertex(surface_style_id, diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h index 59c4e63e59..38a3bc87d5 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h @@ -20,6 +20,13 @@ #ifndef CGALCONVERSIONRESULT_H #define CGALCONVERSIONRESULT_H +#include "../../../ifcgeom/schema_agnostic/Kernel.h" +#include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" +#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" + +// @todo create separate shapetype enum? +#include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h" + #include #include #include @@ -28,12 +35,16 @@ #include #include #include +#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef Kernel::Aff_transformation_3 cgal_placement_t; typedef Kernel::Point_3 cgal_point_t; typedef Kernel::Vector_3 cgal_direction_t; +typedef Kernel::Vector_3 cgal_vector_t; +typedef Kernel::Plane_3 cgal_plane_t; typedef std::vector cgal_curve_t; typedef std::vector cgal_wire_t; @@ -60,19 +71,15 @@ namespace IfcGeom { operator const cgal_placement_t& () { return trsf_; } virtual double Value(int i, int j) const { - // TODO: Check -// std::cout << "Getting CgalPlacement with i = " << i << " and j = " << j << std::endl; - return CGAL::to_double(trsf_.cartesian(i-1, j-1)); + return CGAL::to_double(trsf_.cartesian(i-1, j-1)); } virtual void Multiply(const ConversionResultPlacement* other) { - // TODO: Check - trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; + trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; } virtual void PreMultiply(const ConversionResultPlacement* other) { - // TODO: Check - trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; + trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; } virtual ConversionResultPlacement* clone() const {