diff --git a/src/examples/IfcAlignment.cpp b/src/examples/IfcAlignment.cpp index fb701dc667..a3028e9044 100644 --- a/src/examples/IfcAlignment.cpp +++ b/src/examples/IfcAlignment.cpp @@ -17,423 +17,567 @@ * * ********************************************************************************/ -/******************************************************************************** - * * - * Example that generates extrusions of parameterized profiles. * - * * - ********************************************************************************/ +// 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) +// https://www.fhwa.dot.gov/bridge/pubs/hif22034.pdf +// +// Sections and page number for this document are cited in the code comments. +// +// This examples differs from IfcSimplifiedAlignment because it builds the +// alignment explicitly -#include "../ifcparse/Ifc2x3.h" +// Disable warnings coming from IfcOpenShell +#pragma warning(disable : 4018 4267 4250 4984 4985) + +#include "../ifcparse/Ifc4x3_add2.h" #include "../ifcparse/IfcHierarchyHelper.h" -#include "../ifcparse/IfcUtil.h" +#include #include -#include -#include -typedef std::string S; -typedef IfcWrite::IfcGuidHelper guid; -boost::none_t const null = (static_cast(0)); +const double PI = boost::math::constants::pi(); +double to_radian(double deg) { return PI * deg / 180; } -void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) { - IfcSchema::IfcProfileDef* profile = *profiles->begin(); - const std::string profile_type = IfcSchema::Type::ToString(profile->type()); - const std::string filename = profile_type + ".ifc"; +#define Schema Ifc4x3_add2 - IfcHierarchyHelper file; - file.filename(filename); +// performs basic project setup including created the IfcProject object +// and initializing the project units to FEET +Schema::IfcProject setup_project(IfcHierarchyHelper& file) { + std::vector file_description; + file_description.push_back("ViewDefinition[Alignment-basedReferenceView]"); + file.header().file_description().setdescription(file_description); - int i = 0; - for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it, ++i) { - IfcSchema::IfcProfileDef* profile = *it; - IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy( - guid(), 0, S("profile"), null, null, 0, 0, null, null); - file.addBuildingProduct(product); - file.getSingle()->setName(profile_type); - product->setOwnerHistory(file.getSingle()); + auto project = file.addProject(); + project.setName("FHWA Bridge Geometry Manual Example Alignment"); + project.setDescription("C++ Example"); - product->setObjectPlacement(file.addLocalPlacement(0, 100. * i)); + // 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 = file.create(); + dimensions.setLengthExponent(1); + dimensions.setMassExponent(0); + dimensions.setTimeExponent(0); + dimensions.setElectricCurrentExponent(0); + dimensions.setThermodynamicTemperatureExponent(0); + dimensions.setAmountOfSubstanceExponent(0); + dimensions.setLuminousIntensityExponent(0); + + auto conversion_factor = file.create(); + auto length = file.create(); + length.set_attribute_value(0, 304.80); + conversion_factor.setValueComponent(length); + conversion_factor.setUnitComponent(unit); - if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) { - ((IfcSchema::IfcParameterizedProfileDef*)profile)->setPosition(file.addPlacement2d()); + auto conversion_based_unit = file.create(); + conversion_based_unit.setDimensions(dimensions); + conversion_based_unit.setUnitType(Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT); + conversion_based_unit.setName("FEET"); + conversion_based_unit.setConversionFactor(conversion_factor); + + units.erase(std::remove(units.begin(), units.end(), unit)); // remove the millimeter unit + units.push_back(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 } - - IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile, - file.addPlacement3d(), - file.addTriplet(0, 0, 1), - 20.0); - - file.addEntity(profile); - file.addEntity(solid); - - IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list); - IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list); - - items->push(solid); - IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation( - file.getSingle(), S("Body"), S("SweptSolid"), items); - reps->push(rep); - - IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps); - file.addEntity(rep); - file.addEntity(shape); - - product->setRepresentation(shape); } - std::ofstream f(filename.c_str()); - f << file; + return project; } -int main(int argc, char** argv) { - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcUShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - null, - null, - null, - null)); - profiles->push(new Ifc2x3::IfcUShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - 2.0, - 2.0, - null, - null)); - profiles->push(new Ifc2x3::IfcUShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - null, - null, - 4.0, - null)); - profiles->push(new Ifc2x3::IfcUShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - 1.0, - 3.0, - 6.0, - null)); - create_testcase_for(profiles); - } +// creates geometry and business logic segments for horizontal alignment tangent runs +std::pair create_tangent(IfcHierarchyHelper& file, const typename Schema::IfcCartesianPoint& p, double dir, double length) { + // geometry + auto parent_curve = file.create(); + parent_curve.setPnt(file.addDoublet(0.0, 0.0)); + auto vec = file.create(); + vec.setOrientation(file.addDoublet(1.0, 0.0)); + vec.setMagnitude(1.0); + parent_curve.setDir(vec); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcTShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - null, - null, - null, - null, - null, - null)); - profiles->push(new Ifc2x3::IfcTShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - 2.0, - 2.0, - 2.0, - null, - null, - null)); - profiles->push(new Ifc2x3::IfcTShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - null, - null, - null, - 2.0, - 2.0, - null)); - profiles->push(new Ifc2x3::IfcTShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - 3.0, - 2.0, - 1.0, - 2.0, - 2.0, - null)); - create_testcase_for(profiles); - } + auto place = file.create(); + place.setLocation(p); + place.setRefDirection(file.addDoublet(cos(dir), sin(dir))); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcZShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - null, - null)); - profiles->push(new Ifc2x3::IfcZShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 5.0, - 2.0, - 2.0)); - create_testcase_for(profiles); - } + auto curve_segment = file.create(); + curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT); + curve_segment.setPlacement(place); + curve_segment.setSegmentStart(file.addValue(0.0)); + curve_segment.setSegmentLength(file.addValue(length)); + curve_segment.setParentCurve(parent_curve); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcEllipseProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0, - 15.0)); - profiles->push(new Ifc2x3::IfcEllipseProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 15.0, - 25.0)); - create_testcase_for(profiles); - } + // business logic + auto design_parameters = file.create(); + design_parameters.setStartPoint(p); + design_parameters.setStartDirection(dir); + design_parameters.setStartRadiusOfCurvature(0.0); + design_parameters.setEndRadiusOfCurvature(0.0); + design_parameters.setSegmentLength(length); + design_parameters.setPredefinedType(Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcIShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0, - 50.0, - 5.0, - 5.0, - null)); - profiles->push(new Ifc2x3::IfcIShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0, - 50.0, - 5.0, - 5.0, - 2.0)); - profiles->push(new Ifc2x3::IfcAsymmetricIShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0, - 50.0, - 5.0, - 5.0, - 2.0, - 20.0, - 10.0, - 5.0, - null)); - create_testcase_for(profiles); - } + auto alignment_segment = file.create(); + alignment_segment.setGlobalId(IfcParse::IfcGlobalId()); + alignment_segment.setDesignParameters(design_parameters); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcLShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - null, - null, - null, - null, - null)); - profiles->push(new Ifc2x3::IfcLShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 2.0, - 2.0, - null, - null, - null)); - profiles->push(new Ifc2x3::IfcLShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - null, - null, - 2.0, - null, - null)); - profiles->push(new Ifc2x3::IfcLShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 1.0, - 2.0, - 2.0, - null, - null)); - create_testcase_for(profiles); - } + return {curve_segment, alignment_segment}; +} - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcCShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 10.0, - null, - null)); - profiles->push(new Ifc2x3::IfcCShapeProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 10.0, - 2.0, - null)); - create_testcase_for(profiles); - } +// creates geometry and business logic segments for horizontal alignment horizonal curves +std::pair create_hcurve(IfcHierarchyHelper& file, const typename Schema::IfcCartesianPoint& pc, double dir, double radius, double lc) { + // geometry + double sign = radius / fabs(radius); + auto place = file.create(); + place.setLocation(file.addDoublet(0.0, 0.0)); + place.setRefDirection(file.addDoublet(1.0, 0.0)); + auto parent_curve = file.create(); + parent_curve.setPosition(place); + parent_curve.setRadius(fabs(radius)); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcCircleProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0)); - profiles->push(new Ifc2x3::IfcCircleHollowProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 25.0, - 5.0)); - create_testcase_for(profiles); - } + auto place2 = file.create(); + place2.setLocation(pc); + place2.setRefDirection(file.addDoublet(cos(dir), sin(dir))); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcRectangleProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0)); - profiles->push(new Ifc2x3::IfcRoundedRectangleProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0)); - profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - null, - null)); - profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 25.0, - 5.0, - 2.0, - 4.0)); - create_testcase_for(profiles); - } + auto curve_segment = file.create(); + curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT); + curve_segment.setPlacement(place2); + curve_segment.setSegmentStart(file.addValue(0.0)); + curve_segment.setSegmentLength(file.addValue(sign * lc)); + curve_segment.setParentCurve(parent_curve); - { - IfcSchema::IfcProfileDef::list::ptr profiles(new IfcSchema::IfcProfileDef::list); - profiles->push(new Ifc2x3::IfcTrapeziumProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 30.0, - 25.0, - 0.0)); - profiles->push(new Ifc2x3::IfcTrapeziumProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 60.0, - 25.0, - -20.0)); - profiles->push(new Ifc2x3::IfcTrapeziumProfileDef( - IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, - null, - 0, - 50.0, - 10.0, - 25.0, - 30.0)); - create_testcase_for(profiles); + // business logic + auto design_parameters = file.create(); + design_parameters.setStartPoint(pc); + design_parameters.setStartDirection(dir); + design_parameters.setStartRadiusOfCurvature(radius); + design_parameters.setEndRadiusOfCurvature(radius); + design_parameters.setSegmentLength(lc); + design_parameters.setPredefinedType(Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC); + + auto alignment_segment = file.create(); + alignment_segment.setGlobalId(IfcParse::IfcGlobalId()); + alignment_segment.setDesignParameters(design_parameters); + + return {curve_segment, alignment_segment}; +} + +// creates geometry and business logic segments for vertical profile gradient runs +std::pair create_gradient(IfcHierarchyHelper& file, const typename Schema::IfcCartesianPoint& p, double slope, double length) { + // geometry + auto parent_curve = file.create(); + parent_curve.setPnt(file.addDoublet(0.0, 0.0)); + auto vec = file.create(); + vec.setOrientation(file.addDoublet(1.0, 0.0)); + vec.setMagnitude(1.0); + parent_curve.setDir(vec); + + auto place2 = file.create(); + place2.setLocation(p); + place2.setRefDirection(file.addDoublet(sqrt(1 - slope * slope), slope)); + + auto curve_segment = file.create(); + curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT); + curve_segment.setPlacement(place2); + curve_segment.setSegmentStart(file.addValue(0.0)); + curve_segment.setSegmentLength(file.addValue(length)); + curve_segment.setParentCurve(parent_curve); + + // business logic + auto design_parameters = file.create(); + design_parameters.setStartDistAlong(p.Coordinates()[0]); + design_parameters.setHorizontalLength(length); + design_parameters.setStartHeight(p.Coordinates()[1]); + design_parameters.setStartGradient(slope); + design_parameters.setEndGradient(slope); + design_parameters.setPredefinedType(Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT); + + auto alignment_segment = file.create(); + alignment_segment.setGlobalId(IfcParse::IfcGlobalId()); + alignment_segment.setDesignParameters(design_parameters); + + return {curve_segment, alignment_segment}; +} + +// creates geometry and business logic segments for vertical profile parabolic vertical curves +std::pair create_vcurve(IfcHierarchyHelper& file, const typename Schema::IfcCartesianPoint& p, double start_slope, double end_slope, double length) { + // geometry + double A = p.Coordinates()[1]; + double B = start_slope; + double C = (end_slope - start_slope) / (2 * length); + + auto place = file.create(); + place.setLocation(file.addDoublet(0.0, 0.0)); + place.setRefDirection(file.addDoublet(1.0, 0.0)); + + auto parent_curve = file.create(); + parent_curve.setPosition(place); + parent_curve.setCoefficientsX(std::vector{0.0, 1.0}); + parent_curve.setCoefficientsY(std::vector{A, B, C}); + + auto place2 = file.create(); + place2.setLocation(p); + place2.setRefDirection(file.addDoublet(sqrt(1 - start_slope * start_slope), start_slope)); + + auto curve_segment = file.create(); + curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT); + curve_segment.setPlacement(place2); + curve_segment.setSegmentStart(file.addValue(0.0)); + curve_segment.setSegmentLength(file.addValue(length)); + curve_segment.setParentCurve(parent_curve); + + // business logic + double k = (end_slope - start_slope) / length; + + auto design_parameters = file.create(); + design_parameters.setStartDistAlong(p.Coordinates()[0]); + design_parameters.setHorizontalLength(length); + design_parameters.setStartHeight(p.Coordinates()[1]); + design_parameters.setStartGradient(start_slope); + design_parameters.setEndGradient(end_slope); + design_parameters.setRadiusOfCurvature(1 / k); + design_parameters.setPredefinedType(Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_PARABOLICARC); + + auto alignment_segment = file.create(); + alignment_segment.setGlobalId(IfcParse::IfcGlobalId()); + alignment_segment.setDesignParameters(design_parameters); + + return {curve_segment, alignment_segment}; +} + +// 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, const Schema::IfcLocalPlacement& global_placement, const Schema::IfcGeometricRepresentationSubContext& segment_axis_subcontext, std::vector& curve_segments, std::vector& 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(); + + auto axis_representation = file.create(); + axis_representation.setContextOfItems(segment_axis_subcontext); + axis_representation.setRepresentationIdentifier("Axis"); + axis_representation.setRepresentationType("Segment"); + axis_representation.setItems({curve_segment}); + + auto product = file.create(); + product.setRepresentations({axis_representation}); + + alignment_segment.setObjectPlacement(global_placement); + alignment_segment.setRepresentation(product); } } + +int main() { + IfcHierarchyHelper file; + + auto project = setup_project(file); + + auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist + + auto axis_model_representation_subcontext = file.create(); + axis_model_representation_subcontext.setContextIdentifier("Axis"); + axis_model_representation_subcontext.setContextType("Model"); + axis_model_representation_subcontext.setParentContext(geometric_representation_context); + axis_model_representation_subcontext.setTargetView(Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW); + + 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 + std::vector horizontal_curve_segments; // geometry + std::vector horizontal_segments; // business logic + + // + // Build the horizontal alignment segments + // + + // POB to PC1 + auto curve_segment_1 = create_tangent(file, pob, angle_1, run_1); + horizontal_curve_segments.push_back(curve_segment_1.first); + horizontal_segments.push_back(curve_segment_1.second); + + // Curve 1 + auto curve_segment_2 = create_hcurve(file, pc1, angle_1, rc_1, lc_1); + horizontal_curve_segments.push_back(curve_segment_2.first); + horizontal_segments.push_back(curve_segment_2.second); + + // PT1 to PC2 + auto curve_segment_3 = create_tangent(file, pt1, angle_2, run_2); + horizontal_curve_segments.push_back(curve_segment_3.first); + horizontal_segments.push_back(curve_segment_3.second); + + // Curve 2 + auto curve_segment_4 = create_hcurve(file, pc2, angle_2, rc_2, lc_2); + horizontal_curve_segments.push_back(curve_segment_4.first); + horizontal_segments.push_back(curve_segment_4.second); + + // PT2 to PC3 + auto curve_segment_5 = create_tangent(file, pt2, angle_3, run_3); + horizontal_curve_segments.push_back(curve_segment_5.first); + horizontal_segments.push_back(curve_segment_5.second); + + // Curve 3 + auto curve_segment_6 = create_hcurve(file, pc3, angle_3, rc_3, lc_3); + horizontal_curve_segments.push_back(curve_segment_6.first); + horizontal_segments.push_back(curve_segment_6.second); + + // PT3 to POE + auto curve_segment_7 = create_tangent(file, pt3, angle_4, run_4); + horizontal_curve_segments.push_back(curve_segment_7.first); + horizontal_segments.push_back(curve_segment_7.second); + + // Zero-length terminator segment + auto terminator_segment = create_tangent(file, poe, angle_4, 0.0); + terminator_segment.first.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS); + horizontal_curve_segments.push_back(terminator_segment.first); + horizontal_segments.push_back(terminator_segment.second); + + // + // Create the horizontal alignment (IfcAlignmentHorizontal) and nest alignment segments + // + auto horizontal_alignment = file.create(); + horizontal_alignment.setGlobalId(IfcParse::IfcGlobalId()); + horizontal_alignment.setName("Example Alignment"); + + auto nests_horizontal_segments = file.create(); + nests_horizontal_segments.setGlobalId(IfcParse::IfcGlobalId()); + nests_horizontal_segments.setName("Nests horizontal alignment segments with horizontal alignment"); + nests_horizontal_segments.setRelatingObject(horizontal_alignment); + nests_horizontal_segments.setRelatedObjects(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 = file.create(); + composite_curve.setSegments(horizontal_curve_segments); + composite_curve.setSelfIntersect(false); + + // create the footprint representation + auto footprint_shape_representation = file.create(); + footprint_shape_representation.setContextOfItems(axis_model_representation_subcontext); + footprint_shape_representation.setRepresentationIdentifier("Footprint"); + footprint_shape_representation.setRepresentationType("Curve2D"); + // the composite curve is a representation item + footprint_shape_representation.setItems({composite_curve}); + + // + // Define vertical profile segments + // + + // create containers to store the curve segments + std::vector vertical_curve_segments; // geometry + std::vector vertical_segments; // 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(file, vpob, 1.75 / 100, 1200); + vertical_curve_segments.push_back(vertical_profile_segment_1.first); + vertical_segments.push_back(vertical_profile_segment_1.second); + + // Vertical Curve 1 + auto vertical_profile_segment_2 = create_vcurve(file, vpc1, 1.75 / 100, -1.0 / 100, 1600); + vertical_curve_segments.push_back(vertical_profile_segment_2.first); + vertical_segments.push_back(vertical_profile_segment_2.second); + + // Grade VPT1 to VPC2 + auto vertical_profile_segment_3 = create_gradient(file, vpt1, -1.0 / 100, 1600); + vertical_curve_segments.push_back(vertical_profile_segment_3.first); + vertical_segments.push_back(vertical_profile_segment_3.second); + + // Vertical Curve 2 + auto vertical_profile_segment_4 = create_vcurve(file, vpc2, -1.0 / 100, 2.0 / 100, 1200); + vertical_curve_segments.push_back(vertical_profile_segment_4.first); + vertical_segments.push_back(vertical_profile_segment_4.second); + + // Grade PVT2 to VPC3 + auto vertical_profile_segment_5 = create_gradient(file, vpt2, 2.0 / 100, 800); + vertical_curve_segments.push_back(vertical_profile_segment_5.first); + vertical_segments.push_back(vertical_profile_segment_5.second); + + // Vertical Curve 3 + auto vertical_profile_segment_6 = create_vcurve(file, vpc3, 2.0 / 100, -2.0 / 100, 2000); + vertical_curve_segments.push_back(vertical_profile_segment_6.first); + vertical_segments.push_back(vertical_profile_segment_6.second); + + // Grade PVT3 to VPC4 + auto vertical_profile_segment_7 = create_gradient(file, vpt3, -2.0 / 100, 1000); + vertical_curve_segments.push_back(vertical_profile_segment_7.first); + vertical_segments.push_back(vertical_profile_segment_7.second); + + // Vertical Curve 4 + auto vertical_profile_segment_8 = create_vcurve(file, vpc4, -2.0 / 100, -0.5 / 100, 800); + vertical_curve_segments.push_back(vertical_profile_segment_8.first); + vertical_segments.push_back(vertical_profile_segment_8.second); + + // Grade VPT4 to End + auto vertical_profile_segment_9 = create_gradient(file, vpt4, -0.5 / 100, 2600); + vertical_curve_segments.push_back(vertical_profile_segment_9.first); + vertical_segments.push_back(vertical_profile_segment_9.second); + + // Zero-length terminator + auto vertical_terminator_segment = create_gradient(file, vpoe, -0.5 / 100, 0.0); + vertical_terminator_segment.first.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS); + vertical_curve_segments.push_back(vertical_terminator_segment.first); + vertical_segments.push_back(vertical_terminator_segment.second); + + // + // Create the vertical alignment (IfcAlignmentVertical) and nest alignment segments + // + auto vertical_profile = file.create(); + vertical_profile.setGlobalId(IfcParse::IfcGlobalId()); + vertical_profile.setName("Example Vertical Profile"); + + auto nests_vertical_segments = file.create(); + nests_vertical_segments.setGlobalId(IfcParse::IfcGlobalId()); + nests_vertical_segments.setName("Nests vertical alignment segments with vertical profile"); + nests_vertical_segments.setRelatingObject(vertical_profile); + nests_vertical_segments.setRelatedObjects(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 = file.create(); + gradient_curve.setSegments(vertical_curve_segments); + gradient_curve.setSelfIntersect(false); + gradient_curve.setBaseCurve(composite_curve); + + // create the axis representation + auto axis3d_shape_representation = file.create(); + axis3d_shape_representation.setContextOfItems(axis_model_representation_subcontext); + axis3d_shape_representation.setRepresentationIdentifier("Axis"); + axis3d_shape_representation.setRepresentationType("Curve3D"); + // the gradient curve is a representation item + axis3d_shape_representation.setItems({gradient_curve}); + + // 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 + // + + // create the alignment product definition + auto alignment_product = file.create(); + alignment_product.setName("Alignment Product Definition Shape"); + // the alignment has two representations, a plan view footprint and a 3d curve + alignment_product.setRepresentations({footprint_shape_representation, axis3d_shape_representation}); + + // create the alignment + auto alignment = file.create(); + alignment.setGlobalId(IfcParse::IfcGlobalId()); + alignment.setName("Example Alignment"); + alignment.setObjectPlacement(global_placement); + alignment.setRepresentation(alignment_product); + + // 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 + auto nests_alignment_layouts = file.create(); + nests_alignment_layouts.setGlobalId(IfcParse::IfcGlobalId()); + nests_alignment_layouts.setName("Nest horizontal and vertical alignment layouts with the alignment"); + nests_alignment_layouts.setRelatingObject(alignment); + nests_alignment_layouts.setRelatedObjects({horizontal_alignment, vertical_profile}); + + // 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 + auto aggregate_alignments_with_project = file.create(); + aggregate_alignments_with_project.setGlobalId(IfcParse::IfcGlobalId()); + aggregate_alignments_with_project.setName("Alignments in project"); + aggregate_alignments_with_project.setRelatingObject(project); + aggregate_alignments_with_project.setRelatedObjects({alignment}); + + // 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 + std::vector list_alignments_referenced_in_site{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); + site.setName(os.str()); + + std::ostringstream description; + description << "Alignments referenced into the spatial structure of Bridge Site " << i; + + auto rel_referenced_in_spatial_structure = file.create(); + rel_referenced_in_spatial_structure.setGlobalId(IfcParse::IfcGlobalId()); + rel_referenced_in_spatial_structure.setDescription(description.str()); + rel_referenced_in_spatial_structure.setRelatedElements(list_alignments_referenced_in_site); + rel_referenced_in_spatial_structure.setRelatingStructure(site); + } + + // That's it - save the model to a file + std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example.ifc"); + ofs << file; +} diff --git a/src/ifcparse/IfcHierarchyHelper.h b/src/ifcparse/IfcHierarchyHelper.h index 0c4981ebbc..e0ef5b1c95 100644 --- a/src/ifcparse/IfcHierarchyHelper.h +++ b/src/ifcparse/IfcHierarchyHelper.h @@ -376,6 +376,13 @@ class IFC_PARSE_API IfcHierarchyHelper : public IfcParse::IfcFile { auto t = create(); t.set_attribute_value(0, std::vector{x, y}); return t; + } + + template + T addValue(U v) { + auto measure = create(); + measure.set_attribute_value(0, v); + return measure; } template