/* * Copyright (c) 1991-2023 by STEP Tools Inc. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation is hereby granted, provided that this copyright * notice and license appear on all copies of the software. * * STEP TOOLS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. STEP TOOLS * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. * * Author: Dave Loffredo (loffredo@steptools.com) */ #include #include // some utilities for making ifc data #include "make_guid.h" #include "make_history.h" #include "make_units.h" // HELLO WALL - This IFC "hello world" program creates a standard wall // and attaches property sets and quantities to it. Inspired by the // HelloWall IFC sample created by Peter Bonsma, but much simplified // and reorganized to just focus on property sets. // // This program writes a Part 21 file called "output_wall.ifc". You // can look at this text file with a text editor or STEP Part 21 file // browser to see how the information is represented. IfcRepresentationContext * make_geometry_context( RoseDesign * d ); IfcBuildingStorey * create_project_and_building_storey ( IfcRepresentationContext * ctx ); // Make various properties single value properties IfcPropertySingleValue * make_prop_bool ( RoseDesign *, const char * nm, bool val ); IfcPropertySingleValue * make_prop_id ( RoseDesign *, const char * nm, const char * val ); IfcPropertySingleValue * make_prop_label ( RoseDesign *, const char * nm, const char * val ); IfcPropertySingleValue * make_prop_measure (RoseDesign *, const char * nm); IfcPropertySingleValue * make_prop_simple (RoseDesign *, const char * nm); IfcPropertySingleValue * make_prop_derived (RoseDesign *, const char * nm); // Make various physical quantity properties IfcQuantityArea * make_qty_area (RoseDesign *, const char * nm, double); IfcQuantityLength * make_qty_length (RoseDesign *, const char * nm, double); IfcQuantityVolume * make_qty_volume (RoseDesign *, const char * nm, double); int main(int /*argc*/, char** /*argv*/) { ifclib_init(); // force optimizing linkers to use all C++ classes // Make create a RoseDesign to hold the data RoseDesign * d = new RoseDesign ("output_wall.ifc"); d-> initialize_header(); d-> header_name()-> originating_system ("IFC Hello Wall"); // Make one shared representation context that gives the origin, // precision information, and the number of dimensions. See the // function below for the details. // IfcRepresentationContext * ctx = make_geometry_context (d); // Make a project and basic spatial structure, returning a // building storey that we can attach walls to. IfcBuildingStorey * storey = create_project_and_building_storey(ctx); //---------------------------------------- // COMMON WALL PROPERTY SET - Start by making the common wall // property set that will be shared among all of our walls. Refer // to the list of property sets in the IFC spec for details on // each of these properties. // IfcPropertySet * ps_common = pnewIn(d) IfcPropertySet; assign_ifc_guid (ps_common); assign_ifc_owner_history (ps_common); ps_common-> Name("Pset_WallCommon"); IfcPropertySingleValue * p; SetOfIfcProperty * props = ps_common-> HasProperties(); props-> add (make_prop_id (d, "Reference", "")); props-> add (make_prop_label(d, "AcousticRating", "")); props-> add (make_prop_label(d, "FireRating", "")); props-> add (make_prop_bool (d, "Combustible", false)); props-> add (make_prop_label(d, "SurfaceSpreadOfFlame", "")); p = make_prop_derived(d, "ThermalTransmittance"); p-> NominalValue()-> _IfcDerivedMeasureValue()-> _IfcThermalTransmittanceMeasure (0.24); props-> add (p); props-> add (make_prop_bool (d, "IsExternal", true)); props-> add (make_prop_bool (d, "ExtendToStructure", true)); props-> add (make_prop_bool (d, "LoadBearing", true)); props-> add (make_prop_bool (d, "Compartmentation", false)); //---------------------------------------- // CREATE WALL PHYSICAL QUANTITIES - This is a group of parameters // for describing physical quantities like length, width, etc. It // can be shared, but will likely be unique to each wall. // IfcElementQuantity * eq = pnewIn(d) IfcElementQuantity; assign_ifc_guid (eq); assign_ifc_owner_history (eq); eq-> Name("BaseQuantities"); // Build the individual quantities. The quantity objects also // have a unit field, but we leave this null to use the default // unit from the project. In this case it is feet, square feet, // and cubic feet. // double thickness = 0.5; // used by material below SetOfIfcPhysicalQuantity * qty = eq-> Quantities(); qty-> add (make_qty_length (d, "NominalHeight", 8)); qty-> add (make_qty_length (d, "NominalLength", 10)); qty-> add (make_qty_length (d, "NominalWidth", thickness)); qty-> add (make_qty_area (d, "GrossFootprintArea", 5)); qty-> add (make_qty_area (d, "NetFootprintArea", 5)); qty-> add (make_qty_area (d, "GrossSideArea", 80)); qty-> add (make_qty_area (d, "NetSideArea", 80)); qty-> add (make_qty_volume (d, "GrossVolume", 40)); qty-> add (make_qty_volume (d, "NetVolume", 40)); //---------------------------------------- // CREATE WALL MATERIAL AND LAYERS - A standard wall is of uniform // thickness and this material and layer definition describes how // it is aligned with the reference line. // IfcMaterial * mtl = pnewIn(d) IfcMaterial; mtl-> Name ("ice"); // BIM for an igloo :-) IfcMaterialLayer * layer = pnewIn(d) IfcMaterialLayer; layer-> Material(mtl); layer-> LayerThickness (thickness); IfcMaterialLayerSet * lset = pnewIn(d) IfcMaterialLayerSet; lset-> MaterialLayers()-> add (layer); IfcMaterialLayerSetUsage * lsu = pnewIn(d) IfcMaterialLayerSetUsage; lsu-> ForLayerSet(lset); lsu-> LayerSetDirection (IfcLayerSetDirectionEnum_AXIS2); lsu-> DirectionSense (IfcDirectionSenseEnum_POSITIVE); lsu-> OffsetFromReferenceLine (-thickness/2); // center on reference line //---------------------------------------- // CREATE A STANDARD WALL - Create instance, add common property // set, quantities, material, and assign to the building storey. // The wall that we will describe IfcWallStandardCase * w1 = pnewIn(d) IfcWallStandardCase; assign_ifc_guid (w1); assign_ifc_owner_history (w1); w1-> Name("Hadrian's Wall"); // Attach walls to the building storey IfcRelContainedInSpatialStructure * rel_storey = pnewIn(d) IfcRelContainedInSpatialStructure(); assign_ifc_guid (rel_storey); assign_ifc_owner_history (rel_storey); rel_storey-> RelatingStructure(storey); rel_storey-> RelatedElements()-> add (w1); // add other walls to storey // Attach common property set to the wall IfcRelDefinesByProperties * rel_pset = pnewIn(d) IfcRelDefinesByProperties; assign_ifc_guid (rel_pset); assign_ifc_owner_history (rel_pset); rel_pset-> RelatingPropertyDefinition ( pnewIn(d) IfcPropertySetDefinitionSelect // IFC4 adds a select here ); rel_pset-> RelatingPropertyDefinition()-> _IfcPropertySetDefinition(ps_common); rel_pset-> RelatedObjects()-> add (w1); // add common property to other walls // Attach the quantity object to the wall IfcRelDefinesByProperties * rel_qty = pnewIn(d) IfcRelDefinesByProperties; assign_ifc_guid (rel_qty); assign_ifc_owner_history (rel_qty); rel_qty-> RelatingPropertyDefinition ( pnewIn(d) IfcPropertySetDefinitionSelect // IFC4 adds a select here ); rel_qty-> RelatingPropertyDefinition()-> _IfcPropertySetDefinition(eq); rel_qty-> RelatedObjects()-> add (w1); // probably make new quantities for other walls unless they happen // to be the same length and height // Attach the material definition to the wall IfcRelAssociatesMaterial * rel_material = pnewIn(d) IfcRelAssociatesMaterial; assign_ifc_guid (rel_material); assign_ifc_owner_history (rel_material); // material is connected using a select rel_material-> RelatingMaterial(pnewIn (d) IfcMaterialSelect); rel_material-> RelatingMaterial()-> _IfcMaterialUsageDefinition(lsu); // IFC4 adds a select to RelAssociates IfcDefinitionSelect * w1_sel = pnewIn (d) IfcDefinitionSelect; w1_sel-> _IfcObjectDefinition(w1); rel_material-> RelatedObjects()-> add (w1_sel); // add material to other walls d-> save(); return 0; } //---------------------------------------- // PROPERTY UTILITIES -- Create the various kinds of IfcProperty // subtypes and values that are used by property sets. // IfcPropertySingleValue * make_prop_measure( RoseDesign * d, const char * name ) { // create a property with a nested measure value select, but do // not fill in the number since there are many possibilities. The // calling code can initialize it as needed. // IfcPropertySingleValue * prop = pnewIn(d) IfcPropertySingleValue; prop-> Name (name); prop-> NominalValue (pnewIn(d) IfcValue); prop-> NominalValue()-> _IfcMeasureValue(pnewIn(d) IfcMeasureValue); prop-> Unit(0); return prop; } IfcPropertySingleValue * make_prop_simple( RoseDesign * d, const char * name ) { // create a property with a nested simple value select, but do not // fill in the value. The calling code can initialize as needed. // IfcPropertySingleValue * prop = pnewIn(d) IfcPropertySingleValue; prop-> Name (name); prop-> NominalValue (pnewIn(d) IfcValue); prop-> NominalValue()-> _IfcSimpleValue(pnewIn(d) IfcSimpleValue); prop-> Unit(0); return prop; } IfcPropertySingleValue * make_prop_derived( RoseDesign * d, const char * name ) { // create a property with a nested derived measure select, but do // not fill in the value since there are dozens of possibilities. // The calling code can initialize it as needed. // IfcPropertySingleValue * prop = pnewIn(d) IfcPropertySingleValue; prop-> Name (name); prop-> NominalValue (pnewIn(d) IfcValue); prop-> NominalValue()-> _IfcDerivedMeasureValue( pnewIn(d) IfcDerivedMeasureValue ); prop-> Unit(0); return prop; } IfcPropertySingleValue * make_prop_bool( RoseDesign * d, const char * name, bool val ) { // Make a property with a simple boolean value IfcPropertySingleValue * prop = make_prop_simple(d, name); prop-> NominalValue()-> _IfcSimpleValue()-> _IfcBoolean(val); return prop; } IfcPropertySingleValue * make_prop_id( RoseDesign * d, const char * name, const char * val ) { // Make a property with a simple identifier value IfcPropertySingleValue * prop = make_prop_simple(d, name); prop-> NominalValue()-> _IfcSimpleValue()-> _IfcIdentifier(val); return prop; } IfcPropertySingleValue * make_prop_label( RoseDesign * d, const char * name, const char * val ) { // Make a property with a simple label value IfcPropertySingleValue * prop = make_prop_simple(d, name); prop-> NominalValue()-> _IfcSimpleValue()-> _IfcLabel(val); return prop; } IfcQuantityLength * make_qty_length( RoseDesign * d, const char * name, double val ) { IfcQuantityLength * qty = pnewIn(d) IfcQuantityLength; qty-> Name (name); qty-> LengthValue(val); qty-> Unit(NULL); return qty; } IfcQuantityArea * make_qty_area( RoseDesign * d, const char * name, double val ) { IfcQuantityArea * qty = pnewIn(d) IfcQuantityArea; qty-> Name (name); qty-> AreaValue(val); qty-> Unit(NULL); return qty; } IfcQuantityVolume * make_qty_volume( RoseDesign * d, const char * name, double val ) { IfcQuantityVolume * qty = pnewIn(d) IfcQuantityVolume; qty-> Name (name); qty-> VolumeValue(val); qty-> Unit(NULL); return qty; } // ------------------------------------------------------------ // ------------------------------------------------------------ // SUPPORT FUNCTIONS -- Adjust these as needed // ------------------------------------------------------------ // ------------------------------------------------------------ IfcRelAggregates * create_rel_aggregates( IfcObjectDefinition * relating ) { // CREATE AGGREGATES RELATIONSHIP -- Assign the relating pointer // and then return the relationship so that we can add children to // the related attribute // create in the same design as the relating object IfcRelAggregates * rel = pnewIn(relating->design()) IfcRelAggregates(); assign_ifc_guid (rel); assign_ifc_owner_history (rel); rel-> Name (""); rel-> Description (""); rel-> RelatingObject(relating); return rel; } IfcBuildingStorey * create_project_and_building_storey ( IfcRepresentationContext * ctx ) { // CREATE A PROJECT - Create the project object for the file, // assign the units for the file, and geometry context. // create in the same design as the context RoseDesign * d = ctx-> design(); IfcProject * p = pnewIn(d) IfcProject(); assign_ifc_guid (p); assign_ifc_owner_history (p); p-> Name ("project"); p-> RepresentationContexts()-> add (ctx); // Declare units so we know what the numbers in the geometry mean. // See the make_units.cxx file for details. // IfcUnitAssignment * units = make_units(d); p-> UnitsInContext (units); // CREATE THE BUILDING IfcBuilding * bldg = pnewIn(d) IfcBuilding(); assign_ifc_guid (bldg); assign_ifc_owner_history (bldg); bldg-> Name ("sample building"); bldg-> Description (""); // Add the building as a child of the project in the spatial // structure. IfcRelAggregates * rel = create_rel_aggregates (p); rel-> RelatedObjects()-> add(bldg); // CREATE THE BUILDING STOREY IfcBuildingStorey * stor = pnewIn(d) IfcBuildingStorey(); assign_ifc_guid (stor); assign_ifc_owner_history (stor); stor-> Name ("Level 1"); stor-> Description (""); // Add the storey as a child of the building in the spatial // structure. rel = create_rel_aggregates (bldg); rel-> RelatedObjects()-> add(stor); return stor; } IfcRepresentationContext * make_geometry_context( RoseDesign * d ) { // Create a geometric context IfcGeometricRepresentationContext * ctx = pnewIn(d) IfcGeometricRepresentationContext; // A file can have a "Model" context for the 3D view and a "Plan" // context for the 2D view // ctx-> ContextIdentifier ("Model"); ctx-> ContextType ("Design"); ctx-> CoordinateSpaceDimension (3); // geometric uncertainty for points ctx-> Precision (1e-6); // Create a coordinate system origin for the context IfcCartesianPoint * p1 = pnewIn(d) IfcCartesianPoint; p1-> Coordinates()->add(0.0); p1-> Coordinates()->add(0.0); p1-> Coordinates()->add(0.0); IfcAxis2Placement3D* ap3d = pnewIn(d) IfcAxis2Placement3D; ap3d-> Location(p1); // The placement is referenced through a select type ctx-> WorldCoordinateSystem (pnewIn(d) IfcAxis2Placement); ctx-> WorldCoordinateSystem()-> _IfcAxis2Placement3D (ap3d); return ctx; }