2017-01-16 11:53:11 +01: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/>. *
* *
********************************************************************************/
# include "CgalKernel.h"
2019-01-18 15:19:00 +01:00
namespace {
struct MAKE_TYPE_NAME ( factory_t ) {
IfcGeom : : Kernel * operator ( ) ( IfcParse : : IfcFile * file ) const {
2019-01-18 16:43:38 +01:00
IfcGeom : : MAKE_TYPE_NAME ( CgalKernel ) * k = new IfcGeom : : MAKE_TYPE_NAME ( CgalKernel ) ;
2019-01-18 15:19:00 +01:00
return k ;
}
} ;
}
void MAKE_INIT_FN ( KernelImplementation_cgal_ ) ( IfcGeom : : impl : : KernelFactoryImplementation * mapping ) {
static const std : : string schema_name = STRINGIFY ( IfcSchema ) ;
MAKE_TYPE_NAME ( factory_t ) factory ;
mapping - > bind ( schema_name , " cgal " , factory ) ;
}
# define CgalKernel MAKE_TYPE_NAME(CgalKernel)
2019-01-20 13:16:42 +01:00
bool IfcGeom : : CgalKernel : : is_identity_transform ( const IfcUtil : : IfcBaseClass * l ) {
2017-01-16 11:53:11 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Not implemented is_identity_transform() " ) ;
return false ;
/*
// OpenCascade kernel code below
IfcSchema::IfcAxis2Placement2D* ax2d;
IfcSchema::IfcAxis2Placement3D* ax3d;
IfcSchema::IfcCartesianTransformationOperator2D* op2d;
IfcSchema::IfcCartesianTransformationOperator3D* op3d;
IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu;
IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu;
if ((op2dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
gp_GTrsf2d gtrsf2d;
convert(op2dnonu, gtrsf2d);
return gtrsf2d.Form() == gp_Identity;
} else if ((op2d = l->as<IfcSchema::IfcCartesianTransformationOperator2D>()) != 0) {
gp_Trsf2d trsf2d;
convert(op2d, trsf2d);
return trsf2d.Form() == gp_Identity;
} else if ((op3dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator3DnonUniform>()) != 0) {
gp_GTrsf gtrsf;
convert(op3dnonu, gtrsf);
return gtrsf.Form() == gp_Identity;
} else if ((op3d = l->as<IfcSchema::IfcCartesianTransformationOperator3D>()) != 0) {
gp_Trsf trsf;
convert(op3d, trsf);
return trsf.Form() == gp_Identity;
} else if ((ax2d = l->as<IfcSchema::IfcAxis2Placement2D>()) != 0) {
gp_Trsf2d trsf2d;
convert(ax2d, trsf2d);
return trsf2d.Form() == gp_Identity;
} else if ((ax3d = l->as<IfcSchema::IfcAxis2Placement3D>()) != 0) {
gp_Trsf trsf;
convert(ax3d, trsf);
return trsf.Form() == gp_Identity;
} else {
throw IfcParse::IfcException("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator");
}
*/
}
2019-01-20 13:16:42 +01:00
bool IfcGeom : : CgalKernel : : apply_layerset ( const IfcSchema : : IfcProduct * product , IfcGeom : : ConversionResults & shapes ) {
throw std : : runtime_error ( " not implemented " ) ;
2017-01-16 11:53:11 +01:00
}
2019-01-20 13:16:42 +01:00
bool IfcGeom : : CgalKernel : : validate_quantities ( const IfcSchema : : IfcProduct * product , const IfcGeom : : Representation : : BRep & brep ) {
throw std : : runtime_error ( " not implemented " ) ;
2017-01-16 11:53:11 +01:00
}
2019-01-18 16:43:38 +01:00
2019-01-25 14:25:34 +01:00
bool IfcGeom : : CgalKernel : : convert_placement ( IfcUtil : : IfcBaseClass * item , ConversionResultPlacement * & trsf ) {
if ( item - > as < IfcSchema : : IfcObjectPlacement > ( ) ) {
cgal_placement_t cgal_trsf ;
if ( convert ( item - > as < IfcSchema : : IfcObjectPlacement > ( ) , cgal_trsf ) ) {
trsf = new CgalPlacement ( cgal_trsf ) ;
return true ;
}
}
return false ;
}
2019-01-23 17:27:13 +01:00
bool IfcGeom : : CgalKernel : : convert_openings ( const IfcSchema : : IfcProduct * product , const IfcSchema : : IfcRelVoidsElement : : list : : ptr & openings , const IfcGeom : : ConversionResults & entity_shapes , const IfcGeom : : ConversionResultPlacement * trsf , IfcGeom : : ConversionResults & opened_shapes ) {
const cgal_placement_t & entity_trsf = ( ( CgalPlacement * ) trsf ) - > trsf ( ) ;
2017-03-09 18:42:54 -06:00
std : : list < cgal_shape_t > opening_shapelist ;
for ( IfcSchema : : IfcRelVoidsElement : : list : : it it = openings - > begin ( ) ; it ! = openings - > end ( ) ; + + it ) {
IfcSchema : : IfcRelVoidsElement * v = * it ;
IfcSchema : : IfcFeatureElementSubtraction * fes = v - > RelatedOpeningElement ( ) ;
2019-01-23 17:27:13 +01:00
if ( fes - > as < IfcSchema : : IfcOpeningElement > ( ) ) {
2017-03-09 18:42:54 -06:00
if ( ! fes - > hasRepresentation ( ) ) continue ;
// Convert the IfcRepresentation of the IfcOpeningElement
cgal_placement_t opening_trsf ;
if ( fes - > hasObjectPlacement ( ) ) {
try {
convert ( fes - > ObjectPlacement ( ) , opening_trsf ) ;
} catch ( . . . ) { }
}
// Move the opening into the coordinate system of the IfcProduct
2017-04-05 16:06:07 +02:00
opening_trsf = entity_trsf . inverse ( ) * opening_trsf ;
2017-03-09 18:42:54 -06:00
IfcSchema : : IfcProductRepresentation * prodrep = fes - > Representation ( ) ;
IfcSchema : : IfcRepresentation : : list : : ptr reps = prodrep - > Representations ( ) ;
IfcGeom : : ConversionResults opening_shapes ;
for ( IfcSchema : : IfcRepresentation : : list : : it it2 = reps - > begin ( ) ; it2 ! = reps - > end ( ) ; + + it2 ) {
convert_shapes ( * it2 , opening_shapes ) ;
}
for ( unsigned int i = 0 ; i < opening_shapes . size ( ) ; + + i ) {
2017-03-10 18:21:15 -06:00
cgal_placement_t gtrsf ;
2017-03-10 18:26:15 -06:00
if ( opening_shapes [ i ] . Placement ( ) ) {
gtrsf = * ( CgalPlacement * ) opening_shapes [ i ] . Placement ( ) ;
}
2017-04-05 16:06:07 +02:00
gtrsf = opening_trsf * gtrsf ;
2017-03-09 18:42:54 -06:00
cgal_shape_t opening_shape ( ( ( CgalShape * ) opening_shapes [ i ] . Shape ( ) ) - > shape ( ) ) ;
2017-03-23 19:49:15 -06:00
for ( auto & vertex : vertices ( opening_shape ) ) vertex - > point ( ) = vertex - > point ( ) . transform ( gtrsf ) ;
2017-03-10 18:21:15 -06:00
opening_shapelist . push_back ( opening_shape ) ;
2017-03-09 18:42:54 -06:00
}
}
}
// Iterate over the shapes of the IfcProduct
for ( IfcGeom : : ConversionResults : : const_iterator it3 = entity_shapes . begin ( ) ; it3 ! = entity_shapes . end ( ) ; + + it3 ) {
const cgal_shape_t & entity_shape_unlocated ( ( ( CgalShape * ) it3 - > Shape ( ) ) - > shape ( ) ) ;
cgal_shape_t entity_shape ( entity_shape_unlocated ) ;
if ( it3 - > Placement ( ) ) {
const cgal_placement_t & entity_shape_gtrsf = * ( CgalPlacement * ) it3 - > Placement ( ) ;
2017-03-23 19:49:15 -06:00
for ( auto & vertex : vertices ( entity_shape ) ) vertex - > point ( ) = vertex - > point ( ) . transform ( entity_shape_gtrsf ) ;
2017-03-09 18:42:54 -06:00
}
2017-04-25 13:44:34 +02:00
cgal_shape_t original_entity_shape ( entity_shape ) ;
2019-01-23 15:44:19 +01:00
2017-04-25 13:44:34 +02:00
if ( ! entity_shape . is_valid ( ) ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Invalid geometry: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
if ( ! entity_shape . is_closed ( ) ) {
2017-04-25 13:44:34 +02:00
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Subtraction of openings not supported for non-closed geometry: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
bool success = false ;
2017-04-25 13:44:34 +02:00
try {
success = CGAL : : Polygon_mesh_processing : : triangulate_faces ( entity_shape ) ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of geometry crashed: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
if ( ! success ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of geometry failed: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
if ( CGAL : : Polygon_mesh_processing : : does_self_intersect ( entity_shape ) ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Self-intersecting geometry: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
2019-01-23 17:27:13 +01:00
CGAL : : Nef_polyhedron_3 < Kernel_ > nef_brep_cut_result ;
2019-01-23 15:44:19 +01:00
2017-04-25 13:44:34 +02:00
try {
2019-01-23 17:27:13 +01:00
nef_brep_cut_result = CGAL : : Nef_polyhedron_3 < Kernel_ > ( entity_shape ) ;
2017-04-25 13:44:34 +02:00
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Could not convert geometry to Nef: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
try {
2017-04-25 13:44:34 +02:00
cgal_shape_t brep_cut_result ;
nef_brep_cut_result . convert_to_polyhedron ( brep_cut_result ) ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_WARNING , " Final conversion will likely fail. Could not convert geometry from Nef: " , product ) ;
2017-04-25 13:44:34 +02:00
}
2017-03-09 18:42:54 -06:00
for ( auto & opening : opening_shapelist ) {
2017-03-10 17:44:19 -06:00
2017-04-25 13:44:34 +02:00
cgal_shape_t original_opening_shape ( opening ) ;
if ( ! opening . is_valid ( ) ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Invalid opening in geometry: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
} if ( ! opening . is_closed ( ) ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Subtraction of opening makes no sense. Not closed opening in geometry: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
success = false ;
2017-04-25 13:44:34 +02:00
try {
success = CGAL : : Polygon_mesh_processing : : triangulate_faces ( opening ) ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of opening of geometry crashed: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
if ( ! success ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Triangulation of opening of geometry failed: " , product ) ;
2017-04-25 13:44:34 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
if ( CGAL : : Polygon_mesh_processing : : does_self_intersect ( entity_shape ) ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Conversion to Nef will fail. Self-intersecting opening of geometry: " , product ) ;
2019-01-23 15:44:19 +01:00
}
2019-01-23 17:27:13 +01:00
CGAL : : Nef_polyhedron_3 < Kernel_ > nef_opening ;
2019-01-23 15:44:19 +01:00
2017-04-21 15:43:19 +02:00
try {
2019-01-23 17:27:13 +01:00
nef_opening = CGAL : : Nef_polyhedron_3 < Kernel_ > ( opening ) ;
2017-04-21 15:43:19 +02:00
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Could not convert opening of geometry to Nef: " , product ) ;
2017-04-21 15:43:19 +02:00
return false ;
2019-01-23 15:44:19 +01:00
}
try {
2017-04-25 13:44:34 +02:00
cgal_shape_t opening_shape ;
nef_opening . convert_to_polyhedron ( opening_shape ) ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_WARNING , " Final conversion will likely fail. Could not convert opening of geometry from Nef: " , product ) ;
2019-01-23 15:44:19 +01:00
// return false;
}
try {
2017-04-21 15:43:19 +02:00
nef_brep_cut_result - = nef_opening ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Could not subtract Nef opening of geometry: " , product ) ;
2017-04-21 15:43:19 +02:00
return false ;
}
2017-03-09 18:42:54 -06:00
}
2017-04-25 13:44:34 +02:00
try {
nef_brep_cut_result . convert_to_polyhedron ( entity_shape ) ;
} catch ( . . . ) {
2019-01-23 17:27:13 +01:00
Logger : : Message ( Logger : : LOG_ERROR , " Could not convert geometry with openings from Nef: " , product ) ;
2017-03-09 18:42:54 -06:00
return false ;
2019-01-23 15:44:19 +01:00
}
2019-01-23 17:27:13 +01:00
opened_shapes . push_back ( IfcGeom : : ConversionResult ( it3 - > ItemId ( ) , new CgalShape ( entity_shape ) , & it3 - > Style ( ) ) ) ;
2017-03-09 18:42:54 -06:00
2017-04-25 13:44:34 +02:00
} return true ;
2019-01-19 12:39:47 +01:00
}