/////////////////////////////////////////////////////////////////////////////// // 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 "IfcRepresentationContextValidationTask.h" #include "daiValidationCommon.h" #include "daiValidationHealer.h" using namespace OdDAI; using namespace OdIfc; ODRX_VALIDATION_CONS_DEFINE_MEMBERS(RepresentationContextValidationTask, ExtentValidationTask, RXIMPL_CONSTR); ODRX_CONS_DEFINE_MEMBERS(RepresentationContextValidationHealer, OdDAI::ValidationHealer, RXIMPL_CONSTR); RepresentationContextValidationTask::RepresentationContextValidationTask() { m_extentName = "IfcGeometricRepresentationContext"; } OdDAI::Logical RepresentationContextValidationTask::validate(OdDAI::InstanceValidationContext* pInstanceCtx, OdSharedPtr& invalidParams) { InvalidObjectIdsValidationParams* pInvalidIds = new InvalidObjectIdsValidationParams; invalidParams = pInvalidIds; const OdDAI::SetOfOdDAIObjectId* ifcProjects = pInstanceCtx->pModel->getEntityExtent("IfcProject"); if (ifcProjects->getMemberCount() < 1) return OdDAI::Logical::False; OdDAIObjectId ifcProjectId = ifcProjects->getArray().first(); OdDAI::ApplicationInstancePtr pIfcProject = ifcProjectId.openObject(); OdDAIObjectIds validContexts; if (!(pIfcProject->getAttr("representationcontexts") >> validContexts)) return OdDAI::Logical::False; if (pInstanceCtx->pInstance->isInstanceOf("ifcgeometricrepresentationcontext")) { unsigned int index; if (!validContexts.find(pInstanceCtx->pInstance->id(), index)) { pInvalidIds->addData(pInstanceCtx->pInstance->id()); return OdDAI::Logical::False; } } else if (pInstanceCtx->pInstance->isInstanceOf("ifcgeometricrepresentationsubcontext")) { return OdDAI::Logical::True; } if (m_healingEnable) { auto healer = desc()->getX(OdDAI::ExtentValidationTask::desc()); if (healer) { OdDAI::ValidationHealerPtr validationHealer = OdDAI::ValidationHealer::cast(healer); if (!validationHealer.isNull()) { validationHealer->heal(pInstanceCtx->pModel, pInvalidIds); } } } return pInvalidIds->invalidItemsCount() > 0 ? OdDAI::Logical::False : OdDAI::Logical::True; } OdAnsiString RepresentationContextValidationTask::description() const { return "Representation Context assignment validation"; } OdDAI::Logical RepresentationContextValidationHealer::moveSubcontexts(const OdDAIObjectId sourceCtx, const OdDAIObjectId destinationCtx) { OdDAI::ApplicationInstance* pSourceReprCtx = sourceCtx.openObject(); OdDAI::Aggr* srcSubContexts; if (!(pSourceReprCtx->getAttr("hassubcontexts") >> srcSubContexts)) return OdDAI::Logical::False; const OdDAIObjectIds* srcSubContextsArr; srcSubContexts->getArray(srcSubContextsArr); OdDAI::ApplicationInstance* pDestinationReprCtx = destinationCtx.openObject(); OdDAI::Aggr* destinationSubContexts; if (!(pDestinationReprCtx->getAttr("hassubcontexts") >> destinationSubContexts)) return OdDAI::Logical::False; const OdDAIObjectIds* destinationSubContextsArr = nullptr; destinationSubContexts->getArray(destinationSubContextsArr); OdDAIObjectIds srcSubContextsArrCopy = *srcSubContextsArr; for (OdDAIObjectId srcSubContext : srcSubContextsArrCopy) { OdDAI::ApplicationInstance* pSourceSub = srcSubContext.openObject(); OdAnsiString sourceType; if (!(pSourceSub->getAttr("contexttype") >> sourceType)) continue; bool isFound = false; if (destinationSubContextsArr) for (auto destinationSubContext : *destinationSubContextsArr) { OdDAI::ApplicationInstance* pDestinationSubContext = destinationSubContext.openObject(); OdAnsiString destinationCtxType; if (!(pDestinationSubContext->getAttr("contexttype") >> destinationCtxType)) continue; if (sourceType.compare(destinationCtxType) == 0) { if (moveRepresentations(srcSubContext, destinationSubContext) == OdDAI::Logical::True) { isFound = true; break; } } } if (!isFound) { pSourceSub->resetInverseCounterParts(); pSourceSub->putAttr("parentcontext", destinationCtx); pSourceSub->setInverseCounterParts(); } } return OdDAI::Logical::True; } OdDAI::Logical RepresentationContextValidationHealer::moveRepresentations(OdDAIObjectId sourceCtx, OdDAIObjectId parentNew) { OdDAI::ApplicationInstance* pSourceCtx = sourceCtx.openObject(); OdDAI::Aggr* representationsInContext; if (!(pSourceCtx->getAttr("representationsincontext") >> representationsInContext)) return OdDAI::Logical::False; if (representationsInContext->isNil()) return OdDAI::Logical::True; const OdDAIObjectIds* repInCtxArray; representationsInContext->getArray(repInCtxArray); OdDAIObjectIds repInCtxArrayCopy = *repInCtxArray; for (auto representation : repInCtxArrayCopy) { OdDAI::ApplicationInstance* pIfcRepresentation = representation.openObject(); pIfcRepresentation->resetInverseCounterParts(); pIfcRepresentation->putAttr("contextofitems", parentNew); pIfcRepresentation->setInverseCounterParts(); } return OdDAI::Logical::True; } OdDAI::Logical RepresentationContextValidationHealer::heal(OdDAI::Model* pModel, OdDAI::ValidationTask::InvalidValidationParamsBase* invalidParams) { const OdDAI::SetOfOdDAIObjectId* ifcProjects = pModel->getEntityExtent("IfcProject"); if (ifcProjects->getMemberCount() == 0) { ODA_FAIL_M("IFC Model doesn't have single IfcProject instance"); return OdDAI::Logical::Unknown; } OdDAIObjectId ifcProjectId = ifcProjects->getArray().first(); OdDAI::ApplicationInstancePtr pIfcProject = ifcProjectId.openObject(); OdDAI::SetOfOdDAIObjectId* connectedCtxs; pIfcProject->getAttr("representationcontexts") >> connectedCtxs; OdDAIObjectIds connectedCtxsArray = connectedCtxs->getArray(); std::map ctxTypeMapping; for (auto connectedCtx : connectedCtxsArray) { OdDAI::ApplicationInstance* pCtx = connectedCtx.openObject(); OdAnsiString ctxType; if (pCtx->getAttr("contexttype") >> ctxType) ctxTypeMapping.insert({ ctxType, connectedCtx }); } OdDAIObjectIds invalidInstances = dynamic_cast (invalidParams)->invalidObjects; for (auto invalidInstance : invalidInstances) { OdDAI::ApplicationInstance* pRepresentationCtx = invalidInstance.openObject(); if (!pRepresentationCtx->isInstanceOf("ifcgeometricrepresentationcontext")) continue; OdAnsiString ctxType; if (pRepresentationCtx->getAttr("contexttype") >> ctxType) { auto mapSearch = ctxTypeMapping.find(ctxType); if (mapSearch == ctxTypeMapping.end()) { connectedCtxs->Add(pRepresentationCtx); ctxTypeMapping.insert({ ctxType , invalidInstance }); } else if (moveSubcontexts(invalidInstance, mapSearch->second) == OdDAI::Logical::False || moveRepresentations(invalidInstance, mapSearch->second) == OdDAI::Logical::False) { return OdDAI::Logical::False; } } } return OdDAI::Logical::True; }