From f49334355825f225a21982b552fc8f1bd00def06 Mon Sep 17 00:00:00 2001 From: Richard Brice <37087370+RickBrice@users.noreply.github.com> Date: Wed, 20 Dec 2023 14:53:20 -0800 Subject: [PATCH] Adds geometric representations for CT 4.1.7.1.1.4 Alignment Geometry - Segments to the IfcAlignment example --- src/examples/IfcAlignment.cpp | 776 +++++++++++++++++++--------------- 1 file changed, 426 insertions(+), 350 deletions(-) diff --git a/src/examples/IfcAlignment.cpp b/src/examples/IfcAlignment.cpp index ecbc07fa25..e00ce75690 100644 --- a/src/examples/IfcAlignment.cpp +++ b/src/examples/IfcAlignment.cpp @@ -1,3 +1,22 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + // This example illustrates the basic of building an alignment model. // The alignment is based on "Bridge Geometry Manual", April 2022 // US Department of Transportation, Federal Highway Administration (FHWA) @@ -14,387 +33,444 @@ #include const double PI = boost::math::constants::pi(); -double ToRadian(double deg) { return PI * deg / 180; } +double to_radian(double deg) { return PI * deg / 180; } #define Schema Ifc4x3_add2 // creates geometry and business logic segments for horizontal alignment tangent runs -std::pair create_tangent(typename Schema::IfcCartesianPoint* p,double dir,double length) -{ - // geometry - auto parent_curve = new Schema::IfcLine( - new Schema::IfcCartesianPoint(std::vector({0,0})), - new Schema::IfcVector(new Schema::IfcDirection(std::vector{1.0, 0.0}), 1.0)); +std::pair create_tangent(typename Schema::IfcCartesianPoint* p, double dir, double length) { + // geometry + auto parent_curve = new Schema::IfcLine( + new Schema::IfcCartesianPoint(std::vector({0, 0})), + new Schema::IfcVector(new Schema::IfcDirection(std::vector{1.0, 0.0}), 1.0)); - auto curve_segment = new Schema::IfcCurveSegment( - Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, - new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{cos(dir), sin(dir)})), - new Schema::IfcLengthMeasure(0.0), // start - new Schema::IfcLengthMeasure(length), - parent_curve); + auto curve_segment = new Schema::IfcCurveSegment( + Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, + new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{cos(dir), sin(dir)})), + new Schema::IfcLengthMeasure(0.0), // start + new Schema::IfcLengthMeasure(length), + parent_curve); - // business logic - auto design_parameters = new Schema::IfcAlignmentHorizontalSegment( - boost::none, boost::none, p, dir, 0.0, 0.0, length, boost::none, - Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE); - - auto alignment_segment = new Schema::IfcAlignmentSegment( - IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); + // business logic + auto design_parameters = new Schema::IfcAlignmentHorizontalSegment( + boost::none, boost::none, p, dir, 0.0, 0.0, length, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE); - return { curve_segment,alignment_segment }; + auto alignment_segment = new Schema::IfcAlignmentSegment( + IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); + + return {curve_segment, alignment_segment}; } // creates geometry and business logic segments for horizontal alignment horizonal curves -std::pair create_hcurve(typename Schema::IfcCartesianPoint* pc, double dir, double radius,double lc) -{ - // geometry - double sign = radius / fabs(radius); - auto parent_curve = new Schema::IfcCircle( - new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector({0, 0})), new Schema::IfcDirection(std::vector{1, 0})), - fabs(radius)); +std::pair create_hcurve(typename Schema::IfcCartesianPoint* pc, double dir, double radius, double lc) { + // geometry + double sign = radius / fabs(radius); + auto parent_curve = new Schema::IfcCircle( + new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector({0, 0})), new Schema::IfcDirection(std::vector{1, 0})), + fabs(radius)); - auto curve_segment = new Schema::IfcCurveSegment( - Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, - new Schema::IfcAxis2Placement2D(pc, new Schema::IfcDirection(std::vector{cos(dir), sin(dir)})) , - new Schema::IfcLengthMeasure(0.0), - new Schema::IfcLengthMeasure(sign * lc), - parent_curve); + auto curve_segment = new Schema::IfcCurveSegment( + Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, + new Schema::IfcAxis2Placement2D(pc, new Schema::IfcDirection(std::vector{cos(dir), sin(dir)})), + new Schema::IfcLengthMeasure(0.0), + new Schema::IfcLengthMeasure(sign * lc), + parent_curve); - // business logic - auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(boost::none, boost::none, pc, dir, radius, radius, lc, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC); - auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr,boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); + // business logic + auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(boost::none, boost::none, pc, dir, radius, radius, lc, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC); + auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); - return { curve_segment,alignment_segment }; + return {curve_segment, alignment_segment}; } // creates geometry and business logic segments for vertical profile gradient runs -std::pair create_gradient(typename Schema::IfcCartesianPoint* p,double slope,double length) -{ - // geometry - auto parent_curve = new Schema::IfcLine( - new Schema::IfcCartesianPoint(std::vector({0, 0})), - new Schema::IfcVector(new Schema::IfcDirection(std::vector{1, 0}), 1.0)); +std::pair create_gradient(typename Schema::IfcCartesianPoint* p, double slope, double length) { + // geometry + auto parent_curve = new Schema::IfcLine( + new Schema::IfcCartesianPoint(std::vector({0, 0})), + new Schema::IfcVector(new Schema::IfcDirection(std::vector{1, 0}), 1.0)); - auto curve_segment = new Schema::IfcCurveSegment( - Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, - new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{sqrt(1-slope*slope), slope})), - new Schema::IfcLengthMeasure(0.0), // start - new Schema::IfcLengthMeasure(length), - parent_curve); + auto curve_segment = new Schema::IfcCurveSegment( + Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, + new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{sqrt(1 - slope * slope), slope})), + new Schema::IfcLengthMeasure(0.0), // start + new Schema::IfcLengthMeasure(length), + parent_curve); - // business logic - auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], slope, slope, boost::none, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT); - auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); + // business logic + auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], slope, slope, boost::none, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT); + auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); - return { curve_segment,alignment_segment }; + return {curve_segment, alignment_segment}; } // creates geometry and business logic segments for vertical profile parabolic vertical curves -std::pair create_vcurve(typename Schema::IfcCartesianPoint* p, double start_slope,double end_slope, double length) -{ - // geometry - double A = 0.0; - double B = start_slope; - double C = (end_slope - start_slope) / (2 * length); +std::pair create_vcurve(typename Schema::IfcCartesianPoint* p, double start_slope, double end_slope, double length) { + // geometry + double A = 0.0; + double B = start_slope; + double C = (end_slope - start_slope) / (2 * length); - auto parent_curve = new Schema::IfcPolynomialCurve( - new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector{0.0, 0.0}), new Schema::IfcDirection(std::vector{1.0, 0.0})), - std::vector{0.0, 1.0}, - std::vector{A, B, C}, boost::none); + auto parent_curve = new Schema::IfcPolynomialCurve( + new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector{0.0, 0.0}), new Schema::IfcDirection(std::vector{1.0, 0.0})), + std::vector{0.0, 1.0}, + std::vector{A, B, C}, + boost::none); - auto curve_segment = new Schema::IfcCurveSegment( - Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, - new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{1.0, 0.0})), - new Schema::IfcLengthMeasure(0.0), - new Schema::IfcLengthMeasure(length), parent_curve); + auto curve_segment = new Schema::IfcCurveSegment( + Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, + new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector{1.0, 0.0})), + new Schema::IfcLengthMeasure(0.0), + new Schema::IfcLengthMeasure(length), + parent_curve); - // business logic - double k = (end_slope - start_slope) / length; - auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], start_slope, end_slope, 1 / k, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_PARABOLICARC); - auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); + // business logic + double k = (end_slope - start_slope) / length; + auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], start_slope, end_slope, 1 / k, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_PARABOLICARC); + auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); - return { curve_segment,alignment_segment }; + return {curve_segment, alignment_segment}; } -int main() -{ - IfcHierarchyHelper file; +// creates representations for each IfcAlignmentSegment per CT 4.1.7.1.1.4 +// https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Product_Shape/Product_Geometric_Representation/Alignment_Geometry/Alignment_Geometry_-_Segments/content.html +void create_segment_representations(IfcHierarchyHelper& file, Schema::IfcLocalPlacement* global_placement, Schema::IfcGeometricRepresentationSubContext* segment_axis_subcontext, typename aggregate_of::ptr curve_segments, typename aggregate_of::ptr segments) { + auto cs_iter = curve_segments->begin(); + auto s_iter = segments->begin(); + for (; cs_iter != curve_segments->end(); cs_iter++, s_iter++) { + auto curve_segment = *cs_iter; + auto alignment_segment = (*s_iter)->as(); - std::vector file_description; - std::ostringstream os; - os << "ViewDefinition[Alignment-basedReferenceView]" << std::ends; - file_description.push_back(os.str().c_str()); - file.header().file_description().description(file_description); + typename aggregate_of::ptr representation_items(new aggregate_of()); + representation_items->push(curve_segment); - auto project = file.addProject(); - project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment")); + auto axis_representation = new Schema::IfcShapeRepresentation(segment_axis_subcontext, std::string("Axis"), std::string("Segment"), representation_items); + file.addEntity(axis_representation); - // set up project units for feet - // the call to file.addProject() sets up length units as millimeter. - auto units_in_context = project->UnitsInContext(); - auto units = units_in_context->Units(); - auto begin = units->begin(); - auto iter = begin; - auto end = units->end(); - for (; iter != end; iter++) - { - auto unit = *iter; - if (unit->as() && unit->as()->UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) - { - auto dimensions = new Schema::IfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0); - file.addEntity(dimensions); - - auto conversion_factor = new Schema::IfcMeasureWithUnit(new Schema::IfcLengthMeasure(304.80), unit->as()); - file.addEntity(conversion_factor); + typename aggregate_of::ptr representations(new aggregate_of()); + representations->push(axis_representation); - auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor); - file.addEntity(conversion_based_unit); + auto product = new Schema::IfcProductDefinitionShape(boost::none, boost::none, representations); + file.addEntity(product); - units->remove(unit); // remove the millimeter unit - units->push(conversion_based_unit); // add the feet unit - units_in_context->setUnits(units); // update the UnitsInContext - - break; // Done!, the length unit was found, so break out of the loop - } - } - - auto site = file.addSite(project, nullptr); - - auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist - - // - // Define horizontal alignment - // - - // define key points - // B.1.4 pg 212 - auto pob = file.addDoublet(500, 2500); // beginning - auto pc1 = file.addDoublet(2142.237995, 1436.014820); // Point of curve (PC), Curve #1 - auto pt1 = file.addDoublet(3660.446123, 2050.736173); // Point of tangent (PT), Curve #1 - auto pc2 = file.addDoublet(4084.115884, 3889.462938); - auto pt2 = file.addDoublet(5469.395067, 4847.566310); - auto pc3 = file.addDoublet(7019.971367, 4638.286073); - auto pt3 = file.addDoublet(7790.932128, 4006.730765); - auto poe = file.addDoublet(8480, 2010); // ending - - // define tangent runs and curve lengths - double run_1 = 1956.785654; - double lc_1 = 1919.222667; - double run_2 = 1886.905454; - double lc_2 = 1848.115835; - double run_3 = 1564.635765; - double lc_3 = 1049.119737; - double run_4 = 2112.285084; - - // define curve radii - double rc_1 = 1000; - double rc_2 = -1250; // negative radius for curves to the right - double rc_3 = -950; - - // bearing of tangents - // pg 17, Eq 2.16 - 2.19 - double angle_1 = ToRadian(327.0613); - double angle_2 = ToRadian(77.0247); - double angle_3 = ToRadian(352.3133); - double angle_4 = ToRadian(289.0395); - - // geometric representations - typename aggregate_of::ptr horizontal_curve_segments(new aggregate_of()); - typename aggregate_of::ptr horizontal_segments(new aggregate_of()); - - // POB to PC1 - auto curve_segment_1 = create_tangent(pob, angle_1, run_1); - horizontal_curve_segments->push(curve_segment_1.first); - horizontal_segments->push(curve_segment_1.second); - - // Curve 1 - auto curve_segment_2 = create_hcurve(pc1, angle_1,rc_1,lc_1); - horizontal_curve_segments->push(curve_segment_2.first); - horizontal_segments->push(curve_segment_2.second); - - // PT1 to PC2 - auto curve_segment_3 = create_tangent(pt1, angle_2, run_2); - horizontal_curve_segments->push(curve_segment_3.first); - horizontal_segments->push(curve_segment_3.second); - - // Curve 2 - auto curve_segment_4 = create_hcurve(pc2, angle_2, rc_2, lc_2); - horizontal_curve_segments->push(curve_segment_4.first); - horizontal_segments->push(curve_segment_4.second); - - // PT2 to PC3 - auto curve_segment_5 = create_tangent(pt2, angle_3, run_3); - horizontal_curve_segments->push(curve_segment_5.first); - horizontal_segments->push(curve_segment_5.second); - - // Curve 3 - auto curve_segment_6 = create_hcurve(pc3, angle_3, rc_3, lc_3); - horizontal_curve_segments->push(curve_segment_6.first); - horizontal_segments->push(curve_segment_6.second); - - // PT3 to POE - auto curve_segment_7 = create_tangent(pt3, angle_4, run_4); - horizontal_curve_segments->push(curve_segment_7.first); - horizontal_segments->push(curve_segment_7.second); - - // Zero-length terminator segment - auto terminator_segment = create_tangent(poe, angle_4, 0.0); - terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS); - horizontal_curve_segments->push(terminator_segment.first); - horizontal_segments->push(terminator_segment.second); - - // 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); - - // the composite curve is a representation item - typename aggregate_of::ptr alignment_representation_items(new aggregate_of()); - alignment_representation_items->push(composite_curve); - - // create the footprint representation subcontext for CT 4.1.7.1.1.2 Alignment Geometry - Horizontal and Vertical - auto axis_model_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_model_representation_subcontext); - - // create the footprint representation - auto footprint_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), alignment_representation_items); - file.addEntity(footprint_shape_representation); - - auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr); - 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); - - // - // Define vertical profile segments - // - - typename aggregate_of::ptr vertical_curve_segments(new aggregate_of()); - typename aggregate_of::ptr vertical_segments(new aggregate_of()); - - // define key profile points - auto vpob = file.addDoublet(0.0, 100.0); // beginning - auto vpc1 = file.addDoublet(1200.0, 121.0); // Vertical Curve Point (VPC), Vertical Curve #1 - auto vpt1 = file.addDoublet(2800.0, 127.0); // Vertical Curve Tangent (VPT), Vertical Curve #1 - auto vpc2 = file.addDoublet(4400.0, 111.0); - auto vpt2 = file.addDoublet(5600.0, 117.0); - auto vpc3 = file.addDoublet(6400.0, 133.0); - auto vpt3 = file.addDoublet(8400.0, 133.0); - auto vpc4 = file.addDoublet(9400.0, 113.0); - auto vpt4 = file.addDoublet(10200.0, 103.0); - auto vpoe = file.addDoublet(12800.0, 90.0); // ending - - // Grade start to VPC1 - auto vertical_profile_segment_1 = create_gradient(vpob, 1.75 / 100, 1200); - vertical_curve_segments->push(vertical_profile_segment_1.first); - vertical_segments->push(vertical_profile_segment_1.second); - - // Vertical Curve 1 - auto vertical_profile_segment_2 = create_vcurve(vpc1, 1.75 / 100, -1.0 / 100, 1600); - vertical_curve_segments->push(vertical_profile_segment_2.first); - vertical_segments->push(vertical_profile_segment_2.second); - - // Grade VPT1 to VPC2 - auto vertical_profile_segment_3 = create_gradient(vpt1, -1.0 / 100, 1600); - vertical_curve_segments->push(vertical_profile_segment_3.first); - vertical_segments->push(vertical_profile_segment_3.second); - - // Vertical Curve 2 - auto vertical_profile_segment_4 = create_vcurve(vpc2, -1.0 / 100, 2.0 / 100, 1200); - vertical_curve_segments->push(vertical_profile_segment_4.first); - vertical_segments->push(vertical_profile_segment_4.second); - - // Grade PVT2 to VPC3 - auto vertical_profile_segment_5 = create_gradient(vpt2, 2.0 / 100, 800); - vertical_curve_segments->push(vertical_profile_segment_5.first); - vertical_segments->push(vertical_profile_segment_5.second); - - // Vertical Curve 3 - auto vertical_profile_segment_6 = create_vcurve(vpc3, 2.0 / 100, -2.0 / 100, 2000); - vertical_curve_segments->push(vertical_profile_segment_6.first); - vertical_segments->push(vertical_profile_segment_6.second); - - // Grade PVT3 to VPC4 - auto vertical_profile_segment_7 = create_gradient(vpt3, -2.0 / 100, 1000); - vertical_curve_segments->push(vertical_profile_segment_7.first); - vertical_segments->push(vertical_profile_segment_7.second); - - // Vertical Curve 4 - auto vertical_profile_segment_8 = create_vcurve(vpc4, -2.0 / 100, -0.5 / 100, 800); - vertical_curve_segments->push(vertical_profile_segment_8.first); - vertical_segments->push(vertical_profile_segment_8.second); - - // Grade VPT4 to End - auto vertical_profile_segment_9 = create_gradient(vpt4, -0.5 / 100, 2600); - vertical_curve_segments->push(vertical_profile_segment_9.first); - vertical_segments->push(vertical_profile_segment_9.second); - - // Zero-length terminator - auto vertical_terminator_segment = create_gradient(vpoe, -0.5 / 100, 0.0); - vertical_curve_segments->push(vertical_terminator_segment.first); - vertical_segments->push(vertical_terminator_segment.second); - - // 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 horizontal 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 - auto axis3d_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("Axis"), std::string("Curve3D"), profile_representation_items); - file.addEntity(axis3d_shape_representation); - - auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, nullptr, nullptr); - 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 curve - typename aggregate_of::ptr alignment_representations(new aggregate_of()); - alignment_representations->push(footprint_shape_representation); // 2D footprint - alignment_representations->push(axis3d_shape_representation); // 3D curve - - // create the alignment - auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, alignment_representations); - - auto alignment = new Schema::IfcAlignment(IfcParse::IfcGlobalId(), nullptr, std::string("Example Alignment"), boost::none, boost::none, site->ObjectPlacement(), alignment_product, boost::none); - file.addEntity(alignment); - - // 4.1.4.4.1 Alignments nest horizontal and vertical layouts - // https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Object_Composition/Nesting/Alignment_Layouts/content.html - typename aggregate_of::ptr alignment_layout_list(new aggregate_of()); - alignment_layout_list->push(horizontal_alignment); - alignment_layout_list->push(vertical_profile); - - auto nests_alignment_layouts = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, std::string("Nest horizontal and vertical alignment layouts with the alignment"), boost::none, alignment, alignment_layout_list); - file.addEntity(nests_alignment_layouts); - - // IFC 4.1.4.1.1 "Every IfcAlignment must be related to IfcProject using the IfcRelAggregates relationship" - // https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Object_Composition/Aggregation/Alignment_Aggregation_To_Project/content.html - // IfcProject <-> IfcRelAggregates <-> IfcAlignment - typename aggregate_of::ptr list_of_alignments_in_project(new aggregate_of()); - list_of_alignments_in_project->push(alignment); - auto aggregate_alignments_with_project = new Schema::IfcRelAggregates(IfcParse::IfcGlobalId(), nullptr, std::string("Alignments in project"), boost::none, project, list_of_alignments_in_project); - file.addEntity(aggregate_alignments_with_project); - - // IFC 4.1.5.1 alignment is referenced in spatial structure of an IfcSpatialElement. In this case IfcSite is the highest level IfcSpatialElement - // https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Object_Connectivity/Alignment_Spatial_Reference/content.html - // IfcSite <-> IfcRelReferencedInSpatialStructure <-> IfcAlignment - // This means IfcAlignment is not part of the IfcSite (it is not an aggregate component) but instead IfcAlignment is used within - // the IfcSite by reference. This implies an IfcAlignment can traverse many IfcSite instances within an IfcProject - typename Schema::IfcSpatialReferenceSelect::list::ptr list_alignments_referenced_in_site(new Schema::IfcSpatialReferenceSelect::list); - list_alignments_referenced_in_site->push(alignment); - auto rel_referenced_in_spatial_structure = new Schema::IfcRelReferencedInSpatialStructure(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, list_alignments_referenced_in_site, site); - file.addEntity(rel_referenced_in_spatial_structure); - - std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example.ifc"); - ofs << file; + alignment_segment->setObjectPlacement(global_placement); + alignment_segment->setRepresentation(product); + } +} + +int main() { + IfcHierarchyHelper file; + + std::vector file_description; + file_description.push_back("ViewDefinition[Alignment-basedReferenceView]"); + file.header().file_description().description(file_description); + + auto project = file.addProject(); + project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment")); + + // set up project units for feet + // the call to file.addProject() sets up length units as millimeter. + auto units_in_context = project->UnitsInContext(); + auto units = units_in_context->Units(); + auto begin = units->begin(); + auto iter = begin; + auto end = units->end(); + for (; iter != end; iter++) { + auto unit = *iter; + if (unit->as() && unit->as()->UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) { + auto dimensions = new Schema::IfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0); + file.addEntity(dimensions); + + auto conversion_factor = new Schema::IfcMeasureWithUnit(new Schema::IfcLengthMeasure(304.80), unit->as()); + file.addEntity(conversion_factor); + + auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor); + file.addEntity(conversion_based_unit); + + units->remove(unit); // remove the millimeter unit + units->push(conversion_based_unit); // add the feet unit + units_in_context->setUnits(units); // update the UnitsInContext + + break; // Done!, the length unit was found, so break out of the loop + } + } + + auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist + + auto axis_model_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_model_representation_subcontext); + + auto global_placement = file.addLocalPlacement(); + + // + // Define horizontal alignment + // + + // define key points + // B.1.4 pg 212 + auto pob = file.addDoublet(500, 2500); // beginning + auto pc1 = file.addDoublet(2142.237995, 1436.014820); // Point of curve (PC), Curve #1 + auto pt1 = file.addDoublet(3660.446123, 2050.736173); // Point of tangent (PT), Curve #1 + auto pc2 = file.addDoublet(4084.115884, 3889.462938); // Point of curve (PC), Curve #2 + auto pt2 = file.addDoublet(5469.395067, 4847.566310); // Point of tangent (PT), Curve #2 + auto pc3 = file.addDoublet(7019.971367, 4638.286073); // Point of curve (PC), Curve #3 + auto pt3 = file.addDoublet(7790.932128, 4006.730765); // Point of tangent (PT), Curve #3 + auto poe = file.addDoublet(8480, 2010); // ending + + // define tangent runs and curve lengths + double run_1 = 1956.785654; + double lc_1 = 1919.222667; + double run_2 = 1886.905454; + double lc_2 = 1848.115835; + double run_3 = 1564.635765; + double lc_3 = 1049.119737; + double run_4 = 2112.285084; + + // define curve radii + double rc_1 = 1000; + double rc_2 = -1250; // negative radius for curves to the right + double rc_3 = -950; + + // bearing of tangents + double angle_1 = to_radian(327.0613); + double angle_2 = to_radian(77.0247); + double angle_3 = to_radian(352.3133); + double angle_4 = to_radian(289.0395); + + // create containers to store the curve segments + typename aggregate_of::ptr horizontal_curve_segments(new aggregate_of()); // geometry + typename aggregate_of::ptr horizontal_segments(new aggregate_of()); // business logic + + // + // Build the horizontal alignment segments + // + + // POB to PC1 + auto curve_segment_1 = create_tangent(pob, angle_1, run_1); + horizontal_curve_segments->push(curve_segment_1.first); + horizontal_segments->push(curve_segment_1.second); + + // Curve 1 + auto curve_segment_2 = create_hcurve(pc1, angle_1, rc_1, lc_1); + horizontal_curve_segments->push(curve_segment_2.first); + horizontal_segments->push(curve_segment_2.second); + + // PT1 to PC2 + auto curve_segment_3 = create_tangent(pt1, angle_2, run_2); + horizontal_curve_segments->push(curve_segment_3.first); + horizontal_segments->push(curve_segment_3.second); + + // Curve 2 + auto curve_segment_4 = create_hcurve(pc2, angle_2, rc_2, lc_2); + horizontal_curve_segments->push(curve_segment_4.first); + horizontal_segments->push(curve_segment_4.second); + + // PT2 to PC3 + auto curve_segment_5 = create_tangent(pt2, angle_3, run_3); + horizontal_curve_segments->push(curve_segment_5.first); + horizontal_segments->push(curve_segment_5.second); + + // Curve 3 + auto curve_segment_6 = create_hcurve(pc3, angle_3, rc_3, lc_3); + horizontal_curve_segments->push(curve_segment_6.first); + horizontal_segments->push(curve_segment_6.second); + + // PT3 to POE + auto curve_segment_7 = create_tangent(pt3, angle_4, run_4); + horizontal_curve_segments->push(curve_segment_7.first); + horizontal_segments->push(curve_segment_7.second); + + // Zero-length terminator segment + auto terminator_segment = create_tangent(poe, angle_4, 0.0); + terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS); + horizontal_curve_segments->push(terminator_segment.first); + horizontal_segments->push(terminator_segment.second); + + // + // Create the horizontal alignment (IfcAlignmentHorizontal) and nest alignment segments + // + auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr); + file.addEntity(horizontal_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); + + // + // 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); + + // the composite curve is a representation item + typename aggregate_of::ptr alignment_representation_items(new aggregate_of()); + alignment_representation_items->push(composite_curve); + + // create the footprint representation + auto footprint_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), alignment_representation_items); + file.addEntity(footprint_shape_representation); + + // + // Define vertical profile segments + // + + // create containers to store the curve segments + typename aggregate_of::ptr vertical_curve_segments(new aggregate_of()); // geometry + typename aggregate_of::ptr vertical_segments(new aggregate_of()); // business logic + + // define key profile points + auto vpob = file.addDoublet(0.0, 100.0); // beginning + auto vpc1 = file.addDoublet(1200.0, 121.0); // Vertical Curve Point (VPC), Vertical Curve #1 + auto vpt1 = file.addDoublet(2800.0, 127.0); // Vertical Curve Tangent (VPT), Vertical Curve #1 + auto vpc2 = file.addDoublet(4400.0, 111.0); // Vertical Curve Point (VPC), Vertical Curve #2 + auto vpt2 = file.addDoublet(5600.0, 117.0); // Vertical Curve Tangent (VPT), Vertical Curve #2 + auto vpc3 = file.addDoublet(6400.0, 133.0); // Vertical Curve Point (VPC), Vertical Curve #3 + auto vpt3 = file.addDoublet(8400.0, 133.0); // Vertical Curve Tangent (VPT), Vertical Curve #3 + auto vpc4 = file.addDoublet(9400.0, 113.0); // Vertical Curve Point (VPC), Vertical Curve #4 + auto vpt4 = file.addDoublet(10200.0, 103.0); // Vertical Curve Tangent (VPT), Vertical Curve #4 + auto vpoe = file.addDoublet(12800.0, 90.0); // ending + + // + // Build the vertical alignment segments + // + + // Grade start to VPC1 + auto vertical_profile_segment_1 = create_gradient(vpob, 1.75 / 100, 1200); + vertical_curve_segments->push(vertical_profile_segment_1.first); + vertical_segments->push(vertical_profile_segment_1.second); + + // Vertical Curve 1 + auto vertical_profile_segment_2 = create_vcurve(vpc1, 1.75 / 100, -1.0 / 100, 1600); + vertical_curve_segments->push(vertical_profile_segment_2.first); + vertical_segments->push(vertical_profile_segment_2.second); + + // Grade VPT1 to VPC2 + auto vertical_profile_segment_3 = create_gradient(vpt1, -1.0 / 100, 1600); + vertical_curve_segments->push(vertical_profile_segment_3.first); + vertical_segments->push(vertical_profile_segment_3.second); + + // Vertical Curve 2 + auto vertical_profile_segment_4 = create_vcurve(vpc2, -1.0 / 100, 2.0 / 100, 1200); + vertical_curve_segments->push(vertical_profile_segment_4.first); + vertical_segments->push(vertical_profile_segment_4.second); + + // Grade PVT2 to VPC3 + auto vertical_profile_segment_5 = create_gradient(vpt2, 2.0 / 100, 800); + vertical_curve_segments->push(vertical_profile_segment_5.first); + vertical_segments->push(vertical_profile_segment_5.second); + + // Vertical Curve 3 + auto vertical_profile_segment_6 = create_vcurve(vpc3, 2.0 / 100, -2.0 / 100, 2000); + vertical_curve_segments->push(vertical_profile_segment_6.first); + vertical_segments->push(vertical_profile_segment_6.second); + + // Grade PVT3 to VPC4 + auto vertical_profile_segment_7 = create_gradient(vpt3, -2.0 / 100, 1000); + vertical_curve_segments->push(vertical_profile_segment_7.first); + vertical_segments->push(vertical_profile_segment_7.second); + + // Vertical Curve 4 + auto vertical_profile_segment_8 = create_vcurve(vpc4, -2.0 / 100, -0.5 / 100, 800); + vertical_curve_segments->push(vertical_profile_segment_8.first); + vertical_segments->push(vertical_profile_segment_8.second); + + // Grade VPT4 to End + auto vertical_profile_segment_9 = create_gradient(vpt4, -0.5 / 100, 2600); + vertical_curve_segments->push(vertical_profile_segment_9.first); + vertical_segments->push(vertical_profile_segment_9.second); + + // Zero-length terminator + auto vertical_terminator_segment = create_gradient(vpoe, -0.5 / 100, 0.0); + vertical_curve_segments->push(vertical_terminator_segment.first); + vertical_segments->push(vertical_terminator_segment.second); + + // + // Create the vertical alignment (IfcAlignmentVertical) and nest alignment segments + // + auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, nullptr, nullptr); + file.addEntity(vertical_profile); + + 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); + + // + // 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 horizontal 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 + auto axis3d_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("Axis"), std::string("Curve3D"), profile_representation_items); + file.addEntity(axis3d_shape_representation); + + // create axis representations for each segment + create_segment_representations(file, global_placement, axis_model_representation_subcontext, horizontal_curve_segments, horizontal_segments); + create_segment_representations(file, global_placement, axis_model_representation_subcontext, vertical_curve_segments, vertical_segments); + + // + // Create the IfcAlignment + // + + // the alignment has two representations, a plan view footprint and a 3d curve + typename aggregate_of::ptr alignment_representations(new aggregate_of()); + alignment_representations->push(footprint_shape_representation); // 2D footprint + alignment_representations->push(axis3d_shape_representation); // 3D curve + + // create the alignment product definition + auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, alignment_representations); + + // create the alignment + auto alignment = new Schema::IfcAlignment(IfcParse::IfcGlobalId(), nullptr, std::string("Example Alignment"), boost::none, boost::none, global_placement, alignment_product, boost::none); + file.addEntity(alignment); + + // Nest the IfcAlignmentHorizontal and IfcAlignmentVertical with the IfcAlignment to complete the business logic + // 4.1.4.4.1 Alignments nest horizontal and vertical layouts + // https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Composition/Nesting/Alignment_Layouts/content.html + typename aggregate_of::ptr alignment_layout_list(new aggregate_of()); + alignment_layout_list->push(horizontal_alignment); + alignment_layout_list->push(vertical_profile); + + auto nests_alignment_layouts = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, std::string("Nest horizontal and vertical alignment layouts with the alignment"), boost::none, alignment, alignment_layout_list); + file.addEntity(nests_alignment_layouts); + + // Define the relationship with the project + + // IFC 4.1.4.1.1 "Every IfcAlignment must be related to IfcProject using the IfcRelAggregates relationship" + // https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Composition/Aggregation/Alignment_Aggregation_To_Project/content.html + // IfcProject <-> IfcRelAggregates <-> IfcAlignment + typename aggregate_of::ptr list_of_alignments_in_project(new aggregate_of()); + list_of_alignments_in_project->push(alignment); + auto aggregate_alignments_with_project = new Schema::IfcRelAggregates(IfcParse::IfcGlobalId(), nullptr, std::string("Alignments in project"), boost::none, project, list_of_alignments_in_project); + file.addEntity(aggregate_alignments_with_project); + + // Define the spatial structure of the alignment with respect to the site + + // IFC 4.1.5.1 alignment is referenced in spatial structure of an IfcSpatialElement. In this case IfcSite is the highest level IfcSpatialElement + // https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Connectivity/Alignment_Spatial_Reference/content.html + // IfcSite <-> IfcRelReferencedInSpatialStructure <-> IfcAlignment + // This means IfcAlignment is not part of the IfcSite (it is not an aggregate component) but instead IfcAlignment is used within + // the IfcSite by reference. This implies an IfcAlignment can traverse many IfcSite instances within an IfcProject + typename Schema::IfcSpatialReferenceSelect::list::ptr list_alignments_referenced_in_site(new Schema::IfcSpatialReferenceSelect::list); + list_alignments_referenced_in_site->push(alignment); + + // this alignment traverse 3 bridge sites. + for (int i = 1; i <= 3; i++) { + std::ostringstream os; + os << "Site of Bridge " << i; + auto site = file.addSite(project, nullptr); + site->setName(os.str()); + + auto rel_referenced_in_spatial_structure = new Schema::IfcRelReferencedInSpatialStructure(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, list_alignments_referenced_in_site, site); + file.addEntity(rel_referenced_in_spatial_structure); + } + + // That's it - save the model to a file + std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example.ifc"); + ofs << file; }