diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 75dbc3319b..6eeefff91f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -279,8 +279,8 @@ ENDIF() IF(NOT libMPFR) MESSAGE(FATAL_ERROR "Unable to find MPFR library files, aborting") ENDIF() -list(APPEND CGAL_LIBRARIES "${libGMP}") list(APPEND CGAL_LIBRARIES "${libMPFR}") +list(APPEND CGAL_LIBRARIES "${libGMP}") diff --git a/nix/build-all.py b/nix/build-all.py index b7c10d50a6..ff5889a622 100644 --- a/nix/build-all.py +++ b/nix/build-all.py @@ -67,7 +67,7 @@ PYTHON_VERSIONS=["2.7.12", "3.2.6", "3.3.6", "3.4.6", "3.5.3", "3.6.2"] # OCCT_VERSION="7.2.0" # OCCT_HASH="88af392" OCCT_VERSION="7.3.0" -BOOST_VERSION="1.59.0" +BOOST_VERSION="1.69.0" PCRE_VERSION="8.39" LIBXML_VERSION="2.9.3" CMAKE_VERSION="3.4.1" @@ -75,6 +75,7 @@ ICU_VERSION="56.1" SWIG_VERSION="3.0.12" GMP_VERSION="6.1.2" MPFR_VERSION="3.1.5" +CGAL_VERSION="4.13" # binaries cp="cp" @@ -659,7 +660,7 @@ if "cgal" in targets: if BUILD_CFG != "Debug": # CGAL only supports Debug and Release for CMAKE_BUILD_TYPE BUILD_CFG = "Release" - build_dependency(name="cgal", mode="cmake", build_tool_args=["-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal/" % (DEPS_DIR,)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git) + build_dependency(name="cgal-{CGAL_VERSION}".format(**locals()), mode="cmake", build_tool_args=["-DGMP_LIBRARIES=%s/install/gmp-%s/lib/libgmp.a" % (DEPS_DIR, GMP_VERSION), "-DGMP_INCLUDE_DIR=%s/install/gmp-%s/include" % (DEPS_DIR, GMP_VERSION), "-DMPFR_LIBRARIES=%s/install/mpfr-%s/lib/libmpfr.a" % (DEPS_DIR, MPFR_VERSION), "-DMPFR_INCLUDE_DIR=%s/install/mpfr-%s/include" % (DEPS_DIR, MPFR_VERSION), "-DBoost_INCLUDE_DIR=%s/install/boost-%s" % (DEPS_DIR, BOOST_VERSION), "-DCMAKE_INSTALL_PREFIX=%s/install/cgal-%s/" % (DEPS_DIR, CGAL_VERSION)], download_url="https://github.com/CGAL/cgal.git", download_name="cgal", download_tool=download_tool_git, revision="releases/CGAL-{CGAL_VERSION}".format(**locals())) BUILD_CFG = OLD_BUILD_CFG cecho("Building IfcOpenShell:", GREEN) @@ -703,6 +704,16 @@ elif "occ" in targets: "-DOCC_LIBRARY_DIR=" +occ_library_dir ]) +if "cgal" in targets: + cmake_args.extend([ + "-DCGAL_INCLUDE_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/include".format(**locals()), + "-DCGAL_LIBRARY_DIR=" "{DEPS_DIR}/install/cgal-{CGAL_VERSION}/lib".format(**locals()), + "-DGMP_INCLUDE_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/include".format(**locals()), + "-DGMP_LIBRARY_DIR=" "{DEPS_DIR}/install/gmp-{GMP_VERSION}/lib".format(**locals()), + "-DMPFR_INCLUDE_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/include".format(**locals()), + "-DMPFR_LIBRARY_DIR=" "{DEPS_DIR}/install/mpfr-{MPFR_VERSION}/lib".format(**locals()) + ]) + if "OpenCOLLADA" in targets: cmake_args.extend([ "-DOPENCOLLADA_INCLUDE_DIR=" "{DEPS_DIR}/install/OpenCOLLADA/include/opencollada".format(**locals()), diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 651a53fca3..c09f8e5810 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -3,6 +3,9 @@ #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; @@ -26,7 +29,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers 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); + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l); return false; } @@ -49,10 +52,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal std::list face_list; face_list.push_back(face); - for (std::vector::const_iterator current_vertex = face.outer.begin(); + 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; + std::vector::const_iterator next_vertex = current_vertex; ++next_vertex; if (next_vertex == face.outer.end()) { next_vertex = face.outer.begin(); @@ -65,14 +68,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); + for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); vertex != face.outer.rend(); ++vertex) { top_face.outer.push_back(*vertex+height*dir); } face_list.push_back(top_face); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -91,7 +94,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal 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, + 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; @@ -104,7 +107,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_po 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, + 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) @@ -114,15 +117,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi 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? + 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), + 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); @@ -133,8 +136,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ 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? + 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); @@ -145,8 +148,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ // 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), + 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)); @@ -163,8 +166,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ 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->is(IfcSchema::Type::IfcLocalPlacement) ) { - Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity); + if ( ! l->as() ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l); return false; } @@ -180,7 +183,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p cgal_placement_t trsf2; IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement(); - if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) { + if ( relplacement->as() ) { IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2); // std::cout << "trsf2" << std::endl; @@ -201,7 +204,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p } if ( current->hasPlacementRelTo() ) { IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo(); - if ( relto->is(IfcSchema::Type::IfcLocalPlacement) ) + if ( relto->as() ) current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo(); else break; } else break; @@ -215,7 +218,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg 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); + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l); return false; } @@ -229,10 +232,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg } 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)); + face.outer.push_back(Kernel_::Point_3(-x, -y, 0.0)); + face.outer.push_back(Kernel_::Point_3( x, -y, 0.0)); + face.outer.push_back(Kernel_::Point_3( x, y, 0.0)); + face.outer.push_back(Kernel_::Point_3(-x, y, 0.0)); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp index f32a578d27..9f9a01684e 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp @@ -21,6 +21,9 @@ #define CgalKernel MAKE_TYPE_NAME(CgalKernel) +// @todo two distinct uses of the word Kernel is getting confusing +typedef Kernel Kernel_; + using namespace IfcUtil; bool IfcGeom::CgalKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) { @@ -84,11 +87,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv const SurfaceStyle* indiv_style = get_style(l->Outer()); IfcSchema::IfcClosedShell::list::ptr voids(new IfcSchema::IfcClosedShell::list); - if (l->is(IfcSchema::Type::IfcFacetedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #ifdef USE_IFC4 - if (l->is(IfcSchema::Type::IfcAdvancedBrepWithVoids)) { + if (l->as()) { voids = l->as()->Voids(); } #endif @@ -102,7 +105,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv // } } - shape.push_back(ConversionResult(new CgalShape(s), indiv_style ? indiv_style : collective_style)); + shape.push_back(ConversionResult(l->data().id(), new CgalShape(s), indiv_style ? indiv_style : collective_style)); return true; } return false; @@ -121,7 +124,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } catch (...) {} if (!success) { - Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", (*it)->entity); + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", *it); continue; } @@ -134,7 +137,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -169,11 +172,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face 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 (bound->as()) num_outer_bounds ++; } if (num_outer_bounds != 1) { - Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", l); return false; } @@ -183,11 +186,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face IfcSchema::IfcFaceBound* bound = *it; IfcSchema::IfcLoop* loop = bound->Bound(); - const bool is_interior = !bound->is(IfcSchema::Type::IfcFaceOuterBound); + 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->entity); + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", loop); return false; } @@ -212,7 +215,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); // Parse and store the points in a sequence - cgal_wire_t polygon = std::vector(); + 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); @@ -222,7 +225,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& // 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); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } @@ -232,11 +235,11 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& 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); + Logger::Message(Logger::LOG_WARNING, ss.str(), l); } if (count < 3) { - Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 00492f8089..6519b0ad68 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -35,6 +35,8 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #endif */ +#define ALMOST_ZERO 1.e-9 + #include "../../../ifcparse/macros.h" #include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h" diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp index 6e2943d3c6..1f752e30fd 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFaces.cpp @@ -106,6 +106,19 @@ #define Kernel MAKE_TYPE_NAME(Kernel) +namespace { + int count_occt(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::count(&Ss, (int) t); + } + + int is_manifold_occt(const TopoDS_Shape& s) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::is_manifold(&Ss); + } +} + + bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { IfcSchema::IfcFaceBound::list::ptr bounds = l->Bounds(); @@ -239,7 +252,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) { if (face_surface.IsNull()) { gp_Pln pln; - if (count(wire, TopAbs_EDGE) > 128 && approximate_plane_through_wire(wire, pln)) { + if (count_occt(wire, TopAbs_EDGE) > 128 && approximate_plane_through_wire(wire, pln)) { // tfk: optimization find the underlying surface ourselves since it's going // to be planar in IFC if no explicit surface is given. Should we always do this? // @todo is this still relevant considering the code above diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp index 66819ef849..24bb7b858a 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomFunctions.cpp @@ -337,6 +337,18 @@ namespace { } } +namespace { + int count_occt(const TopoDS_Shape& s, TopAbs_ShapeEnum t) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::count(&Ss, (int) t); + } + + int is_manifold_occt(const TopoDS_Shape& s) { + IfcGeom::OpenCascadeShape Ss(s); + return IfcGeom::Kernel::is_manifold(&Ss); + } +} + bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) { TopTools_ListOfShape face_list; TopExp_Explorer exp(compound, TopAbs_FACE); @@ -388,7 +400,7 @@ bool IfcGeom::Kernel::create_solid_from_faces(const TopTools_ListOfShape& face_l } BRepCheck_Analyzer ana(shape); - valid_shell = ana.IsValid() != 0 && count(shape, TopAbs_SHELL) > 0; + valid_shell = ana.IsValid() != 0 && count_occt(shape, TopAbs_SHELL) > 0; } catch (const Standard_Failure& e) { if (e.GetMessageString() && strlen(e.GetMessageString())) { Logger::Error(e.GetMessageString()); @@ -1899,12 +1911,12 @@ bool IfcGeom::Kernel::apply_folded_layerset(const ConversionResults& items, cons TopoDS_Shape Bn = BRepPrimAPI_MakeHalfSpace(B, jt->second.second).Solid(); TopoDS_Shape a = BRepAlgoAPI_Cut(A, Bn); - if (count(a, TopAbs_FACE) == 1) { + if (count_occt(a, TopAbs_FACE) == 1) { A = TopoDS::Face(TopExp_Explorer(a, TopAbs_FACE).Current()); } TopoDS_Shape b = BRepAlgoAPI_Cut(B, An); - if (count(b, TopAbs_FACE) == 1) { + if (count_occt(b, TopAbs_FACE) == 1) { B = TopoDS::Face(TopExp_Explorer(b, TopAbs_FACE).Current()); } } @@ -2504,7 +2516,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO return false; } - int n = count(wire, TopAbs_EDGE); + int n = count_occt(wire, TopAbs_EDGE); if (n < 3) { wires.Append(wire); return false; @@ -2936,7 +2948,7 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li if (success) { - success = !is_manifold(a) || is_manifold(r); + success = !is_manifold_occt(a) || is_manifold_occt(r); if (success) { @@ -3108,7 +3120,7 @@ bool IfcGeom::Kernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGe TopoDS_Shape merge; if (flatten_shape_list(shapes, merge, false)) { - if (count(merge, TopAbs_FACE) > 0) { + if (count_occt(merge, TopAbs_FACE) > 0) { std::vector thickness; std::vector layers; std::vector< std::vector > folded_layers; @@ -3189,7 +3201,7 @@ bool IfcGeom::Kernel::validate_quantities(const IfcSchema::IfcProduct* product, int genus = q2->as()->CountValue(); for (auto& part : brep) { if (part.ItemId() == item_id) { - if (surface_genus(*(OpenCascadeShape*)part.Shape()) != genus) { + if (surface_genus(part.Shape()) != genus) { all_succeeded = false; } } diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index a1f5ff83e2..f3c97f9c23 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -113,7 +113,8 @@ namespace IfcGeom { std::vector ts_filtered; const TopoDS_Shape& A = shapes_.find(t)->second; - if (IfcGeom::Kernel::count(A, TopAbs_SHELL) == 0) { + OpenCascadeShape SA(A); + if (IfcGeom::Kernel::count(&SA, (int) TopAbs_SHELL) == 0) { return ts_filtered; } @@ -122,21 +123,24 @@ namespace IfcGeom { typename std::vector::const_iterator it = ts.begin(); for (it = ts.begin(); it != ts.end(); ++it) { const TopoDS_Shape& B = shapes_.find(*it)->second; - if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) { + OpenCascadeShape SB(B); + if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) { continue; } if (completely_within) { BRepAlgoAPI_Cut cut(B, A); if (cut.IsDone()) { - if (IfcGeom::Kernel::count(cut.Shape(), TopAbs_SHELL) == 0) { + OpenCascadeShape Sc(cut.Shape()); + if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) == 0) { ts_filtered.push_back(*it); } } } else { BRepAlgoAPI_Common common(A, B); if (common.IsDone()) { - if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) { + OpenCascadeShape Sc(common.Shape()); + if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) { ts_filtered.push_back(*it); } } @@ -152,7 +156,8 @@ namespace IfcGeom { std::vector ts; - if (IfcGeom::Kernel::count(s, TopAbs_SHELL) == 0) { + OpenCascadeShape Ss(s); + if (IfcGeom::Kernel::count(&Ss, (int) TopAbs_SHELL) == 0) { return ts; } @@ -169,13 +174,15 @@ namespace IfcGeom { for (it = ts.begin(); it != ts.end(); ++it) { const TopoDS_Shape& B = shapes_.find(*it)->second; - if (IfcGeom::Kernel::count(B, TopAbs_SHELL) == 0) { + OpenCascadeShape SB(B); + if (IfcGeom::Kernel::count(&SB, (int) TopAbs_SHELL) == 0) { continue; } BRepAlgoAPI_Common common(s, B); if (common.IsDone()) { - if (IfcGeom::Kernel::count(common.Shape(), TopAbs_SHELL) > 0) { + OpenCascadeShape Sc(common.Shape());; + if (IfcGeom::Kernel::count(&Sc, (int) TopAbs_SHELL) > 0) { ts_filtered.push_back(*it); } } @@ -268,7 +275,7 @@ namespace IfcGeom { if (it.initialize()) { do { IfcGeom::NativeElement* elem = (IfcGeom::NativeElement*)it.get(); - add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), elem->geometry().as_compound()); + add((IfcUtil::IfcBaseEntity*)f.instance_by_id(elem->id()), ((OpenCascadeShape*)elem->geometry().as_compound())->shape()); } while (it.next()); } } diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp index e7230d8b17..ea52aaaf3e 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,10 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings()) , id_(brep.id()) { - TopoDS_Compound compound = brep.as_compound(); + IfcGeom::ConversionResultShape* shape = brep.as_compound(); + TopoDS_Compound compound = TopoDS::Compound(((OpenCascadeShape*) shape)->shape()); + delete shape; + for (IfcGeom::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) { if (it->hasStyle() && it->Style().Diffuse()) { const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse(); @@ -82,7 +86,7 @@ TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { } } -TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const { +IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound() const { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); @@ -103,7 +107,8 @@ TopoDS_Compound IfcGeom::Representation::BRep::as_compound() const { const TopoDS_Shape moved_shape = apply_transformation(s, trsf); builder.Add(compound, moved_shape); } - return compound; + + return new OpenCascadeShape(compound); } namespace { @@ -212,7 +217,7 @@ bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { volume = 0.; for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { + if (Kernel::is_manifold(it->Shape())) { GProp_GProps prop; BRepGProp::VolumeProperties(*(OpenCascadeShape*)it->Shape(), prop); volume += prop.Mass(); @@ -240,7 +245,7 @@ bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const Conve double x, y, z; surface_area_along_direction(settings().deflection_tolerance(), *(OpenCascadeShape*)it->Shape(), ax, x, y, z); - if (Kernel::is_manifold(*(OpenCascadeShape*)it->Shape())) { + if (Kernel::is_manifold(it->Shape())) { x /= 2.; y /= 2.; z /= 2.; diff --git a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h index f6232007ce..e938f00a1d 100644 --- a/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h +++ b/src/ifcgeom/schema_agnostic/IfcGeomRepresentation.h @@ -20,27 +20,10 @@ #ifndef IFCGEOMREPRESENTATION_H #define IFCGEOMREPRESENTATION_H -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - #include "../../ifcgeom/schema_agnostic/IfcGeomIteratorSettings.h" #include "../../ifcgeom/schema_agnostic/IfcGeomMaterial.h" #include "../../ifcgeom/schema_agnostic/ConversionResult.h" -#include - #include namespace IfcGeom { @@ -77,7 +60,7 @@ namespace IfcGeom { IfcGeom::ConversionResults::const_iterator end() const { return shapes_.end(); } const IfcGeom::ConversionResults& shapes() const { return shapes_; } const std::string& id() const { return id_; } - TopoDS_Compound as_compound() const; + ConversionResultShape* as_compound() const; bool calculate_volume(double&) const; bool calculate_surface_area(double&) const; diff --git a/src/ifcgeom/schema_agnostic/Kernel.cpp b/src/ifcgeom/schema_agnostic/Kernel.cpp index de6bf568a8..a75f04053a 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.cpp +++ b/src/ifcgeom/schema_agnostic/Kernel.cpp @@ -3,6 +3,9 @@ #include "../../ifcparse/Ifc2x3.h" #include "../../ifcparse/Ifc4.h" +// @todo remove +#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + #include #include #include @@ -19,7 +22,11 @@ IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* } } -int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool unique) { +int IfcGeom::Kernel::count(const ConversionResultShape* s_, int t_, bool unique) { + // @todo make kernel agnostic + const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape(); + TopAbs_ShapeEnum t = (TopAbs_ShapeEnum) t_; + if (unique) { TopTools_IndexedMapOfShape map; TopExp::MapShapes(s, t, map); @@ -35,10 +42,14 @@ int IfcGeom::Kernel::count(const TopoDS_Shape& s, TopAbs_ShapeEnum t, bool uniqu } -int IfcGeom::Kernel::surface_genus(const TopoDS_Shape& s) { - int nv = count(s, TopAbs_VERTEX, true); - int ne = count(s, TopAbs_EDGE, true); - int nf = count(s, TopAbs_FACE, true); +int IfcGeom::Kernel::surface_genus(const ConversionResultShape* s_) { + // @todo make kernel agnostic + const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape(); + OpenCascadeShape Ss(s); + + int nv = count(&Ss, (int) TopAbs_VERTEX, true); + int ne = count(&Ss, (int) TopAbs_EDGE, true); + int nf = count(&Ss, (int) TopAbs_FACE, true); const int euler = nv - ne + nf; const int genus = (2 - euler) / 2; @@ -202,11 +213,15 @@ std::map IfcGeom::Kernel::get_layers(IfcUt } } -bool IfcGeom::Kernel::is_manifold(const TopoDS_Shape& a) { +bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) { + // @todo make kernel agnostic + const TopoDS_Shape& a = ((OpenCascadeShape*) s_)->shape(); + if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) { TopoDS_Iterator it(a); for (; it.More(); it.Next()) { - if (!is_manifold(it.Value())) { + OpenCascadeShape s(it.Value()); + if (!is_manifold(&s)) { return false; } } diff --git a/src/ifcgeom/schema_agnostic/Kernel.h b/src/ifcgeom/schema_agnostic/Kernel.h index 5bbb050649..7bc04705bd 100644 --- a/src/ifcgeom/schema_agnostic/Kernel.h +++ b/src/ifcgeom/schema_agnostic/Kernel.h @@ -7,8 +7,6 @@ #include -#include - namespace IfcGeom { template @@ -76,10 +74,10 @@ namespace IfcGeom { return implementation_->convert_placement(item, trsf); } - static int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique=false); - static int surface_genus(const TopoDS_Shape&); + static int count(const ConversionResultShape*, int, bool unique=false); + static int surface_genus(const ConversionResultShape*); - static bool is_manifold(const TopoDS_Shape& a); + static bool is_manifold(const ConversionResultShape*); static IfcUtil::IfcBaseEntity* get_decomposing_entity(IfcUtil::IfcBaseEntity*); static std::map get_layers(IfcUtil::IfcBaseEntity*); static IfcEntityList::ptr find_openings(IfcUtil::IfcBaseEntity* product); diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp index fa1b9a5958..8651236af9 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp @@ -1,9 +1,14 @@ #include "CgalConversionResult.h" +#include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" + template -void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { - cgal_shape_t s = shape_; - const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); +void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) { + // Copy is made because triangulate_faces() does not accept a const argument + cgal_shape_t s = shape_const; + + const cgal_placement_t& trsf = dynamic_cast(place)->trsf(); // std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; // std::cout << "Valid: " << s.is_valid() << std::endl; @@ -17,6 +22,7 @@ void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & se 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 { @@ -35,14 +41,21 @@ void triangulate_helper(const cgal_shape_t, const IfcGeom::IteratorSettings & se CGAL::to_double(current_halfedge->vertex()->point().cartesian(0)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(2))); - for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); - t->faces().push_back(num_vertices); + + const double nx = CGAL::to_double(face_normals_map[face].cartesian(0)); + const double ny = CGAL::to_double(face_normals_map[face].cartesian(1)); + const double nz = CGAL::to_double(face_normals_map[face].cartesian(2)); + t->addNormal(nx, ny, nz); + ++num_vertices; ++current_halfedge; } while (current_halfedge != face->facet_begin()); - t->material_ids().push_back(surface_style_id); + + t->addFace(surface_style_id, num_vertices-3, num_vertices-2, num_vertices-1); + ++num_faces; } + } void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { diff --git a/src/serializers/OpenCascadeBasedSerializer.cpp b/src/serializers/OpenCascadeBasedSerializer.cpp index 257fa83e4e..f3be07c51f 100644 --- a/src/serializers/OpenCascadeBasedSerializer.cpp +++ b/src/serializers/OpenCascadeBasedSerializer.cpp @@ -35,7 +35,9 @@ bool OpenCascadeBasedSerializer::ready() { } void OpenCascadeBasedSerializer::write(const IfcGeom::NativeElement* o) { - TopoDS_Shape compound = o->geometry().as_compound(); + IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound()); + TopoDS_Shape compound = occt_shape->shape(); + delete occt_shape; if (o->geometry().settings().get(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS)) { gp_Trsf scale; diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 06427e4331..6e89083c9f 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -19,6 +19,8 @@ * * ********************************************************************************/ +#include "../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" + #include #include #include @@ -342,7 +344,10 @@ void SvgSerializer::write(const IfcGeom::NativeElement* o) path_object& p = start_path(storey, nameElement(o)); - TopoDS_Shape compound = o->geometry().as_compound(); + IfcGeom::OpenCascadeShape* occt_shape = ((IfcGeom::OpenCascadeShape*) o->geometry().as_compound()); + TopoDS_Shape compound = occt_shape->shape(); + delete occt_shape; + TopoDS_Iterator it(compound); // Iterate over components of compound to have better chance of matching section edges to closed wires