2026-03-31 15:32:36 +02:00
# include "../ifcparse/logger.h"
2023-03-21 20:15:01 +01:00
# include "taxonomy.h"
2023-10-02 16:30:39 -07:00
# include "profile_helper.h"
2025-01-02 11:10:56 -08:00
# include "function_item_evaluator.h"
2023-03-21 20:15:01 +01:00
2026-08-08 07:42:45 +02:00
using namespace ifcopenshell : : geom : : taxonomy ;
2023-03-21 20:15:01 +01:00
namespace {
bool compare ( const trimmed_curve & a , const trimmed_curve & b ) ;
bool compare ( const collection & a , const collection & b ) ;
2023-07-27 16:42:06 +08:00
bool compare ( const loop & a , const loop & b ) ;
bool compare ( const face & a , const face & b ) ;
bool compare ( const shell & a , const shell & b ) ;
bool compare ( const solid & a , const solid & b ) ;
bool compare ( const loft & a , const loft & b ) ;
bool compare ( const boolean_result & a , const boolean_result & b ) ;
2023-03-21 20:15:01 +01:00
template < typename T >
bool compare ( const eigen_base < T > & t , const eigen_base < T > & u ) {
if ( t . components_ = = nullptr & & u . components_ = = nullptr ) {
return false ;
2023-10-02 16:30:39 -07:00
}
else if ( t . components_ = = nullptr & & u . components_ ! = nullptr ) {
2023-03-21 20:15:01 +01:00
return true ;
2023-10-02 16:30:39 -07:00
}
else if ( t . components_ ! = nullptr & & u . components_ = = nullptr ) {
2023-03-21 20:15:01 +01:00
return false ;
}
auto t_begin = t . components_ - > data ( ) ;
auto t_end = t . components_ - > data ( ) + t . components_ - > size ( ) ;
auto u_begin = u . components_ - > data ( ) ;
auto u_end = u . components_ - > data ( ) + u . components_ - > size ( ) ;
return std : : lexicographical_compare ( t_begin , t_end , u_begin , u_end ) ;
}
bool compare ( const line & a , const line & b ) {
2023-07-27 16:42:06 +08:00
return compare ( * a . matrix , * b . matrix ) ;
2023-03-21 20:15:01 +01:00
}
bool compare ( const plane & a , const plane & b ) {
2023-07-27 16:42:06 +08:00
return compare ( * a . matrix , * b . matrix ) ;
2023-03-21 20:15:01 +01:00
}
bool compare ( const circle & a , const circle & b ) {
if ( a . radius = = b . radius ) {
2023-07-27 16:42:06 +08:00
return compare ( * a . matrix , * b . matrix ) ;
2023-03-21 20:15:01 +01:00
}
return a . radius < b . radius ;
}
bool compare ( const ellipse & a , const ellipse & b ) {
if ( a . radius = = b . radius & & a . radius2 = = b . radius2 ) {
2023-07-27 16:42:06 +08:00
return compare ( * a . matrix , * b . matrix ) ;
2023-03-21 20:15:01 +01:00
}
return
std : : tie ( a . radius , a . radius2 ) <
std : : tie ( b . radius , b . radius2 ) ;
}
bool compare ( const bspline_curve & , const bspline_curve & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
template < typename T >
typename std : : enable_if < std : : is_base_of < item , T > : : value , int > : : type less_to_order ( const T & a , const T & b ) {
const bool a_lt_b = compare ( a , b ) ;
const bool b_lt_a = compare ( b , a ) ;
return a_lt_b ?
- 1 : ( ! b_lt_a ? 0 : 1 ) ;
}
template < typename T >
typename std : : enable_if < ! std : : is_base_of < item , T > : : value , int > : : type less_to_order ( const T & a , const T & b ) {
const bool a_lt_b = a < b ;
const bool b_lt_a = b < a ;
return a_lt_b ?
- 1 : ( ! b_lt_a ? 0 : 1 ) ;
}
template < typename T >
2026-01-04 10:40:02 +01:00
int less_to_order_optional ( const std : : optional < T > & a , const std : : optional < T > & b ) {
2023-03-21 20:15:01 +01:00
if ( a & & b ) {
return less_to_order ( * a , * b ) ;
2023-10-02 16:30:39 -07:00
}
else if ( ! a & & ! b ) {
2023-03-21 20:15:01 +01:00
return 0 ;
2023-10-02 16:30:39 -07:00
}
else if ( a ) {
2023-03-21 20:15:01 +01:00
return 1 ;
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return - 1 ;
}
}
2026-01-04 10:40:02 +01:00
int compare ( const std : : variant < boost : : blank , point3 : : ptr , double > & a , const std : : variant < boost : : blank , point3 : : ptr , double > & b ) {
2023-03-21 20:15:01 +01:00
bool a_lt_b , b_lt_a ;
2026-01-04 10:40:02 +01:00
if ( a . index ( ) = = 0 ) {
2024-07-03 14:36:35 +02:00
return 0 ;
2026-01-04 10:40:02 +01:00
} else if ( a . index ( ) = = 1 ) {
a_lt_b = compare ( * std : : get < point3 : : ptr > ( a ) , * std : : get < point3 : : ptr > ( b ) ) ;
b_lt_a = compare ( * std : : get < point3 : : ptr > ( b ) , * std : : get < point3 : : ptr > ( a ) ) ;
2024-07-03 14:36:35 +02:00
} else {
2026-01-04 10:40:02 +01:00
a_lt_b = std : : less < double > ( ) ( std : : get < double > ( a ) , std : : get < double > ( b ) ) ;
b_lt_a = std : : less < double > ( ) ( std : : get < double > ( b ) , std : : get < double > ( a ) ) ;
2023-03-21 20:15:01 +01:00
}
return a_lt_b ?
- 1 : ( ! b_lt_a ? 0 : 1 ) ;
}
bool compare ( const extrusion & a , const extrusion & b ) {
// @todo extrusions can also have non-identity matrices right? perhaps it's time
// for a dedicated transform node and not on the abstract geom_item.
const int order [ 3 ] = {
less_to_order ( a . basis , b . basis ) ,
less_to_order ( a . direction , b . direction ) ,
a . depth < b . depth ? - 1 : ( a . depth = = b . depth ? 0 : 1 )
} ;
auto it = std : : find_if ( std : : begin ( order ) , std : : end ( order ) , [ ] ( int x ) { return x ; } ) ;
if ( it = = std : : end ( order ) ) return false ;
return * it = = - 1 ;
}
bool compare ( const node & , const node & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const offset_curve & , const offset_curve & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const revolve & , const revolve & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const bspline_surface & , const bspline_surface & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const cylinder & , const cylinder & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
2024-04-29 20:54:36 +02:00
bool compare ( const sphere & , const sphere & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
2024-07-03 14:36:35 +02:00
bool compare ( const torus & , const torus & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const sweep_along_curve & , const sweep_along_curve & ) {
2023-03-21 20:15:01 +01:00
throw std : : runtime_error ( " not implemented " ) ;
}
2023-10-02 16:30:39 -07:00
2025-01-02 11:10:56 -08:00
bool compare ( const function_item & , const function_item & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const functor_item & , const functor_item & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
2023-10-02 16:30:39 -07:00
bool compare ( const piecewise_function & , const piecewise_function & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
2025-01-02 11:10:56 -08:00
bool compare ( const gradient_function & , const gradient_function & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const cant_function & , const cant_function & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
bool compare ( const offset_function & , const offset_function & ) {
throw std : : runtime_error ( " not implemented " ) ;
}
2023-03-21 20:15:01 +01:00
/* A compile-time for loop over the taxonomy kinds */
template < size_t N >
struct dispatch_comparison {
static bool dispatch ( const item * a , const item * b ) {
if ( N = = a - > kind ( ) & & N = = b - > kind ( ) ) {
auto A = static_cast < const type_by_kind : : type < N > * > ( a ) ;
auto B = static_cast < const type_by_kind : : type < N > * > ( b ) ;
return compare ( * A , * B ) ;
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return dispatch_comparison < N + 1 > : : dispatch ( a , b ) ;
}
}
} ;
template < >
struct dispatch_comparison < type_by_kind : : max > {
static bool dispatch ( const item * , const item * ) {
return false ;
}
} ;
}
2026-08-08 07:42:45 +02:00
ifcopenshell : : geom : : taxonomy : : topology_error : : ~ topology_error ( ) = default ;
2025-10-03 14:00:20 +00:00
2026-08-08 07:42:45 +02:00
bool ifcopenshell : : geom : : taxonomy : : less ( item : : const_ptr a , item : : const_ptr b ) {
2023-03-21 20:15:01 +01:00
if ( a = = b ) {
return false ;
}
int a_kind = a - > kind ( ) ;
int b_kind = b - > kind ( ) ;
if ( a_kind ! = b_kind ) {
return a_kind < b_kind ;
}
2023-07-27 16:42:06 +08:00
# ifdef TAXONOMY_USE_SHARED_PTR
return dispatch_comparison < 0 > : : dispatch ( a . get ( ) , b . get ( ) ) ;
# endif
2023-03-21 20:15:01 +01:00
}
namespace {
bool compare ( const trimmed_curve & a , const trimmed_curve & b ) {
2026-08-08 17:08:26 +02:00
std : : size_t a_which_start = a . start . index ( ) ;
std : : size_t a_which_end = a . end . index ( ) ;
std : : size_t b_which_start = b . start . index ( ) ;
std : : size_t b_which_end = b . end . index ( ) ;
2023-03-21 20:15:01 +01:00
if ( std : : tie ( a . orientation , a_which_start , a_which_end ) = =
std : : tie ( b . orientation , b_which_start , b_which_end ) ) {
int start_state = compare ( a . start , b . start ) ;
if ( start_state = = 0 ) {
int end_state = compare ( a . end , b . end ) ;
if ( end_state = = 0 ) {
int a_has_basis = ! ! a . basis ;
int b_has_basis = ! ! a . basis ;
if ( a_has_basis = = b_has_basis ) {
if ( ! a_has_basis ) {
// Finally, equality
return false ;
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return less ( a . basis , b . basis ) ;
}
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return a_has_basis < b_has_basis ;
}
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return end_state = = - 1 ;
}
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return start_state = = - 1 ;
}
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return
std : : tie ( a . orientation , a_which_start , a_which_end ) <
std : : tie ( b . orientation , b_which_start , b_which_end ) ;
}
}
2023-07-27 16:42:06 +08:00
template < typename T >
bool compare_collection ( const collection_base < T > & a , const collection_base < T > & b ) {
2023-03-21 20:15:01 +01:00
if ( a . children . size ( ) = = b . children . size ( ) ) {
auto at = a . children . begin ( ) ;
auto bt = b . children . begin ( ) ;
for ( ; at ! = a . children . end ( ) ; + + at , + + bt ) {
const bool a_lt_b = less ( * at , * bt ) ;
const bool b_lt_a = less ( * bt , * at ) ;
if ( ! a_lt_b & & ! b_lt_a ) {
// Elements equal.
continue ;
}
return a_lt_b ;
}
// Vectors equal, compare matrix (in case of mapped items).
2023-07-27 16:42:06 +08:00
return compare ( * a . matrix , * b . matrix ) ;
2023-10-02 16:30:39 -07:00
}
else {
2023-03-21 20:15:01 +01:00
return a . children . size ( ) < b . children . size ( ) ;
}
}
2023-07-27 16:42:06 +08:00
bool compare ( const loop & a , const loop & b ) {
return compare_collection < edge > ( a , b ) ;
}
bool compare ( const face & a , const face & b ) {
return compare_collection < loop > ( a , b ) ;
}
bool compare ( const shell & a , const shell & b ) {
return compare_collection < face > ( a , b ) ;
}
bool compare ( const solid & a , const solid & b ) {
return compare_collection < shell > ( a , b ) ;
}
bool compare ( const loft & a , const loft & b ) {
2024-09-12 11:20:30 +02:00
return compare_collection < geom_item > ( a , b ) ;
2023-07-27 16:42:06 +08:00
}
bool compare ( const collection & a , const collection & b ) {
return compare_collection < geom_item > ( a , b ) ;
}
bool compare ( const boolean_result & a , const boolean_result & b ) {
return compare_collection < geom_item > ( a , b ) ;
}
2023-03-21 20:15:01 +01:00
}
2026-08-08 07:42:45 +02:00
ifcopenshell : : geom : : taxonomy : : solid : : ptr ifcopenshell : : geom : : create_box ( double dx , double dy , double dz ) {
2023-03-21 20:15:01 +01:00
return create_box ( 0. , 0. , 0. , dx , dy , dz ) ;
}
2026-08-08 07:42:45 +02:00
ifcopenshell : : geom : : taxonomy : : solid : : ptr ifcopenshell : : geom : : create_box ( double x , double y , double z , double dx , double dy , double dz ) {
2023-07-27 16:42:06 +08:00
auto solid = make < taxonomy : : solid > ( ) ;
auto shell = make < taxonomy : : shell > ( ) ;
2023-03-21 20:15:01 +01:00
solid - > children . push_back ( shell ) ;
// x = 0
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + dz )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
// x = dx
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + 0 )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
// y = 0
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + 0 )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
// y = dy
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + dz )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
// z = 0
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + 0 ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + 0 )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
// z = dz
{
2023-07-27 16:42:06 +08:00
auto face = make < taxonomy : : face > ( ) ;
auto loop = make < taxonomy : : loop > ( ) ;
2023-03-21 20:15:01 +01:00
face - > children . push_back ( loop ) ;
loop - > external = true ;
shell - > children . push_back ( face ) ;
2023-07-27 16:42:06 +08:00
std : : array < taxonomy : : point3 : : ptr , 4 > points {
2023-10-02 16:30:39 -07:00
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + 0 , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + 0 , y + dy , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + dy , z + dz ) ,
taxonomy : : make < taxonomy : : point3 > ( x + dx , y + 0 , z + dz )
2023-03-21 20:15:01 +01:00
} ;
2023-07-27 16:42:06 +08:00
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 0 ] , points [ 1 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 1 ] , points [ 2 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 2 ] , points [ 3 ] ) ) ;
loop - > children . push_back ( make < taxonomy : : edge > ( points [ 3 ] , points [ 0 ] ) ) ;
2023-03-21 20:15:01 +01:00
}
return solid ;
}
2024-08-01 12:34:49 -07:00
///////////////////
2026-08-08 14:58:15 +02:00
piecewise_function : : piecewise_function ( double start , const span_list & s , const express : : base & instance ) : function_item ( instance ) , start_ ( start ) , spans_ ( s ) {
2024-05-22 13:51:55 -07:00
}
2026-08-08 07:42:45 +02:00
piecewise_function : : piecewise_function ( double start , const std : : vector < piecewise_function : : ptr > & pwfs , const express : : base & instance ) : function_item ( instance ) , start_ ( start ) {
2025-01-02 11:10:56 -08:00
for ( auto & pwf : pwfs ) {
spans_ . insert ( spans_ . end ( ) , pwf - > spans ( ) . begin ( ) , pwf - > spans ( ) . end ( ) ) ;
}
2024-08-01 12:34:49 -07:00
} ;
2023-10-02 16:30:39 -07:00
2026-08-08 14:58:15 +02:00
const piecewise_function : : span_list & piecewise_function : : spans ( ) const { return spans_ ; }
2025-01-02 11:10:56 -08:00
bool piecewise_function : : is_empty ( ) const { return spans_ . empty ( ) ; }
double piecewise_function : : start ( ) const { return start_ ; }
double piecewise_function : : end ( ) const { return start_ + length ( ) ; }
double piecewise_function : : length ( ) const {
return std : : accumulate ( spans_ . begin ( ) , spans_ . end ( ) , 0.0 , [ ] ( const auto & v , const auto & s ) { return v + s - > length ( ) ; } ) ;
// this is a secondary option where we only compute length once and cache it.
// mutex is needed to prevent interruption of the accumulation if there is multi-threading
// skipping this detail for now and just adding up the span lengths every time
//if (!length_.has_value()) {
// length_ = std::accumulate(spans_.begin(), spans_.end(), 0.0, [](const auto& v, const auto& s) { return v + s->length(); });
//}
//return *length_;
2024-07-29 09:48:15 -07:00
}
2024-05-22 13:51:55 -07:00
2025-01-02 11:10:56 -08:00
2026-08-08 07:42:45 +02:00
gradient_function : : gradient_function ( piecewise_function : : const_ptr horizontal , piecewise_function : : const_ptr vertical , const express : : base & instance ) :
2025-01-02 11:10:56 -08:00
function_item ( instance ) , horizontal_ ( horizontal ) , vertical_ ( vertical ) {
2024-04-06 10:40:22 -07:00
}
2025-01-02 11:10:56 -08:00
double gradient_function : : start ( ) const { return std : : max ( horizontal_ - > start ( ) , vertical_ - > start ( ) ) ; }
double gradient_function : : end ( ) const { return std : : min ( horizontal_ - > end ( ) , vertical_ - > end ( ) ) ; }
piecewise_function : : const_ptr gradient_function : : get_horizontal ( ) const { return horizontal_ ; }
piecewise_function : : const_ptr gradient_function : : get_vertical ( ) const { return vertical_ ; }
2023-10-02 16:30:39 -07:00
2025-01-02 11:10:56 -08:00
2026-08-08 07:42:45 +02:00
cant_function : : cant_function ( gradient_function : : const_ptr gradient , piecewise_function : : const_ptr cant , const express : : base & instance ) :
2025-01-02 11:10:56 -08:00
function_item ( instance ) , gradient_ ( gradient ) , cant_ ( cant ) {
}
double cant_function : : start ( ) const { return std : : max ( gradient_ - > start ( ) , cant_ - > start ( ) ) ; }
double cant_function : : end ( ) const { return std : : min ( gradient_ - > end ( ) , cant_ - > end ( ) ) ; }
gradient_function : : const_ptr cant_function : : get_gradient ( ) const { return gradient_ ; }
piecewise_function : : const_ptr cant_function : : get_cant ( ) const { return cant_ ; }
2026-08-08 07:42:45 +02:00
offset_function : : offset_function ( function_item : : const_ptr basis , piecewise_function : : const_ptr offset , const express : : base & instance ) : function_item ( instance ) ,
2025-01-02 11:10:56 -08:00
basis_ ( basis ) ,
offset_ ( offset ) {
}
double offset_function : : start ( ) const { return basis_ - > start ( ) ; }
double offset_function : : end ( ) const { return basis_ - > end ( ) ; }
function_item : : const_ptr offset_function : : get_basis ( ) const { return basis_ ; }
piecewise_function : : const_ptr offset_function : : get_offset ( ) const { return offset_ ; }
2024-08-01 12:34:49 -07:00
2023-10-25 11:44:19 -07:00
2026-08-08 07:42:45 +02:00
ifcopenshell : : geom : : taxonomy : : collection : : ptr ifcopenshell : : geom : : flatten ( const taxonomy : : collection : : ptr & deep ) {
2023-07-27 16:42:06 +08:00
auto flat = make < taxonomy : : collection > ( ) ;
2026-08-08 07:42:45 +02:00
ifcopenshell : : geom : : visit < taxonomy : : collection > ( deep , [ & flat ] ( taxonomy : : ptr i ) {
2023-07-27 16:42:06 +08:00
flat - > children . push_back ( taxonomy : : cast < taxonomy : : geom_item > ( clone ( i ) ) ) ;
2023-10-02 16:30:39 -07:00
} ) ;
2023-03-21 20:15:01 +01:00
return flat ;
2023-03-27 14:02:53 +02:00
}
2026-08-08 07:42:45 +02:00
const std : : string & ifcopenshell : : geom : : taxonomy : : kind_to_string ( kinds k ) {
2023-03-27 14:02:53 +02:00
using namespace std : : string_literals ;
static std : : string values [ ] = {
2025-01-02 11:10:56 -08:00
" matrix4 " s ,
" point3 " s ,
" direction3 " s ,
" line " s ,
" circle " s ,
" ellipse " s ,
" bspline_curve " s ,
" offset_curve " s ,
" plane " s ,
" cylinder " s ,
" sphere " s ,
" torus " s ,
" bspline_surface " s ,
" edge " s ,
" loop " s ,
" face " s ,
" shell " s ,
" solid " s ,
" loft " s ,
" extrusion " s ,
" revolve " s ,
" sweep_along_curve " s ,
" node " s ,
" collection " s ,
" boolean_result " s ,
" function_item " s ,
" functor_item " s ,
" piecewise_function " s ,
" gradient_function " s ,
" cant_function " s ,
" offset_function " s ,
" colour " s ,
" style " s ,
2023-03-27 14:02:53 +02:00
} ;
return values [ k ] ;
2023-04-03 13:31:22 +02:00
}
2026-04-14 13:50:23 +02:00
IFC_GEOM_API std : : atomic_uint32_t item : : counter_ ( 0 ) ;
2024-06-24 21:56:27 +02:00
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : item : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
o < < std : : string ( indent , ' ' ) < < kind_to_string ( kind ( ) ) < < std : : endl ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : matrix4 : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : colour : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : style : : print ( std : : ostream & o , int indent ) const {
2024-06-24 21:56:27 +02:00
o < < std : : string ( indent , ' ' ) < < " style " < < std : : endl ;
2024-07-02 11:43:09 +02:00
o < < std : : string ( indent , ' ' ) < < " " < < " name " < < ( name ) < < std : : endl ;
2024-06-24 21:56:27 +02:00
if ( diffuse . components_ ) {
2024-07-02 11:43:09 +02:00
o < < std : : string ( indent , ' ' ) < < " " < < " diffuse " < < std : : endl ;
2024-06-24 21:56:27 +02:00
diffuse . print ( o , indent + 5 + 7 ) ;
}
if ( specular . components_ ) {
2024-07-02 11:43:09 +02:00
o < < std : : string ( indent , ' ' ) < < " " < < " specular " < < std : : endl ;
2024-06-24 21:56:27 +02:00
specular . print ( o , indent + 5 + 8 ) ;
}
// @todo
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : point3 : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : direction3 : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : line : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : circle : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-07-21 02:40:56 +02:00
o < < std : : string ( indent + 4 , ' ' ) < < " radius " < < radius < < std : : endl ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : ellipse : : print ( std : : ostream & o , int indent ) const {
2024-07-03 14:36:35 +02:00
print_impl ( o , kind_to_string ( kind ( ) ) , indent ) ;
2024-07-21 02:40:56 +02:00
o < < std : : string ( indent + 4 , ' ' ) < < " radii " < < radius < < " " < < radius2 < < std : : endl ;
2024-06-24 21:56:27 +02:00
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : trimmed_curve : : print ( std : : ostream & o , int indent ) const {
2024-06-28 13:38:36 +02:00
o < < std : : string ( indent , ' ' ) < < kind_to_string ( kind ( ) ) ;
2026-01-04 10:40:02 +01:00
if ( ! this - > orientation . value_or ( true ) ) {
2024-06-24 21:56:27 +02:00
o < < " [R] " ;
} else {
o < < " [ ] " ;
}
2026-01-04 10:40:02 +01:00
if ( ! this - > curve_sense . value_or ( true ) ) {
2024-06-24 21:56:27 +02:00
o < < " [R] " ;
} else {
o < < " [ ] " ;
}
o < < std : : endl ;
if ( basis ) {
basis - > print ( o , indent + 4 ) ;
}
2026-01-04 10:40:02 +01:00
const std : : variant < boost : : blank , point3 : : ptr , double > * const start_end [ 2 ] = { & start , & end } ;
2024-06-24 21:56:27 +02:00
for ( int i = 0 ; i < 2 ; + + i ) {
o < < std : : string ( indent + 4 , ' ' ) < < ( i = = 0 ? " start " : " end " ) < < std : : endl ;
2026-01-04 10:40:02 +01:00
if ( start_end [ i ] - > index ( ) = = 1 ) {
std : : get < point3 : : ptr > ( * start_end [ i ] ) - > print ( o , indent + 4 ) ;
} else if ( start_end [ i ] - > index ( ) = = 2 ) {
o < < std : : string ( indent + 4 , ' ' ) < < " parameter " < < std : : get < double > ( * start_end [ i ] ) < < std : : endl ;
2024-06-24 21:56:27 +02:00
}
}
2026-01-04 10:40:02 +01:00
if ( instance ) {
2024-08-23 20:29:07 +02:00
std : : ostringstream oss ;
2026-03-31 15:32:36 +02:00
instance . to_string ( oss ) ;
2024-08-23 20:29:07 +02:00
o < < std : : string ( indent + 4 , ' ' ) < < oss . str ( ) < < std : : endl ;
2024-06-24 21:56:27 +02:00
}
}
2026-08-08 07:42:45 +02:00
void ifcopenshell : : geom : : taxonomy : : extrusion : : print ( std : : ostream & o , int indent ) const {
2024-06-24 21:56:27 +02:00
o < < std : : string ( indent , ' ' ) < < " extrusion " < < depth < < std : : endl ;
direction - > print ( o , indent + 4 ) ;
basis - > print ( o , indent + 4 ) ;
}
2024-09-11 11:56:49 +05:00
2026-08-08 07:42:45 +02:00
std : : optional < face : : ptr > ifcopenshell : : geom : : taxonomy : : loop_to_face_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < face : : ptr > face_ ;
2024-09-11 11:56:49 +05:00
auto loop_ = dcast < loop > ( item ) ;
if ( loop_ ) {
loop_ - > external = true ;
face_ = make < face > ( ) ;
( * face_ ) - > instance = loop_ - > instance ;
( * face_ ) - > matrix = loop_ - > matrix ;
( * face_ ) - > children = { clone ( loop_ ) } ;
}
return face_ ;
}
2026-08-08 07:42:45 +02:00
std : : optional < edge : : ptr > ifcopenshell : : geom : : taxonomy : : curve_to_edge_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < edge : : ptr > edge_ ;
2024-09-11 11:56:49 +05:00
auto circle_ = dcast < circle > ( item ) ;
auto ellipse_ = dcast < ellipse > ( item ) ;
auto line_ = dcast < line > ( item ) ;
auto bspline_curve_ = dcast < bspline_curve > ( item ) ;
if ( circle_ | | ellipse_ | | line_ | | bspline_curve_ ) {
edge_ = make < edge > ( ) ;
if ( circle_ ) {
( * edge_ ) - > basis = circle_ ;
2024-09-11 11:56:21 +05:00
( * edge_ ) - > instance = circle_ - > instance ;
2024-09-11 11:56:49 +05:00
} else if ( ellipse_ ) {
( * edge_ ) - > basis = ellipse_ ;
2024-09-11 11:56:21 +05:00
( * edge_ ) - > instance = ellipse_ - > instance ;
2024-09-11 11:56:49 +05:00
} else if ( line_ ) {
( * edge_ ) - > basis = line_ ;
2024-09-11 11:56:21 +05:00
( * edge_ ) - > instance = line_ - > instance ;
2024-09-11 11:56:49 +05:00
} else if ( bspline_curve_ ) {
( * edge_ ) - > basis = bspline_curve_ ;
2024-09-11 11:56:21 +05:00
( * edge_ ) - > instance = bspline_curve_ - > instance ;
2024-09-11 11:56:49 +05:00
}
if ( circle_ | | ellipse_ ) {
// @todo
( * edge_ ) - > start = 0. ;
( * edge_ ) - > end = 2 * boost : : math : : constants : : pi < double > ( ) ;
}
}
return edge_ ;
}
2026-08-08 07:42:45 +02:00
std : : optional < loop : : ptr > ifcopenshell : : geom : : taxonomy : : curve_to_loop_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < loop : : ptr > loop_ ;
2024-09-11 11:56:49 +05:00
auto circle_ = dcast < circle > ( item ) ;
auto ellipse_ = dcast < ellipse > ( item ) ;
auto line_ = dcast < line > ( item ) ;
auto bspline_curve_ = dcast < bspline_curve > ( item ) ;
if ( circle_ | | ellipse_ | | line_ | | bspline_curve_ ) {
auto edge_ = make < edge > ( ) ;
if ( circle_ ) {
edge_ - > basis = circle_ ;
} else if ( ellipse_ ) {
edge_ - > basis = ellipse_ ;
} else if ( line_ ) {
edge_ - > basis = line_ ;
} else if ( bspline_curve_ ) {
edge_ - > basis = bspline_curve_ ;
}
if ( circle_ | | ellipse_ ) {
// @todo
edge_ - > start = 0. ;
edge_ - > end = 2 * boost : : math : : constants : : pi < double > ( ) ;
}
loop_ = make < loop > ( ) ;
( * loop_ ) - > children . push_back ( edge_ ) ;
}
return loop_ ;
}
2026-08-08 07:42:45 +02:00
std : : optional < loop : : ptr > ifcopenshell : : geom : : taxonomy : : edge_to_loop_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < loop : : ptr > loop_ ;
2024-09-11 11:56:49 +05:00
auto edge_ = dcast < edge > ( item ) ;
if ( edge_ ) {
loop_ = make < loop > ( ) ;
( * loop_ ) - > children . push_back ( edge_ ) ;
}
return loop_ ;
}
2026-08-08 07:42:45 +02:00
std : : optional < face : : ptr > ifcopenshell : : geom : : taxonomy : : curve_to_face_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < face : : ptr > face_ ;
2024-09-11 11:56:49 +05:00
auto circle_ = dcast < circle > ( item ) ;
auto ellipse_ = dcast < ellipse > ( item ) ;
auto line_ = dcast < line > ( item ) ;
auto bspline_curve_ = dcast < bspline_curve > ( item ) ;
if ( circle_ | | ellipse_ | | line_ | | bspline_curve_ ) {
auto edge_ = make < edge > ( ) ;
if ( circle_ ) {
edge_ - > basis = circle_ ;
} else if ( ellipse_ ) {
edge_ - > basis = ellipse_ ;
} else if ( line_ ) {
edge_ - > basis = line_ ;
} else if ( bspline_curve_ ) {
edge_ - > basis = bspline_curve_ ;
}
if ( circle_ | | ellipse_ ) {
// @todo
edge_ - > start = 0. ;
edge_ - > end = 2 * boost : : math : : constants : : pi < double > ( ) ;
}
auto loop_ = make < loop > ( ) ;
loop_ - > children . push_back ( edge_ ) ;
face_ = make < face > ( ) ;
( * face_ ) - > instance = loop_ - > instance ;
( * face_ ) - > matrix = loop_ - > matrix ;
( * face_ ) - > children = { clone ( loop_ ) } ;
}
return face_ ;
}
2025-03-20 20:57:47 +01:00
namespace {
// @todo eliminate redundancy with cgal kernel
void evaluate_curve ( const circle : : ptr & c , double u , point3 & p ) {
Eigen : : Vector4d xy { c - > radius * std : : cos ( u ) , c - > radius * std : : sin ( u ) , 0 , 1. } ;
p . components ( ) = ( c - > matrix - > ccomponents ( ) * xy ) . head < 3 > ( ) ;
}
// @todo eliminate redundancy with cgal kernel
void evaluate_curve_d1 ( const circle : : ptr & c , double u , direction3 & p ) {
Eigen : : Vector4d xy { - std : : sin ( u ) , cos ( u ) , 0 , 0. } ;
p . components ( ) = ( c - > matrix - > ccomponents ( ) * xy ) . head < 3 > ( ) ;
}
double project_onto_curve ( const circle : : ptr & c , const point3 & p ) {
Eigen : : Vector2d xy = ( c - > matrix - > ccomponents ( ) . inverse ( ) * p . ccomponents ( ) . homogeneous ( ) ) . head < 2 > ( ) ;
return std : : atan2 ( xy ( 1 ) , xy ( 0 ) ) ;
}
}
2024-09-11 11:56:49 +05:00
2026-08-08 07:42:45 +02:00
std : : optional < function_item : : ptr > ifcopenshell : : geom : : taxonomy : : loop_to_function_item_upgrade_impl ( ptr item ) {
2026-01-04 10:40:02 +01:00
std : : optional < function_item : : ptr > fi_ ;
2024-09-11 11:56:49 +05:00
auto loop_ = dcast < loop > ( item ) ;
if ( loop_ ) {
2026-01-04 10:40:02 +01:00
if ( loop_ - > fi . has_value ( ) ) {
2025-02-22 16:04:01 -08:00
fi_ = loop_ - > fi ;
2024-09-11 11:56:49 +05:00
} else {
2025-02-22 16:04:01 -08:00
// piecewise_function is a specialization of function_item - callers don't need to know this detail
2026-08-08 14:58:15 +02:00
piecewise_function : : span_list spans ;
2024-09-11 11:56:49 +05:00
spans . reserve ( loop_ - > children . size ( ) ) ;
for ( auto & edge_ : loop_ - > children ) {
2025-03-20 20:57:47 +01:00
if ( edge_ - > basis & & edge_ - > basis - > kind ( ) = = CIRCLE ) {
const circle : : ptr circ = std : : static_pointer_cast < circle > ( edge_ - > basis ) ;
2026-01-04 10:40:02 +01:00
auto * s_pnt = std : : get_if < point3 : : ptr > ( & edge_ - > start ) ;
auto * e_pnt = std : : get_if < point3 : : ptr > ( & edge_ - > end ) ;
auto * s_param = std : : get_if < double > ( & edge_ - > start ) ;
auto * e_param = std : : get_if < double > ( & edge_ - > end ) ;
2024-09-11 11:56:49 +05:00
2025-03-20 20:57:47 +01:00
if ( ! s_pnt & & ! s_param ) {
2026-01-04 10:40:02 +01:00
return std : : nullopt ;
2025-03-20 20:57:47 +01:00
}
if ( ! e_pnt & & ! e_param ) {
2026-01-04 10:40:02 +01:00
return std : : nullopt ;
2025-03-20 20:57:47 +01:00
}
double s = s_pnt ? project_onto_curve ( circ , * * s_pnt ) : * s_param ;
double e = e_pnt ? project_onto_curve ( circ , * * e_pnt ) : * e_param ;
auto l = std : : fabs ( s - e ) * circ - > radius ;
std : : function < Eigen : : Matrix4d ( double ) > fn = [ circ , s ] ( double u ) {
point3 P ;
direction3 d ;
evaluate_curve ( circ , u / circ - > radius + s , P ) ;
evaluate_curve_d1 ( circ , u / circ - > radius + s , d ) ;
return matrix4 ( P . ccomponents ( ) , circ - > matrix - > ccomponents ( ) . col ( 2 ) . head < 3 > ( ) , d . ccomponents ( ) ) . components ( ) ;
} ;
spans . emplace_back ( taxonomy : : make < taxonomy : : functor_item > ( l , fn ) ) ;
2026-01-04 10:40:02 +01:00
} else if ( edge_ - > start . index ( ) = = 1 & & edge_ - > end . index ( ) = = 1 ) {
2025-03-20 20:57:47 +01:00
if ( edge_ - > basis & & edge_ - > basis - > kind ( ) ! = LINE ) {
2026-08-08 13:58:39 +02:00
ifcopenshell : : logger : : root ( ) . message ( ifcopenshell : : logger : : severity : : LOG_WARNING , " UNS " , 20 , " Basis curve not supported - edge is treated as a straight line edge " ) ;
2025-03-20 20:57:47 +01:00
}
2026-01-04 10:40:02 +01:00
const auto & s = std : : get < point3 : : ptr > ( edge_ - > start ) - > ccomponents ( ) ;
const auto & e = std : : get < point3 : : ptr > ( edge_ - > end ) - > ccomponents ( ) ;
2025-03-20 20:57:47 +01:00
Eigen : : Vector3d v = e - s ;
auto l = v . norm ( ) ; // the norm of a vector is a measure of its length
v . normalize ( ) ; // normalize the vector so that it is a unit direction vector
std : : function < Eigen : : Matrix4d ( double ) > fn = [ s , v ] ( double u ) {
Eigen : : Vector3d o ( s + u * v ) , axis ( 0 , 0 , 1 ) , refDirection ( v ) ;
auto Y = axis . cross ( refDirection ) . normalized ( ) ;
axis = refDirection . cross ( Y ) . normalized ( ) ;
return make < matrix4 > ( o , axis , refDirection ) - > components ( ) ;
} ;
spans . emplace_back ( taxonomy : : make < taxonomy : : functor_item > ( l , fn ) ) ;
} else {
2026-08-08 13:58:39 +02:00
ifcopenshell : : logger : : root ( ) . message ( ifcopenshell : : logger : : severity : : LOG_ERROR , " UNS " , 21 , " Basis curve not supported " ) ;
2026-07-09 13:30:48 +02:00
return std : : nullopt ;
2025-03-20 20:57:47 +01:00
}
2024-09-11 11:56:49 +05:00
}
2025-02-22 16:04:01 -08:00
fi_ = make < piecewise_function > ( 0.0 , spans ) ;
loop_ - > fi = fi_ ;
2024-09-11 11:56:49 +05:00
}
}
2025-02-22 16:04:01 -08:00
return fi_ ;
2024-09-11 11:56:49 +05:00
}