3030// @todo use std::numbers::pi when upgrading to C++ 20
3131static const double PI = boost::math::constants::pi<double >();
3232
33+ #include < boost/math/quadrature/trapezoidal.hpp>
3334
3435#ifdef HAS_SCHEMA_4x3_add2
3536
@@ -243,14 +244,14 @@ std::tuple<typename aggregate_of<Ifc4x3_add2::IfcObjectDefinition>::ptr, typenam
243244 // back gradient
244245 auto dxBG = xPVI - xPBG;
245246 auto dyBG = yPVI - yPBG;
246- auto start_slope = atan2 (dyBG, dxBG);
247+ auto start_slope = tan ( atan2 (dyBG,dxBG) );
247248
248249 // forward gradient
249250 point_iter++;
250251 std::tie (xPFG, yPFG) = *point_iter;
251252 auto dxFG = xPFG - xPVI;
252253 auto dyFG = yPFG - yPVI;
253- auto end_slope = atan2 (dyFG, dxFG);
254+ auto end_slope = tan ( atan2 (dyFG,dxFG) );
254255
255256 double xEVC = xPVI + length / 2 ;
256257 double yEVC = yPVI + end_slope * length / 2 ;
@@ -292,8 +293,9 @@ std::tuple<typename aggregate_of<Ifc4x3_add2::IfcObjectDefinition>::ptr, typenam
292293 // create last tangent run
293294 auto dx = xPVI - xPBG;
294295 auto dy = yPVI - yPBG;
295- auto slope = atan2 (dy, dx);
296- auto gradient_length = sqrt (dx * dx + dy * dy);
296+ auto slope = tan (atan2 (dy,dx));
297+ auto gradient_length = dx;
298+
297299 file.addDoublet <Ifc4x3_add2::IfcCartesianPoint>(xPBG, yPBG);
298300 auto design_parameters = new Ifc4x3_add2::IfcAlignmentVerticalSegment (boost::none, boost::none, xPBG, gradient_length, yPBG, slope, slope, boost::none, Ifc4x3_add2::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT);
299301 auto alignment_segment = new Ifc4x3_add2::IfcAlignmentSegment (IfcParse::IfcGlobalId (), nullptr , boost::none, boost::none, boost::none, nullptr , nullptr , design_parameters);
@@ -688,13 +690,18 @@ std::pair<Ifc4x3_add2::IfcCurveSegment*, Ifc4x3_add2::IfcCurveSegment*> mapAlign
688690 new Ifc4x3_add2::IfcCartesianPoint (std::vector<double >({0 , 0 })),
689691 new Ifc4x3_add2::IfcVector (new Ifc4x3_add2::IfcDirection (std::vector<double >{1 , 0 }), 1.0 ));
690692
693+ // IfcCurveSegment.SegmentLength is the length of the curve segment, not the horizontal length.
694+ auto dx = cos (atan (start_gradient));
695+ auto dy = sin (atan (start_gradient));
696+ auto segment_curve_length = horizontal_length / dx;
697+
691698 auto curve_segment = new Ifc4x3_add2::IfcCurveSegment (
692699 Ifc4x3_add2::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
693700 new Ifc4x3_add2::IfcAxis2Placement2D (
694701 new Ifc4x3_add2::IfcCartesianPoint ({start_distance_along, start_height}),
695- new Ifc4x3_add2::IfcDirection ({sqrt ( 1.0 - start_gradient * start_gradient), start_gradient })),
702+ new Ifc4x3_add2::IfcDirection ({dx,dy })),
696703 new Ifc4x3_add2::IfcLengthMeasure (0.0 ), // start
697- new Ifc4x3_add2::IfcLengthMeasure (horizontal_length ),
704+ new Ifc4x3_add2::IfcLengthMeasure (segment_curve_length ),
698705 parent_curve);
699706
700707 result.first = curve_segment;
@@ -710,11 +717,22 @@ std::pair<Ifc4x3_add2::IfcCurveSegment*, Ifc4x3_add2::IfcCurveSegment*> mapAlign
710717 std::vector<double >{A, B, C},
711718 boost::none);
712719
720+ // IfcCurveSegment.SegmentLength is the length of the curve segment, not the horizontal length.
721+ // The curve length is calculated by integrating the differential curve length equation sqrt(1 + (dy/dx)^2) from 0 to horizontal_length.
722+ // y = A + Bx + Cx^2
723+ // dy/dx = B + 2Cx
724+ auto dx = cos (atan (start_gradient));
725+ auto dy = sin (atan (start_gradient));
726+ auto curve_length_fn = [B, C](double x) { return sqrt (1 + pow (B + C * x, 2 )); };
727+ auto segment_curve_length = boost::math::quadrature::trapezoidal (curve_length_fn, 0.0 , horizontal_length);
728+
713729 auto curve_segment = new Ifc4x3_add2::IfcCurveSegment (
714730 Ifc4x3_add2::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
715- new Ifc4x3_add2::IfcAxis2Placement2D (new Ifc4x3_add2::IfcCartesianPoint ({start_distance_along, start_height}), new Ifc4x3_add2::IfcDirection ({sqrt (1.0 - start_gradient * start_gradient), start_gradient})),
731+ new Ifc4x3_add2::IfcAxis2Placement2D (
732+ new Ifc4x3_add2::IfcCartesianPoint ({start_distance_along, start_height}),
733+ new Ifc4x3_add2::IfcDirection ({dx,dy})),
716734 new Ifc4x3_add2::IfcLengthMeasure (0.0 ),
717- new Ifc4x3_add2::IfcLengthMeasure (horizontal_length ),
735+ new Ifc4x3_add2::IfcLengthMeasure (segment_curve_length ),
718736 parent_curve);
719737
720738 result.first = curve_segment;
@@ -735,11 +753,14 @@ std::pair<Ifc4x3_add2::IfcCurveSegment*, Ifc4x3_add2::IfcCurveSegment*> mapAlign
735753 new Ifc4x3_add2::IfcDirection (std::vector<double >{1 , 0 })),
736754 radius);
737755
756+
757+ auto segment_curve_length = radius * fabs (end_angle - start_angle);
758+
738759 Ifc4x3_add2::IfcCurveSegment* curve_segment = new Ifc4x3_add2::IfcCurveSegment (
739760 Ifc4x3_add2::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
740761 new Ifc4x3_add2::IfcAxis2Placement2D (new Ifc4x3_add2::IfcCartesianPoint ({start_distance_along, start_height}), new Ifc4x3_add2::IfcDirection ({1.0 , 0.0 })),
741762 new Ifc4x3_add2::IfcLengthMeasure (0.0 ),
742- new Ifc4x3_add2::IfcLengthMeasure (horizontal_length ),
763+ new Ifc4x3_add2::IfcLengthMeasure (segment_curve_length ),
743764 parent_curve);
744765
745766 result.first = curve_segment;
0 commit comments