2015-05-19 03:48:29 +00:00
/*
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2024-02-23 21:30:05 +00:00
Copyright ( c ) 2006 - 2024 , assimp team
2015-05-19 03:48:29 +00:00
All rights reserved .
2015-05-19 03:52:10 +00:00
Redistribution and use of this software in source and binary forms ,
with or without modification , are permitted provided that the
2015-05-19 03:48:29 +00:00
following conditions are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the
following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the
following disclaimer in the documentation and / or other
materials provided with the distribution .
* Neither the name of the assimp team , nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team .
2015-05-19 03:52:10 +00:00
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
2015-05-19 03:48:29 +00:00
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2015-05-19 03:52:10 +00:00
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
2015-05-19 03:48:29 +00:00
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
2015-05-19 03:52:10 +00:00
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
2015-05-19 03:48:29 +00:00
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
2015-05-19 03:52:10 +00:00
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
2015-05-19 03:48:29 +00:00
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2023-09-09 17:29:15 +00:00
/// @file IFCGeometry.cpp
/// @brief Geometry conversion and synthesis for IFC
2015-05-19 03:48:29 +00:00
# ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
# include "IFCUtil.h"
2019-06-10 21:26:00 +00:00
# include "Common/PolyTools.h"
# include "PostProcessing/ProcessHelper.h"
2023-09-09 17:29:15 +00:00
# include "contrib/poly2tri/poly2tri/poly2tri.h"
# include "contrib/clipper/clipper.hpp"
2015-05-19 03:48:29 +00:00
# include <iterator>
2022-11-03 16:35:10 +00:00
# include <memory>
# include <utility>
2015-05-19 03:48:29 +00:00
namespace Assimp {
2019-06-10 21:26:00 +00:00
namespace IFC {
2015-05-19 03:48:29 +00:00
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
bool ProcessPolyloop ( const Schema_2x3 : : IfcPolyLoop & loop , TempMesh & meshout , ConversionData & /*conv*/ ) {
2015-05-19 03:57:13 +00:00
size_t cnt = 0 ;
2018-01-13 09:27:45 +00:00
for ( const Schema_2x3 : : IfcCartesianPoint & c : loop . Polygon ) {
2015-05-19 03:57:13 +00:00
IfcVector3 tmp ;
ConvertCartesianPoint ( tmp , c ) ;
2018-01-13 09:27:45 +00:00
meshout . mVerts . push_back ( tmp ) ;
2015-05-19 03:57:13 +00:00
+ + cnt ;
}
2018-01-13 09:27:45 +00:00
meshout . mVertcnt . push_back ( static_cast < unsigned int > ( cnt ) ) ;
2015-05-19 03:57:13 +00:00
// zero- or one- vertex polyloops simply ignored
2018-01-13 09:27:45 +00:00
if ( meshout . mVertcnt . back ( ) > 1 ) {
2015-05-19 03:57:13 +00:00
return true ;
}
2018-01-13 09:27:45 +00:00
if ( meshout . mVertcnt . back ( ) = = 1 ) {
meshout . mVertcnt . pop_back ( ) ;
meshout . mVerts . pop_back ( ) ;
2015-05-19 03:57:13 +00:00
}
return false ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void ProcessPolygonBoundaries ( TempMesh & result , const TempMesh & inmesh , size_t master_bounds = ( size_t ) - 1 ) {
2015-05-19 03:57:13 +00:00
// handle all trivial cases
2018-01-13 09:27:45 +00:00
if ( inmesh . mVertcnt . empty ( ) ) {
2015-05-19 03:57:13 +00:00
return ;
}
2018-01-13 09:27:45 +00:00
if ( inmesh . mVertcnt . size ( ) = = 1 ) {
2015-05-19 03:57:13 +00:00
result . Append ( inmesh ) ;
return ;
}
2020-03-08 20:24:01 +00:00
ai_assert ( std : : count ( inmesh . mVertcnt . begin ( ) , inmesh . mVertcnt . end ( ) , 0u ) = = 0 ) ;
2015-05-19 03:57:13 +00:00
typedef std : : vector < unsigned int > : : const_iterator face_iter ;
2018-01-13 09:27:45 +00:00
face_iter begin = inmesh . mVertcnt . begin ( ) , end = inmesh . mVertcnt . end ( ) , iit ;
2015-05-19 03:57:13 +00:00
std : : vector < unsigned int > : : const_iterator outer_polygon_it = end ;
// major task here: given a list of nested polygon boundaries (one of which
// is the outer contour), reduce the triangulation task arising here to
// one that can be solved using the "quadrulation" algorithm which we use
// for pouring windows out of walls. The algorithm does not handle all
// cases but at least it is numerically stable and gives "nice" triangles.
// first compute normals for all polygons using Newell's algorithm
// do not normalize 'normals', we need the original length for computing the polygon area
std : : vector < IfcVector3 > normals ;
inmesh . ComputePolygonNormals ( normals , false ) ;
// One of the polygons might be a IfcFaceOuterBound (in which case `master_bounds`
// is its index). Sadly we can't rely on it, the docs say 'At most one of the bounds
// shall be of the type IfcFaceOuterBound'
IfcFloat area_outer_polygon = 1e-10 f ;
if ( master_bounds ! = ( size_t ) - 1 ) {
2018-01-13 09:27:45 +00:00
ai_assert ( master_bounds < inmesh . mVertcnt . size ( ) ) ;
2015-05-19 03:57:13 +00:00
outer_polygon_it = begin + master_bounds ;
2023-09-09 17:29:15 +00:00
} else {
2019-08-29 08:54:21 +00:00
for ( iit = begin ; iit ! = end ; + + iit ) {
2015-05-19 03:57:13 +00:00
// find the polygon with the largest area and take it as the outer bound.
IfcVector3 & n = normals [ std : : distance ( begin , iit ) ] ;
const IfcFloat area = n . SquareLength ( ) ;
if ( area > area_outer_polygon ) {
area_outer_polygon = area ;
outer_polygon_it = iit ;
}
}
}
2023-09-09 17:29:15 +00:00
if ( outer_polygon_it = = end ) {
2019-12-08 09:12:14 +00:00
return ;
}
2015-05-19 03:57:13 +00:00
const size_t outer_polygon_size = * outer_polygon_it ;
const IfcVector3 & master_normal = normals [ std : : distance ( begin , outer_polygon_it ) ] ;
// Generate fake openings to meet the interface for the quadrulate
// algorithm. It boils down to generating small boxes given the
// inner polygon and the surface normal of the outer contour.
// It is important that we use the outer contour's normal because
// this is the plane onto which the quadrulate algorithm will
// project the entire mesh.
std : : vector < TempOpening > fake_openings ;
2018-01-13 09:27:45 +00:00
fake_openings . reserve ( inmesh . mVertcnt . size ( ) - 1 ) ;
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
std : : vector < IfcVector3 > : : const_iterator vit = inmesh . mVerts . begin ( ) , outer_vit ;
2015-05-19 03:57:13 +00:00
for ( iit = begin ; iit ! = end ; vit + = * iit + + ) {
if ( iit = = outer_polygon_it ) {
outer_vit = vit ;
continue ;
}
// Filter degenerate polygons to keep them from causing trouble later on
IfcVector3 & n = normals [ std : : distance ( begin , iit ) ] ;
const IfcFloat area = n . SquareLength ( ) ;
if ( area < 1e-5 f ) {
IFCImporter : : LogWarn ( " skipping degenerate polygon (ProcessPolygonBoundaries) " ) ;
continue ;
}
2022-08-23 15:41:49 +00:00
fake_openings . emplace_back ( ) ;
2015-05-19 03:57:13 +00:00
TempOpening & opening = fake_openings . back ( ) ;
opening . extrusionDir = master_normal ;
2020-06-23 19:05:42 +00:00
opening . solid = nullptr ;
2015-05-19 03:57:13 +00:00
2016-04-05 21:23:53 +00:00
opening . profileMesh = std : : make_shared < TempMesh > ( ) ;
2018-01-13 09:27:45 +00:00
opening . profileMesh - > mVerts . reserve ( * iit ) ;
opening . profileMesh - > mVertcnt . push_back ( * iit ) ;
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
std : : copy ( vit , vit + * iit , std : : back_inserter ( opening . profileMesh - > mVerts ) ) ;
2015-05-19 03:57:13 +00:00
}
// fill a mesh with ONLY the main polygon
TempMesh temp ;
2018-01-13 09:27:45 +00:00
temp . mVerts . reserve ( outer_polygon_size ) ;
temp . mVertcnt . push_back ( static_cast < unsigned int > ( outer_polygon_size ) ) ;
2015-05-19 03:57:13 +00:00
std : : copy ( outer_vit , outer_vit + outer_polygon_size ,
2018-01-13 09:27:45 +00:00
std : : back_inserter ( temp . mVerts ) ) ;
2015-05-19 03:57:13 +00:00
2022-01-17 14:59:17 +00:00
GenerateOpenings ( fake_openings , temp , false , false ) ;
2015-05-19 03:57:13 +00:00
result . Append ( temp ) ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2018-01-13 09:27:45 +00:00
void ProcessConnectedFaceSet ( const Schema_2x3 : : IfcConnectedFaceSet & fset , TempMesh & result , ConversionData & conv )
2015-05-19 03:48:29 +00:00
{
2018-01-13 09:27:45 +00:00
for ( const Schema_2x3 : : IfcFace & face : fset . CfsFaces ) {
2015-05-19 03:57:13 +00:00
// size_t ob = -1, cnt = 0;
TempMesh meshout ;
2018-01-13 09:27:45 +00:00
for ( const Schema_2x3 : : IfcFaceBound & bound : face . Bounds ) {
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
if ( const Schema_2x3 : : IfcPolyLoop * const polyloop = bound . Bound - > ToPtr < Schema_2x3 : : IfcPolyLoop > ( ) ) {
2015-05-19 03:57:13 +00:00
if ( ProcessPolyloop ( * polyloop , meshout , conv ) ) {
// The outer boundary is better determined by checking which
// polygon covers the largest area.
}
2023-09-09 17:29:15 +00:00
} else {
2021-05-13 11:05:31 +00:00
IFCImporter : : LogWarn ( " skipping unknown IfcFaceBound entity, type is " , bound . Bound - > GetClassName ( ) ) ;
2015-05-19 03:57:13 +00:00
continue ;
}
}
ProcessPolygonBoundaries ( result , meshout ) ;
}
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void ProcessRevolvedAreaSolid ( const Schema_2x3 : : IfcRevolvedAreaSolid & solid , TempMesh & result , ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
TempMesh meshout ;
// first read the profile description
2018-01-13 09:27:45 +00:00
if ( ! ProcessProfile ( * solid . SweptArea , meshout , conv ) | | meshout . mVerts . size ( ) < = 1 ) {
2015-05-19 03:57:13 +00:00
return ;
}
IfcVector3 axis , pos ;
ConvertAxisPlacement ( axis , pos , solid . Axis ) ;
IfcMatrix4 tb0 , tb1 ;
IfcMatrix4 : : Translation ( pos , tb0 ) ;
IfcMatrix4 : : Translation ( - pos , tb1 ) ;
2018-01-13 09:27:45 +00:00
const std : : vector < IfcVector3 > & in = meshout . mVerts ;
2015-05-19 03:57:13 +00:00
const size_t size = in . size ( ) ;
bool has_area = solid . SweptArea - > ProfileType = = " AREA " & & size > 2 ;
const IfcFloat max_angle = solid . Angle * conv . angle_scale ;
if ( std : : fabs ( max_angle ) < 1e-3 ) {
if ( has_area ) {
result = meshout ;
}
return ;
}
2023-09-09 17:29:15 +00:00
const unsigned int cnt_segments =
std : : max ( 2u , static_cast < unsigned int > ( conv . settings . cylindricalTessellation * std : : fabs ( max_angle ) / AI_MATH_HALF_PI_F ) ) ;
2015-05-19 03:57:13 +00:00
const IfcFloat delta = max_angle / cnt_segments ;
has_area = has_area & & std : : fabs ( max_angle ) < AI_MATH_TWO_PI_F * 0.99 ;
2018-01-13 09:27:45 +00:00
result . mVerts . reserve ( size * ( ( cnt_segments + 1 ) * 4 + ( has_area ? 2 : 0 ) ) ) ;
result . mVertcnt . reserve ( size * cnt_segments + 2 ) ;
2015-05-19 03:57:13 +00:00
IfcMatrix4 rot ;
rot = tb0 * IfcMatrix4 : : Rotation ( delta , axis , rot ) * tb1 ;
size_t base = 0 ;
2018-01-13 09:27:45 +00:00
std : : vector < IfcVector3 > & out = result . mVerts ;
2015-05-19 03:57:13 +00:00
// dummy data to simplify later processing
for ( size_t i = 0 ; i < size ; + + i ) {
out . insert ( out . end ( ) , 4 , in [ i ] ) ;
}
for ( unsigned int seg = 0 ; seg < cnt_segments ; + + seg ) {
for ( size_t i = 0 ; i < size ; + + i ) {
const size_t next = ( i + 1 ) % size ;
2018-01-13 09:27:45 +00:00
result . mVertcnt . push_back ( 4 ) ;
2016-08-30 17:46:34 +00:00
const IfcVector3 base_0 = out [ base + i * 4 + 3 ] , base_1 = out [ base + next * 4 + 3 ] ;
2015-05-19 03:57:13 +00:00
out . push_back ( base_0 ) ;
out . push_back ( base_1 ) ;
out . push_back ( rot * base_1 ) ;
out . push_back ( rot * base_0 ) ;
}
base + = size * 4 ;
}
out . erase ( out . begin ( ) , out . begin ( ) + size * 4 ) ;
if ( has_area ) {
// leave the triangulation of the profile area to the ear cutting
// implementation in aiProcess_Triangulate - for now we just
// feed in two huge polygons.
base - = size * 8 ;
for ( size_t i = size ; i - - ; ) {
out . push_back ( out [ base + i * 4 + 3 ] ) ;
}
for ( size_t i = 0 ; i < size ; + + i ) {
out . push_back ( out [ i * 4 ] ) ;
}
2018-01-13 09:27:45 +00:00
result . mVertcnt . push_back ( static_cast < unsigned int > ( size ) ) ;
result . mVertcnt . push_back ( static_cast < unsigned int > ( size ) ) ;
2015-05-19 03:57:13 +00:00
}
IfcMatrix4 trafo ;
ConvertAxisPlacement ( trafo , solid . Position ) ;
result . Transform ( trafo ) ;
2020-05-18 10:55:14 +00:00
IFCImporter : : LogVerboseDebug ( " generate mesh procedurally by radial extrusion (IfcRevolvedAreaSolid) " ) ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void ProcessSweptDiskSolid ( const Schema_2x3 : : IfcSweptDiskSolid & solid ,
TempMesh & result ,
ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
const Curve * const curve = Curve : : Convert ( * solid . Directrix , conv ) ;
if ( ! curve ) {
IFCImporter : : LogError ( " failed to convert Directrix curve (IfcSweptDiskSolid) " ) ;
return ;
}
2017-03-17 13:55:18 +00:00
const unsigned int cnt_segments = conv . settings . cylindricalTessellation ;
2015-05-19 03:57:13 +00:00
const IfcFloat deltaAngle = AI_MATH_TWO_PI / cnt_segments ;
2018-01-03 15:14:20 +00:00
TempMesh temp ;
curve - > SampleDiscrete ( temp , solid . StartParam , solid . EndParam ) ;
2018-01-13 09:27:45 +00:00
const std : : vector < IfcVector3 > & curve_points = temp . mVerts ;
2018-01-03 15:14:20 +00:00
const size_t samples = curve_points . size ( ) ;
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
result . mVerts . reserve ( cnt_segments * samples * 4 ) ;
result . mVertcnt . reserve ( ( cnt_segments - 1 ) * samples ) ;
2015-05-19 03:57:13 +00:00
std : : vector < IfcVector3 > points ;
points . reserve ( cnt_segments * samples ) ;
if ( curve_points . empty ( ) ) {
IFCImporter : : LogWarn ( " curve evaluation yielded no points (IfcSweptDiskSolid) " ) ;
return ;
}
IfcVector3 current = curve_points [ 0 ] ;
IfcVector3 previous = current ;
IfcVector3 next ;
IfcVector3 startvec ;
startvec . x = 1.0f ;
startvec . y = 1.0f ;
startvec . z = 1.0f ;
unsigned int last_dir = 0 ;
// generate circles at the sweep positions
for ( size_t i = 0 ; i < samples ; + + i ) {
if ( i ! = samples - 1 ) {
next = curve_points [ i + 1 ] ;
}
// get a direction vector reflecting the approximate curvature (i.e. tangent)
IfcVector3 d = ( current - previous ) + ( next - previous ) ;
d . Normalize ( ) ;
// figure out an arbitrary point q so that (p-q) * d = 0,
// try to maximize ||(p-q)|| * ||(p_last-q_last)||
IfcVector3 q ;
bool take_any = false ;
2020-03-08 20:24:01 +00:00
for ( unsigned int j = 0 ; j < 2 ; + + j , take_any = true ) {
2022-02-16 19:07:27 +00:00
if ( ( last_dir = = 0 | | take_any ) & & std : : abs ( d . x ) > ai_epsilon ) {
2015-05-19 03:57:13 +00:00
q . y = startvec . y ;
q . z = startvec . z ;
q . x = - ( d . y * q . y + d . z * q . z ) / d . x ;
last_dir = 0 ;
break ;
2022-02-16 19:07:27 +00:00
} else if ( ( last_dir = = 1 | | take_any ) & & std : : abs ( d . y ) > ai_epsilon ) {
2015-05-19 03:57:13 +00:00
q . x = startvec . x ;
q . z = startvec . z ;
q . y = - ( d . x * q . x + d . z * q . z ) / d . y ;
last_dir = 1 ;
break ;
2022-02-16 19:07:27 +00:00
} else if ( ( last_dir = = 2 & & std : : abs ( d . z ) > ai_epsilon ) | | take_any ) {
2015-05-19 03:57:13 +00:00
q . y = startvec . y ;
q . x = startvec . x ;
q . z = - ( d . y * q . y + d . x * q . x ) / d . z ;
last_dir = 2 ;
break ;
}
}
q * = solid . Radius / q . Length ( ) ;
startvec = q ;
// generate a rotation matrix to rotate q around d
IfcMatrix4 rot ;
IfcMatrix4 : : Rotation ( deltaAngle , d , rot ) ;
for ( unsigned int seg = 0 ; seg < cnt_segments ; + + seg , q * = rot ) {
points . push_back ( q + current ) ;
}
previous = current ;
current = next ;
}
// make quads
for ( size_t i = 0 ; i < samples - 1 ; + + i ) {
const aiVector3D & this_start = points [ i * cnt_segments ] ;
// locate corresponding point on next sample ring
unsigned int best_pair_offset = 0 ;
float best_distance_squared = 1e10 f ;
for ( unsigned int seg = 0 ; seg < cnt_segments ; + + seg ) {
const aiVector3D & p = points [ ( i + 1 ) * cnt_segments + seg ] ;
const float l = ( p - this_start ) . SquareLength ( ) ;
if ( l < best_distance_squared ) {
best_pair_offset = seg ;
best_distance_squared = l ;
}
}
for ( unsigned int seg = 0 ; seg < cnt_segments ; + + seg ) {
2018-01-13 09:27:45 +00:00
result . mVerts . push_back ( points [ i * cnt_segments + ( seg % cnt_segments ) ] ) ;
result . mVerts . push_back ( points [ i * cnt_segments + ( seg + 1 ) % cnt_segments ] ) ;
result . mVerts . push_back ( points [ ( i + 1 ) * cnt_segments + ( ( seg + 1 + best_pair_offset ) % cnt_segments ) ] ) ;
result . mVerts . push_back ( points [ ( i + 1 ) * cnt_segments + ( ( seg + best_pair_offset ) % cnt_segments ) ] ) ;
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
IfcVector3 & v1 = * ( result . mVerts . end ( ) - 1 ) ;
IfcVector3 & v2 = * ( result . mVerts . end ( ) - 2 ) ;
IfcVector3 & v3 = * ( result . mVerts . end ( ) - 3 ) ;
IfcVector3 & v4 = * ( result . mVerts . end ( ) - 4 ) ;
2015-05-19 03:57:13 +00:00
if ( ( ( v4 - v3 ) ^ ( v4 - v1 ) ) * ( v4 - curve_points [ i ] ) < 0.0f ) {
std : : swap ( v4 , v1 ) ;
std : : swap ( v3 , v2 ) ;
}
2018-01-13 09:27:45 +00:00
result . mVertcnt . push_back ( 4 ) ;
2015-05-19 03:57:13 +00:00
}
}
2020-05-18 10:55:14 +00:00
IFCImporter : : LogVerboseDebug ( " generate mesh procedurally by sweeping a disk along a curve (IfcSweptDiskSolid) " ) ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
IfcMatrix3 DerivePlaneCoordinateSpace ( const TempMesh & curmesh , bool & ok , IfcVector3 & norOut ) {
2018-01-13 09:27:45 +00:00
const std : : vector < IfcVector3 > & out = curmesh . mVerts ;
2015-05-19 03:57:13 +00:00
IfcMatrix3 m ;
ok = true ;
// The input "mesh" must be a single polygon
const size_t s = out . size ( ) ;
2018-01-13 09:27:45 +00:00
ai_assert ( curmesh . mVertcnt . size ( ) = = 1 ) ;
ai_assert ( curmesh . mVertcnt . back ( ) = = s ) ;
2015-05-19 03:57:13 +00:00
const IfcVector3 any_point = out [ s - 1 ] ;
IfcVector3 nor ;
// The input polygon is arbitrarily shaped, therefore we might need some tries
// until we find a suitable normal. Note that Newell's algorithm would give
// a more robust result, but this variant also gives us a suitable first
// axis for the 2D coordinate space on the polygon plane, exploiting the
// fact that the input polygon is nearly always a quad.
bool done = false ;
2018-01-13 09:27:45 +00:00
size_t idx ( 0 ) ;
for ( size_t i = 0 ; ! done & & i < s - 2 ; done | | + + i ) {
idx = i ;
for ( size_t j = i + 1 ; j < s - 1 ; + + j ) {
2015-05-19 03:57:13 +00:00
nor = - ( ( out [ i ] - any_point ) ^ ( out [ j ] - any_point ) ) ;
if ( std : : fabs ( nor . Length ( ) ) > 1e-8 f ) {
done = true ;
break ;
}
}
}
if ( ! done ) {
ok = false ;
return m ;
}
nor . Normalize ( ) ;
norOut = nor ;
2018-01-13 09:27:45 +00:00
IfcVector3 r = ( out [ idx ] - any_point ) ;
2015-05-19 03:57:13 +00:00
r . Normalize ( ) ;
// Reconstruct orthonormal basis
// XXX use Gram Schmidt for increased robustness
IfcVector3 u = r ^ nor ;
u . Normalize ( ) ;
m . a1 = r . x ;
m . a2 = r . y ;
m . a3 = r . z ;
m . b1 = u . x ;
m . b2 = u . y ;
m . b3 = u . z ;
m . c1 = - nor . x ;
m . c2 = - nor . y ;
m . c3 = - nor . z ;
return m ;
2015-05-19 03:48:29 +00:00
}
2022-02-16 20:19:17 +00:00
const auto closeDistance = ai_epsilon ;
2022-01-17 14:59:17 +00:00
bool areClose ( Schema_2x3 : : IfcCartesianPoint pt1 , Schema_2x3 : : IfcCartesianPoint pt2 ) {
2023-09-09 17:29:15 +00:00
if ( pt1 . Coordinates . size ( ) ! = pt2 . Coordinates . size ( ) ) {
2022-01-17 14:59:17 +00:00
IFCImporter : : LogWarn ( " unable to compare differently-dimensioned points " ) ;
return false ;
}
auto coord1 = pt1 . Coordinates . begin ( ) ;
auto coord2 = pt2 . Coordinates . begin ( ) ;
// we're just testing each dimension separately rather than doing euclidean distance, as we're
// looking for very close coordinates
2023-09-09 17:29:15 +00:00
for ( ; coord1 ! = pt1 . Coordinates . end ( ) ; coord1 + + , coord2 + + ) {
if ( std : : fabs ( * coord1 - * coord2 ) > closeDistance ) {
2022-01-17 14:59:17 +00:00
return false ;
2023-09-09 17:29:15 +00:00
}
2022-01-17 14:59:17 +00:00
}
return true ;
}
bool areClose ( IfcVector3 pt1 , IfcVector3 pt2 ) {
return ( std : : fabs ( pt1 . x - pt2 . x ) < closeDistance & &
std : : fabs ( pt1 . y - pt2 . y ) < closeDistance & &
std : : fabs ( pt1 . z - pt2 . z ) < closeDistance ) ;
}
2023-09-09 17:29:15 +00:00
2015-05-19 03:48:29 +00:00
// Extrudes the given polygon along the direction, converts it into an opening or applies all openings as necessary.
2018-01-13 09:27:45 +00:00
void ProcessExtrudedArea ( const Schema_2x3 : : IfcExtrudedAreaSolid & solid , const TempMesh & curve ,
2015-05-19 03:57:13 +00:00
const IfcVector3 & extrusionDir , TempMesh & result , ConversionData & conv , bool collect_openings )
2015-05-19 03:48:29 +00:00
{
2015-05-19 03:57:13 +00:00
// Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
// forming new triangles.
2018-01-13 09:27:45 +00:00
const bool has_area = solid . SweptArea - > ProfileType = = " AREA " & & curve . mVerts . size ( ) > 2 ;
2022-02-16 19:07:27 +00:00
if ( solid . Depth < ai_epsilon ) {
2015-05-19 03:57:13 +00:00
if ( has_area ) {
result . Append ( curve ) ;
}
return ;
}
2018-01-13 09:27:45 +00:00
result . mVerts . reserve ( curve . mVerts . size ( ) * ( has_area ? 4 : 2 ) ) ;
result . mVertcnt . reserve ( curve . mVerts . size ( ) + 2 ) ;
std : : vector < IfcVector3 > in = curve . mVerts ;
2015-05-19 03:57:13 +00:00
// First step: transform all vertices into the target coordinate space
IfcMatrix4 trafo ;
ConvertAxisPlacement ( trafo , solid . Position ) ;
IfcVector3 vmin , vmax ;
MinMaxChooser < IfcVector3 > ( ) ( vmin , vmax ) ;
2016-04-05 20:53:54 +00:00
for ( IfcVector3 & v : in ) {
2015-05-19 03:57:13 +00:00
v * = trafo ;
vmin = std : : min ( vmin , v ) ;
vmax = std : : max ( vmax , v ) ;
}
vmax - = vmin ;
const IfcFloat diag = vmax . Length ( ) ;
IfcVector3 dir = IfcMatrix3 ( trafo ) * extrusionDir ;
// reverse profile polygon if it's winded in the wrong direction in relation to the extrusion direction
IfcVector3 profileNormal = TempMesh : : ComputePolygonNormal ( in . data ( ) , in . size ( ) ) ;
2023-09-09 17:29:15 +00:00
if ( profileNormal * dir < 0.0 ) {
2015-05-19 03:57:13 +00:00
std : : reverse ( in . begin ( ) , in . end ( ) ) ;
2023-09-09 17:29:15 +00:00
}
2015-05-19 03:57:13 +00:00
std : : vector < IfcVector3 > nors ;
const bool openings = ! ! conv . apply_openings & & conv . apply_openings - > size ( ) ;
// Compute the normal vectors for all opening polygons as a prerequisite
// to TryAddOpenings_Poly2Tri()
// XXX this belongs into the aforementioned function
if ( openings ) {
if ( ! conv . settings . useCustomTriangulation ) {
// it is essential to apply the openings in the correct spatial order. The direction
// doesn't matter, but we would screw up if we started with e.g. a door in between
// two windows.
std : : sort ( conv . apply_openings - > begin ( ) , conv . apply_openings - > end ( ) , TempOpening : : DistanceSorter ( in [ 0 ] ) ) ;
}
nors . reserve ( conv . apply_openings - > size ( ) ) ;
2016-04-05 20:53:54 +00:00
for ( TempOpening & t : * conv . apply_openings ) {
2022-11-08 16:03:55 +00:00
TempMesh & bounds = * t . profileMesh ;
2015-05-19 03:57:13 +00:00
2018-01-13 09:27:45 +00:00
if ( bounds . mVerts . size ( ) < = 2 ) {
2022-08-23 15:41:49 +00:00
nors . emplace_back ( ) ;
2015-05-19 03:57:13 +00:00
continue ;
}
2022-01-17 14:59:17 +00:00
auto nor = ( ( bounds . mVerts [ 2 ] - bounds . mVerts [ 0 ] ) ^ ( bounds . mVerts [ 1 ] - bounds . mVerts [ 0 ] ) ) . Normalize ( ) ;
auto vI0 = bounds . mVertcnt [ 0 ] ;
for ( size_t faceI = 0 ; faceI < bounds . mVertcnt . size ( ) ; faceI + + )
{
if ( bounds . mVertcnt [ faceI ] > = 3 ) {
// do a check that this is at least parallel to the base plane
auto nor2 = ( ( bounds . mVerts [ vI0 + 2 ] - bounds . mVerts [ vI0 ] ) ^ ( bounds . mVerts [ vI0 + 1 ] - bounds . mVerts [ vI0 ] ) ) . Normalize ( ) ;
if ( ! areClose ( nor , nor2 ) ) {
std : : stringstream msg ;
msg < < " Face " < < faceI < < " is not parallel with face 0 - opening on entity " < < solid . GetID ( ) ;
IFCImporter : : LogWarn ( msg . str ( ) . c_str ( ) ) ;
}
}
}
nors . push_back ( nor ) ;
2015-05-19 03:57:13 +00:00
}
}
TempMesh temp ;
TempMesh & curmesh = openings ? temp : result ;
2018-01-13 09:27:45 +00:00
std : : vector < IfcVector3 > & out = curmesh . mVerts ;
2015-05-19 03:57:13 +00:00
size_t sides_with_openings = 0 ;
for ( size_t i = 0 ; i < in . size ( ) ; + + i ) {
const size_t next = ( i + 1 ) % in . size ( ) ;
2018-01-13 09:27:45 +00:00
curmesh . mVertcnt . push_back ( 4 ) ;
2015-05-19 03:57:13 +00:00
out . push_back ( in [ i ] ) ;
out . push_back ( in [ next ] ) ;
out . push_back ( in [ next ] + dir ) ;
out . push_back ( in [ i ] + dir ) ;
if ( openings ) {
2022-01-17 14:59:17 +00:00
if ( ( in [ i ] - in [ next ] ) . Length ( ) > diag * 0.1 & & GenerateOpenings ( * conv . apply_openings , temp , true , true , dir ) ) {
2015-05-19 03:57:13 +00:00
+ + sides_with_openings ;
}
result . Append ( temp ) ;
temp . Clear ( ) ;
}
}
2022-01-17 14:59:17 +00:00
if ( openings ) {
2016-04-05 20:53:54 +00:00
for ( TempOpening & opening : * conv . apply_openings ) {
2022-01-17 14:59:17 +00:00
if ( ! opening . wallPoints . empty ( ) ) {
std : : stringstream msg ;
msg < < " failed to generate all window caps on ID " < < ( int ) solid . GetID ( ) ;
IFCImporter : : LogError ( msg . str ( ) . c_str ( ) ) ;
2015-05-19 03:57:13 +00:00
}
opening . wallPoints . clear ( ) ;
}
}
size_t sides_with_v_openings = 0 ;
2022-01-17 14:59:17 +00:00
if ( has_area ) {
2015-05-19 03:57:13 +00:00
2022-01-17 14:59:17 +00:00
for ( size_t n = 0 ; n < 2 ; + + n ) {
if ( n > 0 ) {
for ( size_t i = 0 ; i < in . size ( ) ; + + i )
2015-05-19 03:57:13 +00:00
out . push_back ( in [ i ] + dir ) ;
2023-09-09 17:29:15 +00:00
} else {
2022-01-17 14:59:17 +00:00
for ( size_t i = in . size ( ) ; i - - ; )
2015-05-19 03:57:13 +00:00
out . push_back ( in [ i ] ) ;
}
2018-01-13 09:27:45 +00:00
curmesh . mVertcnt . push_back ( static_cast < unsigned int > ( in . size ( ) ) ) ;
2022-01-17 14:59:17 +00:00
if ( openings & & in . size ( ) > 2 ) {
if ( GenerateOpenings ( * conv . apply_openings , temp , true , true , dir ) ) {
2015-05-19 03:57:13 +00:00
+ + sides_with_v_openings ;
}
result . Append ( temp ) ;
temp . Clear ( ) ;
}
}
}
2022-01-17 14:59:17 +00:00
if ( openings & & ( sides_with_openings = = 1 | | sides_with_v_openings = = 2 ) ) {
std : : stringstream msg ;
msg < < " failed to resolve all openings, presumably their topology is not supported by Assimp - ID " < < solid . GetID ( ) < < " sides_with_openings " < < sides_with_openings < < " sides_with_v_openings " < < sides_with_v_openings ;
IFCImporter : : LogWarn ( msg . str ( ) . c_str ( ) ) ;
2015-05-19 03:57:13 +00:00
}
2020-05-18 10:55:14 +00:00
IFCImporter : : LogVerboseDebug ( " generate mesh procedurally by extrusion (IfcExtrudedAreaSolid) " ) ;
2015-05-19 03:57:13 +00:00
// If this is an opening element, store both the extruded mesh and the 2D profile mesh
// it was created from. Return an empty mesh to the caller.
if ( collect_openings & & ! result . IsEmpty ( ) ) {
ai_assert ( conv . collect_openings ) ;
2016-04-05 21:23:53 +00:00
std : : shared_ptr < TempMesh > profile = std : : shared_ptr < TempMesh > ( new TempMesh ( ) ) ;
2015-05-19 03:57:13 +00:00
profile - > Swap ( result ) ;
2016-04-05 21:23:53 +00:00
std : : shared_ptr < TempMesh > profile2D = std : : shared_ptr < TempMesh > ( new TempMesh ( ) ) ;
2018-01-13 09:27:45 +00:00
profile2D - > mVerts . insert ( profile2D - > mVerts . end ( ) , in . begin ( ) , in . end ( ) ) ;
profile2D - > mVertcnt . push_back ( static_cast < unsigned int > ( in . size ( ) ) ) ;
2022-11-03 16:35:10 +00:00
conv . collect_openings - > push_back ( TempOpening ( & solid , dir , std : : move ( profile ) , std : : move ( profile2D ) ) ) ;
2015-05-19 03:57:13 +00:00
ai_assert ( result . IsEmpty ( ) ) ;
}
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void ProcessExtrudedAreaSolid ( const Schema_2x3 : : IfcExtrudedAreaSolid & solid ,
TempMesh & result ,
ConversionData & conv ,
bool collect_openings ) {
2015-05-19 03:57:13 +00:00
TempMesh meshout ;
// First read the profile description.
2018-01-13 09:27:45 +00:00
if ( ! ProcessProfile ( * solid . SweptArea , meshout , conv ) | | meshout . mVerts . size ( ) < = 1 ) {
2015-05-19 03:57:13 +00:00
return ;
}
IfcVector3 dir ;
ConvertDirection ( dir , solid . ExtrudedDirection ) ;
dir * = solid . Depth ;
// Some profiles bring their own holes, for which we need to provide a container. This all is somewhat backwards,
// and there's still so many corner cases uncovered - we really need a generic solution to all of this hole carving.
std : : vector < TempOpening > fisherPriceMyFirstOpenings ;
std : : vector < TempOpening > * oldApplyOpenings = conv . apply_openings ;
2018-01-13 09:27:45 +00:00
if ( const Schema_2x3 : : IfcArbitraryProfileDefWithVoids * const cprofile = solid . SweptArea - > ToPtr < Schema_2x3 : : IfcArbitraryProfileDefWithVoids > ( ) ) {
2015-05-19 03:57:13 +00:00
if ( ! cprofile - > InnerCurves . empty ( ) ) {
// read all inner curves and extrude them to form proper openings.
std : : vector < TempOpening > * oldCollectOpenings = conv . collect_openings ;
conv . collect_openings = & fisherPriceMyFirstOpenings ;
2018-01-13 09:27:45 +00:00
for ( const Schema_2x3 : : IfcCurve * curve : cprofile - > InnerCurves ) {
2015-05-19 03:57:13 +00:00
TempMesh curveMesh , tempMesh ;
ProcessCurve ( * curve , curveMesh , conv ) ;
ProcessExtrudedArea ( solid , curveMesh , dir , tempMesh , conv , true ) ;
}
// and then apply those to the geometry we're about to generate
conv . apply_openings = conv . collect_openings ;
conv . collect_openings = oldCollectOpenings ;
}
}
ProcessExtrudedArea ( solid , meshout , dir , result , conv , collect_openings ) ;
conv . apply_openings = oldApplyOpenings ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void ProcessSweptAreaSolid ( const Schema_2x3 : : IfcSweptAreaSolid & swept ,
TempMesh & meshout ,
ConversionData & conv ) {
2018-01-13 09:27:45 +00:00
if ( const Schema_2x3 : : IfcExtrudedAreaSolid * const solid = swept . ToPtr < Schema_2x3 : : IfcExtrudedAreaSolid > ( ) ) {
2015-05-19 03:57:13 +00:00
ProcessExtrudedAreaSolid ( * solid , meshout , conv , ! ! conv . collect_openings ) ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcRevolvedAreaSolid * const rev = swept . ToPtr < Schema_2x3 : : IfcRevolvedAreaSolid > ( ) ) {
2015-05-19 03:57:13 +00:00
ProcessRevolvedAreaSolid ( * rev , meshout , conv ) ;
2023-09-09 17:29:15 +00:00
} else {
2021-05-13 11:05:31 +00:00
IFCImporter : : LogWarn ( " skipping unknown IfcSweptAreaSolid entity, type is " , swept . GetClassName ( ) ) ;
2015-05-19 03:57:13 +00:00
}
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
bool ProcessGeometricItem ( const Schema_2x3 : : IfcRepresentationItem & geo ,
unsigned int matid ,
std : : set < unsigned int > & mesh_indices ,
ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
bool fix_orientation = false ;
2016-04-05 21:23:53 +00:00
std : : shared_ptr < TempMesh > meshtmp = std : : make_shared < TempMesh > ( ) ;
2018-01-13 09:27:45 +00:00
if ( const Schema_2x3 : : IfcShellBasedSurfaceModel * shellmod = geo . ToPtr < Schema_2x3 : : IfcShellBasedSurfaceModel > ( ) ) {
2021-06-22 16:27:15 +00:00
for ( const std : : shared_ptr < const Schema_2x3 : : IfcShell > & shell : shellmod - > SbsmBoundary ) {
2015-05-19 03:57:13 +00:00
try {
2018-01-13 09:27:45 +00:00
const : : Assimp : : STEP : : EXPRESS : : ENTITY & e = shell - > To < : : Assimp : : STEP : : EXPRESS : : ENTITY > ( ) ;
const Schema_2x3 : : IfcConnectedFaceSet & fs = conv . db . MustGetObject ( e ) . To < Schema_2x3 : : IfcConnectedFaceSet > ( ) ;
2015-05-19 03:57:13 +00:00
2022-11-08 16:03:55 +00:00
ProcessConnectedFaceSet ( fs , * meshtmp , conv ) ;
2023-09-09 17:29:15 +00:00
} catch ( std : : bad_cast & ) {
2015-05-19 03:57:13 +00:00
IFCImporter : : LogWarn ( " unexpected type error, IfcShell ought to inherit from IfcConnectedFaceSet " ) ;
}
}
fix_orientation = true ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcConnectedFaceSet * fset = geo . ToPtr < Schema_2x3 : : IfcConnectedFaceSet > ( ) ) {
2022-11-08 16:03:55 +00:00
ProcessConnectedFaceSet ( * fset , * meshtmp , conv ) ;
2015-05-19 03:57:13 +00:00
fix_orientation = true ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcSweptAreaSolid * swept = geo . ToPtr < Schema_2x3 : : IfcSweptAreaSolid > ( ) ) {
2022-11-08 16:03:55 +00:00
ProcessSweptAreaSolid ( * swept , * meshtmp , conv ) ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcSweptDiskSolid * disk = geo . ToPtr < Schema_2x3 : : IfcSweptDiskSolid > ( ) ) {
2022-11-08 16:03:55 +00:00
ProcessSweptDiskSolid ( * disk , * meshtmp , conv ) ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcManifoldSolidBrep * brep = geo . ToPtr < Schema_2x3 : : IfcManifoldSolidBrep > ( ) ) {
2022-11-08 16:03:55 +00:00
ProcessConnectedFaceSet ( brep - > Outer , * meshtmp , conv ) ;
2015-05-19 03:57:13 +00:00
fix_orientation = true ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcFaceBasedSurfaceModel * surf = geo . ToPtr < Schema_2x3 : : IfcFaceBasedSurfaceModel > ( ) ) {
2018-01-13 09:27:45 +00:00
for ( const Schema_2x3 : : IfcConnectedFaceSet & fc : surf - > FbsmFaces ) {
2022-11-08 16:03:55 +00:00
ProcessConnectedFaceSet ( fc , * meshtmp , conv ) ;
2015-05-19 03:57:13 +00:00
}
fix_orientation = true ;
2023-09-09 17:29:15 +00:00
} else if ( const Schema_2x3 : : IfcBooleanResult * boolean = geo . ToPtr < Schema_2x3 : : IfcBooleanResult > ( ) ) {
2022-11-08 16:03:55 +00:00
ProcessBoolean ( * boolean , * meshtmp , conv ) ;
2023-09-09 17:29:15 +00:00
} else if ( geo . ToPtr < Schema_2x3 : : IfcBoundingBox > ( ) ) {
2015-05-19 03:57:13 +00:00
// silently skip over bounding boxes
return false ;
2023-09-09 17:29:15 +00:00
} else {
2022-01-17 14:59:17 +00:00
std : : stringstream toLog ;
toLog < < " skipping unknown IfcGeometricRepresentationItem entity, type is " < < geo . GetClassName ( ) < < " id is " < < geo . GetID ( ) ;
IFCImporter : : LogWarn ( toLog . str ( ) . c_str ( ) ) ;
2015-05-19 03:57:13 +00:00
return false ;
}
// Do we just collect openings for a parent element (i.e. a wall)?
// In such a case, we generate the polygonal mesh as usual,
// but attach it to a TempOpening instance which will later be applied
// to the wall it pertains to.
// Note: swep area solids are added in ProcessExtrudedAreaSolid(),
// which returns an empty mesh.
if ( conv . collect_openings ) {
if ( ! meshtmp - > IsEmpty ( ) ) {
2018-01-13 09:27:45 +00:00
conv . collect_openings - > push_back ( TempOpening ( geo . ToPtr < Schema_2x3 : : IfcSolidModel > ( ) ,
2015-05-19 03:57:13 +00:00
IfcVector3 ( 0 , 0 , 0 ) ,
2022-11-03 16:35:10 +00:00
std : : move ( meshtmp ) ,
2016-04-05 21:23:53 +00:00
std : : shared_ptr < TempMesh > ( ) ) ) ;
2015-05-19 03:57:13 +00:00
}
return true ;
}
if ( meshtmp - > IsEmpty ( ) ) {
return false ;
}
meshtmp - > RemoveAdjacentDuplicates ( ) ;
meshtmp - > RemoveDegenerates ( ) ;
if ( fix_orientation ) {
// meshtmp->FixupFaceOrientation();
}
aiMesh * const mesh = meshtmp - > ToMesh ( ) ;
if ( mesh ) {
mesh - > mMaterialIndex = matid ;
2018-04-18 09:12:40 +00:00
mesh_indices . insert ( static_cast < unsigned int > ( conv . meshes . size ( ) ) ) ;
2015-05-19 03:57:13 +00:00
conv . meshes . push_back ( mesh ) ;
return true ;
}
return false ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
void AssignAddedMeshes ( std : : set < unsigned int > & mesh_indices , aiNode * nd , ConversionData & /*conv*/ ) {
2015-05-19 03:57:13 +00:00
if ( ! mesh_indices . empty ( ) ) {
2018-04-18 09:12:40 +00:00
std : : set < unsigned int > : : const_iterator it = mesh_indices . cbegin ( ) ;
std : : set < unsigned int > : : const_iterator end = mesh_indices . cend ( ) ;
2015-05-19 03:48:29 +00:00
2018-04-18 09:12:40 +00:00
nd - > mNumMeshes = static_cast < unsigned int > ( mesh_indices . size ( ) ) ;
2015-05-19 03:48:29 +00:00
2015-05-19 03:57:13 +00:00
nd - > mMeshes = new unsigned int [ nd - > mNumMeshes ] ;
2018-04-18 09:12:40 +00:00
for ( unsigned int i = 0 ; it ! = end & & i < nd - > mNumMeshes ; + + i , + + it ) {
nd - > mMeshes [ i ] = * it ;
2015-05-19 03:57:13 +00:00
}
}
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2018-01-13 09:27:45 +00:00
bool TryQueryMeshCache ( const Schema_2x3 : : IfcRepresentationItem & item ,
2023-09-09 17:29:15 +00:00
std : : set < unsigned int > & mesh_indices ,
unsigned int mat_index ,
ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
ConversionData : : MeshCacheIndex idx ( & item , mat_index ) ;
ConversionData : : MeshCache : : const_iterator it = conv . cached_meshes . find ( idx ) ;
if ( it ! = conv . cached_meshes . end ( ) ) {
2018-04-18 09:12:40 +00:00
std : : copy ( ( * it ) . second . begin ( ) , ( * it ) . second . end ( ) , std : : inserter ( mesh_indices , mesh_indices . end ( ) ) ) ;
2015-05-19 03:57:13 +00:00
return true ;
}
return false ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2018-01-13 09:27:45 +00:00
void PopulateMeshCache ( const Schema_2x3 : : IfcRepresentationItem & item ,
2023-09-09 17:29:15 +00:00
const std : : set < unsigned int > & mesh_indices ,
unsigned int mat_index ,
ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
ConversionData : : MeshCacheIndex idx ( & item , mat_index ) ;
conv . cached_meshes [ idx ] = mesh_indices ;
2015-05-19 03:48:29 +00:00
}
// ------------------------------------------------------------------------------------------------
2023-09-09 17:29:15 +00:00
bool ProcessRepresentationItem ( const Schema_2x3 : : IfcRepresentationItem & item ,
unsigned int matid ,
std : : set < unsigned int > & mesh_indices ,
ConversionData & conv ) {
2015-05-19 03:57:13 +00:00
// determine material
unsigned int localmatid = ProcessMaterials ( item . GetID ( ) , matid , conv , true ) ;
if ( ! TryQueryMeshCache ( item , mesh_indices , localmatid , conv ) ) {
if ( ProcessGeometricItem ( item , localmatid , mesh_indices , conv ) ) {
if ( mesh_indices . size ( ) ) {
PopulateMeshCache ( item , mesh_indices , localmatid , conv ) ;
}
2023-09-09 17:29:15 +00:00
} else {
return false ;
2015-05-19 03:57:13 +00:00
}
}
return true ;
2015-05-19 03:48:29 +00:00
}
} // ! IFC
} // ! Assimp
2023-09-09 17:29:15 +00:00
# endif // ASSIMP_BUILD_NO_IFC_IMPORTER