Adds geometric representations for CT 4.1.7.1.1.4 Alignment Geometry - Segments to the IfcAlignment example

This commit is contained in:
Richard Brice
2023-12-20 14:53:20 -08:00
parent d5da636b00
commit f493343558
+425 -349
View File
@@ -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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
// This example illustrates the basic of building an alignment model. // This example illustrates the basic of building an alignment model.
// The alignment is based on "Bridge Geometry Manual", April 2022 // The alignment is based on "Bridge Geometry Manual", April 2022
// US Department of Transportation, Federal Highway Administration (FHWA) // US Department of Transportation, Federal Highway Administration (FHWA)
@@ -14,387 +33,444 @@
#include <boost/math/constants/constants.hpp> #include <boost/math/constants/constants.hpp>
const double PI = boost::math::constants::pi<double>(); const double PI = boost::math::constants::pi<double>();
double ToRadian(double deg) { return PI * deg / 180; } double to_radian(double deg) { return PI * deg / 180; }
#define Schema Ifc4x3_add2 #define Schema Ifc4x3_add2
// creates geometry and business logic segments for horizontal alignment tangent runs // creates geometry and business logic segments for horizontal alignment tangent runs
std::pair<typename Schema::IfcCurveSegment*,typename Schema::IfcAlignmentSegment*> create_tangent(typename Schema::IfcCartesianPoint* p,double dir,double length) std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_tangent(typename Schema::IfcCartesianPoint* p, double dir, double length) {
{ // geometry
// geometry auto parent_curve = new Schema::IfcLine(
auto parent_curve = new Schema::IfcLine( new Schema::IfcCartesianPoint(std::vector<double>({0, 0})),
new Schema::IfcCartesianPoint(std::vector<double>({0,0})), new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1.0, 0.0}), 1.0));
new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1.0, 0.0}), 1.0));
auto curve_segment = new Schema::IfcCurveSegment( auto curve_segment = new Schema::IfcCurveSegment(
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})), new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})),
new Schema::IfcLengthMeasure(0.0), // start new Schema::IfcLengthMeasure(0.0), // start
new Schema::IfcLengthMeasure(length), new Schema::IfcLengthMeasure(length),
parent_curve); parent_curve);
// business logic // business logic
auto design_parameters = new Schema::IfcAlignmentHorizontalSegment( auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(
boost::none, boost::none, p, dir, 0.0, 0.0, length, boost::none, boost::none, boost::none, p, dir, 0.0, 0.0, length, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE);
Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE);
auto alignment_segment = new Schema::IfcAlignmentSegment( auto alignment_segment = new Schema::IfcAlignmentSegment(
IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters); 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 horizontal alignment horizonal curves // creates geometry and business logic segments for horizontal alignment horizonal curves
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_hcurve(typename Schema::IfcCartesianPoint* pc, double dir, double radius,double lc) std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_hcurve(typename Schema::IfcCartesianPoint* pc, double dir, double radius, double lc) {
{ // geometry
// geometry double sign = radius / fabs(radius);
double sign = radius / fabs(radius); auto parent_curve = new Schema::IfcCircle(
auto parent_curve = new Schema::IfcCircle( new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>({0, 0})), new Schema::IfcDirection(std::vector<double>{1, 0})),
new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>({0, 0})), new Schema::IfcDirection(std::vector<double>{1, 0})), fabs(radius));
fabs(radius));
auto curve_segment = new Schema::IfcCurveSegment( auto curve_segment = new Schema::IfcCurveSegment(
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
new Schema::IfcAxis2Placement2D(pc, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})) , new Schema::IfcAxis2Placement2D(pc, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})),
new Schema::IfcLengthMeasure(0.0), new Schema::IfcLengthMeasure(0.0),
new Schema::IfcLengthMeasure(sign * lc), new Schema::IfcLengthMeasure(sign * lc),
parent_curve); parent_curve);
// business logic // business logic
auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(boost::none, boost::none, pc, dir, radius, radius, lc, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC); 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); 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 // creates geometry and business logic segments for vertical profile gradient runs
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_gradient(typename Schema::IfcCartesianPoint* p,double slope,double length) std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_gradient(typename Schema::IfcCartesianPoint* p, double slope, double length) {
{ // geometry
// geometry auto parent_curve = new Schema::IfcLine(
auto parent_curve = new Schema::IfcLine( new Schema::IfcCartesianPoint(std::vector<double>({0, 0})),
new Schema::IfcCartesianPoint(std::vector<double>({0, 0})), new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1, 0}), 1.0));
new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1, 0}), 1.0));
auto curve_segment = new Schema::IfcCurveSegment( auto curve_segment = new Schema::IfcCurveSegment(
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{sqrt(1-slope*slope), slope})), new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{sqrt(1 - slope * slope), slope})),
new Schema::IfcLengthMeasure(0.0), // start new Schema::IfcLengthMeasure(0.0), // start
new Schema::IfcLengthMeasure(length), new Schema::IfcLengthMeasure(length),
parent_curve); parent_curve);
// business logic // 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 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); 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 // creates geometry and business logic segments for vertical profile parabolic vertical curves
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_vcurve(typename Schema::IfcCartesianPoint* p, double start_slope,double end_slope, double length) std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_vcurve(typename Schema::IfcCartesianPoint* p, double start_slope, double end_slope, double length) {
{ // geometry
// geometry double A = 0.0;
double A = 0.0; double B = start_slope;
double B = start_slope; double C = (end_slope - start_slope) / (2 * length);
double C = (end_slope - start_slope) / (2 * length);
auto parent_curve = new Schema::IfcPolynomialCurve( auto parent_curve = new Schema::IfcPolynomialCurve(
new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>{0.0, 0.0}), new Schema::IfcDirection(std::vector<double>{1.0, 0.0})), new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>{0.0, 0.0}), new Schema::IfcDirection(std::vector<double>{1.0, 0.0})),
std::vector<double>{0.0, 1.0}, std::vector<double>{0.0, 1.0},
std::vector<double>{A, B, C}, boost::none); std::vector<double>{A, B, C},
boost::none);
auto curve_segment = new Schema::IfcCurveSegment( auto curve_segment = new Schema::IfcCurveSegment(
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{1.0, 0.0})), new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{1.0, 0.0})),
new Schema::IfcLengthMeasure(0.0), new Schema::IfcLengthMeasure(0.0),
new Schema::IfcLengthMeasure(length), parent_curve); new Schema::IfcLengthMeasure(length),
parent_curve);
// business logic // business logic
double k = (end_slope - start_slope) / length; 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 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); 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() // 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
IfcHierarchyHelper<Schema> file; void create_segment_representations(IfcHierarchyHelper<Schema>& file, Schema::IfcLocalPlacement* global_placement, Schema::IfcGeometricRepresentationSubContext* segment_axis_subcontext, typename aggregate_of<typename Schema::IfcSegment>::ptr curve_segments, typename aggregate_of<typename Schema::IfcObjectDefinition>::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<Schema::IfcAlignmentSegment>();
std::vector<std::string> file_description; typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
std::ostringstream os; representation_items->push(curve_segment);
os << "ViewDefinition[Alignment-basedReferenceView]" << std::ends;
file_description.push_back(os.str().c_str());
file.header().file_description().description(file_description);
auto project = file.addProject(); auto axis_representation = new Schema::IfcShapeRepresentation(segment_axis_subcontext, std::string("Axis"), std::string("Segment"), representation_items);
project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment")); file.addEntity(axis_representation);
// set up project units for feet typename aggregate_of<typename Schema::IfcRepresentation>::ptr representations(new aggregate_of<typename Schema::IfcRepresentation>());
// the call to file.addProject() sets up length units as millimeter. representations->push(axis_representation);
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<Schema::IfcSIUnit>() && unit->as<Schema::IfcSIUnit>()->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<Schema::IfcSIUnit>()); auto product = new Schema::IfcProductDefinitionShape(boost::none, boost::none, representations);
file.addEntity(conversion_factor); file.addEntity(product);
auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor); alignment_segment->setObjectPlacement(global_placement);
file.addEntity(conversion_based_unit); alignment_segment->setRepresentation(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 int main() {
IfcHierarchyHelper<Schema> file;
break; // Done!, the length unit was found, so break out of the loop
} std::vector<std::string> file_description;
} file_description.push_back("ViewDefinition[Alignment-basedReferenceView]");
file.header().file_description().description(file_description);
auto site = file.addSite(project, nullptr);
auto project = file.addProject();
auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment"));
// // set up project units for feet
// Define horizontal alignment // the call to file.addProject() sets up length units as millimeter.
// auto units_in_context = project->UnitsInContext();
auto units = units_in_context->Units();
// define key points auto begin = units->begin();
// B.1.4 pg 212 auto iter = begin;
auto pob = file.addDoublet<Schema::IfcCartesianPoint>(500, 2500); // beginning auto end = units->end();
auto pc1 = file.addDoublet<Schema::IfcCartesianPoint>(2142.237995, 1436.014820); // Point of curve (PC), Curve #1 for (; iter != end; iter++) {
auto pt1 = file.addDoublet<Schema::IfcCartesianPoint>(3660.446123, 2050.736173); // Point of tangent (PT), Curve #1 auto unit = *iter;
auto pc2 = file.addDoublet<Schema::IfcCartesianPoint>(4084.115884, 3889.462938); if (unit->as<Schema::IfcSIUnit>() && unit->as<Schema::IfcSIUnit>()->UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) {
auto pt2 = file.addDoublet<Schema::IfcCartesianPoint>(5469.395067, 4847.566310); auto dimensions = new Schema::IfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0);
auto pc3 = file.addDoublet<Schema::IfcCartesianPoint>(7019.971367, 4638.286073); file.addEntity(dimensions);
auto pt3 = file.addDoublet<Schema::IfcCartesianPoint>(7790.932128, 4006.730765);
auto poe = file.addDoublet<Schema::IfcCartesianPoint>(8480, 2010); // ending auto conversion_factor = new Schema::IfcMeasureWithUnit(new Schema::IfcLengthMeasure(304.80), unit->as<Schema::IfcSIUnit>());
file.addEntity(conversion_factor);
// define tangent runs and curve lengths
double run_1 = 1956.785654; auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor);
double lc_1 = 1919.222667; file.addEntity(conversion_based_unit);
double run_2 = 1886.905454;
double lc_2 = 1848.115835; units->remove(unit); // remove the millimeter unit
double run_3 = 1564.635765; units->push(conversion_based_unit); // add the feet unit
double lc_3 = 1049.119737; units_in_context->setUnits(units); // update the UnitsInContext
double run_4 = 2112.285084;
break; // Done!, the length unit was found, so break out of the loop
// define curve radii }
double rc_1 = 1000; }
double rc_2 = -1250; // negative radius for curves to the right
double rc_3 = -950; auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist
// bearing of tangents 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);
// pg 17, Eq 2.16 - 2.19 file.addEntity(axis_model_representation_subcontext);
double angle_1 = ToRadian(327.0613);
double angle_2 = ToRadian(77.0247); auto global_placement = file.addLocalPlacement();
double angle_3 = ToRadian(352.3133);
double angle_4 = ToRadian(289.0395); //
// Define horizontal alignment
// geometric representations //
typename aggregate_of<typename Schema::IfcSegment>::ptr horizontal_curve_segments(new aggregate_of<typename Schema::IfcSegment>());
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr horizontal_segments(new aggregate_of<typename Schema::IfcObjectDefinition>()); // define key points
// B.1.4 pg 212
// POB to PC1 auto pob = file.addDoublet<Schema::IfcCartesianPoint>(500, 2500); // beginning
auto curve_segment_1 = create_tangent(pob, angle_1, run_1); auto pc1 = file.addDoublet<Schema::IfcCartesianPoint>(2142.237995, 1436.014820); // Point of curve (PC), Curve #1
horizontal_curve_segments->push(curve_segment_1.first); auto pt1 = file.addDoublet<Schema::IfcCartesianPoint>(3660.446123, 2050.736173); // Point of tangent (PT), Curve #1
horizontal_segments->push(curve_segment_1.second); auto pc2 = file.addDoublet<Schema::IfcCartesianPoint>(4084.115884, 3889.462938); // Point of curve (PC), Curve #2
auto pt2 = file.addDoublet<Schema::IfcCartesianPoint>(5469.395067, 4847.566310); // Point of tangent (PT), Curve #2
// Curve 1 auto pc3 = file.addDoublet<Schema::IfcCartesianPoint>(7019.971367, 4638.286073); // Point of curve (PC), Curve #3
auto curve_segment_2 = create_hcurve(pc1, angle_1,rc_1,lc_1); auto pt3 = file.addDoublet<Schema::IfcCartesianPoint>(7790.932128, 4006.730765); // Point of tangent (PT), Curve #3
horizontal_curve_segments->push(curve_segment_2.first); auto poe = file.addDoublet<Schema::IfcCartesianPoint>(8480, 2010); // ending
horizontal_segments->push(curve_segment_2.second);
// define tangent runs and curve lengths
// PT1 to PC2 double run_1 = 1956.785654;
auto curve_segment_3 = create_tangent(pt1, angle_2, run_2); double lc_1 = 1919.222667;
horizontal_curve_segments->push(curve_segment_3.first); double run_2 = 1886.905454;
horizontal_segments->push(curve_segment_3.second); double lc_2 = 1848.115835;
double run_3 = 1564.635765;
// Curve 2 double lc_3 = 1049.119737;
auto curve_segment_4 = create_hcurve(pc2, angle_2, rc_2, lc_2); double run_4 = 2112.285084;
horizontal_curve_segments->push(curve_segment_4.first);
horizontal_segments->push(curve_segment_4.second); // define curve radii
double rc_1 = 1000;
// PT2 to PC3 double rc_2 = -1250; // negative radius for curves to the right
auto curve_segment_5 = create_tangent(pt2, angle_3, run_3); double rc_3 = -950;
horizontal_curve_segments->push(curve_segment_5.first);
horizontal_segments->push(curve_segment_5.second); // bearing of tangents
double angle_1 = to_radian(327.0613);
// Curve 3 double angle_2 = to_radian(77.0247);
auto curve_segment_6 = create_hcurve(pc3, angle_3, rc_3, lc_3); double angle_3 = to_radian(352.3133);
horizontal_curve_segments->push(curve_segment_6.first); double angle_4 = to_radian(289.0395);
horizontal_segments->push(curve_segment_6.second);
// create containers to store the curve segments
// PT3 to POE typename aggregate_of<typename Schema::IfcSegment>::ptr horizontal_curve_segments(new aggregate_of<typename Schema::IfcSegment>()); // geometry
auto curve_segment_7 = create_tangent(pt3, angle_4, run_4); typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr horizontal_segments(new aggregate_of<typename Schema::IfcObjectDefinition>()); // business logic
horizontal_curve_segments->push(curve_segment_7.first);
horizontal_segments->push(curve_segment_7.second); //
// Build the horizontal alignment segments
// Zero-length terminator segment //
auto terminator_segment = create_tangent(poe, angle_4, 0.0);
terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS); // POB to PC1
horizontal_curve_segments->push(terminator_segment.first); auto curve_segment_1 = create_tangent(pob, angle_1, run_1);
horizontal_segments->push(terminator_segment.second); horizontal_curve_segments->push(curve_segment_1.first);
horizontal_segments->push(curve_segment_1.second);
// create plan view footprint model representation for the horizontal alignment
// Curve 1
// start by defining a composite curve composed of the horizonal curve segments auto curve_segment_2 = create_hcurve(pc1, angle_1, rc_1, lc_1);
auto composite_curve = new Schema::IfcCompositeCurve(horizontal_curve_segments, false /*not self-intersecting*/); horizontal_curve_segments->push(curve_segment_2.first);
file.addEntity(composite_curve); horizontal_segments->push(curve_segment_2.second);
// the composite curve is a representation item // PT1 to PC2
typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr alignment_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>()); auto curve_segment_3 = create_tangent(pt1, angle_2, run_2);
alignment_representation_items->push(composite_curve); horizontal_curve_segments->push(curve_segment_3.first);
horizontal_segments->push(curve_segment_3.second);
// 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); // Curve 2
file.addEntity(axis_model_representation_subcontext); auto curve_segment_4 = create_hcurve(pc2, angle_2, rc_2, lc_2);
horizontal_curve_segments->push(curve_segment_4.first);
// create the footprint representation horizontal_segments->push(curve_segment_4.second);
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); // PT2 to PC3
auto curve_segment_5 = create_tangent(pt2, angle_3, run_3);
auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr); horizontal_curve_segments->push(curve_segment_5.first);
file.addEntity(horizontal_alignment); horizontal_segments->push(curve_segment_5.second);
// for the business logic, nest the individual horizontal alignment segment with the alignment // Curve 3
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); auto curve_segment_6 = create_hcurve(pc3, angle_3, rc_3, lc_3);
file.addEntity(nests_horizontal_segments); horizontal_curve_segments->push(curve_segment_6.first);
horizontal_segments->push(curve_segment_6.second);
//
// Define vertical profile segments // PT3 to POE
// auto curve_segment_7 = create_tangent(pt3, angle_4, run_4);
horizontal_curve_segments->push(curve_segment_7.first);
typename aggregate_of<typename Schema::IfcSegment>::ptr vertical_curve_segments(new aggregate_of<typename Schema::IfcSegment>()); horizontal_segments->push(curve_segment_7.second);
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr vertical_segments(new aggregate_of<typename Schema::IfcObjectDefinition>());
// Zero-length terminator segment
// define key profile points auto terminator_segment = create_tangent(poe, angle_4, 0.0);
auto vpob = file.addDoublet<Schema::IfcCartesianPoint>(0.0, 100.0); // beginning terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS);
auto vpc1 = file.addDoublet<Schema::IfcCartesianPoint>(1200.0, 121.0); // Vertical Curve Point (VPC), Vertical Curve #1 horizontal_curve_segments->push(terminator_segment.first);
auto vpt1 = file.addDoublet<Schema::IfcCartesianPoint>(2800.0, 127.0); // Vertical Curve Tangent (VPT), Vertical Curve #1 horizontal_segments->push(terminator_segment.second);
auto vpc2 = file.addDoublet<Schema::IfcCartesianPoint>(4400.0, 111.0);
auto vpt2 = file.addDoublet<Schema::IfcCartesianPoint>(5600.0, 117.0); //
auto vpc3 = file.addDoublet<Schema::IfcCartesianPoint>(6400.0, 133.0); // Create the horizontal alignment (IfcAlignmentHorizontal) and nest alignment segments
auto vpt3 = file.addDoublet<Schema::IfcCartesianPoint>(8400.0, 133.0); //
auto vpc4 = file.addDoublet<Schema::IfcCartesianPoint>(9400.0, 113.0); auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr);
auto vpt4 = file.addDoublet<Schema::IfcCartesianPoint>(10200.0, 103.0); file.addEntity(horizontal_alignment);
auto vpoe = file.addDoublet<Schema::IfcCartesianPoint>(12800.0, 90.0); // ending
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);
// Grade start to VPC1 file.addEntity(nests_horizontal_segments);
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); // Create plan view footprint model representation for the horizontal alignment
//
// Vertical Curve 1
auto vertical_profile_segment_2 = create_vcurve(vpc1, 1.75 / 100, -1.0 / 100, 1600); // start by defining a composite curve composed of the horizonal curve segments
vertical_curve_segments->push(vertical_profile_segment_2.first); auto composite_curve = new Schema::IfcCompositeCurve(horizontal_curve_segments, false /*not self-intersecting*/);
vertical_segments->push(vertical_profile_segment_2.second); file.addEntity(composite_curve);
// Grade VPT1 to VPC2 // the composite curve is a representation item
auto vertical_profile_segment_3 = create_gradient(vpt1, -1.0 / 100, 1600); typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr alignment_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
vertical_curve_segments->push(vertical_profile_segment_3.first); alignment_representation_items->push(composite_curve);
vertical_segments->push(vertical_profile_segment_3.second);
// create the footprint representation
// Vertical Curve 2 auto footprint_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), alignment_representation_items);
auto vertical_profile_segment_4 = create_vcurve(vpc2, -1.0 / 100, 2.0 / 100, 1200); file.addEntity(footprint_shape_representation);
vertical_curve_segments->push(vertical_profile_segment_4.first);
vertical_segments->push(vertical_profile_segment_4.second); //
// Define vertical profile segments
// 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); // create containers to store the curve segments
vertical_segments->push(vertical_profile_segment_5.second); typename aggregate_of<typename Schema::IfcSegment>::ptr vertical_curve_segments(new aggregate_of<typename Schema::IfcSegment>()); // geometry
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr vertical_segments(new aggregate_of<typename Schema::IfcObjectDefinition>()); // business logic
// Vertical Curve 3
auto vertical_profile_segment_6 = create_vcurve(vpc3, 2.0 / 100, -2.0 / 100, 2000); // define key profile points
vertical_curve_segments->push(vertical_profile_segment_6.first); auto vpob = file.addDoublet<Schema::IfcCartesianPoint>(0.0, 100.0); // beginning
vertical_segments->push(vertical_profile_segment_6.second); auto vpc1 = file.addDoublet<Schema::IfcCartesianPoint>(1200.0, 121.0); // Vertical Curve Point (VPC), Vertical Curve #1
auto vpt1 = file.addDoublet<Schema::IfcCartesianPoint>(2800.0, 127.0); // Vertical Curve Tangent (VPT), Vertical Curve #1
// Grade PVT3 to VPC4 auto vpc2 = file.addDoublet<Schema::IfcCartesianPoint>(4400.0, 111.0); // Vertical Curve Point (VPC), Vertical Curve #2
auto vertical_profile_segment_7 = create_gradient(vpt3, -2.0 / 100, 1000); auto vpt2 = file.addDoublet<Schema::IfcCartesianPoint>(5600.0, 117.0); // Vertical Curve Tangent (VPT), Vertical Curve #2
vertical_curve_segments->push(vertical_profile_segment_7.first); auto vpc3 = file.addDoublet<Schema::IfcCartesianPoint>(6400.0, 133.0); // Vertical Curve Point (VPC), Vertical Curve #3
vertical_segments->push(vertical_profile_segment_7.second); auto vpt3 = file.addDoublet<Schema::IfcCartesianPoint>(8400.0, 133.0); // Vertical Curve Tangent (VPT), Vertical Curve #3
auto vpc4 = file.addDoublet<Schema::IfcCartesianPoint>(9400.0, 113.0); // Vertical Curve Point (VPC), Vertical Curve #4
// Vertical Curve 4 auto vpt4 = file.addDoublet<Schema::IfcCartesianPoint>(10200.0, 103.0); // Vertical Curve Tangent (VPT), Vertical Curve #4
auto vertical_profile_segment_8 = create_vcurve(vpc4, -2.0 / 100, -0.5 / 100, 800); auto vpoe = file.addDoublet<Schema::IfcCartesianPoint>(12800.0, 90.0); // ending
vertical_curve_segments->push(vertical_profile_segment_8.first);
vertical_segments->push(vertical_profile_segment_8.second); //
// Build the vertical alignment segments
// 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); // Grade start to VPC1
vertical_segments->push(vertical_profile_segment_9.second); auto vertical_profile_segment_1 = create_gradient(vpob, 1.75 / 100, 1200);
vertical_curve_segments->push(vertical_profile_segment_1.first);
// Zero-length terminator vertical_segments->push(vertical_profile_segment_1.second);
auto vertical_terminator_segment = create_gradient(vpoe, -0.5 / 100, 0.0);
vertical_curve_segments->push(vertical_terminator_segment.first); // Vertical Curve 1
vertical_segments->push(vertical_terminator_segment.second); auto vertical_profile_segment_2 = create_vcurve(vpc1, 1.75 / 100, -1.0 / 100, 1600);
vertical_curve_segments->push(vertical_profile_segment_2.first);
// create profile view axis model representation for the vertical profile vertical_segments->push(vertical_profile_segment_2.second);
// start by defining a gradient curve composed of the vertical curve segments and associated with the horizontal composite curve // Grade VPT1 to VPC2
auto gradient_curve = new Schema::IfcGradientCurve(vertical_curve_segments, false, composite_curve, nullptr); auto vertical_profile_segment_3 = create_gradient(vpt1, -1.0 / 100, 1600);
vertical_curve_segments->push(vertical_profile_segment_3.first);
// the gradient curve is a representation item vertical_segments->push(vertical_profile_segment_3.second);
typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr profile_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
profile_representation_items->push(gradient_curve); // Vertical Curve 2
auto vertical_profile_segment_4 = create_vcurve(vpc2, -1.0 / 100, 2.0 / 100, 1200);
// create the axis representation vertical_curve_segments->push(vertical_profile_segment_4.first);
auto axis3d_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("Axis"), std::string("Curve3D"), profile_representation_items); vertical_segments->push(vertical_profile_segment_4.second);
file.addEntity(axis3d_shape_representation);
// Grade PVT2 to VPC3
auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, nullptr, nullptr); auto vertical_profile_segment_5 = create_gradient(vpt2, 2.0 / 100, 800);
file.addEntity(vertical_profile); vertical_curve_segments->push(vertical_profile_segment_5.first);
vertical_segments->push(vertical_profile_segment_5.second);
// 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); // Vertical Curve 3
file.addEntity(nests_vertical_segments); auto vertical_profile_segment_6 = create_vcurve(vpc3, 2.0 / 100, -2.0 / 100, 2000);
vertical_curve_segments->push(vertical_profile_segment_6.first);
// the alignment has two representations, a plan view footprint and a 3d curve vertical_segments->push(vertical_profile_segment_6.second);
typename aggregate_of<typename Schema::IfcRepresentation>::ptr alignment_representations(new aggregate_of<typename Schema::IfcRepresentation>());
alignment_representations->push(footprint_shape_representation); // 2D footprint // Grade PVT3 to VPC4
alignment_representations->push(axis3d_shape_representation); // 3D curve auto vertical_profile_segment_7 = create_gradient(vpt3, -2.0 / 100, 1000);
vertical_curve_segments->push(vertical_profile_segment_7.first);
// create the alignment vertical_segments->push(vertical_profile_segment_7.second);
auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, alignment_representations);
// Vertical Curve 4
auto alignment = new Schema::IfcAlignment(IfcParse::IfcGlobalId(), nullptr, std::string("Example Alignment"), boost::none, boost::none, site->ObjectPlacement(), alignment_product, boost::none); auto vertical_profile_segment_8 = create_vcurve(vpc4, -2.0 / 100, -0.5 / 100, 800);
file.addEntity(alignment); vertical_curve_segments->push(vertical_profile_segment_8.first);
vertical_segments->push(vertical_profile_segment_8.second);
// 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 // Grade VPT4 to End
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr alignment_layout_list(new aggregate_of<typename Schema::IfcObjectDefinition>()); auto vertical_profile_segment_9 = create_gradient(vpt4, -0.5 / 100, 2600);
alignment_layout_list->push(horizontal_alignment); vertical_curve_segments->push(vertical_profile_segment_9.first);
alignment_layout_list->push(vertical_profile); vertical_segments->push(vertical_profile_segment_9.second);
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); // Zero-length terminator
file.addEntity(nests_alignment_layouts); auto vertical_terminator_segment = create_gradient(vpoe, -0.5 / 100, 0.0);
vertical_curve_segments->push(vertical_terminator_segment.first);
// IFC 4.1.4.1.1 "Every IfcAlignment must be related to IfcProject using the IfcRelAggregates relationship" vertical_segments->push(vertical_terminator_segment.second);
// 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<typename Schema::IfcObjectDefinition>::ptr list_of_alignments_in_project(new aggregate_of<typename Schema::IfcObjectDefinition>()); // Create the vertical alignment (IfcAlignmentVertical) and nest alignment segments
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); auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, nullptr, nullptr);
file.addEntity(aggregate_alignments_with_project); file.addEntity(vertical_profile);
// IFC 4.1.5.1 alignment is referenced in spatial structure of an IfcSpatialElement. In this case IfcSite is the highest level IfcSpatialElement 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);
// https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/concepts/Object_Connectivity/Alignment_Spatial_Reference/content.html file.addEntity(nests_vertical_segments);
// 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 // Create profile view axis model representation for the vertical profile
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); // start by defining a gradient curve composed of the vertical curve segments and associated with the horizontal composite curve
file.addEntity(rel_referenced_in_spatial_structure); auto gradient_curve = new Schema::IfcGradientCurve(vertical_curve_segments, false, composite_curve, nullptr);
std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example.ifc"); // the gradient curve is a representation item
ofs << file; typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr profile_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
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<typename Schema::IfcRepresentation>::ptr alignment_representations(new aggregate_of<typename Schema::IfcRepresentation>());
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<typename Schema::IfcObjectDefinition>::ptr alignment_layout_list(new aggregate_of<typename Schema::IfcObjectDefinition>());
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<typename Schema::IfcObjectDefinition>::ptr list_of_alignments_in_project(new aggregate_of<typename Schema::IfcObjectDefinition>());
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;
} }