/////////////////////////////////////////////////////////////////////////////// // 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 "Entities.h" #include "DWGConstraintCreation.h" #include "DWGCommandsUtils.h" #include "OdExplicitConstr.h" #include "DbBlockTable.h" #include "DbBlockTableRecord.h" #include "DbAssocNetwork.h" #include "DbAssocDimDependencyBodyBase.h" #include "DbAssocVariable.h" #include "DbAssocDimDependencyBody.h" #include "DbAssocValueDependency.h" #include "DbAssoc2dConstraintGroup.h" #include "DbDimAssoc.h" #define STL_USING_MEMORY #include "OdaSTL.h" #include "DbAssocManager.h" #include #include #include OdResult postToDatabase(OdDbEntity* pEntity, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdDbBlockTablePtr blkTable = pDb->getBlockTableId().safeOpenObject(OdDb::kForRead); if (blkTable.isNull() || !blkTable->has(spaceId)) return eInvalidInput; OdDbBlockTableRecordPtr btr = spaceId.safeOpenObject(OdDb::kForWrite); if (btr.isNull()) return eInvalidInput; btr->appendOdDbEntity(pEntity); return eOk; } static OdResult getNameAndExpressionFromDimension(const OdDbObjectId& networkId, const OdDbObjectId& dimId, const OdDbAssocConstraintType& constraintType, OdString& name, OdString& expression) { OdResult err = eOk; name.empty(); expression.empty(); // Choose the name prefix based on the type of constraint OdString namePrefix; switch (constraintType) { case kDistanceAssocConstraintType: case kHorizontalDistanceAssocConstraintType: case kVerticalDistanceAssocConstraintType: namePrefix = OD_T("d"); break; case kAngle0AssocConstraintType: case kAngle1AssocConstraintType: case kAngle2AssocConstraintType: case kAngle3AssocConstraintType: namePrefix = OD_T("ang"); break; case kRadiusAssocConstraintType: namePrefix = OD_T("rad"); break; case kDiameterAssocConstraintType: namePrefix = OD_T("dia"); break; default: ODA_ASSERT_ONCE(!OD_T("Unsupported dimensional constraint type")); namePrefix = OD_T("error"); break; } OdString dimensionText; double measurement = 0.; bool isAngular = false; { OdDbDimensionPtr pDim = dimId.safeOpenObject(OdDb::kForRead); if (pDim.isNull()) return eInvalidInput; if (pDim->isConstraintObject()) { dimensionText = pDim->dimensionText(); } measurement = pDim->measurement(); isAngular = pDim->isKindOf(OdDb2LineAngularDimension::desc()) || pDim->isKindOf(OdDb3PointAngularDimension::desc()); } // Extract the dimension name and expression given the entity text OdString dfltName, dfltExpression; err = OdDbAssocDimDependencyBodyBase::getNameAndExpressionFromEntityText(dimensionText, true, measurement, isAngular, dfltName, dfltExpression); //ODA_ASSERT_ONCE(!dfltExpression.isEmpty()); // not implemented //default name should be empty if it's not a dimconstraint, need to generate a unique name from prefix if (dfltName.isEmpty()) { OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForRead); if (pNetwork.isNull()) { return eInvalidInput; } OdDbObjectIdArray actions = pNetwork->getActions(); OdArray suffixArray; for (OdDbObjectId id : actions) { OdDbObjectPtr pObj = id.safeOpenObject(OdDb::kForRead, true); if (!pObj->isKindOf(OdDbAssocVariable::desc())) { continue; } OdDbAssocVariablePtr pVar = pObj; const OdString varName = pVar->name(); OdString varBeg = varName.left(namePrefix.getLength()); //if (varName.matchNoCase(namePrefix) == namePrefix.getLength()) if (varBeg.iCompare(namePrefix) == 0) { const OdString number = varName.mid(namePrefix.getLength()); int val = odStrToInt(number); if (val >= 0) { suffixArray.append(val); } } } int index = 1; unsigned int findIndex = 0; while (suffixArray.find(index, findIndex)) { if (index < 0) { ODA_ASSERT_ONCE(!"Interger overflow"); return eInvalidInput; } ++index; } dfltName = namePrefix; OdString tmp; tmp.format(L"%i", index); dfltName += tmp; } name = dfltName; expression = dfltExpression; return eOk; // err; - getNameAndExpressionFromEntityText is not implemented } static OdResult createAlignedDim(const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdResult es; OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimPt1(entPt1); OdGePoint3d dimPt2(entPt2); OdGePoint3d dimTxt(dimPos); OdDbAlignedDimensionPtr dim = OdDbAlignedDimension::createObject(); dim->setDatabaseDefaults(pDb); dim->setXLine1Point(dimPt1.transformBy(ucsMatrixInv)); dim->setXLine2Point(dimPt2.transformBy(ucsMatrixInv)); //dim->setTextPosition(dimTxt.transformBy(ucsMatrixInv)); dim->setDimLinePoint(dimTxt.transformBy(ucsMatrixInv)); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } else { //dim->setDimensionStyle(pDb->getTEXTSTYLE()); // exc "wrong obj type" } es = postToDatabase(dim, pDb, spaceId); dimId = dim->objectId(); return es; } #define EXPRESSION_EVALUATOR_DEFAULT OD_T("") static OdResult addNewVariableToAssocNetwork(const OdDbObjectId& networkId, const OdString& name, const OdString& expression, OdDbObjectId& varId, double dValue) { OdString realExpression; if (expression.isEmpty()) { std::ostringstream out; out.precision(20); out << std::fixed << dValue; std::string stdstr = std::move(out.str()); realExpression = OdString(stdstr.c_str()); } else { realExpression = expression; } OdResult es = eOk; varId = OdDbObjectId::kNull; OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForWrite); if (pNetwork.isNull()) return eInvalidInput; { OdDbAssocVariablePtr pVar = OdDbAssocVariable::createObject(); varId = pNetwork->database()->addOdDbObject(pVar); if (varId.isNull()) return eInvalidInput; if ((es = pNetwork->addAction(varId, true)) != eOk) return es; } OdDbAssocVariablePtr pAssocVar = varId.safeOpenObject(OdDb::kForWrite); OdString errMsgValidate(L"Name or Expression invalid"); if ((es = pAssocVar->validateNameAndExpression(name, realExpression, &errMsgValidate)) != eOk) return es; if ((es = pAssocVar->setName(name, true)) != eOk) return es; OdDbEvalVariantPtr value = OdDbEvalVariant::init(dValue); pAssocVar->setValue(*value); if ((es = pAssocVar->setExpression(realExpression, EXPRESSION_EVALUATOR_DEFAULT, true, true)) != eOk) return es; OdString errMsgEval(L"Expression evaluation failed"); OdDbEvalVariantPtr evaluatedExpressionValue = OdDbEvalVariant::init(double(1.)); if ((es = pAssocVar->evaluateExpression(evaluatedExpressionValue.get(), &errMsgEval)) != eOk) return es; if ((pAssocVar->setValue(*evaluatedExpressionValue)) != eOk) return es; return es; } static OdResult addValueDependency(const OdDbObjectId& networkId, const OdDbObjectId& varId, OdDbObjectId& varDepId) { OdResult es = eOk; varDepId = OdDbObjectId::kNull; OdDbAssocValueDependencyPtr pValDep = OdDbAssocValueDependency::createObject(); varDepId = networkId.database()->addOdDbObject(pValDep); if (varDepId.isNull()) { return eInvalidInput; } OdDbCompoundObjectId conpoundId; conpoundId.set(varId); if ((es = pValDep->attachToObject(conpoundId)) != eOk) return es; if (varId.isNull() || varDepId.isNull()) return eNullObjectId; pValDep->evaluate(); // must happen automaticaly, but doesn't return es; } static OdResult createDistanceConstraint(const OdDbObjectId& varDepId, const OdDbObjectId& dimDepId, OdConstrainedGeometry*& pConsGeom1, const OdGePoint3d& entPt1, OdConstrainedGeometry*& pConsGeom2, const OdGePoint3d& entPt2, const OdGeVector3d* pFixedDirection, OdDbDatabase* pDb, const OdDbObjectId& spaceId, OdDistanceConstraint** ppNewDisConstraint) { OdResult es; OdDbObjectId consGrpId = DWGConstraintUtils::getConstraintGroup(spaceId, true); if (consGrpId.isNull()) return eNullObjectId; OdDbAssoc2dConstraintGroupPtr p2dConstrGrp = consGrpId.safeOpenObject(OdDb::kForWrite); if (p2dConstrGrp.isNull()) return eInvalidInput; OdGeMatrix3d coordSysInv = DWGConstraintUtils::getConstraintGroupCoordSysInv(p2dConstrGrp); //Get closest constrained point1 OdGePoint3d entPt1InConstGrp = entPt1; entPt1InConstGrp.transformBy(coordSysInv); OdConstrainedPoint* point1; if ((es = DWGConstraintUtils::getClosestConstrainedPoint(pConsGeom1, entPt1InConstGrp, point1)) != eOk) return es; //Get closest constrained point2 OdGePoint3d entPt2InConstGrp = entPt2; entPt2InConstGrp.transformBy(coordSysInv); OdConstrainedPoint* point2; if ((es = DWGConstraintUtils::getClosestConstrainedPoint(pConsGeom2, entPt2InConstGrp, point2)) != eOk) return es; if ((es = p2dConstrGrp->addDistanceConstraint(point1, point2, pFixedDirection != NULL ? OdDistanceConstraint::kFixedDirection : OdDistanceConstraint::kNotDirected, varDepId, dimDepId, pFixedDirection, NULL, ppNewDisConstraint)) != eOk) { return es; } OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromDatabase(pDb, true, ASSOCNETWORK_DICTIONARYKEY); OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForWrite); DWGConstraintUtils::DwgConstraintEvaluationCallback tmpCallback; tmpCallback._allowOverconstrain = false; pNetwork->evaluate(&tmpCallback); return es; } static void doCleanUp(OdDbObjectIdArray& cleanupObjectIds) { for (unsigned int i = 0; i < cleanupObjectIds.logicalLength(); ++i) { OdDbObjectPtr pObject = cleanupObjectIds[i].safeOpenObject(OdDb::kForWrite); if (!pObject.isNull()) pObject->erase(true); } } OdResult createAlignedDimConstraintPrivate(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, OdDbObjectId& varDimId, OdDbAlignedDimensionPtr dimAssoc = OdDbAlignedDimensionPtr()) { varDimId = OdDbObjectId::kNull; OdDbObjectIdArray cleanupObjectIds; try { OdResult err = eOk; OdDbFullSubentPathArray aPathsEdge; // Take the first edge OdDbFullSubentPath edgeEntPath1; OdGePoint3d vertex1; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId1, entPt1, edgeEntPath1, NULL, NULL, NULL, NULL, NULL, &vertex1)) != eOk) throw err; aPathsEdge.append(edgeEntPath1); // Take the second edge OdDbFullSubentPath edgeEntPath2; OdGePoint3d vertex2; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId2, entPt2, edgeEntPath2, NULL, NULL, NULL, NULL, NULL, &vertex2)) != eOk) throw err; aPathsEdge.append(edgeEntPath2); OdArray pConsGeoms; if ((err = DWGConstraintUtils::addConstrainedGeometry(pDatabase, aPathsEdge, pConsGeoms)) != eOk) throw err; OdDbObjectId dimId = OdDbObjectId::kNull; OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); if (dimAssoc.isNull()) { OdDbObjectId dimStyleId = OdDbObjectId::kNull; if ((err = createAlignedDim(vertex1, vertex2, dimPos, dimId, dimStyleId, pDatabase, spaceId)) != eOk) { throw err; } cleanupObjectIds.append(dimId); } else { dimId = dimAssoc->objectId(); } OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); OdString dimName; OdString dimExpression; if ((err = getNameAndExpressionFromDimension(networkId, dimId, OdDbAssocConstraintType::kDistanceAssocConstraintType, dimName, dimExpression)) != eOk) { throw err; } //Create new AssocVariable if ((err = addNewVariableToAssocNetwork(networkId, dimName, dimExpression, varDimId, vertex1.distanceTo(vertex2))) != eOk) throw err; //As the variable didn't exist, we will need to clean it up if something goes wrong from here. cleanupObjectIds.append(varDimId); OdDbObjectId varDepId = OdDbObjectId::kNull; if ((err = addValueDependency(networkId, varDimId, varDepId)) != eOk) throw err; //create dim dependency OdDbObjectId dimDepBodyId, dimDepId; if ((err = OdDbAssocDimDependencyBody::createAndPostToDatabase(dimId, dimDepId, dimDepBodyId)) != eOk) throw err; const bool bPreviousValue = OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(false); OdDistanceConstraint* ppNewDisConstraint = NULL; if ((err = createDistanceConstraint(varDepId, dimDepId, pConsGeoms[0], vertex1, pConsGeoms[1], vertex2, NULL, pDatabase, spaceId, &ppNewDisConstraint)) != eOk) { throw err; } OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(bPreviousValue); return err; } catch (OdResult err) { if (err != eOk) { doCleanUp(cleanupObjectIds); } return err; } } static OdResult create2LinesAngularDim(const OdGePoint3d& startPoint1, const OdGePoint3d& endPoint1, const OdGePoint3d& startPoint2, const OdGePoint3d& endPoint2, const OdGePoint3d& dimPos, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdResult es; OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimStart1(startPoint1); OdGePoint3d dimEnd1(endPoint1); OdGePoint3d dimStart2(startPoint2); OdGePoint3d dimEnd2(endPoint2); OdGePoint3d dimTxt(dimPos); OdDb2LineAngularDimensionPtr dim = OdDb2LineAngularDimension::createObject(); dim->setXLine1Start(dimStart1.transformBy(ucsMatrixInv)); dim->setXLine1End(dimEnd1.transformBy(ucsMatrixInv)); dim->setXLine2Start(dimStart2.transformBy(ucsMatrixInv)); dim->setXLine2End(dimEnd2.transformBy(ucsMatrixInv)); dim->setArcPoint(dimTxt.transformBy(ucsMatrixInv)); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } else { /*OdDbDimStyleTableRecordPtr pDimStyle = OdDbDimStyleTableRecord::createObject(); pDb->getDimstyleData(pDimStyle); pDimStyle->setDimscale(1.0); dim->setDimstyleData(pDimStyle);*/ } es = postToDatabase(dim, pDb, spaceId); dimId = dim->objectId(); return es; } static OdResult create2LineAngleConstraint(const OdDbObjectId& varDepId, const OdDbObjectId& dimDepId, OdConstrainedGeometry*& pConsGeom1, OdConstrainedGeometry*& pConsGeom2, OdAngleConstraint::SectorType sectorType, OdDbDatabase* pDb, const OdDbObjectId& spaceId, OdAngleConstraint** ppNewAngConstraint) { OdResult es; OdDbObjectId consGrpId = DWGConstraintUtils::getConstraintGroup(spaceId, true); if (consGrpId.isNull()) return eNullObjectId; OdDbAssoc2dConstraintGroupPtr p2dConstrGrp = consGrpId.safeOpenObject(OdDb::kForWrite); if (p2dConstrGrp.isNull()) return eInvalidInput; if (!pConsGeom1->isKindOf(OdConstrainedLine::desc())) return eInvalidInput; if (!pConsGeom2->isKindOf(OdConstrainedLine::desc())) return eInvalidInput; OdConstrainedLine* pConsLine1 = OdConstrainedLine::cast(pConsGeom1); OdConstrainedLine* pConsLine2 = OdConstrainedLine::cast(pConsGeom2); if ((es = p2dConstrGrp->addAngleConstraint(pConsLine1, pConsLine2, sectorType, varDepId, dimDepId, ppNewAngConstraint)) != eOk) { return es; } OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromDatabase(pDb, true, ASSOCNETWORK_DICTIONARYKEY); OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForWrite); DWGConstraintUtils::DwgConstraintEvaluationCallback tmpCallback; tmpCallback._allowOverconstrain = false; pNetwork->evaluate(&tmpCallback); return es; } OdResult create2LineAngularDimConstraintPrivate(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, OdDbObjectId& varDimId, OdDb2LineAngularDimensionPtr dimAssoc = OdDb2LineAngularDimensionPtr()) { varDimId = OdDbObjectId::kNull; OdDbObjectIdArray cleanupObjectIds; try { OdResult err = eOk; OdDbFullSubentPath edgeEntPath1; OdGePoint3d startPoint1, endPoint1; if ((err = DWGConstraintUtils::getLinearEdgeData(entId1, entPt1, edgeEntPath1, startPoint1, endPoint1)) != eOk) throw err; OdDbFullSubentPath edgeEntPath2; OdGePoint3d startPoint2, endPoint2; if ((err = DWGConstraintUtils::getLinearEdgeData(entId2, entPt2, edgeEntPath2, startPoint2, endPoint2)) != eOk) throw err; // calc the angle between lines OdGeVector3d v1 = endPoint1 - startPoint1; OdGeVector3d v2 = endPoint2 - startPoint2; double angle = v1.angleTo(v2) * 180. / OdaPI; // lines are parallel if (OdZero(angle) || OdEqual(angle, OdaPI)) { throw eInvalidIndex; } OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); OdAngleConstraint::SectorType sectorType = OdAngleConstraint::SectorType::kParallelAntiClockwise; { OdGeLine3d line1(startPoint1, endPoint1); OdGeLine3d line2(startPoint2, endPoint2); OdGePoint3d ptIntersect; line1.intersectWith(line2, ptIntersect); OdGePlane plane(ptIntersect, v1, v2); OdGePlane planeUCS; DWGConstraintUtils::currentUCS(spaceId, &planeUCS); const bool anticlockwise = v1.crossProduct(v2).isCodirectionalTo(planeUCS.normal()); OdGePoint2d paramAngle = plane.paramOf(dimPos); if (paramAngle.x > 0 && paramAngle.y > 0) { sectorType = anticlockwise ? OdAngleConstraint::SectorType::kParallelAntiClockwise : OdAngleConstraint::SectorType::kParallelClockwise; } else if (paramAngle.x < 0 && paramAngle.y > 0) { angle = 180. - angle; sectorType = anticlockwise ? OdAngleConstraint::SectorType::kAntiParallelClockwise : OdAngleConstraint::SectorType::kAntiParallelAntiClockwise; } else if (paramAngle.x > 0 && paramAngle.y < 0) { angle = 180. - angle; sectorType = anticlockwise ? OdAngleConstraint::SectorType::kAntiParallelClockwise : OdAngleConstraint::SectorType::kAntiParallelAntiClockwise; } else //if (paramAngle.x < 0 && paramAngle.y < 0) { sectorType = anticlockwise ? OdAngleConstraint::SectorType::kParallelAntiClockwise : OdAngleConstraint::SectorType::kParallelClockwise; } } OdDbObjectId dimId = OdDbObjectId::kNull; if (dimAssoc.isNull()) { OdDbObjectId dimStyleId = OdDbObjectId::kNull; // 2 and 1 points are changed places due to strange acad behavior if ((err = create2LinesAngularDim(startPoint2, endPoint2, startPoint1, endPoint1, dimPos, dimId, dimStyleId, pDatabase, spaceId)) != eOk) { throw err; } cleanupObjectIds.append(dimId); } else { dimId = dimAssoc->objectId(); } OdDbFullSubentPathArray aPathsEdge; aPathsEdge.append(edgeEntPath1); aPathsEdge.append(edgeEntPath2); OdArray pConsGeoms; if ((err = DWGConstraintUtils::addConstrainedGeometry(pDatabase, aPathsEdge, pConsGeoms)) != eOk) throw err; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); OdString dimName; OdString dimExpression; if ((err = getNameAndExpressionFromDimension(networkId, dimId, OdDbAssocConstraintType::kAngle0AssocConstraintType, dimName, dimExpression)) != eOk) { throw err; } //Create new AssocVariable if ((err = addNewVariableToAssocNetwork(networkId, dimName, dimExpression, varDimId, angle)) != eOk) throw err; //As the variable didn't exist, we will need to clean it up if something goes wrong from here. cleanupObjectIds.append(varDimId); OdDbObjectId varDepId = OdDbObjectId::kNull; if ((err = addValueDependency(networkId, varDimId, varDepId)) != eOk) throw err; //create dim dependency OdDbObjectId dimDepBodyId, dimDepId; if ((err = OdDbAssocDimDependencyBody::createAndPostToDatabase(dimId, dimDepId, dimDepBodyId)) != eOk) throw err; const bool bPreviousValue = OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(false); OdAngleConstraint* ppNewAngConstraint = NULL; if ((err = create2LineAngleConstraint(varDepId, dimDepId, pConsGeoms[0], pConsGeoms[1], sectorType, pDatabase, spaceId, &ppNewAngConstraint)) != eOk) throw err; OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(bPreviousValue); return err; } catch (OdResult err) { if (err != eOk) { doCleanUp(cleanupObjectIds); } return err; } } static OdResult create3PointAngularDim(const OdGePoint3d& centerPoint, const OdGePoint3d& xLine1Point, const OdGePoint3d& xLine2Point, const OdGePoint3d& arcPoint, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimCenter(centerPoint); OdGePoint3d dimxLine1(xLine2Point); OdGePoint3d dimxLine2(xLine1Point); OdGePoint3d dimArc(arcPoint); OdDb3PointAngularDimensionPtr dim = OdDb3PointAngularDimension::createObject(); dim->setCenterPoint(dimCenter.transformBy(ucsMatrixInv)); dim->setXLine1Point(dimxLine1.transformBy(ucsMatrixInv)); dim->setXLine2Point(dimxLine2.transformBy(ucsMatrixInv)); dim->setArcPoint(dimArc.transformBy(ucsMatrixInv)); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } else { /*OdDbDimStyleTableRecordPtr pDimStyle = OdDbDimStyleTableRecord::createObject(); pDb->getDimstyleData(pDimStyle); pDimStyle->setDimscale(1.0); dim->setDimstyleData(pDimStyle);*/ } OdResult es = postToDatabase(dim, pDb, spaceId); dimId = dim->objectId(); return es; } static OdResult create3PointAngleConstraint(const OdDbObjectId& varDepId, const OdDbObjectId& dimDepId, OdConstrainedGeometry*& pConsGeom1, const OdGePoint3d& entPt1, OdConstrainedGeometry*& pConsGeom2, const OdGePoint3d& entPt2, OdConstrainedGeometry*& pConsGeom3, const OdGePoint3d& entPt3, OdAngleConstraint::SectorType sectorType, OdDbDatabase* pDb, const OdDbObjectId& spaceId, Od3PointAngleConstraint** ppNewAngConstraint) { OdResult es; OdDbObjectId consGrpId = DWGConstraintUtils::getConstraintGroup(spaceId, true); if (consGrpId.isNull()) return eNullObjectId; OdDbAssoc2dConstraintGroupPtr p2dConstrGrp = consGrpId.safeOpenObject(OdDb::kForWrite); if (p2dConstrGrp.isNull()) return eInvalidInput; OdGeMatrix3d coordSysInv = DWGConstraintUtils::getConstraintGroupCoordSysInv(p2dConstrGrp); //Get closest constrained point1 OdGePoint3d entPt1InConstGrp = entPt1; entPt1InConstGrp.transformBy(coordSysInv); OdConstrainedPoint* point1; if ((es = DWGConstraintUtils::getClosestConstrainedPoint(pConsGeom1, entPt1InConstGrp, point1)) != eOk) return es; //Get closest constrained point2 OdGePoint3d entPt2InConstGrp = entPt2; entPt2InConstGrp.transformBy(coordSysInv); OdConstrainedPoint* point2; if ((es = DWGConstraintUtils::getClosestConstrainedPoint(pConsGeom2, entPt2InConstGrp, point2)) != eOk) return es; //Get closest constrained point3 OdGePoint3d entPt3InConstGrp = entPt3; entPt3InConstGrp.transformBy(coordSysInv); OdConstrainedPoint* point3; if ((es = DWGConstraintUtils::getClosestConstrainedPoint(pConsGeom3, entPt3InConstGrp, point3)) != eOk) return es; if ((es = p2dConstrGrp->add3PointAngleConstraint(point1, point2, point3, sectorType, varDepId, dimDepId, ppNewAngConstraint)) != eOk) return es; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromDatabase(pDb, true, ASSOCNETWORK_DICTIONARYKEY); OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForWrite); DWGConstraintUtils::DwgConstraintEvaluationCallback tmpCallback; tmpCallback._allowOverconstrain = false; pNetwork->evaluate(&tmpCallback); return es; } OdResult create3PointAngularDimConstraintPrivate(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdDbObjectId& entId3, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& entPt3, const OdGePoint3d& dimPos, OdDbObjectId& varDimId, OdDb3PointAngularDimensionPtr dimAssoc = OdDb3PointAngularDimensionPtr()) { varDimId = OdDbObjectId::kNull; OdDbObjectIdArray cleanupObjectIds; try { OdResult err = eOk; OdDbFullSubentPathArray aPathsEdge; OdDbFullSubentPathArray pathsRequiresMidPoint; bool addMidPoint = false; //Get Edge/Vertex 1 OdDbFullSubentPath edgeEntPath1; OdGePoint3d vertex1; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId1, entPt1, edgeEntPath1, addMidPoint, NULL, NULL, NULL, NULL, NULL, &vertex1)) != eOk) throw err; aPathsEdge.append(edgeEntPath1); if(addMidPoint) pathsRequiresMidPoint.append(edgeEntPath1); //Get Edge/Vertex 2 OdDbFullSubentPath edgeEntPath2; OdGePoint3d vertex2; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId2, entPt2, edgeEntPath2, addMidPoint, NULL, NULL, NULL, NULL, NULL, &vertex2)) != eOk) throw err; aPathsEdge.append(edgeEntPath2); if (addMidPoint) pathsRequiresMidPoint.append(edgeEntPath2); //Get Edge/Vertex 3 OdDbFullSubentPath edgeEntPath3; OdGePoint3d vertex3; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId3, entPt3, edgeEntPath3, addMidPoint, NULL, NULL, NULL, NULL, NULL, &vertex3)) != eOk) throw err; aPathsEdge.append(edgeEntPath3); if (addMidPoint) pathsRequiresMidPoint.append(edgeEntPath3); OdArray pConsGeoms; if ((err = DWGConstraintUtils::addConstrainedGeometry(pDatabase, aPathsEdge, pathsRequiresMidPoint, pConsGeoms)) != eOk) throw err; // calc the angle OdGeVector3d v1 = vertex2 - vertex1; OdGeVector3d v2 = vertex3 - vertex1; double angle = v1.angleTo(v2) * 180. / OdaPI; // lines are parallel if (OdZero(angle) || OdEqual(angle, OdaPI)) { throw eInvalidIndex; } OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); OdAngleConstraint::SectorType sectorType = OdAngleConstraint::SectorType::kParallelAntiClockwise; { OdGePlane plane(vertex1, v1, v2); OdGePlane planeUCS; DWGConstraintUtils::currentUCS(spaceId, &planeUCS); const bool anticlockwise = v1.crossProduct(v2).isCodirectionalTo(planeUCS.normal()); OdGePoint2d paramAngle = plane.paramOf(dimPos); if (paramAngle.x > 0 && paramAngle.y > 0) { sectorType = anticlockwise ? OdAngleConstraint::SectorType::kParallelAntiClockwise : OdAngleConstraint::SectorType::kParallelClockwise; } else { angle = 360. - angle; sectorType = anticlockwise ? OdAngleConstraint::SectorType::kParallelClockwise : OdAngleConstraint::SectorType::kParallelAntiClockwise; } } OdDbObjectId dimId = OdDbObjectId::kNull; if (dimAssoc.isNull()) { OdDbObjectId dimStyleId = OdDbObjectId::kNull; if ((err = create3PointAngularDim(vertex1, vertex3, vertex2, dimPos, dimId, dimStyleId, pDatabase, spaceId)) != eOk) { throw err; } cleanupObjectIds.append(dimId); } else { dimId = dimAssoc->objectId(); } OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); OdString dimName, dimExpression; if ((err = getNameAndExpressionFromDimension(networkId, dimId, OdDbAssocConstraintType::kAngle0AssocConstraintType, dimName, dimExpression)) != eOk) { throw err; } //Create new AssocVariable if ((err = addNewVariableToAssocNetwork(networkId, dimName, dimExpression, varDimId, angle)) != eOk) throw err; //As the variable didn't exist, we will need to clean it up if something goes wrong from here. cleanupObjectIds.append(varDimId); OdDbObjectId varDepId = OdDbObjectId::kNull; if ((err = addValueDependency(networkId, varDimId, varDepId)) != eOk) throw err; //create dim dependency OdDbObjectId dimDepBodyId, dimDepId; if ((err = OdDbAssocDimDependencyBody::createAndPostToDatabase(dimId, dimDepId, dimDepBodyId)) != eOk) throw err; const bool bPreviousValue = OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(false); Od3PointAngleConstraint* ppNewAngConstraint = NULL; if ((err = create3PointAngleConstraint(varDepId, dimDepId, pConsGeoms[0], vertex1, pConsGeoms[1], vertex2, pConsGeoms[2], vertex3, sectorType, pDatabase, spaceId, &ppNewAngConstraint)) != eOk) { throw err; } OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(bPreviousValue); return err; } catch (OdResult err) { if (err != eOk) { doCleanUp(cleanupObjectIds); } return err; } } static OdResult createRadialDim(const OdGePoint3d& centerPt, const OdGePoint3d& chordPt, double leaderLength, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimCenter(centerPt); OdGePoint3d dimChord(chordPt); OdDbRadialDimensionPtr dim = OdDbRadialDimension::createObject(); dim->setCenter(dimCenter.transformBy(ucsMatrixInv)); dim->setChordPoint(dimChord.transformBy(ucsMatrixInv)); dim->setLeaderLength(leaderLength); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } OdResult es; if ((es = postToDatabase(dim, pDb, spaceId)) == eOk) { dimId = dim->objectId(); } return es; } static OdResult createDiametricDim(const OdGePoint3d& chordPt, const OdGePoint3d& farChordPt, const OdGePoint3d& dimPos, const double leaderLength, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimChord(chordPt); OdGePoint3d dimFarChord(farChordPt); OdGePoint3d dimTxt(dimPos); OdDbDiametricDimensionPtr dim = OdDbDiametricDimension::createObject(); dim->setChordPoint(dimChord.transformBy(ucsMatrixInv)); dim->setFarChordPoint(dimFarChord.transformBy(ucsMatrixInv)); dim->setLeaderLength(leaderLength); dim->useSetTextPosition(); dim->setTextPosition(dimTxt.transformBy(ucsMatrixInv)); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } OdResult es; if ((es = postToDatabase(dim, pDb, spaceId)) == eOk) { dimId = dim->objectId(); } return es; } static OdResult createRadiusDiameterConstraint(const OdDbObjectId& varDepId, const OdDbObjectId& dimDepId, OdConstrainedGeometry*& pConsGeom, OdRadiusDiameterConstraint::RadiusDiameterConstrType constrType, OdDbDatabase* pDb, const OdDbObjectId& spaceId, OdRadiusDiameterConstraint** ppNewRadDiaConstraint) { OdResult es; OdDbObjectId consGrpId = DWGConstraintUtils::getConstraintGroup(spaceId, true); if (consGrpId.isNull()) return eNullObjectId; OdDbAssoc2dConstraintGroupPtr p2dConstrGrp = consGrpId.safeOpenObject(OdDb::kForWrite); if (p2dConstrGrp.isNull()) return eInvalidInput; if (!pConsGeom->isKindOf(OdConstrainedCircle::desc())) return eInvalidInput; if ((es = p2dConstrGrp->addRadiusDiameterConstraint(pConsGeom, constrType, varDepId, dimDepId, ppNewRadDiaConstraint)) != eOk) return es; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromDatabase(pDb, true, ASSOCNETWORK_DICTIONARYKEY); OdDbAssocNetworkPtr pNetwork = networkId.safeOpenObject(OdDb::kForWrite); DWGConstraintUtils::DwgConstraintEvaluationCallback tmpCallback; tmpCallback._allowOverconstrain = false; pNetwork->evaluate(&tmpCallback); return es; } OdResult createRadialOrDiamDimConstraintPrivate(OdDbDatabase* pDatabase, const OdDbObjectId& entId, const OdGePoint3d& entPt, const OdGePoint3d& dimPos, bool isRadial, OdDbObjectId& varDimId, OdDbDimensionPtr dimAssoc = OdDbDimensionPtr()) { varDimId = OdDbObjectId::kNull; OdDbObjectIdArray cleanupObjectIds; try { OdResult err = eOk; OdDbFullSubentPathArray aPathsEdge; OdDbFullSubentPath edgeEntPath; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId, entPt, edgeEntPath)) != eOk) throw err; aPathsEdge.append(edgeEntPath); std::unique_ptr segment(DWGConstraintUtils::getCurveForEdgeSubentity(entId, edgeEntPath)); if (!(segment->type() == OdGe::kCircArc3d)) { throw eInvalidInput; } OdGeCircArc3d* arc = static_cast(segment.get()); OdGePoint3d center = arc->center(); OdGeVector3d dir = dimPos - center; if (dir.length() > 0.001) dir = dir * (arc->radius() / dir.length()); OdGePoint3d chordPt = center + dir; double leaderLength = chordPt.distanceTo(dimPos); OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); OdDbAssocConstraintType constrTypeForName; OdRadiusDiameterConstraint::RadiusDiameterConstrType constrType; OdDbObjectId dimId = OdDbObjectId::kNull; double dimValue = arc->radius(); if (dimAssoc.isNull()) { OdDbObjectId dimStyleId = OdDbObjectId::kNull; if (isRadial) { err = createRadialDim(center, chordPt, leaderLength, dimId, dimStyleId, pDatabase, spaceId); constrTypeForName = OdDbAssocConstraintType::kRadiusAssocConstraintType; constrType = OdRadiusDiameterConstraint::RadiusDiameterConstrType::kCircleRadius; } else { dimValue *= 2.; const OdGePoint3d farChordPt = center - dir; err = createDiametricDim(chordPt, farChordPt, dimPos, leaderLength, dimId, dimStyleId, pDatabase, spaceId); constrTypeForName = OdDbAssocConstraintType::kDiameterAssocConstraintType; constrType = OdRadiusDiameterConstraint::RadiusDiameterConstrType::kCircleDiameter; } if (err != eOk) throw err; cleanupObjectIds.append(dimId); } else { if (isRadial) { constrTypeForName = OdDbAssocConstraintType::kRadiusAssocConstraintType; constrType = OdRadiusDiameterConstraint::RadiusDiameterConstrType::kCircleRadius; } else { constrTypeForName = OdDbAssocConstraintType::kDiameterAssocConstraintType; constrType = OdRadiusDiameterConstraint::RadiusDiameterConstrType::kCircleDiameter; } dimId = dimAssoc->objectId(); } OdArray pConsGeoms; if ((err = DWGConstraintUtils::addConstrainedGeometry(pDatabase, aPathsEdge, pConsGeoms)) != eOk) throw err; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); OdString dimName; OdString dimExpression; if ((err = getNameAndExpressionFromDimension(networkId, dimId, constrTypeForName, dimName, dimExpression)) != eOk) { throw err; } if ((err = addNewVariableToAssocNetwork(networkId, dimName, dimExpression, varDimId, dimValue)) != eOk) throw err; //As the variable didn't exist, we will need to clean it up if something goes wrong from here. cleanupObjectIds.append(varDimId); OdDbObjectId varDepId = OdDbObjectId::kNull; if ((err = addValueDependency(networkId, varDimId, varDepId)) != eOk) throw err; //create dim dependency OdDbObjectId dimDepBodyId, dimDepId; if ((err = OdDbAssocDimDependencyBody::createAndPostToDatabase(dimId, dimDepId, dimDepBodyId)) != eOk) throw err; const bool bPreviousValue = OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(false); OdRadiusDiameterConstraint* ppNewRadDiaConstraint = NULL; if ((err = createRadiusDiameterConstraint(varDepId, dimDepId, pConsGeoms[0], constrType, pDatabase, spaceId, &ppNewRadDiaConstraint)) != eOk) throw err; OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(bPreviousValue); return err; } catch (OdResult err) { if (err != eOk) { doCleanUp(cleanupObjectIds); } return err; } } static OdResult createRotatedDim(const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, double rotation, OdDbObjectId& dimId, const OdDbObjectId& dimStyleId, OdDbDatabase* pDb, const OdDbObjectId& spaceId) { OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeMatrix3d ucsMatrixInv(ucsMatrix.inverse()); OdGePoint3d dimPt1(entPt1); OdGePoint3d dimPt2(entPt2); OdGePoint3d dimTxt(dimPos); OdDbRotatedDimensionPtr dim = OdDbRotatedDimension::createObject(); dim->setRotation(rotation); dim->setXLine1Point(dimPt1.transformBy(ucsMatrixInv)); dim->setXLine2Point(dimPt2.transformBy(ucsMatrixInv)); dim->setDimLinePoint(dimTxt.transformBy(ucsMatrixInv)); dim->setDatabaseDefaults(pDb); dim->transformBy(ucsMatrix); if (dimStyleId != OdDbObjectId::kNull) { dim->setDimensionStyle(dimStyleId); } OdResult es; if ((es = postToDatabase(dim, pDb, spaceId)) == eOk) { dimId = dim->objectId(); } return es; } static OdResult createRotatedDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdGePoint3d& entPt1, const OdDbObjectId& entId2, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, double rotation, const OdGeVector3d& fixedDirection, OdDbObjectId& varDimId, OdDbRotatedDimensionPtr dimAssoc = OdDbRotatedDimensionPtr()) { varDimId = OdDbObjectId::kNull; OdDbObjectIdArray cleanupObjectIds; try { OdResult err = eOk; OdDbFullSubentPathArray aPathsEdge; OdDbFullSubentPathArray pathsRequiresMidPoint; bool addMidPoint = false; // Take the first edge OdDbFullSubentPath edgeEntPath1; OdGePoint3d vertex1; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId1, entPt1, edgeEntPath1, addMidPoint, NULL, NULL, NULL, NULL, NULL, &vertex1)) != eOk) throw err; aPathsEdge.append(edgeEntPath1); if (addMidPoint) pathsRequiresMidPoint.append(edgeEntPath1); // Take the second edge OdDbFullSubentPath edgeEntPath2; OdGePoint3d vertex2; if ((err = DWGConstraintUtils::getClosestEdgeSubEntPath(entId2, entPt2, edgeEntPath2, addMidPoint, NULL, NULL, NULL, NULL, NULL, &vertex2)) != eOk) throw err; aPathsEdge.append(edgeEntPath2); if (addMidPoint) pathsRequiresMidPoint.append(edgeEntPath2); OdGeLine3d line(OdGePoint3d(), fixedDirection); const double dimValue = line.closestPointTo(vertex1).distanceTo(line.closestPointTo(vertex2)); if (OdZero(dimValue)) { throw eInvalidInput; } OdArray pConsGeoms; if ((err = DWGConstraintUtils::addConstrainedGeometry(pDatabase, aPathsEdge, pathsRequiresMidPoint, pConsGeoms)) != eOk) throw err; OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); OdDbObjectId dimId = OdDbObjectId::kNull; if (dimAssoc.isNull()) { OdDbObjectId dimStyleId = OdDbObjectId::kNull; if ((err = createRotatedDim(vertex1, vertex2, dimPos, rotation, dimId, dimStyleId, pDatabase, spaceId)) != eOk) { throw err; } cleanupObjectIds.append(dimId); } else { dimId = dimAssoc->objectId(); } OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); OdString dimName; OdString dimExpression; if ((err = getNameAndExpressionFromDimension(networkId, dimId, OdDbAssocConstraintType::kDistanceAssocConstraintType, dimName, dimExpression)) != eOk) throw err; if ((err = addNewVariableToAssocNetwork(networkId, dimName, dimExpression, varDimId, dimValue)) != eOk) throw err; //As the variable didn't exist, we will need to clean it up if something goes wrong from here. cleanupObjectIds.append(varDimId); OdDbObjectId varDepId = OdDbObjectId::kNull; if ((err = addValueDependency(networkId, varDimId, varDepId)) != eOk) throw err; //create dim dependency OdDbObjectId dimDepBodyId, dimDepId; if ((err = OdDbAssocDimDependencyBody::createAndPostToDatabase(dimId, dimDepId, dimDepBodyId)) != eOk) throw err; const bool bPreviousValue = OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(false); OdGeMatrix3d ucsMatrix; DWGConstraintUtils::currentUCS(spaceId, NULL, &ucsMatrix); OdGeVector3d fixedDirectionUcs(fixedDirection); fixedDirectionUcs.transformBy(ucsMatrix); OdDistanceConstraint* ppNewDisConstraint = NULL; if ((err = createDistanceConstraint(varDepId, dimDepId, pConsGeoms[0], vertex1, pConsGeoms[1], vertex2, &fixedDirectionUcs, pDatabase, spaceId, &ppNewDisConstraint)) != eOk) { throw err; } OdDbAssocDimDependencyBodyBase::setEraseDimensionIfDependencyIsErased(bPreviousValue); return err; } catch (OdResult err) { if (err != eOk) { doCleanUp(cleanupObjectIds); } return err; } } OdResult createHorizontalOrVerticalDimConstraintPrivate(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, bool bVertical, OdDbObjectId& varDimId, OdDbRotatedDimensionPtr /*dimAssoc*/ = OdDbRotatedDimensionPtr()) { double rotation = bVertical ? OdaPI2 : 0.; OdGeVector3d fixedDirection = bVertical ? OdGeVector3d(0, 1, 0) : OdGeVector3d(1, 0, 0); return createRotatedDimConstraint(pDatabase, entId1, entPt1, entId2, entPt2, dimPos, rotation, fixedDirection, varDimId); } OdResult DwgConstraintCreation::createAlignedDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; return createAlignedDimConstraintPrivate(pDatabase, entId1, entId2, entPt1, entPt2, dimPos, varDimId); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::createHorizontalOrVerticalDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, bool bVertical, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; return createHorizontalOrVerticalDimConstraintPrivate(pDatabase, entId1, entId2, entPt1, entPt2, dimPos, bVertical, varDimId); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::create2LineAngularDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& dimPos, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; return create2LineAngularDimConstraintPrivate(pDatabase, entId1, entId2, entPt1, entPt2, dimPos, varDimId); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::create3PointAngularDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId1, const OdDbObjectId& entId2, const OdDbObjectId& entId3, const OdGePoint3d& entPt1, const OdGePoint3d& entPt2, const OdGePoint3d& entPt3, const OdGePoint3d& dimPos, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; return create3PointAngularDimConstraintPrivate(pDatabase, entId1, entId2, entId3, entPt1, entPt2, entPt3, dimPos, varDimId); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::createRadialOrDiamDimConstraint(OdDbDatabase* pDatabase, const OdDbObjectId& entId, const OdGePoint3d& entPt, const OdGePoint3d& dimPos, bool isRadial, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; return createRadialOrDiamDimConstraintPrivate(pDatabase, entId, entPt, dimPos, isRadial, varDimId); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } bool isDimAssoc(const OdDbObjectId& id) { return id.safeOpenObject()->isKindOf(OdDbDimAssoc::desc()); } OdResult findEntitiesConnectedToDimension(const OdDbDatabase* database, const OdDbDimensionPtr dimAssoc, OdDbObjectIdArray& entIds) { // Get the reactor id connected to dimension OdDbObjectIdArray reactorIds = dimAssoc->getPersistentReactors(); if (reactorIds.logicalLength() == 0) return eInvalidInput; OdDbDimAssocPtr reactorDimAssoc; for (OdDbObjectIdArray::value_type reactorId : reactorIds) { if( isDimAssoc(reactorId) ) { reactorDimAssoc = reactorId.safeOpenObject(); break; } } // Find entities connected to the same reactor OdDbBlockTablePtr blockTable = database->getBlockTableId().safeOpenObject(); OdDbBlockTableIteratorPtr tableItr; for (tableItr = blockTable->newIterator(); !tableItr->done(); tableItr->step()) { OdDbBlockTableRecordPtr record = tableItr->getRecord(); OdDbObjectIteratorPtr tableRecordItr; for (tableRecordItr = record->newIterator(); !tableRecordItr->done(); tableRecordItr->step()) { OdDbEntityPtr entity = tableRecordItr->entity(); if (entity->handle() == dimAssoc->handle()) continue; OdDbObjectId entityId = tableRecordItr->objectId(); OdDbObjectIdArray entityReactorIds = entity->getPersistentReactors(); OdDbDimAssocPtr reactorEntity; for (OdDbObjectIdArray::value_type reactorId : entityReactorIds) { if ( isDimAssoc(reactorId) ) { reactorEntity = reactorId.safeOpenObject(); if ( reactorEntity == reactorDimAssoc) { entIds.append(entityId); break; } } } } } return eOk; } OdResult convertAlignedDimensionToConstraint(OdDbDatabase* database, OdDbAlignedDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; OdGePoint3d pointFirst = dimAssoc->xLine1Point(); OdGePoint3d pointSecond = dimAssoc->xLine2Point(); double measurement = dimAssoc->measurement(); if (entityIds.logicalLength() == 2) { OdDbObjectId objIdFirst = DWGConstraintUtils::selectClosestEntity(pointFirst, entityIds[0], entityIds[1]); OdDbObjectId objIdSecond = DWGConstraintUtils::selectClosestEntity(pointSecond, entityIds[0], entityIds[1]); // Create dim constraint res = createAlignedDimConstraintPrivate(database, objIdFirst, objIdSecond, pointFirst, pointSecond, dimAssoc->textPosition(), varDimId, dimAssoc); } else if (entityIds.logicalLength() == 1) { // Create dim constraint res = createAlignedDimConstraintPrivate(database, entityIds[0], entityIds[0], pointFirst, pointSecond, dimAssoc->textPosition(), varDimId, dimAssoc); } else { ODA_FAIL_ONCE(); return eInvalidInput; } if (res != eOk) return res; if (varDimId.isNull() || !varDimId.isValid()) return eNullObjectId; OdDbAssocVariablePtr var = varDimId.safeOpenObject(OdDb::kForWrite); database->startTransaction(); OdDbEvalVariantPtr varValue = OdDbEvalVariant::init(measurement); var->setValue(*varValue); database->endTransaction(); OdDbAssocManager::evaluateTopLevelNetwork(database); return res; } OdResult convertRadialDimensionToConstraint(OdDbDatabase* database, OdDbRadialDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; ODA_ASSERT_ONCE(entityIds.logicalLength() > 0); OdGePoint3d point = dimAssoc->chordPoint(); // Create dim constraint return createRadialOrDiamDimConstraintPrivate(database, entityIds[0], point, dimAssoc->textPosition(), true, varDimId, dimAssoc); } OdResult convertDiametricDimensionToConstraint(OdDbDatabase* database, OdDbDiametricDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; ODA_ASSERT_ONCE(entityIds.logicalLength() > 0); OdGePoint3d point = dimAssoc->chordPoint(); // Create dim constraint return createRadialOrDiamDimConstraintPrivate(database, entityIds[0], point, dimAssoc->textPosition(), false, varDimId, dimAssoc); } OdResult convert2LineAngularDimensionToConstraint( OdDbDatabase* database, OdDb2LineAngularDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; ODA_ASSERT_ONCE(entityIds.logicalLength() > 0); // Dimension can be connected to two vertices of a single entity. In this case entityIds contains only one element. OdDbObjectId idFirst = entityIds[0]; OdDbObjectId idSecond = (entityIds.logicalLength() == 1) ? entityIds[0] : entityIds[1]; OdGePoint3d pointFirst = dimAssoc->arcPoint(); OdGePoint3d pointSecond = dimAssoc->arcPoint(); // Create dim constraint return create2LineAngularDimConstraintPrivate(database, idFirst, idSecond, pointFirst, pointSecond, dimAssoc->textPosition(), varDimId, dimAssoc); } OdResult convert3PointAngularDimensionToConstraint(OdDbDatabase* database, OdDb3PointAngularDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; ODA_ASSERT_ONCE(entityIds.logicalLength() > 0); // Dimension can be connected to three vertices of a single entity. In this case entityIds contains only one element. OdDbObjectId idFirst = entityIds[0]; OdDbObjectId idSecond = (entityIds.logicalLength() == 1 || entityIds.logicalLength() == 2) ? entityIds[0] : entityIds[1]; OdDbObjectId idThird; if(entityIds.logicalLength() == 1) idThird = entityIds[0]; else if (entityIds.logicalLength() == 2) idThird = entityIds[1]; else idThird = entityIds[2]; OdGePoint3d pointFirst = dimAssoc->centerPoint(); OdGePoint3d pointSecond = dimAssoc->xLine1Point(); OdGePoint3d pointThird = dimAssoc->xLine2Point(); // Create dim constraint return create3PointAngularDimConstraintPrivate(database, idFirst, idSecond, idThird, pointFirst, pointSecond, pointThird, dimAssoc->textPosition(), varDimId, dimAssoc); } OdResult convertRotatedDimensionToConstraint(OdDbDatabase* database, OdDbRotatedDimensionPtr dimAssoc, OdDbObjectId& varDimId) { OdResult res = eOk; // Find entities which connected to dimension OdDbObjectIdArray entityIds; if ((res = findEntitiesConnectedToDimension(database, dimAssoc, entityIds)) != eOk) return res; ODA_ASSERT_ONCE(entityIds.logicalLength() > 0); // Dimension can be connected to two vertices of a single entity. In this case entityIds contains only one element. OdDbObjectId idFirst = entityIds[0]; OdDbObjectId idSecond = (entityIds.logicalLength() == 1) ? entityIds[0] : entityIds[1]; bool horizontal = !OdEqual(dimAssoc->horizontalRotation(), 0); OdGePoint3d pointFirst = dimAssoc->xLine1Point(); OdGePoint3d pointSecond = dimAssoc->xLine2Point(); // Create dim constraint return createHorizontalOrVerticalDimConstraintPrivate(database, idFirst, idSecond, pointFirst, pointSecond, dimAssoc->textPosition(), !horizontal, varDimId, dimAssoc); } OdResult DwgConstraintCreation::convertAssocDimensionToConstraint(OdDbDatabase* database, OdDbObjectId& dimAssocId, OdDbObjectId& varDimId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; OdDbEntityPtr entity = dimAssocId.openObject(OdDb::kForWrite); if (entity->isKindOf(OdDbAlignedDimension::desc())) return convertAlignedDimensionToConstraint(database, entity, varDimId); else if (entity->isKindOf(OdDbRadialDimension::desc())) return convertRadialDimensionToConstraint(database, entity, varDimId); else if (entity->isKindOf(OdDbDiametricDimension::desc())) return convertDiametricDimensionToConstraint(database, entity, varDimId); else if (entity->isKindOf(OdDb2LineAngularDimension::desc())) return convert2LineAngularDimensionToConstraint(database, entity, varDimId); else if (entity->isKindOf(OdDb3PointAngularDimension::desc())) return convert3PointAngularDimensionToConstraint(database, entity, varDimId); else if (entity->isKindOf(OdDbRotatedDimension::desc())) return convertRotatedDimensionToConstraint(database, entity, varDimId); return eInvalidInput; } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::listParameters(const OdDbDatabase* pDatabase, OdDbObjectIdArray& paramIds) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); if (spaceId.isNull()) return eInvalidInput; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, false); if (networkId.isNull()) return eNullHandle; OdDbAssocNetworkPtr network = networkId.safeOpenObject(); if (network.isNull()) return eNullHandle; OdDbObjectIdArray actions = network->getActions(); paramIds.reserve(actions.size()); for (const OdDbObjectIdArray::value_type& action : actions) { if (!action.isNull() && action.objectClass() == OdDbAssocVariable::desc()) paramIds.append(action); } return eOk; } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::createUserParameter(const OdDbDatabase* pDatabase, OdDbObjectId& paramId, const OdString& name, const OdString& expression, double value) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; paramId = OdDbObjectId::kNull; OdDbObjectId spaceId = DWGConstraintUtils::currentSpaceId(pDatabase); if (spaceId.isNull()) return eInvalidInput; OdDbObjectId networkId = OdDbAssocNetwork::getInstanceFromObject(spaceId, true); if (spaceId.isNull()) return eNullHandle; if ((addNewVariableToAssocNetwork(networkId, name, expression, paramId, value)) != eOk) return eNullHandle; return eOk; } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::deleteParameter(const OdDbDatabase* /*pDatabase*/, const OdDbObjectId& paramId, bool autoDereference) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; OdDbObjectIdArray dependentIds; OdResult res = eOk; if ((res = listReferencedParameters(paramId, dependentIds)) != eOk) return res; if (dependentIds.logicalLength() > 0) { if (autoDereference) { for (const OdDbObjectId& refId : dependentIds) dereferenceParameter(refId, paramId); } else { return eInvalidInput; } } OdDbAssocVariablePtr var = paramId.safeOpenObject(OdDb::kForWrite); return var->erase(); } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::listReferencedParameters(const OdDbObjectId& paramId, OdDbObjectIdArray& referenceParamIds) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; OdResult res = eOk; OdDbObjectIdArray allVariableIds; DwgConstraintCreation dwgConstraints; OdDbAssocVariablePtr variable = paramId.safeOpenObject(); if ((res = dwgConstraints.listParameters(variable->database(), allVariableIds)) != eOk) return res; for (const OdDbObjectId& varId : allVariableIds) { OdDbAssocVariablePtr var = varId.safeOpenObject(); if (var == variable) continue; OdDbObjectIdArray dependencyIds; if ((res = var->getDependencies(true, true, dependencyIds)) != eOk) break; for (const OdDbObjectId& dependencyId : dependencyIds) { OdDbAssocValueDependencyPtr dependency = dependencyId.safeOpenObject(); OdDbAssocVariablePtr dependencyVar = dependency->dependentOnObject().safeOpenObject(); if (dependencyVar == variable) referenceParamIds.append(varId); } } return res; } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } } OdResult DwgConstraintCreation::dereferenceParameter(const OdDbObjectId& modifiedParamId, const OdDbObjectId& referencedParamId) ODRX_NOEXCEPT { try { if (!DWGConstraintUtils::moduleIsLoaded()) return eNotApplicable; if (modifiedParamId.objectClass() != OdDbAssocVariable::desc() || referencedParamId.objectClass() != OdDbAssocVariable::desc()) return eInvalidInput; OdDbAssocVariablePtr modifiedVar = modifiedParamId.safeOpenObject(OdDb::kForWrite); OdDbAssocVariablePtr referencedVar = referencedParamId.safeOpenObject(); std::wstring referencedVarName = referencedVar->name().c_str(); std::wstring referencedVarValue = std::to_wstring(referencedVar->value()->getAsDouble()); std::size_t referencedVarNameLen = referencedVarName.length(); std::wstring expression = modifiedVar->expression().c_str(); // Replace all occurrence of referencedVarName with referencedVarValue std::size_t startIndex = 0; while ((startIndex = expression.find(referencedVarName, startIndex)) != -1) { bool isWholeName = true; if (startIndex > 0) { wchar_t symBefore = expression[startIndex - 1]; if (std::iswalnum(symBefore) || symBefore == '_') isWholeName = false; } std::size_t endIndex = startIndex + referencedVarNameLen; if (endIndex < expression.length()) { wchar_t symAfter = expression[endIndex]; if (std::iswalnum(symAfter) || symAfter == '_') isWholeName = false; } if (isWholeName) expression.replace(startIndex, referencedVarNameLen, referencedVarValue); startIndex += endIndex; } OdString evaluatorId = modifiedVar->evaluatorId(); modifiedVar->setExpression(expression.c_str(), evaluatorId, true, true); return eOk; } catch (const OdError& e) { return e.code(); } catch (...) { return eNotApplicable; } }