diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 10168dfaa8..65bfce6556 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -2,6 +2,7 @@ #include "../../ifcgeom/schema_agnostic/IfcGeomElement.h" #include "../../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" +#include "../../ifcgeom/kernels/cgal/CgalKernel.h" namespace { /* A compile-time for loop over the taxonomy kinds */ @@ -34,6 +35,8 @@ ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels const std::string geometry_library_lower = boost::to_lower_copy(geometry_library); if (geometry_library_lower == "opencascade") { return new OpenCascadeKernel; + } else if (geometry_library_lower == "cgal") { + return new CgalKernel; } else { throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp rename to src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp_ diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp similarity index 65% rename from src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp rename to src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index cd59ecd70a..86f5f93cbb 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -3,18 +3,23 @@ #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h" -template -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; +void ifcopenshell::geometry::CgalShape::Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const { + // Copy is made because triangulate_faces() does not accept a const argument + cgal_shape_t s = shape_; - 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; - - // Apply transformation - if (place != NULL) for (auto &vertex: vertices(s)) { - vertex->point() = vertex->point().transform(trsf); + if (!place.components.isIdentity()) { + const auto& m = place.components; + + // @todo check + const cgal_placement_t trsf( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3)); + + // Apply transformation + for (auto &vertex : vertices(s)) { + vertex->point() = vertex->point().transform(trsf); + } } if (!s.is_valid()) { @@ -78,11 +83,3 @@ void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::Iterator } } - -void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { - triangulate_helper(shape_, settings, place, t, surface_style_id); -} - -void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { - triangulate_helper(shape_, settings, place, t, surface_style_id); -} diff --git a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h similarity index 65% rename from src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h rename to src/ifcgeom/kernels/cgal/CgalConversionResult.h index df085e0c8d..35aaa5d61d 100644 --- a/src/ifcgeom/schema_agnostic/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -20,12 +20,7 @@ #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 @@ -59,49 +54,9 @@ typedef boost::graph_traits>::face_descriptor cgal_f #include "../../../ifcgeom/schema_agnostic/ConversionResult.h" -namespace IfcGeom { +namespace ifcopenshell { namespace geometry { - class CgalPlacement : public ConversionResultPlacement { - public: - CgalPlacement(const cgal_placement_t& trsf) - : trsf_(trsf) - {} - - const cgal_placement_t& trsf() const { return trsf_; } - operator const cgal_placement_t& () { return trsf_; } - - virtual double Value(int i, int j) const { - return CGAL::to_double(trsf_.cartesian(i-1, j-1)); - } - - virtual void Multiply(const ConversionResultPlacement* other) { - trsf_ = trsf_ * ((CgalPlacement *)other)->trsf_; - } - - virtual void PreMultiply(const ConversionResultPlacement* other) { - trsf_ = ((CgalPlacement *)other)->trsf_ * trsf_; - } - - virtual ConversionResultPlacement* clone() const { - return new CgalPlacement(trsf_); - } - - virtual ConversionResultPlacement* inverted() const { - throw std::runtime_error("Not implemented"); - } - - virtual ConversionResultPlacement* multiplied(const ConversionResultPlacement*) const { - throw std::runtime_error("Not implemented"); - } - - virtual void TranslationPart(double& X, double& Y, double& Z) const { - throw std::runtime_error("Not implemented"); - } - private: - cgal_placement_t trsf_; - }; - - class CgalShape : public ConversionResultShape { + class CgalShape : public ConversionResultShape { public: CgalShape(const cgal_shape_t& shape) : shape_(shape) @@ -110,9 +65,7 @@ namespace IfcGeom { const cgal_shape_t& shape() const { return shape_; } operator const cgal_shape_t& () { return shape_; } - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation * t, int surface_style_id) const; - - virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(const settings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(std::string&) const { throw std::runtime_error("Not implemented"); @@ -122,6 +75,10 @@ namespace IfcGeom { return new CgalShape(shape_); } + virtual bool is_manifold() const { + throw std::runtime_error("Not implemented"); + } + virtual int surface_genus() const { throw std::runtime_error("Not implemented"); } @@ -129,6 +86,6 @@ namespace IfcGeom { cgal_shape_t shape_; }; -} +}} #endif diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp b/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp deleted file mode 100644 index a604069f8b..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ - -#include "CgalKernel.h" - -#define CgalKernel MAKE_TYPE_NAME(CgalKernel) - -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), get_style(l->as()))); - return true; - } - return false; - } - -#include "CgalEntityMappingShapes.h" - Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l); - return false; -} - -IfcGeom::ShapeType IfcGeom::CgalKernel::shape_type(const IfcBaseClass* l) { -#include "CgalEntityMappingShapeType.h" - return ST_OTHER; -} - -bool IfcGeom::CgalKernel::convert_shape(const IfcBaseClass* l, cgal_shape_t& r) { - const unsigned int id = l->data().id(); - bool success = false; - bool processed = false; - bool ignored = false; - -#ifndef NO_CACHE - std::map::const_iterator it = cache.Shape.find(id); - if ( it != cache.Shape.end() ) { r = it->second; return true; } -#endif - const bool include_curves = getValue(GV_DIMENSIONALITY) != +1; - const bool include_solids_and_surfaces = getValue(GV_DIMENSIONALITY) != -1; - - IfcGeom::ShapeType st = shape_type(l); - ignored = (!include_solids_and_surfaces && (st == ST_SHAPE || st == ST_FACE)) || (!include_curves && (st == ST_WIRE || st == ST_CURVE)); - if (st == ST_SHAPE && include_solids_and_surfaces) { -#include "CgalEntityMappingShape.h" - } - - if ( processed && success ) { -// const double precision = getValue(GV_PRECISION); - // apply_tolerance(r, precision); -#ifndef NO_CACHE - cache.Shape[id] = r; -#endif - } else if (!ignored) { - const char* const msg = processed - ? "Failed to convert:" - : "No operation defined for:"; - Logger::Message(Logger::LOG_ERROR, msg, l); - } - return success; -} - -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); - 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); - return false; -} - -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); - return false; -} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h deleted file mode 100644 index 51874f1550..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ - -/******************************************************************************** - * * - * This file registers function prototypes for all supported IFC geometrical * - * entities. For entities of type CLASS an std::map is also created to cache * - * the output of the conversion functions * - * * - ********************************************************************************/ - -#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(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/CgalEntityMappingCreateCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h deleted file mode 100644 index ebfb8daca7..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingCreateCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CLASS(T,V) \ - std::map T; -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h deleted file mode 100644 index 5bebf39992..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingCurve.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CURVE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h deleted file mode 100644 index 7101613c26..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingDeclaration.h +++ /dev/null @@ -1,10 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r); -#define SHAPES(T) CLASS(T,ConversionResults) -#define SHAPE(T) CLASS(T,cgal_shape_t) -#define WIRE(T) CLASS(T,cgal_wire_t) -#define FACE(T) CLASS(T,cgal_face_t) -#define CURVE(T) CLASS(T,cgal_curve_t) -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h deleted file mode 100644 index 65f8704a81..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingDefine.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SHAPES -#define SHAPES(T) -#endif -#ifndef SHAPE -#define SHAPE(T) -#endif -#ifndef WIRE -#define WIRE(T) -#endif -#ifndef FACE -#define FACE(T) -#endif -#ifndef CURVE -#define CURVE(T) -#endif -#ifndef CLASS -#define CLASS(T,V) -#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h deleted file mode 100644 index 65087a1a5f..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingFace.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define FACE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h deleted file mode 100644 index ea8c2c2554..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingPurgeCache.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define CLASS(T,V) \ - T.clear(); -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h deleted file mode 100644 index 14dc9d51e1..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShape.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define SHAPE(T) \ - if ( !processed && l->declaration().is(IfcSchema::T::Class()) ) { \ - processed = true; \ - try { \ - if (convert((IfcSchema::T*)l, r) ) { \ - success = true; \ - } \ - } catch (const std::exception& e) { \ - Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ - return false; \ - } \ - if (!success) { \ - Logger::Message(Logger::LOG_ERROR,"Failed to convert:", l); \ - return false; \ - } \ - } -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h deleted file mode 100644 index ec25d81d25..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapeType.h +++ /dev/null @@ -1,14 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define SHAPES(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPELIST; -#define SHAPE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return ST_SHAPE; -#define WIRE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return ST_WIRE; -#define FACE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return ST_FACE; -#define CURVE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return ST_CURVE; -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h deleted file mode 100644 index 700b4a08a2..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingShapes.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define SHAPES(T) \ - if (l->declaration().is(IfcSchema::T::Class())) { \ - try { \ - return convert((IfcSchema::T*)l,r); \ - } catch (const std::exception& e) { \ - Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l); \ - } \ - return false; \ - } -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h deleted file mode 100644 index d2d537a073..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingUndefine.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifdef SHAPES -#undef SHAPES -#endif -#ifdef SHAPE -#undef SHAPE -#endif -#ifdef WIRE -#undef WIRE -#endif -#ifdef FACE -#undef FACE -#endif -#ifdef CURVE -#undef CURVE -#endif -#ifdef CLASS -#undef CLASS -#endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h b/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h deleted file mode 100644 index 459ad8267c..0000000000 --- a/src/ifcgeom/kernels/cgal/CgalEntityMappingWire.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CgalEntityMappingUndefine.h" -#define WIRE(T) \ - if (l->declaration().is(IfcSchema::T::Class())) return convert((IfcSchema::T*)l,r); -#include "CgalEntityMappingDefine.h" - -#include "CgalEntityMapping.h" diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomCurves.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomPrimitives.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomShapesWithStyles.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp_ similarity index 100% rename from src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp rename to src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp_ diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index c885fa5974..f78f39a18c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -1,267 +1,246 @@ -/******************************************************************************** -* * -* This file is part of IfcOpenShell. * -* * -* IfcOpenShell is free software: you can redistribute it and/or modify * -* it under the terms of the Lesser GNU General Public License as published by * -* the Free Software Foundation, either version 3.0 of the License, or * -* (at your option) any later version. * -* * -* IfcOpenShell is distributed in the hope that it will be useful, * -* but WITHOUT ANY WARRANTY; without even the implied warranty of * -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -* Lesser GNU General Public License for more details. * -* * -* You should have received a copy of the Lesser GNU General Public License * -* along with this program. If not, see . * -* * -********************************************************************************/ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ #include "CgalKernel.h" -namespace { - struct MAKE_TYPE_NAME(factory_t) { - IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const { - IfcGeom::MAKE_TYPE_NAME(CgalKernel)* k = new IfcGeom::MAKE_TYPE_NAME(CgalKernel); - return k; - } - }; -} +#include "../../../ifcparse/IfcLogger.h" +#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" -void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplementation* mapping) { - static const std::string schema_name = STRINGIFY(IfcSchema); - MAKE_TYPE_NAME(factory_t) factory; - mapping->bind(schema_name, "cgal", factory); -} +using namespace ifcopenshell::geometry; +using namespace ifcopenshell::geometry::kernels; -#define CgalKernel MAKE_TYPE_NAME(CgalKernel) - -bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { - Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()"); - return false; - /* - // OpenCascade kernel code below - - IfcSchema::IfcAxis2Placement2D* ax2d; - IfcSchema::IfcAxis2Placement3D* ax3d; - - IfcSchema::IfcCartesianTransformationOperator2D* op2d; - IfcSchema::IfcCartesianTransformationOperator3D* op3d; - IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; - IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; - - if ((op2dnonu = l->as()) != 0) { - gp_GTrsf2d gtrsf2d; - convert(op2dnonu, gtrsf2d); - return gtrsf2d.Form() == gp_Identity; - } else if ((op2d = l->as()) != 0) { - gp_Trsf2d trsf2d; - convert(op2d, trsf2d); - return trsf2d.Form() == gp_Identity; - } else if ((op3dnonu = l->as()) != 0) { - gp_GTrsf gtrsf; - convert(op3dnonu, gtrsf); - return gtrsf.Form() == gp_Identity; - } else if ((op3d = l->as()) != 0) { - gp_Trsf trsf; - convert(op3d, trsf); - return trsf.Form() == gp_Identity; - } else if ((ax2d = l->as()) != 0) { - gp_Trsf2d trsf2d; - convert(ax2d, trsf2d); - return trsf2d.Form() == gp_Identity; - } else if ((ax3d = l->as()) != 0) { - gp_Trsf trsf; - convert(ax3d, trsf); - return trsf.Form() == gp_Identity; - } else { - throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); +void 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]); } - */ } -bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { - throw std::runtime_error("not implemented"); +CGAL::Polyhedron_3 CgalKernel::create_polyhedron(std::list &face_list) { + + // Naive creation + 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; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + 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); + } + } + + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + return polyhedron; } -bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { - throw std::runtime_error("not implemented"); +CGAL::Polyhedron_3 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(); + } } -bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { - if (item->as()) { - cgal_placement_t cgal_trsf; - if (convert(item->as(), cgal_trsf)) { - trsf = new CgalPlacement(cgal_trsf); - return true; - } - } - return false; +CGAL::Nef_polyhedron_3 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; } -bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& entity_shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { - const cgal_placement_t& entity_trsf = ((CgalPlacement*) trsf)->trsf(); - 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->as() ) { - 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 geometry:", product); - 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 geometry:", product); - return false; - } - - bool success = false; - - try { - success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", product); - return false; - } - - if (!success) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", product); - return false; - } - - if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) { - Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", product); - 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 geometry to Nef:", product); - 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 geometry from Nef:", product); - } - - 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 geometry:", product); - return false; - } if (!opening.is_closed()) { - Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in geometry:", product); - return false; - } - - success = false; - - try { - success = CGAL::Polygon_mesh_processing::triangulate_faces(opening); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry crashed:", product); - return false; - } - - if (!success) { - Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry failed:", product); - 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 geometry:", product); - } - - 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 geometry to Nef:", product); - 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 geometry from Nef:", product); - // return false; - } - - try { - nef_brep_cut_result -= nef_opening; - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of geometry:", product); - return false; - } - } - - try { - nef_brep_cut_result.convert_to_polyhedron(entity_shape); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", product); - return false; - } - - opened_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), new CgalShape(entity_shape), &it3->Style())); - - } return true; +CGAL::Nef_polyhedron_3 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(); + } +} + +bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) { + auto faces = l->children_as(); + + std::list face_list; + for (auto& f : faces) { + bool success = false; + cgal_face_t face; + + try { + success = convert(f, face); + } catch (...) {} + + if (!success) { + Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", f->instance); + 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 CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) { + auto bounds = face->children_as(); + + int num_outer_bounds = 0; + + for (auto& bound : bounds) { + if (bound->external.get_value_or(false)) num_outer_bounds++; + } + + if (num_outer_bounds != 1) { + Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance); + return false; + } + + cgal_face_t mf; + + for (auto& bound : bounds) { + + const bool is_interior = !bound->external.get_value_or(false); + + cgal_wire_t wire; + if (!convert(bound, wire)) { + Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance); + return false; + } + + if (!is_interior) { + mf.outer = wire; + } else { + mf.inner.push_back(wire); + } + } + + result = mf; + + // std::cout << "Face: " << std::endl; + // for (auto &point: face.outer) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} + +bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { + // @todo only implement polygonal loops + + auto edges = loop->children_as(); + std::vector points; + + for (auto& e : edges) { + if (e->basis) { + return false; + } + points.push_back(boost::get(e->start)); + } + + // Parse and store the points in a sequence + cgal_wire_t polygon = std::vector(); + for (auto& p : points) { + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + 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:", loop->instance); + 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(), loop->instance); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", loop->instance); + return false; + } + + result = polygon; + + // std::cout << "PolyLoop: " << std::endl; + // for (auto &point: polygon) { + // std::cout << "\tPoint(" << point << ")" << std::endl; + // } + + return true; +} + + +bool CgalKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geometry::ConversionResults& results) { + cgal_shape_t shape; + if (!convert(shell, shape)) { + return false; + } + results.emplace_back(ConversionResult( + shell->instance->data().id(), + shell->matrix, + new CgalShape(shape), + shell->surface_style + )); + return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ new file mode 100644 index 0000000000..c885fa5974 --- /dev/null +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp_ @@ -0,0 +1,267 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#include "CgalKernel.h" + +namespace { + struct MAKE_TYPE_NAME(factory_t) { + IfcGeom::Kernel* operator()(IfcParse::IfcFile* file) const { + IfcGeom::MAKE_TYPE_NAME(CgalKernel)* k = new IfcGeom::MAKE_TYPE_NAME(CgalKernel); + return k; + } + }; +} + +void MAKE_INIT_FN(KernelImplementation_cgal_)(IfcGeom::impl::KernelFactoryImplementation* mapping) { + static const std::string schema_name = STRINGIFY(IfcSchema); + MAKE_TYPE_NAME(factory_t) factory; + mapping->bind(schema_name, "cgal", factory); +} + +#define CgalKernel MAKE_TYPE_NAME(CgalKernel) + +bool IfcGeom::CgalKernel::is_identity_transform(const IfcUtil::IfcBaseClass* l) { + Logger::Message(Logger::LOG_ERROR, "Not implemented is_identity_transform()"); + return false; + /* + // OpenCascade kernel code below + + IfcSchema::IfcAxis2Placement2D* ax2d; + IfcSchema::IfcAxis2Placement3D* ax3d; + + IfcSchema::IfcCartesianTransformationOperator2D* op2d; + IfcSchema::IfcCartesianTransformationOperator3D* op3d; + IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu; + IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu; + + if ((op2dnonu = l->as()) != 0) { + gp_GTrsf2d gtrsf2d; + convert(op2dnonu, gtrsf2d); + return gtrsf2d.Form() == gp_Identity; + } else if ((op2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(op2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((op3dnonu = l->as()) != 0) { + gp_GTrsf gtrsf; + convert(op3dnonu, gtrsf); + return gtrsf.Form() == gp_Identity; + } else if ((op3d = l->as()) != 0) { + gp_Trsf trsf; + convert(op3d, trsf); + return trsf.Form() == gp_Identity; + } else if ((ax2d = l->as()) != 0) { + gp_Trsf2d trsf2d; + convert(ax2d, trsf2d); + return trsf2d.Form() == gp_Identity; + } else if ((ax3d = l->as()) != 0) { + gp_Trsf trsf; + convert(ax3d, trsf); + return trsf.Form() == gp_Identity; + } else { + throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator"); + } + */ +} + +bool IfcGeom::CgalKernel::apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes) { + throw std::runtime_error("not implemented"); +} + +bool IfcGeom::CgalKernel::validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep) { + throw std::runtime_error("not implemented"); +} + +bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) { + if (item->as()) { + cgal_placement_t cgal_trsf; + if (convert(item->as(), cgal_trsf)) { + trsf = new CgalPlacement(cgal_trsf); + return true; + } + } + return false; +} + +bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& entity_shapes, const IfcGeom::ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes) { + const cgal_placement_t& entity_trsf = ((CgalPlacement*) trsf)->trsf(); + 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->as() ) { + 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 geometry:", product); + 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 geometry:", product); + return false; + } + + bool success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", product); + return false; + } + + if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", product); + return false; + } + + if (CGAL::Polygon_mesh_processing::does_self_intersect(entity_shape)) { + Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", product); + 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 geometry to Nef:", product); + 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 geometry from Nef:", product); + } + + 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 geometry:", product); + return false; + } if (!opening.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Subtraction of opening makes no sense. Not closed opening in geometry:", product); + return false; + } + + success = false; + + try { + success = CGAL::Polygon_mesh_processing::triangulate_faces(opening); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry crashed:", product); + return false; + } + + if (!success) { + Logger::Message(Logger::LOG_ERROR, "Triangulation of opening of geometry failed:", product); + 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 geometry:", product); + } + + 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 geometry to Nef:", product); + 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 geometry from Nef:", product); + // return false; + } + + try { + nef_brep_cut_result -= nef_opening; + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not subtract Nef opening of geometry:", product); + return false; + } + } + + try { + nef_brep_cut_result.convert_to_polyhedron(entity_shape); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", product); + return false; + } + + opened_shapes.push_back(IfcGeom::ConversionResult(it3->ItemId(), 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 4f3186589d..0041c9c172 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -48,17 +48,12 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance=ALMO #include "../../../ifcgeom/kernel_agnostic/AbstractKernel.h" -#include "../../../ifcgeom/schema_agnostic/Kernel.h" #include "../../../ifcgeom/schema_agnostic/IfcGeomElement.h" -#include "../../../ifcgeom/schema_agnostic/cgal/CgalConversionResult.h" +#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" // @todo create separate shapetype enum? #include "../../../ifcgeom/kernels/opencascade/IfcGeomShapeType.h" -#define INCLUDE_SCHEMA(x) STRINGIFY(../../../ifcparse/x.h) -#include INCLUDE_SCHEMA(IfcSchema) -#undef INCLUDE_SCHEMA - struct PolyhedronBuilder : public CGAL::Modifier_base::HalfedgeDS> { private: std::list *face_list; @@ -102,66 +97,32 @@ public: } }; -namespace IfcGeom { +namespace ifcopenshell { +namespace geometry { +namespace kernels { - class IFC_GEOM_API CgalCache { - public: -#include "CgalEntityMappingCreateCache.h" - std::map Shape; - }; - - class IFC_GEOM_API MAKE_TYPE_NAME(CgalKernel) : public MAKE_TYPE_NAME(AbstractKernel) { + class IFC_GEOM_API CgalKernel : public AbstractKernel { public: - MAKE_TYPE_NAME(CgalKernel)() - : MAKE_TYPE_NAME(AbstractKernel)("cgal") {} + CgalKernel() + : AbstractKernel("cgal") {} -#ifndef NO_CACHE - CgalCache cache; -#endif + void remove_duplicate_points_from_loop(cgal_wire_t& polygon); - IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L); + 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); - bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result); - bool convert_shape(const IfcUtil::IfcBaseClass* L, cgal_shape_t& result); - 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(const taxonomy::face*, cgal_face_t&); + bool convert(const taxonomy::loop*, cgal_wire_t&); + bool convert(const taxonomy::shell* l, cgal_shape_t& shape); - 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 - // for large files. SurfaceStyles need to be kept at all costs, as they - // are read later on when serializing Collada files. -#ifndef NO_CACHE - cache = CgalCache(); -#endif - } - - virtual bool is_identity_transform(const IfcUtil::IfcBaseClass*); - virtual bool apply_layerset(const IfcSchema::IfcProduct* product, IfcGeom::ConversionResults& shapes); - virtual bool validate_quantities(const IfcSchema::IfcProduct* product, const IfcGeom::Representation::BRep& brep); - virtual bool convert_openings(const IfcSchema::IfcProduct* product, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const IfcGeom::ConversionResults& shapes, const ConversionResultPlacement* trsf, IfcGeom::ConversionResults& opened_shapes); - virtual bool convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf); - -#include "CgalEntityMappingDeclaration.h" - - private: - double deflection_tolerance; - double dimensionality; + virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); }; } - +} +} #endif \ No newline at end of file diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp index 8db95bdd7a..c59b3056d4 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/opencascade/IfcGeomShapes.cpp @@ -246,11 +246,8 @@ namespace { #include bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result) { - std::vector bounds; - std::transform(face->children.begin(), face->children.end(), std::back_inserter(bounds), [](auto item){ - return static_cast(item); - }); - + auto bounds = face->children_as(); + face_definition fd; const bool is_face_surface = false; /* todo */