/////////////////////////////////////////////////////////////////////////////// // 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 "IfcRepresentationContextRedundantValidationTask.h" #include "daiValidationCommon.h" #include "daiValidationHealer.h" using namespace OdDAI; using namespace OdIfc; ODRX_VALIDATION_CONS_DEFINE_MEMBERS(RepresentationContextRedundantValidationTask, ExtentValidationTask, RXIMPL_CONSTR); ODRX_CONS_DEFINE_MEMBERS(RepresentationContextRedundantValidationHealer, OdDAI::ValidationHealer, RXIMPL_CONSTR); RepresentationContextRedundantValidationTask::RepresentationContextRedundantValidationTask() { m_extentName = "IfcGeometricRepresentationContext"; } OdDAI::Logical RepresentationContextRedundantValidationTask::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 (validContexts.isEmpty()) { 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")) { OdAnsiString strContextType; if (pInstanceCtx->pInstance->getAttr("contexttype") >> strContextType) { OdAnsiString strContextIdentifier; if (pInstanceCtx->pInstance->getAttr("contextidentifier") >> strContextIdentifier) { if (strContextIdentifier.compare("Body") == 0) { OdDAI::SetOfOdDAIObjectId* setOfRepresentations; pInstanceCtx->pInstance->getAttr("representationsincontext") >> setOfRepresentations; if (setOfRepresentations && setOfRepresentations->getMemberCount() < 3) { unsigned int index; if (!validContexts.find(pInstanceCtx->pInstance->id(), index)) { if (m_generalContext.isNull() && m_excessiveContexts.isEmpty()) m_generalContext = pInstanceCtx->pInstance->id(); else m_excessiveContexts.append(pInstanceCtx->pInstance->id()); pInvalidIds->addData(pInstanceCtx->pInstance->id()); pInvalidIds->setValidationTask(this); return OdDAI::Logical::False; } } } } } 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 RepresentationContextRedundantValidationTask::description() const { return "Representation Context Redundant validation"; } const OdDAIObjectIds& OdIfc::RepresentationContextRedundantValidationTask::getExcessiveContexts() { return m_excessiveContexts; } const OdDAIObjectId& OdIfc::RepresentationContextRedundantValidationTask::getGeneralContext() { return m_generalContext; } OdDAI::Logical RepresentationContextRedundantValidationHealer::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; } if (auto invParams = dynamic_cast(invalidParams)) { ValidationTaskPtr contextTask = invParams->parentTask; if (!contextTask.isNull()) { if (auto validationTask = dynamic_cast(contextTask.get())) { OdDAIObjectId generalCtx = validationTask->getGeneralContext(); OdDAIObjectIds invalidInstances = invParams->invalidObjects; OdDAI::SetOfOdDAIObjectId* setOfRepresentations; if (!invalidInstances.isEmpty()) { OdDAIObjectIds excessiveContexts = validationTask->getExcessiveContexts(); const OdDAI::SetOfOdDAIObjectId* idsShape = pModel->getEntityExtent("ifcshaperepresentation"); if (idsShape && excessiveContexts.size() > 0) { if (idsShape->getMemberCount() / excessiveContexts.size() < 5) { invalidInstances.at(0).openObject()->getAttr("representationsincontext") >> setOfRepresentations; if (setOfRepresentations && setOfRepresentations->getMemberCount() > 0) { for (auto& shapeRepresentation : setOfRepresentations->getArray()) { OdDAIObjectId ctx; if (OdDAI::ApplicationInstancePtr pInst = shapeRepresentation.openObject()) { pInst->resetInverseCounterParts(); if (pInst->putAttr("contextofitems", generalCtx)) { pInst->setInverseCounterParts(); } } else { ODA_ASSERT(!shapeRepresentation.isNull() && "pointer cannot be null"); } } } for (auto& ctx : invalidInstances) { if (ctx != generalCtx) pModel->deleteInstance(ctx.openObject()); } } } else { return OdDAI::Logical::False; } } } } } else { return OdDAI::Logical::Unknown; } return OdDAI::Logical::True; }