2014-12-19 12:14:36 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* Geometrical data in an IFC file consists of shapes (IfcShapeRepresentation) *
* and instances (SUBTYPE OF IfcBuildingElement e.g. IfcWindow). *
* *
* IfcGeom::Representation::Triangulation is a class that represents a *
* triangulated IfcShapeRepresentation. *
* Triangulation.verts is a 1 dimensional vector of float defining the *
* cartesian coordinates of the vertices of the triangulated shape in the *
* format of [x1,y1,z1,..,xn,yn,zn] *
* Triangulation.faces is a 1 dimensional vector of int containing the *
* indices of the triangles referencing positions in Triangulation.verts *
* Triangulation.edges is a 1 dimensional vector of int in {0,1} that dictates*
* the visibility of the edges that span the faces in Triangulation.faces *
* *
* IfcGeom::Element represents the actual IfcBuildingElements. *
* IfcGeomObject.name is the GUID of the element *
* IfcGeomObject.type is the datatype of the element e.g. IfcWindow *
* IfcGeomObject.mesh is a pointer to an IfcMesh *
* IfcGeomObject.transformation.matrix is a 4x3 matrix that defines the *
* orientation and translation of the mesh in relation to the world origin *
* *
2015-04-22 09:15:48 +00:00
* IfcGeom::Iterator::initialize() *
2014-12-19 12:14:36 +00:00
* finds the most suitable representation contexts. Returns true iff *
* at least a single representation will process successfully *
* *
* IfcGeom::Iterator::get() *
* returns a pointer to the current IfcGeom::Element *
2021-09-22 18:58:32 +10:00
* *
2014-12-19 12:14:36 +00:00
* IfcGeom::Iterator::next() *
* returns true iff a following entity is available for a successive call to *
* IfcGeom::Iterator::get() *
* *
* IfcGeom::Iterator::progress() *
* returns an int in [0..100] that indicates the overall progress *
* *
********************************************************************************/
# ifndef IFCGEOMITERATOR_H
# define IFCGEOMITERATOR_H
# include <map>
# include <set>
# include <vector>
2014-12-19 12:36:06 +00:00
# include <limits>
2014-12-19 12:14:36 +00:00
# include <algorithm>
2019-07-09 16:00:29 +02:00
# include <atomic>
2014-12-19 12:14:36 +00:00
2019-07-03 12:10:27 +02:00
# include <future>
# include <thread>
# include <chrono>
2015-09-13 15:00:21 +02:00
# include <boost/algorithm/string.hpp>
2014-12-19 12:14:36 +00:00
# include <gp_Mat.hxx>
# include <gp_Mat2d.hxx>
# include <gp_GTrsf.hxx>
# include <gp_GTrsf2d.hxx>
# include <gp_Trsf.hxx>
# include <gp_Trsf2d.hxx>
2015-01-05 14:11:42 +00:00
# include "../ifcparse/IfcFile.h"
2014-12-19 12:14:36 +00:00
# include "../ifcgeom/IfcGeom.h"
# include "../ifcgeom/IfcGeomElement.h"
2017-12-20 17:09:42 +01:00
# include "../ifcgeom_schema_agnostic/IfcGeomMaterial.h"
2014-12-19 12:14:36 +00:00
# include "../ifcgeom/IfcGeomIteratorSettings.h"
# include "../ifcgeom/IfcRepresentationShapeItem.h"
2018-09-07 14:08:56 +02:00
# include "../ifcgeom_schema_agnostic/IfcGeomFilter.h"
2017-12-20 17:09:42 +01:00
# include "../ifcgeom_schema_agnostic/IteratorImplementation.h"
2017-12-19 20:24:00 +01:00
2019-07-19 15:55:22 +02:00
# include <atomic>
2016-07-11 21:36:12 +03:00
// The infamous min & max Win32 #defines can leak here from OCE depending on the build configuration
# ifdef min
# undef min
# endif
# ifdef max
# undef max
# endif
2019-07-03 12:10:27 +02:00
namespace {
struct geometry_conversion_task {
int index ;
IfcSchema : : IfcRepresentation * representation ;
IfcSchema : : IfcProduct : : list : : ptr products ;
2021-07-11 15:00:59 +02:00
std : : vector < IfcGeom : : BRepElement * > breps ;
std : : vector < IfcGeom : : Element * > elements ;
2019-07-03 12:10:27 +02:00
} ;
}
2014-12-19 12:14:36 +00:00
namespace IfcGeom {
2021-09-22 18:58:32 +10:00
2021-07-11 15:00:59 +02:00
class MAKE_TYPE_NAME ( IteratorImplementation_ ) : public IteratorImplementation {
2014-12-19 12:14:36 +00:00
private :
2017-12-19 20:24:00 +01:00
2019-07-19 15:55:22 +02:00
std : : atomic < int > progress_ ;
2021-07-11 15:00:59 +02:00
std : : vector < geometry_conversion_task > tasks_ ;
std : : vector < IfcGeom : : Element * > all_processed_elements_ ;
std : : vector < IfcGeom : : BRepElement * > all_processed_native_elements_ ;
typename std : : vector < IfcGeom : : Element * > : : const_iterator task_result_iterator_ ;
typename std : : vector < IfcGeom : : BRepElement * > : : const_iterator native_task_result_iterator_ ;
2019-07-03 12:10:27 +02:00
2017-12-19 20:24:00 +01:00
MAKE_TYPE_NAME ( IteratorImplementation_ ) ( const MAKE_TYPE_NAME ( IteratorImplementation_ ) & ) ; // N/I
MAKE_TYPE_NAME ( IteratorImplementation_ ) & operator = ( const MAKE_TYPE_NAME ( IteratorImplementation_ ) & ) ; // N/I
2016-03-07 22:37:36 +02:00
2017-12-20 16:38:55 +01:00
MAKE_TYPE_NAME ( Kernel ) kernel ;
2014-12-19 12:14:36 +00:00
2020-03-18 11:59:11 +01:00
IteratorSettings settings ;
2014-12-19 12:14:36 +00:00
IfcParse : : IfcFile * ifc_file ;
2020-03-18 11:59:11 +01:00
std : : vector < filter_t > filters_ ;
bool owns_ifc_file ;
int num_threads_ ;
2014-12-19 12:14:36 +00:00
2015-01-05 14:11:42 +00:00
// A container and iterator for IfcRepresentations
2014-12-19 12:14:36 +00:00
IfcSchema : : IfcRepresentation : : list : : ptr representations ;
2015-01-05 14:11:42 +00:00
IfcSchema : : IfcRepresentation : : list : : it representation_iterator ;
2014-12-19 12:14:36 +00:00
// The object is fetched beforehand to be sure that get() returns a valid element
2021-07-11 15:00:59 +02:00
TriangulationElement * current_triangulation ;
BRepElement * current_shape_model ;
SerializedElement * current_serialization ;
2021-09-22 18:58:32 +10:00
2015-01-05 14:11:42 +00:00
// A container and iterator for IfcBuildingElements for the current IfcRepresentation referenced by *representation_iterator
2015-02-05 11:55:25 +00:00
IfcSchema : : IfcProduct : : list : : ptr ifcproducts ;
2014-12-19 12:14:36 +00:00
IfcSchema : : IfcProduct : : list : : it ifcproduct_iterator ;
2018-04-12 16:42:46 +03:00
IfcSchema : : IfcRepresentation : : list : : ptr ok_mapped_representations ;
2021-09-22 19:16:38 +10:00
double lowest_precision_encountered ;
bool any_precision_encountered ;
2014-12-19 12:14:36 +00:00
int done ;
int total ;
std : : string unit_name ;
2017-02-03 19:15:37 +02:00
double unit_magnitude ;
2016-03-17 23:25:53 +02:00
gp_XYZ bounds_min_ ;
gp_XYZ bounds_max_ ;
2014-12-19 12:14:36 +00:00
2017-02-07 17:34:23 +02:00
struct filter_match
{
filter_match ( IfcSchema : : IfcProduct * prod ) : product ( prod ) { }
bool operator ( ) ( const filter_t & filter ) const { return filter ( product ) ; }
IfcSchema : : IfcProduct * product ;
} ;
2014-12-19 12:14:36 +00:00
void initUnits ( ) {
2017-12-19 20:24:00 +01:00
IfcSchema : : IfcProject : : list : : ptr projects = ifc_file - > instances_by_type < IfcSchema : : IfcProject > ( ) ;
2015-01-10 22:13:52 +00:00
if ( projects - > size ( ) = = 1 ) {
2015-01-05 14:11:42 +00:00
IfcSchema : : IfcProject * project = * projects - > begin ( ) ;
std : : pair < std : : string , double > length_unit = kernel . initializeUnits ( project - > UnitsInContext ( ) ) ;
unit_name = length_unit . first ;
2017-02-03 19:15:37 +02:00
unit_magnitude = length_unit . second ;
2018-09-07 14:25:46 +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. " ) ;
2014-12-19 12:14:36 +00:00
}
}
2017-02-16 19:49:46 +02:00
/// @todo public/private sections all over the place: move all public to the beginning of the class
2014-12-19 12:14:36 +00:00
public :
2017-12-19 20:24:00 +01:00
2020-07-22 12:25:24 +02:00
boost : : optional < bool > initialization_outcome_ ;
2015-04-22 09:15:48 +00:00
bool initialize ( ) {
2020-07-22 12:25:24 +02:00
if ( initialization_outcome_ ) {
return * initialization_outcome_ ;
}
2014-12-19 12:14:36 +00:00
try {
initUnits ( ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
2014-12-19 12:14:36 +00:00
2021-09-22 18:58:32 +10:00
representations = IfcSchema : : IfcRepresentation : : list : : ptr ( new IfcSchema : : IfcRepresentation : : list ) ;
ok_mapped_representations = IfcSchema : : IfcRepresentation : : list : : ptr ( new IfcSchema : : IfcRepresentation : : list ) ;
2021-09-22 19:16:38 +10:00
lowest_precision_encountered = std : : numeric_limits < double > : : infinity ( ) ;
any_precision_encountered = false ;
2014-12-19 12:14:36 +00:00
2021-09-22 18:58:32 +10:00
if ( settings . context_ids ( ) . size ( ) ! = 0 ) {
2021-09-22 19:16:38 +10:00
addRepresentationsFromContextIds ( ) ;
2021-09-22 18:58:32 +10:00
} else {
2021-09-22 19:16:38 +10:00
addRepresentationsFromDefaultContexts ( ) ;
2021-09-22 10:56:49 +10:00
}
2014-12-19 12:14:36 +00:00
if ( any_precision_encountered ) {
2015-01-06 14:09:28 +00:00
// Some arbitrary factor that has proven to work better for the models in the set of test files.
2021-02-06 10:26:17 -06:00
lowest_precision_encountered * = kernel . getValue ( IfcGeom : : Kernel : : GV_PRECISION_FACTOR ) ;
2015-01-06 14:09:28 +00:00
lowest_precision_encountered * = unit_magnitude ;
if ( lowest_precision_encountered < 1.e-7 ) {
Logger : : Message ( Logger : : LOG_WARNING , " Precision lower than 0.0000001 meter not enforced " ) ;
kernel . setValue ( IfcGeom : : Kernel : : GV_PRECISION , 1.e-7 ) ;
} else {
kernel . setValue ( IfcGeom : : Kernel : : GV_PRECISION , lowest_precision_encountered ) ;
}
2014-12-19 12:14:36 +00:00
} else {
kernel . setValue ( IfcGeom : : Kernel : : GV_PRECISION , 1.e-5 ) ;
}
2018-10-30 12:15:35 +01:00
if ( representations - > size ( ) = = 0 ) {
2018-12-29 12:34:32 +01:00
Logger : : Warning ( " No representations encountered, aborting " ) ;
2020-07-22 12:25:24 +02:00
initialization_outcome_ = false ;
} else {
representation_iterator = representations - > begin ( ) ;
ifcproducts . reset ( ) ;
2014-12-19 12:14:36 +00:00
2020-07-22 12:25:24 +02:00
done = 0 ;
total = representations - > size ( ) ;
2014-12-19 12:14:36 +00:00
2020-07-22 12:25:24 +02:00
if ( num_threads_ ! = 1 ) {
collect ( ) ;
process_concurrently ( ) ;
2020-05-31 17:07:41 +02:00
2020-07-22 12:25:24 +02:00
initialization_outcome_ = ! all_processed_elements_ . empty ( ) ;
} else {
initialization_outcome_ = create ( ) ;
2019-07-03 12:10:27 +02:00
}
}
2020-07-22 12:25:24 +02:00
return * initialization_outcome_ ;
2018-08-20 14:36:53 +03:00
}
2019-07-03 12:10:27 +02:00
void collect ( ) {
int i = 0 ;
IfcSchema : : IfcProduct : : list * previous = nullptr ;
2020-03-30 10:53:08 +02:00
while ( auto rp = try_get_next_task ( ) ) {
2019-07-03 12:10:27 +02:00
// Note that get_next_task() mutates the state of the iterator
// we use that capture all products that can be processed as
// part of this representation and then keep iterating until
// the underlying list of products changes.
if ( ifcproducts . get ( ) ! = previous ) {
previous = ifcproducts . get ( ) ;
2020-03-30 10:53:08 +02:00
if ( ifcproducts - > size ( ) ) {
2021-07-11 15:00:59 +02:00
geometry_conversion_task t ;
2020-03-30 10:53:08 +02:00
t . index = i + + ;
t . representation = * representation_iterator ;
t . products = ifcproducts ;
tasks_ . emplace_back ( t ) ;
}
}
if ( rp - > which ( ) = = 1 ) {
Logger : : Error ( boost : : get < IfcParse : : IfcException > ( * rp ) ) ;
2019-07-03 12:10:27 +02:00
}
_nextShape ( ) ;
}
}
void process_concurrently ( ) {
2019-07-09 16:00:29 +02:00
size_t conc_threads = num_threads_ ;
if ( conc_threads > tasks_ . size ( ) ) {
conc_threads = tasks_ . size ( ) ;
2019-07-03 12:10:27 +02:00
}
2021-09-22 18:58:32 +10:00
2019-07-03 12:10:27 +02:00
std : : vector < MAKE_TYPE_NAME ( Kernel ) * > kernel_pool ;
kernel_pool . reserve ( conc_threads ) ;
for ( unsigned i = 0 ; i < conc_threads ; + + i ) {
kernel_pool . push_back ( new MAKE_TYPE_NAME ( Kernel ) ( kernel ) ) ;
}
std : : vector < std : : future < void > > threadpool ;
2019-07-09 16:00:58 +02:00
int old_progress = - 1 ;
int processed = 0 ;
Logger : : ProgressBar ( 0 ) ;
2019-07-03 12:10:27 +02:00
for ( auto & rep : tasks_ ) {
2019-07-09 16:00:58 +02:00
MAKE_TYPE_NAME ( Kernel ) * K = nullptr ;
if ( threadpool . size ( ) < kernel_pool . size ( ) ) {
K = kernel_pool [ threadpool . size ( ) ] ;
}
2019-07-03 12:10:27 +02:00
while ( threadpool . size ( ) = = conc_threads ) {
for ( int i = 0 ; i < ( int ) threadpool . size ( ) ; i + + ) {
std : : future < void > & fu = threadpool [ i ] ;
std : : future_status status ;
status = fu . wait_for ( std : : chrono : : seconds ( 0 ) ) ;
if ( status = = std : : future_status : : ready ) {
fu . get ( ) ;
2021-09-22 18:58:32 +10:00
2019-07-09 16:00:58 +02:00
processed + = 1 ;
2019-07-19 15:55:22 +02:00
progress_ = processed * 50 / tasks_ . size ( ) ;
if ( progress_ ! = old_progress ) {
Logger : : ProgressBar ( progress_ ) ;
old_progress = progress_ ;
2019-07-09 16:00:58 +02:00
}
2021-09-22 18:58:32 +10:00
2019-07-03 12:10:27 +02:00
std : : swap ( threadpool [ i ] , threadpool . back ( ) ) ;
threadpool . pop_back ( ) ;
std : : swap ( kernel_pool [ i ] , kernel_pool . back ( ) ) ;
K = kernel_pool . back ( ) ;
break ;
} // if
} // for
} // while
2021-11-02 11:39:49 +01:00
std : : future < void > fu = std : : async (
std : : launch : : async , [ this ] (
IfcGeom : : MAKE_TYPE_NAME ( Kernel ) * kernel ,
const IfcGeom : : IteratorSettings & settings ,
geometry_conversion_task * rep ) {
return this - > create_element_ ( kernel , settings , rep ) ;
} ,
K ,
std : : ref ( settings ) ,
& rep ) ;
2019-07-03 12:10:27 +02:00
threadpool . emplace_back ( std : : move ( fu ) ) ;
}
for ( std : : future < void > & fu : threadpool ) {
fu . get ( ) ;
2019-07-09 16:00:58 +02:00
processed + = 1 ;
2019-07-19 15:55:22 +02:00
progress_ = processed * 50 / tasks_ . size ( ) ;
if ( progress_ ! = old_progress ) {
Logger : : ProgressBar ( progress_ ) ;
old_progress = progress_ ;
2019-07-09 16:00:58 +02:00
}
2019-07-03 12:10:27 +02:00
}
for ( auto & rep : tasks_ ) {
all_processed_elements_ . insert ( all_processed_elements_ . end ( ) , rep . elements . begin ( ) , rep . elements . end ( ) ) ;
2019-07-09 16:00:29 +02:00
all_processed_native_elements_ . insert ( all_processed_native_elements_ . end ( ) , rep . breps . begin ( ) , rep . breps . end ( ) ) ;
2019-07-03 12:10:27 +02:00
}
task_result_iterator_ = all_processed_elements_ . begin ( ) ;
2019-07-09 16:00:29 +02:00
native_task_result_iterator_ = all_processed_native_elements_ . begin ( ) ;
2019-07-09 16:00:58 +02:00
Logger : : Status ( " \r Done creating geometry ( " + boost : : lexical_cast < std : : string > ( all_processed_elements_ . size ( ) ) +
" objects) " ) ;
2019-07-03 12:10:27 +02:00
}
2018-08-20 14:36:53 +03:00
/// Computes model's bounding box (bounds_min and bounds_max).
/// @note Can take several minutes for large files.
2020-02-12 11:38:08 +01:00
void compute_bounds ( bool with_geometry )
2018-08-20 14:36:53 +03:00
{
2016-03-17 23:25:53 +02:00
for ( int i = 1 ; i < 4 ; + + i ) {
bounds_min_ . SetCoord ( i , std : : numeric_limits < double > : : infinity ( ) ) ;
bounds_max_ . SetCoord ( i , - std : : numeric_limits < double > : : infinity ( ) ) ;
}
2020-02-12 11:38:08 +01:00
if ( with_geometry ) {
size_t num_created = 0 ;
do {
2021-07-11 15:00:59 +02:00
IfcGeom : : Element * geom_object = get ( ) ;
const IfcGeom : : TriangulationElement * o = static_cast < const IfcGeom : : TriangulationElement * > ( geom_object ) ;
const IfcGeom : : Representation : : Triangulation & mesh = o - > geometry ( ) ;
2020-02-12 11:38:08 +01:00
const gp_XYZ & pos = o - > transformation ( ) . data ( ) . TranslationPart ( ) ;
2021-07-11 15:00:59 +02:00
for ( typename std : : vector < double > : : const_iterator it = mesh . verts ( ) . begin ( ) ; it ! = mesh . verts ( ) . end ( ) ; ) {
const double & x = * ( it + + ) ;
const double & y = * ( it + + ) ;
const double & z = * ( it + + ) ;
2021-09-22 18:58:32 +10:00
2020-02-12 11:38:08 +01:00
bounds_min_ . SetX ( std : : min ( bounds_min_ . X ( ) , pos . X ( ) + x ) ) ;
bounds_min_ . SetY ( std : : min ( bounds_min_ . Y ( ) , pos . Y ( ) + y ) ) ;
bounds_min_ . SetZ ( std : : min ( bounds_min_ . Z ( ) , pos . Z ( ) + z ) ) ;
bounds_max_ . SetX ( std : : max ( bounds_max_ . X ( ) , pos . X ( ) + x ) ) ;
bounds_max_ . SetY ( std : : max ( bounds_max_ . Y ( ) , pos . Y ( ) + y ) ) ;
bounds_max_ . SetZ ( std : : max ( bounds_max_ . Z ( ) , pos . Z ( ) + z ) ) ;
}
} while ( + + num_created , next ( ) ) ;
} else {
IfcSchema : : IfcProduct : : list : : ptr products = ifc_file - > instances_by_type < IfcSchema : : IfcProduct > ( ) ;
for ( IfcSchema : : IfcProduct : : list : : it iter = products - > begin ( ) ; iter ! = products - > end ( ) ; + + iter ) {
IfcSchema : : IfcProduct * product = * iter ;
2021-07-29 14:54:51 +02:00
if ( product - > ObjectPlacement ( ) ) {
2020-02-12 11:38:08 +01:00
// Use a fresh trsf every time in order to prevent the result to be concatenated
2021-09-22 18:58:32 +10:00
gp_Trsf trsf ;
2020-02-12 11:38:08 +01:00
bool success = false ;
try {
success = kernel . convert ( product - > ObjectPlacement ( ) , trsf ) ;
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to construct placement " ) ;
}
if ( ! success ) {
continue ;
}
const gp_XYZ & pos = trsf . TranslationPart ( ) ;
bounds_min_ . SetX ( std : : min ( bounds_min_ . X ( ) , pos . X ( ) ) ) ;
bounds_min_ . SetY ( std : : min ( bounds_min_ . Y ( ) , pos . Y ( ) ) ) ;
bounds_min_ . SetZ ( std : : min ( bounds_min_ . Z ( ) , pos . Z ( ) ) ) ;
bounds_max_ . SetX ( std : : max ( bounds_max_ . X ( ) , pos . X ( ) ) ) ;
bounds_max_ . SetY ( std : : max ( bounds_max_ . Y ( ) , pos . Y ( ) ) ) ;
bounds_max_ . SetZ ( std : : max ( bounds_max_ . Z ( ) , pos . Z ( ) ) ) ;
}
}
}
2018-08-20 14:36:53 +03:00
}
2014-12-19 12:14:36 +00:00
2021-09-22 18:58:32 +10:00
int progress ( ) const {
2019-07-19 15:55:22 +02:00
if ( num_threads_ = = 1 ) {
return 100 * done / total ;
} else {
return progress_ ;
}
}
2014-12-19 12:14:36 +00:00
2016-03-07 22:37:36 +02:00
const std : : string & getUnitName ( ) const { return unit_name ; }
2014-12-19 12:14:36 +00:00
2017-02-03 19:15:37 +02:00
/// @note Double always as per IFC specification.
double getUnitMagnitude ( ) const { return unit_magnitude ; }
2021-09-22 18:58:32 +10:00
2016-03-07 22:37:36 +02:00
std : : string getLog ( ) const { return Logger : : GetLog ( ) ; }
2014-12-19 12:14:36 +00:00
2017-12-20 11:10:27 +01:00
IfcParse : : IfcFile * file ( ) const { return ifc_file ; }
2014-12-19 12:14:36 +00:00
2017-02-23 18:35:44 +02:00
const std : : vector < IfcGeom : : filter_t > & filters ( ) const { return filters_ ; }
std : : vector < IfcGeom : : filter_t > & filters ( ) { return filters_ ; }
2016-05-31 14:04:44 +03:00
2016-03-17 23:25:53 +02:00
const gp_XYZ & bounds_min ( ) const { return bounds_min_ ; }
const gp_XYZ & bounds_max ( ) const { return bounds_max_ ; }
2014-12-19 12:14:36 +00:00
private :
2021-09-22 19:16:38 +10:00
void addRepresentationsFromContextIds ( ) {
for ( auto context_id : settings . context_ids ( ) ) {
IfcSchema : : IfcGeometricRepresentationContext * context = ifc_file - > instance_by_id ( context_id ) - > as < IfcSchema : : IfcGeometricRepresentationContext > ( ) ;
2021-09-22 20:04:40 +10:00
if ( ! context ) {
Logger : : Error ( " Failed to process context ID " + std : : to_string ( context_id ) ) ;
continue ;
}
2021-09-22 19:16:38 +10:00
representations - > push ( context - > RepresentationsInContext ( ) ) ;
try {
2021-09-22 20:04:40 +10:00
double precision ;
if ( context - > as < IfcSchema : : IfcGeometricRepresentationSubContext > ( ) ) {
precision = * context - > as < IfcSchema : : IfcGeometricRepresentationSubContext > ( ) - > ParentContext ( ) - > Precision ( ) ;
} else {
precision = * context - > Precision ( ) ;
}
if ( precision & & precision < lowest_precision_encountered ) {
lowest_precision_encountered = precision ;
2021-09-22 19:16:38 +10:00
any_precision_encountered = true ;
}
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
}
}
void addRepresentationsFromDefaultContexts ( ) {
std : : set < std : : string > allowed_context_types ;
allowed_context_types . insert ( " model " ) ;
allowed_context_types . insert ( " plan " ) ;
allowed_context_types . insert ( " notdefined " ) ;
std : : set < std : : string > context_types ;
if ( ! settings . get ( IteratorSettings : : EXCLUDE_SOLIDS_AND_SURFACES ) ) {
// Really this should only be 'Model', as per
// the standard 'Design' is deprecated. So,
// just for backwards compatibility:
context_types . insert ( " model " ) ;
context_types . insert ( " design " ) ;
// Some earlier (?) versions DDS-CAD output their own ContextTypes
context_types . insert ( " model view " ) ;
context_types . insert ( " detail view " ) ;
}
if ( settings . get ( IteratorSettings : : INCLUDE_CURVES ) ) {
context_types . insert ( " plan " ) ;
}
IfcSchema : : IfcGeometricRepresentationContext : : list : : it it ;
IfcSchema : : IfcGeometricRepresentationSubContext : : list : : it jt ;
IfcSchema : : IfcGeometricRepresentationContext : : list : : ptr contexts =
ifc_file - > instances_by_type < IfcSchema : : IfcGeometricRepresentationContext > ( ) ;
IfcSchema : : IfcGeometricRepresentationContext : : list : : ptr filtered_contexts ( new IfcSchema : : IfcGeometricRepresentationContext : : list ) ;
for ( it = contexts - > begin ( ) ; it ! = contexts - > end ( ) ; + + it ) {
IfcSchema : : IfcGeometricRepresentationContext * context = * it ;
if ( context - > declaration ( ) . is ( IfcSchema : : IfcGeometricRepresentationSubContext : : Class ( ) ) ) {
// Continue, as the list of subcontexts will be considered
// by the parent's context inverse attributes.
continue ;
}
try {
if ( context - > ContextType ( ) ) {
std : : string context_type = * context - > ContextType ( ) ;
boost : : to_lower ( context_type ) ;
if ( allowed_context_types . find ( context_type ) = = allowed_context_types . end ( ) ) {
Logger : : Warning ( std : : string ( " ContextType ' " ) + * context - > ContextType ( ) + " ' not allowed: " , context ) ;
}
if ( context_types . find ( context_type ) ! = context_types . end ( ) ) {
filtered_contexts - > push ( context ) ;
}
}
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
}
// In case no contexts are identified based on their ContextType, all contexts are
// considered. Note that sub contexts are excluded as they are considered later on.
if ( filtered_contexts - > size ( ) = = 0 ) {
for ( it = contexts - > begin ( ) ; it ! = contexts - > end ( ) ; + + it ) {
IfcSchema : : IfcGeometricRepresentationContext * context = * it ;
if ( ! context - > declaration ( ) . is ( IfcSchema : : IfcGeometricRepresentationSubContext : : Class ( ) ) ) {
filtered_contexts - > push ( context ) ;
}
}
}
for ( it = filtered_contexts - > begin ( ) ; it ! = filtered_contexts - > end ( ) ; + + it ) {
IfcSchema : : IfcGeometricRepresentationContext * context = * it ;
representations - > push ( context - > RepresentationsInContext ( ) ) ;
try {
if ( context - > Precision ( ) & & * context - > Precision ( ) < lowest_precision_encountered ) {
lowest_precision_encountered = * context - > Precision ( ) ;
any_precision_encountered = true ;
}
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
}
IfcSchema : : IfcGeometricRepresentationSubContext : : list : : ptr sub_contexts = context - > HasSubContexts ( ) ;
for ( jt = sub_contexts - > begin ( ) ; jt ! = sub_contexts - > end ( ) ; + + jt ) {
representations - > push ( ( * jt ) - > RepresentationsInContext ( ) ) ;
}
// There is no need for full recursion as the following is governed by the schema:
// WR31: The parent context shall not be another geometric representation sub context.
}
if ( representations - > size ( ) = = 0 ) {
Logger : : Warning ( " No representations encountered in relevant contexts, using all " ) ;
representations = ifc_file - > instances_by_type < IfcSchema : : IfcRepresentation > ( ) ;
}
}
2015-01-05 14:11:42 +00:00
// Move to the next IfcRepresentation
2014-12-19 12:14:36 +00:00
void _nextShape ( ) {
2016-05-01 20:38:10 +02:00
// In order to conserve memory and reduce cache insertion times, the cache is
2018-09-06 12:23:07 -04:00
// cleared after an arbitrary number of processed representations. This has been
2016-05-01 20:38:10 +02:00
// benchmarked extensively: https://github.com/IfcOpenShell/IfcOpenShell/pull/47
static const int clear_interval = 64 ;
if ( done % clear_interval = = clear_interval - 1 ) {
kernel . purge_cache ( ) ;
2016-03-18 11:21:04 +01:00
}
2015-02-05 11:55:25 +00:00
ifcproducts . reset ( ) ;
2015-01-05 14:11:42 +00:00
+ + representation_iterator ;
2014-12-19 12:14:36 +00:00
+ + done ;
}
2017-06-28 15:24:49 +02:00
bool geometry_reuse_ok_for_current_representation_ ;
2017-10-06 15:36:51 +02:00
bool reuse_ok_ ( const IfcSchema : : IfcProduct : : list : : ptr & products ) {
// With world coords enabled, object transformations are directly applied to
// the BRep. There is no way to re-use the geometry for multiple products.
if ( settings . get ( IteratorSettings : : USE_WORLD_COORDS ) ) {
return false ;
}
2021-08-22 21:11:55 +10:00
if ( products - > size ( ) = = 1 ) {
return true ;
}
2017-10-06 15:36:51 +02:00
std : : set < const IfcSchema : : IfcMaterial * > associated_single_materials ;
for ( IfcSchema : : IfcProduct : : list : : it it = products - > begin ( ) ; it ! = products - > end ( ) ; + + it ) {
IfcSchema : : IfcProduct * product = * it ;
if ( ! settings . get ( IteratorSettings : : DISABLE_OPENING_SUBTRACTIONS ) & & kernel . find_openings ( product ) - > size ( ) ) {
return false ;
}
if ( settings . get ( IteratorSettings : : APPLY_LAYERSETS ) ) {
IfcSchema : : IfcRelAssociates : : list : : ptr associations = product - > HasAssociations ( ) ;
for ( IfcSchema : : IfcRelAssociates : : list : : it jt = associations - > begin ( ) ; jt ! = associations - > end ( ) ; + + jt ) {
IfcSchema : : IfcRelAssociatesMaterial * assoc = ( * jt ) - > as < IfcSchema : : IfcRelAssociatesMaterial > ( ) ;
if ( assoc ) {
2017-12-18 15:25:09 +01:00
if ( assoc - > RelatingMaterial ( ) - > declaration ( ) . is ( IfcSchema : : IfcMaterialLayerSetUsage : : Class ( ) ) ) {
2021-09-22 18:58:32 +10:00
// TODO: Check whether single layer?
2017-10-06 15:36:51 +02:00
return false ;
}
}
}
}
// Note that this can be a nullptr (!), but the fact that set size should be one still holds
associated_single_materials . insert ( kernel . get_single_material_association ( product ) ) ;
2018-04-12 16:42:46 +03:00
if ( associated_single_materials . size ( ) > 1 ) return false ;
2017-10-06 15:36:51 +02:00
}
return associated_single_materials . size ( ) = = 1 ;
}
2020-03-30 10:53:08 +02:00
boost : : optional < boost : : variant < std : : pair < IfcSchema : : IfcRepresentation * , IfcSchema : : IfcProduct * > , IfcParse : : IfcException > > try_get_next_task ( ) {
boost : : variant <
std : : pair < IfcSchema : : IfcRepresentation * , IfcSchema : : IfcProduct * > ,
IfcParse : : IfcException
> r ;
try {
auto p = get_next_task ( ) ;
if ( p ) {
r = * p ;
} else {
return boost : : none ;
}
} catch ( IfcParse : : IfcException & e ) {
r = e ;
} catch ( . . . ) {
r = IfcParse : : IfcException ( " Unknown error " ) ;
}
return r ;
}
2019-07-03 12:10:27 +02:00
boost : : optional < std : : pair < IfcSchema : : IfcRepresentation * , IfcSchema : : IfcProduct * > > get_next_task ( ) {
2015-11-21 23:05:28 +02:00
for ( ; ; ) {
2015-01-05 14:11:42 +00:00
IfcSchema : : IfcRepresentation * representation ;
2014-12-19 12:14:36 +00:00
2019-07-03 12:10:27 +02:00
if ( representation_iterator = = representations - > end ( ) ) {
2014-12-19 12:14:36 +00:00
representations . reset ( ) ;
2019-07-03 12:10:27 +02:00
return boost : : none ; // reached the end of our list of representations
2014-12-19 12:14:36 +00:00
}
2015-01-05 14:11:42 +00:00
representation = * representation_iterator ;
2014-12-19 12:14:36 +00:00
2015-02-05 11:55:25 +00:00
if ( ! ifcproducts ) {
2018-08-23 10:33:43 +03:00
// Init. the list of filtered IfcProducts for this representation
2015-02-05 11:55:25 +00:00
ifcproducts = IfcSchema : : IfcProduct : : list : : ptr ( new IfcSchema : : IfcProduct : : list ) ;
2017-10-06 15:36:51 +02:00
IfcSchema : : IfcProduct : : list : : ptr unfiltered_products = kernel . products_represented_by ( representation ) ;
2019-07-03 12:10:27 +02:00
// Include only the desired products for processing.
for ( IfcSchema : : IfcProduct : : list : : it jt = unfiltered_products - > begin ( ) ; jt ! = unfiltered_products - > end ( ) ; + + jt ) {
IfcSchema : : IfcProduct * prod = * jt ;
if ( boost : : all ( filters_ , filter_match ( prod ) ) ) {
ifcproducts - > push ( prod ) ;
}
}
2018-08-21 13:52:09 +03:00
2019-07-03 12:10:27 +02:00
if ( ifcproducts - > size ( ) = = 0 ) {
_nextShape ( ) ;
continue ;
}
2015-02-05 11:55:25 +00:00
2019-07-03 12:10:27 +02:00
geometry_reuse_ok_for_current_representation_ = reuse_ok_ ( ifcproducts ) ;
2016-03-18 11:23:25 +01:00
2018-02-21 14:54:38 +01:00
IfcSchema : : IfcRepresentationMap : : list : : ptr maps = representation - > RepresentationMap ( ) ;
if ( ! geometry_reuse_ok_for_current_representation_ & & maps - > size ( ) = = 1 ) {
2017-10-06 15:36:51 +02:00
// unfiltered_products contains products represented by this representation by means of mapped items.
// For example because of openings applied to products, reuse might not be acceptable and then the
// products will be processed by means of their immediate representation and not the mapped representation.
2018-02-21 14:54:38 +01:00
// IfcRepresentationMaps are also used for IfcTypeProducts, so an additional check is performed whether the map
// is indeed used by IfcMappedItems.
IfcSchema : : IfcRepresentationMap * map = * maps - > begin ( ) ;
if ( map - > MapUsage ( ) - > size ( ) > 0 ) {
_nextShape ( ) ;
continue ;
}
2016-03-18 11:23:25 +01:00
}
2014-12-19 12:14:36 +00:00
2018-08-23 10:33:43 +03:00
// Check if this represenation has (or will be) processed as part its mapped representation
2016-03-18 11:23:25 +01:00
bool representation_processed_as_mapped_item = false ;
2019-07-03 12:10:27 +02:00
IfcSchema : : IfcRepresentation * representation_mapped_to = kernel . representation_mapped_to ( representation ) ;
2016-03-18 11:23:25 +01:00
if ( representation_mapped_to ) {
2019-07-03 12:10:27 +02:00
representation_processed_as_mapped_item = geometry_reuse_ok_for_current_representation_ & & (
ok_mapped_representations - > contains ( representation_mapped_to ) | | reuse_ok_ ( kernel . products_represented_by ( representation_mapped_to ) ) ) ;
2014-12-19 12:14:36 +00:00
}
2016-03-18 11:23:25 +01:00
if ( representation_processed_as_mapped_item ) {
2019-07-03 12:10:27 +02:00
ok_mapped_representations - > push ( representation_mapped_to ) ;
2014-12-19 12:14:36 +00:00
_nextShape ( ) ;
continue ;
}
2016-03-18 11:23:25 +01:00
2015-02-05 11:55:25 +00:00
ifcproduct_iterator = ifcproducts - > begin ( ) ;
2014-12-19 12:14:36 +00:00
}
2016-03-18 11:23:25 +01:00
2014-12-19 12:14:36 +00:00
// Have we reached the end of our list of IfcProducts?
2019-07-03 12:10:27 +02:00
if ( ifcproduct_iterator = = ifcproducts - > end ( ) ) {
2014-12-19 12:14:36 +00:00
_nextShape ( ) ;
continue ;
}
2017-02-07 17:34:23 +02:00
IfcSchema : : IfcProduct * product = * ifcproduct_iterator ;
2019-07-03 12:10:27 +02:00
return std : : make_pair ( representation , product ) ;
}
}
2021-11-02 11:39:49 +01:00
std : : mutex caching_mutex_ ;
template < typename Fn >
Element * decorate_with_cache_ ( GeometrySerializer : : read_type rt , const std : : string & product_guid , const std : : string & representation_id , Fn f ) {
bool read_from_cache = false ;
Element * element = nullptr ;
# ifdef WITH_HDF5
if ( cache_ ) {
std : : lock_guard < std : : mutex > lk ( caching_mutex_ ) ;
auto from_cache = cache_ - > read ( * ifc_file , product_guid , representation_id , rt ) ;
if ( from_cache ) {
read_from_cache = true ;
element = from_cache ;
}
}
# endif
if ( ! read_from_cache ) {
element = f ( ) ;
}
# ifdef WITH_HDF5
if ( cache_ & & ! read_from_cache & & element ) {
std : : lock_guard < std : : mutex > lk ( caching_mutex_ ) ;
if ( rt = = GeometrySerializer : : READ_TRIANGULATION ) {
cache_ - > write ( ( IfcGeom : : TriangulationElement * ) element ) ;
} else {
cache_ - > write ( ( IfcGeom : : BRepElement * ) element ) ;
}
}
# endif
return element ;
}
2021-07-11 15:00:59 +02:00
BRepElement * create_shape_model_for_next_entity ( ) {
2019-07-03 12:10:27 +02:00
for ( ; ; ) {
auto rp = get_next_task ( ) ;
if ( ! rp ) {
return nullptr ;
}
auto representation = rp - > first ;
auto product = rp - > second ;
Logger : : SetProduct ( product ) ;
2016-05-11 09:56:40 +01:00
2021-11-02 11:39:49 +01:00
BRepElement * element = ( BRepElement * ) decorate_with_cache_ ( GeometrySerializer : : READ_BREP , product - > GlobalId ( ) , std : : to_string ( representation - > data ( ) . id ( ) ) , [ this , product , representation ] ( ) {
2021-10-08 15:38:46 +02:00
if ( ifcproduct_iterator = = ifcproducts - > begin ( ) | | ! geometry_reuse_ok_for_current_representation_ ) {
2021-11-02 11:39:49 +01:00
return kernel . create_brep_for_representation_and_product ( settings , representation , product ) ;
2021-10-08 15:38:46 +02:00
} else {
2021-11-02 11:39:49 +01:00
return kernel . create_brep_for_processed_representation ( settings , representation , product , current_shape_model ) ;
2021-10-08 15:38:46 +02:00
}
2021-11-02 11:39:49 +01:00
} ) ;
2014-12-19 12:14:36 +00:00
2016-07-19 15:31:37 +01:00
Logger : : SetProduct ( boost : : none ) ;
2017-02-07 17:34:23 +02:00
if ( ! element ) {
2015-01-05 14:11:42 +00:00
_nextShape ( ) ;
continue ;
2014-12-19 12:14:36 +00:00
}
2017-02-07 17:34:23 +02:00
return element ;
2017-02-03 19:15:37 +02:00
}
2014-12-19 12:14:36 +00:00
}
2016-03-18 11:23:25 +01:00
void free_shapes ( ) {
2014-12-19 12:14:36 +00:00
// Free all possible representations of the current geometrical entity
delete current_triangulation ;
current_triangulation = 0 ;
2015-01-05 14:11:42 +00:00
delete current_serialization ;
current_serialization = 0 ;
delete current_shape_model ;
current_shape_model = 0 ;
2016-03-18 11:23:25 +01:00
}
2021-11-02 11:39:49 +01:00
void create_element_ (
IfcGeom : : MAKE_TYPE_NAME ( Kernel ) * kernel ,
const IfcGeom : : IteratorSettings & settings ,
geometry_conversion_task * rep )
{
IfcSchema : : IfcRepresentation * representation = rep - > representation ;
IfcSchema : : IfcProduct * product = * rep - > products - > begin ( ) ;
IfcGeom : : BRepElement * brep = static_cast < IfcGeom : : BRepElement * > ( decorate_with_cache_ ( GeometrySerializer : : READ_BREP , product - > GlobalId ( ) , std : : to_string ( representation - > data ( ) . id ( ) ) , [ kernel , settings , product , representation ] ( ) {
return kernel - > create_brep_for_representation_and_product ( settings , representation , product ) ;
} ) ) ;
if ( ! brep ) {
return ;
}
auto elem = process_based_on_settings ( settings , brep ) ;
if ( ! elem ) {
return ;
}
rep - > breps = { brep } ;
rep - > elements = { elem } ;
for ( auto it = rep - > products - > begin ( ) + 1 ; it ! = rep - > products - > end ( ) ; + + it ) {
auto product2 = * it ;
IfcGeom : : BRepElement * brep2 = static_cast < IfcGeom : : BRepElement * > ( decorate_with_cache_ ( GeometrySerializer : : READ_BREP , product2 - > GlobalId ( ) , std : : to_string ( representation - > data ( ) . id ( ) ) , [ kernel , settings , product2 , representation , brep ] ( ) {
return kernel - > create_brep_for_processed_representation ( settings , representation , product2 , brep ) ;
} ) ) ;
if ( brep2 ) {
auto elem2 = process_based_on_settings ( settings , brep2 , dynamic_cast < IfcGeom : : TriangulationElement * > ( elem ) ) ;
if ( elem2 ) {
rep - > breps . push_back ( brep2 ) ;
rep - > elements . push_back ( elem2 ) ;
}
}
}
}
IfcGeom : : Element * process_based_on_settings (
const IfcGeom : : IteratorSettings & settings ,
IfcGeom : : BRepElement * elem ,
IfcGeom : : TriangulationElement * previous = nullptr )
{
if ( settings . get ( IfcGeom : : IteratorSettings : : USE_BREP_DATA ) ) {
try {
return new IfcGeom : : SerializedElement ( * elem ) ;
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Getting a serialized element from model failed. " ) ;
return nullptr ;
}
} else if ( ! settings . get ( IfcGeom : : IteratorSettings : : DISABLE_TRIANGULATION ) ) {
// the part before the hyphen is the representation id
auto gid2 = elem - > geometry ( ) . id ( ) ;
auto hyphen = gid2 . find ( " - " ) ;
if ( hyphen ! = std : : string : : npos ) {
gid2 = gid2 . substr ( 0 , hyphen ) ;
}
return decorate_with_cache_ ( GeometrySerializer : : READ_TRIANGULATION , elem - > guid ( ) , gid2 , [ elem , previous ] ( ) {
try {
if ( ! previous ) {
return new TriangulationElement ( * elem ) ;
} else {
return new TriangulationElement ( * elem , previous - > geometry_pointer ( ) ) ;
}
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Getting a triangulation element from model failed. " ) ;
}
return ( TriangulationElement * ) nullptr ;
} ) ;
} else {
return elem ;
}
}
2017-02-07 17:34:23 +02:00
public :
2017-02-03 19:15:37 +02:00
/// Returns what would be the product for the next shape representation
2017-02-07 17:34:23 +02:00
/// @todo Double-check and test the impl.
//IfcSchema::IfcProduct* peek_next() const
//{
// if (ifcproducts && ifcproduct_iterator + 1 != ifcproducts->end()){
// return *(ifcproduct_iterator + 1);
// } else {
// return 0;
// }
//}
/// @todo Would this be as simple as the following code?
//void skip_next() { if (ifcproducts) { ++ifcproduct_iterator; } }
/// Moves to the next shape representation, create its geometry, and returns the associated product.
2017-02-03 19:15:37 +02:00
/// Use get() to retrieve the created geometry.
2017-12-19 20:24:00 +01:00
IfcUtil : : IfcBaseClass * next ( ) {
2019-07-03 12:10:27 +02:00
if ( num_threads_ ! = 1 ) {
2019-07-09 16:00:29 +02:00
task_result_iterator_ + + ;
native_task_result_iterator_ + + ;
2019-07-03 12:10:27 +02:00
if ( task_result_iterator_ = = all_processed_elements_ . end ( ) ) {
return nullptr ;
} else {
return ( * task_result_iterator_ ) - > product ( ) ;
}
} else {
// Increment the iterator over the list of products using the current
// shape representation
if ( ifcproducts ) {
+ + ifcproduct_iterator ;
}
2014-12-19 12:14:36 +00:00
2019-07-03 12:10:27 +02:00
return create ( ) ;
}
2014-12-19 12:14:36 +00:00
}
2016-03-27 21:17:51 +02:00
/// Gets the representation of the current geometrical entity.
2021-07-11 15:00:59 +02:00
Element * get ( )
2016-03-07 22:37:36 +02:00
{
// TODO: Test settings and throw
2021-07-11 15:00:59 +02:00
Element * ret = 0 ;
2019-07-03 12:10:27 +02:00
if ( num_threads_ ! = 1 ) {
ret = * task_result_iterator_ ;
} else {
2021-09-22 18:58:32 +10:00
if ( current_triangulation ) {
ret = current_triangulation ;
} else if ( current_serialization ) {
ret = current_serialization ;
} else if ( current_shape_model ) {
ret = current_shape_model ;
2019-07-03 12:10:27 +02:00
}
}
2017-04-21 15:49:34 +02:00
2017-05-15 17:45:05 +02:00
// If we want to organize the element considering their hierarchy
2017-04-21 15:49:34 +02:00
if ( settings . get ( IteratorSettings : : SEARCH_FLOOR ) )
{
2017-05-15 17:45:05 +02:00
// We are going to build a vector with the element parents.
// First, create the parent vector
2021-07-11 15:00:59 +02:00
std : : vector < const IfcGeom : : Element * > parents ;
2021-09-22 18:58:32 +10:00
2017-04-21 16:02:13 +02:00
// if the element has a parent
2017-04-21 15:49:34 +02:00
if ( ret - > parent_id ( ) ! = - 1 )
{
2021-07-11 15:00:59 +02:00
const IfcGeom : : Element * parent_object = NULL ;
2017-04-21 15:49:34 +02:00
bool hasParent = true ;
2017-04-21 16:02:13 +02:00
2021-09-22 18:58:32 +10:00
// get the parent
2017-08-01 16:45:11 +02:00
try {
2017-12-20 11:10:27 +01:00
parent_object = get_object ( ret - > parent_id ( ) ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
2017-04-21 15:49:34 +02:00
hasParent = false ;
}
2017-05-15 17:45:05 +02:00
// Add the previously found parent to the vector
if ( hasParent ) parents . insert ( parents . begin ( ) , parent_object ) ;
2021-09-22 18:58:32 +10:00
2017-05-15 17:45:05 +02:00
// We need to find all the parents
2017-09-25 14:57:49 +02:00
while ( parent_object ! = NULL & & hasParent & & parent_object - > parent_id ( ) ! = - 1 )
2017-04-21 15:49:34 +02:00
{
2017-05-15 17:45:05 +02:00
// Find the next parent
2017-08-01 16:45:11 +02:00
try {
2017-12-20 11:10:27 +01:00
parent_object = get_object ( parent_object - > parent_id ( ) ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
2017-04-21 15:49:34 +02:00
hasParent = false ;
}
2017-05-15 17:45:05 +02:00
// Add the previously found parent to the vector
if ( hasParent ) parents . insert ( parents . begin ( ) , parent_object ) ;
hasParent = hasParent & & parent_object - > parent_id ( ) ! = - 1 ;
2017-04-21 15:49:34 +02:00
}
2017-05-15 17:45:05 +02:00
// when done push the parent list in the Element object
ret - > SetParents ( parents ) ;
2017-04-21 15:49:34 +02:00
}
}
2016-03-07 22:37:36 +02:00
return ret ;
}
2014-12-19 12:14:36 +00:00
2017-01-22 16:09:14 +01:00
/// Gets the native (Open Cascade) representation of the current geometrical entity.
2021-07-11 15:00:59 +02:00
BRepElement * get_native ( )
2017-01-22 16:09:14 +01:00
{
// TODO: Test settings and throw
2019-07-09 16:00:29 +02:00
if ( num_threads_ ! = 1 ) {
return * native_task_result_iterator_ ;
} else {
return current_shape_model ;
}
2017-01-22 16:09:14 +01:00
}
2021-07-11 15:00:59 +02:00
const Element * get_object ( int id ) {
2014-12-19 12:14:36 +00:00
gp_Trsf trsf ;
int parent_id = - 1 ;
std : : string instance_type , product_name , product_guid ;
2017-02-23 18:35:44 +02:00
IfcSchema : : IfcProduct * ifc_product = 0 ;
2017-09-25 14:57:49 +02:00
2014-12-19 12:14:36 +00:00
try {
2017-12-19 20:24:00 +01:00
IfcUtil : : IfcBaseClass * ifc_entity = ifc_file - > instance_by_id ( id ) ;
instance_type = ifc_entity - > declaration ( ) . name ( ) ;
2017-09-25 14:57:49 +02:00
2017-12-18 15:25:09 +01:00
if ( ifc_entity - > declaration ( ) . is ( IfcSchema : : IfcRoot : : Class ( ) ) ) {
2017-09-25 14:57:49 +02:00
IfcSchema : : IfcRoot * ifc_root = ifc_entity - > as < IfcSchema : : IfcRoot > ( ) ;
product_guid = ifc_root - > GlobalId ( ) ;
2021-07-29 14:54:51 +02:00
product_name = ifc_root - > Name ( ) . get_value_or ( " " ) ;
2017-09-25 14:57:49 +02:00
}
2017-12-18 15:25:09 +01:00
if ( ifc_entity - > declaration ( ) . is ( IfcSchema : : IfcProduct : : Class ( ) ) ) {
2017-09-25 14:57:49 +02:00
ifc_product = ifc_entity - > as < IfcSchema : : IfcProduct > ( ) ;
2015-01-05 14:11:42 +00:00
parent_id = - 1 ;
2014-12-19 12:14:36 +00:00
try {
2018-09-19 14:05:19 +02:00
IfcSchema : : IfcObjectDefinition * parent_object = kernel . get_decomposing_entity ( ifc_product ) - > template as < IfcSchema : : IfcObjectDefinition > ( ) ;
2015-01-05 14:11:42 +00:00
if ( parent_object ) {
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 ) ;
} catch ( . . . ) {
Logger : : Error ( " Failed to find decomposing entity " ) ;
}
2014-12-19 12:14:36 +00:00
try {
kernel . convert ( ifc_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 " ) ;
}
}
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error returning product " ) ;
2014-12-19 12:14:36 +00:00
}
2017-08-01 16:45:11 +02:00
} catch ( . . . ) {
Logger : : Error ( " Unknown error returning product " ) ;
}
2014-12-19 12:14:36 +00:00
ElementSettings element_settings ( settings , unit_magnitude , instance_type ) ;
2017-05-15 17:45:05 +02:00
2021-07-11 15:00:59 +02:00
Element * ifc_object = new Element ( element_settings , id , parent_id , product_name , instance_type , product_guid , " " , trsf , ifc_product ) ;
2014-12-19 12:14:36 +00:00
return ifc_object ;
}
2017-12-19 20:24:00 +01:00
IfcUtil : : IfcBaseClass * create ( ) {
2021-07-11 15:00:59 +02:00
IfcGeom : : BRepElement * next_shape_model = 0 ;
IfcGeom : : SerializedElement * next_serialization = 0 ;
IfcGeom : : TriangulationElement * next_triangulation = 0 ;
2016-03-18 11:23:25 +01:00
2014-12-19 12:14:36 +00:00
try {
2016-03-18 11:23:25 +01:00
next_shape_model = create_shape_model_for_next_entity ( ) ;
2017-08-01 16:45:11 +02:00
} catch ( const std : : exception & e ) {
Logger : : Error ( e ) ;
} catch ( const Standard_Failure & e ) {
if ( e . GetMessageString ( ) & & strlen ( e . GetMessageString ( ) ) ) {
Logger : : Error ( e . GetMessageString ( ) ) ;
} else {
Logger : : Error ( " Unknown error creating geometry " ) ;
}
} catch ( . . . ) {
Logger : : Error ( " Unknown error creating geometry " ) ;
}
2016-03-18 11:23:25 +01:00
2017-02-07 17:34:23 +02:00
if ( next_shape_model ) {
2016-03-22 16:15:28 +01:00
if ( settings . get ( IteratorSettings : : USE_BREP_DATA ) ) {
2016-03-18 11:23:25 +01:00
try {
2021-07-11 15:00:59 +02:00
next_serialization = new SerializedElement ( * next_shape_model ) ;
2016-03-18 11:23:25 +01:00
} catch ( . . . ) {
2016-05-13 12:59:00 +02:00
Logger : : Message ( Logger : : LOG_ERROR , " Getting a serialized element from model failed. " ) ;
2016-03-18 11:23:25 +01:00
}
2016-03-22 16:15:28 +01:00
} else if ( ! settings . get ( IteratorSettings : : DISABLE_TRIANGULATION ) ) {
2021-11-02 11:39:49 +01:00
// the part before the hyphen is the representation id
auto gid2 = next_shape_model - > geometry ( ) . id ( ) ;
auto hyphen = gid2 . find ( " - " ) ;
if ( hyphen ! = std : : string : : npos ) {
gid2 = gid2 . substr ( 0 , hyphen ) ;
2021-10-08 15:38:46 +02:00
}
2021-11-02 11:39:49 +01:00
next_triangulation = ( TriangulationElement * ) decorate_with_cache_ ( GeometrySerializer : : READ_TRIANGULATION , next_shape_model - > guid ( ) , gid2 , [ this , next_shape_model ] ( ) {
2021-10-08 15:38:46 +02:00
try {
if ( ifcproduct_iterator = = ifcproducts - > begin ( ) | | ! geometry_reuse_ok_for_current_representation_ ) {
2021-11-02 11:39:49 +01:00
return new TriangulationElement ( * next_shape_model ) ;
2021-10-08 15:38:46 +02:00
} else {
2021-11-02 11:39:49 +01:00
return new TriangulationElement ( * next_shape_model , current_triangulation - > geometry_pointer ( ) ) ;
2021-10-08 15:38:46 +02:00
}
} catch ( . . . ) {
Logger : : Message ( Logger : : LOG_ERROR , " Getting a triangulation element from model failed. " ) ;
2016-03-18 11:23:25 +01:00
}
2021-11-02 11:39:49 +01:00
return ( TriangulationElement * ) nullptr ;
} ) ;
2016-03-18 11:23:25 +01:00
}
2014-12-19 12:14:36 +00:00
}
2016-03-18 11:23:25 +01:00
free_shapes ( ) ;
2017-02-07 17:34:23 +02:00
current_shape_model = next_shape_model ;
2016-03-18 11:23:25 +01:00
current_serialization = next_serialization ;
current_triangulation = next_triangulation ;
2017-02-07 17:34:23 +02:00
return next_shape_model ? next_shape_model - > product ( ) : 0 ;
2014-12-19 12:14:36 +00:00
}
private :
2015-04-22 09:15:48 +00:00
void _initialize ( ) {
2014-12-19 12:14:36 +00:00
current_triangulation = 0 ;
current_shape_model = 0 ;
current_serialization = 0 ;
2015-02-19 20:17:53 +00:00
2014-12-19 12:14:36 +00:00
unit_name = " METER " ;
unit_magnitude = 1.f ;
2019-05-24 14:29:21 +02:00
kernel . setValue ( IfcGeom : : Kernel : : GV_MAX_FACES_TO_ORIENT , settings . get ( IteratorSettings : : SEW_SHELLS ) ? std : : numeric_limits < double > : : infinity ( ) : - 1 ) ;
2016-03-17 23:25:53 +02:00
kernel . setValue ( IfcGeom : : Kernel : : GV_DIMENSIONALITY , ( settings . get ( IteratorSettings : : INCLUDE_CURVES )
? ( settings . get ( IteratorSettings : : EXCLUDE_SOLIDS_AND_SURFACES ) ? - 1. : 0. ) : + 1. ) ) ;
2020-06-07 19:46:10 +02:00
kernel . setValue ( IfcGeom : : Kernel : : GV_LAYERSET_FIRST ,
settings . get ( IteratorSettings : : LAYERSET_FIRST )
? + 1.0
: - 1.0
) ;
2021-02-05 14:00:23 -06:00
kernel . setValue ( IfcGeom : : Kernel : : GV_NO_WIRE_INTERSECTION_CHECK ,
settings . get ( IteratorSettings : : NO_WIRE_INTERSECTION_CHECK )
? + 1.0
: - 1.0
) ;
2021-02-08 14:06:05 -06:00
kernel . setValue ( IfcGeom : : Kernel : : GV_NO_WIRE_INTERSECTION_TOLERANCE ,
settings . get ( IteratorSettings : : NO_WIRE_INTERSECTION_TOLERANCE )
? + 1.0
: - 1.0
) ;
2021-02-06 10:26:17 -06:00
kernel . setValue ( IfcGeom : : Kernel : : GV_PRECISION_FACTOR ,
settings . get ( IteratorSettings : : STRICT_TOLERANCE )
? 1.0
: 10.0
) ;
2021-02-05 14:00:23 -06:00
2020-11-24 16:58:05 +01:00
kernel . setValue ( IfcGeom : : Kernel : : GV_DISABLE_BOOLEAN_RESULT ,
settings . get ( IteratorSettings : : DISABLE_BOOLEAN_RESULT )
? + 1.0
: - 1.0
) ;
2020-06-07 19:46:10 +02:00
2018-02-14 15:17:37 +01:00
if ( settings . get ( IteratorSettings : : BUILDING_LOCAL_PLACEMENT ) ) {
if ( settings . get ( IteratorSettings : : SITE_LOCAL_PLACEMENT ) ) {
Logger : : Message ( Logger : : LOG_WARNING , " building-local-placement takes precedence over site-local-placement " ) ;
}
2018-07-07 17:15:54 +02:00
kernel . set_conversion_placement_rel_to ( & IfcSchema : : IfcBuilding : : Class ( ) ) ;
2018-02-14 15:17:37 +01:00
} else if ( settings . get ( IteratorSettings : : SITE_LOCAL_PLACEMENT ) ) {
2017-12-19 20:24:00 +01:00
kernel . set_conversion_placement_rel_to ( & IfcSchema : : IfcSite : : Class ( ) ) ;
2017-08-19 17:21:10 +02:00
}
2020-01-31 15:55:04 +01:00
kernel . set_offset ( settings . offset ) ;
kernel . set_rotation ( settings . rotation ) ;
2014-12-19 12:14:36 +00:00
}
2021-09-22 18:58:32 +10:00
2014-12-19 12:14:36 +00:00
public :
2019-07-19 15:55:22 +02:00
MAKE_TYPE_NAME ( IteratorImplementation_ ) ( const IteratorSettings & settings , IfcParse : : IfcFile * file , const std : : vector < IfcGeom : : filter_t > & filters , int num_threads )
2014-12-19 12:14:36 +00:00
: settings ( settings )
, ifc_file ( file )
2018-09-07 14:08:56 +02:00
, filters_ ( filters )
2015-06-20 14:23:59 +00:00
, owns_ifc_file ( false )
2019-07-03 12:10:27 +02:00
, num_threads_ ( num_threads )
2014-12-19 12:14:36 +00:00
{
2015-04-22 09:15:48 +00:00
_initialize ( ) ;
2014-12-19 12:14:36 +00:00
}
2017-12-19 20:24:00 +01:00
~ MAKE_TYPE_NAME ( IteratorImplementation_ ) ( ) {
2015-06-20 14:23:59 +00:00
if ( owns_ifc_file ) {
delete ifc_file ;
}
2014-12-19 12:14:36 +00:00
2019-12-14 13:23:40 +01:00
if ( ! settings . get ( IfcGeom : : IteratorSettings : : DISABLE_TRIANGULATION ) ) {
2019-07-09 16:34:35 +02:00
for ( auto & p : all_processed_native_elements_ ) {
delete p ;
}
}
for ( auto & p : all_processed_elements_ ) {
delete p ;
}
2016-03-18 11:23:25 +01:00
free_shapes ( ) ;
2014-12-19 12:14:36 +00:00
}
} ;
}
# endif