From 4b933812a7997821328c55a2054035df7058eb90 Mon Sep 17 00:00:00 2001 From: Richard Brice <37087370+RickBrice@users.noreply.github.com> Date: Thu, 7 Dec 2023 08:01:31 -0800 Subject: [PATCH 1/2] Generalized calculation of spiral curve tangent vector --- src/ifcgeom/mapping/IfcCurveSegment.cpp | 32 +++++++------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/ifcgeom/mapping/IfcCurveSegment.cpp b/src/ifcgeom/mapping/IfcCurveSegment.cpp index 91b2a9435b..027b61ddd1 100644 --- a/src/ifcgeom/mapping/IfcCurveSegment.cpp +++ b/src/ifcgeom/mapping/IfcCurveSegment.cpp @@ -99,13 +99,13 @@ class segment_geometry_adjuster { auto next = taxonomy::cast(mapping->map(next_inst)); start_of_next_inst_ = next->evaluate(0.0); } else { - // there is not a next segment, however IfcGradientCurve and IfcSegmentedRefernceCurve + // there is not a next segment, however IfcGradientCurve and IfcSegmentedReferenceCurve // have an optional EndPoint attribute that serves the same purpose as the zero-length // "next segment" at the end of the curve. The Ifc specification is a little redundant // in that the "zero length" segment is required thereby negating the need for EndPoint // but some implementations use the EndPoint instead of the "zero length" segment // - // Get the parent of this segment. If it is a IfcGradientCurve or IfcSegmentedRefernceCurve + // Get the parent of this segment. If it is a IfcGradientCurve or IfcSegmentedReferenceCurve // look for the optional EndPoint attribute auto curves = inst->UsingCurves(); if (curves && curves->size()) { @@ -387,7 +387,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, std::function fnSlope) { + void set_spiral_function(mapping* mapping_, const IfcSchema::IfcSpiral* c, double s, std::function signX, std::function fnX, std::function signY, std::function fnY) { // 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_); @@ -405,7 +405,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, fnSlope, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { + eval_ = [L, start, s, signX, fnX, signY, fnY, transformation_matrix, segment_type, geometry_adjuster = this->geometry_adjuster](double u) { u += start; @@ -419,21 +419,8 @@ class curve_segment_evaluator { // From https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/lexical/IfcSpiral.htm, x = Integral(fnX du), y = Integral(fnY du) // The tangent slope of a curve is the derivate of the curve, so the derivitive of an integral, is just the function - // Therefore, Dx/Du = fnX(u) and Dy/Du = fnY(u) which leads to du = Dx/fnX(u) and Dy = fnY(u)*Du = fnY(u)*Dx/fnX(u) so Dy/Dx = fnY(u)/fnX(u) - // 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 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(b); - auto dx = signX(u) * cos(slope); - auto dy = signY(u) * sin(slope); + auto dx = signX(u)*fnX(b)/s; + auto dy = signY(u)*fnY(b)/s; Eigen::Matrix4d m; if (segment_type == ST_HORIZONTAL) { @@ -534,10 +521,8 @@ 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, s](double t) -> double { return pow(t*s / A, 2) / 2; }; - set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y, fn_slope); + set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y); } #endif @@ -562,10 +547,9 @@ 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, fn_slope); + set_spiral_function(mapping_, c, s, sign_x, fn_x, sign_y, fn_y); } #endif From 84a8c370c1e1a4bcc87361fc1a4da3fb3de3c6ce Mon Sep 17 00:00:00 2001 From: Richard Brice <37087370+RickBrice@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:46:23 -0800 Subject: [PATCH 2/2] Updates representations in IfcAlignment example --- src/examples/IfcAlignment.cpp | 95 ++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 29 deletions(-) diff --git a/src/examples/IfcAlignment.cpp b/src/examples/IfcAlignment.cpp index 4c4d77c26a..56c2711ffd 100644 --- a/src/examples/IfcAlignment.cpp +++ b/src/examples/IfcAlignment.cpp @@ -159,7 +159,12 @@ int main() } auto site = file.addSite(project, nullptr); + auto local_placement = site->ObjectPlacement(); + if (!local_placement) { + local_placement = file.addLocalPlacement(); + } + auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist // // Define horizontal alignment @@ -245,21 +250,43 @@ int main() horizontal_curve_segments->push(terminator_segment.first); horizontal_segments->push(terminator_segment.second); - auto composite_curve = new Schema::IfcCompositeCurve(horizontal_curve_segments, false/*not self-intersecting*/); + // create plan view footprint model representation for the horizontal alignment + + // start by defining a composite curve composed of the horizonal curve segments + auto composite_curve = new Schema::IfcCompositeCurve(horizontal_curve_segments, false /*not self-intersecting*/); file.addEntity(composite_curve); - typename aggregate_of::ptr representation_items(new aggregate_of()); - representation_items->push(composite_curve); + // the composite curve is a representation item + typename aggregate_of::ptr alignment_representation_items(new aggregate_of()); + alignment_representation_items->push(composite_curve); - auto geometric_representation_context = file.getRepresentationContext(std::string("3D")); // creates the representation context if it doesn't already exist - auto representation_subcontext = new Schema::IfcGeometricRepresentationSubContext(std::string("Axis"), std::string("Model"), geometric_representation_context, boost::none, Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_GRAPH_VIEW, boost::none); - file.addEntity(representation_subcontext); - auto shape_representation_2D = new Schema::IfcShapeRepresentation(representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), representation_items); - file.addEntity(shape_representation_2D); + // create the footprint representation subcontext for CT 4.1.7.1.1.2 Alignment Geometry - Horizontal and Vertical + auto footprint_representation_subcontext = new Schema::IfcGeometricRepresentationSubContext(std::string("FootPrint"), std::string("Model"), geometric_representation_context, boost::none, Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW, boost::none); + file.addEntity(footprint_representation_subcontext); - auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr/*representation*/); + // create the footprint representation + auto footprint_shape_representation = new Schema::IfcShapeRepresentation(footprint_representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), alignment_representation_items); + file.addEntity(footprint_shape_representation); + + // create the axis representation subcontext for CT 4.1.7.1.1.1 Alignment Geometry - Horizontal + auto axis2d_representation_subcontext = new Schema::IfcGeometricRepresentationSubContext(std::string("Axis"), std::string("Model"), geometric_representation_context, boost::none, Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW, boost::none); + file.addEntity(axis2d_representation_subcontext); + + // create axis curve 2d representation + auto axis2d_shape_representation = new Schema::IfcShapeRepresentation(axis2d_representation_subcontext, std::string("Axis"), std::string("Curve2D"), alignment_representation_items); + file.addEntity(axis2d_shape_representation); + + // there are two representations for the horizontal alignment (footprint and axis2d) + typename aggregate_of::ptr horizontal_representations(new aggregate_of()); + horizontal_representations->push(footprint_shape_representation); + horizontal_representations->push(axis2d_shape_representation); + + auto horizontal_product = new Schema::IfcProductDefinitionShape(std::string("Horizontal product definition shape"), boost::none, horizontal_representations); + + auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, local_placement, horizontal_product); file.addEntity(horizontal_alignment); + // for the business logic, nest the individual horizontal alignment segment with the alignment auto nests_horizontal_segments = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, boost::none, std::string("Nests horizontal alignment segments with horizontal alignment"), horizontal_alignment, horizontal_segments); file.addEntity(nests_horizontal_segments); @@ -332,33 +359,43 @@ int main() vertical_curve_segments->push(vertical_terminator_segment.first); vertical_segments->push(vertical_terminator_segment.second); - auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, file.getSingle(), nullptr); + // create profile view axis model representation for the vertical profile + + // start by defining a gradient curve composed of the vertical curve segments and associated with the horizont composite curve + auto gradient_curve = new Schema::IfcGradientCurve(vertical_curve_segments, false, composite_curve, nullptr); + + // the gradient curve is a representation item + typename aggregate_of::ptr profile_representation_items(new aggregate_of()); + profile_representation_items->push(gradient_curve); + + // create the axis representation subcontext + auto axis_representation_subcontext = new Schema::IfcGeometricRepresentationSubContext(std::string("Axis"), std::string("Model"), geometric_representation_context, boost::none, Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW, boost::none); + file.addEntity(axis_representation_subcontext); + + // create the axis representation + auto axis_shape_representation = new Schema::IfcShapeRepresentation(axis_representation_subcontext, std::string("Axis"), std::string("Curve3D"), profile_representation_items); + file.addEntity(axis_shape_representation); + + typename aggregate_of::ptr vertical_representations(new aggregate_of()); + vertical_representations->push(axis_shape_representation); + + auto vertical_product = new Schema::IfcProductDefinitionShape(std::string("Vertical product definition shape"), boost::none, vertical_representations); + + auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, local_placement, vertical_product); file.addEntity(vertical_profile); + // for the business logic, nest the individual vertical curve segments with the vertical alignment auto nests_vertical_segments = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, boost::none, std::string("Nests vertical alignment segments with vertical alignment"), vertical_profile, vertical_segments); file.addEntity(nests_vertical_segments); + // the alignment has two representations, a plan view footprint and a 3d axis + typename aggregate_of::ptr alignment_representations(new aggregate_of()); + alignment_representations->push(footprint_shape_representation); // 2D alignment geometry + alignment_representations->push(axis_shape_representation); // 3D alignment geometry - typename aggregate_of::ptr representation_items2(new aggregate_of()); - - auto gradient_curve = new Schema::IfcGradientCurve(vertical_curve_segments, false, composite_curve, nullptr); - representation_items2->push(gradient_curve); - - - auto shape_representation_3D = new Schema::IfcShapeRepresentation(representation_subcontext, std::string("Axis"), std::string("Curve3D"), representation_items2); - file.addEntity(shape_representation_3D); - - typename aggregate_of::ptr representations(new aggregate_of()); - representations->push(shape_representation_2D); // 2D alignment geometry - representations->push(shape_representation_3D); // 3D alignment geometry - auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, representations); + // create the alignment + auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, alignment_representations); - auto local_placement = site->ObjectPlacement(); - if (!local_placement) - { - local_placement = file.addLocalPlacement(); - } - auto alignment = new Schema::IfcAlignment(IfcParse::IfcGlobalId(), nullptr, std::string("Example Alignment"), boost::none, boost::none, local_placement, alignment_product, boost::none); file.addEntity(alignment);