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;
}