/******************************************************************************** * * * 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) // 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 IfcAlignment because it uses utility methods // to simplify alignment construction // Disable warnings coming from IfcOpenShell #pragma warning(disable : 4018 4267 4250 4984 4985) #include "../ifcparse/Ifc4x3_add2.h" #include "../ifcparse/alignment_helper.h" #include #define Schema Ifc4x3_add2 // performs basic project setup including created the IfcProject object // and initializing the project units to FEET Schema::IfcProject setup_project(hierarchy_helper& file) { std::vector file_description; file_description.push_back("ViewDefinition[Alignment-basedReferenceView]"); file.header().file_description().setdescription(file_description); auto project = file.addProject(); project.setName(std::string("FHWA Bridge Geometry Manual Example Alignment")); project.setDescription(std::string("C++ Example - Simplified")); // 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); 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 } } return project; } int main() { hierarchy_helper file; auto project = setup_project(file); // // Define horizontal alignment // // PI Data // B.1.1 pg 211 std::vector> points{ { 500.0, 2500.0}, // beginning {3340.0, 660.0}, // Point of intersection (PI), Curve #1 {4340.0, 5000.0}, // Point of intersection (PI), Curve #2 {7600.0, 4560.0}, // Point of intersection (PI), Curve #3 {8480.0, 2010.0} // ending }; // Curve Data // B.1.3 pg 212 std::vector radii{ 1000,1250,950 }; // // Define vertical profile segments // // Vertical Profile Data // Figure B.2 pg 213 double xStart = 10000.0; // subtract xStart so the points are distance along, not station std::vector> vpoints { {10000.0-xStart,100.0}, // Vertical point of beginning (VPOB) {12000.0-xStart,135.0}, // Point of vertical intersection (VPI), Curve #1 {15000.0-xStart,105.0}, // Point of vertical intersection (VPI), Curve #2 {17400.0-xStart,153.0}, // Point of vertical intersection (VPI), Curve #3 {19800.0-xStart,105.0}, // Point of vertical intersection (VPI), Curve #4 {22800.0-xStart, 90.0} // Vertical poitn of ending (VPOE) }; // Vertical Curve Lengths // Figure B.2 pg 213 std::vector vclengths{1600.0, 1200.0, 2000.0, 800.0}; // Use utility function to create alignment auto alignment = addAlignment(file, "Example Alignment", points, radii, vpoints, vclengths); // Define the alignment's 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(ifcopenshell::global_id()); 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 // Complete the model by creating sites for the 3 bridges 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(ifcopenshell::global_id()); rel_referenced_in_spatial_structure.setDescription(description.str()); rel_referenced_in_spatial_structure.setRelatedElements(std::vector{alignment}); rel_referenced_in_spatial_structure.setRelatingStructure(site); } // That's it - save the model to a file std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example_Simplified.ifc"); ofs << file; }