mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-11 06:18:09 +00:00
Isolate geometry processing code into separate opencascade kernel
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "../../../ifcgeom/IfcGeomShapeType.h"
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "OpenCascadeKernel.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
using namespace IfcSchema;
|
||||
using namespace IfcUtil;
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_shapes(const IfcBaseClass* l, ConversionResults& r) {
|
||||
if (shape_type(l) != ST_SHAPELIST) {
|
||||
TopoDS_Shape shp;
|
||||
if (convert_shape(l, shp)) {
|
||||
r.push_back(IfcGeom::ConversionResult(new OpenCascadeShape(shp), get_style(l->as<IfcSchema::IfcRepresentationItem>())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "EntityMappingShapes.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcGeom::ShapeType IfcGeom::OpenCascadeKernel::shape_type(const IfcBaseClass* l) {
|
||||
#include "EntityMappingShapeType.h"
|
||||
return ST_OTHER;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_shape(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
const unsigned int id = l->entity->id();
|
||||
bool success = false;
|
||||
bool processed = false;
|
||||
bool ignored = false;
|
||||
|
||||
#ifndef NO_CACHE
|
||||
std::map<int,TopoDS_Shape>::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_SHAPELIST) {
|
||||
processed = true;
|
||||
ConversionResults items;
|
||||
success = convert_shapes(l, items) && flatten_shape_list(items, r, false);
|
||||
} else if (st == ST_SHAPE && include_solids_and_surfaces) {
|
||||
#include "EntityMappingShape.h"
|
||||
} else if (st == ST_FACE && include_solids_and_surfaces) {
|
||||
processed = true;
|
||||
success = convert_face(l, r);
|
||||
} else if (st == ST_WIRE && include_curves) {
|
||||
processed = true;
|
||||
TopoDS_Wire w;
|
||||
success = convert_wire(l, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
} else if (st == ST_CURVE && include_curves) {
|
||||
processed = true;
|
||||
Handle(Geom_Curve) crv;
|
||||
TopoDS_Wire w;
|
||||
success = convert_curve(l, crv) && convert_curve_to_wire(crv, w);
|
||||
if (success) {
|
||||
r = w;
|
||||
}
|
||||
}
|
||||
|
||||
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->entity);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_wire(const IfcBaseClass* l, TopoDS_Wire& r) {
|
||||
#include "EntityMappingWire.h"
|
||||
Handle(Geom_Curve) curve;
|
||||
if (convert_curve(l, curve)) {
|
||||
return convert_curve_to_wire(curve, r);
|
||||
}
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_face(const IfcBaseClass* l, TopoDS_Shape& r) {
|
||||
#include "EntityMappingFace.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert_curve(const IfcBaseClass* l, Handle(Geom_Curve)& r) {
|
||||
#include "EntityMappingCurve.h"
|
||||
Logger::Message(Logger::LOG_ERROR,"No operation defined for:",l->entity);
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
|
||||
#include "../../../ifcparse/IfcUtil.h"
|
||||
#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);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
SHAPE(IfcBSplineSurfaceWithKnots);
|
||||
SHAPE(IfcTriangulatedFaceSet);
|
||||
SHAPE(IfcExtrudedAreaSolidTapered);
|
||||
#endif
|
||||
SHAPE(IfcPlane);
|
||||
SHAPE(IfcExtrudedAreaSolid);
|
||||
SHAPE(IfcRevolvedAreaSolid);
|
||||
SHAPE(IfcConnectedFaceSet);
|
||||
SHAPE(IfcBooleanResult);
|
||||
SHAPE(IfcPolygonalBoundedHalfSpace);
|
||||
SHAPE(IfcHalfSpaceSolid);
|
||||
// FIXME: Surfaces should have a shape type of their own
|
||||
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,gp_Pnt);
|
||||
CLASS(IfcDirection,gp_Dir);
|
||||
CLASS(IfcAxis2Placement2D,gp_Trsf2d);
|
||||
CLASS(IfcAxis2Placement3D,gp_Trsf);
|
||||
CLASS(IfcAxis1Placement,gp_Ax1);
|
||||
CLASS(IfcCartesianTransformationOperator2DnonUniform,gp_GTrsf2d);
|
||||
CLASS(IfcCartesianTransformationOperator3DnonUniform,gp_GTrsf);
|
||||
CLASS(IfcCartesianTransformationOperator2D,gp_Trsf2d);
|
||||
CLASS(IfcCartesianTransformationOperator3D,gp_Trsf);
|
||||
CLASS(IfcObjectPlacement,gp_Trsf);
|
||||
CLASS(IfcVector,gp_Vec);
|
||||
CLASS(IfcPlane,gp_Pln);
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
std::map<int,V> T;
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define CLASS(T,V) bool convert(const IfcSchema::T* L, V& r);
|
||||
#define SHAPES(T) CLASS(T,ConversionResults)
|
||||
#define SHAPE(T) CLASS(T,TopoDS_Shape)
|
||||
#define WIRE(T) CLASS(T,TopoDS_Wire)
|
||||
#define FACE(T) CLASS(T,TopoDS_Shape)
|
||||
#define CURVE(T) CLASS(T,Handle(Geom_Curve))
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,18 @@
|
||||
#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
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define CLASS(T,V) \
|
||||
T.clear();
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define SHAPE(T) \
|
||||
if ( !processed && l->is(T::Class()) ) { \
|
||||
processed = true; \
|
||||
try { \
|
||||
if ( convert((T*)l,r) ) { \
|
||||
success = true; \
|
||||
} \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \
|
||||
return false; \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString() && strlen(f.GetMessageString())) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l->entity); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l->entity); \
|
||||
return false; \
|
||||
} \
|
||||
if (!success) { \
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert:",l->entity); \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) return ST_SHAPELIST;
|
||||
#define SHAPE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_SHAPE;
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_WIRE;
|
||||
#define FACE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_FACE;
|
||||
#define CURVE(T) \
|
||||
if ( l->is(T::Class()) ) return ST_CURVE;
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define SHAPES(T) \
|
||||
if ( l->is(T::Class()) ) { \
|
||||
try { \
|
||||
return convert((T*)l,r); \
|
||||
} catch (const std::exception& e) { \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string(e.what()) + "\nFailed to convert:", l->entity); \
|
||||
} catch (const Standard_Failure& f) { \
|
||||
if (f.GetMessageString()) \
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error in: ") + f.GetMessageString() + "\nFailed to convert:", l->entity); \
|
||||
else \
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to convert:", l->entity); \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,18 @@
|
||||
#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
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "EntityMappingUndefine.h"
|
||||
#define WIRE(T) \
|
||||
if ( l->is(T::Class()) ) return convert((T*)l,r);
|
||||
#include "EntityMappingDefine.h"
|
||||
|
||||
#include "EntityMapping.h"
|
||||
@@ -0,0 +1,197 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Implementations of the various conversion functions defined in EntityMapping.h *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Vec2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#ifdef USE_IFC4
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#endif
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCircle* l, Handle(Geom_Curve)& curve) {
|
||||
const double r = l->Radius() * getValue(GV_LENGTH_UNIT);
|
||||
if ( r < ALMOST_ZERO ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2().Transformed(trsf);
|
||||
curve = new Geom_Circle(ax, r);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEllipse* l, Handle(Geom_Curve)& curve) {
|
||||
double x = l->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = l->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
if (x < ALMOST_ZERO || y < ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
// Open Cascade does not allow ellipses of which the minor radius
|
||||
// is greater than the major radius. Hence, in this case, the
|
||||
// ellipse is rotated. Note that special care needs to be taken
|
||||
// when creating a trimmed curve off of an ellipse like this.
|
||||
const bool rotated = y > x;
|
||||
gp_Trsf trsf;
|
||||
IfcSchema::IfcAxis2Placement* placement = l->Position();
|
||||
if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) {
|
||||
convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf);
|
||||
} else {
|
||||
gp_Trsf2d trsf2d;
|
||||
convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf2d);
|
||||
trsf = trsf2d;
|
||||
}
|
||||
gp_Ax2 ax = gp_Ax2();
|
||||
if (rotated) {
|
||||
ax.Rotate(ax.Axis(), M_PI / 2.);
|
||||
std::swap(x, y);
|
||||
}
|
||||
ax.Transform(trsf);
|
||||
curve = new Geom_Ellipse(ax, x, y);
|
||||
return true;
|
||||
}
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcLine* l, Handle(Geom_Curve)& curve) {
|
||||
gp_Pnt pnt;gp_Vec vec;
|
||||
convert(l->Pnt(),pnt);
|
||||
convert(l->Dir(),vec);
|
||||
// See note at IfcGeomWires.cpp:237
|
||||
curve = new Geom_Line(pnt,vec);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcBSplineCurveWithKnots* l, Handle(Geom_Curve)& curve) {
|
||||
|
||||
const bool is_rational = l->is(IfcSchema::Type::IfcRationalBSplineCurveWithKnots);
|
||||
|
||||
const IfcSchema::IfcCartesianPoint::list::ptr cps = l->ControlPointsList();
|
||||
const std::vector<int> mults = l->KnotMultiplicities();
|
||||
const std::vector<double> knots = l->Knots();
|
||||
|
||||
TColgp_Array1OfPnt Poles(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Weights(0, cps->size() - 1);
|
||||
TColStd_Array1OfReal Knots(0, (int)knots.size() - 1);
|
||||
TColStd_Array1OfInteger Mults(0, (int)mults.size() - 1);
|
||||
Standard_Integer Degree = l->Degree();
|
||||
Standard_Boolean Periodic = l->ClosedCurve();
|
||||
|
||||
int i;
|
||||
|
||||
if (is_rational) {
|
||||
IfcSchema::IfcRationalBSplineCurveWithKnots* rl = (IfcSchema::IfcRationalBSplineCurveWithKnots*)l;
|
||||
std::vector<double> weights = rl->WeightsData();
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it, ++i) {
|
||||
Weights(i) = *it;
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (IfcSchema::IfcCartesianPoint::list::it it = cps->begin(); it != cps->end(); ++it, ++i) {
|
||||
gp_Pnt pnt;
|
||||
if (!convert(*it, pnt)) return false;
|
||||
Poles(i) = pnt;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<int>::const_iterator it = mults.begin(); it != mults.end(); ++it, ++i) {
|
||||
Mults(i) = *it;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (std::vector<double>::const_iterator it = knots.begin(); it != knots.end(); ++it, ++i) {
|
||||
Knots(i) = *it;
|
||||
}
|
||||
|
||||
if (is_rational) {
|
||||
curve = new Geom_BSplineCurve(Poles, Weights, Knots, Mults, Degree, Periodic);
|
||||
} else {
|
||||
curve = new Geom_BSplineCurve(Poles, Knots, Mults, Degree, Periodic);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,384 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Implementations of the various conversion functions defined in EntityMapping.h *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Vec2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <TopLoc_Location.hxx>
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
// Helper functions (re)set gp_(G)Trsf(2d) forms explicitly to 'Identity'
|
||||
// so that it can be easily identified in the IfcMappedItem processing
|
||||
|
||||
// For axis placements detect equality early in order for the
|
||||
// relatively computionaly expensive gp_Trsf calculation to be skipped
|
||||
template <typename T>
|
||||
bool axis_equal(const T& a, const T& b, double tolerance);
|
||||
template <>
|
||||
bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
// Note that the tolerance below is angular, above is linear. Since architectural
|
||||
// objects are about 1m'ish in scale, it should be somewhat equivalent. Besides,
|
||||
// this is mostly a filter for NULL or default values in the placements.
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
if (!a.XDirection().IsEqual(b.XDirection(), tolerance)) return false;
|
||||
if (!a.YDirection().IsEqual(b.YDirection(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance) {
|
||||
if (!a.Location().IsEqual(b.Location(), tolerance)) return false;
|
||||
if (!a.Direction().IsEqual(b.Direction(), tolerance)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> struct dimension_count {};
|
||||
template <> struct dimension_count <gp_Trsf2d > { static const int n = 2; };
|
||||
template <> struct dimension_count <gp_GTrsf2d> { static const int n = 2; };
|
||||
template <> struct dimension_count < gp_Trsf > { static const int n = 3; };
|
||||
template <> struct dimension_count < gp_GTrsf > { static const int n = 3; };
|
||||
|
||||
template <typename T>
|
||||
bool is_identity(const T& t, double tolerance) {
|
||||
// Note the {1, n+1} range due to Open Cascade's 1-based indexing
|
||||
// Note the {1, n+2} range due to the translation part of the matrix
|
||||
for (int i = 1; i < dimension_count<T>::n + 2; ++i) {
|
||||
for (int j = 1; j < dimension_count<T>::n + 1; ++j) {
|
||||
const double iden_value = i == j ? 1. : 0.;
|
||||
const double trsf_value = t.Value(j, i);
|
||||
if (fabs(trsf_value - iden_value) > tolerance) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianPoint* l, gp_Pnt& point) {
|
||||
IN_CACHE(IfcCartesianPoint,l,gp_Pnt,point)
|
||||
std::vector<double> xyz = l->Coordinates();
|
||||
point = gp_Pnt(
|
||||
xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f,
|
||||
xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f
|
||||
);
|
||||
CACHE(IfcCartesianPoint,l,point)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcDirection* l, gp_Dir& dir) {
|
||||
IN_CACHE(IfcDirection,l,gp_Dir,dir)
|
||||
std::vector<double> xyz = l->DirectionRatios();
|
||||
dir = gp_Dir(
|
||||
xyz.size() ? xyz[0] : 0.0f,
|
||||
xyz.size() > 1 ? xyz[1] : 0.0f,
|
||||
xyz.size() > 2 ? xyz[2] : 0.0f
|
||||
);
|
||||
CACHE(IfcDirection,l,dir)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcVector* l, gp_Vec& v) {
|
||||
IN_CACHE(IfcVector,l,gp_Vec,v)
|
||||
gp_Dir d;
|
||||
IfcGeom::OpenCascadeKernel::convert(l->Orientation(),d);
|
||||
v = l->Magnitude() * getValue(GV_LENGTH_UNIT) * d;
|
||||
CACHE(IfcVector,l,v)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::OpenCascadeKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3, gp::XOY());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis1Placement* l, gp_Ax1& ax) {
|
||||
IN_CACHE(IfcAxis1Placement,l,gp_Ax1,ax)
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);
|
||||
IfcGeom::OpenCascadeKernel::convert(l->Location(),o);
|
||||
if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(), axis);
|
||||
ax = gp_Ax1(o, axis);
|
||||
CACHE(IfcAxis1Placement,l,ax)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf)
|
||||
gp_Pnt origin;
|
||||
IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::OpenCascadeKernel::convert(l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
|
||||
if (!axis_equal(ax3, (gp_Ax3) gp::XOY(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
}
|
||||
|
||||
if (l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.)) {
|
||||
trsf.SetScaleFactor(l->Scale());
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2D* l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2D,l,gp_Trsf2d,trsf)
|
||||
|
||||
gp_Pnt origin;
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
|
||||
// A better match to represent the IfcCartesianTransformationOperator2D would
|
||||
// be the gp_Ax22d, but to my knowledge no easy way exists to convert it into
|
||||
// a gp_Trsf2d. Easiest would probably be to simply update the underlying
|
||||
// gp_Mat2d directly.
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
if ( l->hasScale() && !ALMOST_THE_SAME(l->Scale(), 1.) ) trsf.SetScaleFactor(l->Scale());
|
||||
|
||||
if (is_identity(trsf, getValue(GV_PRECISION))) {
|
||||
trsf = gp_Trsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, gp_GTrsf& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf)
|
||||
gp_Trsf trsf;
|
||||
gp_Pnt origin;
|
||||
IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin);
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
gp_Dir axis3 (0.,0.,1.);
|
||||
if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2);
|
||||
if ( l->hasAxis3() ) IfcGeom::OpenCascadeKernel::convert(l->Axis3(),axis3);
|
||||
gp_Ax3 ax3 (origin,axis3,axis1);
|
||||
if ( axis2.Dot(ax3.YDirection()) < 0 ) ax3.YReverse();
|
||||
trsf.SetTransformation(ax3);
|
||||
trsf.Invert();
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
const double scale3 = l->hasScale3() ? l->Scale3() : scale1;
|
||||
gtrsf = gp_GTrsf();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.SetValue(3,3,scale3);
|
||||
gtrsf.PreMultiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCartesianTransformationOperator2DnonUniform* l, gp_GTrsf2d& gtrsf) {
|
||||
IN_CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gp_GTrsf2d,gtrsf)
|
||||
|
||||
gp_Trsf2d trsf;
|
||||
gp_Pnt origin;
|
||||
gp_Dir axis1 (1.,0.,0.);
|
||||
gp_Dir axis2 (0.,1.,0.);
|
||||
|
||||
IfcGeom::OpenCascadeKernel::convert(l->LocalOrigin(),origin);
|
||||
if ( l->hasAxis1() ) IfcGeom::OpenCascadeKernel::convert(l->Axis1(),axis1);
|
||||
if ( l->hasAxis2() ) IfcGeom::OpenCascadeKernel::convert(l->Axis2(),axis2);
|
||||
|
||||
const gp_Pnt2d origin2d(origin.X(), origin.Y());
|
||||
const gp_Dir2d axis12d(axis1.X(), axis1.Y());
|
||||
const gp_Dir2d axis22d(axis2.X(), axis2.Y());
|
||||
|
||||
const gp_Ax2d ax2d (origin2d, axis12d);
|
||||
trsf.SetTransformation(ax2d);
|
||||
|
||||
if ( ax2d.Direction().Rotated(M_PI / 2.).Dot(axis22d) < 0. ) {
|
||||
gp_Trsf2d mirror; mirror.SetMirror(ax2d);
|
||||
trsf.Multiply(mirror);
|
||||
}
|
||||
|
||||
trsf.Invert();
|
||||
|
||||
const double scale1 = l->hasScale() ? l->Scale() : 1.0f;
|
||||
const double scale2 = l->hasScale2() ? l->Scale2() : scale1;
|
||||
gtrsf = gp_GTrsf2d();
|
||||
gtrsf.SetValue(1,1,scale1);
|
||||
gtrsf.SetValue(2,2,scale2);
|
||||
gtrsf.Multiply(trsf);
|
||||
|
||||
if (is_identity(gtrsf, getValue(GV_PRECISION))) {
|
||||
gtrsf = gp_GTrsf2d();
|
||||
}
|
||||
|
||||
CACHE(IfcCartesianTransformationOperator2DnonUniform,l,gtrsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPlane* pln, gp_Pln& plane) {
|
||||
IN_CACHE(IfcPlane,pln,gp_Pln,plane)
|
||||
IfcSchema::IfcAxis2Placement3D* l = pln->Position();
|
||||
gp_Pnt o;gp_Dir axis = gp_Dir(0,0,1);gp_Dir refDirection;
|
||||
IfcGeom::OpenCascadeKernel::convert(l->Location(),o);
|
||||
bool hasRef = l->hasRefDirection();
|
||||
if ( l->hasAxis() ) IfcGeom::OpenCascadeKernel::convert(l->Axis(),axis);
|
||||
if ( hasRef ) IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),refDirection);
|
||||
gp_Ax3 ax3;
|
||||
if ( hasRef ) ax3 = gp_Ax3(o,axis,refDirection);
|
||||
else ax3 = gp_Ax3(o,axis);
|
||||
plane = gp_Pln(ax3);
|
||||
CACHE(IfcPlane,pln,plane)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, gp_Trsf2d& trsf) {
|
||||
IN_CACHE(IfcAxis2Placement2D,l,gp_Trsf2d,trsf)
|
||||
gp_Pnt P; gp_Dir V (1,0,0);
|
||||
IfcGeom::OpenCascadeKernel::convert(l->Location(),P);
|
||||
if ( l->hasRefDirection() )
|
||||
IfcGeom::OpenCascadeKernel::convert(l->RefDirection(),V);
|
||||
|
||||
gp_Ax2d axis(gp_Pnt2d(P.X(),P.Y()), gp_Dir2d(V.X(),V.Y()));
|
||||
|
||||
if (!axis_equal(axis, gp_Ax2d(), getValue(GV_PRECISION))) {
|
||||
trsf.SetTransformation(axis, gp_Ax2d());
|
||||
}
|
||||
|
||||
CACHE(IfcAxis2Placement2D,l,trsf)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) {
|
||||
IN_CACHE(IfcObjectPlacement,l,gp_Trsf,trsf)
|
||||
if ( ! l->is(IfcSchema::Type::IfcLocalPlacement) ) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Unsupported IfcObjectPlacement:", l->entity);
|
||||
return false;
|
||||
}
|
||||
IfcSchema::IfcLocalPlacement* current = (IfcSchema::IfcLocalPlacement*)l;
|
||||
for (;;) {
|
||||
gp_Trsf trsf2;
|
||||
IfcSchema::IfcAxis2Placement* relplacement = current->RelativePlacement();
|
||||
if ( relplacement->is(IfcSchema::Type::IfcAxis2Placement3D) ) {
|
||||
IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcAxis2Placement3D*)relplacement,trsf2);
|
||||
trsf.PreMultiply(trsf2);
|
||||
}
|
||||
if ( current->hasPlacementRelTo() ) {
|
||||
IfcSchema::IfcObjectPlacement* relto = current->PlacementRelTo();
|
||||
if ( relto->is(IfcSchema::Type::IfcLocalPlacement) )
|
||||
current = (IfcSchema::IfcLocalPlacement*)current->PlacementRelTo();
|
||||
else break;
|
||||
} else break;
|
||||
}
|
||||
CACHE(IfcObjectPlacement,l,trsf)
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
|
||||
#include "../opencascade/OpenCascadeKernel.h"
|
||||
#include "../opencascade/OpenCascadeConversionResult.h"
|
||||
|
||||
IfcGeom::Representation::Serialization::Serialization(const Native& brep)
|
||||
: Representation(brep.settings())
|
||||
, _id(brep.getId())
|
||||
{
|
||||
TopoDS_Compound compound;
|
||||
BRep_Builder builder;
|
||||
builder.MakeCompound(compound);
|
||||
for (IfcGeom::ConversionResults::const_iterator it = brep.begin(); it != brep.end(); ++ it) {
|
||||
const TopoDS_Shape& s = ((OpenCascadeShape*) it->Shape())->shape();
|
||||
gp_GTrsf trsf = ((OpenCascadePlacement*)it->Placement())->trsf();
|
||||
|
||||
if (it->hasStyle() && it->Style().Diffuse()) {
|
||||
const IfcGeom::SurfaceStyle::ColorComponent& clr = *it->Style().Diffuse();
|
||||
_surface_styles.push_back(clr.R());
|
||||
_surface_styles.push_back(clr.G());
|
||||
_surface_styles.push_back(clr.B());
|
||||
} else {
|
||||
_surface_styles.push_back(-1.);
|
||||
_surface_styles.push_back(-1.);
|
||||
_surface_styles.push_back(-1.);
|
||||
}
|
||||
if (it->hasStyle() && it->Style().Transparency()) {
|
||||
_surface_styles.push_back(1. - *it->Style().Transparency());
|
||||
} else {
|
||||
_surface_styles.push_back(1.);
|
||||
}
|
||||
|
||||
if (settings().get(IteratorSettings::CONVERT_BACK_UNITS)) {
|
||||
gp_Trsf scale;
|
||||
scale.SetScaleFactor(1.0 / settings().unit_magnitude());
|
||||
trsf.PreMultiply(scale);
|
||||
}
|
||||
|
||||
const TopoDS_Shape moved_shape = IfcGeom::OpenCascadeKernel::apply_transformation(s, trsf);
|
||||
|
||||
builder.Add(compound, moved_shape);
|
||||
}
|
||||
std::stringstream sstream;
|
||||
BRepTools::Write(compound,sstream);
|
||||
_brep_data = sstream.str();
|
||||
}
|
||||
@@ -0,0 +1,657 @@
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <Poly_Triangulation.hxx>
|
||||
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
|
||||
#include <TColgp_Array2OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array2OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
|
||||
#include "OpenCascadeKernel.h"
|
||||
#include "OpenCascadeSerialization.h"
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
|
||||
std::vector<double> coords(3);
|
||||
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
|
||||
u = new U(coords);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
return convert_to_ifc(pnt, p, advanced);
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
convert_to_ifc(v, p, advanced);
|
||||
vertex = new IfcSchema::IfcVertexPoint(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcDirection *x, *z;
|
||||
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
|
||||
ax = 0;
|
||||
return 0;
|
||||
}
|
||||
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector(T& t, std::vector<U>& u) {
|
||||
u.reserve(t.Length());
|
||||
for (int i = t.Lower(); i <= t.Upper(); ++i) {
|
||||
u.push_back(t.Value(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void opencascade_array_to_vector2(T& t, std::vector< std::vector<U> >& u) {
|
||||
u.reserve(t.RowLength());
|
||||
for (int j = t.LowerRow(); j <= t.UpperRow(); ++j) {
|
||||
std::vector<U> v;
|
||||
v.reserve(t.ColLength());
|
||||
for (int i = t.LowerCol(); i <= t.UpperCol(); ++i) {
|
||||
v.push_back(t.Value(j, i));
|
||||
}
|
||||
u.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcKnotType::IfcKnotType opencascade_knotspec_to_ifc(GeomAbs_BSplKnotDistribution bspline_knot_spec) {
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
if (bspline_knot_spec == GeomAbs_Uniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_QuasiUniform) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
} else if (bspline_knot_spec == GeomAbs_PiecewiseBezier) {
|
||||
knot_spec = IfcSchema::IfcKnotType::IfcKnotType_PIECEWISE_BEZIER_KNOTS;
|
||||
}
|
||||
return knot_spec;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
|
||||
if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
IfcSchema::IfcDirection* d;
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
|
||||
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
|
||||
|
||||
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
|
||||
curve = new IfcSchema::IfcLine(p, v);
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
|
||||
|
||||
convert_to_ifc(circle->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
|
||||
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
|
||||
|
||||
convert_to_ifc(ellipse->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
|
||||
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points->push(p);
|
||||
}
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
|
||||
|
||||
std::vector<int> mults;
|
||||
std::vector<double> knots;
|
||||
std::vector<double> weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_mults(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_knots(1, bspline->NbKnots());
|
||||
TColStd_Array1OfReal bspline_weights(1, bspline->NbPoles());
|
||||
|
||||
bspline->Multiplicities(bspline_mults);
|
||||
bspline->Knots(bspline_knots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_mults, mults);
|
||||
opencascade_array_to_vector(bspline_knots, knots);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector<double>::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
if ((*it) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
curve = new IfcSchema::IfcBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
|
||||
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcPlane(place);
|
||||
return 1;
|
||||
}
|
||||
#ifdef USE_IFC4
|
||||
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
|
||||
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
|
||||
return 1;
|
||||
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
|
||||
typedef IfcTemplatedEntityListList<IfcSchema::IfcCartesianPoint> points_t;
|
||||
|
||||
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
|
||||
points_t::ptr points(new points_t);
|
||||
|
||||
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> ps;
|
||||
ps.reserve(bspline->NbVPoles());
|
||||
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
ps.push_back(p);
|
||||
}
|
||||
points->push(ps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
|
||||
IfcSchema::IfcKnotType::IfcKnotType knot_spec_v = opencascade_knotspec_to_ifc(bspline->VKnotDistribution());
|
||||
|
||||
if (knot_spec_u != knot_spec_v) {
|
||||
knot_spec_u = IfcSchema::IfcKnotType::IfcKnotType_UNSPECIFIED;
|
||||
}
|
||||
|
||||
std::vector<int> umults;
|
||||
std::vector<int> vmults;
|
||||
std::vector<double> uknots;
|
||||
std::vector<double> vknots;
|
||||
std::vector< std::vector<double> > weights;
|
||||
|
||||
TColStd_Array1OfInteger bspline_umults(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfInteger bspline_vmults(1, bspline->NbVKnots());
|
||||
TColStd_Array1OfReal bspline_uknots(1, bspline->NbUKnots());
|
||||
TColStd_Array1OfReal bspline_vknots(1, bspline->NbVKnots());
|
||||
TColStd_Array2OfReal bspline_weights(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
|
||||
bspline->UMultiplicities(bspline_umults);
|
||||
bspline->VMultiplicities(bspline_vmults);
|
||||
bspline->UKnots(bspline_uknots);
|
||||
bspline->VKnots(bspline_vknots);
|
||||
bspline->Weights(bspline_weights);
|
||||
|
||||
opencascade_array_to_vector(bspline_umults, umults);
|
||||
opencascade_array_to_vector(bspline_vmults, vmults);
|
||||
opencascade_array_to_vector(bspline_uknots, uknots);
|
||||
opencascade_array_to_vector(bspline_vknots, vknots);
|
||||
opencascade_array_to_vector2(bspline_weights, weights);
|
||||
|
||||
bool rational = false;
|
||||
for (std::vector< std::vector<double> >::const_iterator it = weights.begin(); it != weights.end(); ++it) {
|
||||
for (std::vector<double>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
|
||||
if ((*jt) != 1.) {
|
||||
rational = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rational) {
|
||||
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u
|
||||
);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
|
||||
double a, b;
|
||||
IfcSchema::IfcCurve* base;
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
if (!convert_to_ifc(crv, base, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue(a));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(b));
|
||||
|
||||
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
|
||||
double a, b;
|
||||
|
||||
TopExp_Explorer exp(e, TopAbs_VERTEX);
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v1 = TopoDS::Vertex(exp.Current());
|
||||
exp.Next();
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
|
||||
|
||||
IfcSchema::IfcVertex *vertex1, *vertex2;
|
||||
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
|
||||
if (crv.IsNull()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcCurve* curve;
|
||||
if (!convert_to_ifc(crv, curve, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo probably not correct
|
||||
const bool sense = e.Orientation() == TopAbs_FORWARD;
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
|
||||
bool polygonal = true;
|
||||
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b);
|
||||
if (crv.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
if (crv->DynamicType() != STANDARD_TYPE(Geom_Line)) {
|
||||
polygonal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polygonal && !advanced) {
|
||||
return 0;
|
||||
} else if (polygonal && !advanced) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
for (; exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
|
||||
points->push(p);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
loop = new IfcSchema::IfcPolyLoop(points);
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcEdge* edge;
|
||||
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(exp.Current(), edge, true)) {
|
||||
double a, b;
|
||||
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
|
||||
continue;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
|
||||
}
|
||||
loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
|
||||
TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
int index = 0;
|
||||
for (; exp.More(); exp.Next(), ++index) {
|
||||
IfcSchema::IfcLoop* loop;
|
||||
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
IfcSchema::IfcFaceBound* bnd;
|
||||
if (index == 0) {
|
||||
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
} else {
|
||||
bnd = new IfcSchema::IfcFaceBound(loop, true);
|
||||
}
|
||||
bounds->push(bnd);
|
||||
}
|
||||
|
||||
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
|
||||
|
||||
if (!is_planar && !advanced) {
|
||||
return 0;
|
||||
}
|
||||
if (is_planar && !advanced) {
|
||||
face = new IfcSchema::IfcFace(bounds);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcSurface* surface;
|
||||
if (!convert_to_ifc(surf, surface, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
|
||||
return 1;
|
||||
#else
|
||||
// No IfcAdvancedFace in Ifc2x3
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
IfcSchema::IfcFace* f;
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
|
||||
faces->push(f);
|
||||
}
|
||||
}
|
||||
item = new U(faces);
|
||||
return faces->size();
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcGeom::serialise(const TopoDS_Shape& shape, bool advanced) {
|
||||
#ifndef USE_IFC4
|
||||
advanced = false;
|
||||
#endif
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
|
||||
/// @todo CompSolids are not supported
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* rep = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
// First check if there is a solid with one or more shells
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcClosedShell* outer = 0;
|
||||
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
|
||||
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
|
||||
IfcSchema::IfcClosedShell* shell;
|
||||
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
/// @todo Are shells always in this order or does Orientation() needs to be checked?
|
||||
if (outer) {
|
||||
inner->push(shell);
|
||||
} else {
|
||||
outer = shell;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_IFC4
|
||||
if (advanced) {
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcAdvancedBrep(outer));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcFacetedBrep(outer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items->size() > 0) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is a shell
|
||||
IfcSchema::IfcOpenShell::list::ptr shells(new IfcSchema::IfcOpenShell::list);
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
shells->push(shell);
|
||||
}
|
||||
|
||||
if (shells->size() > 0) {
|
||||
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells->generalize()));
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
int face_count = convert_to_ifc(shape, shell, advanced);
|
||||
|
||||
if (face_count > 0) {
|
||||
items->push(shell);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), std::string("Brep"), items);
|
||||
} else {
|
||||
|
||||
// If not, see if there are any edges. Note that wires are skipped as
|
||||
// they are not commonly top-level geometrical descriptions in IFC.
|
||||
// Also note that edges are written as trimmed curves rather than edges.
|
||||
|
||||
IfcEntityList::ptr edges(new IfcEntityList);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcCurve* c;
|
||||
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
edges->push(c);
|
||||
}
|
||||
|
||||
if (edges->size() == 0) {
|
||||
return 0;
|
||||
} else if (edges->size() == 1) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
|
||||
} else {
|
||||
// A geometric set is created as that probably (?) makes more sense in IFC
|
||||
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges);
|
||||
items->push(curves);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(rep);
|
||||
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* IfcGeom::tesselate(const TopoDS_Shape& shape, double deflection) {
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
gp_Pnt pnt = nodes(i).Transformed(loc);
|
||||
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
||||
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
|
||||
vertices.push_back(cpnt);
|
||||
}
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(vertices[n1 - 1]);
|
||||
points->push(vertices[n2 - 1]);
|
||||
points->push(vertices[n3 - 1]);
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
|
||||
faces->push(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(surface_model);
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
||||
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
|
||||
return shapedef;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,517 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Implementations of the various conversion functions defined in EntityMapping.h *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt2d.hxx>
|
||||
#include <gp_Vec2d.hxx>
|
||||
#include <gp_Dir2d.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Ax2d.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_TrimmedCurve.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_MakeShell.hxx>
|
||||
#include <BRepBuilderAPI_MakeSolid.hxx>
|
||||
#include <BRepBuilderAPI_MakePolygon.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopLoc_Location.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
|
||||
#include <BRepAlgoAPI_Cut.hxx>
|
||||
#include <BRepOffsetAPI_Sewing.hxx>
|
||||
#include <BRepPrimAPI_MakePrism.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
#include <BRepFilletAPI_MakeFillet2d.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeFix_Solid.hxx>
|
||||
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
#include "OpenCascadeKernel.h"
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
|
||||
if ( getValue(GV_PLANEANGLE_UNIT)<0 ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity);
|
||||
|
||||
// Temporarily pretend we do have unit information
|
||||
setValue(GV_PLANEANGLE_UNIT,1.0);
|
||||
|
||||
bool succes_radians = false;
|
||||
bool succes_degrees = false;
|
||||
bool use_radians = false;
|
||||
bool use_degrees = false;
|
||||
|
||||
// First try radians
|
||||
TopoDS_Wire wire_radians, wire_degrees;
|
||||
try {
|
||||
succes_radians = IfcGeom::OpenCascadeKernel::convert(l,wire_radians);
|
||||
} catch (...) {}
|
||||
|
||||
// Now try degrees
|
||||
setValue(GV_PLANEANGLE_UNIT,0.0174532925199433);
|
||||
try {
|
||||
succes_degrees = IfcGeom::OpenCascadeKernel::convert(l,wire_degrees);
|
||||
} catch (...) {}
|
||||
|
||||
// Restore to unknown unit state
|
||||
setValue(GV_PLANEANGLE_UNIT,-1.0);
|
||||
|
||||
if ( succes_degrees && ! succes_radians ) {
|
||||
use_degrees = true;
|
||||
} else if ( succes_radians && ! succes_degrees ) {
|
||||
use_radians = true;
|
||||
} else if ( succes_radians && succes_degrees ) {
|
||||
if ( wire_degrees.Closed() && ! wire_radians.Closed() ) {
|
||||
use_degrees = true;
|
||||
} else if ( wire_radians.Closed() && ! wire_degrees.Closed() ) {
|
||||
use_radians = true;
|
||||
} else {
|
||||
// No heuristic left to prefer the one over the other,
|
||||
// apparently both variants are equally succesful.
|
||||
// The curve might be composed of only straight segments.
|
||||
// Let's go with the wire created using radians as that
|
||||
// at least is a SI unit.
|
||||
use_radians = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( use_radians ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve");
|
||||
wire = wire_radians;
|
||||
} else if ( use_degrees ) {
|
||||
Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve");
|
||||
wire = wire_degrees;
|
||||
}
|
||||
|
||||
return use_radians || use_degrees;
|
||||
}
|
||||
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
//TopoDS_Vertex last_vertex;
|
||||
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
|
||||
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
|
||||
TopoDS_Wire wire2;
|
||||
if ( !convert_wire(curve,wire2) ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity);
|
||||
continue;
|
||||
}
|
||||
if ( ! (*it)->SameSense() ) wire2.Reverse();
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
FTol.SetTolerance(wire2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_WIRE);
|
||||
/*if ( it != segments->begin() ) {
|
||||
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
|
||||
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
|
||||
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
|
||||
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
|
||||
Standard_Real distance = first.Distance(last);
|
||||
if ( distance > ALMOST_ZERO ) {
|
||||
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
|
||||
}
|
||||
}*/
|
||||
w.Add(wire2);
|
||||
//last_vertex = w.Vertex();
|
||||
if ( w.Error() != BRepBuilderAPI_WireDone ) {
|
||||
Logger::Message(Logger::LOG_ERROR,"Failed to join curve segments:",l->entity);
|
||||
|
||||
TopoDS_Vertex v1, v2, last;
|
||||
last = w.Vertex();
|
||||
|
||||
if (!last.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(last);
|
||||
ss << std::setprecision(4) << "Last vertex at (" << p.X() << " " << p.Y() << " " << p.Z() << ")";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str());
|
||||
}
|
||||
|
||||
TopExp::Vertices(wire2, v1, v2);
|
||||
if (!v1.IsNull()) {
|
||||
std::stringstream ss;
|
||||
gp_Pnt p = BRep_Tool::Pnt(v1);
|
||||
ss << std::setprecision(4) << "Segment starts at (" << p.X() << " " << p.Y() << " " << p.Z() << ") for:";
|
||||
Logger::Message(Logger::LOG_NOTICE, ss.str(), (*it)->entity);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
|
||||
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
|
||||
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
|
||||
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
|
||||
Handle(Geom_Curve) curve;
|
||||
if ( !convert_curve(basis_curve,curve) ) return false;
|
||||
bool trim_cartesian = l->MasterRepresentation() == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN;
|
||||
IfcEntityList::ptr trims1 = l->Trim1();
|
||||
IfcEntityList::ptr trims2 = l->Trim2();
|
||||
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
|
||||
double flts[2];
|
||||
gp_Pnt pnts[2];
|
||||
bool has_flts[2] = {false,false};
|
||||
bool has_pnts[2] = {false,false};
|
||||
BRepBuilderAPI_MakeWire w;
|
||||
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[sense_agreement] );
|
||||
has_pnts[sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[sense_agreement] = value * parameterFactor;
|
||||
has_flts[sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
|
||||
IfcUtil::IfcBaseClass* i = *it;
|
||||
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
|
||||
IfcGeom::OpenCascadeKernel::convert((IfcSchema::IfcCartesianPoint*)i, pnts[1-sense_agreement] );
|
||||
has_pnts[1-sense_agreement] = true;
|
||||
} else if ( i->is(IfcSchema::Type::IfcParameterValue) ) {
|
||||
const double value = *((IfcSchema::IfcParameterValue*)i);
|
||||
flts[1-sense_agreement] = value * parameterFactor;
|
||||
has_flts[1-sense_agreement] = true;
|
||||
}
|
||||
}
|
||||
trim_cartesian &= has_pnts[0] && has_pnts[1];
|
||||
bool trim_cartesian_failed = !trim_cartesian;
|
||||
if ( trim_cartesian ) {
|
||||
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
|
||||
return false;
|
||||
}
|
||||
ShapeFix_ShapeTolerance FTol;
|
||||
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
|
||||
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
|
||||
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
|
||||
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
|
||||
if ( ! e.IsDone() ) {
|
||||
BRepBuilderAPI_EdgeError err = e.Error();
|
||||
if ( err == BRepBuilderAPI_PointProjectionFailed ) {
|
||||
Logger::Message(Logger::LOG_WARNING,"Point projection failed for:",l->entity);
|
||||
trim_cartesian_failed = true;
|
||||
}
|
||||
} else {
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
}
|
||||
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
|
||||
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
|
||||
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
|
||||
// the vector is normalised when passed to Geom_Line constructor the magnitude
|
||||
// needs to be factored in with the IfcParameterValue here.
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcLine) ) {
|
||||
IfcSchema::IfcLine* line = static_cast<IfcSchema::IfcLine*>(basis_curve);
|
||||
const double magnitude = line->Dir()->Magnitude();
|
||||
flts[0] *= magnitude; flts[1] *= magnitude;
|
||||
}
|
||||
if ( basis_curve->is(IfcSchema::Type::IfcEllipse) ) {
|
||||
IfcSchema::IfcEllipse* ellipse = static_cast<IfcSchema::IfcEllipse*>(basis_curve);
|
||||
double x = ellipse->SemiAxis1() * getValue(GV_LENGTH_UNIT);
|
||||
double y = ellipse->SemiAxis2() * getValue(GV_LENGTH_UNIT);
|
||||
const bool rotated = y > x;
|
||||
if (rotated) {
|
||||
flts[0] -= M_PI / 2.;
|
||||
flts[1] -= M_PI / 2.;
|
||||
}
|
||||
}
|
||||
if ( isConic && ALMOST_THE_SAME(fmod(flts[1]-flts[0],M_PI*2.),0.) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(curve));
|
||||
} else {
|
||||
BRepBuilderAPI_MakeEdge e (curve,flts[0],flts[1]);
|
||||
w.Add(e.Edge());
|
||||
}
|
||||
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
|
||||
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
|
||||
}
|
||||
if ( w.IsDone() ) {
|
||||
wire = w.Wire();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
TColgp_SequenceOfPnt polygon;
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
gp_Pnt pnt;
|
||||
IfcGeom::OpenCascadeKernel::convert(*it, pnt);
|
||||
polygon.Append(pnt);
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_duplicate_points_from_loop(polygon, false);
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
}
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
|
||||
|
||||
// Parse and store the points in a sequence
|
||||
TColgp_SequenceOfPnt polygon;
|
||||
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
|
||||
gp_Pnt pnt;
|
||||
IfcGeom::OpenCascadeKernel::convert(*it, pnt);
|
||||
polygon.Append(pnt);
|
||||
}
|
||||
|
||||
// A loop should consist of at least three vertices
|
||||
int original_count = polygon.Length();
|
||||
if (original_count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove points that are too close to one another
|
||||
remove_duplicate_points_from_loop(polygon, true);
|
||||
|
||||
int count = polygon.Length();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakePolygon w;
|
||||
for (int i = 1; i <= polygon.Length(); ++i) {
|
||||
w.Add(polygon.Value(i));
|
||||
}
|
||||
w.Close();
|
||||
|
||||
result = w.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcArbitraryOpenProfileDef* l, TopoDS_Wire& result) {
|
||||
return convert_wire(l->Curve(), result);
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdgeCurve* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!IfcGeom::OpenCascadeKernel::convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!IfcGeom::OpenCascadeKernel::convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
Handle_Geom_Curve crv;
|
||||
|
||||
// The lack of a clear separation between topological and geometrical entities
|
||||
// is starting to get problematic. If the underlying curve is bounded it is
|
||||
// assumed that a topological wire can be crafted from it. After which an
|
||||
// attempt is made to reconstruct it from the individual curves and the vertices
|
||||
// of the IfcEdgeCurve.
|
||||
const bool is_bounded = l->EdgeGeometry()->is(IfcSchema::Type::IfcBoundedCurve);
|
||||
|
||||
if (!is_bounded && convert_curve(l->EdgeGeometry(), crv)) {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, p1, p2));
|
||||
result = mw;
|
||||
return true;
|
||||
} else if (is_bounded && convert_wire(l->EdgeGeometry(), result)) {
|
||||
if (!l->SameSense()) {
|
||||
result.Reverse();
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
|
||||
while (exp.More()) {
|
||||
const TopoDS_Edge& ed = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) ecrv = BRep_Tool::Curve(ed, u1, u2);
|
||||
exp.Next();
|
||||
const bool last = !exp.More();
|
||||
|
||||
gp_Pnt a, b;
|
||||
|
||||
if (first && last) {
|
||||
a = p1;
|
||||
b = p2;
|
||||
} else if (first) {
|
||||
a = p1;
|
||||
ecrv->D0(u2, b);
|
||||
} else if (last) {
|
||||
ecrv->D0(u1, a);
|
||||
b = p2;
|
||||
} else {
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, u1, u2));
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
BRep_Builder builder;
|
||||
TopoDS_Vertex v1, v2;
|
||||
/// @todo project first and emit warnings accordingly
|
||||
builder.MakeVertex(v1, a, getValue(GV_PRECISION));
|
||||
builder.MakeVertex(v2, b, getValue(GV_PRECISION));
|
||||
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(ecrv, v1, v2));
|
||||
|
||||
first = false;
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdgeLoop* l, TopoDS_Wire& result) {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList();
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) {
|
||||
TopoDS_Wire w;
|
||||
if (convert_wire(*it, w)) {
|
||||
mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value()));
|
||||
}
|
||||
}
|
||||
result = mw;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcEdge* l, TopoDS_Wire& result) {
|
||||
if (!l->EdgeStart()->is(IfcSchema::Type::IfcVertexPoint) || !l->EdgeEnd()->is(IfcSchema::Type::IfcVertexPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcVertexPoints are supported for EdgeStart and -End", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
IfcSchema::IfcPoint* pnt1 = ((IfcSchema::IfcVertexPoint*) l->EdgeStart())->VertexGeometry();
|
||||
IfcSchema::IfcPoint* pnt2 = ((IfcSchema::IfcVertexPoint*) l->EdgeEnd())->VertexGeometry();
|
||||
if (!pnt1->is(IfcSchema::Type::IfcCartesianPoint) || !pnt2->is(IfcSchema::Type::IfcCartesianPoint)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Only IfcCartesianPoints are supported for VertexGeometry", l->entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
gp_Pnt p1, p2;
|
||||
if (!convert(((IfcSchema::IfcCartesianPoint*)pnt1), p1) ||
|
||||
!convert(((IfcSchema::IfcCartesianPoint*)pnt2), p2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(p1, p2));
|
||||
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcOrientedEdge* l, TopoDS_Wire& result) {
|
||||
if (convert_wire(l->EdgeElement(), result)) {
|
||||
if (!l->Orientation()) {
|
||||
result.Reverse();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IfcGeom::OpenCascadeKernel::convert(const IfcSchema::IfcSubedge* l, TopoDS_Wire& result) {
|
||||
TopoDS_Wire temp;
|
||||
if (convert_wire(l->ParentEdge(), result) && convert((IfcSchema::IfcEdge*) l, temp)) {
|
||||
TopExp_Explorer exp(result, TopAbs_EDGE);
|
||||
TopoDS_Edge edge = TopoDS::Edge(exp.Current());
|
||||
Standard_Real u1, u2;
|
||||
Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u1, u2);
|
||||
TopoDS_Vertex v1, v2;
|
||||
TopExp::Vertices(temp, v1, v2);
|
||||
BRepBuilderAPI_MakeWire mw;
|
||||
mw.Add(BRepBuilderAPI_MakeEdge(crv, v1, v2));
|
||||
result = mw.Wire();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
#define IFCGEOMOPENCASCADEREPRESENTATION_H
|
||||
|
||||
#include <BRepMesh_IncrementalMesh.hxx>
|
||||
#include <BRepGProp_Face.hxx>
|
||||
|
||||
#include <Poly_Triangulation.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColgp_Array1OfPnt2d.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <GCPnts_QuasiUniformDeflection.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class OpenCascadePlacement : public ConversionResultPlacement {
|
||||
public:
|
||||
OpenCascadePlacement(const gp_GTrsf& trsf)
|
||||
: trsf_(trsf)
|
||||
{}
|
||||
|
||||
const gp_GTrsf& trsf() const { return trsf_; }
|
||||
operator const gp_GTrsf& () { return trsf_; }
|
||||
|
||||
virtual double Value(int i, int j) const {
|
||||
return trsf_.Value(i, j);
|
||||
}
|
||||
virtual void Multiply(const ConversionResultPlacement* other) {
|
||||
trsf_.Multiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
virtual void PreMultiply(const ConversionResultPlacement* other) {
|
||||
trsf_.PreMultiply(((OpenCascadePlacement*)other)->trsf_);
|
||||
}
|
||||
virtual ConversionResultPlacement* clone() const {
|
||||
return new OpenCascadePlacement(trsf_);
|
||||
}
|
||||
private:
|
||||
gp_GTrsf trsf_;
|
||||
};
|
||||
|
||||
class OpenCascadeShape : public ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape)
|
||||
{}
|
||||
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
|
||||
virtual void Triangulate(const IfcGeom::IteratorSettings & settings, const IfcGeom::ConversionResultPlacement * place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const;
|
||||
virtual void Serialize(std::string&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
virtual ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
private:
|
||||
TopoDS_Shape shape_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef OPENCASADE_KERNEL_H
|
||||
#define OPENCASADE_KERNEL_H
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Mat.hxx>
|
||||
#include <gp_Mat2d.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <gp_GTrsf2d.hxx>
|
||||
#include <gp_Trsf.hxx>
|
||||
#include <gp_Trsf2d.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <TColgp_SequenceOfPnt.hxx>
|
||||
#include <TopTools_ListOfShape.hxx>
|
||||
#include <Geom_Surface.hxx>
|
||||
|
||||
// Define this in case you want to conserve memory usage at all cost. This has been
|
||||
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
|
||||
// #define NO_CACHE
|
||||
|
||||
#ifdef NO_CACHE
|
||||
|
||||
#define IN_CACHE(T,E,t,e)
|
||||
#define CACHE(T,E,e)
|
||||
|
||||
#else
|
||||
|
||||
#define IN_CACHE(T,E,t,e) std::map<int,t>::const_iterator it = cache.T.find(E->entity->id());\
|
||||
if ( it != cache.T.end() ) { e = it->second; return true; }
|
||||
#define CACHE(T,E,e) cache.T[E->entity->id()] = e;
|
||||
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
class IFC_GEOM_API Cache {
|
||||
public:
|
||||
#include "EntityMappingCreateCache.h"
|
||||
std::map<int, TopoDS_Shape> Shape;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API OpenCascadeKernel : public AbstractKernel {
|
||||
public:
|
||||
|
||||
#ifndef NO_CACHE
|
||||
Cache cache;
|
||||
#endif
|
||||
|
||||
IfcGeom::ShapeType shape_type(const IfcUtil::IfcBaseClass* L);
|
||||
|
||||
bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face);
|
||||
bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire);
|
||||
bool convert_shapes(const IfcUtil::IfcBaseClass* L, ConversionResults& result);
|
||||
bool convert_shape(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse);
|
||||
bool convert_wire(const IfcUtil::IfcBaseClass* L, TopoDS_Wire& result);
|
||||
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
|
||||
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Shape& result);
|
||||
|
||||
|
||||
bool convert_layerset(const IfcSchema::IfcProduct*, std::vector<Handle_Geom_Surface>&, std::vector<const SurfaceStyle*>&, std::vector<double>&);
|
||||
bool apply_layerset(const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool apply_folded_layerset(const ConversionResults&, const std::vector< std::vector<Handle_Geom_Surface> >&, const std::vector<const SurfaceStyle*>&, ConversionResults&);
|
||||
bool fold_layers(const IfcSchema::IfcWall*, const ConversionResults&, const std::vector<Handle_Geom_Surface>&, const std::vector<double>&, std::vector< std::vector<Handle_Geom_Surface> >&);
|
||||
|
||||
bool split_solid_by_surface(const TopoDS_Shape&, const Handle_Geom_Surface&, TopoDS_Shape&, TopoDS_Shape&);
|
||||
bool split_solid_by_shell(const TopoDS_Shape&, const TopoDS_Shape& s, TopoDS_Shape&, TopoDS_Shape&);
|
||||
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&);
|
||||
const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&);
|
||||
const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&);
|
||||
bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&);
|
||||
bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector<gp_Pnt>&);
|
||||
bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair<Handle_Geom_Surface, Handle_Geom_Curve> >&);
|
||||
bool closest(const gp_Pnt&, const std::vector<gp_Pnt>&, gp_Pnt&);
|
||||
bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d);
|
||||
bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1);
|
||||
int count(const TopoDS_Shape&, TopAbs_ShapeEnum);
|
||||
|
||||
|
||||
bool find_wall_end_points(const IfcSchema::IfcWall*, gp_Pnt& start, gp_Pnt& end);
|
||||
|
||||
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
|
||||
bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid);
|
||||
bool is_compound(const TopoDS_Shape& shape);
|
||||
bool is_convex(const TopoDS_Wire& wire);
|
||||
TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent);
|
||||
gp_Pln plane_from_face(const TopoDS_Face& face);
|
||||
gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true);
|
||||
const TopoDS_Shape& ensure_fit_for_subtraction(const TopoDS_Shape& shape, TopoDS_Shape& solid);
|
||||
bool profile_helper(int numVerts, double* verts, int numFillets, int* filletIndices, double* filletRadii, gp_Trsf2d trsf, TopoDS_Shape& face);
|
||||
double shape_volume(const TopoDS_Shape& s);
|
||||
double face_area(const TopoDS_Face& f);
|
||||
void apply_tolerance(TopoDS_Shape& s, double t);
|
||||
|
||||
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
|
||||
void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol = -1.);
|
||||
void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol = -1.);
|
||||
bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&);
|
||||
void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed);
|
||||
bool approximate_plane_through_wire(const TopoDS_Wire&, gp_Pln&);
|
||||
bool flatten_wire(TopoDS_Wire&);
|
||||
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&);
|
||||
static TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&);
|
||||
|
||||
bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes);
|
||||
bool convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes);
|
||||
|
||||
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 = Cache();
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool is_identity_transform(IfcUtil::IfcBaseClass*);
|
||||
virtual IfcGeom::NativeElement<double>* create_brep_for_representation_and_product(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*);
|
||||
virtual IfcGeom::NativeElement<double>* create_brep_for_processed_representation(
|
||||
const IteratorSettings&, IfcSchema::IfcRepresentation*, IfcSchema::IfcProduct*, IfcGeom::NativeElement<double>*);
|
||||
|
||||
#include "EntityMappingDeclaration.h"
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef OPENCASCADESERIALIZATION_H
|
||||
#define OPENCASCADESERIALIZATION_H
|
||||
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* tesselate(const TopoDS_Shape& shape, double deflection);
|
||||
IfcSchema::IfcProductDefinitionShape* serialise(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,194 @@
|
||||
|
||||
|
||||
#include "../../../ifcgeom/IfcGeom.h"
|
||||
#include "../../../ifcgeom/IfcGeomIteratorSettings.h"
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
|
||||
void IfcGeom::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings& settings, const IfcGeom::ConversionResultPlacement* place, IfcGeom::Representation::Triangulation<double>* t, int surface_style_id) const {
|
||||
|
||||
const TopoDS_Shape& s = shape_;
|
||||
const gp_GTrsf& trsf = dynamic_cast<const OpenCascadePlacement*>(place)->trsf();
|
||||
|
||||
// Triangulate the shape
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, settings.deflection_tolerance());
|
||||
} catch (...) {
|
||||
|
||||
// TODO: Catch outside
|
||||
// Logger::Message(Logger::LOG_ERROR,"Failed to triangulate shape:",ifc_file->entityById(_id)->entity);
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterates over the faces of the shape
|
||||
int num_faces = 0;
|
||||
TopExp_Explorer exp;
|
||||
for (exp.Init(s, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
|
||||
TopoDS_Face face = TopoDS::Face(exp.Current());
|
||||
TopLoc_Location loc;
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
const gp_Mat rotation_matrix = trsf.VectorialPart();
|
||||
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
std::map<std::pair<int, int>, int> edgecount;
|
||||
std::vector<std::pair<int, int> > edges_temp;
|
||||
|
||||
const TColgp_Array1OfPnt& nodes = tri->Nodes();
|
||||
const TColgp_Array1OfPnt2d& uvs = tri->UVNodes();
|
||||
std::vector<gp_XYZ> coords;
|
||||
BRepGProp_Face prop(face);
|
||||
std::map<int, int> dict;
|
||||
|
||||
// Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly.
|
||||
const bool calculate_normals = !settings.get(IteratorSettings::WELD_VERTICES) &&
|
||||
!settings.get(IteratorSettings::NO_NORMALS);
|
||||
|
||||
for (int i = 1; i <= nodes.Length(); ++i) {
|
||||
coords.push_back(nodes(i).Transformed(loc).XYZ());
|
||||
trsf.Transforms(*coords.rbegin());
|
||||
const gp_XYZ& last = *coords.rbegin();
|
||||
dict[i] = t->addVertex(surface_style_id, last.X(), last.Y(), last.Z());
|
||||
|
||||
if (calculate_normals) {
|
||||
const gp_Pnt2d& uv = uvs(i);
|
||||
gp_Pnt p;
|
||||
gp_Vec normal_direction;
|
||||
prop.Normal(uv.X(), uv.Y(), p, normal_direction);
|
||||
gp_Vec normal(0., 0., 0.);
|
||||
if (normal_direction.Magnitude() > ALMOST_ZERO) {
|
||||
normal = gp_Dir(normal_direction.XYZ() * rotation_matrix);
|
||||
}
|
||||
t->normals().push_back(static_cast<double>(normal.X()));
|
||||
t->normals().push_back(static_cast<double>(normal.Y()));
|
||||
t->normals().push_back(static_cast<double>(normal.Z()));
|
||||
}
|
||||
}
|
||||
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
if (face.Orientation() == TopAbs_REVERSED)
|
||||
triangles(i).Get(n3, n2, n1);
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
/* An alternative would be to calculate normals based
|
||||
* on the coordinates of the mesh vertices */
|
||||
/*
|
||||
const gp_XYZ pt1 = coords[n1-1];
|
||||
const gp_XYZ pt2 = coords[n2-1];
|
||||
const gp_XYZ pt3 = coords[n3-1];
|
||||
const gp_XYZ v1 = pt2-pt1;
|
||||
const gp_XYZ v2 = pt3-pt2;
|
||||
gp_Dir normal = gp_Dir(v1^v2);
|
||||
_normals.push_back((float)normal.X());
|
||||
_normals.push_back((float)normal.Y());
|
||||
_normals.push_back((float)normal.Z());
|
||||
*/
|
||||
|
||||
t->faces().push_back(dict[n1]);
|
||||
t->faces().push_back(dict[n2]);
|
||||
t->faces().push_back(dict[n3]);
|
||||
|
||||
t->material_ids().push_back(surface_style_id);
|
||||
|
||||
t->addEdge(dict[n1], dict[n2], edgecount, edges_temp);
|
||||
t->addEdge(dict[n2], dict[n3], edgecount, edges_temp);
|
||||
t->addEdge(dict[n3], dict[n1], edgecount, edges_temp);
|
||||
}
|
||||
for (std::vector<std::pair<int, int> >::const_iterator jt = edges_temp.begin(); jt != edges_temp.end(); ++jt) {
|
||||
if (edgecount[*jt] == 1) {
|
||||
// non manifold edge, face boundary
|
||||
t->edges().push_back(jt->first);
|
||||
t->edges().push_back(jt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Unimplemented
|
||||
if (!t.normals().empty() && settings().get(IfcGeom::IteratorSettings::GENERATE_UVS)) {
|
||||
t.uvs() = box_project_uvs(t.verts(), t.normals());
|
||||
}
|
||||
*/
|
||||
|
||||
if (num_faces == 0) {
|
||||
// Edges are only emitted if there are no faces. A mixed representation of faces
|
||||
// and loose edges is discouraged by the standard. An alternative would be to use
|
||||
// TopExp_Explorer texp(s, TopAbs_EDGE, TopAbs_FACE) to find edges that do not
|
||||
// belong to any face.
|
||||
for (TopExp_Explorer texp(s, TopAbs_EDGE); texp.More(); texp.Next()) {
|
||||
BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current()));
|
||||
GCPnts_QuasiUniformDeflection tessellater(crv, settings.deflection_tolerance());
|
||||
int n = tessellater.NbPoints();
|
||||
int start = (int)t->verts().size() / 3;
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
gp_XYZ p = tessellater.Value(i).XYZ();
|
||||
|
||||
/*
|
||||
// In case you want direction arrows on your edges
|
||||
double u = tessellater.Parameter(i);
|
||||
gp_XYZ p2, p3;
|
||||
gp_Pnt tmp;
|
||||
gp_Vec tmp2;
|
||||
crv.D1(u, tmp, tmp2);
|
||||
gp_Dir d1, d2, d3, d4;
|
||||
d1 = tmp2;
|
||||
if (texp.Current().Orientation() == TopAbs_REVERSED) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (fabs(d1.Z()) < 0.5) {
|
||||
d2 = d1.Crossed(gp::DZ());
|
||||
} else {
|
||||
d2 = d1.Crossed(gp::DY());
|
||||
}
|
||||
d3 = d1.XYZ() + d2.XYZ();
|
||||
d4 = d1.XYZ() - d2.XYZ();
|
||||
p2 = p - d3.XYZ() / 10.;
|
||||
p3 = p - d4.XYZ() / 10.;
|
||||
trsf.Transforms(p2);
|
||||
trsf.Transforms(p3);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_material_ids.push_back(surface_style_id);
|
||||
_verts.push_back(static_cast<P>(p2.X()));
|
||||
_verts.push_back(static_cast<P>(p2.Y()));
|
||||
_verts.push_back(static_cast<P>(p2.Z()));
|
||||
_verts.push_back(static_cast<P>(p3.X()));
|
||||
_verts.push_back(static_cast<P>(p3.Y()));
|
||||
_verts.push_back(static_cast<P>(p3.Z()));
|
||||
*/
|
||||
|
||||
trsf.Transforms(p);
|
||||
|
||||
t->material_ids().push_back(surface_style_id);
|
||||
|
||||
t->verts().push_back(static_cast<double>(p.X()));
|
||||
t->verts().push_back(static_cast<double>(p.Y()));
|
||||
t->verts().push_back(static_cast<double>(p.Z()));
|
||||
|
||||
if (i > 1) {
|
||||
t->edges().push_back(start + i - 2);
|
||||
t->edges().push_back(start + i - 1);
|
||||
// _edges.push_back(start + 3 * (i - 2) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
|
||||
// _edges.push_back(start + 3 * (i - 1) + 0);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 1);
|
||||
// _edges.push_back(start + 3 * (i - 1) + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BRepTools::Clean(s);
|
||||
}
|
||||
Reference in New Issue
Block a user