/////////////////////////////////////////////////////////////////////////////// // 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 "IfcArbitraryProfileCurve2dValidationTask.h" #include "IfcEntity.h" #include "IfcCurves.h" #include "daiValidationCommon.h" #include "daiValidationHealer.h" using namespace OdDAI; using namespace OdIfc; ODRX_NO_CONS_DEFINE_MEMBERS(ArbitraryProfileCurve2dValidationTask, ExtentValidationTask); ODRX_VALIDATION_CONS_DEFINE_MEMBERS(ArbitraryOpenProfileCurve2dValidationTask, ArbitraryProfileCurve2dValidationTask, RXIMPL_CONSTR); ODRX_VALIDATION_CONS_DEFINE_MEMBERS(ArbitraryClosedProfileCurve2dValidationTask, ArbitraryProfileCurve2dValidationTask, RXIMPL_CONSTR); ODRX_CONS_DEFINE_MEMBERS(ArbitraryProfileCurve2dValidationHealer, OdDAI::ValidationHealer, RXIMPL_CONSTR); OdIfc::ArbitraryOpenProfileCurve2dValidationTask::ArbitraryOpenProfileCurve2dValidationTask() { m_extentName = "IfcArbitraryOpenProfileDef"; } OdAnsiString OdIfc::ArbitraryOpenProfileCurve2dValidationTask::description() const { return "IfcArbitraryOpenProfileDef curve validation. Checks inside curve on 2D."; } OdIfc::ArbitraryClosedProfileCurve2dValidationTask::ArbitraryClosedProfileCurve2dValidationTask() { m_extentName = "IfcArbitraryClosedProfileDef"; } OdAnsiString OdIfc::ArbitraryClosedProfileCurve2dValidationTask::description() const { return "IfcArbitraryClosedProfileDef curve validation. Checks inside curve on 2D."; } OdDAI::Logical ArbitraryProfileCurve2dValidationTask::validate(OdDAI::InstanceValidationContext* pInstanceCtx, OdSharedPtr& invalidParams) { InvalidObjectIdsValidationParams* pInvalidIds = new InvalidObjectIdsValidationParams; invalidParams = pInvalidIds; OdUInt64 ttt = OdDAIObjectId(pInstanceCtx->pInstance->id()).getHandle(); OdDAIObjectId curveId; if (!(OdIfc::OdIfcInstance::cast(pInstanceCtx->pInstance)->getAttr(kOuterCurve) >> curveId) || !curveId.isValid()) { pInvalidIds->addData(pInstanceCtx->pInstance->id()); return OdDAI::Logical::False; } OdIfcInstancePtr pCurveInst = curveId.openObject(); OdIfcCurvePtr pCurve = OdIfcCurve::cast(pCurveInst->owningStepFile()->getCompound(curveId)); if (pCurve->is3d()) { pInvalidIds->addData(pInstanceCtx->pInstance->id()); return OdDAI::Logical::False; } //OdGePoint3d testPoint; //pCurve->getGeCurve()->hasStartPoint(testPoint); //if (OdNonZero(testPoint.z)) //{ // pInvalidIds->addData(pInstanceCtx->pInstance->id()); // return OdDAI::Logical::False; //} return OdDAI::Logical::True; } namespace { OdDAIObjectId heal3dTo2d(OdIfcInstance* pInst); void checkExplicitAttributes(OdIfcInstance* pInst, Entity* pEntityType) { OdDAIObjectId id; const OdArray& explicitAttributes = pEntityType->explicitAttributes(); for (OdDAI::ExplicitAttribute* pAttr : explicitAttributes) { OdDAI::BaseTypePtr domain = pAttr->domain(); OdTCKind kind = domain->type()->kind(); if (kind == tkSequence) { if (const OdDAI::AggregationType* at = domain->aggregationType()) { const OdTCKind elementKind = at->elementType()->type()->kind(); if (elementKind == tkObjectId || elementKind == tkSelect) { OdDAI::Aggr* pAggr{ nullptr }; pInst->getAttr(pAttr) >> pAggr; if (pAggr && pAggr->getMemberCount()) { for (auto it = pAggr->createIterator(); it->next();) { it->getCurrentMember() >> id; if (id.isValid()) { if (OdDAIObjectId newId = heal3dTo2d(OdIfcInstance::cast(id.openObject()))) { it->putCurrentMember(newId); } } } } } } } else if (kind == tkObjectId || kind == tkSelect) { if (pInst->getAttr(pAttr) >> id && id.isValid()) { if (OdDAIObjectId newId = heal3dTo2d(OdIfcInstance::cast(id.openObject()))) { pInst->putAttr(pAttr, newId); } } } } } OdDAIObjectId heal3dTo2d(OdIfcInstance* pInst) { if (pInst->isKindOf(kIfcPoint)) { OdDAI::List* pCoords{nullptr}; pInst->getAttr(kCoordinates) >> pCoords; if (pCoords && pCoords->getMemberCount() == 3) { pCoords->removeByIndex(2); } } else if (pInst->isKindOf(kIfcDirection)) { OdDAI::List* pDirectionRatios{ nullptr }; pInst->getAttr(kDirectionRatios) >> pDirectionRatios; if (pDirectionRatios && pDirectionRatios->getMemberCount() == 3) { pDirectionRatios->removeByIndex(2); } } else if (pInst->isKindOf(kIfcAxis2Placement3D)) { OdDAIObjectId locationId; if (pInst->getAttr(kLocation) >> locationId && locationId.isValid()) heal3dTo2d(OdIfcInstance::cast(locationId.openObject())); OdDAIObjectId refDirectionId; if (pInst->getAttr(kRefDirection) >> refDirectionId && refDirectionId.isValid()) heal3dTo2d(OdIfcInstance::cast(refDirectionId.openObject())); OdDAI::ModelPtr pModel = pInst->owningModel(); OdIfcInstancePtr pNewInst = pModel->createEntityInstance("ifcaxis2placement2d"); pNewInst->putAttr(kLocation, locationId); pNewInst->putAttr(kRefDirection, refDirectionId); return pModel->insertEntityInstance(pNewInst, OdDAIObjectId(pInst->id()).getHandle()); } else { auto pEntityType = pInst->getInstanceType(); for(const auto& supertype : pEntityType->supertypes().getArray()) { checkExplicitAttributes(pInst, supertype); } checkExplicitAttributes(pInst, pEntityType); } return {}; } } OdDAI::Logical ArbitraryProfileCurve2dValidationHealer::heal(OdDAI::Model* pModel, OdDAI::ValidationTask::InvalidValidationParamsBase* invalidParams) { if (!pModel || !invalidParams) return OdDAI::Logical::False; OdDAI::Logical result = Logical::True; OdDAIObjectIds invalidInstances = dynamic_cast (invalidParams)->invalidObjects; OdDAIObjectId id; for (auto invalidInstance : invalidInstances) { OdIfcInstancePtr pInvalidInst = invalidInstance.openObject(); pInvalidInst->getAttr(kOuterCurve) >> id; OdIfcInstancePtr pCurveInst = id.openObject(); if (pCurveInst->isKindOf(kIfcCurve)) { OdIfcCurvePtr pCurve = OdIfcCurve::cast(pCurveInst->owningStepFile()->getCompound(id)); if (pCurve.isNull()) { result = Logical::False; continue; } OdGePoint3d testPoint; pCurve->getGeCurve()->hasStartPoint(testPoint); if (OdNonZero(testPoint.z)) { //Change position, if Z coord is nonZero OdDAI::NonPersistentList instanceUsers; pInvalidInst->findUsers(&instanceUsers); for (auto it = instanceUsers.createConstIterator(); it->next();) { OdDAIObjectSDAI* pObject; if (it->getCurrentMember() >> pObject) { OdIfcInstancePtr pInstance = OdIfcInstance::cast(pObject); OdDAIObjectId id; if (pInstance->getAttr(kPosition) >> id && id.isValid()) { OdIfcInstancePtr pPositionInst = id.openObject(); if (pPositionInst->isKindOf(kIfcAxis2Placement3D)) { if (pPositionInst->getAttr(kLocation) >> id && id.isValid()) { OdIfcInstancePtr pLocationInst = id.openObject(); //OdGePoint3d point = *OdIfcInstance::asPoint3d(pLocationInst); OdDAI::List* pointCoords; pLocationInst->getAttr(kCoordinates) >> pointCoords; double coordZ(0.); pointCoords->getByIndex(2) >> coordZ; pointCoords->putByIndex(2, coordZ + testPoint.z); } } } else { ODA_FAIL_M("Not implemented yet."); result = Logical::False; } } } } //Heal curve if (OdDAIObjectId newId = heal3dTo2d(pCurveInst)) { pInvalidInst->putAttr(kOuterCurve, newId); } } } return result; }