2021-11-05 16:54:16 +01: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>
2014-07-24 11:14:54 +00:00
# include <algorithm>
2019-08-21 11:59:30 +02:00
# include <numeric>
2012-06-25 15:08:58 +00:00
2018-12-19 16:30:05 +01:00
# include <Standard_Version.hxx>
2011-07-25 14:56:40 +00:00
# include <gp_Pnt.hxx>
# include <gp_Vec.hxx>
# include <gp_Dir.hxx>
# include <gp_Pnt2d.hxx>
2011-10-23 17:11:06 +00:00
# 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_Pln.hxx>
# include <Geom_Line.hxx>
# include <Geom_Circle.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>
2018-12-19 16:10:33 +01:00
# if OCC_VERSION_HEX >= 0x70200
# include <BRepAlgoAPI_Splitter.hxx>
# endif
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>
2019-02-12 13:59:49 +01:00
# include <ShapeFix_Shell.hxx>
2011-07-25 14:56:40 +00:00
2015-10-07 17:33:30 +02:00
# include <ShapeAnalysis_Curve.hxx>
# include <ShapeAnalysis_Surface.hxx>
2019-04-24 16:32:06 +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>
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 <BRepGProp_Face.hxx>
2021-12-18 22:02:47 +01:00
# include <BRepCheck.hxx>
# include <BRepCheck_Analyzer.hxx>
2012-03-13 11:56:52 +00:00
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>
2015-10-07 17:33:30 +02:00
# include <BOPAlgo_PaveFiller.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>
2019-08-16 10:42:48 +02:00
# include <Extrema_ExtCS.hxx>
2018-08-20 11:46:26 +02:00
2019-09-26 15:14:23 +02:00
# include <ShapeAnalysis_Edge.hxx>
2021-11-19 10:39:14 +01:00
# if OCC_VERSION_HEX >= 0x70200
# include <BOPAlgo_Alerts.hxx>
# endif
2018-03-16 16:04:48 +01:00
# include "../ifcparse/macros.h"
2015-02-17 19:48:41 +00:00
# include "../ifcparse/IfcSIPrefix.h"
2022-06-15 13:41:13 +02:00
2015-10-07 17:33:30 +02:00
# include "../ifcparse/IfcFile.h"
2011-08-24 12:21:07 +00:00
# include "../ifcgeom/IfcGeom.h"
2022-06-15 13:41:13 +02:00
# include "../ifcgeom_schema_agnostic/IfcGeomTree.h"
2022-06-14 15:02:54 +02:00
# include "../ifcgeom_schema_agnostic/boolean_utils.h"
2022-09-12 10:34:04 +02:00
# include "../ifcgeom_schema_agnostic/wire_utils.h"
2022-11-13 11:04:16 +01:00
# include "../ifcgeom_schema_agnostic/base_utils.h"
2022-11-14 09:23:59 +01:00
# include "../ifcgeom_schema_agnostic/layerset.h"
2011-07-25 14:56:40 +00:00
2018-12-10 10:45:58 +01:00
# include <memory>
2021-12-19 21:57:47 +01:00
# include <thread>
2018-12-10 10:45:58 +01: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
2021-03-17 22:19:19 +02:00
# warning "You are 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."
2016-02-18 13:17:15 +01:00
# endif
2016-01-25 13:30:33 +01:00
# endif
2017-12-28 16:33:07 +01:00
namespace {
2018-09-05 14:42:59 +02:00
struct MAKE_TYPE_NAME ( factory_t ) {
2017-12-22 13:51:11 +01:00
IfcGeom : : Kernel * operator ( ) ( IfcParse : : IfcFile * file ) const {
IfcGeom : : MAKE_TYPE_NAME ( Kernel ) * k = new IfcGeom : : MAKE_TYPE_NAME ( Kernel ) ;
if ( file ) {
double unit_magnitude = 1. ;
// Set unit information from file
IfcSchema : : IfcProject : : list : : ptr projects = file - > instances_by_type < IfcSchema : : IfcProject > ( ) ;
if ( projects - > size ( ) = = 1 ) {
IfcSchema : : IfcProject * project = * projects - > begin ( ) ;
std : : pair < std : : string , double > unit_info = k - > initializeUnits ( project - > UnitsInContext ( ) ) ;
unit_magnitude = unit_info . second ;
2018-09-08 08:27:45 +02:00
} else {
2018-12-29 12:34:32 +01:00
Logger : : Warning ( " A single IfcProject is expected (encountered " + boost : : lexical_cast < std : : string > ( projects - > size ( ) ) + " ); unable to read unit information. " ) ;
2017-12-22 13:51:11 +01:00
}
// Set precision from file
double lowest_precision_encountered = std : : numeric_limits < double > : : infinity ( ) ;
bool any_precision_encountered = false ;
IfcSchema : : IfcGeometricRepresentationContext : : list : : it it ;
IfcSchema : : IfcGeometricRepresentationContext : : list : : ptr contexts =
2018-01-01 11:22:12 +01:00
file - > instances_by_type_excl_subtypes < IfcSchema : : IfcGeometricRepresentationContext > ( ) ;
2017-12-22 13:51:11 +01:00
for ( it = contexts - > begin ( ) ; it ! = contexts - > end ( ) ; + + it ) {
IfcSchema : : IfcGeometricRepresentationContext * context = * it ;
2021-07-29 14:54:51 +02:00
if ( context - > Precision ( ) & & ( * context - > Precision ( ) * unit_magnitude * 10. ) < lowest_precision_encountered ) {
2017-12-22 13:51:11 +01:00
// Some arbitrary factor that has proven to work better for the models in the set of test files.
2021-07-29 14:54:51 +02:00
lowest_precision_encountered = * context - > Precision ( ) * unit_magnitude * 10. ;
2017-12-22 13:51:11 +01:00
any_precision_encountered = true ;
}
}
double precision_to_set = 1.e-5 ;
if ( any_precision_encountered ) {
if ( lowest_precision_encountered < 1.e-7 ) {
Logger : : Message ( Logger : : LOG_WARNING , " Precision lower than 0.0000001 meter not enforced " ) ;
precision_to_set = 1.e-7 ;
} else {
precision_to_set = lowest_precision_encountered ;
}
}
k - > setValue ( IfcGeom : : Kernel : : GV_PRECISION , precision_to_set ) ;
}
return k ;
}
2017-12-28 16:33:07 +01:00
} ;
}
2017-12-22 13:51:11 +01:00
2017-12-28 16:33:07 +01:00
void MAKE_INIT_FN ( KernelImplementation_ ) ( IfcGeom : : impl : : KernelFactoryImplementation * mapping ) {
static const std : : string schema_name = STRINGIFY ( IfcSchema ) ;
2018-09-05 14:42:59 +02:00
MAKE_TYPE_NAME ( factory_t ) factory ;
2017-12-22 13:51:11 +01:00
mapping - > bind ( schema_name , factory ) ;
}
2017-12-20 16:38:55 +01:00
# define Kernel MAKE_TYPE_NAME(Kernel)
2020-01-31 15:55:04 +01:00
void IfcGeom : : Kernel : : set_offset ( const std : : array < double , 3 > & p_offset ) {
offset = gp_Vec ( p_offset [ 0 ] , p_offset [ 1 ] , p_offset [ 2 ] ) ;
2022-11-13 11:04:16 +01:00
offset_and_rotation = util : : combine_offset_and_rotation ( offset , rotation ) ;
2020-01-31 15:55:04 +01:00
}
void IfcGeom : : Kernel : : set_rotation ( const std : : array < double , 4 > & p_rotation ) {
rotation = gp_Quaternion ( p_rotation [ 0 ] , p_rotation [ 1 ] , p_rotation [ 2 ] , p_rotation [ 3 ] ) ;
2022-11-13 11:04:16 +01:00
offset_and_rotation = util : : combine_offset_and_rotation ( offset , rotation ) ;
2018-09-21 10:22:24 +02:00
}
2018-11-23 11:45:23 +01:00
namespace {
struct opening_sorter {
bool operator ( ) ( const std : : pair < double , TopoDS_Shape > & a , const std : : pair < double , TopoDS_Shape > & b ) const {
return a . first > b . first ;
}
} ;
}
2022-11-13 11:04:16 +01:00
bool IfcGeom : : Kernel : : convert_openings ( const IfcSchema : : IfcProduct * entity , const IfcSchema : : IfcRelVoidsElement : : list : : ptr & openings ,
2018-11-23 11:45:23 +01:00
const IfcGeom : : IfcRepresentationShapeItems & entity_shapes , const gp_Trsf & entity_trsf , IfcGeom : : IfcRepresentationShapeItems & cut_shapes ) {
2022-11-13 11:04:16 +01:00
util : : boolean_settings bst ;
bst . attempt_2d = getValue ( GV_BOOLEAN_ATTEMPT_2D ) > 0. ;
bst . debug = getValue ( GV_DEBUG_BOOLEAN ) > 0. ;
bst . precision = getValue ( GV_PRECISION ) ;
2018-11-23 11:45:23 +01:00
std : : vector < std : : pair < double , TopoDS_Shape > > opening_vector ;
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
2016-01-25 13:30:33 +01:00
IfcSchema : : IfcRelVoidsElement * v = * it ;
IfcSchema : : IfcFeatureElementSubtraction * fes = v - > RelatedOpeningElement ( ) ;
2018-11-28 14:18:58 +01:00
if ( fes - > declaration ( ) . is ( IfcSchema : : IfcOpeningElement : : Class ( ) ) ) {
2021-07-29 14:54:51 +02:00
if ( ! fes - > Representation ( ) ) continue ;
2016-01-25 13:30:33 +01:00
2021-12-19 21:55:41 +01:00
/*
// Not yet implemented and tested, process opening placement up to parent wall
// placement so that the matrix inverse can be eliminated.
// @todo property check and handle the decomposition into parts (where element
// carying geom and opening are in different branches).
// @todo properly check whether opening correctly references wall placement
// and fallback to matrix inverse when not the case.
auto relative = entity;
{
auto ds = relative->Decomposes();
if (ds->size() == 1) {
relative = (*ds->begin())->RelatingObject()->as<IfcSchema::IfcProduct>();
}
2022-01-13 01:24:57 +01:00
}
2021-12-19 21:55:41 +01:00
set_conversion_placement_rel_to_instance(relative);
*/
2016-01-25 13:30:33 +01:00
// Convert the IfcRepresentation of the IfcOpeningElement
gp_Trsf opening_trsf ;
2021-07-29 14:54:51 +02:00
if ( fes - > ObjectPlacement ( ) ) {
2016-01-25 13:30:33 +01:00
try {
2018-11-23 11:45:23 +01:00
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
}
2021-12-19 21:55:41 +01:00
// set_conversion_placement_rel_to_instance(nullptr);
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 ;
2018-11-23 11:45:23 +01:00
for ( IfcSchema : : IfcRepresentation : : list : : it it2 = reps - > begin ( ) ; it2 ! = reps - > end ( ) ; + + it2 ) {
2021-11-02 15:09:26 +01:00
if ( IfcParse : : traverse ( ( * it2 ) ) - > as < IfcSchema : : IfcBoundingBox > ( ) - > size ( ) ) {
continue ;
}
2018-11-23 11:45:23 +01:00
convert_shapes ( * it2 , opening_shapes ) ;
2016-01-25 13:30:33 +01:00
}
2018-11-23 11:45:23 +01:00
for ( unsigned int i = 0 ; i < opening_shapes . size ( ) ; + + i ) {
2018-05-05 16:09:12 +02:00
TopoDS_Shape opening_shape_solid ;
2022-11-14 09:23:59 +01:00
const TopoDS_Shape & opening_shape_unlocated = util : : ensure_fit_for_subtraction ( opening_shapes [ i ] . Shape ( ) , opening_shape_solid , getValue ( GV_PRECISION ) ) ;
2018-05-05 16:09:12 +02:00
2016-01-25 13:30:33 +01:00
gp_GTrsf gtrsf = opening_shapes [ i ] . Placement ( ) ;
gtrsf . PreMultiply ( opening_trsf ) ;
2022-11-14 09:23:59 +01:00
TopoDS_Shape opening_shape = util : : apply_transformation ( opening_shape_unlocated , gtrsf ) ;
2022-06-14 15:02:54 +02:00
opening_vector . push_back ( std : : make_pair ( util : : min_edge_length ( opening_shape ) , opening_shape ) ) ;
2016-01-25 13:30:33 +01:00
}
}
}
2018-11-23 11:45:23 +01:00
std : : sort ( opening_vector . begin ( ) , opening_vector . end ( ) , opening_sorter ( ) ) ;
2016-01-25 13:30:33 +01:00
// Iterate over the shapes of the IfcProduct
2022-06-11 15:48:04 +02:00
for ( IfcGeom : : IfcRepresentationShapeItems : : const_iterator it3 = entity_shapes . begin ( ) ; it3 ! = entity_shapes . end ( ) ; + + it3 ) {
2022-01-13 01:24:57 +01:00
2022-06-11 15:48:04 +02:00
TopoDS_Compound C ;
BRep_Builder B ;
B . MakeCompound ( C ) ;
TopoDS_Shape combined_result ;
2021-05-23 16:26:34 +02:00
2022-06-11 15:48:04 +02:00
std : : list < TopoDS_Shape > parts ;
2016-01-22 17:27:28 +01:00
2022-06-11 15:48:04 +02:00
bool is_multiple = it3 - > Shape ( ) . ShapeType ( ) = = TopAbs_COMPOUND & & TopoDS_Iterator ( it3 - > Shape ( ) ) . More ( ) & & util : : is_nested_compound_of_solid ( it3 - > Shape ( ) ) ;
2018-11-23 11:45:23 +01:00
2022-06-11 15:48:04 +02:00
if ( is_multiple ) {
TopoDS_Iterator sit ( it3 - > Shape ( ) ) ;
for ( ; sit . More ( ) ; sit . Next ( ) ) {
parts . push_back ( sit . Value ( ) ) ;
2021-05-23 16:26:34 +02:00
}
2022-06-11 15:48:04 +02:00
} else {
parts . push_back ( it3 - > Shape ( ) ) ;
}
for ( auto & entity_part : parts ) {
2022-11-13 11:04:16 +01:00
bool is_manifold = util : : is_manifold ( entity_part ) ;
2022-06-11 15:48:04 +02:00
if ( ! is_manifold ) {
Logger : : Warning ( " Non-manifold first operand " ) ;
2021-05-23 16:26:34 +02:00
}
2018-11-23 11:45:23 +01:00
2022-06-11 15:48:04 +02:00
TopoDS_Shape entity_part_result ;
for ( int as_shell = 0 ; as_shell < 2 ; + + as_shell ) {
TopoDS_Shape entity_shape_solid ;
TopoDS_Shape entity_shape_unlocated ;
if ( as_shell ) {
entity_shape_unlocated = entity_part ;
} else {
2022-11-14 09:23:59 +01:00
entity_shape_unlocated = util : : ensure_fit_for_subtraction ( entity_part , entity_shape_solid , getValue ( GV_PRECISION ) ) ;
2022-06-11 15:48:04 +02:00
}
const gp_GTrsf & entity_shape_gtrsf = it3 - > Placement ( ) ;
if ( entity_shape_gtrsf . Form ( ) = = gp_Other ) {
Logger : : Message ( Logger : : LOG_WARNING , " Applying non uniform transformation to: " , entity ) ;
}
2022-11-14 09:23:59 +01:00
TopoDS_Shape entity_shape = util : : apply_transformation ( entity_shape_unlocated , entity_shape_gtrsf ) ;
2018-11-23 11:45:23 +01:00
2022-06-11 15:48:04 +02:00
TopoDS_Shape result = entity_shape ;
2021-05-23 16:26:34 +02:00
2022-06-11 15:48:04 +02:00
auto it = opening_vector . begin ( ) ;
auto jt = it ;
2021-05-23 16:26:34 +02:00
2022-06-11 15:48:04 +02:00
for ( ; ; + + it ) {
if ( it = = opening_vector . end ( ) | | jt - > first / it - > first > 10. ) {
2021-05-23 16:26:34 +02:00
2022-06-11 15:48:04 +02:00
TopTools_ListOfShape opening_list ;
for ( auto kt = jt ; kt < it ; + + kt ) {
opening_list . Append ( kt - > second ) ;
}
TopoDS_Shape intermediate_result ;
2022-11-13 11:04:16 +01:00
if ( util : : boolean_operation ( bst , result , opening_list , BOPAlgo_CUT , intermediate_result ) ) {
2022-06-11 15:48:04 +02:00
result = intermediate_result ;
} else {
Logger : : Message ( Logger : : LOG_ERROR , " Opening subtraction failed for " + boost : : lexical_cast < std : : string > ( std : : distance ( jt , it ) ) + " openings " , entity ) ;
}
jt = it ;
2021-05-23 16:26:34 +02:00
}
2022-06-11 15:48:04 +02:00
if ( it = = opening_vector . end ( ) ) {
break ;
}
2018-11-23 11:45:23 +01:00
}
2022-11-13 11:04:16 +01:00
int result_n_faces = util : : count ( result , TopAbs_FACE ) ;
2022-06-11 15:48:04 +02:00
if ( ! is_manifold & & as_shell = = 0 & & result_n_faces = = 0 ) {
// If we have a non-manifold first operand and our first attempt
// on a Solid-Solid subtraction yielded a empty result (no faces)
// or a strange result, a larger number of faces with the original input
// included. Then retry (another iteration on the for-loop on as-shell)
// where we keep the first operand as is (a compound of faces probably,
// unless --orient-shells was activated in which case we're already lost).
if ( ! is_manifold ) {
Logger : : Warning ( " Retrying boolean operation on individual faces " ) ;
}
continue ;
2021-05-23 16:26:34 +02:00
}
2022-06-11 15:48:04 +02:00
entity_part_result = result ;
// For manifold first operands we're not even going to try if processing
// as loose faces gives a better result.
break ;
2018-11-23 11:45:23 +01:00
}
2022-06-11 15:48:04 +02:00
if ( is_multiple ) {
B . Add ( C , entity_part_result ) ;
} else {
combined_result = entity_part_result ;
2018-11-23 11:45:23 +01:00
}
2022-06-11 15:48:04 +02:00
}
2021-05-23 16:26:34 +02:00
2022-06-11 15:48:04 +02:00
if ( is_multiple ) {
combined_result = C ;
2021-05-23 16:26:34 +02:00
}
2022-06-11 15:48:04 +02:00
cut_shapes . push_back ( IfcGeom : : IfcRepresentationShapeItem ( it3 - > ItemId ( ) , combined_result , it3 - > StylePtr ( ) ) ) ;
2012-06-07 14:38:21 +00:00
}
return true ;
}
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-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 ;
2019-05-24 14:29:21 +02:00
case GV_MAX_FACES_TO_ORIENT :
max_faces_to_orient = value ;
break ;
2020-06-07 19:46:10 +02:00
case GV_LAYERSET_FIRST :
layerset_first = value ;
break ;
2020-11-24 16:58:05 +01:00
case GV_DISABLE_BOOLEAN_RESULT :
disable_boolean_result = value ;
break ;
2021-02-05 14:00:23 -06:00
case GV_NO_WIRE_INTERSECTION_CHECK :
no_wire_intersection_check = value ;
break ;
2021-02-06 10:26:17 -06:00
case GV_PRECISION_FACTOR :
precision_factor = value ;
break ;
2021-02-08 14:06:05 -06:00
case GV_NO_WIRE_INTERSECTION_TOLERANCE :
no_wire_intersection_tolerance = value ;
break ;
2021-12-19 21:57:47 +01:00
case GV_DEBUG_BOOLEAN :
boolean_debug_setting = value ;
break ;
2022-01-09 15:15:29 +01:00
case GV_BOOLEAN_ATTEMPT_2D :
boolean_attempt_2d = value ;
break ;
2012-06-27 15:59:09 +00:00
default :
2019-05-24 14:29:21 +02:00
throw std : : runtime_error ( " Invalid setting " ) ;
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_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.
2019-05-24 14:29:21 +02:00
return modelling_precision * modelling_precision / 20. ;
2012-06-25 15:08:58 +00:00
case GV_POINT_EQUALITY_TOLERANCE :
2019-05-24 14:29:21 +02:00
return modelling_precision ;
2012-08-11 13:24:08 +00:00
case GV_LENGTH_UNIT :
return ifc_length_unit ;
case GV_PLANEANGLE_UNIT :
return ifc_planeangle_unit ;
2013-11-24 15:44:27 +00:00
case GV_PRECISION :
return modelling_precision ;
2015-04-22 09:15:48 +00:00
case GV_DIMENSIONALITY :
return dimensionality ;
2019-05-24 14:29:21 +02:00
case GV_MAX_FACES_TO_ORIENT :
return max_faces_to_orient ;
2020-06-07 19:46:10 +02:00
case GV_LAYERSET_FIRST :
return layerset_first ;
2020-11-24 16:58:05 +01:00
case GV_DISABLE_BOOLEAN_RESULT :
return disable_boolean_result ;
2021-02-05 14:00:23 -06:00
case GV_NO_WIRE_INTERSECTION_CHECK :
return no_wire_intersection_check ;
2021-02-06 10:26:17 -06:00
case GV_PRECISION_FACTOR :
return precision_factor ;
2021-02-08 14:06:05 -06:00
case GV_NO_WIRE_INTERSECTION_TOLERANCE :
return no_wire_intersection_tolerance ;
2021-12-19 21:57:47 +01:00
case GV_DEBUG_BOOLEAN :
return boolean_debug_setting ;
2022-01-09 15:15:29 +01:00
case GV_BOOLEAN_ATTEMPT_2D :
return boolean_attempt_2d ;
2012-06-25 15:08:58 +00:00
}
2019-05-24 14:29:21 +02:00
throw std : : runtime_error ( " Invalid setting " ) ;
2012-11-04 16:26:33 +00:00
}
2017-12-20 16:38:55 +01:00
2022-11-14 09:23:59 +01:00
IfcSchema : : IfcRelVoidsElement : : list : : ptr IfcGeom : : Kernel : : find_openings ( IfcSchema : : IfcProduct * product ) {
std : : vector < IfcSchema : : IfcRelVoidsElement * > rs ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
2022-11-14 09:23:59 +01:00
if ( product - > declaration ( ) . is ( IfcSchema : : IfcElement : : Class ( ) ) & & ! product - > declaration ( ) . is ( IfcSchema : : IfcOpeningElement : : Class ( ) ) ) {
IfcSchema : : IfcElement * element = ( IfcSchema : : IfcElement * ) product ;
auto rels = element - > HasOpenings ( ) ;
rs . insert ( rs . end ( ) , rels - > begin ( ) , rels - > end ( ) ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
}
2017-12-20 16:38:55 +01:00
2022-11-14 09:23:59 +01:00
// Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
IfcSchema : : IfcObjectDefinition * obdef = product - > as < IfcSchema : : IfcObjectDefinition > ( ) ;
for ( ; ; ) {
auto decomposes = obdef - > Decomposes ( ) ;
if ( decomposes - > size ( ) ! = 1 ) break ;
IfcSchema : : IfcObjectDefinition * rel_obdef = ( * decomposes - > begin ( ) ) - > RelatingObject ( ) ;
if ( rel_obdef - > declaration ( ) . is ( IfcSchema : : IfcElement : : Class ( ) ) & & ! rel_obdef - > declaration ( ) . is ( IfcSchema : : IfcOpeningElement : : Class ( ) ) ) {
IfcSchema : : IfcElement * element = ( IfcSchema : : IfcElement * ) rel_obdef ;
auto rels = element - > HasOpenings ( ) ;
rs . insert ( rs . end ( ) , rels - > begin ( ) , rels - > end ( ) ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
}
2022-11-14 09:23:59 +01:00
obdef = rel_obdef ;
}
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
2022-11-14 09:23:59 +01:00
// Filter openings in Reference view, solely marked as Reference.
IfcSchema : : IfcRelVoidsElement : : list : : ptr openings ( new IfcSchema : : IfcRelVoidsElement : : list ) ;
std : : for_each ( rs . begin ( ) , rs . end ( ) , [ & openings ] ( IfcSchema : : IfcRelVoidsElement * rel ) {
if ( rel - > RelatedOpeningElement ( ) - > ObjectPlacement ( ) & & rel - > RelatedOpeningElement ( ) - > Representation ( ) ) {
auto reps = rel - > RelatedOpeningElement ( ) - > Representation ( ) - > Representations ( ) ;
if ( ! ( reps - > size ( ) = = 1 & & ( * reps - > begin ( ) ) - > RepresentationIdentifier ( ) . get_value_or ( " " ) = = " Reference " ) ) {
openings - > push ( rel ) ;
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
}
}
2022-11-14 09:23:59 +01:00
} ) ;
2022-01-13 01:24:57 +01:00
2022-11-14 09:23:59 +01:00
return openings ;
}
Add support for IfcBooleanResult, IfcBlock, IfcRectangularPyramid, IfcRightCircularCylinder, IfcRightCircularCone, IfcSphere, IfcCsgSolid, IfcCurveBoundedPlane, IfcRectangularTrimmedSurface, IfcSurfaceCurveSweptAreaSolid, IfcCylindricalSurface.
2014-03-22 10:31:51 +00:00
2022-11-14 09:23:59 +01: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 > ( ) ;
// NB: IfcMaterialLayerSets are also considered, regardless of --enable-layerset-slicing. Picking
// the first material (in accordance with other viewers) when layerset-slicing is disabled.
if ( ! single_material & & associated_material - > as < IfcSchema : : IfcMaterialLayerSetUsage > ( ) ) {
IfcSchema : : IfcMaterialLayerSet * layerset = associated_material - > as < IfcSchema : : IfcMaterialLayerSetUsage > ( ) - > ForLayerSet ( ) ;
if ( getValue ( GV_LAYERSET_FIRST ) > 0.0 ? layerset - > MaterialLayers ( ) - > size ( ) > = 1 : layerset - > MaterialLayers ( ) - > size ( ) = = 1 ) {
IfcSchema : : IfcMaterialLayer * layer = ( * layerset - > MaterialLayers ( ) - > begin ( ) ) ;
if ( layer - > Material ( ) ) {
single_material = layer - > Material ( ) ;
}
}
2017-08-01 16:45:11 +02:00
}
}
2022-11-14 09:23:59 +01:00
return single_material ;
2017-10-06 15:36:51 +02:00
}
2021-07-11 15:00:59 +02:00
IfcGeom : : BRepElement * IfcGeom : : Kernel : : create_brep_for_representation_and_product (
2016-07-11 21:36:12 +03:00
const IteratorSettings & settings , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product )
{
2017-06-28 15:24:49 +02:00
std : : stringstream representation_id_builder ;
2017-12-11 15:07:40 +01:00
representation_id_builder < < representation - > data ( ) . id ( ) ;
2017-06-28 15:24:49 +02:00
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 ;
2022-11-14 09:23:59 +01:00
if ( util : : flatten_shape_list ( shapes , merge , false , getValue ( GV_PRECISION ) ) ) {
2022-11-13 11:04:16 +01:00
if ( util : : count ( merge , TopAbs_FACE ) > 0 ) {
2015-10-07 17:33:30 +02:00
std : : vector < double > thickness ;
std : : vector < Handle_Geom_Surface > layers ;
std : : vector < std : : vector < Handle_Geom_Surface > > folded_layers ;
2021-10-08 15:38:46 +02:00
std : : vector < std : : shared_ptr < const SurfaceStyle > > styles ;
2015-10-07 17:33:30 +02:00
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 ) {
2017-12-11 15:07:40 +01:00
unsigned layerset_id = associates_material - > RelatingMaterial ( ) - > data ( ) . id ( ) ;
2017-06-28 15:24:49 +02:00
representation_id_builder < < " -layerset- " < < layerset_id ;
break ;
}
}
2022-01-13 01:24:57 +01:00
2018-12-19 15:15:28 +01:00
if ( styles . size ( ) > 1 ) {
// If there's only a single layer there is no need to manipulate geometries.
bool success = true ;
if ( product - > as < IfcSchema : : IfcWall > ( ) & & fold_layers ( product - > as < IfcSchema : : IfcWall > ( ) , shapes , layers , thickness , folded_layers ) ) {
2022-11-14 09:23:59 +01:00
if ( util : : apply_folded_layerset ( shapes , folded_layers , styles , shapes2 , getValue ( GV_PRECISION ) ) ) {
2018-12-19 15:15:28 +01:00
std : : swap ( shapes , shapes2 ) ;
success = true ;
}
} else {
2022-11-14 09:23:59 +01:00
if ( util : : apply_layerset ( shapes , layers , styles , shapes2 , getValue ( GV_PRECISION ) ) ) {
2018-12-19 15:15:28 +01:00
std : : swap ( shapes , shapes2 ) ;
success = true ;
}
2015-10-07 17:33:30 +02:00
}
2018-12-19 15:15:28 +01:00
if ( ! success ) {
Logger : : Error ( " Failed processing layerset " ) ;
2015-10-07 17:33:30 +02:00
}
}
}
}
}
}
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 ) {
2021-10-08 15:38:46 +02:00
auto 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 ;
}
}
2018-12-19 16:54:02 +01:00
} else {
bool some_items_without_style = false ;
for ( IfcGeom : : IfcRepresentationShapeItems : : iterator it = shapes . begin ( ) ; it ! = shapes . end ( ) ; + + it ) {
2022-11-13 11:04:16 +01:00
if ( ! it - > hasStyle ( ) & & util : : count ( it - > Shape ( ) , TopAbs_FACE ) ) {
2018-12-19 16:54:02 +01:00
some_items_without_style = true ;
break ;
}
}
if ( some_items_without_style ) {
2018-12-21 11:53:36 +01:00
Logger : : Warning ( " No material and surface styles for: " , product ) ;
2018-12-19 16:54:02 +01:00
}
2018-03-28 17:33:46 +03:00
}
2017-10-06 15:36:51 +02:00
if ( material_style_applied ) {
2017-12-11 15:07:40 +01:00
representation_id_builder < < " -material- " < < single_material - > data ( ) . id ( ) ;
2017-10-06 15:36:51 +02:00
}
2020-09-27 11:51:00 +02:00
if ( settings . force_space_transparency ( ) > = 0. & & product - > declaration ( ) . is ( " IfcSpace " ) ) {
for ( auto & s : shapes ) {
if ( s . hasStyle ( ) ) {
for ( auto & p : style_cache ) {
2021-10-08 15:38:46 +02:00
if ( p . second = = s . StylePtr ( ) ) {
std : : const_pointer_cast < IfcGeom : : SurfaceStyle > ( p . second ) - > Transparency ( ) = settings . force_space_transparency ( ) ;
2020-09-27 11:51:00 +02:00
}
}
}
}
}
2015-01-05 14:11:42 +00:00
int parent_id = - 1 ;
try {
2019-01-11 16:22:53 +01:00
IfcUtil : : IfcBaseEntity * parent_object = get_decomposing_entity ( product ) ;
if ( parent_object & & parent_object - > as < IfcSchema : : IfcObjectDefinition > ( ) ) {
2017-12-11 15:07:40 +01:00
parent_id = parent_object - > data ( ) . id ( ) ;
2015-01-05 14:11:42 +00:00
}
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
2022-01-13 01:24:57 +01:00
2021-07-29 14:54:51 +02:00
const std : : string name = product - > Name ( ) . get_value_or ( " " ) ;
2015-01-05 14:11:42 +00:00
const std : : string guid = product - > GlobalId ( ) ;
2022-01-13 01:24:57 +01:00
2015-01-05 14:11:42 +00:00
gp_Trsf trsf ;
try {
2021-09-26 11:25:36 +02:00
if ( product - > ObjectPlacement ( ) ) {
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
2017-12-18 15:25:09 +01:00
const std : : string product_type = product - > declaration ( ) . name ( ) ;
2015-01-05 14:11:42 +00:00
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 ) {
2017-12-11 15:07:40 +01:00
representation_id_builder < < " - " < < ( * it ) - > data ( ) . id ( ) ;
2017-06-28 15:24:49 +02:00
}
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 {
2022-11-13 11:04:16 +01:00
convert_openings ( product , openings , shapes , trsf , opened_shapes ) ;
2018-09-12 16:44:30 +02:00
} catch ( const std : : exception & e ) {
2018-09-17 17:46:13 +02:00
Logger : : Message ( Logger : : LOG_ERROR , std : : string ( " Error processing openings for: " ) + e . what ( ) + " : " , product ) ;
2018-09-17 14:11:03 +02:00
caught_error = true ;
2022-01-13 01:24:57 +01:00
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Error processing openings for: " , product ) ;
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 = " " ;
2021-07-29 14:54:51 +02:00
if ( representation - > RepresentationIdentifier ( ) ) {
context_string = * representation - > RepresentationIdentifier ( ) ;
} else if ( representation - > ContextOfItems ( ) - > ContextType ( ) ) {
context_string = * representation - > ContextOfItems ( ) - > ContextType ( ) ;
2015-04-22 09:15:48 +00:00
}
2021-07-11 15:00:59 +02:00
auto elem = new BRepElement (
2017-12-11 15:07:40 +01:00
product - > data ( ) . id ( ) ,
2015-01-05 14:11:42 +00:00
parent_id ,
2018-12-12 12:33:09 +01:00
name ,
2015-01-05 14:11:42 +00:00
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 ) ,
2018-12-12 12:33:09 +01:00
product
2016-03-18 11:23:25 +01:00
) ;
2018-12-12 12:33:09 +01:00
if ( settings . get ( IteratorSettings : : VALIDATE_QUANTITIES ) ) {
auto rels = product - > IsDefinedBy ( ) ;
for ( auto & rel : * rels ) {
if ( rel - > as < IfcSchema : : IfcRelDefinesByProperties > ( ) ) {
auto pdef = rel - > as < IfcSchema : : IfcRelDefinesByProperties > ( ) - > RelatingPropertyDefinition ( ) ;
if ( pdef - > as < IfcSchema : : IfcElementQuantity > ( ) ) {
2018-12-30 12:55:17 +01:00
std : : string organization_name ;
try {
// A couple of files are not according to the schema here.
organization_name = pdef - > as < IfcSchema : : IfcElementQuantity > ( ) - > OwnerHistory ( ) - > OwningApplication ( ) - > ApplicationDeveloper ( ) - > Name ( ) ;
} catch ( . . . ) { }
if ( organization_name = = " IfcOpenShell " ) {
2018-12-12 12:33:09 +01:00
auto qs = pdef - > as < IfcSchema : : IfcElementQuantity > ( ) - > Quantities ( ) ;
for ( auto & q : * qs ) {
if ( q - > as < IfcSchema : : IfcQuantityArea > ( ) & & q - > Name ( ) = = " Total Surface Area " ) {
double a_calc ;
double a_file = q - > as < IfcSchema : : IfcQuantityArea > ( ) - > AreaValue ( ) ;
if ( elem - > geometry ( ) . calculate_surface_area ( a_calc ) ) {
double diff = std : : abs ( a_calc - a_file ) ;
if ( diff / std : : sqrt ( a_file ) > getValue ( GV_PRECISION ) ) {
Logger : : Error ( " Validation of surface area failed for: " , product ) ;
} else {
Logger : : Notice ( " Validation of surface area succeeded for: " , product ) ;
}
} else {
Logger : : Error ( " Validation of surface area failed for: " , product ) ;
}
} else if ( q - > as < IfcSchema : : IfcQuantityVolume > ( ) & & q - > Name ( ) = = " Volume " ) {
double v_calc ;
double v_file = q - > as < IfcSchema : : IfcQuantityVolume > ( ) - > VolumeValue ( ) ;
if ( elem - > geometry ( ) . calculate_volume ( v_calc ) ) {
double diff = std : : abs ( v_calc - v_file ) ;
if ( diff / std : : sqrt ( v_file ) > getValue ( GV_PRECISION ) ) {
Logger : : Error ( " Validation of volume failed for: " , product ) ;
} else {
Logger : : Notice ( " Validation of volume succeeded for: " , product ) ;
}
} else {
Logger : : Error ( " Validation of volume failed for: " , product ) ;
}
} else if ( q - > as < IfcSchema : : IfcPhysicalComplexQuantity > ( ) & & q - > Name ( ) = = " Shape Validation Properties " ) {
auto qs2 = q - > as < IfcSchema : : IfcPhysicalComplexQuantity > ( ) - > HasQuantities ( ) ;
bool all_succeeded = qs2 - > size ( ) > 0 ;
for ( auto & q2 : * qs2 ) {
2021-07-29 14:54:51 +02:00
if ( q2 - > as < IfcSchema : : IfcQuantityCount > ( ) & & q2 - > Name ( ) = = " Surface Genus " & & q2 - > Description ( ) ) {
int item_id = boost : : lexical_cast < int > ( ( * q2 - > Description ( ) ) . substr ( 1 ) ) ;
int genus = ( int ) q2 - > as < IfcSchema : : IfcQuantityCount > ( ) - > CountValue ( ) ;
2018-12-12 12:33:09 +01:00
for ( auto & part : elem - > geometry ( ) ) {
if ( part . ItemId ( ) = = item_id ) {
2022-11-13 11:04:16 +01:00
if ( util : : surface_genus ( part . Shape ( ) ) ! = genus ) {
2018-12-12 12:33:09 +01:00
all_succeeded = false ;
}
}
}
}
}
if ( ! all_succeeded ) {
Logger : : Error ( " Validation of surface genus failed for: " , product ) ;
} else {
Logger : : Notice ( " Validation of surface genus succeeded for: " , product ) ;
}
}
}
}
}
}
}
}
return elem ;
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 ;
2020-05-20 11:55:59 +02:00
try {
IfcSchema : : IfcRepresentationItem : : list : : ptr items = representation - > Items ( ) ;
if ( items - > size ( ) = = 1 ) {
IfcSchema : : IfcRepresentationItem * item = * items - > begin ( ) ;
if ( item - > declaration ( ) . is ( IfcSchema : : IfcMappedItem : : Class ( ) ) ) {
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 ( ) ;
}
2017-10-06 15:36:51 +02:00
}
}
}
}
2020-05-20 11:55:59 +02:00
} catch ( const IfcParse : : IfcException & e ) {
Logger : : Error ( e ) ;
// @todo reset representation_mapped_to to zero?
2017-10-06 15:36:51 +02:00
}
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
2022-01-13 01:24:57 +01:00
// IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
2017-10-06 15:36:51 +02:00
// 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
2017-12-18 15:25:09 +01:00
products - > push ( ( * it ) - > data ( ) . getInverse ( ( & IfcSchema : : IfcProduct : : Class ( ) ) , - 1 ) - > as < IfcSchema : : IfcProduct > ( ) ) ;
2017-10-06 15:36:51 +02:00
}
2022-01-13 01:24:57 +01:00
2017-10-06 15:36:51 +02:00
IfcSchema : : IfcRepresentationMap : : list : : ptr maps = representation - > RepresentationMap ( ) ;
2019-11-17 14:07:32 +01:00
if ( products - > size ( ) & & maps - > size ( ) ) {
Logger : : Warning ( " Representation used by IfcRepresentationMap and IfcProductDefinitionShape " , representation ) ;
}
2019-11-18 12:59:48 +01:00
if ( prodreps - > size ( ) > 1 ) {
Logger : : Warning ( " Multiple IfcProductDefinitionShapes for representation " , representation ) ;
}
if ( maps - > size ( ) > 1 ) {
Logger : : Warning ( " Multiple IfcRepresentationMaps for representation " , representation ) ;
}
2017-10-06 15:36:51 +02:00
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 ;
}
2017-12-18 15:25:09 +01:00
IfcSchema : : IfcRepresentation : : list : : ptr reps = item - > data ( ) . getInverse ( ( & IfcSchema : : IfcRepresentation : : Class ( ) ) , - 1 ) - > as < IfcSchema : : IfcRepresentation > ( ) ;
2017-10-06 15:36:51 +02:00
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 ) {
2017-12-18 15:25:09 +01:00
IfcSchema : : IfcProduct : : list : : ptr ps = ( * kt ) - > data ( ) . getInverse ( ( & IfcSchema : : IfcProduct : : Class ( ) ) , - 1 ) - > as < IfcSchema : : IfcProduct > ( ) ;
2017-10-06 15:36:51 +02:00
products - > push ( ps ) ;
}
}
}
}
}
return products ;
}
2021-07-11 15:00:59 +02:00
IfcGeom : : BRepElement * IfcGeom : : Kernel : : create_brep_for_processed_representation (
2016-07-11 21:36:12 +03:00
const IteratorSettings & /*settings*/ , IfcSchema : : IfcRepresentation * representation , IfcSchema : : IfcProduct * product ,
2021-07-11 15:00:59 +02:00
IfcGeom : : BRepElement * brep )
2016-07-11 21:36:12 +03:00
{
2016-03-18 11:23:25 +01:00
int parent_id = - 1 ;
try {
2019-01-11 16:22:53 +01:00
IfcUtil : : IfcBaseEntity * parent_object = get_decomposing_entity ( product ) ;
if ( parent_object & & parent_object - > as < IfcSchema : : IfcObjectDefinition > ( ) ) {
2017-12-11 15:07:40 +01:00
parent_id = parent_object - > data ( ) . id ( ) ;
2016-03-18 11:23:25 +01:00
}
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
2022-01-13 01:24:57 +01:00
2021-07-29 14:54:51 +02:00
const std : : string name = product - > Name ( ) . get_value_or ( " " ) ;
2016-03-18 11:23:25 +01:00
const std : : string guid = product - > GlobalId ( ) ;
2022-01-13 01:24:57 +01:00
2016-03-18 11:23:25 +01:00
gp_Trsf trsf ;
try {
2021-09-26 11:25:36 +02:00
if ( product - > ObjectPlacement ( ) ) {
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 = " " ;
2021-07-29 14:54:51 +02:00
if ( representation - > RepresentationIdentifier ( ) ) {
context_string = * representation - > RepresentationIdentifier ( ) ;
} else if ( representation - > ContextOfItems ( ) - > ContextType ( ) ) {
context_string = * representation - > ContextOfItems ( ) - > ContextType ( ) ;
2016-03-18 11:23:25 +01:00
}
2017-12-18 15:25:09 +01:00
const std : : string product_type = product - > declaration ( ) . name ( ) ;
2016-03-18 11:23:25 +01:00
2021-07-11 15:00:59 +02:00
return new BRepElement (
2017-12-11 15:07:40 +01:00
product - > data ( ) . id ( ) ,
2016-03-18 11:23:25 +01:00
parent_id ,
2022-01-13 01:24:57 +01:00
name ,
2016-03-18 11:23:25 +01:00
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
) ;
}
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 {
2021-07-29 14:54:51 +02:00
aggregate_of_instance : : ptr units = unit_assignment - > Units ( ) ;
2015-01-10 22:13:52 +00:00
if ( ! units | | ! units - > size ( ) ) {
2018-12-29 12:34:32 +01:00
Logger : : Warning ( " No unit information found " ) ;
2015-01-05 14:11:42 +00:00
} else {
2021-07-29 14:54:51 +02:00
for ( aggregate_of_instance : : it it = units - > begin ( ) ; it ! = units - > end ( ) ; + + it ) {
2015-01-05 14:11:42 +00:00
IfcUtil : : IfcBaseClass * base = * it ;
2017-12-18 15:25:09 +01:00
if ( base - > declaration ( ) . is ( IfcSchema : : IfcNamedUnit : : Class ( ) ) ) {
2016-05-24 13:50:50 +02:00
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 ;
2017-12-18 15:25:09 +01:00
const double current_unit_magnitude = IfcParse : : get_SI_equivalent < IfcSchema > ( named_unit ) ;
2016-05-24 13:50:50 +02:00
if ( current_unit_magnitude ! = 0. ) {
2017-12-18 15:25:09 +01:00
if ( named_unit - > declaration ( ) . is ( IfcSchema : : IfcConversionBasedUnit : : Class ( ) ) ) {
2016-05-24 13:50:50 +02:00
IfcSchema : : IfcConversionBasedUnit * u = ( IfcSchema : : IfcConversionBasedUnit * ) base ;
current_unit_name = u - > Name ( ) ;
2017-12-18 15:25:09 +01:00
} else if ( named_unit - > declaration ( ) . is ( IfcSchema : : IfcSIUnit : : Class ( ) ) ) {
2016-05-24 13:50:50 +02:00
IfcSchema : : IfcSIUnit * si_unit = named_unit - > as < IfcSchema : : IfcSIUnit > ( ) ;
2021-07-29 14:54:51 +02:00
if ( si_unit - > Prefix ( ) ) {
current_unit_name = IfcSchema : : IfcSIPrefix : : ToString ( * si_unit - > Prefix ( ) ) + unit_name ;
2016-05-24 13:50:50 +02:00
}
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 ) {
2018-12-29 12:34:32 +01:00
Logger : : Warning ( " No length unit encountered " ) ;
2018-09-07 14:25:46 +02:00
}
if ( ! angle_unit_encountered ) {
2018-12-29 12:34:32 +01:00
Logger : : Warning ( " No plane angle unit encountered " ) ;
2018-09-07 14:25:46 +02:00
}
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
}
2021-10-08 15:38:46 +02:00
bool IfcGeom : : Kernel : : convert_layerset ( const IfcSchema : : IfcProduct * product , std : : vector < Handle_Geom_Surface > & surfaces , std : : vector < std : : shared_ptr < const SurfaceStyle > > & styles , std : : vector < double > & thicknesses ) {
2015-10-07 17:33:30 +02:00
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 " ) ;
2018-11-20 12:10:44 +01:00
if ( ! body_representation ) {
2018-11-28 14:18:58 +01:00
Logger : : Warning ( " No body representation for product " , product ) ;
2018-11-20 12:10:44 +01:00
return false ;
}
2015-10-07 17:33:30 +02:00
2017-12-18 15:25:09 +01:00
if ( product - > declaration ( ) . is ( IfcSchema : : IfcWall : : Class ( ) ) ) {
2018-11-20 12:10:44 +01:00
IfcSchema : : IfcRepresentation * axis_representation = find_representation ( product , " Axis " ) ;
2015-10-07 17:33:30 +02:00
if ( ! axis_representation ) {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_WARNING , " No axis representation for: " , product ) ;
2015-10-07 17:33:30 +02:00
return false ;
}
IfcRepresentationShapeItems axis_items ;
{
Kernel temp = * this ;
temp . setValue ( GV_DIMENSIONALITY , - 1. ) ;
temp . convert_shapes ( axis_representation , axis_items ) ;
}
TopoDS_Shape axis_shape ;
2022-11-14 09:23:59 +01:00
util : : flatten_shape_list ( axis_items , axis_shape , false , getValue ( GV_PRECISION ) ) ;
2015-10-07 17:33:30 +02:00
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 {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_WARNING , " No edge found in axis representation: " , product ) ;
2015-10-07 17:33:30 +02:00
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 ) ;
2018-12-21 14:40:58 +01:00
// @todo note that this creates an offset into the wrong order, the cross product arguments should be
// reversed. This causes some inversions later on, e.g. if(positive) { reverse(); }
2015-10-07 17:33:30 +02:00
reference_surface = new Geom_Plane ( axis_line - > Lin ( ) . Location ( ) , axis_line - > Lin ( ) . Direction ( ) ^ gp : : DZ ( ) ) ;
} else if ( axis_curve - > DynamicType ( ) = = STANDARD_TYPE ( Geom_Circle ) ) {
2018-12-21 14:40:58 +01:00
// @todo note that in this branch this inversion does not seem to take place.
2015-10-07 17:33:30 +02:00
Handle_Geom_Circle axis_line = Handle_Geom_Circle : : DownCast ( axis_curve ) ;
reference_surface = new Geom_CylindricalSurface ( axis_line - > Position ( ) , axis_line - > Radius ( ) ) ;
} else {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Unsupported underlying curve of Axis representation: " , product ) ;
2015-10-07 17:33:30 +02:00
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 ( ) ) ;
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
} else {
2017-12-11 15:07:40 +01:00
IfcSchema : : IfcExtrudedAreaSolid : : list : : ptr extrusions = IfcParse : : traverse ( body_representation ) - > as < IfcSchema : : IfcExtrudedAreaSolid > ( ) ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
if ( extrusions - > size ( ) ! = 1 ) {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_WARNING , " No single extrusion found in body representation for: " , product ) ;
2015-10-07 17:33:30 +02:00
return false ;
}
IfcSchema : : IfcExtrudedAreaSolid * extrusion = * extrusions - > begin ( ) ;
gp_Trsf extrusion_position ;
2017-08-09 17:01:10 +02:00
bool has_position = true ;
2019-06-26 13:50:46 +02:00
# ifdef SCHEMA_IfcSweptAreaSolid_Position_IS_OPTIONAL
2021-08-07 10:44:29 +02:00
has_position = extrusion - > Position ( ) ! = nullptr ;
2017-08-09 17:01:10 +02:00
# endif
if ( has_position ) {
if ( ! convert ( extrusion - > Position ( ) , extrusion_position ) ) {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Failed to convert placement for extrusion of: " , product ) ;
2017-08-09 17:01:10 +02:00
return false ;
}
2015-10-07 17:33:30 +02:00
}
gp_Dir extrusion_direction ;
if ( ! convert ( extrusion - > ExtrudedDirection ( ) , extrusion_direction ) ) {
2017-12-11 15:07:40 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Failed to convert direction for extrusion of: " , product ) ;
2015-10-07 17:33:30 +02:00
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 ) ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
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 ) {
2019-06-06 09:09:36 +03:00
std : : reverse ( thicknesses . begin ( ) , thicknesses . end ( ) ) ;
2019-05-24 14:57:29 +03:00
std : : reverse ( styles . begin ( ) , styles . end ( ) ) ;
2015-10-07 17:33:30 +02:00
std : : reverse ( surfaces . begin ( ) , surfaces . end ( ) ) ;
}
return true ;
}
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 ;
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
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 ;
2022-01-13 01:24:57 +01:00
}
2015-10-07 17:33:30 +02:00
}
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
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 ) {
2019-08-16 10:42:48 +02:00
/*
* @todo isn't it easier to do this based on the non-folded surfaces of
* the connected walls and fold both pairs of layersets simultaneously?
*/
2015-10-07 17:33:30 +02:00
bool folds_made = false ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
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 ;
2017-12-18 15:25:09 +01:00
typedef std : : vector < std : : pair < std : : pair < IfcSchema : : IfcConnectionTypeEnum : : Value , IfcSchema : : IfcConnectionTypeEnum : : Value > , const IfcSchema : : IfcProduct * > > endpoint_connections_t ;
2015-10-07 17:33:30 +02:00
typedef std : : vector < std : : vector < Handle_Geom_Surface > > result_t ;
endpoint_connections_t endpoint_connections ;
2019-08-16 10:42:48 +02:00
// Find the semantic connections ot other wall elements when they are not connected 'AT_PATH' because
// in that latter case no folds need to be made.
2015-10-07 17:33:30 +02:00
for ( IfcSchema : : IfcRelConnectsPathElements : : list : : it it = connections - > begin ( ) ; it ! = connections - > end ( ) ; + + it ) {
IfcSchema : : IfcRelConnectsPathElements * connection = * it ;
2017-12-18 15:25:09 +01:00
IfcSchema : : IfcConnectionTypeEnum : : Value own_type = connection - > RelatedElement ( ) = = wall
2015-10-07 17:33:30 +02:00
? connection - > RelatedConnectionType ( )
: connection - > RelatingConnectionType ( ) ;
2017-12-18 15:25:09 +01:00
IfcSchema : : IfcConnectionTypeEnum : : Value other_type = connection - > RelatedElement ( ) = = wall
2015-10-07 17:33:30 +02:00
? connection - > RelatingConnectionType ( )
: connection - > RelatedConnectionType ( ) ;
2022-01-13 01:24:57 +01:00
if ( other_type ! = IfcSchema : : IfcConnectionTypeEnum : : IfcConnectionType_ATPATH & &
2015-10-07 17:33:30 +02:00
( 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 ;
}
2022-01-13 01:24:57 +01:00
2019-08-16 10:42:48 +02:00
// Count how many connections are made AT_START and AT_END respectively
2015-10-07 17:33:30 +02:00
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 ;
2021-09-26 11:25:36 +02:00
if ( wall - > ObjectPlacement ( ) ) {
if ( ! convert ( wall - > ObjectPlacement ( ) , local ) ) {
return false ;
}
2015-10-07 17:33:30 +02:00
}
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 ) ;
}
}
2021-03-13 10:05:33 +01:00
const double total_thickness = std : : accumulate ( thicknesses . begin ( ) , thicknesses . end ( ) , 0. ) ;
2015-10-07 17:33:30 +02:00
gp_Pnt own_axis_start , own_axis_end ;
find_wall_end_points ( wall , own_axis_start , own_axis_end ) ;
2019-08-16 10:42:48 +02:00
// Sometimes duplicate IfcRelConnectsPathElements exist. These are detected
// and the counts of connections are decremented accordingly.
2015-10-07 17:33:30 +02:00
for ( int idx = 0 ; idx < 2 ; + + idx ) {
if ( connection_type_count [ idx ] < = 1 ) {
continue ;
}
2019-08-21 11:59:30 +02:00
2016-05-02 15:56:08 +02:00
/*
2017-12-18 15:25:09 +01:00
IfcSchema::IfcConnectionTypeEnum::Value connection_type = idx == 1
2015-10-07 17:33:30 +02:00
? 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 ) ;
2019-08-21 11:59:30 +02:00
- - connection_type_count [ idx ] ;
2015-10-07 17:33:30 +02:00
} else {
others . insert ( other ) ;
+ + it ;
}
}
2019-08-21 11:59:30 +02:00
}
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
// 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::Value own_type = it->first.first;
IfcSchema::IfcConnectionTypeEnum::Value other_type = it->first.second;
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
gp_Pnt other_axis_start, other_axis_end;
find_wall_end_points(it->second->as<IfcSchema::IfcWall>(), other_axis_start, other_axis_end);
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
gp_Trsf other;
if (!convert(it->second->ObjectPlacement(), other)) {
continue;
}
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
other.Transforms(other_axis_start.ChangeCoord());
local.Transforms(other_axis_start.ChangeCoord());
other.Transforms(other_axis_end.ChangeCoord());
local.Transforms(other_axis_end.ChangeCoord());
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
const gp_Pnt& a = own_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
? own_axis_start
: own_axis_end;
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
const gp_Pnt& b = other_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
? other_axis_start
: other_axis_end;
2015-10-07 17:33:30 +02:00
2019-08-21 11:59:30 +02:00
const double d = a.Distance(b);
2015-10-07 17:33:30 +02:00
}
2019-08-21 11:59:30 +02:00
*/
2015-10-07 17:33:30 +02:00
2021-03-13 10:05:33 +01:00
const double length_required = endpoint_connections . size ( ) * total_thickness ;
// @todo this is not precisely the distance in case of curved walls. Also, it's safer
// to first reproject the body onto the axis to get the precise curve parametrization
// range. It's only a safeguard though, so can probably be approximated.
const double axis_length = own_axis_start . Distance ( own_axis_end ) ;
if ( length_required > axis_length ) {
Logger : : Warning ( " The wall axis is not long enough to accomodate the fold points " ) ;
return false ;
}
2015-10-07 17:33:30 +02:00
for ( endpoint_connections_t : : const_iterator it = endpoint_connections . begin ( ) ; it ! = endpoint_connections . end ( ) ; + + it ) {
2017-12-18 15:25:09 +01:00
IfcSchema : : IfcConnectionTypeEnum : : Value connection_type = it - > first . first ;
2015-10-07 17:33:30 +02:00
// 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 ;
2019-08-16 10:42:48 +02:00
// Pick the corresponding point from the axis
2015-10-07 17:33:30 +02:00
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 ;
2021-09-26 11:25:36 +02:00
if ( other_wall - > ObjectPlacement ( ) ) {
if ( ! convert ( other_wall - > ObjectPlacement ( ) , other ) ) {
Logger : : Error ( " Failed to convert placement " , other_wall ) ;
continue ;
}
2015-10-07 17:33:30 +02:00
}
IfcSchema : : IfcRepresentation * axis_representation = find_representation ( other_wall , " Axis " ) ;
2018-11-20 12:10:44 +01:00
if ( ! axis_representation ) {
2018-11-28 14:18:58 +01:00
Logger : : Warning ( " Joined wall has no axis representation " , other_wall ) ;
2018-11-20 12:10:44 +01:00
continue ;
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
IfcRepresentationShapeItems axis_items ;
{
Kernel temp = * this ;
temp . setValue ( GV_DIMENSIONALITY , - 1. ) ;
temp . convert_shapes ( axis_representation , axis_items ) ;
}
TopoDS_Shape axis_shape ;
2022-11-14 09:23:59 +01:00
util : : flatten_shape_list ( axis_items , axis_shape , false , getValue ( GV_PRECISION ) ) ;
2022-01-13 01:24:57 +01:00
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 ) ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
TopoDS_Shape body_shape ;
2022-11-14 09:23:59 +01:00
util : : flatten_shape_list ( items , body_shape , false , getValue ( GV_PRECISION ) ) ;
2015-10-07 17:33:30 +02:00
2019-08-16 10:42:48 +02:00
// Create a single paremetric range over a single curve
// that represents the entire 1d domain of the other wall
// Sometimes there are multiple edges in the Axis shape
// but it is assumed these are colinear.
Handle_Geom_Curve other_axis_curve ;
2015-10-07 17:33:30 +02:00
double axis_u1 , axis_u2 ;
2022-01-13 01:24:57 +01:00
{
2015-10-07 17:33:30 +02:00
TopExp_Explorer exp ( axis_shape , TopAbs_EDGE ) ;
if ( ! exp . More ( ) ) {
return false ;
}
TopoDS_Edge axis_edge = TopoDS : : Edge ( exp . Current ( ) ) ;
2019-08-16 10:42:48 +02:00
other_axis_curve = BRep_Tool : : Curve ( axis_edge , axis_u1 , axis_u2 ) ;
2015-10-07 17:33:30 +02:00
gp_Pnt other_a_1 , other_a_2 ;
2019-08-16 10:42:48 +02:00
other_axis_curve - > D0 ( axis_u1 , other_a_1 ) ;
other_axis_curve - > D0 ( axis_u2 , other_a_2 ) ;
2015-10-07 17:33:30 +02:00
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 ;
2022-11-14 09:23:59 +01:00
if ( util : : project ( other_axis_curve , p , pp , u , d ) ) {
2015-10-07 17:33:30 +02:00
if ( u < axis_u1 ) axis_u1 = u ;
if ( u > axis_u2 ) axis_u2 = u ;
}
2022-01-13 01:24:57 +01:00
}
2015-10-07 17:33:30 +02:00
}
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
double layer_offset = 0 ;
2019-08-21 11:59:30 +02:00
2015-10-07 17:33:30 +02:00
std : : vector < double > : : const_iterator thickness = thicknesses . begin ( ) ;
result_t : : iterator result_vector = result . begin ( ) + 1 ;
2019-08-16 10:42:48 +02:00
// nb The first layer is never folded, because it corresponds
// to one of the longitudonal faces of the wall. Hence the +1
2015-10-07 17:33:30 +02:00
for ( surfaces_t : : const_iterator jt = surfaces . begin ( ) + 1 ; jt ! = surfaces . end ( ) - 1 ; + + jt , + + result_vector ) {
layer_offset + = * thickness + + ;
2020-11-25 11:02:57 +01:00
bool found_intersection = false , parallel = false ;
2015-10-07 17:33:30 +02:00
boost : : optional < gp_Pnt > point_outside_param_range ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
const Handle_Geom_Surface & surface = * jt ;
2019-08-16 10:42:48 +02:00
// Find the intersection point between the layerset surface
// and the other axis curve. If it's within the parametric
// range of the other wall it means the walls are connected
// with an angle.
GeomAPI_IntCS intersections ( other_axis_curve , surface ) ;
2015-10-07 17:33:30 +02:00
if ( intersections . IsDone ( ) & & intersections . NbPoints ( ) = = 1 ) {
const gp_Pnt & p = intersections . Point ( 1 ) ;
2020-11-25 11:02:57 +01:00
2015-10-07 17:33:30 +02:00
double u , v , w ;
intersections . Parameters ( 1 , u , v , w ) ;
2020-11-25 11:02:57 +01:00
gp_Pnt Pc , Ps ;
gp_Vec Vc , Vs1 , Vs2 ;
other_axis_curve - > D1 ( w , Pc , Vc ) ;
surface - > D1 ( u , v , Ps , Vs1 , Vs2 ) ;
Vs1 . Cross ( Vs2 ) ;
2021-03-13 10:05:33 +01:00
if ( Vs1 . IsNormal ( Vc , 1.e-5 ) ) {
2020-11-25 11:02:57 +01:00
Logger : : Warning ( " Connected walls are parallel " ) ;
parallel = true ;
} else if ( w < axis_u1 | | w > axis_u2 ) {
2015-10-07 17:33:30 +02:00
point_outside_param_range = p ;
} else {
// Found an intersection. Layer end point is covered by connecting wall
found_intersection = true ;
break ;
}
}
2020-11-25 11:02:57 +01:00
if ( ! parallel & & ! found_intersection & & point_outside_param_range ) {
2015-10-07 17:33:30 +02:00
/*
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);
*/
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
Handle_Geom_Surface plane = new Geom_Plane ( * point_outside_param_range , gp : : DZ ( ) ) ;
2019-08-16 10:42:48 +02:00
// vertical edges at wall end point face.
2015-10-07 17:33:30 +02:00
curves_on_surfaces_t layer_ends ;
2022-11-14 09:23:59 +01:00
util : : intersect ( surface , body_shape , layer_ends ) ;
2015-10-07 17:33:30 +02:00
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 ;
}
2019-08-16 10:42:48 +02:00
// Find vertical wall end point edge closest to end point associated with semantic connection
2022-11-14 09:23:59 +01:00
if ( util : : project ( kt - > second , own_end_point , p , u , d ) ) {
2019-08-21 11:59:30 +02:00
// In addition to closest, there is a length threshold based on thickness.
// @todo ideally, first, the point closest to end-point is selected, and
// after that the parallel check is performed. But threshold probably
// functions good enough.
if ( d < total_thickness * 3 & & d < mind ) {
2019-08-16 10:42:48 +02:00
GeomAdaptor_Curve GAC ( other_axis_curve ) ;
GeomAdaptor_Surface GAS ( kt - > first ) ;
Extrema_ExtCS x ( GAC , GAS , getValue ( GV_PRECISION ) , getValue ( GV_PRECISION ) ) ;
if ( x . IsParallel ( ) ) {
body_surface = kt - > first ;
layer_body_intersection = kt - > second ;
mind = d ;
}
2015-10-07 17:33:30 +02:00
}
}
}
2019-08-16 10:42:48 +02:00
if ( body_surface . IsNull ( ) ) {
continue ;
}
// Intersect vertical edge with ground plane for point.
2015-10-07 17:33:30 +02:00
GeomAPI_IntCS intersection2 ( layer_body_intersection , plane ) ;
if ( intersection2 . IsDone ( ) & & intersection2 . NbPoints ( ) = = 1 ) {
const gp_Pnt & layer_end_point = intersection2 . Point ( 1 ) ;
2019-08-16 10:42:48 +02:00
// Intersect layerset surface with ground plane
2015-10-07 17:33:30 +02:00
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 ) ;
2019-08-16 10:42:48 +02:00
// Move point inwards by distance from other layerset
2015-10-07 17:33:30 +02:00
GCPnts_AbscissaPoint dst ( layer_line_adaptor , layer_offset , layer_end_point_param ) ;
if ( dst . IsDone ( ) ) {
2019-08-16 10:42:48 +02:00
// Convert parameter to point
2015-10-07 17:33:30 +02:00
gp_Pnt layer_fold_point ;
layer_line - > D0 ( dst . Parameter ( ) , layer_fold_point ) ;
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
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 ;
}
}
}
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
}
2022-01-13 01:24:57 +01:00
2015-10-07 17:33:30 +02:00
}
}
return folds_made ;
}
IfcSchema : : IfcRepresentation * IfcGeom : : Kernel : : find_representation ( const IfcSchema : : IfcProduct * product , const std : : string & identifier ) {
2021-07-29 14:54:51 +02:00
if ( ! product - > Representation ( ) ) return 0 ;
2015-10-07 17:33:30 +02:00
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 ) {
2021-07-29 14:54:51 +02:00
if ( ( * * it ) . RepresentationIdentifier ( ) & & ( * ( * * it ) . RepresentationIdentifier ( ) ) = = identifier ) {
2015-10-07 17:33:30 +02:00
return * it ;
}
}
return 0 ;
}
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 ;
}
2020-01-15 11:50:44 +01:00
while ( item - > declaration ( ) . is ( IfcSchema : : IfcBooleanResult : : Class ( ) ) ) {
2016-01-22 17:27:28 +01:00
// All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
// IfcGeometricRepresentationItem
2021-09-13 13:19:56 +02:00
item = item - > as < IfcSchema : : IfcBooleanResult > ( ) - > FirstOperand ( ) - > as < IfcSchema : : IfcRepresentationItem > ( ) ;
if ( item & & 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
2021-09-06 18:52:37 +02:00
bool IfcGeom : : Kernel : : is_identity_transform ( IfcUtil : : IfcBaseInterface * l ) {
2016-03-18 11:23:25 +01:00
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 " ) ;
}
}
2022-06-14 15:02:54 +02:00
void IfcGeom : : Kernel : : set_conversion_placement_rel_to_type ( const IfcParse : : declaration * type ) {
placement_rel_to_type_ = type ;
}
void IfcGeom : : Kernel : : set_conversion_placement_rel_to_instance ( const IfcUtil : : IfcBaseEntity * instance ) {
placement_rel_to_instance_ = instance ;
}
2022-06-15 13:41:13 +02:00
namespace {
bool process_colour ( IfcSchema : : IfcColourRgb * colour , double * rgb ) {
if ( colour ! = 0 ) {
rgb [ 0 ] = colour - > Red ( ) ;
rgb [ 1 ] = colour - > Green ( ) ;
rgb [ 2 ] = colour - > Blue ( ) ;
}
return colour ! = 0 ;
}
bool process_colour ( IfcSchema : : IfcNormalisedRatioMeasure * factor , double * rgb ) {
if ( factor ! = 0 ) {
const double f = * factor ;
rgb [ 0 ] = rgb [ 1 ] = rgb [ 2 ] = f ;
}
return factor ! = 0 ;
}
bool process_colour ( IfcSchema : : IfcColourOrFactor * colour_or_factor , double * rgb ) {
if ( colour_or_factor = = 0 ) {
return false ;
} else if ( colour_or_factor - > declaration ( ) . is ( IfcSchema : : IfcColourRgb : : Class ( ) ) ) {
return process_colour ( static_cast < IfcSchema : : IfcColourRgb * > ( colour_or_factor ) , rgb ) ;
} else if ( colour_or_factor - > declaration ( ) . is ( IfcSchema : : IfcNormalisedRatioMeasure : : Class ( ) ) ) {
return process_colour ( static_cast < IfcSchema : : IfcNormalisedRatioMeasure * > ( colour_or_factor ) , rgb ) ;
} else {
return false ;
}
}
}
# define Kernel MAKE_TYPE_NAME(Kernel)
std : : shared_ptr < const IfcGeom : : SurfaceStyle > IfcGeom : : Kernel : : internalize_surface_style ( const std : : pair < IfcUtil : : IfcBaseClass * , IfcUtil : : IfcBaseClass * > & shading_styles ) {
if ( shading_styles . second = = 0 ) {
return 0 ;
}
int surface_style_id = shading_styles . first - > data ( ) . id ( ) ;
auto it = style_cache . find ( surface_style_id ) ;
if ( it ! = style_cache . end ( ) ) {
return it - > second ;
}
IfcSchema : : IfcSurfaceStyle * style = shading_styles . first - > as < IfcSchema : : IfcSurfaceStyle > ( ) ;
IfcSchema : : IfcSurfaceStyleShading * shading = shading_styles . second - > as < IfcSchema : : IfcSurfaceStyleShading > ( ) ;
std : : shared_ptr < SurfaceStyle > surface_style_ptr ;
if ( style - > Name ( ) ) {
surface_style_ptr . reset ( new SurfaceStyle ( surface_style_id , * style - > Name ( ) ) ) ;
} else {
surface_style_ptr . reset ( new SurfaceStyle ( surface_style_id ) ) ;
}
std : : shared_ptr < const SurfaceStyle > surface_style_ptr_const = std : : const_pointer_cast < const SurfaceStyle > ( surface_style_ptr ) ;
SurfaceStyle & surface_style = * surface_style_ptr ;
double rgb [ 3 ] ;
if ( process_colour ( shading - > SurfaceColour ( ) , rgb ) ) {
surface_style . Diffuse ( ) . reset ( SurfaceStyle : : ColorComponent ( rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] ) ) ;
}
if ( shading_styles . second - > declaration ( ) . is ( IfcSchema : : IfcSurfaceStyleRendering : : Class ( ) ) ) {
IfcSchema : : IfcSurfaceStyleRendering * rendering_style = static_cast < IfcSchema : : IfcSurfaceStyleRendering * > ( shading_styles . second ) ;
if ( rendering_style - > DiffuseColour ( ) & & process_colour ( rendering_style - > DiffuseColour ( ) , rgb ) ) {
SurfaceStyle : : ColorComponent diffuse = surface_style . Diffuse ( ) . get_value_or ( SurfaceStyle : : ColorComponent ( 1 , 1 , 1 ) ) ;
surface_style . Diffuse ( ) . reset ( SurfaceStyle : : ColorComponent ( diffuse . R ( ) * rgb [ 0 ] , diffuse . G ( ) * rgb [ 1 ] , diffuse . B ( ) * rgb [ 2 ] ) ) ;
}
if ( rendering_style - > DiffuseTransmissionColour ( ) ) {
// Not supported
}
if ( rendering_style - > ReflectionColour ( ) ) {
// Not supported
}
if ( rendering_style - > SpecularColour ( ) & & process_colour ( rendering_style - > SpecularColour ( ) , rgb ) ) {
surface_style . Specular ( ) . reset ( SurfaceStyle : : ColorComponent ( rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] ) ) ;
}
if ( rendering_style - > SpecularHighlight ( ) ) {
IfcSchema : : IfcSpecularHighlightSelect * highlight = rendering_style - > SpecularHighlight ( ) ;
if ( highlight - > declaration ( ) . is ( IfcSchema : : IfcSpecularRoughness : : Class ( ) ) ) {
double roughness = * ( ( IfcSchema : : IfcSpecularRoughness * ) highlight ) ;
if ( roughness > = 1e-9 ) {
surface_style . Specularity ( ) . reset ( 1.0 / roughness ) ;
}
} else if ( highlight - > declaration ( ) . is ( IfcSchema : : IfcSpecularExponent : : Class ( ) ) ) {
surface_style . Specularity ( ) . reset ( * ( ( IfcSchema : : IfcSpecularExponent * ) highlight ) ) ;
}
}
if ( rendering_style - > TransmissionColour ( ) ) {
// Not supported
}
if ( rendering_style - > Transparency ( ) ) {
const double d = * rendering_style - > Transparency ( ) ;
surface_style . Transparency ( ) . reset ( d ) ;
}
}
return style_cache [ surface_style_id ] = surface_style_ptr_const ;
}
std : : shared_ptr < const IfcGeom : : SurfaceStyle > IfcGeom : : Kernel : : get_style ( const IfcSchema : : IfcRepresentationItem * item ) {
return internalize_surface_style ( get_surface_style < IfcSchema : : IfcSurfaceStyleShading > ( item ) ) ;
}
std : : shared_ptr < const IfcGeom : : SurfaceStyle > IfcGeom : : Kernel : : get_style ( const IfcSchema : : IfcMaterial * material ) {
IfcSchema : : IfcMaterialDefinitionRepresentation : : list : : ptr defs = material - > HasRepresentation ( ) ;
for ( IfcSchema : : IfcMaterialDefinitionRepresentation : : list : : it jt = defs - > begin ( ) ; jt ! = defs - > end ( ) ; + + jt ) {
IfcSchema : : IfcRepresentation : : list : : ptr reps = ( * jt ) - > Representations ( ) ;
IfcSchema : : IfcStyledItem : : list : : ptr styles ( new IfcSchema : : IfcStyledItem : : list ) ;
for ( IfcSchema : : IfcRepresentation : : list : : it it = reps - > begin ( ) ; it ! = reps - > end ( ) ; + + it ) {
styles - > push ( ( * * it ) . Items ( ) - > as < IfcSchema : : IfcStyledItem > ( ) ) ;
}
for ( IfcSchema : : IfcStyledItem : : list : : it it = styles - > begin ( ) ; it ! = styles - > end ( ) ; + + it ) {
const std : : pair < IfcSchema : : IfcSurfaceStyle * , IfcSchema : : IfcSurfaceStyleShading * > ss = get_surface_style < IfcSchema : : IfcSurfaceStyleShading > ( * it ) ;
if ( ss . second ) {
return internalize_surface_style ( ss ) ;
}
}
}
auto material_style = std : : make_shared < IfcGeom : : SurfaceStyle > ( material - > data ( ) . id ( ) , material - > Name ( ) ) ;
return style_cache [ material - > data ( ) . id ( ) ] = material_style ;
}