/////////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "ExIfcTutorial_ScheduleCreation.h" #include namespace { struct ProductData { OdDAIObjectId productId; int level; }; bool getZCoordinateObjectPlacement(OdIfc::OdIfcInstancePtr pObjectPlacement, double& zCoordinate) { if (pObjectPlacement->resolved() == OdIfc::kResMatrix3d) { OdGePoint3d point = OdIfc::OdIfcInstance::asMatrix3d(pObjectPlacement)->getCsOrigin(); zCoordinate = point.z; return true; } else { OdDAIObjectId objectPlacementId; pObjectPlacement->getAttr(OdIfc::kPlacementRelTo) >> objectPlacementId; if (!objectPlacementId.isNull()) { getZCoordinateObjectPlacement(objectPlacementId.openObject(), zCoordinate); } } return false; } bool fillPlacementData(OdIfc::OdIfcInstancePtr pProductInstance, double& zCoordinate) { OdDAIObjectId placementId; pProductInstance->getAttr(OdIfc::kObjectPlacement) >> placementId; if (placementId.isNull()) return false; OdIfc::OdIfcInstancePtr pObjectplacement = placementId.openObject(); double zCoordiante; if (!getZCoordinateObjectPlacement(pObjectplacement, zCoordinate)) { OdDAIObjectId relativePlacementId; pObjectplacement->getAttr(OdIfc::kRelativePlacement) >> relativePlacementId; if (relativePlacementId.isNull()) return false; OdIfc::OdIfcInstancePtr pPlacement = relativePlacementId.openObject(); if (pPlacement->resolved() == OdIfc::kResMatrix3d) { OdGePoint3d point = OdIfc::OdIfcInstance::asMatrix3d(pPlacement)->getCsOrigin(); zCoordinate = point.z; return true; } else { OdDAIObjectId locationId; pPlacement->getAttr(OdIfc::kLocation) >> locationId; if (locationId.isNull()) return false; OdIfc::OdIfcInstancePtr pLocation = locationId.openObject(); OdArray coordinates; pLocation->getAttr(OdIfc::kCoordinates) >> coordinates; if (coordinates.size() >= 2) { zCoordinate = coordinates[2]; return true; } } } else return true; return false; } OdDAIObjectId createIfcTaskTime(OdDAI::ModelPtr pModel, int day, int month, int year) { // IFC TASK TIME CREATION OdIfc::OdIfcInstancePtr pTaskTime = pModel->createEntityInstance("ifctasktime"); OdDAI::Enum* dataOrigin, * durationType; pTaskTime->getAttr("dataorigin") >> dataOrigin; dataOrigin->setIntValue(1); // PREDICTED pTaskTime->getAttr("durationtype") >> durationType; durationType->setIntValue(1); // WORKTIME OdTimeStamp scheduleStartTime(OdTimeStamp::kInitLocalTime), scheduleFinishTime(OdTimeStamp::kInitLocalTime); scheduleStartTime.setDate(month, day, year); scheduleStartTime.setTime(8, 0, 0, 0); scheduleFinishTime.setDate(month, day + 1, year); scheduleFinishTime.setTime(8, 0, 0, 0); OdString scheduleStart, scheduleFinish; OdDAI::Utils::sdaiStrFTime(scheduleStartTime, L"%Y-%m-%dT%H:%M:%S", scheduleStart); OdDAI::Utils::sdaiStrFTime(scheduleFinishTime, L"%Y-%m-%dT%H:%M:%S", scheduleFinish); pTaskTime->putAttr("schedulestart", OdAnsiString(scheduleStart)); pTaskTime->putAttr("schedulefinish", OdAnsiString(scheduleFinish)); pTaskTime->putAttr("iscritical", OdDAI::Boolean::True); return pModel->appendEntityInstance(pTaskTime); } OdDAIObjectId createIfcTask(OdDAI::ModelPtr pModel, OdDAIObjectId ownerHistoryId, OdDAIObjectId productId, OdDAIObjectId taskTimeId) { OdIfc::OdIfcInstancePtr pTask = pModel->createEntityInstance("ifctask"); OdIfc::Utils::assignGlobalId(pTask); pTask->putAttr("ownerhistory", ownerHistoryId); pTask->putAttr("ismilestone", OdDAI::Boolean::False); OdIfc::OdIfcInstancePtr pProduct = productId.openObject(); OdAnsiString productName; pProduct->getAttr("name") >> productName; pTask->putAttr("name", productName); pTask->putAttr("tasktime", taskTimeId); return pModel->appendEntityInstance(pTask); } } Tutorial_ScheduleCreation::Tutorial_ScheduleCreation(const OdString& applicationName) : BaseIfcTutorial(applicationName) { m_tutorialArgsParser. add_param( std::make_shared>(m_ifcInputFileName, "inputFile", "full path to the input .ifc file.", false)); m_tutorialArgsParser. add_param( std::make_shared>(m_ifcOutputFileName, "outputFile", "full path to the output .ifc file.", false)); m_noWait = false; m_tutorialArgsParser .add_param( std::make_shared(m_noWait, "-NoWait", "disable \"press any key\" on finish.")); } int Tutorial_ScheduleCreation::run(const MyServices& svcs, const std::vector& argv, std::ostream& resultStream) { auto parseResult = BaseIfcTutorial::run(svcs, argv, resultStream); if (parseResult != 0) { return parseResult; } // Return value for main int nRes = 0; //Uninitialize to initialize with geometry calculation enabled odIfcUninitialize(); /**********************************************************************/ /* Initialize IfcCore */ /**********************************************************************/ odIfcInitialize(false /* No CDA */, true /* Geometry calculation needed */); try { OdIfcFilePtr pIfcFile = svcs.createDatabase(); OdResult res = pIfcFile->readFile(m_ifcInputFileName); if (res == eOk) { odPrintConsoleString(OD_T("\Tutorial_ScheduleCreation: reading file %s is successful.\n"), OdString(m_ifcInputFileName).c_str()); } else { odPrintConsoleString(OD_T("\Tutorial_ScheduleCreation: reading file %s is failed.\n"), OdString(m_ifcInputFileName).c_str()); nRes = -1; } /********************************************************************/ /* Retrieve model from IFC file */ /********************************************************************/ pIfcFile->composeEntities(); OdIfcModelPtr pModel = pIfcFile->getModel(sdaiRW); OdAnsiString schema = pModel->underlyingSchemaName(); if (schema.iCompare("IFC4") < 0) { odPrintConsoleString(OD_T("\Tutorial_ScheduleCreation: file schema should be IFC4 or newer.\n"), OdString(m_ifcInputFileName).c_str()); nRes = -1; } if (nRes == 0) { OdDAI::InstanceIteratorPtr pInstanceIterator = pModel->newIterator(); OdDAIObjectIds products; OdDAIObjectId ownerHistoryId; while (!pInstanceIterator->done()) { OdDAIObjectId id = pInstanceIterator->id(); if (id.isValid()) { OdDAI::ApplicationInstancePtr pInst = id.openObject(); if (pInst->isKindOf("ifcproduct")) products.append(id); if (pInst->isKindOf("ifcownerhistory")) ownerHistoryId = id; } pInstanceIterator->step(); } pIfcFile->composeEntities(); OdArray zCoords; for (auto product : products) { OdIfc::OdIfcInstancePtr pProductInstance = product.openObject(); double zCoordinate = 0; if (fillPlacementData(pProductInstance, zCoordinate)) zCoords.append(zCoordinate); else products.remove(product); } for (int i = 0; i < zCoords.size(); ++i) { for (int j = i + 1; j < zCoords.size(); ++j) { if (OdLess(zCoords[j], zCoords[i])) { zCoords.swap(i, j); products.swap(i, j); } } } OdArray productMap; double prevZCoord = zCoords[0]; int level = 0; for (int i = 0; i < zCoords.size(); ++i) { if (OdLess(prevZCoord, zCoords[i])) ++level; productMap.append({ products[i], level }); prevZCoord = zCoords[i]; } int month = 8, day = 20, year = 2025, previousLevel = 0, previousFinishMonth = month, previousFinishDay = day, previousFinishYear = year; bool isFirstOnLevel = true; OdIfc::OdIfcInstancePtr pLevelTask, pLevelTaskTime; OdDAIObjectIds subTasksIds; bool isRootTask = true; for (int i = 0; i < productMap.size(); ++i) { /* * IFC TASK CREATION * * For each floor there is one main task, * that contains information about time of whole floor creation. * This task has links to all floor subtasks and has no assigned product * */ if (previousLevel < productMap[i].level) // if moving to the next floor, so it is necessary to fill link to subtasks { isFirstOnLevel = true; OdTimeStamp scheduleFinishTime(OdTimeStamp::kInitLocalTime); scheduleFinishTime.setDate(previousFinishMonth, previousFinishDay, previousFinishYear); scheduleFinishTime.setTime(8, 0, 0, 0); OdString scheduleFinish; OdDAI::Utils::sdaiStrFTime(scheduleFinishTime, L"%Y-%m-%dT%H:%M:%S", scheduleFinish); pLevelTaskTime->putAttr("schedulefinish", OdAnsiString(scheduleFinish)); OdAnsiString name = OdAnsiString(std::to_string(previousLevel + 1).c_str()); name += " Level"; pLevelTask->putAttr("name", name); OdIfc::OdIfcInstancePtr pRelNests = pModel->createEntityInstance("ifcrelnests"); OdIfc::Utils::assignGlobalId(pRelNests); pRelNests->putAttr("relatingobject", OdDAIObjectId(pLevelTask->id())); pRelNests->putAttr("relatedobjects", subTasksIds); subTasksIds.clear(); pModel->appendEntityInstance(pRelNests); } if (isFirstOnLevel) // if first on level so it is neccessary to create level task { OdDAIObjectId levelTaskTimeId = createIfcTaskTime(pModel, day, month, year); pLevelTaskTime = levelTaskTimeId.openObject(); OdDAIObjectId levelTaskId = createIfcTask(pModel, ownerHistoryId, productMap[i].productId, levelTaskTimeId); pLevelTask = levelTaskId.openObject(); isFirstOnLevel = false; } OdDAIObjectId taskTimeId = createIfcTaskTime(pModel, day, month, year); OdDAIObjectId taskId = createIfcTask(pModel, ownerHistoryId, productMap[i].productId, taskTimeId); subTasksIds.append(taskId); OdIfc::OdIfcInstancePtr pRelAssignsToProduct = pModel->createEntityInstance("ifcrelassignstoproduct"); OdIfc::Utils::assignGlobalId(pRelAssignsToProduct); pRelAssignsToProduct->putAttr("ownerhistory", ownerHistoryId); OdDAIObjectIds relatedObjectsIds; relatedObjectsIds.append(taskId); pRelAssignsToProduct->putAttr("relatedobjects", relatedObjectsIds); OdDAI::Select* productSelect; pRelAssignsToProduct->getAttr("relatingproduct") >> productSelect; pModel->appendEntityInstance(pRelAssignsToProduct); productSelect->setHandle(productMap[i].productId); previousFinishDay = day + 1; previousFinishMonth = month; previousFinishYear = year; ++day; if (day > 29) { day = 1; ++month; if (month > 12) { ++year; month = 1; } } previousLevel = productMap[i].level; } pIfcFile->unresolveEntities(); pIfcFile->writeFile(m_ifcOutputFileName); } } catch (OdError& e) { odPrintConsoleString(OD_T("\n\Tutorial_ScheduleCreation: Error: %ls"), e.description().c_str()); nRes = -1; } catch (...) { odPrintConsoleString(OD_T("\n\Tutorial_ScheduleCreation: Unexpected error.")); nRes = -1; } /**********************************************************************/ /* Uninitialize IfcCore */ /**********************************************************************/ odIfcUninitialize(); odPrintConsoleString(OD_T("\Tutorial_ScheduleCreation: File with work calendar was created successfully.\n")); return nRes; }