/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// // AI-GENERATED using Claude on 2025-09-05 // Reviewed and adapted by iegorychev@opendesign.com #include "OdaCommon.h" #include "ExIfcTutorial_RelAssocMaterial.h" #include "IfcFile.h" #include "Ifc4x3/Ifc4x3Entities.h" using namespace OdIfc; using namespace OdIfc4x3_add2; void Tutorial_RelAssocMaterial::help() const { odPrintConsoleString(L"Tutorial_RelAssocMaterial recreates the relassocmaterial.ifc sample file\n"); odPrintConsoleString(L"It demonstrates creating a steel column with material associations\n"); odPrintConsoleString(L"Parameters: \n"); odPrintConsoleString(L"Example: Tutorial_RelAssocMaterial relassocmaterial_output.ifc\n"); } int Tutorial_RelAssocMaterial::run(const MyServices& svcs, const std::vector& argv, std::ostream& resultStream) { auto parseResult = BaseIfcTutorial::run(svcs, argv, resultStream); if (parseResult != 0) { return parseResult; } try { // Create new IFC file with IFC4X3 schema OdIfcFilePtr pDatabase = svcs.createDatabase(IfcSchema::kScmIfc4x3); OdIfcModelPtr pModel = pDatabase->getModel(sdaiRW); // Step 1: Create basic geometric entities (needed by others) // Create cartesian point (0,0,0) - #2 OdDAI::ApplicationInstancePtr pOriginPointInst = pModel->createEntityInstance("ifccartesianpoint"); pOriginPointInst->putAttr("coordinates", OdArray({0.0, 0.0, 0.0})); OdDAIObjectId originPoint = pModel->appendEntityInstance(pOriginPointInst); // Create cartesian point (0,0,2000) - #215 OdDAI::ApplicationInstancePtr pTopPointInst = pModel->createEntityInstance("ifccartesianpoint"); pTopPointInst->putAttr("coordinates", OdArray({0.0, 0.0, 2000.0})); OdDAIObjectId topPoint = pModel->appendEntityInstance(pTopPointInst); // Create directions // Direction (0,-1,0) - #213 OdDAI::ApplicationInstancePtr pRefDirInst = pModel->createEntityInstance("ifcdirection"); pRefDirInst->putAttr("directionratios", OdArray({0.0, -1.0, 0.0})); OdDAIObjectId refDirection = pModel->appendEntityInstance(pRefDirInst); // Direction (0,0,1) - #214, #221 OdDAI::ApplicationInstancePtr pZDirInst = pModel->createEntityInstance("ifcdirection"); pZDirInst->putAttr("directionratios", OdArray({0.0, 0.0, 1.0})); OdDAIObjectId zDirection = pModel->appendEntityInstance(pZDirInst); // Create axis placement #3 for world coordinates OdDAI::ApplicationInstancePtr pWorldAxisInst = pModel->createEntityInstance("ifcaxis2placement3d"); pWorldAxisInst->putAttr("location", originPoint); OdDAIObjectId worldAxisPlacement = pModel->appendEntityInstance(pWorldAxisInst); // Create axis placement #212 for column OdDAI::ApplicationInstancePtr pColumnAxisInst = pModel->createEntityInstance("ifcaxis2placement3d"); pColumnAxisInst->putAttr("location", originPoint); pColumnAxisInst->putAttr("axis", zDirection); pColumnAxisInst->putAttr("refdirection", refDirection); OdDAIObjectId columnAxisPlacement = pModel->appendEntityInstance(pColumnAxisInst); // Step 2: Create geometric representation context #1 OdDAI::ApplicationInstancePtr pGeomContextInst = pModel->createEntityInstance("ifcgeometricrepresentationcontext"); pGeomContextInst->putAttr("contexttype", OdAnsiString("Model")); //pGeomContextInst->putAttr("coordinatespacedimension", OdDAI::OdDAIObjectId(3)); pGeomContextInst->putAttr("precision", 0.0001); pGeomContextInst->putAttr("worldcoordinatesystem", worldAxisPlacement); OdDAIObjectId geomContext = pModel->appendEntityInstance(pGeomContextInst); // Create sub-contexts #4, #5 OdDAI::ApplicationInstancePtr pAxisSubContextInst = pModel->createEntityInstance("ifcgeometricrepresentationsubcontext"); pAxisSubContextInst->putAttr("contextidentifier", OdAnsiString("Axis")); pAxisSubContextInst->putAttr("contexttype", OdAnsiString("Model")); pAxisSubContextInst->putAttr("parentcontext", geomContext); pAxisSubContextInst->putAttr("targetview", OdAnsiString("MODEL_VIEW")); OdDAIObjectId axisSubContext = pModel->appendEntityInstance(pAxisSubContextInst); OdDAI::ApplicationInstancePtr pBodySubContextInst = pModel->createEntityInstance("ifcgeometricrepresentationsubcontext"); pBodySubContextInst->putAttr("contextidentifier", OdAnsiString("Body")); pBodySubContextInst->putAttr("contexttype", OdAnsiString("Model")); pBodySubContextInst->putAttr("parentcontext", geomContext); pBodySubContextInst->putAttr("targetview", OdAnsiString("MODEL_VIEW")); OdDAIObjectId bodySubContext = pModel->appendEntityInstance(pBodySubContextInst); // Step 3: Create person and organization entities // Person #52 OdDAI::ApplicationInstancePtr pPersonInst = pModel->createEntityInstance("ifcperson"); pPersonInst->putAttr("identification", OdAnsiString("redacted")); pPersonInst->putAttr("familyname", OdAnsiString("redacted")); OdDAIObjectId person = pModel->appendEntityInstance(pPersonInst); // Organization #53 OdDAI::ApplicationInstancePtr pOrganizationInst = pModel->createEntityInstance("ifcorganization"); pOrganizationInst->putAttr("name", OdAnsiString("redacted")); OdDAIObjectId organization = pModel->appendEntityInstance(pOrganizationInst); // PersonAndOrganization #51 OdDAI::ApplicationInstancePtr pPersonAndOrgInst = pModel->createEntityInstance("ifcpersonandorganization"); pPersonAndOrgInst->putAttr("theperson", person); pPersonAndOrgInst->putAttr("theorganization", organization); OdDAIObjectId personAndOrganization = pModel->appendEntityInstance(pPersonAndOrgInst); // App Organization #55 OdDAI::ApplicationInstancePtr pAppOrgInst = pModel->createEntityInstance("ifcorganization"); pAppOrgInst->putAttr("name", OdAnsiString("redacted")); OdDAIObjectId appOrganization = pModel->appendEntityInstance(pAppOrgInst); // Application #54 OdDAI::ApplicationInstancePtr pApplicationInst = pModel->createEntityInstance("ifcapplication"); pApplicationInst->putAttr("applicationdeveloper", appOrganization); pApplicationInst->putAttr("version", OdAnsiString("redacted")); pApplicationInst->putAttr("applicationfullname", OdAnsiString("redacted")); pApplicationInst->putAttr("applicationidentifier", OdAnsiString("redacted")); OdDAIObjectId application = pModel->appendEntityInstance(pApplicationInst); // OwnerHistory #56 OdDAI::ApplicationInstancePtr pOwnerHistoryInst = pModel->createEntityInstance("ifcownerhistory"); pOwnerHistoryInst->putAttr("owninguser", personAndOrganization); pOwnerHistoryInst->putAttr("owningapplication", application); pOwnerHistoryInst->putAttr("changeaction", OdAnsiString("ADDED")); //pOwnerHistoryInst->putAttr("lastmodifieddate", OdDAI::OdDAIObjectId(1454575675)); //pOwnerHistoryInst->putAttr("creationdate", OdDAI::OdDAIObjectId(1454575675)); OdDAIObjectId ownerHistory = pModel->appendEntityInstance(pOwnerHistoryInst); // Step 4: Create units #102, #103, #104 OdDAI::ApplicationInstancePtr pLengthUnitInst = pModel->createEntityInstance("ifcsiunit"); pLengthUnitInst->putAttr("unittype", OdAnsiString("LENGTHUNIT")); pLengthUnitInst->putAttr("prefix", OdAnsiString("MILLI")); pLengthUnitInst->putAttr("name", OdAnsiString("METRE")); OdDAIObjectId lengthUnit = pModel->appendEntityInstance(pLengthUnitInst); OdDAI::ApplicationInstancePtr pAngleUnitInst = pModel->createEntityInstance("ifcsiunit"); pAngleUnitInst->putAttr("unittype", OdAnsiString("PLANEANGLEUNIT")); pAngleUnitInst->putAttr("name", OdAnsiString("RADIAN")); OdDAIObjectId angleUnit = pModel->appendEntityInstance(pAngleUnitInst); OdDAI::ApplicationInstancePtr pTimeUnitInst = pModel->createEntityInstance("ifcsiunit"); pTimeUnitInst->putAttr("unittype", OdAnsiString("TIMEUNIT")); pTimeUnitInst->putAttr("name", OdAnsiString("SECOND")); OdDAIObjectId timeUnit = pModel->appendEntityInstance(pTimeUnitInst); // Unit Assignment #101 OdDAI::ApplicationInstancePtr pUnitAssignmentInst = pModel->createEntityInstance("ifcunitassignment"); pUnitAssignmentInst->putAttr("units", OdDAIObjectIds({lengthUnit, angleUnit, timeUnit})); OdDAIObjectId unitAssignment = pModel->appendEntityInstance(pUnitAssignmentInst); // Step 5: Create project #100 OdDAI::ApplicationInstancePtr pProjectInst = pModel->createEntityInstance("ifcproject"); pProjectInst->putAttr("globalid", OdAnsiString("0$WU4A9R19$vKWO$AdOnKA")); pProjectInst->putAttr("ownerhistory", ownerHistory); pProjectInst->putAttr("name", OdAnsiString("IfcProject")); pProjectInst->putAttr("representationcontexts", OdDAIObjectIds({geomContext})); pProjectInst->putAttr("unitsassignment", unitAssignment); OdDAIObjectId project = pModel->appendEntityInstance(pProjectInst); // Step 6: Create building #50 OdDAI::ApplicationInstancePtr pBuildingInst = pModel->createEntityInstance("ifcbuilding"); pBuildingInst->putAttr("globalid", OdAnsiString("39t4Pu3nTC4ekXYRIHJB9W")); pBuildingInst->putAttr("ownerhistory", ownerHistory); pBuildingInst->putAttr("name", OdAnsiString("IfcBuilding")); OdDAIObjectId building = pModel->appendEntityInstance(pBuildingInst); // Step 7: Create material entities // Material #200 OdDAI::ApplicationInstancePtr pMaterialInst = pModel->createEntityInstance("ifcmaterial"); pMaterialInst->putAttr("name", OdAnsiString("S355JR")); pMaterialInst->putAttr("description", OdAnsiString("Steel")); OdDAIObjectId material = pModel->appendEntityInstance(pMaterialInst); // I-Shape Profile #202 OdDAI::ApplicationInstancePtr pProfileInst = pModel->createEntityInstance("ifcishapeprofiledef"); pProfileInst->putAttr("profiletype", OdAnsiString("AREA")); pProfileInst->putAttr("profilename", OdAnsiString("IPE200")); pProfileInst->putAttr("overallwidth", 100.0); pProfileInst->putAttr("overalldepth", 200.0); pProfileInst->putAttr("webthickness", 5.6); pProfileInst->putAttr("flangethickness", 8.5); pProfileInst->putAttr("filletradius", 12.0); OdDAIObjectId iShapeProfile = pModel->appendEntityInstance(pProfileInst); // Material Profile #203 OdDAI::ApplicationInstancePtr pMatProfileInst = pModel->createEntityInstance("ifcmaterialprofile"); pMatProfileInst->putAttr("name", OdAnsiString("IPE200")); pMatProfileInst->putAttr("material", material); pMatProfileInst->putAttr("profile", iShapeProfile); //pMatProfileInst->putAttr("priority", OdDAI::OdDAIObjectId(0)); OdDAIObjectId materialProfile = pModel->appendEntityInstance(pMatProfileInst); // Material Profile Set #205 OdDAI::ApplicationInstancePtr pMatProfileSetInst = pModel->createEntityInstance("ifcmaterialprofileset"); pMatProfileSetInst->putAttr("name", OdAnsiString("IPE200")); pMatProfileSetInst->putAttr("materialprofiles", OdDAIObjectIds({materialProfile})); OdDAIObjectId materialProfileSet = pModel->appendEntityInstance(pMatProfileSetInst); // Step 8: Create column type #207 OdDAI::ApplicationInstancePtr pColumnTypeInst = pModel->createEntityInstance("ifccolumntype"); pColumnTypeInst->putAttr("globalid", OdAnsiString("3qJDCKcPj1tgEHrIL1MUed")); pColumnTypeInst->putAttr("ownerhistory", ownerHistory); pColumnTypeInst->putAttr("name", OdAnsiString("IPE200")); pColumnTypeInst->putAttr("predefinedtype", OdAnsiString("COLUMN")); OdDAIObjectId columnType = pModel->appendEntityInstance(pColumnTypeInst); // Step 9: Create geometry for column // Local placement #211 OdDAI::ApplicationInstancePtr pLocalPlacementInst = pModel->createEntityInstance("ifclocalplacement"); pLocalPlacementInst->putAttr("relativeplacement", columnAxisPlacement); OdDAIObjectId localPlacement = pModel->appendEntityInstance(pLocalPlacementInst); // Polyline for axis representation #217 OdDAI::ApplicationInstancePtr pPolylineInst = pModel->createEntityInstance("ifcpolyline"); pPolylineInst->putAttr("points", OdDAIObjectIds({originPoint, topPoint})); OdDAIObjectId polyline = pModel->appendEntityInstance(pPolylineInst); // Axis shape representation #218 OdDAI::ApplicationInstancePtr pAxisShapeRepInst = pModel->createEntityInstance("ifcshaperepresentation"); pAxisShapeRepInst->putAttr("contextofitems", axisSubContext); pAxisShapeRepInst->putAttr("representationidentifier", OdAnsiString("Axis")); pAxisShapeRepInst->putAttr("representationtype", OdAnsiString("Curve3D")); pAxisShapeRepInst->putAttr("items", OdDAIObjectIds({polyline})); OdDAIObjectId axisShapeRep = pModel->appendEntityInstance(pAxisShapeRepInst); // Extruded area solid #222 OdDAI::ApplicationInstancePtr pExtrudedSolidInst = pModel->createEntityInstance("ifcextrudedareasolid"); pExtrudedSolidInst->putAttr("sweptarea", iShapeProfile); pExtrudedSolidInst->putAttr("extrudeddirection", zDirection); pExtrudedSolidInst->putAttr("depth", 2000.0); OdDAIObjectId extrudedSolid = pModel->appendEntityInstance(pExtrudedSolidInst); // Body shape representation #223 OdDAI::ApplicationInstancePtr pBodyShapeRepInst = pModel->createEntityInstance("ifcshaperepresentation"); pBodyShapeRepInst->putAttr("contextofitems", bodySubContext); pBodyShapeRepInst->putAttr("representationidentifier", OdAnsiString("Body")); pBodyShapeRepInst->putAttr("representationtype", OdAnsiString("SweptSolid")); pBodyShapeRepInst->putAttr("items", OdDAIObjectIds({extrudedSolid})); OdDAIObjectId bodyShapeRep = pModel->appendEntityInstance(pBodyShapeRepInst); // Product definition shape #224 OdDAI::ApplicationInstancePtr pProductDefShapeInst = pModel->createEntityInstance("ifcproductdefinitionshape"); pProductDefShapeInst->putAttr("representations", OdDAIObjectIds({axisShapeRep, bodyShapeRep})); OdDAIObjectId productDefShape = pModel->appendEntityInstance(pProductDefShapeInst); // Material profile set usage #219 OdDAI::ApplicationInstancePtr pMatProfileSetUsageInst = pModel->createEntityInstance("ifcmaterialprofilesetusage"); pMatProfileSetUsageInst->putAttr("forprofileset", materialProfileSet); pMatProfileSetUsageInst->putAttr("cardinalpoint", 5); // Integer value, not OdDAIObjectId OdDAIObjectId materialProfileSetUsage = pModel->appendEntityInstance(pMatProfileSetUsageInst); // Step 10: Create column instance #210 OdDAI::ApplicationInstancePtr pColumnInst = pModel->createEntityInstance("ifccolumn"); pColumnInst->putAttr("globalid", OdAnsiString("3S1GK_wA565RDoiWQEJc_l")); pColumnInst->putAttr("ownerhistory", ownerHistory); pColumnInst->putAttr("name", OdAnsiString("IPE200")); pColumnInst->putAttr("objectplacement", localPlacement); pColumnInst->putAttr("representation", productDefShape); OdDAIObjectId column = pModel->appendEntityInstance(pColumnInst); // Step 11: Create relationships // Material association for column type #206 OdDAIObjectId relAssocMaterialType = createIfcRelAssociateMaterial( pDatabase, ownerHistory, OdString("MatAssoc"), OdString("Material Associates"), OdDAIObjectIds({columnType}), materialProfileSet ); // Material association for column instance #220 OdDAIObjectId relAssocMaterialUsage = createIfcRelAssociateMaterial( pDatabase, ownerHistory, OdString("MatAssoc"), OdString("Material Associates"), OdDAIObjectIds({column}), materialProfileSetUsage ); // Type definition relationship #208 OdDAI::ApplicationInstancePtr pRelDefinesByTypeInst = pModel->createEntityInstance("ifcreldefinesbytype"); pRelDefinesByTypeInst->putAttr("globalid", OdAnsiString("0QSJIMj99DcOpmktgECZT7")); pRelDefinesByTypeInst->putAttr("ownerhistory", ownerHistory); pRelDefinesByTypeInst->putAttr("relatedobjects", OdDAIObjectIds({column})); pRelDefinesByTypeInst->putAttr("relatingtype", columnType); OdDAIObjectId relDefinesByType = pModel->appendEntityInstance(pRelDefinesByTypeInst); // Declaration relationship #209 OdDAI::ApplicationInstancePtr pRelDeclaresInst = pModel->createEntityInstance("ifcreldeclares"); pRelDeclaresInst->putAttr("globalid", OdAnsiString("2RA6m5trr5aOD9rZCp3GjP")); pRelDeclaresInst->putAttr("ownerhistory", ownerHistory); pRelDeclaresInst->putAttr("relatingcontext", project); pRelDeclaresInst->putAttr("relateddefinitions", OdDAIObjectIds({columnType})); OdDAIObjectId relDeclares = pModel->appendEntityInstance(pRelDeclaresInst); // Project aggregation relationship #105 OdDAI::ApplicationInstancePtr pRelAggregatesInst = pModel->createEntityInstance("ifcrelaggregates"); pRelAggregatesInst->putAttr("globalid", OdAnsiString("091a6ewbvCMQ2Vyiqspa7a")); pRelAggregatesInst->putAttr("ownerhistory", ownerHistory); pRelAggregatesInst->putAttr("name", OdAnsiString("Project Container")); pRelAggregatesInst->putAttr("description", OdAnsiString("Project Container for Buildings")); pRelAggregatesInst->putAttr("relatingobject", project); pRelAggregatesInst->putAttr("relatedobjects", OdDAIObjectIds({building})); OdDAIObjectId relAggregates = pModel->appendEntityInstance(pRelAggregatesInst); // Spatial containment relationship #57 OdDAI::ApplicationInstancePtr pRelContainedInst = pModel->createEntityInstance("ifcrelcontainedinspatialstructure"); pRelContainedInst->putAttr("globalid", OdAnsiString("3Sa3dTJGn0H8TQIGiuGQd5")); pRelContainedInst->putAttr("ownerhistory", ownerHistory); pRelContainedInst->putAttr("name", OdAnsiString("Building")); pRelContainedInst->putAttr("description", OdAnsiString("Building Container for Elements")); pRelContainedInst->putAttr("relatedelements", OdDAIObjectIds({column})); pRelContainedInst->putAttr("relatingstructure", building); OdDAIObjectId relContained = pModel->appendEntityInstance(pRelContainedInst); // Write the file pDatabase->writeFile(m_outputFileName); OdString successMsg = OdString(L"Successfully created IFC file: ") + m_outputFileName + L"\n"; odPrintConsoleString(successMsg); return 0; } catch (const OdError& e) { OdString errorMsg = OdString(L"Error: ") + e.description() + L"\n"; odPrintConsoleString(errorMsg); return 1; } catch (...) { odPrintConsoleString(L"Unknown error occurred\n"); return 1; } } // Reusable function to create IfcRelAssociatesMaterial relationships OdDAIObjectId Tutorial_RelAssocMaterial::createIfcRelAssociateMaterial( const OdIfcFilePtr& pDatabase, const OdDAIObjectId& ownerHistory, const OdString& name, const OdString& description, const OdDAIObjectIds& relatedObjects, const OdDAIObjectId& relatingMaterial) { OdIfcModelPtr pModel = pDatabase->getModel(sdaiRW); OdDAI::ApplicationInstancePtr pRelAssocMaterialInst = pModel->createEntityInstance("ifcrelassociatesmaterial"); // Generate a unique GUID - simplified for tutorial OdString guid = OdString().format(OD_T("0TDF0F6A574e3x4InqoSrm")); pRelAssocMaterialInst->putAttr("globalid", OdAnsiString(guid)); pRelAssocMaterialInst->putAttr("ownerhistory", ownerHistory); pRelAssocMaterialInst->putAttr("name", OdAnsiString(name)); pRelAssocMaterialInst->putAttr("description", OdAnsiString(description)); pRelAssocMaterialInst->putAttr("relatedobjects", relatedObjects); pRelAssocMaterialInst->putAttr("relatingmaterial", relatingMaterial); OdDAIObjectId relAssocMaterial = pModel->appendEntityInstance(pRelAssocMaterialInst); return relAssocMaterial; }