/////////////////////////////////////////////////////////////////////////////// // 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 "IfcClosedShellValidationTask.h" #include "IfcEntity.h" #include "IfcFile.h" using namespace OdDAI; using namespace OdIfc; ODRX_VALIDATION_CONS_DEFINE_MEMBERS(ClosedShellValidationTask, ExtentValidationTask, RXIMPL_CONSTR) ODRX_CONS_DEFINE_MEMBERS(ShellValidationHealer, ValidationHealer, RXIMPL_CONSTR); bool ClosedShellValidationTask::samePointCheck(const OdDAIObjectIds& vertexList) { for (int i = 0; i < static_cast(vertexList.size() - 1); i++) { OdIfcInstancePtr pPoint1 = vertexList[i].openObject(); OdIfcInstancePtr pPoint2 = vertexList[i + 1].openObject(); OdArray coordinates1(3), coordinates2(3); if (pPoint1->getAttr(kCoordinates) >> coordinates1 && pPoint2->getAttr(kCoordinates) >> coordinates2) { if (coordinates1[0] == coordinates2[0] && coordinates1[1] == coordinates2[1] && coordinates1[2] == coordinates2[2]) return true; } else { ODA_ASSERT_ONCE(!"Failed to get coordinates of vertexes!"); } } return false; } bool ClosedShellValidationTask::lineCheck(const OdDAIObjectIds& vertexList) { int size = vertexList.size(); for (int i = 0; i < size - 2; i++) { OdIfcInstancePtr pPoint1 = vertexList[i].openObject(); OdIfcInstancePtr pPoint2 = vertexList[i + 1].openObject(); OdIfcInstancePtr pPoint3 = vertexList[i + 2].openObject(); OdArray coordinates1(3), coordinates2(3), coordinates3(3); if (pPoint1->getAttr(kCoordinates) >> coordinates1 && pPoint2->getAttr(kCoordinates) >> coordinates2 && pPoint3->getAttr(kCoordinates) >> coordinates3) { /* checkin if points are co-linear using the following formula if AC = AB + BC than vertex B is on the line AC */ OdGePoint3d point1(coordinates1[0], coordinates1[1], coordinates1[2]); OdGePoint3d point2(coordinates2[0], coordinates2[1], coordinates2[2]); OdGePoint3d point3(coordinates3[0], coordinates3[1], coordinates3[2]); if ((point1.distanceTo(point3) - (point1.distanceTo(point2) + point2.distanceTo(point3))) < OdGeTol(1e-6).equalPoint()) return true; } else { ODA_ASSERT_ONCE(!"Failed to get coordinates of vertexes!"); } } return false; } ClosedShellValidationTask::ClosedShellValidationTask() { m_extentName = "IfcClosedShell"; } Logical ClosedShellValidationTask::validate(OdDAI::InstanceValidationContext* pInstanceCtx, OdSharedPtr& invalidParams) { InvalidRxArrayValidationParams* invalidInstances = new InvalidRxArrayValidationParams(); invalidParams = invalidInstances; OdDAI::InstanceValidationContext* pIfcCtx = dynamic_cast(pInstanceCtx); if (pIfcCtx == nullptr) { return Logical::False; } OdDAIObjectIds faces; OdIfcInstancePtr pEnt = pIfcCtx->pInstance; if (!(pEnt->getAttr(kCfsFaces) >> faces)) { ODA_ASSERT_ONCE(!"Error while getting faces of shell!"); return Logical::False; } for (auto faceIter : faces) { OdDAIObjectIds bounds; OdIfcInstancePtr pFace = faceIter.openObject(); if (!(pFace->getAttr(kBounds) >> bounds)) { ODA_ASSERT_ONCE(!"Error while getting bounds of face!"); return Logical::False; } for (auto boundsIter : bounds) { OdDAIObjectId loop; OdIfcInstancePtr pBound = boundsIter.openObject(); if (!(pBound->getAttr(kBound) >> loop)) { ODA_ASSERT_ONCE(!"Error while getting bound loop!"); return Logical::False; } OdDAIObjectIds vertexList; OdIfcInstancePtr pLoop = loop.openObject(); if (!(pLoop->getAttr(kPolygon) >> vertexList)) { ODA_ASSERT_ONCE(!"Error while verteg list of loop!"); return Logical::False; } if (vertexList.size() < 3) { invalidInstances->addData(InvalidRxObjectsValidationParams({ pBound }, "There are less than 3 points.", Logical::False)); continue; } if (samePointCheck(vertexList)) { invalidInstances->addData(InvalidRxObjectsValidationParams({ pBound }, "There are 2 consecutive pointes are in the same coordinates", Logical::False)); continue; } if (lineCheck(vertexList)) invalidInstances->addData(InvalidRxObjectsValidationParams({ pBound }, "There are 3 consecutive points that form a line.", Logical::False)); } } return (invalidInstances->invalidItemsCount() ? Logical::False : Logical::True); } OdAnsiString ClosedShellValidationTask::description() const { return "IfcClosedShell validation"; } OdDAI::Logical ShellValidationHealer::heal(OdDAI::Model* model, OdDAI::ValidationTask::InvalidValidationParamsBase* invalidParams) { return OdDAI::Logical(); }