From f204135aa62e76501a2803fa9e8dd57ae9182d4e Mon Sep 17 00:00:00 2001 From: Richard Brice <37087370+RickBrice@users.noreply.github.com> Date: Wed, 15 Nov 2023 07:20:09 -0800 Subject: [PATCH] Fixing bugs --- .../mapping/IfcAxis2PlacementLinear.cpp | 16 +++-- src/ifcgeom/mapping/IfcCurveSegment.cpp | 65 +++++++++++-------- .../mapping/IfcSegmentedReferenceCurve.cpp | 9 ++- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/ifcgeom/mapping/IfcAxis2PlacementLinear.cpp b/src/ifcgeom/mapping/IfcAxis2PlacementLinear.cpp index 17ba88a031..69fb363b62 100644 --- a/src/ifcgeom/mapping/IfcAxis2PlacementLinear.cpp +++ b/src/ifcgeom/mapping/IfcAxis2PlacementLinear.cpp @@ -43,23 +43,27 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcAxis2PlacementLinear* inst) if (hasAxis) { taxonomy::direction3::ptr v = taxonomy::cast(map(inst->Axis())); axis = *v->components_; - } + } else { + // 8.9.3.4 IfcAxis2LinearPlacement does not specify the default when Axis is omitted + // When RefDirection is omitted, see comment below, it is taken to be tangent to the curve. + // To be consistent, Axis is taken to be orthogonal to RefDirection + axis = m->components().col(2).head<3>(); + } if (hasRef) { taxonomy::direction3::ptr v = taxonomy::cast(map(inst->RefDirection())); refDirection = *v->components_; } else { - // @todo: rb "If RefDirection is omitted, the direction is taken from the curve tangent at Location" + // 8.9.3.4 IfcAxis2LinearPlacement // https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/lexical/IfcAxis2PlacementLinear.htm - // Based on our email discussion, I'm using the perpendicular direction towards the right as viewed in the XY Plane for .RefDirection + // "If RefDirection is omitted, the direction is taken from the curve tangent at Location" // // When the PointByDistanceExpression Location is evaluated, it is evaluating the basis curve and returning // the matrix of orthogonal vectors that define the coordinate system at the point on curve as well as the point on curve // In other words, the m matrix has everything needed - refDirection = m->components().col(1).head<3>(); - - axis = m->components().col(2).head<3>(); + refDirection = m->components().col(0).head<3>(); + } return taxonomy::make(o, axis, refDirection); } diff --git a/src/ifcgeom/mapping/IfcCurveSegment.cpp b/src/ifcgeom/mapping/IfcCurveSegment.cpp index 1d46dba51b..e059fb2a8c 100644 --- a/src/ifcgeom/mapping/IfcCurveSegment.cpp +++ b/src/ifcgeom/mapping/IfcCurveSegment.cpp @@ -263,7 +263,7 @@ class linear_segment_geometry_adjuster : public segment_geometry_adjuster { // For now, the derivative of the curvature of the IfcCurve subtype is difficult to implement and example models from the IFC spec // always use IfcAxis2Placement3D with Axis and RefDirection specified, the basic interpolation is used, ignoring the IfcCurve type. // -// This implementation will be revised as the understanding of IfcSegmentedRefereneCurve improves. +// This implementation will be revised as the understanding of IfcSegmentedReferenceCurve improves. class cant_adjuster : public segment_geometry_adjuster { public: using segment_geometry_adjuster::segment_geometry_adjuster; @@ -280,11 +280,6 @@ class cant_adjuster : public segment_geometry_adjuster { p.col(i).normalize(); }; } - - // when cant results are combined with the gradient curve - // the x-locate will be added which effective doubles them - // for this reason, set x location to 0 - p.col(3)(0) = 0; } protected: @@ -366,7 +361,7 @@ class curve_segment_evaluator { } } - void set_spiral_function(mapping* mapping_, const IfcSchema::IfcSpiral* c, double s, std::function signX, std::function fnX, std::function signY, std::function fnY) { + void set_spiral_function(mapping* mapping_, const IfcSchema::IfcSpiral* c, double s, std::function signX, std::function fnX, std::function signY, std::function fnY, std::function fnSlope) { // determine the length of the spiral from the local origin to the end point auto sign_s = binary_sign(start_); auto sign_l = binary_sign(length_); @@ -384,7 +379,7 @@ class curve_segment_evaluator { auto segment_type = segment_type_; auto transformation_matrix = taxonomy::cast(mapping_->map(c->Position()))->ccomponents(); geometry_adjuster = std::make_shared(mapping_, segment_type_, inst_, next_inst_); - eval_ = [L, start, s, signX, fnX, signY, fnY, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { + eval_ = [L, start, s, signX, fnX, signY, fnY, fnSlope, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { u += start; @@ -402,11 +397,17 @@ class curve_segment_evaluator { // However, Dx and Dy are not normalized. Recall that slope = rise/run // If run = 1.0, then rise = Dy/Dx = fnY(u)/fnX(u) and l = sqrt((fnY(u)/fnX(u))^2 + 1.0^2) // The direction ratios are dx = 1.0/l and dy = (fnY/fnX)/l; - auto rise = fnY(u) / fnX(u); - auto run = 1.0; - auto l = sqrt(run * run + rise * rise); - auto dx = run / l; - auto dy = rise / l; + //auto fy = fnY(u); + //auto fx = fnX(u); + //auto rise = fy / fx; + //auto run = 1.0; + //auto l = sqrt(run * run + rise * rise); + //auto dx = run / l; + //auto dy = rise / l; + + auto slope = fnSlope(u); + auto dx = signX(u) * cos(slope); + auto dy = signY(u) * sin(slope); Eigen::Matrix4d m; if (segment_type == ST_HORIZONTAL) { @@ -507,8 +508,10 @@ class curve_segment_evaluator { auto sign_y = [A](double t) { return sign(t) == sign(A) ? 1.0 : -1.0; }; auto fn_x = [A, s](double t) -> double { return s * cos(PI * fabs(A) * t * t / (2 * fabs(A))); }; auto fn_y = [A, s](double t) -> double { return s * sin(PI * fabs(A) * t * t / (2 * fabs(A))); }; + //auto fn_slope = [A](double t) -> double { return sqrt(PI) * t * t / (2 * abs(A)); }; + auto fn_slope = [A](double t) -> double { return pow(t / A, 2) / 2; }; - set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y); + set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y, fn_slope); } #endif @@ -533,18 +536,19 @@ class curve_segment_evaluator { auto fn_x = [theta](double t)->double {return cos(theta(t)); }; auto fn_y = [theta](double t)->double {return sin(theta(t)); }; + auto fn_slope = [](double t)->double { return tan(t); }; double s = 1.0; // @todo: rb - this is supposed to be the curve length when the parametric value u = 1.0 - set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y); + set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y, fn_slope); } #endif void operator()(const IfcSchema::IfcCircle* c) { - auto R = c->Radius(); + auto R = c->Radius() * length_unit_; auto sign_l = sign(length_); - auto start = start_; + auto start_angle = start_/R; auto transformation_matrix = taxonomy::cast(mapping_->map(c->Position()))->ccomponents(); @@ -552,9 +556,9 @@ class curve_segment_evaluator { geometry_adjuster = std::make_shared(mapping_, segment_type_, inst_, next_inst_); - eval_ = [R, start, sign_l, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) + eval_ = [R, start_angle, sign_l, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { - auto angle = start + sign_l * u / R; + auto angle = start_angle + sign_l * u / R; auto dx = cos(angle); auto dy = sin(angle); @@ -702,8 +706,8 @@ class curve_segment_evaluator { auto v = l->Dir(); auto dr = v->Orientation()->DirectionRatios(); auto m = v->Magnitude(); - auto px = c[0]; - auto py = c[1]; + auto px = c[0] * length_unit_; + auto py = c[1] * length_unit_; auto dx = dr[0] / m; auto dy = dr[1] / m; @@ -765,28 +769,35 @@ class curve_segment_evaluator { if (!coeffZ.empty()) Logger::Warning("Expected IfcPolynomialCurve.CoefficientsZ to be undefined for alignment geometry. Coefficients ignored.", p); + + auto transformation_matrix = taxonomy::cast(mapping_->map(p->Position()))->ccomponents(); auto segment_type = segment_type_; + auto length_unit = length_unit_; geometry_adjuster = std::make_shared(mapping_, segment_type_, inst_, next_inst_); - eval_ = [coeffX, coeffY, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { + eval_ = [coeffX, coeffY, transformation_matrix, segment_type, length_unit, geometry_adjuster = this->geometry_adjuster](double u) { std::array*, 2> coefficients{&coeffX, &coeffY}; - std::array position{0.0, 0.0}; + std::array position{0.0, 0.0}; // = SUM(coeff*u^pos) std::array slope{0.0, 0.0}; // slope is derivative of the curve = SUM( coeff*pos*u^(pos-1) ) for (int i = 0; i < 2; i++) { + auto length_conversion = length_unit; auto begin = coefficients[i]->cbegin(); auto end = coefficients[i]->cend(); - for (auto iter = begin; iter != end; iter++) { + for (auto iter = begin; iter != end; iter++) { auto exp = std::distance(begin, iter); - position[i] += (*iter) * pow(u, exp); + auto coeff = (*iter)*length_conversion; + position[i] += coeff* pow(u, exp); if (iter != begin) { - slope[i] += (*iter) * exp * pow(u, exp - 1); + slope[i] += coeff * exp * pow(u, exp - 1); } - } + + length_conversion /= length_unit; + } } auto x = position[0]; diff --git a/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp b/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp index 50383de7ae..f73a14d31b 100644 --- a/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp +++ b/src/ifcgeom/mapping/IfcSegmentedReferenceCurve.cpp @@ -52,8 +52,15 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve* ins auto composition = [gradient, cant](double u)->Eigen::Matrix4d { auto xyz = gradient->evaluate(u); auto c = cant->evaluate(u); + + // when cant results are combined with the gradient curve + // the x-location will be added which doubles them + // for this reason, set x location to 0 c.col(3)(0) = 0; - std::swap(c.col(3)(1),c.col(3)(2)); + + std::swap(c.col(3)(1), c.col(3)(2)); + //c.col(0).swap(c.col(1)); + Eigen::Matrix4d m; m = xyz * c; return m;