mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Begin reenable CGAL kernel
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+16
-19
@@ -3,18 +3,23 @@
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcgeom/schema_agnostic/IfcGeomRepresentation.h"
|
||||
|
||||
template <typename Precision>
|
||||
void triangulate_helper(const cgal_shape_t& shape_const, const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<Precision>* 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<const IfcGeom::CgalPlacement*>(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<float>* 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<double>* t, int surface_style_id) const {
|
||||
triangulate_helper(shape_, settings, place, t, surface_style_id);
|
||||
}
|
||||
+8
-51
@@ -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 <boost/property_map/property_map.hpp>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
@@ -59,49 +54,9 @@ typedef boost::graph_traits<CGAL::Polyhedron_3<Kernel_>>::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<float> * t, int surface_style_id) const;
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* 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
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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<IfcSchema::IfcRepresentationItem>())));
|
||||
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<int, cgal_shape_t>::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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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);
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
std::map<int,V> T;
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "CgalEntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
T.clear();
|
||||
#include "CgalEntityMappingDefine.h"
|
||||
|
||||
#include "CgalEntityMapping.h"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
|
||||
gp_GTrsf2d gtrsf2d;
|
||||
convert(op2dnonu, gtrsf2d);
|
||||
return gtrsf2d.Form() == gp_Identity;
|
||||
} else if ((op2d = l->as<IfcSchema::IfcCartesianTransformationOperator2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(op2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((op3dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) != 0) {
|
||||
gp_GTrsf gtrsf;
|
||||
convert(op3dnonu, gtrsf);
|
||||
return gtrsf.Form() == gp_Identity;
|
||||
} else if ((op3d = l->as<IfcSchema::IfcCartesianTransformationOperator3D>()) != 0) {
|
||||
gp_Trsf trsf;
|
||||
convert(op3d, trsf);
|
||||
return trsf.Form() == gp_Identity;
|
||||
} else if ((ax2d = l->as<IfcSchema::IfcAxis2Placement2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(ax2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((ax3d = l->as<IfcSchema::IfcAxis2Placement3D>()) != 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<cgal_point_t> 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<Kernel_> CgalKernel::create_polyhedron(std::list<cgal_face_t> &face_list) {
|
||||
|
||||
// Naive creation
|
||||
CGAL::Polyhedron_3<Kernel_> 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<Kernel_>();
|
||||
} 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<Kernel_> CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron) {
|
||||
if (nef_polyhedron.is_simple()) {
|
||||
try {
|
||||
CGAL::Polyhedron_3<Kernel_> 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<Kernel_>();
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::CgalKernel::convert_placement(IfcUtil::IfcBaseClass* item, ConversionResultPlacement*& trsf) {
|
||||
if (item->as<IfcSchema::IfcObjectPlacement>()) {
|
||||
cgal_placement_t cgal_trsf;
|
||||
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), cgal_trsf)) {
|
||||
trsf = new CgalPlacement(cgal_trsf);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
CGAL::Nef_polyhedron_3<Kernel_> CgalKernel::create_nef_polyhedron(std::list<cgal_face_t> &face_list) {
|
||||
CGAL::Polyhedron_3<Kernel_> polyhedron = create_polyhedron(face_list);
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(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<cgal_shape_t> 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<IfcSchema::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 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<Kernel_> nef_brep_cut_result;
|
||||
|
||||
try {
|
||||
nef_brep_cut_result = CGAL::Nef_polyhedron_3<Kernel_>(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<Kernel_> nef_opening;
|
||||
|
||||
try {
|
||||
nef_opening = CGAL::Nef_polyhedron_3<Kernel_>(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<Kernel_> CgalKernel::create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &polyhedron) {
|
||||
if (polyhedron.is_valid()) {
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef_polyhedron;
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(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<Kernel_>();
|
||||
}
|
||||
}
|
||||
|
||||
bool CgalKernel::convert(const taxonomy::shell* l, cgal_shape_t& shape) {
|
||||
auto faces = l->children_as<taxonomy::face>();
|
||||
|
||||
std::list<cgal_face_t> 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<taxonomy::loop>();
|
||||
|
||||
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<taxonomy::edge>();
|
||||
std::vector<taxonomy::point3> points;
|
||||
|
||||
for (auto& e : edges) {
|
||||
if (e->basis) {
|
||||
return false;
|
||||
}
|
||||
points.push_back(boost::get<taxonomy::point3>(e->start));
|
||||
}
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
cgal_wire_t polygon = std::vector<Kernel_::Point_3>();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#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<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
|
||||
gp_GTrsf2d gtrsf2d;
|
||||
convert(op2dnonu, gtrsf2d);
|
||||
return gtrsf2d.Form() == gp_Identity;
|
||||
} else if ((op2d = l->as<IfcSchema::IfcCartesianTransformationOperator2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(op2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((op3dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) != 0) {
|
||||
gp_GTrsf gtrsf;
|
||||
convert(op3dnonu, gtrsf);
|
||||
return gtrsf.Form() == gp_Identity;
|
||||
} else if ((op3d = l->as<IfcSchema::IfcCartesianTransformationOperator3D>()) != 0) {
|
||||
gp_Trsf trsf;
|
||||
convert(op3d, trsf);
|
||||
return trsf.Form() == gp_Identity;
|
||||
} else if ((ax2d = l->as<IfcSchema::IfcAxis2Placement2D>()) != 0) {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert(ax2d, trsf2d);
|
||||
return trsf2d.Form() == gp_Identity;
|
||||
} else if ((ax3d = l->as<IfcSchema::IfcAxis2Placement3D>()) != 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<IfcSchema::IfcObjectPlacement>()) {
|
||||
cgal_placement_t cgal_trsf;
|
||||
if (convert(item->as<IfcSchema::IfcObjectPlacement>(), 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<cgal_shape_t> 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<IfcSchema::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 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<Kernel_> nef_brep_cut_result;
|
||||
|
||||
try {
|
||||
nef_brep_cut_result = CGAL::Nef_polyhedron_3<Kernel_>(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<Kernel_> nef_opening;
|
||||
|
||||
try {
|
||||
nef_opening = CGAL::Nef_polyhedron_3<Kernel_>(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;
|
||||
}
|
||||
@@ -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<CGAL::Polyhedron_3<Kernel_>::HalfedgeDS> {
|
||||
private:
|
||||
std::list<cgal_face_t> *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<int, cgal_shape_t> 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<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Polyhedron_3<Kernel_> create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &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<Kernel_> triangulate_faces(CGAL::Polyhedron_3<Kernel_> &polyhedron);
|
||||
CGAL::Polyhedron_3<Kernel_> create_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Polyhedron_3<Kernel_> create_polyhedron(CGAL::Nef_polyhedron_3<Kernel_> &nef_polyhedron);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(std::list<cgal_face_t> &face_list);
|
||||
CGAL::Nef_polyhedron_3<Kernel_> create_nef_polyhedron(CGAL::Polyhedron_3<Kernel_> &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
|
||||
@@ -246,11 +246,8 @@ namespace {
|
||||
#include <ShapeFix_Edge.hxx>
|
||||
|
||||
bool OpenCascadeKernel::convert(const taxonomy::face* face, TopoDS_Shape& result) {
|
||||
std::vector<taxonomy::loop*> bounds;
|
||||
std::transform(face->children.begin(), face->children.end(), std::back_inserter(bounds), [](auto item){
|
||||
return static_cast<taxonomy::loop*>(item);
|
||||
});
|
||||
|
||||
auto bounds = face->children_as<taxonomy::loop>();
|
||||
|
||||
face_definition fd;
|
||||
|
||||
const bool is_face_surface = false; /* todo */
|
||||
|
||||
Reference in New Issue
Block a user