2012-07-19 18:26:47 +00:00
/********************************************************************************
2011-07-25 14:56:40 +00:00
* *
* 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 IfcGeom.h *
* *
********************************************************************************/
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
# include <set>
2012-06-25 15:08:58 +00:00
# include <cassert>
2014-07-24 11:14:54 +00:00
# include <algorithm>
2012-06-25 15:08:58 +00:00
2011-07-25 14:56:40 +00:00
# include <gp_Pnt.hxx>
# include <gp_Vec.hxx>
# include <gp_Dir.hxx>
# include <gp_Pnt2d.hxx>
# include <gp_Vec2d.hxx>
# include <gp_Dir2d.hxx>
2011-10-23 17:11:06 +00:00
# include <gp_Mat.hxx>
# include <gp_Mat2d.hxx>
# include <gp_GTrsf.hxx>
# include <gp_GTrsf2d.hxx>
2011-07-25 14:56:40 +00:00
# include <gp_Trsf.hxx>
# include <gp_Trsf2d.hxx>
# include <gp_Ax3.hxx>
# include <gp_Ax2d.hxx>
# include <gp_Pln.hxx>
# include <gp_Circ.hxx>
2018-09-12 13:26:11 +02:00
# include <boost/range/irange.hpp>
# include <boost/range/algorithm_ext/push_back.hpp>
2011-07-25 14:56:40 +00:00
# include <TColgp_Array1OfPnt.hxx>
# include <TColgp_Array1OfPnt2d.hxx>
# include <TColStd_Array1OfReal.hxx>
# include <TColStd_Array1OfInteger.hxx>
2015-10-07 17:33:30 +02:00
2011-07-25 14:56:40 +00:00
# include <Geom_Line.hxx>
# include <Geom_Circle.hxx>
# include <Geom_Ellipse.hxx>
# include <Geom_TrimmedCurve.hxx>
2015-10-07 17:33:30 +02:00
# include <Geom_Plane.hxx>
# include <Geom_OffsetCurve.hxx>
# include <Geom_OffsetSurface.hxx>
# include <Geom_CylindricalSurface.hxx>
# include <Geom_SurfaceOfLinearExtrusion.hxx>
# include <GeomAPI_IntCS.hxx>
# include <GeomAPI_IntSS.hxx>
# include <BRepBndLib.hxx>
2011-07-25 14:56:40 +00:00
# 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>
2016-02-18 13:17:15 +01:00
# include <TopoDS_CompSolid.hxx>
# include <TopExp.hxx>
2011-07-25 14:56:40 +00:00
# include <TopExp_Explorer.hxx>
# include <BRepPrimAPI_MakePrism.hxx>
# include <BRepBuilderAPI_MakeShell.hxx>
# include <BRepBuilderAPI_MakeSolid.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <BRepAlgoAPI_Cut.hxx>
2014-07-06 14:21:56 +00:00
# include <BRepAlgoAPI_Fuse.hxx>
2015-10-07 17:33:30 +02:00
# include <BRepAlgoAPI_Common.hxx>
2017-02-16 15:54:34 +01:00
# include <BRepAlgoAPI_BooleanOperation.hxx>
2011-07-25 14:56:40 +00:00
2016-04-16 14:47:09 +02:00
# include <BRepAlgo_NormalProjection.hxx>
2011-07-25 14:56:40 +00:00
# include <ShapeFix_Shape.hxx>
# include <ShapeFix_ShapeTolerance.hxx>
# include <ShapeFix_Solid.hxx>
2015-10-07 17:33:30 +02:00
# include <ShapeAnalysis_Curve.hxx>
2018-04-18 11:33:57 +02:00
# include <ShapeAnalysis_Wire.hxx>
2015-10-07 17:33:30 +02:00
# include <ShapeAnalysis_Surface.hxx>
2017-02-16 15:54:34 +01:00
# include <ShapeAnalysis_ShapeTolerance.hxx>
2015-10-07 17:33:30 +02:00
2011-07-25 14:56:40 +00:00
# include <BRepFilletAPI_MakeFillet2d.hxx>
# include <TopLoc_Location.hxx>
2011-10-12 16:43:29 +00:00
# include <GProp_GProps.hxx>
# include <BRepGProp.hxx>
2018-05-05 16:09:12 +02:00
# include <BRepBuilderAPI_Copy.hxx>
2016-05-03 11:01:47 +02:00
# include <BRepBuilderAPI_Transform.hxx>
2011-10-23 17:11:06 +00:00
# include <BRepBuilderAPI_GTransform.hxx>
2012-03-13 11:56:52 +00:00
# include <BRepCheck_Analyzer.hxx>
# include <BRepGProp_Face.hxx>
2015-01-19 16:02:34 +00:00
# include <BRepMesh_IncrementalMesh.hxx>
2012-11-04 16:26:33 +00:00
# include <BRepTools.hxx>
2016-04-16 14:47:09 +02:00
# include <BRepTools_WireExplorer.hxx>
2012-11-04 16:26:33 +00:00
# include <Poly_Triangulation.hxx>
# include <Poly_Array1OfTriangle.hxx>
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
# include <TopTools_IndexedMapOfShape.hxx>
# include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
# include <TopTools_ListIteratorOfListOfShape.hxx>
2017-04-03 14:55:34 +02:00
# include <TopTools_HSequenceOfShape.hxx>
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
2015-10-07 17:33:30 +02:00
# include <BOPAlgo_PaveFiller.hxx>
# include <BOPAlgo_BOP.hxx>
# include <GCPnts_AbscissaPoint.hxx>
2016-12-09 16:40:14 +01:00
# include <BRepClass3d_SolidClassifier.hxx>
2018-04-18 11:33:57 +02:00
# include <GeomAPI_ExtremaCurveCurve.hxx>
2018-08-20 11:46:26 +02:00
# include <Extrema_ExtPC.hxx>
# include <BRepAdaptor_Curve.hxx>
2016-01-22 17:27:28 +01:00
# include <Standard_Version.hxx>
2015-02-17 19:48:41 +00:00
# include "../ifcparse/IfcSIPrefix.h"
2015-10-07 17:33:30 +02:00
# include "../ifcparse/IfcFile.h"
2011-08-24 12:21:07 +00:00
# include "../ifcgeom/IfcGeom.h"
2018-09-12 13:26:11 +02:00
# include "../ifcgeom/IfcGeomTree.h"
2011-07-25 14:56:40 +00:00
2016-01-25 13:30:33 +01:00
# if OCC_VERSION_HEX < 0x60900
2016-02-18 13:17:15 +01:00
# ifdef _MSC_VER
2016-01-25 13:30:33 +01:00
# pragma message("warning: You are linking against Open CASCADE version " OCC_VERSION_COMPLETE ". Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade.")
2016-02-18 13:17:15 +01:00
# else
# warning "You are linking against linking against an older version of Open CASCADE. Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade."
# endif
2016-01-25 13:30:33 +01:00
# endif
2018-09-21 10:22:24 +02:00
namespace {
TopTools_ListOfShape copy_operand ( const TopTools_ListOfShape & l ) {
# if OCC_VERSION_HEX < 0x70000
TopTools_ListOfShape r ;
TopTools_ListIteratorOfListOfShape it ( l ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
r . Append ( BRepBuilderAPI_Copy ( it . Value ( ) ) ) ;
}
return r ;
# else
// On OCCT 7.0 and higher BRepAlgoAPI_BuilderAlgo::SetNonDestructive(true) is
// called. Not entirely sure on the behaviour before 7.0, so overcautiously
// create copies.
return l ;
# endif
}
TopoDS_Shape copy_operand ( const TopoDS_Shape & s ) {
# if OCC_VERSION_HEX < 0x70000
return BRepBuilderAPI_Copy ( s ) ;
# else
return s ;
# endif
}
double min_edge_length ( const TopoDS_Shape & a ) {
double min_edge_len = std : : numeric_limits < double > : : infinity ( ) ;
TopExp_Explorer exp ( a , TopAbs_EDGE ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
GProp_GProps prop ;
BRepGProp : : LinearProperties ( exp . Current ( ) , prop ) ;
double l = prop . Mass ( ) ;
if ( l < min_edge_len ) {
min_edge_len = l ;
}
}
return min_edge_len ;
}
double min_vertex_edge_distance ( const TopoDS_Shape & a , double t ) {
TopExp_Explorer exp ( a , TopAbs_VERTEX ) ;
double M = std : : numeric_limits < double > : : infinity ( ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
if ( exp . Current ( ) . Orientation ( ) ! = TopAbs_FORWARD ) {
continue ;
}
const TopoDS_Vertex & v = TopoDS : : Vertex ( exp . Current ( ) ) ;
gp_Pnt p = BRep_Tool : : Pnt ( v ) ;
TopExp_Explorer exp2 ( a , TopAbs_EDGE ) ;
for ( ; exp2 . More ( ) ; exp2 . Next ( ) ) {
const TopoDS_Edge & e = TopoDS : : Edge ( exp2 . Current ( ) ) ;
TopoDS_Vertex v1 , v2 ;
TopExp : : Vertices ( e , v1 , v2 ) ;
if ( v . IsSame ( v1 ) | | v . IsSame ( v2 ) ) {
continue ;
}
BRepAdaptor_Curve crv ( e ) ;
Extrema_ExtPC ext ( p , crv ) ;
if ( ! ext . IsDone ( ) ) {
continue ;
}
for ( int i = 1 ; i < = ext . NbExt ( ) ; + + i ) {
const double m = sqrt ( ext . SquareDistance ( i ) ) ;
if ( m < M & & m > t ) {
M = m ;
}
}
}
}
return M ;
}
bool is_manifold ( const TopoDS_Shape & a ) {
TopTools_IndexedDataMapOfShapeListOfShape map ;
TopExp : : MapShapesAndAncestors ( a , TopAbs_EDGE , TopAbs_FACE , map ) ;
for ( int i = 1 ; i < = map . Extent ( ) ; + + i ) {
if ( map . FindFromIndex ( i ) . Extent ( ) ! = 2 ) {
return false ;
}
}
return true ;
}
bool is_manifold ( const TopTools_ListOfShape & l ) {
TopTools_ListOfShape r ;
TopTools_ListIteratorOfListOfShape it ( l ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
if ( ! is_manifold ( it . Value ( ) ) ) {
return false ;
}
}
return true ;
}
void bounding_box_overlap ( double p , const TopoDS_Shape & a , const TopTools_ListOfShape & b , TopTools_ListOfShape & c ) {
Bnd_Box A ;
BRepBndLib : : Add ( a , A ) ;
TopTools_ListIteratorOfListOfShape it ( b ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
Bnd_Box B ;
BRepBndLib : : Add ( it . Value ( ) , B ) ;
if ( A . Distance ( B ) < p ) {
c . Append ( it . Value ( ) ) ;
}
}
}
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : create_solid_from_compound ( const TopoDS_Shape & compound , TopoDS_Shape & shape ) {
2016-12-09 16:40:14 +01:00
TopTools_ListOfShape face_list ;
TopExp_Explorer exp ( compound , TopAbs_FACE ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
TopoDS_Face face = TopoDS : : Face ( exp . Current ( ) ) ;
face_list . Append ( face ) ;
}
if ( face_list . Extent ( ) = = 0 ) {
return false ;
}
return create_solid_from_faces ( face_list , shape ) ;
}
bool IfcGeom : : Kernel : : create_solid_from_faces ( const TopTools_ListOfShape & face_list , TopoDS_Shape & shape ) {
bool valid_shell = false ;
2018-09-12 16:44:30 +02:00
int max_faces = getValue ( GV_MAX_FACES_TO_SEW ) ;
if ( max_faces = = - 1 ) {
max_faces = 1000 ;
}
if ( face_list . Extent ( ) > max_faces ) {
throw too_many_faces_exception ( ) ;
}
2016-12-09 16:40:14 +01:00
TopTools_ListIteratorOfListOfShape face_iterator ;
2012-03-01 21:17:06 +00:00
BRepOffsetAPI_Sewing builder ;
2017-11-27 16:27:36 +01:00
builder . SetTolerance ( getValue ( GV_PRECISION ) ) ;
builder . SetMaxTolerance ( getValue ( GV_PRECISION ) ) ;
builder . SetMinTolerance ( getValue ( GV_PRECISION ) ) ;
2018-09-12 16:44:30 +02:00
2016-12-09 16:40:14 +01:00
for ( face_iterator . Initialize ( face_list ) ; face_iterator . More ( ) ; face_iterator . Next ( ) ) {
builder . Add ( face_iterator . Value ( ) ) ;
2012-03-01 21:17:06 +00:00
}
2016-12-09 16:40:14 +01:00
try {
builder . Perform ( ) ;
shape = builder . SewedShape ( ) ;
2017-01-19 10:42:03 +01:00
valid_shell = BRepCheck_Analyzer ( shape ) . IsValid ( ) ! = 0 & & count ( shape , TopAbs_SHELL ) > 0 ;
2017-08-01 16:45:11 +02:00
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error sewing shell " ) ;
}
} catch ( . . . ) {
Logger : : Error ( " Unknown error sewing shell " ) ;
}
2016-12-09 16:40:14 +01:00
if ( valid_shell ) {
2018-04-11 12:26:01 +02:00
2016-12-09 16:40:14 +01:00
TopoDS_Shape complete_shape ;
TopExp_Explorer exp ( shape , TopAbs_SHELL ) ;
2018-04-11 12:26:01 +02:00
2016-12-09 16:40:14 +01:00
for ( ; exp . More ( ) ; exp . Next ( ) ) {
TopoDS_Shape result_shape = exp . Current ( ) ;
try {
ShapeFix_Solid solid ;
2017-11-27 16:27:36 +01:00
solid . SetMaxTolerance ( getValue ( GV_PRECISION ) ) ;
2016-12-09 16:40:14 +01:00
TopoDS_Solid solid_shape = solid . SolidFromShell ( TopoDS : : Shell ( exp . Current ( ) ) ) ;
if ( ! solid_shape . IsNull ( ) ) {
try {
BRepClass3d_SolidClassifier classifier ( solid_shape ) ;
result_shape = solid_shape ;
classifier . PerformInfinitePoint ( getValue ( GV_PRECISION ) ) ;
if ( classifier . State ( ) = = TopAbs_IN ) {
shape . Reverse ( ) ;
}
2017-08-01 16:45:11 +02:00
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error classifying solid " ) ;
}
} catch ( . . . ) {
Logger : : Error ( " Unknown error classifying solid " ) ;
}
}
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error creating solid " ) ;
2016-12-09 16:40:14 +01:00
}
2017-08-01 16:45:11 +02:00
} catch ( . . . ) {
Logger : : Error ( " Unknown error creating solid " ) ;
}
2016-12-09 16:40:14 +01:00
if ( complete_shape . IsNull ( ) ) {
complete_shape = result_shape ;
} else {
BRep_Builder B ;
if ( complete_shape . ShapeType ( ) ! = TopAbs_COMPOUND ) {
TopoDS_Compound C ;
B . MakeCompound ( C ) ;
B . Add ( C , complete_shape ) ;
complete_shape = C ;
2018-04-11 12:26:01 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " Multiple components in IfcConnectedFaceSet " ) ;
2016-12-09 16:40:14 +01:00
}
B . Add ( complete_shape , result_shape ) ;
}
}
2018-04-11 12:26:01 +02:00
TopExp_Explorer loose_faces ( shape , TopAbs_FACE , TopAbs_SHELL ) ;
for ( ; loose_faces . More ( ) ; loose_faces . Next ( ) ) {
BRep_Builder B ;
if ( complete_shape . ShapeType ( ) ! = TopAbs_COMPOUND ) {
TopoDS_Compound C ;
B . MakeCompound ( C ) ;
B . Add ( C , complete_shape ) ;
complete_shape = C ;
Logger : : Message ( Logger : : LOG_ERROR , " Loose faces in IfcConnectedFaceSet " ) ;
}
B . Add ( complete_shape , loose_faces . Current ( ) ) ;
}
2016-12-09 16:40:14 +01:00
shape = complete_shape ;
2018-04-11 12:26:01 +02:00
2016-12-09 16:40:14 +01:00
} else {
Logger : : Message ( Logger : : LOG_WARNING , " Failed to sew faceset " ) ;
2016-03-18 11:23:25 +01:00
}
2016-12-09 16:40:14 +01:00
return valid_shell ;
2012-03-01 21:17:06 +00:00
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : is_compound ( const TopoDS_Shape & shape ) {
2012-03-13 11:56:52 +00:00
bool has_solids = TopExp_Explorer ( shape , TopAbs_SOLID ) . More ( ) ! = 0 ;
2012-03-01 21:17:06 +00:00
bool has_shells = TopExp_Explorer ( shape , TopAbs_SHELL ) . More ( ) ! = 0 ;
bool has_compounds = TopExp_Explorer ( shape , TopAbs_COMPOUND ) . More ( ) ! = 0 ;
bool has_faces = TopExp_Explorer ( shape , TopAbs_FACE ) . More ( ) ! = 0 ;
return has_compounds & & has_faces & & ! has_solids & & ! has_shells ;
}
2014-12-19 12:14:36 +00:00
const TopoDS_Shape & IfcGeom : : Kernel : : ensure_fit_for_subtraction ( const TopoDS_Shape & shape , TopoDS_Shape & solid ) {
const bool is_comp = is_compound ( shape ) ;
2015-06-21 16:14:37 +00:00
if ( ! is_comp ) {
return solid = shape ;
}
2016-12-09 16:40:14 +01:00
if ( ! create_solid_from_compound ( shape , solid ) ) {
return solid = shape ;
}
2014-06-09 12:56:47 +00:00
// If the SEW_SHELLS option had been set this precision had been applied
2014-12-19 12:14:36 +00:00
// at the end of the generic convert_shape() call.
const double precision = getValue ( GV_PRECISION ) ;
apply_tolerance ( solid , precision ) ;
2014-06-09 12:56:47 +00:00
2012-03-01 21:17:06 +00:00
return solid ;
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : convert_openings ( const IfcSchema : : IfcProduct * entity , const IfcSchema : : IfcRelVoidsElement : : list : : ptr & openings ,
const IfcGeom : : IfcRepresentationShapeItems & entity_shapes , const gp_Trsf & entity_trsf , IfcGeom : : IfcRepresentationShapeItems & cut_shapes ) {
2015-05-22 15:41:56 +00:00
// TODO: Refactor convert_openings() convert_openings_fast() and convert(IfcBooleanResult) to use
// the same code base and conform to the same checks and logging messages.
2011-10-23 17:11:06 +00:00
// Iterate over IfcOpeningElements
2013-05-05 08:49:25 +00:00
IfcGeom : : IfcRepresentationShapeItems opening_shapes ;
2011-10-23 17:11:06 +00:00
unsigned int last_size = 0 ;
2014-05-04 14:42:55 +00:00
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
IfcSchema : : IfcRelVoidsElement * v = * it ;
IfcSchema : : IfcFeatureElementSubtraction * fes = v - > RelatedOpeningElement ( ) ;
2014-02-17 22:13:55 +00:00
if ( fes - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
2015-12-05 17:14:10 +01:00
if ( ! fes - > hasRepresentation ( ) ) continue ;
2011-10-23 17:11:06 +00:00
// Convert the IfcRepresentation of the IfcOpeningElement
gp_Trsf opening_trsf ;
2015-12-05 17:14:10 +01:00
if ( fes - > hasObjectPlacement ( ) ) {
try {
convert ( fes - > ObjectPlacement ( ) , opening_trsf ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
2015-12-05 17:14:10 +01:00
}
2011-10-23 17:11:06 +00:00
// Move the opening into the coordinate system of the IfcProduct
opening_trsf . PreMultiply ( entity_trsf . Inverted ( ) ) ;
2014-05-04 14:42:55 +00:00
IfcSchema : : IfcProductRepresentation * prodrep = fes - > Representation ( ) ;
IfcSchema : : IfcRepresentation : : list : : ptr reps = prodrep - > Representations ( ) ;
2011-10-23 17:11:06 +00:00
2014-05-04 14:42:55 +00:00
for ( IfcSchema : : IfcRepresentation : : list : : it it2 = reps - > begin ( ) ; it2 ! = reps - > end ( ) ; + + it2 ) {
2014-12-19 12:14:36 +00:00
convert_shapes ( * it2 , opening_shapes ) ;
2011-10-23 17:11:06 +00:00
}
const unsigned int current_size = ( const unsigned int ) opening_shapes . size ( ) ;
for ( unsigned int i = last_size ; i < current_size ; + + i ) {
2013-07-20 22:12:40 +00:00
opening_shapes [ i ] . prepend ( opening_trsf ) ;
2011-07-25 14:56:40 +00:00
}
2011-10-23 17:11:06 +00:00
last_size = current_size ;
2011-07-25 14:56:40 +00:00
}
}
2011-10-23 17:11:06 +00:00
// Iterate over the shapes of the IfcProduct
2013-05-05 08:49:25 +00:00
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it3 = entity_shapes . begin ( ) ; it3 ! = entity_shapes . end ( ) ; + + it3 ) {
2012-03-01 21:17:06 +00:00
TopoDS_Shape entity_shape_solid ;
2014-12-19 12:14:36 +00:00
const TopoDS_Shape & entity_shape_unlocated = ensure_fit_for_subtraction ( it3 - > Shape ( ) , entity_shape_solid ) ;
2013-05-05 08:49:25 +00:00
const gp_GTrsf & entity_shape_gtrsf = it3 - > Placement ( ) ;
2011-10-23 17:11:06 +00:00
if ( entity_shape_gtrsf . Form ( ) = = gp_Other ) {
2016-05-03 11:01:47 +02:00
Logger : : Message ( Logger : : LOG_WARNING , " Applying non uniform transformation to: " , entity - > entity ) ;
2011-10-23 17:11:06 +00:00
}
2016-05-03 11:01:47 +02:00
TopoDS_Shape entity_shape = apply_transformation ( entity_shape_unlocated , entity_shape_gtrsf ) ;
2011-10-23 17:11:06 +00:00
// Iterate over the shapes of the IfcOpeningElements
2013-05-05 08:49:25 +00:00
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it4 = opening_shapes . begin ( ) ; it4 ! = opening_shapes . end ( ) ; + + it4 ) {
2012-03-01 21:17:06 +00:00
TopoDS_Shape opening_shape_solid ;
2014-12-19 12:14:36 +00:00
const TopoDS_Shape & opening_shape_unlocated = ensure_fit_for_subtraction ( it4 - > Shape ( ) , opening_shape_solid ) ;
2013-05-05 08:49:25 +00:00
const gp_GTrsf & opening_shape_gtrsf = it4 - > Placement ( ) ;
2011-10-23 17:11:06 +00:00
if ( opening_shape_gtrsf . Form ( ) = = gp_Other ) {
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , " Applying non uniform transformation to opening of: " , entity - > entity ) ;
2011-10-23 17:11:06 +00:00
}
2016-05-03 11:01:47 +02:00
TopoDS_Shape opening_shape = apply_transformation ( opening_shape_unlocated , opening_shape_gtrsf ) ;
2011-10-23 17:11:06 +00:00
2015-11-21 23:05:28 +02:00
double opening_volume ;
2017-06-05 13:08:07 +02:00
if ( Logger : : LOG_WARNING > = Logger : : Verbosity ( ) ) {
2012-06-07 14:38:21 +00:00
opening_volume = shape_volume ( opening_shape ) ;
if ( opening_volume < = ALMOST_ZERO )
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , " Empty opening for: " , entity - > entity ) ;
2012-06-07 14:38:21 +00:00
}
2012-03-01 21:17:06 +00:00
2014-07-24 11:22:31 +00:00
if ( entity_shape . ShapeType ( ) = = TopAbs_COMPSOLID ) {
// For compound solids process the subtraction for the constituent
// solids individually and write the result back as a compound solid.
TopoDS_CompSolid compound ;
BRep_Builder builder ;
builder . MakeCompSolid ( compound ) ;
TopExp_Explorer exp ( entity_shape , TopAbs_SOLID ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
2016-01-22 17:27:28 +01:00
# if OCC_VERSION_HEX < 0x60900
2014-07-24 11:22:31 +00:00
BRepAlgoAPI_Cut brep_cut ( exp . Current ( ) , opening_shape ) ;
2016-01-22 17:27:28 +01:00
# else
BRepAlgoAPI_Cut brep_cut ;
TopTools_ListOfShape s1s ;
s1s . Append ( exp . Current ( ) ) ;
TopTools_ListOfShape s2s ;
s2s . Append ( opening_shape ) ;
brep_cut . SetFuzzyValue ( getValue ( GV_PRECISION ) ) ;
brep_cut . SetArguments ( s1s ) ;
brep_cut . SetTools ( s2s ) ;
brep_cut . Build ( ) ;
# endif
2014-07-24 11:22:31 +00:00
bool added = false ;
if ( brep_cut . IsDone ( ) ) {
TopoDS_Shape brep_cut_result = brep_cut ;
BRepCheck_Analyzer analyser ( brep_cut_result ) ;
bool is_valid = analyser . IsValid ( ) ! = 0 ;
if ( is_valid ) {
2015-11-21 23:05:28 +02:00
TopExp_Explorer exp2 ( brep_cut_result , TopAbs_SOLID ) ;
for ( ; exp2 . More ( ) ; exp2 . Next ( ) ) {
builder . Add ( compound , exp2 . Current ( ) ) ;
2014-07-24 11:22:31 +00:00
added = true ;
}
}
}
if ( ! added ) {
// Add the original in case subtraction fails
builder . Add ( compound , exp . Current ( ) ) ;
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to process subtraction: " , entity - > entity ) ;
}
}
entity_shape = compound ;
} else {
2016-01-22 17:27:28 +01:00
# if OCC_VERSION_HEX < 0x60900
2014-07-24 11:22:31 +00:00
BRepAlgoAPI_Cut brep_cut ( entity_shape , opening_shape ) ;
2016-01-22 17:27:28 +01:00
# else
BRepAlgoAPI_Cut brep_cut ;
TopTools_ListOfShape s1s ;
s1s . Append ( entity_shape ) ;
TopTools_ListOfShape s2s ;
s2s . Append ( opening_shape ) ;
brep_cut . SetFuzzyValue ( getValue ( GV_PRECISION ) ) ;
brep_cut . SetArguments ( s1s ) ;
brep_cut . SetTools ( s2s ) ;
brep_cut . Build ( ) ;
# endif
2014-07-24 11:22:31 +00:00
if ( brep_cut . IsDone ( ) ) {
TopoDS_Shape brep_cut_result = brep_cut ;
2015-05-22 15:41:56 +00:00
ShapeFix_Shape fix ( brep_cut_result ) ;
try {
fix . Perform ( ) ;
brep_cut_result = fix . Shape ( ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_WARNING , " Shape healing failed on opening subtraction result " , entity - > entity ) ;
}
2014-07-24 11:22:31 +00:00
BRepCheck_Analyzer analyser ( brep_cut_result ) ;
bool is_valid = analyser . IsValid ( ) ! = 0 ;
if ( is_valid ) {
2015-05-22 15:41:56 +00:00
entity_shape = brep_cut_result ;
2017-06-05 13:08:07 +02:00
if ( Logger : : LOG_WARNING > = Logger : : Verbosity ( ) ) {
2014-07-24 11:22:31 +00:00
const double volume_after_subtraction = shape_volume ( entity_shape ) ;
2015-11-21 23:05:28 +02:00
double original_shape_volume = shape_volume ( entity_shape ) ;
2014-07-24 11:22:31 +00:00
if ( ALMOST_THE_SAME ( original_shape_volume , volume_after_subtraction ) )
Logger : : Message ( Logger : : LOG_WARNING , " Subtraction yields unchanged volume: " , entity - > entity ) ;
}
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Invalid result from subtraction: " , entity - > entity ) ;
2012-06-07 14:38:21 +00:00
}
2012-03-13 11:56:52 +00:00
} else {
2014-07-24 11:22:31 +00:00
Logger : : Message ( Logger : : LOG_ERROR , " Failed to process subtraction: " , entity - > entity ) ;
2012-03-13 11:56:52 +00:00
}
2012-03-01 21:17:06 +00:00
}
2012-03-13 11:56:52 +00:00
2011-10-23 17:11:06 +00:00
}
2013-05-05 08:49:25 +00:00
cut_shapes . push_back ( IfcGeom : : IfcRepresentationShapeItem ( entity_shape , & it3 - > Style ( ) ) ) ;
2011-10-23 17:11:06 +00:00
}
2011-07-25 14:56:40 +00:00
return true ;
}
2012-06-07 14:38:21 +00:00
2016-01-25 13:30:33 +01:00
# if OCC_VERSION_HEX < 0x60900
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : convert_openings_fast ( const IfcSchema : : IfcProduct * entity , const IfcSchema : : IfcRelVoidsElement : : list : : ptr & openings ,
const IfcGeom : : IfcRepresentationShapeItems & entity_shapes , const gp_Trsf & entity_trsf , IfcGeom : : IfcRepresentationShapeItems & cut_shapes ) {
2012-06-07 14:38:21 +00:00
// Create a compound of all opening shapes in order to speed up the boolean operations
TopoDS_Compound opening_compound ;
BRep_Builder builder ;
builder . MakeCompound ( opening_compound ) ;
2014-05-04 14:42:55 +00:00
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
IfcSchema : : IfcRelVoidsElement * v = * it ;
IfcSchema : : IfcFeatureElementSubtraction * fes = v - > RelatedOpeningElement ( ) ;
2014-02-17 22:13:55 +00:00
if ( fes - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
2015-12-05 17:14:10 +01:00
if ( ! fes - > hasRepresentation ( ) ) continue ;
2012-06-07 14:38:21 +00:00
// Convert the IfcRepresentation of the IfcOpeningElement
gp_Trsf opening_trsf ;
2015-12-05 17:14:10 +01:00
if ( fes - > hasObjectPlacement ( ) ) {
try {
convert ( fes - > ObjectPlacement ( ) , opening_trsf ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
2015-12-05 17:14:10 +01:00
}
2012-06-07 14:38:21 +00:00
// Move the opening into the coordinate system of the IfcProduct
opening_trsf . PreMultiply ( entity_trsf . Inverted ( ) ) ;
2014-05-04 14:42:55 +00:00
IfcSchema : : IfcProductRepresentation * prodrep = fes - > Representation ( ) ;
IfcSchema : : IfcRepresentation : : list : : ptr reps = prodrep - > Representations ( ) ;
2012-06-07 14:38:21 +00:00
2013-05-05 08:49:25 +00:00
IfcGeom : : IfcRepresentationShapeItems opening_shapes ;
2012-06-07 14:38:21 +00:00
2014-05-04 14:42:55 +00:00
for ( IfcSchema : : IfcRepresentation : : list : : it it2 = reps - > begin ( ) ; it2 ! = reps - > end ( ) ; + + it2 ) {
2014-12-19 12:14:36 +00:00
convert_shapes ( * it2 , opening_shapes ) ;
2012-06-07 14:38:21 +00:00
}
for ( unsigned int i = 0 ; i < opening_shapes . size ( ) ; + + i ) {
2013-05-05 08:49:25 +00:00
gp_GTrsf gtrsf = opening_shapes [ i ] . Placement ( ) ;
2012-06-07 14:38:21 +00:00
gtrsf . PreMultiply ( opening_trsf ) ;
2016-05-03 11:01:47 +02:00
TopoDS_Shape opening_shape = apply_transformation ( opening_shapes [ i ] . Shape ( ) , gtrsf ) ;
builder . Add ( opening_compound , opening_shape ) ;
2012-06-07 14:38:21 +00:00
}
}
}
// Iterate over the shapes of the IfcProduct
2013-05-05 08:49:25 +00:00
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it3 = entity_shapes . begin ( ) ; it3 ! = entity_shapes . end ( ) ; + + it3 ) {
2012-06-07 14:38:21 +00:00
TopoDS_Shape entity_shape_solid ;
2014-12-19 12:14:36 +00:00
const TopoDS_Shape & entity_shape_unlocated = ensure_fit_for_subtraction ( it3 - > Shape ( ) , entity_shape_solid ) ;
2013-05-05 08:49:25 +00:00
const gp_GTrsf & entity_shape_gtrsf = it3 - > Placement ( ) ;
2016-05-03 11:01:47 +02:00
if ( entity_shape_gtrsf . Form ( ) = = gp_Other ) {
Logger : : Message ( Logger : : LOG_WARNING , " Applying non uniform transformation to: " , entity - > entity ) ;
2012-06-07 14:38:21 +00:00
}
2016-05-03 11:01:47 +02:00
TopoDS_Shape entity_shape = apply_transformation ( entity_shape_unlocated , entity_shape_gtrsf ) ;
2012-06-07 14:38:21 +00:00
BRepAlgoAPI_Cut brep_cut ( entity_shape , opening_compound ) ;
2016-01-25 13:30:33 +01:00
2012-06-07 14:38:21 +00:00
bool is_valid = false ;
if ( brep_cut . IsDone ( ) ) {
TopoDS_Shape brep_cut_result = brep_cut ;
BRepCheck_Analyzer analyser ( brep_cut_result ) ;
is_valid = analyser . IsValid ( ) ! = 0 ;
if ( is_valid ) {
2013-05-05 08:49:25 +00:00
cut_shapes . push_back ( IfcGeom : : IfcRepresentationShapeItem ( brep_cut_result , & it3 - > Style ( ) ) ) ;
2012-06-07 14:38:21 +00:00
}
}
if ( ! is_valid ) {
// Apparently processing the boolean operation failed or resulted in an invalid result
// in which case the original shape without the subtractions is returned instead
// we try convert the openings in the original way, one by one.
2012-08-11 13:24:08 +00:00
Logger : : Message ( Logger : : LOG_WARNING , " Subtracting combined openings compound failed: " , entity - > entity ) ;
2012-06-07 14:38:21 +00:00
return false ;
}
}
return true ;
}
2016-01-22 17:27:28 +01:00
# else
2016-01-25 13:30:33 +01:00
bool IfcGeom : : Kernel : : convert_openings_fast ( const IfcSchema : : IfcProduct * entity , const IfcSchema : : IfcRelVoidsElement : : list : : ptr & openings ,
const IfcGeom : : IfcRepresentationShapeItems & entity_shapes , const gp_Trsf & entity_trsf , IfcGeom : : IfcRepresentationShapeItems & cut_shapes ) {
TopTools_ListOfShape opening_shapelist ;
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
IfcSchema : : IfcRelVoidsElement * v = * it ;
IfcSchema : : IfcFeatureElementSubtraction * fes = v - > RelatedOpeningElement ( ) ;
if ( fes - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
if ( ! fes - > hasRepresentation ( ) ) continue ;
// Convert the IfcRepresentation of the IfcOpeningElement
gp_Trsf opening_trsf ;
if ( fes - > hasObjectPlacement ( ) ) {
try {
convert ( fes - > ObjectPlacement ( ) , opening_trsf ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
2016-01-25 13:30:33 +01:00
}
// Move the opening into the coordinate system of the IfcProduct
opening_trsf . PreMultiply ( entity_trsf . Inverted ( ) ) ;
IfcSchema : : IfcProductRepresentation * prodrep = fes - > Representation ( ) ;
IfcSchema : : IfcRepresentation : : list : : ptr reps = prodrep - > Representations ( ) ;
IfcGeom : : IfcRepresentationShapeItems opening_shapes ;
for ( IfcSchema : : IfcRepresentation : : list : : it it2 = reps - > begin ( ) ; it2 ! = reps - > end ( ) ; + + it2 ) {
convert_shapes ( * it2 , opening_shapes ) ;
}
for ( unsigned int i = 0 ; i < opening_shapes . size ( ) ; + + i ) {
2018-05-05 16:09:12 +02:00
TopoDS_Shape opening_shape_solid ;
const TopoDS_Shape & opening_shape_unlocated = ensure_fit_for_subtraction ( opening_shapes [ i ] . Shape ( ) , opening_shape_solid ) ;
2016-01-25 13:30:33 +01:00
gp_GTrsf gtrsf = opening_shapes [ i ] . Placement ( ) ;
gtrsf . PreMultiply ( opening_trsf ) ;
2018-05-05 16:09:12 +02:00
TopoDS_Shape opening_shape = apply_transformation ( opening_shape_unlocated , gtrsf ) ;
2016-01-25 13:30:33 +01:00
opening_shapelist . Append ( opening_shape ) ;
}
}
}
// Iterate over the shapes of the IfcProduct
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it3 = entity_shapes . begin ( ) ; it3 ! = entity_shapes . end ( ) ; + + it3 ) {
TopoDS_Shape entity_shape_solid ;
const TopoDS_Shape & entity_shape_unlocated = ensure_fit_for_subtraction ( it3 - > Shape ( ) , entity_shape_solid ) ;
const gp_GTrsf & entity_shape_gtrsf = it3 - > Placement ( ) ;
2016-05-03 11:01:47 +02:00
if ( entity_shape_gtrsf . Form ( ) = = gp_Other ) {
Logger : : Message ( Logger : : LOG_WARNING , " Applying non uniform transformation to: " , entity - > entity ) ;
2016-01-25 13:30:33 +01:00
}
2016-05-03 11:01:47 +02:00
TopoDS_Shape entity_shape = apply_transformation ( entity_shape_unlocated , entity_shape_gtrsf ) ;
2016-01-22 17:27:28 +01:00
2017-11-13 12:41:37 +01:00
TopoDS_Shape result ;
if ( boolean_operation ( entity_shape , opening_shapelist , BOPAlgo_CUT , result ) ) {
cut_shapes . push_back ( IfcGeom : : IfcRepresentationShapeItem ( result , & it3 - > Style ( ) ) ) ;
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Opening subtraction failed: " , entity - > entity ) ;
cut_shapes . push_back ( IfcGeom : : IfcRepresentationShapeItem ( entity_shape , & it3 - > Style ( ) ) ) ;
2012-06-07 14:38:21 +00:00
}
}
return true ;
}
2016-01-25 13:30:33 +01:00
# endif
2012-06-07 14:38:21 +00:00
2018-04-18 11:33:57 +02:00
bool IfcGeom : : Kernel : : convert_wire_to_face ( const TopoDS_Wire & w , TopoDS_Face & face ) {
TopoDS_Wire wire = w ;
TopTools_ListOfShape results ;
if ( wire_intersections ( wire , results ) ) {
Logger : : Error ( " Self-intersections with " + boost : : lexical_cast < std : : string > ( results . Extent ( ) ) + " cycles detected " ) ;
select_largest ( results , wire ) ;
}
2018-08-20 11:46:26 +02:00
bool is_2d = true ;
TopExp_Explorer exp ( wire , TopAbs_EDGE ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
double a , b ;
Handle ( Geom_Curve ) crv = BRep_Tool : : Curve ( TopoDS : : Edge ( exp . Current ( ) ) , a , b ) ;
if ( crv - > DynamicType ( ) ! = STANDARD_TYPE ( Geom_Line ) ) {
is_2d = false ;
break ;
}
Handle ( Geom_Line ) line = Handle ( Geom_Line ) : : DownCast ( crv ) ;
if ( line - > Lin ( ) . Direction ( ) . Z ( ) > ALMOST_ZERO ) {
is_2d = false ;
break ;
}
}
if ( ! is_2d ) {
// For 2d wires (e.g. profiles) a higher tolerance for plane fitting is never required.
ShapeFix_ShapeTolerance FTol ;
FTol . SetTolerance ( wire , getValue ( GV_PRECISION ) , TopAbs_WIRE ) ;
}
2017-11-08 13:27:45 +01:00
2011-07-25 14:56:40 +00:00
BRepBuilderAPI_MakeFace mf ( wire , false ) ;
BRepBuilderAPI_FaceError er = mf . Error ( ) ;
2017-11-08 13:27:45 +01:00
if ( er ! = BRepBuilderAPI_FaceDone ) {
Logger : : Error ( " Failed to create face. " ) ;
return false ;
2011-07-25 14:56:40 +00:00
}
face = mf . Face ( ) ;
2017-11-08 13:27:45 +01:00
2011-07-25 14:56:40 +00:00
return true ;
}
2014-03-15 11:51:23 +00:00
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : convert_curve_to_wire ( const Handle ( Geom_Curve ) & curve , TopoDS_Wire & wire ) {
2015-04-22 09:15:48 +00:00
try {
wire = BRepBuilderAPI_MakeWire ( BRepBuilderAPI_MakeEdge ( curve ) ) ;
2017-08-01 16:45:11 +02:00
return true ;
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
2018-09-06 12:23:07 -04:00
Logger : : Error ( " Unknown error converting curve to wire " ) ;
2017-08-01 16:45:11 +02:00
}
} catch ( . . . ) {
2018-09-06 12:23:07 -04:00
Logger : : Error ( " Unknown error converting curve to wire " ) ;
2017-08-01 16:45:11 +02:00
}
return false ;
2014-03-15 11:51:23 +00:00
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : profile_helper ( int numVerts , double * verts , int numFillets , int * filletIndices , double * filletRadii , gp_Trsf2d trsf , TopoDS_Shape & face_shape ) {
2011-07-25 14:56:40 +00:00
TopoDS_Vertex * vertices = new TopoDS_Vertex [ numVerts ] ;
for ( int i = 0 ; i < numVerts ; i + + ) {
gp_XY xy ( verts [ 2 * i ] , verts [ 2 * i + 1 ] ) ;
trsf . Transforms ( xy ) ;
vertices [ i ] = BRepBuilderAPI_MakeVertex ( gp_Pnt ( xy . X ( ) , xy . Y ( ) , 0.0f ) ) ;
}
BRepBuilderAPI_MakeWire w ;
for ( int i = 0 ; i < numVerts ; i + + )
w . Add ( BRepBuilderAPI_MakeEdge ( vertices [ i ] , vertices [ ( i + 1 ) % numVerts ] ) ) ;
2014-03-16 13:34:01 +00:00
TopoDS_Face face ;
2014-12-19 12:14:36 +00:00
convert_wire_to_face ( w . Wire ( ) , face ) ;
2011-07-25 14:56:40 +00:00
2014-07-24 11:14:54 +00:00
if ( numFillets & & * std : : max_element ( filletRadii , filletRadii + numFillets ) > ALMOST_ZERO ) {
2011-07-25 14:56:40 +00:00
BRepFilletAPI_MakeFillet2d fillet ( face ) ;
for ( int i = 0 ; i < numFillets ; i + + ) {
2012-03-13 11:56:52 +00:00
const double radius = filletRadii [ i ] ;
2014-07-24 11:14:54 +00:00
if ( radius < = ALMOST_ZERO ) continue ;
2011-07-25 14:56:40 +00:00
fillet . AddFillet ( vertices [ filletIndices [ i ] ] , radius ) ;
}
fillet . Build ( ) ;
2014-07-24 11:14:54 +00:00
if ( fillet . IsDone ( ) ) {
face = TopoDS : : Face ( fillet . Shape ( ) ) ;
} else {
Logger : : Message ( Logger : : LOG_WARNING , " Failed to process profile fillets " ) ;
}
2011-07-25 14:56:40 +00:00
}
2014-03-16 13:34:01 +00:00
face_shape = face ;
2011-07-25 14:56:40 +00:00
delete [ ] vertices ;
return true ;
2011-10-12 16:43:29 +00:00
}
2014-12-19 12:14:36 +00:00
double IfcGeom : : Kernel : : shape_volume ( const TopoDS_Shape & s ) {
2012-04-07 14:34:44 +00:00
GProp_GProps prop ;
BRepGProp : : VolumeProperties ( s , prop ) ;
return prop . Mass ( ) ;
}
2014-12-19 12:14:36 +00:00
double IfcGeom : : Kernel : : face_area ( const TopoDS_Face & f ) {
2012-04-07 14:34:44 +00:00
GProp_GProps prop ;
BRepGProp : : SurfaceProperties ( f , prop ) ;
return prop . Mass ( ) ;
2012-03-13 11:56:52 +00:00
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : is_convex ( const TopoDS_Wire & wire ) {
2012-03-13 11:56:52 +00:00
for ( TopExp_Explorer exp1 ( wire , TopAbs_VERTEX ) ; exp1 . More ( ) ; exp1 . Next ( ) ) {
TopoDS_Vertex V1 = TopoDS : : Vertex ( exp1 . Current ( ) ) ;
gp_Pnt P1 = BRep_Tool : : Pnt ( V1 ) ;
// Store the neighboring points
std : : vector < gp_Pnt > neighbors ;
for ( TopExp_Explorer exp3 ( wire , TopAbs_EDGE ) ; exp3 . More ( ) ; exp3 . Next ( ) ) {
TopoDS_Edge edge = TopoDS : : Edge ( exp3 . Current ( ) ) ;
std : : vector < gp_Pnt > edge_points ;
for ( TopExp_Explorer exp2 ( edge , TopAbs_VERTEX ) ; exp2 . More ( ) ; exp2 . Next ( ) ) {
TopoDS_Vertex V2 = TopoDS : : Vertex ( exp2 . Current ( ) ) ;
gp_Pnt P2 = BRep_Tool : : Pnt ( V2 ) ;
edge_points . push_back ( P2 ) ;
}
if ( edge_points . size ( ) ! = 2 ) continue ;
2014-12-19 12:14:36 +00:00
if ( edge_points [ 0 ] . IsEqual ( P1 , getValue ( GV_POINT_EQUALITY_TOLERANCE ) ) ) neighbors . push_back ( edge_points [ 1 ] ) ;
else if ( edge_points [ 1 ] . IsEqual ( P1 , getValue ( GV_POINT_EQUALITY_TOLERANCE ) ) ) neighbors . push_back ( edge_points [ 0 ] ) ;
2012-03-13 11:56:52 +00:00
}
// There should be two of these
if ( neighbors . size ( ) ! = 2 ) return false ;
// Now find the non neighboring points
std : : vector < gp_Pnt > non_neighbors ;
for ( TopExp_Explorer exp2 ( wire , TopAbs_VERTEX ) ; exp2 . More ( ) ; exp2 . Next ( ) ) {
TopoDS_Vertex V2 = TopoDS : : Vertex ( exp2 . Current ( ) ) ;
gp_Pnt P2 = BRep_Tool : : Pnt ( V2 ) ;
2014-12-19 12:14:36 +00:00
if ( P1 . IsEqual ( P2 , getValue ( GV_POINT_EQUALITY_TOLERANCE ) ) ) continue ;
2012-03-13 11:56:52 +00:00
bool found = false ;
for ( std : : vector < gp_Pnt > : : const_iterator it = neighbors . begin ( ) ; it ! = neighbors . end ( ) ; + + it ) {
2014-12-19 12:14:36 +00:00
if ( ( * it ) . IsEqual ( P2 , getValue ( GV_POINT_EQUALITY_TOLERANCE ) ) ) { found = true ; break ; }
2012-03-13 11:56:52 +00:00
}
if ( ! found ) non_neighbors . push_back ( P2 ) ;
}
// Calculate the angle between the two edges of the vertex
gp_Dir dir1 ( neighbors [ 0 ] . XYZ ( ) - P1 . XYZ ( ) ) ;
gp_Dir dir2 ( neighbors [ 1 ] . XYZ ( ) - P1 . XYZ ( ) ) ;
const double angle = acos ( dir1 . Dot ( dir2 ) ) + 0.0001 ;
// Now for the non-neighbors see whether a greater angle can be found with one of the edges
for ( std : : vector < gp_Pnt > : : const_iterator it = non_neighbors . begin ( ) ; it ! = non_neighbors . end ( ) ; + + it ) {
gp_Dir dir3 ( ( * it ) . XYZ ( ) - P1 . XYZ ( ) ) ;
const double angle2 = acos ( dir3 . Dot ( dir1 ) ) ;
const double angle3 = acos ( dir3 . Dot ( dir2 ) ) ;
if ( angle2 > angle | | angle3 > angle ) return false ;
}
}
return true ;
}
2014-12-19 12:14:36 +00:00
TopoDS_Shape IfcGeom : : Kernel : : halfspace_from_plane ( const gp_Pln & pln , const gp_Pnt & cent ) {
2012-03-13 11:56:52 +00:00
TopoDS_Face face = BRepBuilderAPI_MakeFace ( pln ) . Face ( ) ;
return BRepPrimAPI_MakeHalfSpace ( face , cent ) . Solid ( ) ;
}
2014-12-19 12:14:36 +00:00
gp_Pln IfcGeom : : Kernel : : plane_from_face ( const TopoDS_Face & face ) {
2012-03-13 11:56:52 +00:00
BRepGProp_Face prop ( face ) ;
Standard_Real u1 , u2 , v1 , v2 ;
prop . Bounds ( u1 , u2 , v1 , v2 ) ;
Standard_Real u = ( u1 + u2 ) / 2.0 ;
Standard_Real v = ( v1 + v2 ) / 2.0 ;
gp_Pnt p ;
gp_Vec n ;
prop . Normal ( u , v , p , n ) ;
return gp_Pln ( p , n ) ;
}
2014-12-19 12:14:36 +00:00
gp_Pnt IfcGeom : : Kernel : : point_above_plane ( const gp_Pln & pln , bool agree ) {
2012-03-13 11:56:52 +00:00
if ( agree ) {
return pln . Location ( ) . Translated ( pln . Axis ( ) . Direction ( ) ) ;
} else {
return pln . Location ( ) . Translated ( - pln . Axis ( ) . Direction ( ) ) ;
}
2012-06-25 15:08:58 +00:00
}
2014-12-19 12:14:36 +00:00
void IfcGeom : : Kernel : : apply_tolerance ( TopoDS_Shape & s , double t ) {
2017-08-09 17:00:41 +02:00
/*
// This does not result in actionable error messages and has been disabled.
2017-04-03 14:55:34 +02:00
ShapeAnalysis_ShapeTolerance toler;
2017-06-05 13:08:07 +02:00
if (Logger::LOG_WARNING >= Logger::Verbosity()) {
2017-08-09 17:00:41 +02:00
if (toler.Tolerance(s, 0) > t * 10.) {
Handle_TopTools_HSequenceOfShape shapes = toler.OverTolerance(s, t * 10.);
2017-06-05 13:08:07 +02:00
for (int i = 1; i <= shapes->Length(); ++i) {
const TopoDS_Shape& sub = shapes->Value(i);
std::stringstream ss;
TopAbs::Print(sub.ShapeType(), ss);
Logger::Warning("Tolerance of " + boost::lexical_cast<std::string>(toler.Tolerance(sub, 0)) + " on " + ss.str());
}
2017-04-03 14:55:34 +02:00
}
}
2017-08-09 17:00:41 +02:00
*/
2017-11-13 12:41:37 +01:00
# if OCC_VERSION_HEX < 0x60900
// This tolerance hack is not required as the boolean ops use a fuzziness value
2013-11-24 15:44:27 +00:00
ShapeFix_ShapeTolerance tol ;
2017-04-03 14:55:34 +02:00
tol . LimitTolerance ( s , t ) ;
2017-11-13 12:41:37 +01:00
# else
( void ) s ;
( void ) t ;
# endif
2013-11-24 15:44:27 +00:00
}
2014-12-19 12:14:36 +00:00
void IfcGeom : : Kernel : : setValue ( GeomValue var , double value ) {
2012-06-25 15:08:58 +00:00
switch ( var ) {
case GV_DEFLECTION_TOLERANCE :
deflection_tolerance = value ;
2012-06-27 15:59:09 +00:00
break ;
2012-06-25 15:08:58 +00:00
case GV_WIRE_CREATION_TOLERANCE :
wire_creation_tolerance = value ;
2012-06-27 15:59:09 +00:00
break ;
2012-06-25 15:08:58 +00:00
case GV_POINT_EQUALITY_TOLERANCE :
point_equality_tolerance = value ;
2012-06-27 15:59:09 +00:00
break ;
2012-06-25 15:08:58 +00:00
case GV_MAX_FACES_TO_SEW :
max_faces_to_sew = value ;
2012-06-27 15:59:09 +00:00
break ;
2012-08-11 13:24:08 +00:00
case GV_LENGTH_UNIT :
ifc_length_unit = value ;
break ;
case GV_PLANEANGLE_UNIT :
ifc_planeangle_unit = value ;
break ;
2013-11-24 15:44:27 +00:00
case GV_PRECISION :
modelling_precision = value ;
break ;
2015-04-22 09:15:48 +00:00
case GV_DIMENSIONALITY :
dimensionality = value ;
break ;
2012-06-27 15:59:09 +00:00
default :
assert ( ! " never reach here " ) ;
2012-06-25 15:08:58 +00:00
}
}
2015-10-07 16:13:25 +02:00
double IfcGeom : : Kernel : : getValue ( GeomValue var ) const {
2012-06-25 15:08:58 +00:00
switch ( var ) {
case GV_DEFLECTION_TOLERANCE :
return deflection_tolerance ;
case GV_WIRE_CREATION_TOLERANCE :
return wire_creation_tolerance ;
case GV_MINIMAL_FACE_AREA :
2016-05-24 12:50:05 +02:00
// Considering a right-angled triangle, this about the smallest
// area you can obtain without the vertices being confused.
return modelling_precision * modelling_precision / 2. ;
2012-06-25 15:08:58 +00:00
case GV_POINT_EQUALITY_TOLERANCE :
return point_equality_tolerance ;
case GV_MAX_FACES_TO_SEW :
return max_faces_to_sew ;
2012-08-11 13:24:08 +00:00
case GV_LENGTH_UNIT :
return ifc_length_unit ;
break ;
case GV_PLANEANGLE_UNIT :
return ifc_planeangle_unit ;
break ;
2013-11-24 15:44:27 +00:00
case GV_PRECISION :
return modelling_precision ;
break ;
2015-04-22 09:15:48 +00:00
case GV_DIMENSIONALITY :
return dimensionality ;
break ;
2012-06-25 15:08:58 +00:00
}
assert ( ! " never reach here " ) ;
return 0 ;
2012-11-04 16:26:33 +00:00
}
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
// Returns the vertex part of an TopoDS_Edge edge that is not TopoDS_Vertex vertex
TopoDS_Vertex find_other ( const TopoDS_Edge & edge , const TopoDS_Vertex & vertex ) {
TopExp_Explorer exp ( edge , TopAbs_VERTEX ) ;
while ( exp . More ( ) ) {
if ( ! exp . Current ( ) . IsSame ( vertex ) ) {
return TopoDS : : Vertex ( exp . Current ( ) ) ;
}
exp . Next ( ) ;
}
2014-03-31 14:00:02 +00:00
return TopoDS_Vertex ( ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
}
TopoDS_Edge find_next ( const TopTools_IndexedMapOfShape & edge_set , const TopTools_IndexedDataMapOfShapeListOfShape & vertex_to_edges , const TopoDS_Vertex & current , const TopoDS_Edge & previous_edge ) {
const TopTools_ListOfShape & edges = vertex_to_edges . FindFromKey ( current ) ;
TopTools_ListIteratorOfListOfShape eit ;
for ( eit . Initialize ( edges ) ; eit . More ( ) ; eit . Next ( ) ) {
const TopoDS_Edge & edge = TopoDS : : Edge ( eit . Value ( ) ) ;
if ( edge . IsSame ( previous_edge ) ) continue ;
if ( edge_set . Contains ( edge ) ) {
return edge ;
}
}
2014-03-31 14:00:02 +00:00
return TopoDS_Edge ( ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : fill_nonmanifold_wires_with_planar_faces ( TopoDS_Shape & shape ) {
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
BRepOffsetAPI_Sewing sew ;
sew . Add ( shape ) ;
TopTools_IndexedDataMapOfShapeListOfShape edge_to_faces ;
TopTools_IndexedDataMapOfShapeListOfShape vertex_to_edges ;
std : : set < int > visited ;
TopTools_IndexedMapOfShape edge_set ;
TopExp : : MapShapesAndAncestors ( shape , TopAbs_EDGE , TopAbs_FACE , edge_to_faces ) ;
const int num_edges = edge_to_faces . Extent ( ) ;
for ( int i = 1 ; i < = num_edges ; + + i ) {
const TopTools_ListOfShape & faces = edge_to_faces . FindFromIndex ( i ) ;
const int count = faces . Extent ( ) ;
// Find only the non-manifold edges: Edges that are only part of a
// single face and therefore part of the wire(s) we want to fill.
if ( count = = 1 ) {
const TopoDS_Shape & edge = edge_to_faces . FindKey ( i ) ;
TopExp : : MapShapesAndAncestors ( edge , TopAbs_VERTEX , TopAbs_EDGE , vertex_to_edges ) ;
edge_set . Add ( edge ) ;
}
}
const int num_verts = vertex_to_edges . Extent ( ) ;
TopoDS_Vertex first , current ;
TopoDS_Edge previous_edge ;
// Now loop over all the vertices that are part of the wire(s) to be filled
for ( int i = 1 ; i < = num_verts ; + + i ) {
first = current = TopoDS : : Vertex ( vertex_to_edges . FindKey ( i ) ) ;
// We keep track of the vertices we already used
if ( visited . find ( vertex_to_edges . FindIndex ( current ) ) ! = visited . end ( ) ) {
continue ;
}
// Given these vertices, try to find closed loops and create new
// wires out of them.
BRepBuilderAPI_MakeWire w ;
2015-11-21 23:05:28 +02:00
for ( ; ; ) {
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
visited . insert ( vertex_to_edges . FindIndex ( current ) ) ;
// Find the edge that the current vertex is part of and points
// away from the previous vertex (null for the first vertex).
TopoDS_Edge edge = find_next ( edge_set , vertex_to_edges , current , previous_edge ) ;
if ( edge . IsNull ( ) ) {
return false ;
}
TopoDS_Vertex other = find_other ( edge , current ) ;
2014-03-31 14:00:02 +00:00
if ( other . IsNull ( ) ) {
// Dealing with a conical edge probably, for some reason
// this works better than adding the edge directly.
double u1 , u2 ;
Handle ( Geom_Curve ) crv = BRep_Tool : : Curve ( edge , u1 , u2 ) ;
w . Add ( BRepBuilderAPI_MakeEdge ( crv , u1 , u2 ) ) ;
break ;
} else {
w . Add ( edge ) ;
}
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
// See if the starting point of this loop has been reached. Note that
// additional wires after this one potentially will be created.
if ( other . IsSame ( first ) ) {
break ;
}
previous_edge = edge ;
current = other ;
}
sew . Add ( BRepBuilderAPI_MakeFace ( w ) ) ;
previous_edge . Nullify ( ) ;
}
sew . Perform ( ) ;
shape = sew . SewedShape ( ) ;
try {
ShapeFix_Solid solid ;
2014-12-19 12:14:36 +00:00
solid . LimitTolerance ( getValue ( GV_POINT_EQUALITY_TOLERANCE ) ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
shape = solid . SolidFromShell ( TopoDS : : Shell ( shape ) ) ;
2017-08-01 16:45:11 +02:00
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error creating solid " ) ;
}
} catch ( . . . ) {
Logger : : Error ( " Unknown error creating solid " ) ;
}
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
return true ;
2014-07-06 14:21:56 +00:00
}
2014-12-19 12:14:36 +00:00
bool IfcGeom : : Kernel : : flatten_shape_list ( const IfcGeom : : IfcRepresentationShapeItems & shapes , TopoDS_Shape & result , bool fuse ) {
2014-07-06 14:21:56 +00:00
TopoDS_Compound compound ;
BRep_Builder builder ;
builder . MakeCompound ( compound ) ;
result = TopoDS_Shape ( ) ;
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it = shapes . begin ( ) ; it ! = shapes . end ( ) ; + + it ) {
TopoDS_Shape merged ;
const TopoDS_Shape & s = it - > Shape ( ) ;
if ( fuse ) {
2014-12-19 12:14:36 +00:00
ensure_fit_for_subtraction ( s , merged ) ;
2014-07-06 14:21:56 +00:00
} else {
merged = s ;
}
const gp_GTrsf & trsf = it - > Placement ( ) ;
2016-05-03 11:01:47 +02:00
const TopoDS_Shape moved_shape = apply_transformation ( merged , trsf ) ;
2014-07-06 14:21:56 +00:00
if ( shapes . size ( ) = = 1 ) {
result = moved_shape ;
2015-02-06 17:14:05 +00:00
const double precision = getValue ( GV_PRECISION ) ;
apply_tolerance ( result , precision ) ;
2014-07-06 14:21:56 +00:00
return true ;
}
if ( fuse ) {
if ( result . IsNull ( ) ) {
result = moved_shape ;
} else {
BRepAlgoAPI_Fuse brep_fuse ( result , moved_shape ) ;
if ( brep_fuse . IsDone ( ) ) {
TopoDS_Shape fused = brep_fuse ;
ShapeFix_Shape fix ( result ) ;
fix . Perform ( ) ;
result = fix . Shape ( ) ;
bool is_valid = BRepCheck_Analyzer ( result ) . IsValid ( ) ! = 0 ;
if ( is_valid ) {
result = fused ;
}
}
}
} else {
builder . Add ( compound , moved_shape ) ;
}
}
2015-10-07 16:14:34 +02:00
if ( ! fuse ) {
result = compound ;
}
2015-02-06 17:14:05 +00:00
const bool success = ! result . IsNull ( ) ;
if ( success ) {
const double precision = getValue ( GV_PRECISION ) ;
apply_tolerance ( result , precision ) ;
}
return success ;
2014-07-06 14:21:56 +00:00
}
2014-07-28 20:03:53 +00:00
2016-01-22 17:27:28 +01:00
void IfcGeom : : Kernel : : remove_duplicate_points_from_loop ( TColgp_SequenceOfPnt & polygon , bool closed , double tol ) {
2016-12-10 14:11:01 +01:00
if ( tol < = 0. ) tol = getValue ( GV_PRECISION ) ;
2014-07-28 20:03:53 +00:00
tol * = tol ;
2015-11-21 23:05:28 +02:00
for ( ; ; ) {
2014-07-28 20:03:53 +00:00
bool removed = false ;
int n = polygon . Length ( ) - ( closed ? 0 : 1 ) ;
for ( int i = 1 ; i < = n ; + + i ) {
// wrap around to the first point in case of a closed loop
int j = ( i % polygon . Length ( ) ) + 1 ;
double dist = polygon . Value ( i ) . SquareDistance ( polygon . Value ( j ) ) ;
if ( dist < tol ) {
// do not remove the first or last point to
// maintain connectivity with other wires
if ( ( closed & & j = = 1 ) | | ( ! closed & & j = = n ) ) polygon . Remove ( i ) ;
else polygon . Remove ( j ) ;
removed = true ;
break ;
}
}
if ( ! removed ) break ;
}
2015-01-05 14:11:42 +00:00
}
2016-01-22 17:27:28 +01:00
void IfcGeom : : Kernel : : remove_collinear_points_from_loop ( TColgp_SequenceOfPnt & polygon , bool closed , double tol ) {
2016-12-10 14:11:01 +01:00
if ( tol < = 0. ) tol = getValue ( GV_PRECISION ) ;
2016-01-22 17:27:28 +01:00
const int start = closed ? 1 : 2 ;
const int end = polygon . Length ( ) - ( closed ? 0 : 1 ) ;
std : : vector < bool > to_remove ( polygon . Length ( ) , false ) ;
for ( int i = start ; i < = end ; + + i ) {
const gp_Pnt & a = polygon . Value ( ( ( i - 2 + polygon . Length ( ) ) % polygon . Length ( ) ) + 1 ) ;
const gp_Pnt & b = polygon . Value ( i ) ;
const gp_Pnt & c = polygon . Value ( ( i % polygon . Length ( ) ) + 1 ) ;
const gp_Vec d1 = c . XYZ ( ) - a . XYZ ( ) ;
const gp_Vec d2 = b . XYZ ( ) - a . XYZ ( ) ;
const double dt = d2 . Dot ( d1 ) / d1 . Dot ( d1 ) ;
const gp_Vec d3 = d1 . Scaled ( dt ) ;
const gp_Pnt b2 = a . XYZ ( ) + d3 . XYZ ( ) ;
if ( b . Distance ( b2 ) < tol ) {
to_remove [ i - 1 ] = true ;
}
}
2016-01-25 13:30:33 +01:00
for ( int i = ( int ) to_remove . size ( ) - 1 ; i > = 0 ; - - i ) {
2016-01-22 17:27:28 +01:00
if ( to_remove [ i ] ) {
polygon . Remove ( i + 1 ) ;
}
}
}
bool IfcGeom : : Kernel : : wire_to_sequence_of_point ( const TopoDS_Wire & w , TColgp_SequenceOfPnt & p ) {
TopExp_Explorer exp ( w , TopAbs_EDGE ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
double a , b ;
Handle_Geom_Curve crv = BRep_Tool : : Curve ( TopoDS : : Edge ( exp . Current ( ) ) , a , b ) ;
if ( crv - > DynamicType ( ) ! = STANDARD_TYPE ( Geom_Line ) ) {
return false ;
}
}
exp . ReInit ( ) ;
int i = 0 ;
for ( ; exp . More ( ) ; exp . Next ( ) , + + i ) {
TopoDS_Vertex v1 , v2 ;
TopExp : : Vertices ( TopoDS : : Edge ( exp . Current ( ) ) , v1 , v2 , true ) ;
if ( exp . More ( ) ) {
if ( i = = 0 ) {
p . Append ( BRep_Tool : : Pnt ( v1 ) ) ;
}
p . Append ( BRep_Tool : : Pnt ( v2 ) ) ;
}
}
return true ;
}
void IfcGeom : : Kernel : : sequence_of_point_to_wire ( const TColgp_SequenceOfPnt & p , TopoDS_Wire & w , bool close ) {
BRepBuilderAPI_MakePolygon builder ;
for ( int i = 1 ; i < = p . Length ( ) ; + + i ) {
builder . Add ( p . Value ( i ) ) ;
}
if ( close ) {
builder . Close ( ) ;
}
w = builder . Wire ( ) ;
}
2016-03-18 11:23:25 +01:00
IfcSchema : : IfcRelVoidsElement : : list : : ptr IfcGeom : : Kernel : : find_openings ( IfcSchema : : IfcProduct * product ) {
IfcSchema : : IfcRelVoidsElement : : list : : ptr openings ( new IfcSchema : : IfcRelVoidsElement : : list ) ;
if ( product - > is ( IfcSchema : : Type : : IfcElement ) & & ! product - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
IfcSchema : : IfcElement * element = ( IfcSchema : : IfcElement * ) product ;
openings = element - > HasOpenings ( ) ;
}
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
IfcSchema : : IfcObjectDefinition * obdef = product - > as < IfcSchema : : IfcObjectDefinition > ( ) ;
for ( ; ; ) {
# ifdef USE_IFC4
IfcSchema : : IfcRelAggregates : : list : : ptr decomposes = obdef - > Decomposes ( ) ;
# else
IfcSchema : : IfcRelDecomposes : : list : : ptr decomposes = obdef - > Decomposes ( ) ;
# endif
2016-05-18 17:15:44 +02:00
if ( decomposes - > size ( ) ! = 1 ) break ;
2016-03-18 11:23:25 +01:00
IfcSchema : : IfcObjectDefinition * rel_obdef = ( * decomposes - > begin ( ) ) - > RelatingObject ( ) ;
if ( rel_obdef - > is ( IfcSchema : : Type : : IfcElement ) & & ! rel_obdef - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
IfcSchema : : IfcElement * element = ( IfcSchema : : IfcElement * ) rel_obdef ;
openings - > push ( element - > HasOpenings ( ) ) ;
}
obdef = rel_obdef ;
}
return openings ;
}
2017-10-06 15:36:51 +02:00
const IfcSchema : : IfcMaterial * IfcGeom : : Kernel : : get_single_material_association ( const IfcSchema : : IfcProduct * product ) {
IfcSchema : : IfcMaterial * single_material = 0 ;
IfcSchema : : IfcRelAssociatesMaterial : : list : : ptr associated_materials = product - > HasAssociations ( ) - > as < IfcSchema : : IfcRelAssociatesMaterial > ( ) ;
if ( associated_materials - > size ( ) = = 1 ) {
IfcSchema : : IfcMaterialSelect * associated_material = ( * associated_materials - > begin ( ) ) - > RelatingMaterial ( ) ;
single_material = associated_material - > as < IfcSchema : : IfcMaterial > ( ) ;
// TODO: Should this check for APPLY_LAYERSETS setting?
if ( ! single_material & & associated_material - > as < IfcSchema : : IfcMaterialLayerSetUsage > ( ) ) {
IfcSchema : : IfcMaterialLayerSet * layerset = associated_material - > as < IfcSchema : : IfcMaterialLayerSetUsage > ( ) - > ForLayerSet ( ) ;
if ( layerset - > MaterialLayers ( ) - > size ( ) = = 1 ) {
IfcSchema : : IfcMaterialLayer * layer = ( * layerset - > MaterialLayers ( ) - > begin ( ) ) ;
if ( layer - > hasMaterial ( ) ) {
single_material = layer - > Material ( ) ;
}
}
}
}
return single_material ;
}
2015-01-05 14:11:42 +00:00
template < typename P >
2016-07-11 21:36:12 +03:00
IfcGeom : : BRepElement < P > * IfcGeom : : Kernel : : create_brep_for_representation_and_product (
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product )
{
2017-06-28 15:24:49 +02:00
std : : stringstream representation_id_builder ;
representation_id_builder < < representation - > entity - > id ( ) ;
2015-01-05 14:11:42 +00:00
IfcGeom : : Representation : : BRep * shape ;
2015-10-07 17:33:30 +02:00
IfcGeom : : IfcRepresentationShapeItems shapes , shapes2 ;
2015-01-05 14:11:42 +00:00
2015-10-07 17:33:30 +02:00
if ( ! convert_shapes ( representation , shapes ) ) {
2015-01-05 14:11:42 +00:00
return 0 ;
}
2016-05-02 15:13:30 +02:00
if ( settings . get ( IteratorSettings : : APPLY_LAYERSETS ) ) {
2015-10-07 17:33:30 +02:00
TopoDS_Shape merge ;
if ( flatten_shape_list ( shapes , merge , false ) ) {
if ( count ( merge , TopAbs_FACE ) > 0 ) {
std : : vector < double > thickness ;
std : : vector < Handle_Geom_Surface > layers ;
std : : vector < std : : vector < Handle_Geom_Surface > > folded_layers ;
std : : vector < const SurfaceStyle * > styles ;
if ( convert_layerset ( product , layers , styles , thickness ) ) {
2017-06-28 15:24:49 +02:00
IfcSchema : : IfcRelAssociates : : list : : ptr associations = product - > HasAssociations ( ) ;
for ( IfcSchema : : IfcRelAssociates : : list : : it it = associations - > begin ( ) ; it ! = associations - > end ( ) ; + + it ) {
IfcSchema : : IfcRelAssociatesMaterial * associates_material = ( * * it ) . as < IfcSchema : : IfcRelAssociatesMaterial > ( ) ;
if ( associates_material ) {
unsigned layerset_id = associates_material - > RelatingMaterial ( ) - > entity - > id ( ) ;
representation_id_builder < < " -layerset- " < < layerset_id ;
break ;
}
}
2015-10-07 17:33:30 +02:00
if ( product - > as < IfcSchema : : IfcWall > ( ) & & fold_layers ( product - > as < IfcSchema : : IfcWall > ( ) , shapes , layers , thickness , folded_layers ) ) {
2016-05-02 15:56:08 +02:00
if ( apply_folded_layerset ( shapes , folded_layers , styles , shapes2 ) ) {
2015-10-07 17:33:30 +02:00
std : : swap ( shapes , shapes2 ) ;
}
} else {
2016-05-02 15:56:08 +02:00
if ( apply_layerset ( shapes , layers , styles , shapes2 ) ) {
2015-10-07 17:33:30 +02:00
std : : swap ( shapes , shapes2 ) ;
}
}
}
}
}
}
2017-10-06 15:36:51 +02:00
bool material_style_applied = false ;
const IfcSchema : : IfcMaterial * single_material = get_single_material_association ( product ) ;
if ( single_material ) {
const IfcGeom : : SurfaceStyle * s = get_style ( single_material ) ;
2017-10-06 16:01:18 +02:00
for ( IfcGeom : : IfcRepresentationShapeItems : : iterator it = shapes . begin ( ) ; it ! = shapes . end ( ) ; + + it ) {
2017-10-06 15:36:51 +02:00
if ( ! it - > hasStyle ( ) & & s ) {
it - > setStyle ( s ) ;
material_style_applied = true ;
}
}
}
if ( material_style_applied ) {
representation_id_builder < < " -material- " < < single_material - > entity - > id ( ) ;
}
2015-01-05 14:11:42 +00:00
int parent_id = - 1 ;
try {
IfcSchema : : IfcObjectDefinition * parent_object = get_decomposing_entity ( product ) ;
if ( parent_object ) {
parent_id = parent_object - > entity - > id ( ) ;
}
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
2015-01-05 14:11:42 +00:00
const std : : string name = product - > hasName ( ) ? product - > Name ( ) : " " ;
const std : : string guid = product - > GlobalId ( ) ;
gp_Trsf trsf ;
try {
convert ( product - > ObjectPlacement ( ) , trsf ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
2015-01-05 14:11:42 +00:00
// Does the IfcElement have any IfcOpenings?
// Note that openings for IfcOpeningElements are not processed
2016-03-18 11:23:25 +01:00
IfcSchema : : IfcRelVoidsElement : : list : : ptr openings = find_openings ( product ) ;
2015-01-05 14:11:42 +00:00
const std : : string product_type = IfcSchema : : Type : : ToString ( product - > type ( ) ) ;
ElementSettings element_settings ( settings , getValue ( GV_LENGTH_UNIT ) , product_type ) ;
2016-03-07 22:37:36 +02:00
if ( ! settings . get ( IfcGeom : : IteratorSettings : : DISABLE_OPENING_SUBTRACTIONS ) & & openings & & openings - > size ( ) ) {
2017-06-28 15:24:49 +02:00
representation_id_builder < < " -openings " ;
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
representation_id_builder < < " - " < < ( * it ) - > entity - > id ( ) ;
}
2015-01-05 14:11:42 +00:00
IfcGeom : : IfcRepresentationShapeItems opened_shapes ;
2018-09-17 14:11:03 +02:00
bool caught_error = false ;
2015-01-05 14:11:42 +00:00
try {
2016-01-25 13:30:33 +01:00
# if OCC_VERSION_HEX < 0x60900
2016-03-07 22:37:36 +02:00
const bool faster_booleans = settings . get ( IteratorSettings : : FASTER_BOOLEANS ) ;
2016-01-25 13:30:33 +01:00
# else
const bool faster_booleans = true ;
# endif
if ( faster_booleans ) {
2017-11-13 12:41:37 +01:00
bool success = convert_openings_fast ( product , openings , shapes , trsf , opened_shapes ) ;
# if OCC_VERSION_HEX < 0x60900
2017-11-13 13:01:59 +01:00
if ( ! success ) {
2015-01-05 14:11:42 +00:00
opened_shapes . clear ( ) ;
convert_openings ( product , openings , shapes , trsf , opened_shapes ) ;
}
2017-11-13 12:41:37 +01:00
# else
( void ) success ;
# endif
2015-01-05 14:11:42 +00:00
} else {
convert_openings ( product , openings , shapes , trsf , opened_shapes ) ;
}
2018-09-12 16:44:30 +02:00
} catch ( const std : : exception & e ) {
Logger : : Message ( Logger : : LOG_ERROR , std : : string ( " Error processing openings for: " ) + e . what ( ) + " : " , product - > entity ) ;
2018-09-17 14:11:03 +02:00
caught_error = true ;
2018-09-12 16:44:30 +02:00
} catch ( . . . ) {
2015-01-05 14:11:42 +00:00
Logger : : Message ( Logger : : LOG_ERROR , " Error processing openings for: " , product - > entity ) ;
2018-09-17 14:11:03 +02:00
caught_error = true ;
2015-01-05 14:11:42 +00:00
}
2018-09-17 14:11:03 +02:00
if ( caught_error & & opened_shapes . size ( ) < shapes . size ( ) ) {
opened_shapes = shapes ;
}
2016-03-07 22:37:36 +02:00
if ( settings . get ( IteratorSettings : : USE_WORLD_COORDS ) ) {
2015-01-05 14:11:42 +00:00
for ( IfcGeom : : IfcRepresentationShapeItems : : iterator it = opened_shapes . begin ( ) ; it ! = opened_shapes . end ( ) ; + + it ) {
it - > prepend ( trsf ) ;
}
trsf = gp_Trsf ( ) ;
2017-06-28 15:24:49 +02:00
representation_id_builder < < " -world-coords " ;
2015-01-05 14:11:42 +00:00
}
2017-06-28 15:24:49 +02:00
shape = new IfcGeom : : Representation : : BRep ( element_settings , representation_id_builder . str ( ) , opened_shapes ) ;
2016-03-07 22:37:36 +02:00
} else if ( settings . get ( IteratorSettings : : USE_WORLD_COORDS ) ) {
2015-01-05 14:11:42 +00:00
for ( IfcGeom : : IfcRepresentationShapeItems : : iterator it = shapes . begin ( ) ; it ! = shapes . end ( ) ; + + it ) {
it - > prepend ( trsf ) ;
}
trsf = gp_Trsf ( ) ;
2017-06-28 15:24:49 +02:00
representation_id_builder < < " -world-coords " ;
shape = new IfcGeom : : Representation : : BRep ( element_settings , representation_id_builder . str ( ) , shapes ) ;
2015-01-05 14:11:42 +00:00
} else {
2017-06-28 15:24:49 +02:00
shape = new IfcGeom : : Representation : : BRep ( element_settings , representation_id_builder . str ( ) , shapes ) ;
2015-01-05 14:11:42 +00:00
}
2015-04-22 09:15:48 +00:00
std : : string context_string = " " ;
if ( representation - > hasRepresentationIdentifier ( ) ) {
context_string = representation - > RepresentationIdentifier ( ) ;
} else if ( representation - > ContextOfItems ( ) - > hasContextType ( ) ) {
context_string = representation - > ContextOfItems ( ) - > ContextType ( ) ;
}
2015-01-05 14:11:42 +00:00
return new BRepElement < P > (
product - > entity - > id ( ) ,
parent_id ,
name ,
product_type ,
guid ,
2015-04-22 09:15:48 +00:00
context_string ,
2015-01-05 14:11:42 +00:00
trsf ,
2017-02-07 17:34:23 +02:00
boost : : shared_ptr < IfcGeom : : Representation : : BRep > ( shape ) ,
product
2016-03-18 11:23:25 +01:00
) ;
}
2017-10-06 15:36:51 +02:00
IfcSchema : : IfcRepresentation * IfcGeom : : Kernel : : representation_mapped_to ( const IfcSchema : : IfcRepresentation * representation ) {
IfcSchema : : IfcRepresentation * representation_mapped_to = 0 ;
IfcSchema : : IfcRepresentationItem : : list : : ptr items = representation - > Items ( ) ;
if ( items - > size ( ) = = 1 ) {
IfcSchema : : IfcRepresentationItem * item = * items - > begin ( ) ;
if ( item - > is ( IfcSchema : : Type : : IfcMappedItem ) ) {
if ( item - > StyledByItem ( ) - > size ( ) = = 0 ) {
IfcSchema : : IfcMappedItem * mapped_item = item - > as < IfcSchema : : IfcMappedItem > ( ) ;
if ( is_identity_transform ( mapped_item - > MappingTarget ( ) ) ) {
IfcSchema : : IfcRepresentationMap * map = mapped_item - > MappingSource ( ) ;
if ( is_identity_transform ( map - > MappingOrigin ( ) ) ) {
representation_mapped_to = map - > MappedRepresentation ( ) ;
}
}
}
}
}
return representation_mapped_to ;
}
IfcSchema : : IfcProduct : : list : : ptr IfcGeom : : Kernel : : products_represented_by ( const IfcSchema : : IfcRepresentation * representation ) {
IfcSchema : : IfcProduct : : list : : ptr products ( new IfcSchema : : IfcProduct : : list ) ;
IfcSchema : : IfcProductRepresentation : : list : : ptr prodreps = representation - > OfProductRepresentation ( ) ;
for ( IfcSchema : : IfcProductRepresentation : : list : : it it = prodreps - > begin ( ) ; it ! = prodreps - > end ( ) ; + + it ) {
// http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// It will be changed into an ABSTRACT supertype in future releases of IFC.
// IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// Let's find the IfcProducts that reference the IfcProductRepresentation anyway
products - > push ( ( * it ) - > entity - > getInverse ( IfcSchema : : Type : : IfcProduct , - 1 ) - > as < IfcSchema : : IfcProduct > ( ) ) ;
}
IfcSchema : : IfcRepresentationMap : : list : : ptr maps = representation - > RepresentationMap ( ) ;
if ( maps - > size ( ) = = 1 ) {
IfcSchema : : IfcRepresentationMap * map = * maps - > begin ( ) ;
if ( is_identity_transform ( map - > MappingOrigin ( ) ) ) {
IfcSchema : : IfcMappedItem : : list : : ptr items = map - > MapUsage ( ) ;
for ( IfcSchema : : IfcMappedItem : : list : : it it = items - > begin ( ) ; it ! = items - > end ( ) ; + + it ) {
IfcSchema : : IfcMappedItem * item = * it ;
if ( item - > StyledByItem ( ) - > size ( ) ! = 0 ) continue ;
if ( ! is_identity_transform ( item - > MappingTarget ( ) ) ) {
continue ;
}
IfcSchema : : IfcRepresentation : : list : : ptr reps = item - > entity - > getInverse ( IfcSchema : : Type : : IfcRepresentation , - 1 ) - > as < IfcSchema : : IfcRepresentation > ( ) ;
for ( IfcSchema : : IfcRepresentation : : list : : it jt = reps - > begin ( ) ; jt ! = reps - > end ( ) ; + + jt ) {
IfcSchema : : IfcRepresentation * rep = * jt ;
if ( rep - > Items ( ) - > size ( ) ! = 1 ) continue ;
IfcSchema : : IfcProductRepresentation : : list : : ptr prodreps_mapped = rep - > OfProductRepresentation ( ) ;
for ( IfcSchema : : IfcProductRepresentation : : list : : it kt = prodreps_mapped - > begin ( ) ; kt ! = prodreps_mapped - > end ( ) ; + + kt ) {
IfcSchema : : IfcProduct : : list : : ptr ps = ( * kt ) - > entity - > getInverse ( IfcSchema : : Type : : IfcProduct , - 1 ) - > as < IfcSchema : : IfcProduct > ( ) ;
products - > push ( ps ) ;
}
}
}
}
}
return products ;
}
2016-03-18 11:23:25 +01:00
template < typename P >
2016-07-11 21:36:12 +03:00
IfcGeom : : BRepElement < P > * IfcGeom : : Kernel : : create_brep_for_processed_representation (
const IteratorSettings & /*settings*/ , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product ,
IfcGeom : : BRepElement < P > * brep )
{
2016-03-18 11:23:25 +01:00
int parent_id = - 1 ;
try {
IfcSchema : : IfcObjectDefinition * parent_object = get_decomposing_entity ( product ) ;
if ( parent_object ) {
parent_id = parent_object - > entity - > id ( ) ;
}
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
2016-03-18 11:23:25 +01:00
const std : : string name = product - > hasName ( ) ? product - > Name ( ) : " " ;
const std : : string guid = product - > GlobalId ( ) ;
gp_Trsf trsf ;
try {
convert ( product - > ObjectPlacement ( ) , trsf ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
2016-03-18 11:23:25 +01:00
std : : string context_string = " " ;
if ( representation - > hasRepresentationIdentifier ( ) ) {
context_string = representation - > RepresentationIdentifier ( ) ;
} else if ( representation - > ContextOfItems ( ) - > hasContextType ( ) ) {
context_string = representation - > ContextOfItems ( ) - > ContextType ( ) ;
}
const std : : string product_type = IfcSchema : : Type : : ToString ( product - > type ( ) ) ;
return new BRepElement < P > (
product - > entity - > id ( ) ,
parent_id ,
name ,
product_type ,
guid ,
context_string ,
trsf ,
2017-02-07 17:34:23 +02:00
brep - > geometry_pointer ( ) ,
product
2015-01-05 14:11:42 +00:00
) ;
}
IfcSchema : : IfcObjectDefinition * IfcGeom : : Kernel : : get_decomposing_entity ( IfcSchema : : IfcProduct * product ) {
IfcSchema : : IfcObjectDefinition * parent = 0 ;
// In case of an opening element, parent to the RelatingBuildingElement
if ( product - > is ( IfcSchema : : Type : : IfcOpeningElement ) ) {
IfcSchema : : IfcOpeningElement * opening = ( IfcSchema : : IfcOpeningElement * ) product ;
IfcSchema : : IfcRelVoidsElement : : list : : ptr voids = opening - > VoidsElements ( ) ;
2015-01-10 22:13:52 +00:00
if ( voids - > size ( ) ) {
2015-01-05 14:11:42 +00:00
IfcSchema : : IfcRelVoidsElement * ifc_void = * voids - > begin ( ) ;
parent = ifc_void - > RelatingBuildingElement ( ) ;
}
} else if ( product - > is ( IfcSchema : : Type : : IfcElement ) ) {
IfcSchema : : IfcElement * element = ( IfcSchema : : IfcElement * ) product ;
IfcSchema : : IfcRelFillsElement : : list : : ptr fills = element - > FillsVoids ( ) ;
2017-02-07 17:34:23 +02:00
// In case of a RelatedBuildingElement parent to the opening element
2015-01-10 22:13:52 +00:00
if ( fills - > size ( ) ) {
2015-01-05 14:11:42 +00:00
for ( IfcSchema : : IfcRelFillsElement : : list : : it it = fills - > begin ( ) ; it ! = fills - > end ( ) ; + + it ) {
IfcSchema : : IfcRelFillsElement * fill = * it ;
IfcSchema : : IfcObjectDefinition * ifc_objectdef = fill - > RelatingOpeningElement ( ) ;
if ( product = = ifc_objectdef ) continue ;
parent = ifc_objectdef ;
}
}
// Else simply parent to the containing structure
if ( ! parent ) {
IfcSchema : : IfcRelContainedInSpatialStructure : : list : : ptr parents = element - > ContainedInStructure ( ) ;
2015-01-10 22:13:52 +00:00
if ( parents - > size ( ) ) {
2015-01-05 14:11:42 +00:00
IfcSchema : : IfcRelContainedInSpatialStructure * container = * parents - > begin ( ) ;
parent = container - > RelatingStructure ( ) ;
}
}
}
// Parent decompositions to the RelatingObject
if ( ! parent ) {
2015-01-10 22:13:52 +00:00
IfcEntityList : : ptr parents = product - > entity - > getInverse ( IfcSchema : : Type : : IfcRelAggregates , - 1 ) ;
parents - > push ( product - > entity - > getInverse ( IfcSchema : : Type : : IfcRelNests , - 1 ) ) ;
2015-01-05 14:11:42 +00:00
for ( IfcEntityList : : it it = parents - > begin ( ) ; it ! = parents - > end ( ) ; + + it ) {
IfcSchema : : IfcRelDecomposes * decompose = ( IfcSchema : : IfcRelDecomposes * ) * it ;
IfcSchema : : IfcObjectDefinition * ifc_objectdef ;
# ifdef USE_IFC4
if ( decompose - > is ( IfcSchema : : Type : : IfcRelAggregates ) ) {
ifc_objectdef = ( ( IfcSchema : : IfcRelAggregates * ) decompose ) - > RelatingObject ( ) ;
} else {
continue ;
}
# else
ifc_objectdef = decompose - > RelatingObject ( ) ;
# endif
if ( product = = ifc_objectdef ) continue ;
parent = ifc_objectdef ;
}
}
return parent ;
}
2017-02-03 11:02:24 +02:00
std : : map < std : : string , IfcSchema : : IfcPresentationLayerAssignment * > IfcGeom : : Kernel : : get_layers ( IfcSchema : : IfcProduct * prod )
{
using namespace IfcSchema ;
std : : map < std : : string , IfcPresentationLayerAssignment * > layers ;
if ( prod - > hasRepresentation ( ) ) {
IfcEntityList : : ptr r = prod - > entity - > file - > traverse ( prod - > Representation ( ) ) ;
IfcRepresentation : : list : : ptr representations = r - > as < IfcRepresentation > ( ) ;
for ( IfcRepresentation : : list : : it it = representations - > begin ( ) ; it ! = representations - > end ( ) ; + + it ) {
IfcPresentationLayerAssignment : : list : : ptr a = ( * it ) - > LayerAssignments ( ) ;
for ( IfcPresentationLayerAssignment : : list : : it jt = a - > begin ( ) ; jt ! = a - > end ( ) ; + + jt ) {
layers [ ( * jt ) - > Name ( ) ] = * jt ;
}
}
IfcRepresentationItem : : list : : ptr items = r - > as < IfcRepresentationItem > ( ) ;
for ( IfcRepresentationItem : : list : : it it = items - > begin ( ) ; it ! = items - > end ( ) ; + + it ) {
IfcPresentationLayerAssignment : : list : : ptr a = ( * it ) - >
// LayerAssignments renamed from plural to singular, LayerAssignment, so work around that
# ifdef USE_IFC4
LayerAssignment ( ) ;
# else
LayerAssignments ( ) ;
# endif
for ( IfcPresentationLayerAssignment : : list : : it jt = a - > begin ( ) ; jt ! = a - > end ( ) ; + + jt ) {
layers [ ( * jt ) - > Name ( ) ] = * jt ;
}
}
}
return layers ;
}
2016-07-11 21:36:12 +03:00
template IFC_GEOM_API IfcGeom : : BRepElement < float > * IfcGeom : : Kernel : : create_brep_for_representation_and_product < float > (
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product ) ;
template IFC_GEOM_API IfcGeom : : BRepElement < double > * IfcGeom : : Kernel : : create_brep_for_representation_and_product < double > (
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product ) ;
2015-01-05 14:11:42 +00:00
2016-07-11 21:36:12 +03:00
template IFC_GEOM_API IfcGeom : : BRepElement < float > * IfcGeom : : Kernel : : create_brep_for_processed_representation < float > (
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product , IfcGeom : : BRepElement < float > * brep ) ;
template IFC_GEOM_API IfcGeom : : BRepElement < double > * IfcGeom : : Kernel : : create_brep_for_processed_representation < double > (
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product , IfcGeom : : BRepElement < double > * brep ) ;
2016-03-18 11:23:25 +01:00
2015-01-05 14:11:42 +00:00
std : : pair < std : : string , double > IfcGeom : : Kernel : : initializeUnits ( IfcSchema : : IfcUnitAssignment * unit_assignment ) {
// Set default units, set length to meters, angles to undefined
setValue ( IfcGeom : : Kernel : : GV_LENGTH_UNIT , 1.0 ) ;
setValue ( IfcGeom : : Kernel : : GV_PLANEANGLE_UNIT , - 1.0 ) ;
std : : string unit_name = " METER " ;
double unit_magnitude = 1. ;
2018-09-07 14:25:46 +02:00
bool length_unit_encountered = false , angle_unit_encountered = false ;
2015-01-05 14:11:42 +00:00
try {
IfcEntityList : : ptr units = unit_assignment - > Units ( ) ;
2015-01-10 22:13:52 +00:00
if ( ! units | | ! units - > size ( ) ) {
2015-01-05 14:11:42 +00:00
Logger : : Message ( Logger : : LOG_ERROR , " No unit information found " ) ;
} else {
2016-05-24 13:50:50 +02:00
for ( IfcEntityList : : it it = units - > begin ( ) ; it ! = units - > end ( ) ; + + it ) {
2015-01-05 14:11:42 +00:00
IfcUtil : : IfcBaseClass * base = * it ;
2016-05-24 13:50:50 +02:00
if ( base - > is ( IfcSchema : : Type : : IfcNamedUnit ) ) {
IfcSchema : : IfcNamedUnit * named_unit = base - > as < IfcSchema : : IfcNamedUnit > ( ) ;
if ( named_unit - > UnitType ( ) = = IfcSchema : : IfcUnitEnum : : IfcUnit_LENGTHUNIT | |
named_unit - > UnitType ( ) = = IfcSchema : : IfcUnitEnum : : IfcUnit_PLANEANGLEUNIT )
{
std : : string current_unit_name ;
const double current_unit_magnitude = IfcParse : : get_SI_equivalent ( named_unit ) ;
if ( current_unit_magnitude ! = 0. ) {
if ( named_unit - > is ( IfcSchema : : Type : : IfcConversionBasedUnit ) ) {
IfcSchema : : IfcConversionBasedUnit * u = ( IfcSchema : : IfcConversionBasedUnit * ) base ;
current_unit_name = u - > Name ( ) ;
} else if ( named_unit - > is ( IfcSchema : : Type : : IfcSIUnit ) ) {
IfcSchema : : IfcSIUnit * si_unit = named_unit - > as < IfcSchema : : IfcSIUnit > ( ) ;
if ( si_unit - > hasPrefix ( ) ) {
current_unit_name = IfcSchema : : IfcSIPrefix : : ToString ( si_unit - > Prefix ( ) ) + unit_name ;
}
current_unit_name + = IfcSchema : : IfcSIUnitName : : ToString ( si_unit - > Name ( ) ) ;
}
if ( named_unit - > UnitType ( ) = = IfcSchema : : IfcUnitEnum : : IfcUnit_LENGTHUNIT ) {
unit_name = current_unit_name ;
unit_magnitude = current_unit_magnitude ;
setValue ( IfcGeom : : Kernel : : GV_LENGTH_UNIT , current_unit_magnitude ) ;
2018-09-07 14:25:46 +02:00
length_unit_encountered = true ;
2016-05-24 13:50:50 +02:00
} else {
setValue ( IfcGeom : : Kernel : : GV_PLANEANGLE_UNIT , current_unit_magnitude ) ;
2018-09-07 14:25:46 +02:00
angle_unit_encountered = true ;
2015-01-05 14:11:42 +00:00
}
}
}
}
}
}
} catch ( const IfcParse : : IfcException & ex ) {
std : : stringstream ss ;
ss < < " Failed to determine unit information ' " < < ex . what ( ) < < " ' " ;
Logger : : Message ( Logger : : LOG_ERROR , ss . str ( ) ) ;
}
2018-09-07 14:25:46 +02:00
if ( ! length_unit_encountered ) {
Logger : : Error ( " No length unit encountered " ) ;
}
if ( ! angle_unit_encountered ) {
Logger : : Error ( " No plane angle unit encountered " ) ;
}
2015-01-05 14:11:42 +00:00
return std : : pair < std : : string , double > ( unit_name , unit_magnitude ) ;
2015-10-07 17:33:30 +02:00
}
bool IfcGeom : : Kernel : : convert_layerset ( const IfcSchema : : IfcProduct * product , std : : vector < Handle_Geom_Surface > & surfaces , std : : vector < const SurfaceStyle * > & styles , std : : vector < double > & thicknesses ) {
IfcSchema : : IfcMaterialLayerSetUsage * usage = 0 ;
Handle_Geom_Surface reference_surface ;
IfcSchema : : IfcRelAssociates : : list : : ptr associations = product - > HasAssociations ( ) ;
for ( IfcSchema : : IfcRelAssociates : : list : : it it = associations - > begin ( ) ; it ! = associations - > end ( ) ; + + it ) {
IfcSchema : : IfcRelAssociatesMaterial * associates_material = ( * * it ) . as < IfcSchema : : IfcRelAssociatesMaterial > ( ) ;
if ( associates_material ) {
usage = associates_material - > RelatingMaterial ( ) - > as < IfcSchema : : IfcMaterialLayerSetUsage > ( ) ;
break ;
}
}
if ( ! usage ) {
return false ;
}
IfcSchema : : IfcRepresentation * body_representation = find_representation ( product , " Body " ) ;
IfcSchema : : IfcRepresentation * axis_representation = find_representation ( product , " Axis " ) ;
if ( product - > is ( IfcSchema : : Type : : IfcWall ) ) {
if ( ! axis_representation ) {
Logger : : Message ( Logger : : LOG_WARNING , " No axis representation for: " , product - > entity ) ;
return false ;
}
IfcRepresentationShapeItems axis_items ;
{
Kernel temp = * this ;
temp . setValue ( GV_DIMENSIONALITY , - 1. ) ;
temp . convert_shapes ( axis_representation , axis_items ) ;
}
TopoDS_Shape axis_shape ;
flatten_shape_list ( axis_items , axis_shape , false ) ;
TopExp_Explorer exp ( axis_shape , TopAbs_EDGE ) ;
TopoDS_Edge axis_edge ;
int edge_count = 0 ;
2016-05-02 15:56:08 +02:00
if ( exp . More ( ) ) {
2015-10-07 17:33:30 +02:00
axis_edge = TopoDS : : Edge ( exp . Current ( ) ) ;
+ + edge_count ;
2016-05-02 15:56:08 +02:00
} else {
2015-10-07 17:33:30 +02:00
Logger : : Message ( Logger : : LOG_WARNING , " No edge found in axis representation: " , product - > entity ) ;
return false ;
}
double u1 , u2 ;
Handle_Geom_Curve axis_curve = BRep_Tool : : Curve ( axis_edge , u1 , u2 ) ;
2016-05-30 13:44:03 +03:00
if ( true ) { /**< @todo Why always true? */
2015-10-07 17:33:30 +02:00
if ( axis_curve - > DynamicType ( ) = = STANDARD_TYPE ( Geom_Line ) ) {
Handle_Geom_Line axis_line = Handle_Geom_Line : : DownCast ( axis_curve ) ;
reference_surface = new Geom_Plane ( axis_line - > Lin ( ) . Location ( ) , axis_line - > Lin ( ) . Direction ( ) ^ gp : : DZ ( ) ) ;
} else if ( axis_curve - > DynamicType ( ) = = STANDARD_TYPE ( Geom_Circle ) ) {
Handle_Geom_Circle axis_line = Handle_Geom_Circle : : DownCast ( axis_curve ) ;
reference_surface = new Geom_CylindricalSurface ( axis_line - > Position ( ) , axis_line - > Radius ( ) ) ;
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Unsupported underlying curve of Axis representation: " , product - > entity ) ;
return false ;
}
} else {
// Unfortunately this does not work when its intersection
// is calculated later on when the layerset is applied.
reference_surface = new Geom_SurfaceOfLinearExtrusion ( axis_curve , gp : : DZ ( ) ) ;
}
} else {
IfcSchema : : IfcExtrudedAreaSolid : : list : : ptr extrusions = body_representation - > entity - > file - > traverse ( body_representation ) - > as < IfcSchema : : IfcExtrudedAreaSolid > ( ) ;
if ( extrusions - > size ( ) ! = 1 ) {
Logger : : Message ( Logger : : LOG_WARNING , " No single extrusion found in body representation for: " , product - > entity ) ;
return false ;
}
IfcSchema : : IfcExtrudedAreaSolid * extrusion = * extrusions - > begin ( ) ;
gp_Trsf extrusion_position ;
2017-08-09 17:01:10 +02:00
bool has_position = true ;
# ifdef USE_IFC4
has_position = extrusion - > hasPosition ( ) ;
# endif
if ( has_position ) {
if ( ! convert ( extrusion - > Position ( ) , extrusion_position ) ) {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to convert placement for extrusion of: " , product - > entity ) ;
return false ;
}
2015-10-07 17:33:30 +02:00
}
gp_Dir extrusion_direction ;
if ( ! convert ( extrusion - > ExtrudedDirection ( ) , extrusion_direction ) ) {
Logger : : Message ( Logger : : LOG_ERROR , " Failed to convert direction for extrusion of: " , product - > entity ) ;
return false ;
}
reference_surface = new Geom_Plane ( extrusion_position . TranslationPart ( ) , extrusion_direction ) ;
}
const IfcSchema : : IfcMaterialLayerSet * layerset = usage - > ForLayerSet ( ) ;
const bool positive = usage - > DirectionSense ( ) = = IfcSchema : : IfcDirectionSenseEnum : : IfcDirectionSense_POSITIVE ;
double offset = usage - > OffsetFromReferenceLine ( ) * getValue ( GV_LENGTH_UNIT ) ;
IfcSchema : : IfcMaterialLayer : : list : : ptr material_layers = layerset - > MaterialLayers ( ) ;
surfaces . push_back ( new Geom_OffsetSurface ( reference_surface , - offset ) ) ;
for ( IfcSchema : : IfcMaterialLayer : : list : : it it = material_layers - > begin ( ) ; it ! = material_layers - > end ( ) ; + + it ) {
styles . push_back ( get_style ( ( * it ) - > Material ( ) ) ) ;
double thickness = ( * it ) - > LayerThickness ( ) * getValue ( GV_LENGTH_UNIT ) ;
thicknesses . push_back ( thickness ) ;
if ( ! positive ) {
thickness * = - 1 ;
}
offset + = thickness ;
if ( fabs ( offset ) < 1.e-7 ) {
surfaces . push_back ( reference_surface ) ;
} else {
surfaces . push_back ( new Geom_OffsetSurface ( reference_surface , - offset ) ) ;
}
}
if ( positive ) {
std : : reverse ( surfaces . begin ( ) , surfaces . end ( ) ) ;
}
return true ;
}
const Handle_Geom_Curve IfcGeom : : Kernel : : intersect ( const Handle_Geom_Surface & a , const Handle_Geom_Surface & b ) {
GeomAPI_IntSS x ( a , b , 1.e-7 ) ;
if ( x . IsDone ( ) & & x . NbLines ( ) = = 1 ) {
return x . Line ( 1 ) ;
} else {
return Handle_Geom_Curve ( ) ;
}
}
const Handle_Geom_Curve IfcGeom : : Kernel : : intersect ( const Handle_Geom_Surface & a , const TopoDS_Face & b ) {
return intersect ( a , BRep_Tool : : Surface ( b ) ) ;
}
const Handle_Geom_Curve IfcGeom : : Kernel : : intersect ( const TopoDS_Face & a , const Handle_Geom_Surface & b ) {
return intersect ( BRep_Tool : : Surface ( a ) , b ) ;
}
2016-05-02 15:56:08 +02:00
bool IfcGeom : : Kernel : : intersect ( const Handle_Geom_Curve & a , const Handle_Geom_Surface & b , gp_Pnt & p ) {
2015-10-07 17:33:30 +02:00
GeomAPI_IntCS x ( a , b ) ;
if ( x . IsDone ( ) & & x . NbPoints ( ) = = 1 ) {
p = x . Point ( 1 ) ;
return true ;
} else {
return false ;
}
}
bool IfcGeom : : Kernel : : intersect ( const Handle_Geom_Curve & a , const TopoDS_Face & b , gp_Pnt & c ) {
2016-05-02 15:56:08 +02:00
return intersect ( a , BRep_Tool : : Surface ( b ) , c ) ;
2015-10-07 17:33:30 +02:00
}
bool IfcGeom : : Kernel : : intersect ( const Handle_Geom_Curve & a , const TopoDS_Shape & b , std : : vector < gp_Pnt > & out ) {
TopExp_Explorer exp ( b , TopAbs_FACE ) ;
gp_Pnt p ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
if ( intersect ( a , TopoDS : : Face ( exp . Current ( ) ) , p ) ) {
out . push_back ( p ) ;
}
}
return ! out . empty ( ) ;
}
bool IfcGeom : : Kernel : : intersect ( const Handle_Geom_Surface & a , const TopoDS_Shape & b , std : : vector < std : : pair < Handle_Geom_Surface , Handle_Geom_Curve > > & out ) {
TopExp_Explorer exp ( b , TopAbs_FACE ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
const TopoDS_Face & f = TopoDS : : Face ( exp . Current ( ) ) ;
const Handle_Geom_Surface & s = BRep_Tool : : Surface ( f ) ;
Handle_Geom_Curve crv = intersect ( a , s ) ;
if ( ! crv . IsNull ( ) ) {
out . push_back ( std : : make_pair ( s , crv ) ) ;
}
}
return ! out . empty ( ) ;
}
bool IfcGeom : : Kernel : : closest ( const gp_Pnt & a , const std : : vector < gp_Pnt > & b , gp_Pnt & c ) {
double minimal_distance = std : : numeric_limits < double > : : infinity ( ) ;
for ( std : : vector < gp_Pnt > : : const_iterator it = b . begin ( ) ; it ! = b . end ( ) ; + + it ) {
const double d = a . Distance ( * it ) ;
if ( d < minimal_distance ) {
minimal_distance = d ;
c = * it ;
}
}
return minimal_distance ! = std : : numeric_limits < double > : : infinity ( ) ;
}
bool IfcGeom : : Kernel : : project ( const Handle_Geom_Curve & crv , const gp_Pnt & pt , gp_Pnt & p , double & u , double & d ) {
ShapeAnalysis_Curve sac ;
sac . Project ( crv , pt , 1e-3 , p , u , false ) ;
d = pt . Distance ( p ) ;
return true ;
}
int IfcGeom : : Kernel : : count ( const TopoDS_Shape & s , TopAbs_ShapeEnum t ) {
int i = 0 ;
TopExp_Explorer exp ( s , t ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
+ + i ;
}
return i ;
}
bool IfcGeom : : Kernel : : find_wall_end_points ( const IfcSchema : : IfcWall * wall , gp_Pnt & start , gp_Pnt & end ) {
IfcSchema : : IfcRepresentation * axis_representation = find_representation ( wall , " Axis " ) ;
if ( ! axis_representation ) {
return false ;
}
IfcRepresentationShapeItems items ;
{
Kernel temp = * this ;
temp . setValue ( GV_DIMENSIONALITY , - 1. ) ;
temp . convert_shapes ( axis_representation , items ) ;
}
TopoDS_Vertex a , b ;
for ( IfcRepresentationShapeItems : : const_iterator it = items . begin ( ) ; it ! = items . end ( ) ; + + it ) {
TopExp_Explorer exp ( it - > Shape ( ) , TopAbs_VERTEX ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
b = TopoDS : : Vertex ( exp . Current ( ) ) ;
if ( a . IsNull ( ) ) {
a = b ;
}
}
}
if ( a . IsNull ( ) | | b . IsNull ( ) ) {
return false ;
}
start = BRep_Tool : : Pnt ( a ) ;
end = BRep_Tool : : Pnt ( b ) ;
return true ;
}
bool IfcGeom : : Kernel : : fold_layers ( const IfcSchema : : IfcWall * wall , const IfcRepresentationShapeItems & items , const std : : vector < Handle_Geom_Surface > & surfaces , const std : : vector < double > & thicknesses , std : : vector < std : : vector < Handle_Geom_Surface > > & result ) {
bool folds_made = false ;
IfcSchema : : IfcRelConnectsPathElements : : list : : ptr connections ( new IfcSchema : : IfcRelConnectsPathElements : : list ) ;
connections - > push ( wall - > ConnectedFrom ( ) - > as < IfcSchema : : IfcRelConnectsPathElements > ( ) ) ;
connections - > push ( wall - > ConnectedTo ( ) - > as < IfcSchema : : IfcRelConnectsPathElements > ( ) ) ;
typedef std : : vector < Handle_Geom_Surface > surfaces_t ;
typedef std : : pair < Handle_Geom_Surface , Handle_Geom_Curve > curve_on_surface ;
typedef std : : vector < curve_on_surface > curves_on_surfaces_t ;
typedef std : : vector < std : : pair < std : : pair < IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionTypeEnum , IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionTypeEnum > , const IfcSchema : : IfcProduct * > > endpoint_connections_t ;
typedef std : : vector < std : : vector < Handle_Geom_Surface > > result_t ;
endpoint_connections_t endpoint_connections ;
for ( IfcSchema : : IfcRelConnectsPathElements : : list : : it it = connections - > begin ( ) ; it ! = connections - > end ( ) ; + + it ) {
IfcSchema : : IfcRelConnectsPathElements * connection = * it ;
IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionTypeEnum own_type = connection - > RelatedElement ( ) = = wall
? connection - > RelatedConnectionType ( )
: connection - > RelatingConnectionType ( ) ;
IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionTypeEnum other_type = connection - > RelatedElement ( ) = = wall
? connection - > RelatingConnectionType ( )
: connection - > RelatedConnectionType ( ) ;
if ( other_type ! = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATPATH & &
( own_type = = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATEND | |
own_type = = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATSTART ) )
{
IfcSchema : : IfcElement * other = connection - > RelatedElement ( ) = = wall
? connection - > RelatingElement ( )
: connection - > RelatedElement ( ) ;
if ( other - > as < IfcSchema : : IfcWall > ( ) ) {
endpoint_connections . push_back ( std : : make_pair ( std : : make_pair ( own_type , other_type ) , other ) ) ;
}
}
}
if ( endpoint_connections . size ( ) = = 0 ) {
return false ;
}
int connection_type_count [ 2 ] = { 0 , 0 } ;
2016-04-09 17:54:23 +02:00
for ( endpoint_connections_t : : const_iterator it = endpoint_connections . begin ( ) ; it ! = endpoint_connections . end ( ) ; + + it ) {
2015-10-07 17:33:30 +02:00
const int idx = it - > first . first = = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATSTART ;
connection_type_count [ idx ] + + ;
}
gp_Trsf local ;
if ( ! convert ( wall - > ObjectPlacement ( ) , local ) ) {
return false ;
}
local . Invert ( ) ;
{
// Copy the unfolded surfaces
result . resize ( surfaces . size ( ) ) ;
2016-04-09 17:54:23 +02:00
std : : vector < std : : vector < Handle_Geom_Surface > > : : iterator result_it = result . begin ( ) + 1 ;
std : : vector < Handle_Geom_Surface > : : const_iterator input_it = surfaces . begin ( ) + 1 ;
2015-10-07 17:33:30 +02:00
for ( ; input_it ! = surfaces . end ( ) - 1 ; + + result_it , + + input_it ) {
result_it - > push_back ( * input_it ) ;
}
}
gp_Pnt own_axis_start , own_axis_end ;
find_wall_end_points ( wall , own_axis_start , own_axis_end ) ;
for ( int idx = 0 ; idx < 2 ; + + idx ) {
if ( connection_type_count [ idx ] < = 1 ) {
continue ;
}
2016-05-02 15:56:08 +02:00
/*
2015-10-07 17:33:30 +02:00
IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum connection_type = idx == 1
? IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
: IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND;
2016-05-02 15:56:08 +02:00
*/
2015-10-07 17:33:30 +02:00
std : : set < const IfcSchema : : IfcProduct * > others ;
2016-04-09 17:54:23 +02:00
endpoint_connections_t : : iterator it = endpoint_connections . begin ( ) ;
2015-10-07 17:33:30 +02:00
while ( it ! = endpoint_connections . end ( ) ) {
const IfcSchema : : IfcProduct * other = it - > second ;
if ( others . find ( other ) ! = others . end ( ) ) {
it = endpoint_connections . erase ( it ) ;
- - connection_type_count [ idx ] ;
} else {
others . insert ( other ) ;
+ + it ;
}
}
/*
Additionally one could check whether the end points are of the wall are really ~1 LayerThickness away from each other
for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) {
IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum relating_connection_type = it->first.first;
IfcSchema::IfcConnectionTypeEnum::IfcConnectionTypeEnum related_connection_type = it->first.second;
if (connection_type != relating_connection_type) {
continue;
}
gp_Pnt other_axis_start, other_axis_end;
find_wall_end_points(it->second->as<IfcSchema::IfcWall>(), other_axis_start, other_axis_end);
gp_Trsf other;
if (!convert(it->second->ObjectPlacement(), other)) {
continue;
}
other.Transforms(other_axis_start.ChangeCoord());
local.Transforms(other_axis_start.ChangeCoord());
other.Transforms(other_axis_end.ChangeCoord());
local.Transforms(other_axis_end.ChangeCoord());
const gp_Pnt& a = relating_connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
? own_axis_start
: own_axis_end;
const gp_Pnt& b = related_connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
? other_axis_start
: other_axis_end;
const double d = a.Distance(b);
}
*/
}
for ( endpoint_connections_t : : const_iterator it = endpoint_connections . begin ( ) ; it ! = endpoint_connections . end ( ) ; + + it ) {
IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionTypeEnum connection_type = it - > first . first ;
// If more than one wall connects to this start/end -point assume layers do not need to be folded
const int idx = connection_type = = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATSTART ;
if ( connection_type_count [ idx ] > 1 ) continue ;
const gp_Pnt & own_end_point = connection_type = = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATEND
? own_axis_end
: own_axis_start ;
const IfcSchema : : IfcProduct * other_wall = it - > second ;
gp_Trsf other ;
if ( ! convert ( other_wall - > ObjectPlacement ( ) , other ) ) {
continue ;
}
IfcSchema : : IfcRepresentation * axis_representation = find_representation ( other_wall , " Axis " ) ;
IfcRepresentationShapeItems axis_items ;
{
Kernel temp = * this ;
temp . setValue ( GV_DIMENSIONALITY , - 1. ) ;
temp . convert_shapes ( axis_representation , axis_items ) ;
}
TopoDS_Shape axis_shape ;
flatten_shape_list ( axis_items , axis_shape , false ) ;
2016-05-03 11:01:47 +02:00
// local and other are IfcLocalPlacements and therefore have a unit
// scale factor that can be applied by means of TopoDS_Shape::Move()
2015-10-07 17:33:30 +02:00
axis_shape . Move ( other ) ;
axis_shape . Move ( local ) ;
TopoDS_Shape body_shape ;
flatten_shape_list ( items , body_shape , false ) ;
Handle_Geom_Curve axis_curve ;
double axis_u1 , axis_u2 ;
{
TopExp_Explorer exp ( axis_shape , TopAbs_EDGE ) ;
if ( ! exp . More ( ) ) {
return false ;
}
TopoDS_Edge axis_edge = TopoDS : : Edge ( exp . Current ( ) ) ;
axis_curve = BRep_Tool : : Curve ( axis_edge , axis_u1 , axis_u2 ) ;
gp_Pnt other_a_1 , other_a_2 ;
axis_curve - > D0 ( axis_u1 , other_a_1 ) ;
axis_curve - > D0 ( axis_u2 , other_a_2 ) ;
if ( axis_u2 < axis_u1 ) {
std : : swap ( axis_u1 , axis_u2 ) ;
}
exp . Next ( ) ;
for ( ; exp . More ( ) ; exp . Next ( ) ) {
2016-05-02 15:56:08 +02:00
TopoDS_Edge axis_edge2 = TopoDS : : Edge ( exp . Current ( ) ) ;
TopExp_Explorer exp2 ( axis_edge2 , TopAbs_VERTEX ) ;
2015-10-07 17:33:30 +02:00
for ( ; exp2 . More ( ) ; exp2 . Next ( ) ) {
gp_Pnt p = BRep_Tool : : Pnt ( TopoDS : : Vertex ( exp2 . Current ( ) ) ) ;
gp_Pnt pp ;
double u , d ;
if ( project ( axis_curve , p , pp , u , d ) ) {
if ( u < axis_u1 ) axis_u1 = u ;
if ( u > axis_u2 ) axis_u2 = u ;
}
}
}
}
double layer_offset = 0 ;
std : : vector < double > : : const_iterator thickness = thicknesses . begin ( ) ;
result_t : : iterator result_vector = result . begin ( ) + 1 ;
for ( surfaces_t : : const_iterator jt = surfaces . begin ( ) + 1 ; jt ! = surfaces . end ( ) - 1 ; + + jt , + + result_vector ) {
layer_offset + = * thickness + + ;
bool found_intersection = false ;
boost : : optional < gp_Pnt > point_outside_param_range ;
2016-07-15 06:49:32 +03:00
//double param;
2015-10-07 17:33:30 +02:00
const Handle_Geom_Surface & surface = * jt ;
GeomAPI_IntCS intersections ( axis_curve , surface ) ;
if ( intersections . IsDone ( ) & & intersections . NbPoints ( ) = = 1 ) {
const gp_Pnt & p = intersections . Point ( 1 ) ;
double u , v , w ;
intersections . Parameters ( 1 , u , v , w ) ;
if ( w < axis_u1 | | w > axis_u2 ) {
point_outside_param_range = p ;
2016-07-15 06:49:32 +03:00
//param = w;
2015-10-07 17:33:30 +02:00
} else {
// Found an intersection. Layer end point is covered by connecting wall
found_intersection = true ;
break ;
}
}
if ( ! found_intersection & & point_outside_param_range ) {
/*
Is there a bug in Open Cascade related to the intersection
of offset surfaces constructed from linear extrusions?
Handle_Geom_Surface xy = new Geom_Plane(gp::Origin(), gp::DZ());
// Handle_Geom_Surface yz = new Geom_Plane(gp::Origin(), gp::DX());
// Handle_Geom_Surface yz2 = new Geom_OffsetSurface(yz, 1.);
Handle_Geom_Curve ln = new Geom_Line(gp::Origin(), gp::DX());
Handle_Geom_Surface yz = new Geom_SurfaceOfLinearExtrusion(ln, gp::DZ());
Handle_Geom_Surface yz2 = new Geom_OffsetSurface(yz, 1.);
intersect(xy, yz2);
*/
Handle_Geom_Surface plane = new Geom_Plane ( * point_outside_param_range , gp : : DZ ( ) ) ;
curves_on_surfaces_t layer_ends ;
intersect ( surface , body_shape , layer_ends ) ;
Handle_Geom_Curve layer_body_intersection ;
Handle_Geom_Surface body_surface ;
double mind = std : : numeric_limits < double > : : infinity ( ) ;
2016-05-02 15:56:08 +02:00
for ( curves_on_surfaces_t : : const_iterator kt = layer_ends . begin ( ) ; kt ! = layer_ends . end ( ) ; + + kt ) {
2015-10-07 17:33:30 +02:00
gp_Pnt p ;
gp_Vec v ;
double u , d ;
2016-05-02 15:56:08 +02:00
kt - > second - > D1 ( 0. , p , v ) ;
2015-10-07 17:33:30 +02:00
if ( ALMOST_THE_SAME ( 0. , v . Dot ( gp : : DZ ( ) ) ) ) {
// Filter horizontal curves
continue ;
}
2016-05-02 15:56:08 +02:00
if ( project ( kt - > second , own_end_point , p , u , d ) ) {
2015-10-07 17:33:30 +02:00
if ( d < mind ) {
2016-05-02 15:56:08 +02:00
body_surface = kt - > first ;
layer_body_intersection = kt - > second ;
2015-10-07 17:33:30 +02:00
mind = d ;
}
}
}
GeomAPI_IntCS intersection2 ( layer_body_intersection , plane ) ;
if ( intersection2 . IsDone ( ) & & intersection2 . NbPoints ( ) = = 1 ) {
const gp_Pnt & layer_end_point = intersection2 . Point ( 1 ) ;
GeomAPI_IntSS intersection3 ( surface , plane , 1.e-7 ) ;
if ( intersection3 . IsDone ( ) & & intersection3 . NbLines ( ) = = 1 ) {
Handle_Geom_Curve layer_line = intersection3 . Line ( 1 ) ;
GeomAdaptor_Curve layer_line_adaptor ( layer_line ) ;
ShapeAnalysis_Curve sac ;
gp_Pnt layer_end_point_projected ; double layer_end_point_param ;
sac . Project ( layer_line , layer_end_point , 1e-3 , layer_end_point_projected , layer_end_point_param , false ) ;
GCPnts_AbscissaPoint dst ( layer_line_adaptor , layer_offset , layer_end_point_param ) ;
if ( dst . IsDone ( ) ) {
gp_Pnt layer_fold_point ;
layer_line - > D0 ( dst . Parameter ( ) , layer_fold_point ) ;
GeomAPI_IntSS intersection4 ( body_surface , plane , 1.e-7 ) ;
if ( intersection4 . IsDone ( ) & & intersection4 . NbLines ( ) = = 1 ) {
Handle_Geom_Curve body_trim_curve = intersection4 . Line ( 1 ) ;
ShapeAnalysis_Curve sac2 ;
gp_Pnt layer_fold_point_projected ; double layer_fold_point_param ;
sac2 . Project ( body_trim_curve , layer_fold_point , 1.e-7 , layer_fold_point_projected , layer_fold_point_param , false ) ;
Handle_Geom_Curve fold_curve = new Geom_OffsetCurve ( body_trim_curve - > Reversed ( ) , layer_fold_point_projected . Distance ( layer_fold_point ) , gp : : DZ ( ) ) ;
Handle_Geom_Surface fold_surface = new Geom_SurfaceOfLinearExtrusion ( fold_curve , gp : : DZ ( ) ) ;
result_vector - > push_back ( fold_surface ) ;
folds_made = true ;
}
}
}
}
}
}
}
return folds_made ;
}
2016-05-02 15:56:08 +02:00
bool IfcGeom : : Kernel : : apply_folded_layerset ( const IfcRepresentationShapeItems & items , const std : : vector < std : : vector < Handle_Geom_Surface > > & surfaces , const std : : vector < const SurfaceStyle * > & styles , IfcRepresentationShapeItems & result ) {
2015-10-07 17:33:30 +02:00
Bnd_Box bb ;
TopoDS_Shape input ;
flatten_shape_list ( items , input , false ) ;
BRepBndLib : : Add ( input , bb ) ;
std : : vector < double > bb_coords ( 6 ) ;
bb . Get ( bb_coords [ 0 ] , bb_coords [ 1 ] , bb_coords [ 2 ] , bb_coords [ 3 ] , bb_coords [ 4 ] , bb_coords [ 5 ] ) ;
typedef std : : vector < std : : vector < Handle_Geom_Surface > > folded_surfaces_t ;
typedef std : : vector < std : : pair < TopoDS_Face , std : : pair < gp_Pnt , gp_Pnt > > > faces_with_mass_t ;
std : : vector < TopoDS_Shell > shells ;
// result = items;
for ( folded_surfaces_t : : const_iterator it = surfaces . begin ( ) ; it ! = surfaces . end ( ) ; + + it ) {
if ( it - > empty ( ) ) {
continue ;
} else if ( it - > size ( ) = = 1 ) {
const Handle_Geom_Surface & surface = ( * it ) [ 0 ] ;
double u1 , v1 , u2 , v2 ;
if ( ! project ( surface , input , u1 , v1 , u2 , v2 ) ) {
continue ;
}
shells . push_back ( BRepBuilderAPI_MakeShell ( surface , u1 , v1 , u2 , v2 ) . Shell ( ) ) ;
} else {
faces_with_mass_t solids ;
for ( folded_surfaces_t : : value_type : : const_iterator jt = it - > begin ( ) ; jt ! = it - > end ( ) ; + + jt ) {
const Handle_Geom_Surface & surface = * jt ;
double u1 , v1 , u2 , v2 ;
if ( ! project ( surface , input , u1 , v1 , u2 , v2 ) ) {
continue ;
}
TopoDS_Face face = BRepBuilderAPI_MakeFace ( surface , u1 , u2 , v1 , v2 , 1.e-7 ) . Face ( ) ;
gp_Pnt p , p1 , p2 ; gp_Vec vu , vv , n ;
surface - > D1 ( ( u1 + u2 ) / 2. , ( v1 + v2 ) / 2. , p , vu , vv ) ;
n = vu ^ vv ;
p1 = p . Translated ( n ) ;
p2 = p . Translated ( - n ) ;
solids . push_back ( std : : make_pair ( face , std : : make_pair ( p1 , p2 ) ) ) ;
}
if ( solids . empty ( ) ) {
continue ;
}
faces_with_mass_t : : iterator jt = solids . begin ( ) ;
TopoDS_Face & A = jt - > first ;
TopoDS_Shape An = BRepPrimAPI_MakeHalfSpace ( A , jt - > second . second ) . Solid ( ) ;
for ( + + jt ; jt ! = solids . end ( ) ; + + jt ) {
TopoDS_Face & B = jt - > first ;
TopoDS_Shape Bn = BRepPrimAPI_MakeHalfSpace ( B , jt - > second . second ) . Solid ( ) ;
TopoDS_Shape a = BRepAlgoAPI_Cut ( A , Bn ) ;
if ( count ( a , TopAbs_FACE ) = = 1 ) {
A = TopoDS : : Face ( TopExp_Explorer ( a , TopAbs_FACE ) . Current ( ) ) ;
}
TopoDS_Shape b = BRepAlgoAPI_Cut ( B , An ) ;
if ( count ( b , TopAbs_FACE ) = = 1 ) {
B = TopoDS : : Face ( TopExp_Explorer ( b , TopAbs_FACE ) . Current ( ) ) ;
}
}
BRepOffsetAPI_Sewing builder ;
2016-05-02 15:56:08 +02:00
for ( faces_with_mass_t : : const_iterator kt = solids . begin ( ) ; kt ! = solids . end ( ) ; + + kt ) {
builder . Add ( kt - > first ) ;
2015-10-07 17:33:30 +02:00
}
builder . Perform ( ) ;
shells . push_back ( TopoDS : : Shell ( builder . SewedShape ( ) ) ) ;
}
}
if ( shells . empty ( ) ) {
return false ;
} else if ( shells . size ( ) = = 1 ) {
for ( IfcRepresentationShapeItems : : const_iterator it = items . begin ( ) ; it ! = items . end ( ) ; + + it ) {
TopoDS_Shape a , b ;
if ( split_solid_by_shell ( it - > Shape ( ) , shells [ 0 ] , a , b ) ) {
result . push_back ( IfcRepresentationShapeItem ( it - > Placement ( ) , b , styles [ 0 ] ? styles [ 0 ] : & it - > Style ( ) ) ) ;
result . push_back ( IfcRepresentationShapeItem ( it - > Placement ( ) , a , styles [ 1 ] ? styles [ 1 ] : & it - > Style ( ) ) ) ;
} else {
continue ;
}
}
return true ;
} else {
typedef std : : vector < std : : vector < TopoDS_Shape > > temp_t ;
temp_t temp ;
for ( IfcRepresentationShapeItems : : const_iterator it = items . begin ( ) ; it ! = items . end ( ) ; + + it ) {
const TopoDS_Shape & s = it - > Shape ( ) ;
TopoDS_Solid sld ;
ensure_fit_for_subtraction ( s , sld ) ;
std : : vector < TopoDS_Shape > temp2 ;
temp2 . push_back ( sld ) ;
temp . push_back ( temp2 ) ;
}
for ( unsigned i = 0 ; i < shells . size ( ) ; + + i ) {
for ( temp_t : : iterator it = temp . begin ( ) ; it ! = temp . end ( ) ; + + it ) {
TopoDS_Shape a , b ;
TopoDS_Shape & ab = ( * it ) [ ( * it ) . size ( ) - 1 ] ;
if ( split_solid_by_shell ( ab , shells [ i ] , a , b ) ) {
ab = b ;
it - > push_back ( a ) ;
} else {
continue ;
}
}
}
IfcRepresentationShapeItems : : const_iterator it1 = items . begin ( ) ;
temp_t : : const_iterator it2 = temp . begin ( ) ;
for ( ; it1 ! = items . end ( ) ; + + it1 , + + it2 ) {
std : : vector < const SurfaceStyle * > : : const_iterator it4 = styles . begin ( ) ;
for ( temp_t : : value_type : : const_iterator it3 = it2 - > begin ( ) ; it3 ! = it2 - > end ( ) ; + + it3 , + + it4 ) {
result . push_back ( IfcRepresentationShapeItem ( it1 - > Placement ( ) , * it3 , ( * it4 ) ? ( * it4 ) : & it1 - > Style ( ) ) ) ;
}
}
return true ;
}
}
2016-05-02 15:56:08 +02:00
bool IfcGeom : : Kernel : : apply_layerset ( const IfcRepresentationShapeItems & items , const std : : vector < Handle_Geom_Surface > & surfaces , const std : : vector < const SurfaceStyle * > & styles , IfcRepresentationShapeItems & result ) {
2015-10-07 17:33:30 +02:00
if ( surfaces . size ( ) < 3 ) {
return false ;
} else if ( surfaces . size ( ) = = 3 ) {
for ( IfcRepresentationShapeItems : : const_iterator it = items . begin ( ) ; it ! = items . end ( ) ; + + it ) {
TopoDS_Shape a , b ;
if ( split_solid_by_surface ( it - > Shape ( ) , surfaces [ 1 ] , a , b ) ) {
result . push_back ( IfcRepresentationShapeItem ( it - > Placement ( ) , b , styles [ 0 ] ? styles [ 0 ] : & it - > Style ( ) ) ) ;
result . push_back ( IfcRepresentationShapeItem ( it - > Placement ( ) , a , styles [ 1 ] ? styles [ 1 ] : & it - > Style ( ) ) ) ;
} else {
continue ;
}
}
return true ;
} else {
/*
// Determine whether sequence of surfaces is consistent with surface normal, so that
// layer operations are applied in the correct order. This seems to be always the case.
Bnd_Box bb;
for (IfcRepresentationShapeItems::const_iterator it = items.begin(); it != items.end(); ++it) {
BRepBndLib::Add(it->Shape(), bb);
}
double x1, y1, z1, x2, y2, z2;
bb.Get(x1, y1, z1, x2, y2, z2);
gp_Pnt p1(x1, y1, z1);
gp_Pnt p2(x2, y2, z2);
gp_Pnt avg = (p1.XYZ() + p2.XYZ()) / 2.;
ShapeAnalysis_Surface sas1(surfaces[0]);
ShapeAnalysis_Surface sas2(surfaces[1]);
const gp_Pnt2d uv = sas1.ValueOfUV(avg, 1e-3);
gp_Pnt ps1, ps2, mass;
gp_Vec du1, dv1, du2, dv2;
surfaces[0]->D1(uv.X(), uv.Y(), ps1, du1, dv1);
const gp_Vec n1 = dv1.XYZ() ^ du1.XYZ();
const bool reversed = gp_Dir(ps2.XYZ() - ps1.XYZ()).Dot(n1) < 0.;
surfaces[surfaces.size() - 1]->D0(uv.X(), uv.Y(), mass);
mass.ChangeCoord() += n1.XYZ();
*/
typedef std : : vector < std : : vector < TopoDS_Shape > > temp_t ;
temp_t temp ;
for ( IfcRepresentationShapeItems : : const_iterator it = items . begin ( ) ; it ! = items . end ( ) ; + + it ) {
// No transformation on purpose in order not interfere with layerset alignment
const TopoDS_Shape & s = it - > Shape ( ) ;
TopoDS_Solid sld ;
ensure_fit_for_subtraction ( s , sld ) ;
std : : vector < TopoDS_Shape > temp2 ;
temp2 . push_back ( sld ) ;
temp . push_back ( temp2 ) ;
}
for ( unsigned i = 1 ; i < surfaces . size ( ) - 1 ; + + i ) {
for ( temp_t : : iterator it = temp . begin ( ) ; it ! = temp . end ( ) ; + + it ) {
TopoDS_Shape a , b ;
TopoDS_Shape & ab = ( * it ) [ ( * it ) . size ( ) - 1 ] ;
if ( split_solid_by_surface ( ab , surfaces [ i ] , a , b ) ) {
ab = b ;
it - > push_back ( a ) ;
} else {
continue ;
}
}
}
IfcRepresentationShapeItems : : const_iterator it1 = items . begin ( ) ;
temp_t : : const_iterator it2 = temp . begin ( ) ;
for ( ; it1 ! = items . end ( ) ; + + it1 , + + it2 ) {
std : : vector < const SurfaceStyle * > : : const_iterator it4 = styles . begin ( ) ;
for ( temp_t : : value_type : : const_iterator it3 = it2 - > begin ( ) ; it3 ! = it2 - > end ( ) ; + + it3 , + + it4 ) {
result . push_back ( IfcRepresentationShapeItem ( it1 - > Placement ( ) , * it3 , ( * it4 ) ? ( * it4 ) : & it1 - > Style ( ) ) ) ;
}
}
return true ;
}
}
IfcSchema : : IfcRepresentation * IfcGeom : : Kernel : : find_representation ( const IfcSchema : : IfcProduct * product , const std : : string & identifier ) {
if ( ! product - > hasRepresentation ( ) ) return 0 ;
IfcSchema : : IfcProductRepresentation * prod_rep = product - > Representation ( ) ;
IfcSchema : : IfcRepresentation : : list : : ptr reps = prod_rep - > Representations ( ) ;
for ( IfcSchema : : IfcRepresentation : : list : : it it = reps - > begin ( ) ; it ! = reps - > end ( ) ; + + it ) {
if ( ( * * it ) . hasRepresentationIdentifier ( ) & & ( * * it ) . RepresentationIdentifier ( ) = = identifier ) {
return * it ;
}
}
return 0 ;
}
bool IfcGeom : : Kernel : : split_solid_by_surface ( const TopoDS_Shape & input , const Handle_Geom_Surface & surface , TopoDS_Shape & front , TopoDS_Shape & back ) {
// Use an unbounded surface, that isolate part of the input shape,
// to split this shape into two parts. Make sure that the addition
// of the two result volumes matches that of the input.
double u1 , v1 , u2 , v2 ;
if ( ! project ( surface , input , u1 , v1 , u2 , v2 ) ) {
return false ;
}
TopoDS_Face face = BRepBuilderAPI_MakeFace ( surface , u1 , u2 , v1 , v2 , 1.e-7 ) . Face ( ) ;
gp_Pnt p , p1 , p2 ; gp_Vec vu , vv , n ;
surface - > D1 ( ( u1 + u2 ) / 2. , ( v1 + v2 ) / 2. , p , vu , vv ) ;
n = vu ^ vv ;
p1 = p . Translated ( - n ) ;
TopoDS_Solid solid = BRepPrimAPI_MakeHalfSpace ( face , p1 ) . Solid ( ) ;
const bool b = split_solid_by_shell ( input , solid , front , back ) ;
return b ;
}
bool IfcGeom : : Kernel : : split_solid_by_shell ( const TopoDS_Shape & input , const TopoDS_Shape & shell , TopoDS_Shape & front , TopoDS_Shape & back ) {
// Use a shell, typically one or more connected faces, that isolate part
// of the input shape, to split this shape into two parts. Make sure that
// the addition of the two result volumes matches that of the input.
TopoDS_Solid solid ;
if ( shell . ShapeType ( ) = = TopAbs_SHELL ) {
solid = BRepBuilderAPI_MakeSolid ( TopoDS : : Shell ( shell ) ) . Solid ( ) ;
} else if ( shell . ShapeType ( ) = = TopAbs_SOLID ) {
solid = TopoDS : : Solid ( shell ) ;
} else {
return false ;
}
2016-09-01 15:13:48 +02:00
apply_tolerance ( solid , getValue ( GV_PRECISION ) ) ;
2015-10-07 17:33:30 +02:00
2018-05-16 10:11:00 -03:00
# if OCC_VERSION_HEX >= 0x70300
2018-05-14 13:08:27 -03:00
TopTools_ListOfShape shapes ;
2018-05-16 10:11:00 -03:00
# else
BOPCol_ListOfShape shapes ;
# endif
2015-10-07 17:33:30 +02:00
shapes . Append ( input ) ;
shapes . Append ( solid ) ;
BOPAlgo_PaveFiller filler ( new NCollection_IncAllocator ) ; // TODO: Does this need to be freed?
filler . SetArguments ( shapes ) ;
filler . Perform ( ) ;
front = BRepAlgoAPI_Cut ( input , solid , filler ) ;
back = BRepAlgoAPI_Common ( input , solid , filler ) ;
2016-09-01 15:13:48 +02:00
bool is_null [ 2 ] ;
2015-10-07 17:33:30 +02:00
for ( int i = 0 ; i < 2 ; + + i ) {
TopoDS_Shape & shape = i = = 0 ? front : back ;
2016-10-09 13:39:47 +03:00
const bool result_is_null = is_null [ i ] = shape . IsNull ( ) ! = 0 ;
2016-09-01 15:13:48 +02:00
if ( result_is_null ) {
continue ;
}
2015-10-07 17:33:30 +02:00
try {
ShapeFix_Shape fix ( shape ) ;
if ( fix . Perform ( ) ) {
shape = fix . Shape ( ) ;
}
2017-08-01 16:45:11 +02:00
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error performing fixes " ) ;
}
} catch ( . . . ) {
Logger : : Error ( " Unknown error performing fixes " ) ;
}
2015-10-07 17:33:30 +02:00
BRepCheck_Analyzer analyser ( shape ) ;
bool is_valid = analyser . IsValid ( ) ! = 0 ;
if ( ! is_valid ) {
return false ;
}
}
2016-09-01 15:13:48 +02:00
if ( is_null [ 0 ] | | is_null [ 1 ] ) {
Logger : : Message ( Logger : : LOG_ERROR , " Null result obtained from layerset slicing " ) ;
if ( is_null [ 0 ] & & is_null [ 1 ] ) {
return false ;
}
}
2015-10-07 17:33:30 +02:00
const double ab = shape_volume ( input ) ;
const double a = shape_volume ( front ) ;
const double b = shape_volume ( back ) ;
return ALMOST_THE_SAME ( ab , a + b , 1.e-3 ) ;
}
bool IfcGeom : : Kernel : : project ( const Handle_Geom_Surface & srf , const TopoDS_Shape & shp , double & u1 , double & v1 , double & u2 , double & v2 , double widen ) {
ShapeAnalysis_Surface sas ( srf ) ;
u1 = v1 = + std : : numeric_limits < double > : : infinity ( ) ;
u2 = v2 = - std : : numeric_limits < double > : : infinity ( ) ;
gp_Pnt median ;
int vertex_count = 0 ;
for ( TopExp_Explorer exp ( shp , TopAbs_VERTEX ) ; exp . More ( ) ; exp . Next ( ) , + + vertex_count ) {
gp_Pnt p = BRep_Tool : : Pnt ( TopoDS : : Vertex ( exp . Current ( ) ) ) ;
median . ChangeCoord ( ) + = p . XYZ ( ) ;
const gp_Pnt2d uv = sas . ValueOfUV ( p , 1e-3 ) ;
if ( uv . X ( ) < u1 ) u1 = uv . X ( ) ;
if ( uv . Y ( ) < v1 ) v1 = uv . Y ( ) ;
if ( uv . X ( ) > u2 ) u2 = uv . X ( ) ;
if ( uv . Y ( ) > v2 ) v2 = uv . Y ( ) ;
}
if ( vertex_count = = 0 ) {
return false ;
}
2018-09-06 12:23:07 -04:00
// Add a little bit of resolution so that the median is shifted towards the mass
2015-10-07 17:33:30 +02:00
// of the curve. This helps to find the parameter ordering for conic surfaces.
for ( TopExp_Explorer exp ( shp , TopAbs_EDGE ) ; exp . More ( ) ; exp . Next ( ) , + + vertex_count ) {
const TopoDS_Edge & e = TopoDS : : Edge ( exp . Current ( ) ) ;
double a , b ;
Handle_Geom_Curve crv = BRep_Tool : : Curve ( e , a , b ) ;
gp_Pnt p ;
crv - > D0 ( ( a + b ) / 2. , p ) ;
median . ChangeCoord ( ) + = p . XYZ ( ) ;
}
median . ChangeCoord ( ) . Divide ( vertex_count ) ;
const gp_Pnt2d uv = sas . ValueOfUV ( median , 1e-3 ) ;
if ( uv . X ( ) < u1 | | uv . X ( ) > u2 ) {
std : : swap ( u1 , u2 ) ;
}
u1 - = widen ;
u2 + = widen ;
v1 - = widen ;
v2 + = widen ;
return true ;
2016-05-02 15:13:30 +02:00
}
2016-01-22 17:27:28 +01:00
const IfcSchema : : IfcRepresentationItem * IfcGeom : : Kernel : : find_item_carrying_style ( const IfcSchema : : IfcRepresentationItem * item ) {
2016-02-03 22:34:50 +02:00
if ( item - > StyledByItem ( ) - > size ( ) ) {
2016-01-22 17:27:28 +01:00
return item ;
}
while ( item - > is ( IfcSchema : : Type : : IfcBooleanClippingResult ) ) {
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
// IfcGeometricRepresentationItem
item = ( IfcSchema : : IfcGeometricRepresentationItem * ) ( ( IfcSchema : : IfcBooleanClippingResult * ) item ) - > FirstOperand ( ) ;
2016-02-03 22:34:50 +02:00
if ( item - > StyledByItem ( ) - > size ( ) ) {
2016-01-22 17:27:28 +01:00
return item ;
}
}
// TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
// But neither are these very prevalent, nor does the current IfcOpenShell style
// mechanism enable to conveniently style subshapes, which would be necessary for
// distinctly styled union operands.
return item ;
2016-02-03 22:34:50 +02:00
}
2016-03-18 11:23:25 +01:00
bool IfcGeom : : Kernel : : is_identity_transform ( IfcUtil : : IfcBaseClass * l ) {
IfcSchema : : IfcAxis2Placement2D * ax2d ;
IfcSchema : : IfcAxis2Placement3D * ax3d ;
IfcSchema : : IfcCartesianTransformationOperator2D * op2d ;
IfcSchema : : IfcCartesianTransformationOperator3D * op3d ;
IfcSchema : : IfcCartesianTransformationOperator2DnonUniform * op2dnonu ;
IfcSchema : : IfcCartesianTransformationOperator3DnonUniform * op3dnonu ;
if ( ( op2dnonu = l - > as < IfcSchema : : IfcCartesianTransformationOperator2DnonUniform > ( ) ) ! = 0 ) {
gp_GTrsf2d gtrsf2d ;
convert ( op2dnonu , gtrsf2d ) ;
return gtrsf2d . Form ( ) = = gp_Identity ;
} else if ( ( op2d = l - > as < IfcSchema : : IfcCartesianTransformationOperator2D > ( ) ) ! = 0 ) {
gp_Trsf2d trsf2d ;
convert ( op2d , trsf2d ) ;
return trsf2d . Form ( ) = = gp_Identity ;
} else if ( ( op3dnonu = l - > as < IfcSchema : : IfcCartesianTransformationOperator3DnonUniform > ( ) ) ! = 0 ) {
gp_GTrsf gtrsf ;
convert ( op3dnonu , gtrsf ) ;
return gtrsf . Form ( ) = = gp_Identity ;
} else if ( ( op3d = l - > as < IfcSchema : : IfcCartesianTransformationOperator3D > ( ) ) ! = 0 ) {
gp_Trsf trsf ;
convert ( op3d , trsf ) ;
return trsf . Form ( ) = = gp_Identity ;
} else if ( ( ax2d = l - > as < IfcSchema : : IfcAxis2Placement2D > ( ) ) ! = 0 ) {
gp_Trsf2d trsf2d ;
convert ( ax2d , trsf2d ) ;
return trsf2d . Form ( ) = = gp_Identity ;
} else if ( ( ax3d = l - > as < IfcSchema : : IfcAxis2Placement3D > ( ) ) ! = 0 ) {
gp_Trsf trsf ;
convert ( ax3d , trsf ) ;
return trsf . Form ( ) = = gp_Identity ;
} else {
throw IfcParse : : IfcException ( " Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator " ) ;
}
}
2016-04-16 14:47:09 +02:00
bool IfcGeom : : Kernel : : approximate_plane_through_wire ( const TopoDS_Wire & wire , gp_Pln & plane ) {
// Newell's Method is used for the normal calculation
// as a simple edge cross product can give opposite results
// for a concave face boundary.
// Reference: Graphics Gems III p. 231
double x = 0 , y = 0 , z = 0 ;
gp_Pnt current , previous , first ;
gp_XYZ center ;
int n = 0 ;
BRepTools_WireExplorer exp ( wire ) ;
for ( ; ; exp . Next ( ) ) {
2016-09-01 12:28:17 +03:00
const bool has_more = exp . More ( ) ! = 0 ;
2016-04-16 14:47:09 +02:00
if ( has_more ) {
const TopoDS_Vertex & v = exp . CurrentVertex ( ) ;
current = BRep_Tool : : Pnt ( v ) ;
center + = current . XYZ ( ) ;
} else {
current = first ;
}
if ( n ) {
const double & xn = previous . X ( ) ;
const double & yn = previous . Y ( ) ;
const double & zn = previous . Z ( ) ;
const double & xn1 = current . X ( ) ;
const double & yn1 = current . Y ( ) ;
const double & zn1 = current . Z ( ) ;
x + = ( yn - yn1 ) * ( zn + zn1 ) ;
y + = ( xn + xn1 ) * ( zn - zn1 ) ;
z + = ( xn - xn1 ) * ( yn + yn1 ) ;
} else {
first = current ;
}
if ( ! has_more ) {
break ;
}
previous = current ;
+ + n ;
}
if ( n < 3 ) {
return false ;
}
plane = gp_Pln ( center / n , gp_Dir ( x , y , z ) ) ;
return true ;
}
bool IfcGeom : : Kernel : : flatten_wire ( TopoDS_Wire & wire ) {
gp_Pln pln ;
if ( ! approximate_plane_through_wire ( wire , pln ) ) {
return false ;
}
TopoDS_Face face = BRepBuilderAPI_MakeFace ( pln ) . Face ( ) ;
BRepAlgo_NormalProjection proj ( face ) ;
proj . Add ( wire ) ;
proj . Build ( ) ;
if ( ! proj . IsDone ( ) ) {
return false ;
}
TopTools_ListOfShape list ;
proj . BuildWire ( list ) ;
if ( list . Extent ( ) ! = 1 ) {
return false ;
}
wire = TopoDS : : Wire ( list . First ( ) ) ;
return true ;
2016-04-24 15:22:10 +02:00
}
2016-05-03 11:01:47 +02:00
2017-11-27 16:27:36 +01:00
bool IfcGeom : : Kernel : : triangulate_wire ( const TopoDS_Wire & wire , TopTools_ListOfShape & faces ) {
// This is a bit of a precarious approach, but seems to work for the
// versions of OCCT tested for. OCCT has a Delaunay triangulation function
// BRepMesh_Delaun, but it is notoriously hard to interpret the results
// (due to the Bowyer-Watson super triangle perhaps?). Therefore
// alternatively we use the regular OCCT incremental mesher on a new face
// created from the UV coordinates of the original wire. Pray to our gods
// that the vertex coordinates are unaffected by the meshing algorithm and
// map them back to 3d coordinates when iterating over the mesh triangles.
typedef std : : pair < double , double > uv_node ;
gp_Pln pln ;
if ( ! approximate_plane_through_wire ( wire , pln ) ) {
return false ;
}
const gp_XYZ & udir = pln . Position ( ) . XDirection ( ) . XYZ ( ) ;
const gp_XYZ & vdir = pln . Position ( ) . YDirection ( ) . XYZ ( ) ;
const gp_XYZ & pnt = pln . Position ( ) . Location ( ) . XYZ ( ) ;
BRepTools_WireExplorer exp ( wire ) ;
BRepBuilderAPI_MakePolygon mp ;
std : : map < uv_node , gp_Pnt > mapping ;
// Add UV coordinates to a newly created polygon
for ( ; exp . More ( ) ; exp . Next ( ) ) {
gp_Pnt p = BRep_Tool : : Pnt ( exp . CurrentVertex ( ) ) ;
double u = ( p . XYZ ( ) - pnt ) . Dot ( udir ) ;
double v = ( p . XYZ ( ) - pnt ) . Dot ( vdir ) ;
mp . Add ( gp_Pnt ( u , v , 0 ) ) ;
mapping . insert ( std : : make_pair ( std : : make_pair ( u , v ) , p ) ) ;
}
// Not closed by default
mp . Close ( ) ;
// Create a new face from the {u,v,0} wire and mesh the face
TopoDS_Face face = BRepBuilderAPI_MakeFace ( mp . Wire ( ) ) ;
BRepMesh_IncrementalMesh ( face , Precision : : Confusion ( ) ) ;
int n123 [ 3 ] ;
TopLoc_Location loc ;
Handle_Poly_Triangulation tri = BRep_Tool : : Triangulation ( face , loc ) ;
if ( ! tri . IsNull ( ) ) {
const TColgp_Array1OfPnt & nodes = tri - > Nodes ( ) ;
const Poly_Array1OfTriangle & triangles = tri - > Triangles ( ) ;
for ( int i = 1 ; i < = triangles . Length ( ) ; + + i ) {
if ( face . Orientation ( ) = = TopAbs_REVERSED )
triangles ( i ) . Get ( n123 [ 2 ] , n123 [ 1 ] , n123 [ 0 ] ) ;
else triangles ( i ) . Get ( n123 [ 0 ] , n123 [ 1 ] , n123 [ 2 ] ) ;
// Create polygons from the mesh vertices
BRepBuilderAPI_MakePolygon mp2 ;
for ( int j = 0 ; j < 3 ; + + j ) {
const gp_Pnt & uv = nodes . Value ( n123 [ j ] ) ;
uv_node key = std : : make_pair ( uv . X ( ) , uv . Y ( ) ) ;
if ( mapping . find ( key ) = = mapping . end ( ) ) {
Logger : : Error ( " Internal error: unable to unproject uv-mesh " ) ;
return false ;
}
const gp_Pnt & p = mapping . find ( key ) - > second ;
mp2 . Add ( p ) ;
}
mp2 . Close ( ) ;
BRepBuilderAPI_MakeFace mf ( mp2 . Wire ( ) ) ;
if ( mf . IsDone ( ) ) {
TopoDS_Face triangle_face = mf . Face ( ) ;
TopoDS_Iterator jt ( triangle_face , false ) ;
for ( ; jt . More ( ) ; jt . Next ( ) ) {
const TopoDS_Wire & w = TopoDS : : Wire ( jt . Value ( ) ) ;
if ( w . Orientation ( ) ! = wire . Orientation ( ) ) {
triangle_face . Reverse ( ) ;
}
}
faces . Append ( triangle_face ) ;
}
}
}
return true ;
}
2016-05-03 11:01:47 +02:00
TopoDS_Shape IfcGeom : : Kernel : : apply_transformation ( const TopoDS_Shape & s , const gp_Trsf & t ) {
if ( t . Form ( ) = = gp_Identity ) {
return s ;
} else {
/// @todo set to 1. and exactly 1. or use epsilon?
if ( t . ScaleFactor ( ) ! = 1. ) {
return BRepBuilderAPI_Transform ( s , t , true ) ;
} else {
return s . Moved ( t ) ;
}
}
}
TopoDS_Shape IfcGeom : : Kernel : : apply_transformation ( const TopoDS_Shape & s , const gp_GTrsf & t ) {
if ( t . Form ( ) = = gp_Other ) {
return BRepBuilderAPI_GTransform ( s , t , true ) ;
} else {
return apply_transformation ( s , t . Trsf ( ) ) ;
}
}
2018-04-18 11:33:57 +02:00
namespace {
/*
* A small helper utility to wrap around a numeric range
*/
class bounded_int {
private :
int i ;
size_t n ;
public :
bounded_int ( int i , size_t n ) : i ( i ) , n ( n ) { }
bounded_int & operator - - ( ) {
- - i ;
if ( i = = - 1 ) {
i = n - 1 ;
}
return * this ;
}
bounded_int & operator + + ( ) {
+ + i ;
2018-05-05 16:09:12 +02:00
if ( i = = ( int ) n ) {
2018-04-18 11:33:57 +02:00
i = 0 ;
}
return * this ;
}
operator int ( ) { return i ; }
} ;
std : : string format_pnt ( const gp_Pnt & p ) {
std : : stringstream ss ;
ss < < std : : fixed < < std : : setprecision ( 4 ) < < p . X ( ) < < " " < < p . Y ( ) < < " " < < p . Z ( ) ;
return ss . str ( ) ;
}
std : : string format_edge ( const TopoDS_Edge & e ) {
std : : stringstream ss ;
TopoDS_Vertex v1 , v2 ;
TopExp : : Vertices ( e , v1 , v2 ) ;
gp_Pnt p1 = BRep_Tool : : Pnt ( v1 ) ;
gp_Pnt p2 = BRep_Tool : : Pnt ( v2 ) ;
ss < < " edge " < < format_pnt ( p1 ) < < " -> " < < format_pnt ( p2 ) ;
return ss . str ( ) ;
}
}
bool IfcGeom : : Kernel : : wire_intersections ( const TopoDS_Wire & wire , TopTools_ListOfShape & wires ) {
if ( ! wire . Closed ( ) ) {
wires . Append ( wire ) ;
return false ;
}
int n = count ( wire , TopAbs_EDGE ) ;
2018-09-12 13:26:11 +02:00
if ( n < 3 ) {
2018-04-18 11:33:57 +02:00
wires . Append ( wire ) ;
return false ;
}
// Note: initialize empty
Handle ( ShapeExtend_WireData ) wd = new ShapeExtend_WireData ( ) ;
// ... to be sure to get consecutive edges
BRepTools_WireExplorer exp ( wire ) ;
2018-09-12 13:26:11 +02:00
IfcGeom : : impl : : tree < int > tree ;
int edge_idx = 0 ;
2018-04-18 11:33:57 +02:00
for ( ; exp . More ( ) ; exp . Next ( ) ) {
wd - > Add ( exp . Current ( ) ) ;
2018-09-12 13:26:11 +02:00
if ( n > 64 ) {
// tfk: indices in tree are 0-based vd 1-based in wiredata
tree . add ( edge_idx + + , exp . Current ( ) ) ;
}
2018-04-18 11:33:57 +02:00
}
2018-09-17 14:59:15 +02:00
if ( wd - > NbEdges ( ) ! = n ) {
// If the number of edges differs, BRepTools_WireExplorer did not
// reach every edge, probably due to loops exactly at vertex locations.
// This is not supported by this algorithm which only elimates loops
// due to edge crossings.
throw geometry_exception ( " Invalid loop " ) ;
}
2018-04-18 11:33:57 +02:00
bool intersected = false ;
// tfk: Extrema on infinite curves proved to be more robust.
// TopoDS_Face face = BRepBuilderAPI_MakeFace(wire, true).Face();
// ShapeAnalysis_Wire saw(wd, face, getValue(GV_PRECISION));
2018-09-12 13:26:11 +02:00
2018-09-21 10:22:24 +02:00
const double eps = ( std : : min ) ( min_edge_length ( wire ) / 2. , getValue ( GV_PRECISION ) * 10. ) ;
2018-09-12 13:26:11 +02:00
2018-04-18 11:33:57 +02:00
for ( int i = 2 ; i < n ; + + i ) {
2018-09-12 13:26:11 +02:00
std : : vector < int > js ;
if ( n > 64 ) {
Bnd_Box b ;
BRepBndLib : : Add ( wd - > Edge ( i + 1 ) , b ) ;
b . Enlarge ( eps ) ;
js = tree . select_box ( b , false ) ;
} else {
boost : : push_back ( js , boost : : irange ( 0 , i - 1 ) ) ;
}
for ( std : : vector < int > : : const_iterator it = js . begin ( ) ; it ! = js . end ( ) ; + + it ) {
int j = * it ;
if ( n > 64 ) {
if ( j > i ) {
continue ;
}
if ( ( std : : max ) ( i , j ) - ( std : : min ) ( i , j ) < = 1 ) {
continue ;
}
}
// Only check non-consecutive edges
if ( i = = n - 1 & & j = = 0 ) continue ;
2018-04-18 11:33:57 +02:00
bool unbounded_intersects ;
double u11 , u12 , u21 , u22 , U1 , U2 ;
GeomAPI_ExtremaCurveCurve ecc (
BRep_Tool : : Curve ( wd - > Edge ( i + 1 ) , u11 , u12 ) ,
BRep_Tool : : Curve ( wd - > Edge ( j + 1 ) , u21 , u22 )
) ;
2018-09-21 10:22:24 +02:00
// @todo: extend this to work in case of multiple extrema and curved segments.
2018-04-18 11:33:57 +02:00
if ( ( unbounded_intersects = ( ecc . NbExtrema ( ) = = 1 & & ecc . Distance ( 1 ) < eps ) ) ) {
ecc . Parameters ( 1 , U1 , U2 ) ;
}
if ( u11 > u12 ) {
std : : swap ( u11 , u12 ) ;
}
if ( u21 > u22 ) {
std : : swap ( u21 , u22 ) ;
}
/// @todo: tfk: probably need different thresholds on non-linear curves
u11 - = eps ;
u12 + = eps ;
u21 - = eps ;
u22 + = eps ;
// tfk: code below is for ShapeAnalysis_Wire::CheckIntersectingEdges()
// IntRes2d_SequenceOfIntersectionPoint points2d;
// TColgp_SequenceOfPnt points3d;
// TColStd_SequenceOfReal errors;
// if (saw.CheckIntersectingEdges(i + 1, j + 1, points2d, points3d, errors)) {
if ( unbounded_intersects & & u11 < U1 & & U1 < u12 & & u21 < U2 & & U2 < u22 ) {
intersected = true ;
// Explore a forward and backward cycle from the intersection point
for ( int fb = 0 ; fb < = 1 ; + + fb ) {
const bool forward = fb = = 0 ;
BRepBuilderAPI_MakeWire mw ;
bool first = true ;
for ( bounded_int k ( j , n ) ; ; ) {
bool intersecting = k = = j | | k = = i ;
if ( intersecting ) {
TopoDS_Edge e = wd - > Edge ( k + 1 ) ;
TopoDS_Vertex v1 , v2 ;
TopExp : : Vertices ( e , v1 , v2 ) ;
const TopoDS_Vertex * v = first = = forward ? & v2 : & v1 ;
// gp_Pnt p2 = points3d.Value(1);
gp_Pnt p1 = BRep_Tool : : Pnt ( * v ) ;
gp_Pnt pp1 , pp2 ;
ecc . Points ( 1 , pp1 , pp2 ) ;
const gp_Pnt & p2 = k = = i ? pp1 : pp2 ;
// Substitute with a new edge from/to the intersection point
if ( p1 . Distance ( p2 ) > getValue ( GV_PRECISION ) * 2 ) {
double _ , __ ;
Handle_Geom_Curve crv = BRep_Tool : : Curve ( e , _ , __ ) ;
BRepBuilderAPI_MakeEdge me ( crv , p1 , p2 ) ;
TopoDS_Edge ed = me . Edge ( ) ;
mw . Add ( ed ) ;
}
first = false ;
} else {
// Re-use original edge
mw . Add ( wd - > Edge ( k + 1 ) ) ;
}
if ( k = = i ) {
break ;
}
if ( forward ) {
+ + k ;
} else {
- - k ;
}
}
// Recursively process both cuts
wire_intersections ( mw . Wire ( ) , wires ) ;
}
return true ;
}
}
}
// No intersections found, append original wire
if ( ! intersected ) {
wires . Append ( wire ) ;
}
return intersected ;
}
void IfcGeom : : Kernel : : select_largest ( const TopTools_ListOfShape & shapes , TopoDS_Shape & largest ) {
double mass = 0. ;
TopTools_ListIteratorOfListOfShape it ( shapes ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
/*
// tfk: bounding box is more efficient probably
const TopoDS_Wire& w = TopoDS::Wire(it.Value());
TopoDS_Face face = BRepBuilderAPI_MakeFace(w).Face();
const double m = face_area(face);
*/
Bnd_Box bb ;
BRepBndLib : : AddClose ( it . Value ( ) , bb ) ;
double xyz_min [ 3 ] , xyz_max [ 3 ] ;
bb . Get ( xyz_min [ 0 ] , xyz_min [ 1 ] , xyz_min [ 2 ] , xyz_max [ 0 ] , xyz_max [ 1 ] , xyz_max [ 2 ] ) ;
const double eps = getValue ( GV_PRECISION ) ;
double m = 1. ;
for ( int i = 0 ; i < 3 ; + + i ) {
if ( Precision : : IsNegativeInfinite ( xyz_min [ i ] ) ) {
xyz_min [ i ] = 0. ;
}
if ( Precision : : IsInfinite ( xyz_max [ i ] ) ) {
xyz_max [ i ] = 0. ;
}
m * = ( xyz_max [ i ] + eps ) - ( xyz_min [ i ] - eps ) ;
}
if ( m > mass ) {
mass = m ;
largest = it . Value ( ) ;
}
}
}
2018-08-20 11:46:26 +02:00
bool IfcGeom : : Kernel : : fit_halfspace ( const TopoDS_Shape & a , const TopoDS_Shape & b , TopoDS_Shape & box , double & height ) {
TopExp_Explorer exp ( b , TopAbs_FACE ) ;
if ( ! exp . More ( ) ) {
return false ;
}
TopoDS_Face face = TopoDS : : Face ( exp . Current ( ) ) ;
exp . Next ( ) ;
if ( exp . More ( ) ) {
return false ;
}
Handle ( Geom_Surface ) surf = BRep_Tool : : Surface ( face ) ;
// const gp_XYZ xyz = a.Location().Transformation().TranslationPart();
// std::cout << "dz " << xyz.Z() << std::endl;
if ( surf - > DynamicType ( ) ! = STANDARD_TYPE ( Geom_Plane ) ) {
return false ;
}
Bnd_Box bb ;
BRepBndLib : : Add ( a , bb ) ;
2018-09-17 15:21:12 +02:00
if ( bb . IsVoid ( ) ) {
return false ;
}
2018-08-20 11:46:26 +02:00
double xs [ 2 ] , ys [ 2 ] , zs [ 2 ] ;
bb . Get ( xs [ 0 ] , ys [ 0 ] , zs [ 0 ] , xs [ 1 ] , ys [ 1 ] , zs [ 1 ] ) ;
gp_Pln pln = Handle ( Geom_Plane ) : : DownCast ( surf ) - > Pln ( ) ;
gp_Pnt P = pln . Position ( ) . Location ( ) ;
gp_Vec z = pln . Position ( ) . Direction ( ) ;
gp_Vec x = pln . Position ( ) . XDirection ( ) ;
gp_Vec y = pln . Position ( ) . YDirection ( ) ;
if ( face . Orientation ( ) ! = TopAbs_REVERSED ) {
z . Reverse ( ) ;
}
double D , Umin , Umax , Vmin , Vmax ;
D = 0. ;
Umin = Vmin = + std : : numeric_limits < double > : : infinity ( ) ;
Umax = Vmax = - std : : numeric_limits < double > : : infinity ( ) ;
for ( int i = 0 ; i < 2 ; + + i ) {
for ( int j = 0 ; j < 2 ; + + j ) {
for ( int k = 0 ; k < 2 ; + + k ) {
gp_Pnt p ( xs [ i ] , ys [ j ] , zs [ k ] ) ;
gp_Vec d = p . XYZ ( ) - P . XYZ ( ) ;
const double u = d . Dot ( x ) ;
const double v = d . Dot ( y ) ;
const double w = d . Dot ( z ) ;
if ( w > D ) {
D = w ;
}
if ( u < Umin ) {
Umin = u ;
}
if ( u > Umax ) {
Umax = u ;
}
if ( v < Vmin ) {
Vmin = v ;
}
if ( v > Vmax ) {
Vmax = v ;
}
}
}
}
const double eps = getValue ( GV_PRECISION ) * 2. ;
BRepBuilderAPI_MakePolygon poly ;
poly . Add ( P . XYZ ( ) + x . XYZ ( ) * ( Umin + eps ) + y . XYZ ( ) * ( Vmin + eps ) ) ;
poly . Add ( P . XYZ ( ) + x . XYZ ( ) * ( Umax + eps ) + y . XYZ ( ) * ( Vmin + eps ) ) ;
poly . Add ( P . XYZ ( ) + x . XYZ ( ) * ( Umax + eps ) + y . XYZ ( ) * ( Vmax + eps ) ) ;
poly . Add ( P . XYZ ( ) + x . XYZ ( ) * ( Umin + eps ) + y . XYZ ( ) * ( Vmax + eps ) ) ;
poly . Close ( ) ;
BRepBuilderAPI_MakeFace mf ( surf , poly . Wire ( ) , true ) ;
gp_Vec vec = gp_Vec ( z . XYZ ( ) * ( D + eps ) ) ;
BRepPrimAPI_MakePrism mp ( mf . Face ( ) , vec ) ;
box = mp . Shape ( ) ;
height = D ;
return true ;
}
2017-02-16 15:54:34 +01:00
# if OCC_VERSION_HEX < 0x60900
bool IfcGeom : : Kernel : : boolean_operation ( const TopoDS_Shape & a , const TopTools_ListOfShape & b , BOPAlgo_Operation op , TopoDS_Shape & result ) {
result = a ;
TopTools_ListIteratorOfListOfShape it ( b ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
TopoDS_Shape r ;
if ( ! boolean_operation ( result , it . Value ( ) , op , r ) ) {
return false ;
}
result = r ;
}
return true ;
}
bool IfcGeom : : Kernel : : boolean_operation ( const TopoDS_Shape & a , const TopoDS_Shape & b , BOPAlgo_Operation op , TopoDS_Shape & result ) {
bool succesful = true ;
BRepAlgoAPI_BooleanOperation * builder ;
if ( op = = BOPAlgo_CUT ) {
builder = new BRepAlgoAPI_Cut ( a , b ) ;
} else if ( op = = BOPAlgo_COMMON ) {
builder = new BRepAlgoAPI_Common ( a , b ) ;
} else if ( op = = BOPAlgo_FUSE ) {
builder = new BRepAlgoAPI_Fuse ( a , b ) ;
} else {
return false ;
}
if ( builder - > IsDone ( ) ) {
TopoDS_Shape r = * builder ;
succesful = BRepCheck_Analyzer ( r ) . IsValid ( ) ! = 0 ;
if ( succesful ) {
result = r ;
ShapeFix_Shape fix ( result ) ;
try {
fix . Perform ( ) ;
result = fix . Shape ( ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_WARNING , " Shape healing failed on boolean result " ) ;
}
} else {
// Increase tolerance max 3 times until succesful
TopoDS_Shape a2 = a ;
TopoDS_Shape b2 = b ;
ShapeAnalysis_ShapeTolerance tolerance ;
const double t1 = tolerance . Tolerance ( a , 1 ) * 10. ;
const double t2 = tolerance . Tolerance ( b , 1 ) * 10. ;
if ( ( ( std : : max ) ( t1 , t2 ) + 1e-15 ) > getValue ( GV_PRECISION ) * 1000. ) {
return false ;
}
apply_tolerance ( a2 , t1 ) ;
apply_tolerance ( b2 , t2 ) ;
succesful = boolean_operation ( a2 , b2 , op , result ) ;
}
}
delete builder ;
return succesful ;
}
# else
2018-09-19 16:42:34 +02:00
bool IfcGeom : : Kernel : : boolean_operation ( const TopoDS_Shape & a , const TopTools_ListOfShape & b_ , BOPAlgo_Operation op , TopoDS_Shape & result , double fuzziness ) {
2017-02-16 15:54:34 +01:00
bool success = false ;
BRepAlgoAPI_BooleanOperation * builder ;
2018-09-19 16:42:34 +02:00
TopTools_ListOfShape b ;
2017-02-16 15:54:34 +01:00
if ( op = = BOPAlgo_CUT ) {
builder = new BRepAlgoAPI_Cut ( ) ;
2018-09-19 16:42:34 +02:00
bounding_box_overlap ( getValue ( GV_PRECISION ) , a , b_ , b ) ;
2017-02-16 15:54:34 +01:00
} else if ( op = = BOPAlgo_COMMON ) {
builder = new BRepAlgoAPI_Common ( ) ;
2018-09-19 16:42:34 +02:00
bounding_box_overlap ( getValue ( GV_PRECISION ) , a , b_ , b ) ;
2017-02-16 15:54:34 +01:00
} else if ( op = = BOPAlgo_FUSE ) {
builder = new BRepAlgoAPI_Fuse ( ) ;
2018-09-19 16:42:34 +02:00
b = b_ ;
2017-02-16 15:54:34 +01:00
} else {
return false ;
}
if ( fuzziness < 0. ) {
fuzziness = getValue ( GV_PRECISION ) ;
}
2018-05-13 09:15:06 +02:00
2018-08-20 11:46:26 +02:00
double min_len = ( std : : min ) ( min_edge_length ( a ) , min_vertex_edge_distance ( a , getValue ( GV_PRECISION ) ) ) ;
TopTools_ListIteratorOfListOfShape it ( b ) ;
for ( ; it . More ( ) ; it . Next ( ) ) {
double d = min_edge_length ( it . Value ( ) ) ;
if ( d < min_len ) {
min_len = d ;
}
d = min_vertex_edge_distance ( it . Value ( ) , getValue ( GV_PRECISION ) ) ;
if ( d < min_len ) {
min_len = d ;
}
}
const double fuzz = ( std : : min ) ( min_len / 10. , fuzziness ) ;
2018-05-13 09:15:06 +02:00
2017-02-16 15:54:34 +01:00
TopTools_ListOfShape s1s ;
2018-06-15 12:39:29 +02:00
s1s . Append ( copy_operand ( a ) ) ;
# if OCC_VERSION_HEX >= 0x70000
2018-06-12 16:15:12 +02:00
builder - > SetNonDestructive ( true ) ;
2018-06-15 12:39:29 +02:00
# endif
2018-06-08 14:12:01 +02:00
builder - > SetFuzzyValue ( fuzz ) ;
2017-02-16 15:54:34 +01:00
builder - > SetArguments ( s1s ) ;
2018-06-15 12:39:29 +02:00
builder - > SetTools ( copy_operand ( b ) ) ;
2017-02-16 15:54:34 +01:00
builder - > Build ( ) ;
if ( builder - > IsDone ( ) ) {
TopoDS_Shape r = * builder ;
2017-11-13 12:41:37 +01:00
ShapeFix_Shape fix ( r ) ;
try {
2018-06-08 14:12:01 +02:00
fix . SetMinTolerance ( fuzz ) ;
fix . SetMaxTolerance ( fuzz ) ;
fix . SetPrecision ( fuzz ) ;
2017-11-13 12:41:37 +01:00
fix . Perform ( ) ;
r = fix . Shape ( ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_WARNING , " Shape healing failed on boolean result " ) ;
}
2017-02-16 15:54:34 +01:00
success = BRepCheck_Analyzer ( r ) . IsValid ( ) ! = 0 ;
2017-11-13 12:41:37 +01:00
2017-02-16 15:54:34 +01:00
if ( success ) {
2018-09-17 12:00:49 +02:00
success = ! is_manifold ( a ) | | is_manifold ( r ) ;
if ( success ) {
2018-09-17 12:02:41 +02:00
// when there are edges or vertex-edge distances close to the used fuzziness, the
// output is not trusted and the operation is attempted with a higher fuzziness.
double min_len_check = ( std : : min ) ( min_edge_length ( r ) , min_vertex_edge_distance ( r , getValue ( GV_PRECISION ) ) ) ;
success = min_len_check > fuzziness * 10. ;
if ( success ) {
result = r ;
}
2018-09-17 12:00:49 +02:00
}
2017-02-16 15:54:34 +01:00
}
}
delete builder ;
if ( ! success ) {
2017-04-25 12:43:29 +02:00
const double new_fuzziness = fuzziness * 10. ;
2018-08-20 11:46:26 +02:00
if ( new_fuzziness + 1e-15 < = getValue ( GV_PRECISION ) * 1000. & & new_fuzziness < min_len ) {
2017-04-25 12:43:29 +02:00
return boolean_operation ( a , b , op , result , new_fuzziness ) ;
}
2017-02-16 15:54:34 +01:00
}
return success ;
}
bool IfcGeom : : Kernel : : boolean_operation ( const TopoDS_Shape & a , const TopoDS_Shape & b , BOPAlgo_Operation op , TopoDS_Shape & result , double fuzziness ) {
TopTools_ListOfShape bs ;
bs . Append ( b ) ;
return boolean_operation ( a , bs , op , result , fuzziness ) ;
}
2017-11-13 13:01:59 +01:00
# endif