2024-03-15 17:26:02 +01:00
/********************************************************************************
* *
* This file is part of IfcOpenShell. *
* *
* IfcOpenShell is free software: you can redistribute it and/or modify *
* it under the terms of the Lesser GNU General Public License as published by *
* the Free Software Foundation, either version 3.0 of the License, or *
* (at your option) any later version. *
* *
* IfcOpenShell is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* Lesser GNU General Public License for more details. *
* *
* You should have received a copy of the Lesser GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
# include "mapping.h"
# define mapping POSTFIX_SCHEMA(mapping)
using namespace ifcopenshell : : geometry ;
# include "../../ifcgeom/profile_helper.h"
2024-09-12 11:20:30 +02:00
# include "../../ifcgeom/infra_sweep_helper.h"
2024-03-15 17:26:02 +01:00
# ifdef SCHEMA_HAS_IfcSectionedSolidHorizontal
2026-01-04 10:40:02 +01:00
taxonomy : : ptr mapping : : map_impl ( const IfcSchema : : IfcSectionedSolidHorizontal & inst ) {
2024-03-29 15:53:34 +01:00
std : : vector < cross_section > cross_sections ;
2026-01-04 10:40:02 +01:00
auto dir = map ( inst . Directrix ( ) ) ;
2025-02-22 16:04:01 -08:00
auto fn = taxonomy : : dcast < taxonomy : : function_item > ( dir ) ;
if ( ! fn ) {
2024-03-29 15:53:34 +01:00
// Only implement on alignment curves
2026-06-10 18:30:54 +02:00
logger_ . Warning ( " GEO " , 285 , " IfcSectionedSolidHorizontal is only implemented for Directrix curves based on taxonomy::function_item " , inst ) ;
2024-07-22 13:21:49 -07:00
return nullptr ;
2024-03-29 15:53:34 +01:00
}
{
2026-01-04 10:40:02 +01:00
auto css = inst . CrossSections ( ) ;
auto csps = inst . CrossSectionPositions ( ) ;
2024-03-29 15:53:34 +01:00
std : : vector < taxonomy : : face : : ptr > faces ;
2024-03-15 17:26:02 +01:00
2025-03-14 07:31:50 -07:00
// The PointByDistanceExpressions are factored out into (a) a cartesian offset relative to the
2024-03-15 17:26:02 +01:00
// reference frame along a certain curve location (b) the longitude.
// The longitudes determine the range of the sweep and the offsets are interpolated in between
// sweep segments.
std : : vector < Eigen : : Vector3d > profile_offsets ;
2026-01-04 10:40:02 +01:00
std : : vector < std : : optional < Eigen : : Matrix3d > > profile_rotations ;
2024-03-15 17:26:02 +01:00
std : : vector < double > longitudes ;
2026-01-04 10:40:02 +01:00
for ( auto & cs : css ) {
2024-03-29 15:53:34 +01:00
faces . push_back ( std : : move ( taxonomy : : cast < taxonomy : : face > ( map ( cs ) ) ) ) ;
2024-03-15 17:26:02 +01:00
}
2025-05-17 16:01:28 +02:00
# if defined(SCHEMA_HAS_IfcPointByDistanceExpression) && !defined(SCHEMA_IfcSectionedSurface_HAS_FixedAxisVertical)
2026-01-04 10:40:02 +01:00
for ( auto & csp : csps ) {
auto pbde = csp . Location ( ) . as < IfcSchema : : IfcPointByDistanceExpression > ( ) ;
2024-03-29 15:53:34 +01:00
2026-01-04 10:40:02 +01:00
longitudes . push_back ( ( double ) pbde . DistanceAlong ( ) . as < IfcSchema : : IfcLengthMeasure > ( ) * length_unit_ ) ;
2024-03-15 17:26:02 +01:00
// Corresponds to the profile X, Y directions (hopefully).
Eigen : : Vector3d po (
2026-01-04 10:40:02 +01:00
pbde . OffsetLateral ( ) . value_or ( 0. ) ,
2024-03-15 17:26:02 +01:00
// @todo I don't understand whether vertical is an offset relative to the tangent plane or to the global XY plane
2026-01-04 10:40:02 +01:00
pbde . OffsetVertical ( ) . value_or ( 0. ) ,
2024-03-15 17:26:02 +01:00
0.
) ;
profile_offsets . push_back ( po ) ;
2025-03-20 16:13:56 +01:00
2026-01-04 10:40:02 +01:00
std : : optional < Eigen : : Matrix3d > rot ;
if ( csp . Axis ( ) & & csp . RefDirection ( ) ) {
2025-03-20 16:13:56 +01:00
rot = taxonomy : : matrix4 (
Eigen : : Vector3d ( 0 , 0 , 0 ) ,
2026-01-04 10:40:02 +01:00
taxonomy : : cast < taxonomy : : direction3 > ( map ( csp . Axis ( ) ) ) - > ccomponents ( ) ,
taxonomy : : cast < taxonomy : : direction3 > ( map ( csp . RefDirection ( ) ) ) - > ccomponents ( ) ) . ccomponents ( ) . block < 3 , 3 > ( 0 , 0 ) ;
} else if ( csp . Axis ( ) ) {
2025-03-20 16:13:56 +01:00
rot = taxonomy : : matrix4 (
Eigen : : Vector3d ( 0 , 0 , 0 ) ,
2026-01-04 10:40:02 +01:00
taxonomy : : cast < taxonomy : : direction3 > ( map ( csp . Axis ( ) ) ) - > ccomponents ( ) ) . ccomponents ( ) . block < 3 , 3 > ( 0 , 0 ) ;
} else if ( csp . RefDirection ( ) ) {
2025-10-21 13:32:51 +02:00
rot = taxonomy : : matrix4 (
Eigen : : Vector3d ( 0 , 0 , 0 ) ,
Eigen : : Vector3d ( 0 , 0 , 1 ) ,
2026-01-04 10:40:02 +01:00
taxonomy : : cast < taxonomy : : direction3 > ( map ( csp . RefDirection ( ) ) ) - > ccomponents ( )
2025-10-21 13:32:51 +02:00
) . ccomponents ( ) . block < 3 , 3 > ( 0 , 0 ) ;
}
2025-03-20 16:13:56 +01:00
profile_rotations . push_back ( rot ) ;
2024-03-15 17:26:02 +01:00
}
2024-03-29 15:53:34 +01:00
if ( faces . size ( ) ! = profile_offsets . size ( ) ) {
2026-06-10 18:30:54 +02:00
logger_ . Warning ( " GEO " , 286 , " Expected CrossSections and CrossSectionPositions to be equal length, but got " + std : : to_string ( faces . size ( ) ) + " and " + std : : to_string ( profile_offsets . size ( ) ) + " respectively " , inst ) ;
2024-03-15 17:26:02 +01:00
return nullptr ;
}
2024-03-29 15:53:34 +01:00
if ( faces . size ( ) < 2 ) {
2026-06-10 18:30:54 +02:00
logger_ . Warning ( " GEO " , 287 , " Expected at least two cross sections, but got " + std : : to_string ( faces . size ( ) ) , inst ) ;
2024-03-15 17:26:02 +01:00
return nullptr ;
}
2024-03-29 15:53:34 +01:00
for ( size_t i = 0 ; i < faces . size ( ) ; + + i ) {
2025-03-20 16:13:56 +01:00
cross_sections . push_back ( { longitudes [ i ] , faces [ i ] , profile_offsets [ i ] , profile_rotations [ i ] } ) ;
2024-03-29 15:53:34 +01:00
}
2025-02-22 16:04:01 -08:00
# else
return nullptr ;
# endif
}
2024-03-29 15:53:34 +01:00
2025-02-22 16:04:01 -08:00
return make_loft ( settings_ , inst , fn , cross_sections ) ;
2024-03-15 17:26:02 +01:00
}
# endif