/////////////////////////////////////////////////////////////////////////////// // 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 #include "DbAssocNetwork.h" #include "DbAssoc2dConstraintGroup.h" #include "OdImplicitConstr.h" #include "OdExplicitConstr.h" #include "DWGAssocActionPE.h" #include "DWGCommands.h" #include "DbCommandContext.h" #include "DbUserIO.h" #include "CsConstraint.h" #include "CsMoveUnderConstraints.h" #include "../Source/CsValidator.h" #include "CsEqualCurveProperty.h" #include "../Source/CsFlowNetwork.h" #include "CsOverDefinedChecker.h" #include "DbEvalGraph.h" #include "DWGCommandsUtils.h" #include "Ge/GeCircArc2d.h" #include "Ge/GeEllipArc2d.h" #include "Ge/GePlane.h" #include "DbCircle.h" #include "DbEllipse.h" #include "DWGAssocActionUtils.h" ODRX_NO_CONS_DEFINE_MEMBERS_ALTNAME(DWGAssocActionPE, AssocActionPE, OD_T("DWGAssocActionPE")); void DWGConstraintsTrace(const OdString& iMsg) { (void)iMsg; #ifdef _DEBUG //if (gpCmdCtx) // gpCmdCtx->userIO()->putString(iMsg); std::cout << (const char*)iMsg << std::endl; #endif } //void DWGConstraintsTrace_ConstraintGroup(OdDbAssoc2dConstraintGroup* const pCnGr) //{ //#ifdef _DEBUG // OdArray aConstGeom; // pCnGr->getConstrainedGeometries(aConstGeom); // for (OdConstrainedGeometry* constrainedGeometry : aConstGeom) // { // std::cout << (const char*)constrainedGeometry->isA()->name() << ":0x" << std::hex << constrainedGeometry->nodeId() << std::endl; // } // // OdArray apConstraints; // pCnGr->getConstraints(apConstraints); // for(OdGeomConstraint* constraint : apConstraints) // { // std::cout << (const char*)constraint->isA()->name() << ":0x" << std::hex << constraint->nodeId() << ":"; // OdArray connectedGeometries;; // constraint->getConnectedGeometries(connectedGeometries); // for (OdConstrainedGeometry* connectedGeometry : connectedGeometries) // std::cout << "0x" << std::hex << connectedGeometry->nodeId() << ", "; // // std::cout << std::endl; // } //#endif // _DEBUG //} const double DEFAULT_ANGULAR_TOLERANCE = 1e-9; // like in OdConstraintSolver DWGAssocActionPE::DWGAssocActionPE() //: _indexAuxiliaryConstraint(-1) { } void DWGAssocActionPE::CreateContext() { DestroyContext(_ctx); } void DWGAssocActionPE::DestroyContext(OdCsConstraintSystem& iContext) { iContext.geometries().clear(); iContext.constraints().clear(); iContext.variables().clear(); _aIds.clear(); _aIdsConstraint.clear(); _auxiliaryConstraintHelper.reset(); _mapCoincidense.clear(); } void DWGAssocActionPE::evaluate(OdDbAssocAction *action) { if ( action->isKindOf(OdDbAssoc2dConstraintGroup::desc()) ) { ProcessAssoc2dConstraintGroup(OdDbAssoc2dConstraintGroup::cast(action)); return; } OdDbAssocNetworkPtr pGlobalNet = OdDbAssocNetwork::cast(action); if (pGlobalNet.isNull()) return; ProcessActions(pGlobalNet->getActions()); } void DWGAssocActionPE::ProcessActions(OdDbObjectIdArray iaActionIds) { for (unsigned int i = 0; i < iaActionIds.length(); i++) { OdDbObjectId id = iaActionIds[i]; OdDbObjectPtr pObj = id.openObject(OdDb::kForWrite); if (OdDbAssocNetwork * pNet = OdDbAssocNetwork::cast(pObj)) { ProcessActions(pNet->getActions()); pNet->setStatus(kIsUpToDateAssocStatus, false, true); } else if (OdDbAssoc2dConstraintGroup * pConstraintGroup = OdDbAssoc2dConstraintGroup::cast(pObj)) { ProcessAssoc2dConstraintGroup(pConstraintGroup); pConstraintGroup->setStatus(kIsUpToDateAssocStatus, false, true); } } } void DWGAssocActionPE::ProcessAssoc2dConstraintGroup(OdDbAssoc2dConstraintGroup *pCnGr) { CreateContext(); OdConstrainedGeometryPtrArray aConstrainedGeom; OdConstrainedGeometryPtrArray aPoint; getModifiedGeometries(pCnGr, aConstrainedGeom, aPoint); // TODO: when rigid set MUC is supported at solver side, filter out curves from sets and MUC sets directly if (aConstrainedGeom.logicalLength() > 1) { std::set setRS; for (unsigned int i = 0; i < aConstrainedGeom.logicalLength(); ++i) { const OdConstrainedRigidSet* pRS = aConstrainedGeom[i]->getOwningRigidSet(); if (!pRS) { continue; } if (setRS.find(pRS) == setRS.end()) { setRS.insert(pRS); } else { aConstrainedGeom.removeAt(i); --i; } } } const unsigned int nCurves = aConstrainedGeom.length(), nPoints = aPoint.length(); SolverTransfTyper commonTf; OdArray aTransforTyperPoints; { aTransforTyperPoints.reserve(nPoints); for (unsigned int i = 0; i < nPoints; ++i) { aTransforTyperPoints.push_back(getTransformation(aPoint[i])); } } OdArray aTransforTyper; if ( nCurves != 0 ) { aTransforTyper.resize(nCurves); SolverTransfTyper* ptrTf = aTransforTyper.asArrayPtr(); for (unsigned int i = 0; i < nCurves; ++i) { *ptrTf++ = getTransformation(aConstrainedGeom[i]); } commonTf = getCommonTransformation(aConstrainedGeom, aTransforTyper); if ( commonTf.isSimpleTypeTransformation() ) { for (unsigned int i = 0; i < nPoints; i++) { if (!isFitTransformation(aPoint[i], commonTf)) { commonTf.setType(commonTf.TransTypeComposite); break; } } } } else { if (nPoints == 0) { if (CreateContextAndApplyChanges(pCnGr)) return; else throw OdError(eInvalidInput); //set not resolved flag return; } commonTf = getCommonTransformation(aPoint, aTransforTyperPoints); } if (commonTf.isSimpleTypeTransformation()) DWGConstraintsTrace("--> Common transformation is simple"); else DWGConstraintsTrace("--> Common transformation is complex"); // grip edit? if (aConstrainedGeom.length() == 1 && aPoint.length() == 0) // object specific transform { OdConstrainedImplicitPoint* movePt; OdGePoint2d movePtCordinate; if (checkMoveVertex(aConstrainedGeom[0], movePt, movePtCordinate)) { InfoMUC infoMUC; infoMUC._geomMUC = aConstrainedGeom[0]; if (aTransforTyper[0].getType() == SolverTransfTyper::TransTypeRotate) { infoMUC._ptMoveCoordinate = aTransforTyper[0].m_center.convert2d(); } else { if (movePt != nullptr) { infoMUC._ptMove = movePt; } else { infoMUC._ptMoveCoordinate = movePtCordinate; } } CreateOriginalSolverModel(pCnGr, &infoMUC); OdCsMoveUnderConstraintsOptions options; bool res = ::tryMoveVertex(this, options, aConstrainedGeom[0]); ODA_VERIFY_ONCE(res); OdConstraintSolver solver(_ctx); OdConstraintSolver::Result modRes = _auxiliaryConstraintHelper.solveWithAuxConstraints(_ctx, &options); if (modRes != OdConstraintSolver::NotSolved && modRes != OdConstraintSolver::NotSolvedInput) { UpdateFromSolver(pCnGr); DestroyContext(_ctx); } else //if (modRes == OdConstraintSolver::NotSolved || modRes == OdConstraintSolver::NotSolvedInput) { RestoreOriginalGeom(aPoint); RestoreOriginalGeom(aConstrainedGeom); } return; } } //if (commonTf.isSimpleTypeTransformation()) //original geom set { InfoMUC infoMUC; if (nCurves > 0) { infoMUC._geomMUC = aConstrainedGeom[0]; if (aTransforTyper[0].getType() == SolverTransfTyper::TransTypeRotate) { infoMUC._ptMoveCoordinate = aTransforTyper[0].m_center.convert2d(); } } CreateOriginalSolverModel(pCnGr, &infoMUC); OdCsMoveUnderConstraintsOptions options; // curves for (unsigned int i = 0; i < nCurves; ++i) { OdConstrainedGeometry* pGeom = aConstrainedGeom[i]; if (aTransforTyper[i].isSimpleTypeTransformation()) { const OdGeMatrix3d& trans = aTransforTyper[i].m_matr; OdGeMatrix2d csTrans; convertMatrixGe2Cs(trans, csTrans); DWGConstraintUtils::ImplicitPointArray aImplicitPoint; DWGConstraintUtils::getImplicitPoints(pGeom, aImplicitPoint); const bool isConstrainedEllipse = pGeom->isKindOf(OdConstrainedEllipse::desc()) && !pGeom->isKindOf(OdConstrainedBoundedEllipse::desc()); const bool isConstrainedSpline = pGeom->isKindOf(OdConstrainedSpline::desc()); const bool isCircleArc = pGeom->isKindOf(OdConstrainedArc::desc()); OdGroupNodeIdArray aNodeId; if (!aImplicitPoint.isEmpty() && !isConstrainedEllipse && !isConstrainedSpline) { for (OdConstrainedImplicitPoint* pt : aImplicitPoint) { OdGePoint3d ptTrans = pt->getOriginalPoint(); ptTrans.transformBy(trans); if (pt->getOriginalPoint().isEqualTo(ptTrans)) { continue; } OdCsGeometryPtr pCsGeom = FindSolverObject(pt->nodeId()); options.transform(pCsGeom, csTrans); } } else { OdCsGeometryPtr pCsGeom = FindSolverObject(pGeom->nodeId()); options.transform(pCsGeom, csTrans); } if (pGeom->isKindOf(OdConstrainedEllipse::desc())) { const OdConstrainedEllipse* pArc = OdConstrainedEllipse::cast(pGeom); OdGeEllipArc3d arc = pArc->getOdGeEllipArc3d(); const double majorRadius = arc.majorRadius(); const double minorRadius = arc.minorRadius(); OdCsGeometryPtr pCsEllipse = FindSolverObject(pGeom->nodeId()); _auxiliaryConstraintHelper.addAuxiliaryConstraint(OdCsRadiusFixation::create(pCsEllipse, majorRadius, OdCsConstraint::MajorRadius)); _auxiliaryConstraintHelper.addAuxiliaryConstraint(OdCsRadiusFixation::create(pCsEllipse, minorRadius, OdCsConstraint::MinorRadius)); } else if (pGeom->isKindOf(OdConstrainedCircle::desc())) { const OdConstrainedCircle* pArc = OdConstrainedCircle::cast(pGeom); OdGeCircArc3d arc = pArc->getOdGeCircArc3d(); const double r = arc.radius(); OdCsGeometryPtr pCs = FindSolverObject(pGeom->nodeId()); _auxiliaryConstraintHelper.addAuxiliaryConstraint(OdCsRadiusFixation::create(pCs, r, OdCsConstraint::CircleRadius)); } if (isCircleArc) { bool needToFixateCenter = std::any_of(aImplicitPoint.begin(), aImplicitPoint.end(), [](OdConstrainedImplicitPoint* pt) -> bool { return pt->pointType() != OdConstrainedImplicitPoint::kCenterImplicit && isImplicitPointFixated(pt); }); for (OdConstrainedImplicitPoint* pt : aImplicitPoint) { if (aTransforTyper[i].getType() == SolverTransfTyper::TransTypeRotate && pt->pointType() == OdConstrainedImplicitPoint::kCenterImplicit && needToFixateCenter) { OdCsGeometryPtr pCsCentrPt = FindSolverObject(pt->nodeId()); _ctx.constraints().append(OdCsFixation::create(pCsCentrPt)); continue; } OdGePoint3d ptTrans = pt->getOriginalPoint(); ptTrans.transformBy(trans); if (pt->getOriginalPoint().isEqualTo(ptTrans)) { continue; } OdCsGeometryPtr pCsGeom = FindSolverObject(pt->nodeId()); options.transform(pCsGeom, csTrans); } } } else // complex transformation { bool res = complicatedMoveVertex(this, options, pGeom); ODA_VERIFY_ONCE(res); } } // points for (unsigned int i = 0; i < nPoints; ++i) { OdConstrainedGeometry* pPt = aPoint[i]; const OdGeMatrix3d& trans = aTransforTyperPoints[i].m_matr; OdGeMatrix2d csTrans; convertMatrixGe2Cs(trans, csTrans); OdCsGeometryPtr pCsGeom = FindSolverObject(pPt->nodeId()); options.transform(pCsGeom, csTrans); } OdConstraintSolver solver(_ctx); OdConstraintSolver::Result modRes = _auxiliaryConstraintHelper.solveWithAuxConstraints(_ctx, &options); if (modRes != OdConstraintSolver::NotSolved && modRes != OdConstraintSolver::NotSolvedInput) { UpdateFromSolver(pCnGr); DestroyContext(_ctx); } else //if (modRes == OdConstraintSolver::NotSolved || modRes == OdConstraintSolver::NotSolvedInput) { RestoreOriginalGeom(aPoint); RestoreOriginalGeom(aConstrainedGeom); } } } bool DWGAssocActionPE::CreateContextAndApplyChanges(OdDbAssoc2dConstraintGroup * ipConstraintGroup) { DWGConstraintsTrace("--> CreateContextAndApplyChanges is called"); CreateSolverModel(ipConstraintGroup); OdConstraintSolver solver(_ctx); OdConstraintSolver::Result modRes = _auxiliaryConstraintHelper.solveWithAuxConstraints(_ctx); if (modRes != OdConstraintSolver::NotSolved && modRes != OdConstraintSolver::NotSolvedInput) { if( modRes != OdConstraintSolver::AlreadySolved ) // No need updating if entities already in proper positions UpdateFromSolver(ipConstraintGroup); DestroyContext(_ctx); return true; } DestroyContext(_ctx); return false; } static void createSplineExplicitPoints(DWGAssocActionPE* pPE, const OdConstrainedSpline* pSpline, const OdCsSplinePtr& csSpline) { OdArray apImplicitPoints; pSpline->getConstrainedImplicitPoints(apImplicitPoints); const OdVector& apControlPoints = csSpline->controlPoints(); ODA_ASSERT_ONCE(apImplicitPoints.logicalLength() <= apControlPoints.logicalLength()); for (OdConstrainedImplicitPoint* implicitPoint : apImplicitPoints) { if (implicitPoint->pointType() != OdConstrainedImplicitPoint::kDefineImplicit) { continue; } const int iCP = implicitPoint->pointIndex(); ODA_ASSERT_ONCE(implicitPoint->getOriginalPoint().convert2d().isEqualTo(apControlPoints[iCP]->position())); #ifdef _DEBUG // can the point appear prior to curve? OdCsGeometryPtr pt = pPE->FindSolverObject(implicitPoint->nodeId()); ODA_ASSERT_ONCE(pt == NULL); #endif DWGAssocActionPE::Solver2DRX idsCP; idsCP._solverId = apControlPoints[iCP]; idsCP._drxId = implicitPoint->nodeId(); pPE->_ctx.geometries().append(idsCP._solverId); pPE->_aIds.append(idsCP); } // CORE-20142 add extra implicit points if ( apImplicitPoints.logicalLength() < apControlPoints.logicalLength() ) { for (unsigned int i = apImplicitPoints.logicalLength(); i < apControlPoints.logicalLength(); i++) { pPE->_ctx.geometries().append(apControlPoints[i]); } } } void DWGAssocActionPE::CreateOriginalSolverModel(OdDbAssoc2dConstraintGroup * ipConstraintGroup, InfoMUC* infoMUC /*= NULL*/) { DWGConstraintsTrace("--> CreateOriginalSolverModel is called"); if (ipConstraintGroup == NULL) return; //create geometries OdArray aConstGeom; OdConstrainedRigidSetArray aRigidSet; ipConstraintGroup->getConstrainedGeometries(aConstGeom); bool alreadyExistObj; for (unsigned int i = 0; i < aConstGeom.length(); i++) { alreadyExistObj = false; DWGAssocActionPE::Solver2DRX ids; OdConstrainedGeometry* pGeom = aConstGeom[i]; ids._drxId = pGeom->nodeId(); if (OdConstrainedLine * pLine = OdConstrainedLine::cast(pGeom)) ids._solverId = CreateOriginalSolverLine(pLine); else if (OdConstrainedCircle* pCircle = OdConstrainedCircle::cast(pGeom)) ids._solverId = CreateOriginalSolverCircle(pCircle); else if (OdConstrainedEllipse * pEllipse = OdConstrainedEllipse::cast(pGeom)) ids._solverId = CreateOriginalSolverEllipse(pEllipse); else if (OdConstrainedSpline* pSpline = OdConstrainedSpline::cast(pGeom)) { ids._solverId = CreateSolverSpline(pSpline, true); const OdCsSplinePtr csSpline = ids._solverId.dynamicCast(); createSplineExplicitPoints(this, pSpline, csSpline); } else if (OdConstrainedPoint* pPoint = OdConstrainedPoint::cast(pGeom)) { ids._solverId = CreateSolverPoint(pPoint, alreadyExistObj, true); } else if ( OdConstrainedRigidSet * pRigidSet = OdConstrainedRigidSet::cast(pGeom) ) { aRigidSet.push_back(pRigidSet); continue; } else continue; if (!alreadyExistObj && ids._solverId != NULL) { if (infoMUC) { if (pGeom == infoMUC->_geomMUC) { infoMUC->_geomCs = ids._solverId.get(); } else if (pGeom == infoMUC->_ptMove) { //infoMUC->_ptCS = ids._solverId.dynamicCast(); infoMUC->_ptMoveCoordinate = ids._solverId.dynamicCast()->position(); } } _ctx.geometries().append(ids._solverId); _aIds.append(ids); } } CreateSolverRigidSets(aRigidSet, true); CreateSolverConstraints(ipConstraintGroup, true, infoMUC); } void DWGAssocActionPE::CreateSolverModel(OdDbAssoc2dConstraintGroup * ipConstraintGroup) { DWGConstraintsTrace("--> CreateSolverModel is called"); if (ipConstraintGroup == NULL) return; //create geometries OdArray aConstGeom; OdConstrainedRigidSetArray aRigidSet; ipConstraintGroup->getConstrainedGeometries(aConstGeom); bool alreadyExistObj; unsigned int i; for (i = 0; i < aConstGeom.length(); i++) { alreadyExistObj = false; Solver2DRX ids; OdConstrainedGeometry* pGeom = aConstGeom[i]; ids._drxId = pGeom->nodeId(); if (OdConstrainedLine * pLine = OdConstrainedLine::cast(pGeom)) if ( pGeom->isReadOnly() ) ids._solverId = CreateOriginalSolverLine(pLine); else ids._solverId = CreateSolverLine(pLine); else if (OdConstrainedCircle* pCircle = OdConstrainedCircle::cast(pGeom)) if ( pGeom->isReadOnly() ) ids._solverId = CreateOriginalSolverCircle(pCircle); else ids._solverId = CreateSolverCircle(pCircle); else if (OdConstrainedEllipse * pEllipse = OdConstrainedEllipse::cast(pGeom)) if ( pGeom->isReadOnly() ) ids._solverId = CreateOriginalSolverEllipse(pEllipse); else ids._solverId = CreateSolverEllipse(pEllipse); else if (OdConstrainedPoint* pPoint = OdConstrainedPoint::cast(pGeom)) { ids._solverId = CreateSolverPoint(pPoint, alreadyExistObj, pGeom->isReadOnly()); } else if (OdConstrainedSpline* pSpline = OdConstrainedSpline::cast(pGeom)) { ids._solverId = CreateSolverSpline(pSpline, pGeom->isReadOnly()); const OdCsSplinePtr csSpline = ids._solverId.dynamicCast(); createSplineExplicitPoints(this, pSpline, csSpline); } else if ( OdConstrainedRigidSet * pRigidSet = OdConstrainedRigidSet::cast(pGeom) ) { aRigidSet.push_back(pRigidSet); continue; } else continue; if (!alreadyExistObj && ids._solverId != NULL) { _ctx.geometries().append(ids._solverId); _aIds.append(ids); } } CreateSolverRigidSets(aRigidSet, false); CreateSolverConstraints(ipConstraintGroup, false); } void DWGAssocActionPE::CreateSolverConstraints(OdDbAssoc2dConstraintGroup * ipConstraintGroup, bool original, InfoMUC* infoMUC /*= NULL*/) { _auxiliaryConstraintHelper.reset(); OdArray apConstraints; ipConstraintGroup->getConstraints(apConstraints); for (unsigned int i = 0; i < apConstraints.length(); i++) { CreateSolverConstraint(apConstraints[i], original, infoMUC); } OdDbAssocEvaluationCallback* callback = ipConstraintGroup->currentEvaluationCallback(); if (callback) { OdDbEvalContext* context = callback->getAdditionalData(); if (context) { OdString key = OD_T("AllowOverconstrain"); OdDbEvalContextPair pair(key, NULL); if (context->getAt(pair)) { _auxiliaryConstraintHelper._allowOverconstrain = *static_cast(pair.value()); } key = OD_T("TempFixedConsGeoms"); pair = OdDbEvalContextPair(key, NULL); if (context->getAt(pair)) { OdGroupNodeIdArray* fixedGeom = static_cast(pair.value()); for (unsigned int i = 0; i < fixedGeom->logicalLength(); ++i) { OdConstraintGroupNodeId& fixedId = fixedGeom->at(i); OdCsGeometryPtr geom = FindSolverObject(fixedId); OdCsConstraintPtr fixation = OdCsFixation::create(geom); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixation); } } key = OD_T("TempFixedRadius"); pair = OdDbEvalContextPair(key, NULL); if (context->getAt(pair)) { OdArray* fixedGeom = static_cast*>(pair.value()); for (unsigned int i = 0; i < fixedGeom->logicalLength(); ++i) { DWGConstraintUtils::ArcFixation& fixedId = fixedGeom->at(i); OdCsGeometryPtr geom = FindSolverObject(fixedId.arc); OdCs::OdCsType geomType = geom->type(); if (geomType == OdCs::kCircle) { OdCsCirclePtr circle = geom.dynamicCast(); OdCsConstraintPtr fixation = OdCsRadiusFixation::create(geom, circle->radius(), OdCsConstraint::CircleRadius); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixation); } else if (geomType == OdCs::kEllipse) { OdCsEllipsePtr ellipse = geom.dynamicCast(); OdCsConstraintPtr fixationMinor = OdCsRadiusFixation::create(geom, ellipse->minorRadius(), OdCsConstraint::MinorRadius); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixationMinor); OdCsConstraintPtr fixationMajor = OdCsRadiusFixation::create(geom, ellipse->majorRadius(), OdCsConstraint::MajorRadius); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixationMajor); // fix ellipse axis direction OdCsLinePtr axisOX = OdCsLine::create(ellipse->center(), OdGeVector2d(1., 0.)); _ctx.geometries().append(axisOX); OdCsConstraintPtr fixationOX = OdCsFixation::create(axisOX); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixationOX); double angle = ellipse->direction().angleToCCW(axisOX->direction()); OdCsAnglePtr angleConstraint = OdCsAngle::create(ellipse, axisOX, angle); _auxiliaryConstraintHelper.addAuxiliaryConstraint(angleConstraint); } else if (geomType == OdCs::kPoint) { ; } else { ODA_ASSERT_ONCE(0); } } } key = OD_T("TempFixedAngle"); pair = OdDbEvalContextPair(key, NULL); if (context->getAt(pair)) { OdArray* fixedGeom = static_cast*>(pair.value()); for (unsigned int i = 0; i < fixedGeom->logicalLength(); ++i) { DWGConstraintUtils::AngleFixation& angleFixation = fixedGeom->at(i); OdCsLinePtr fixedAxis = FindSolverObject(angleFixation.fixedAxisHint).dynamicCast(); if (fixedAxis.isNull()) { fixedAxis = OdCsLine::create(OdGePoint2d(), OdGeVector2d(1., 0.)); _ctx.geometries().append(fixedAxis); OdCsConstraintPtr fixationOX = OdCsFixation::create(fixedAxis); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fixationOX); } OdCsLinePtr line = FindSolverObject(angleFixation.lineToFixAngle).dynamicCast(); if (line.isNull()) { OdCsPointPtr csPt1 = FindSolverObject(angleFixation.pt1).dynamicCast(); OdCsPointPtr csPt2 = FindSolverObject(angleFixation.pt2).dynamicCast(); if (csPt1.isNull() && csPt2.isNull()) { OdCsEllipsePtr ellipse = FindSolverObject(angleFixation.lineToFixAngle).dynamicCast(); if (!ellipse.isNull()) { OdGePoint2d pt1 = ellipse->getPointByParam(0); OdGePoint2d pt2 = ellipse->getPointByParam(OdaPI); line = OdCsLine::create(pt1, pt2 - pt1); _ctx.geometries().append(line); } } else { line = OdCsLine::create(csPt1->position(), csPt2->position() - csPt1->position()); _ctx.geometries().append(line); OdCsCoincidencePtr axisPt1 = OdCsCoincidence::create(line, csPt1); _auxiliaryConstraintHelper.addAuxiliaryConstraint(axisPt1); OdCsCoincidencePtr axisPt2 = OdCsCoincidence::create(line, csPt1); _auxiliaryConstraintHelper.addAuxiliaryConstraint(axisPt2); } } double angle = fixedAxis->direction().angleToCCW(line->direction()); OdCsAnglePtr angleConstraint = OdCsAngle::create(fixedAxis, line, angle); _auxiliaryConstraintHelper.addAuxiliaryConstraint(angleConstraint); } } key = OD_T("TempFixedDistance"); pair = OdDbEvalContextPair(key, NULL); if (context->getAt(pair)) { OdArray* fixedGeom = static_cast*>(pair.value()); for (unsigned int i = 0; i < fixedGeom->logicalLength(); ++i) { DWGConstraintUtils::DistanceFixation& distFixation = fixedGeom->at(i); OdCsPointPtr pt1 = FindSolverObject(distFixation.pt1).dynamicCast(); OdCsPointPtr pt2 = FindSolverObject(distFixation.pt2).dynamicCast(); double distance = pt1->position().distanceTo(pt2->position()); if (distFixation.line != 0) { OdCsLinePtr line = FindSolverObject(distFixation.line).dynamicCast(); OdCsDirectedDistancePtr distConstraint = OdCsDirectedDistance::create(pt1, pt2, line, distance); _auxiliaryConstraintHelper.addAuxiliaryConstraint(distConstraint); } else { OdCsDistancePtr distConstraint = OdCsDistance::create(pt1, pt2, distance); _auxiliaryConstraintHelper.addAuxiliaryConstraint(distConstraint); } } } } } } void DWGAssocActionPE::CreateSolverRigidSets(const OdConstrainedRigidSetArray& rigidSets, bool original) { for (const OdConstrainedRigidSet* rigidSet : rigidSets) { DWGAssocActionPE::Solver2DRX ids; ids._drxId = rigidSet->nodeId(); bool alreadyExist = false; ids._solverId = CreateSolverRigidSet(rigidSet, alreadyExist, original); if (ids._solverId && !alreadyExist) { _ctx.geometries().append(ids._solverId); _aIds.append(ids); } } } OdCsGeometryPtr DWGAssocActionPE::CreateSolverRigidSet(const OdConstrainedRigidSet* rigidSet, bool& alreadyExist, bool original) { if (!rigidSet) { alreadyExist = false; return nullptr; } OdCsGeometryPtr geom = FindSolverObject(rigidSet->nodeId()); if (!geom.isNull()) { alreadyExist = true; return geom; } alreadyExist = false; OdVector nestedGeometries; RigidSetNestedGeometries(rigidSet, nestedGeometries); OdCsRigidSetPtr rs = OdCsRigidSet::create(std::move(nestedGeometries)); const OdGeMatrix3d mat = original ? rigidSet->originalTransform() : rigidSet->transform(); const double angle = OdGeVector3d::kXAxis.angleTo(mat.getCsXAxis(), OdGeVector3d::kZAxis); rs->setRotation(angle); rs->setCenter(mat.getCsOrigin().convert2d()); return rs; } void DWGAssocActionPE::RigidSetNestedGeometries(const OdConstrainedRigidSet* rigidSet, OdVector& nestedGeometries) { for (int i = 0; i < rigidSet->numOfConstrainedGeoms(); i++) { OdConstrainedGeometry* geom = rigidSet->getConstrainedGeomAt(i); if (geom) { OdCsGeometryPtr csGeom = FindSolverObject(geom->nodeId()); nestedGeometries.append(csGeom); } } } OdCsGeometryPtr DWGAssocActionPE::FindSolverObject(OdConstraintGroupNodeId iId) const { int len = _aIds.length(); if (len == 0) return NULL; int idx = 0; while (_aIds[idx]._drxId != iId) { idx++; if (idx >= len) return NULL; } return _aIds[idx]._solverId; } OdCsGeometryPtr DWGAssocActionPE::CreateSolverLine(OdConstrainedLine* ipLine) { if (ipLine == NULL) return NULL; OdGePoint3d startPoint = ipLine->pointOnLine(); OdGeVector3d dir = ipLine->direction(); dir.normalize(); return OdCsLine::create(startPoint.convert2d(), dir.convert2d()); } OdCsGeometryPtr DWGAssocActionPE::CreateSolverCircle(OdConstrainedCircle* ipCircle) { if (ipCircle == NULL) return NULL; OdGePoint3d circleCenter = ipCircle->centerPoint(); double radius = ipCircle->radius(); return OdCsCircle::create(circleCenter.convert2d(), radius); } OdCsGeometryPtr DWGAssocActionPE::CreateSolverEllipse(OdConstrainedEllipse* ipEllipse) { if (ipEllipse == NULL) return NULL; OdGePoint3d center = ipEllipse->centerPoint(); OdGeVector3d dir = ipEllipse->direction(); dir.normalize(); double majorRadius = ipEllipse->majorRadius(); double minorRadius = ipEllipse->minorRadius(); return OdCsEllipse::create(center.convert2d(), dir.convert2d(), majorRadius, minorRadius); } OdCsGeometryPtr DWGAssocActionPE::CreateSolverSpline(OdConstrainedSpline* ipSpline, bool original) { if (ipSpline == NULL) return NULL; OdGeNurbCurve3d nurbCurve = original ? ipSpline->originalNurbSpline() : ipSpline->nurbSpline(); int degree; bool rational, periodic; OdGeKnotVector knots; OdGePoint3dArray controlPoints; OdGeDoubleArray weights; nurbCurve.getDefinitionData(degree, rational, periodic, knots, controlPoints, weights); const unsigned int nCP = controlPoints.logicalLength(); OdGePoint2dArray controlPoints2d; controlPoints2d.resize(nCP); for (unsigned int i = 0; i < nCP; ++i) { controlPoints2d[i] = controlPoints[i].convert2d(); } OdGeNurbCurve2d nurb2d; nurb2d.set(degree, knots, controlPoints2d, weights, periodic); return OdCsSpline::create(nurb2d); #if 0 bool alreadyExistObj; int i, ptQty = ipSpline->numOfDefinePoints(); int allPtQty = ptQty + (nurbCurve.isClosed() ? 1 : 0); LGSGeoObject *iaPoints = new LGSGeoObject[allPtQty]; OdConstrainedImplicitPoint* pPoint; for ( i = 0; i < ptQty; i++ ) { alreadyExistObj = false; pPoint = FindImplicitPoint(i, apImplicitPoints); if ( pPoint == NULL ) return NULL; iaPoints[i] = original ? CreateOriginalSolverPoint(pPoint, alreadyExistObj) : CreateSolverPoint(pPoint, alreadyExistObj); Solver2DRX ids; ids._drxId = pPoint->nodeId(); ids._solverId = iaPoints[i]; if ( !alreadyExistObj && ids._solverId != NULL ) _aIds.append(ids); } if ( allPtQty > ptQty ) iaPoints[ptQty] = iaPoints[0]; int numWeights = nurbCurve.numWeights(); int numKnots = nurbCurve.numKnots(); double *iaKnots = NULL; if ( numKnots > 0 ) { if ( numKnots > 0 ) { iaKnots = new double[numKnots]; for ( i = 0; i < numKnots; i++ ) iaKnots[i] = nurbCurve.knotAt(i); } } double *iaWeights = NULL; if ( numWeights == 0 ) { iaWeights = new double[ptQty]; for ( i = 0; i < ptQty; i++ ) iaWeights[i] = 1.0; } else { iaWeights = new double[numWeights]; for ( i = 0; i < numWeights; i++ ) iaWeights[i] = nurbCurve.weightAt(i); } LGSObject res = LGSCreateNURBS(_ctx, ptQty, iaPoints, nurbCurve.degree(), 0/*nurbCurve.isClosed()*/, iaKnots, iaWeights); delete [] iaPoints; delete [] iaKnots; delete [] iaWeights; return res; #endif } OdCsGeometryPtr DWGAssocActionPE::CreateSolverPoint(OdConstrainedPoint* ipPoint, bool& alreadyExist, bool original) { if (ipPoint == NULL) return NULL; OdCsGeometryPtr pt = FindSolverObject(ipPoint->nodeId()); if ( pt != NULL ) { alreadyExist = true; return pt; } // control points for spline are created in createSplineExplicitPoints OdConstrainedImplicitPoint* implicitPoint = OdConstrainedImplicitPoint::cast(ipPoint); if (implicitPoint && implicitPoint->constrainedCurveId() != OdConstraintGroupNode::kNullGroupNodeId && implicitPoint->pointType() == OdConstrainedImplicitPoint::kDefineImplicit) { OdDbAssoc2dConstraintGroupPtr pGr = OdDbAssoc2dConstraintGroup::cast(implicitPoint->owningConstraintGroupId().openObject()); OdConstraintGroupNode* pCurve = pGr->getGroupNodePtr(implicitPoint->constrainedCurveId()); if (pCurve && pCurve->isKindOf(OdConstrainedSpline::desc())) { alreadyExist = true; return nullptr; } } alreadyExist = false; OdGePoint3d point = original ? ipPoint->getOriginalPoint() : ipPoint->point(); pt = OdCsPoint::create(point.convert2d()); return pt; } OdCsGeometryPtr DWGAssocActionPE::CreateOriginalSolverLine(OdConstrainedLine* ipLine) { if (ipLine == NULL) return NULL; OdGeLine3d line = ipLine->getOriginalOdGeLine3d(); OdGePoint3d startPoint = line.evalPoint(0.0); OdGeVector3d dir = line.direction(); dir.normalize(); return OdCsLine::create(startPoint.convert2d(), dir.convert2d()); } OdCsGeometryPtr DWGAssocActionPE::CreateOriginalSolverCircle(OdConstrainedCircle* ipCircle) { if (ipCircle == NULL) return NULL; OdGeCircArc3d circle = ipCircle->getOriginalOdGeCircArc3d(); OdGePoint3d circleCenter = circle.center(); double radius = circle.radius(); return OdCsCircle::create(circleCenter.convert2d(), radius); } OdCsGeometryPtr DWGAssocActionPE::CreateOriginalSolverEllipse(OdConstrainedEllipse* ipEllipse) { if (ipEllipse == NULL) return NULL; OdGeEllipArc3d ellipse = ipEllipse->getOriginalOdGeEllipArc3d(); OdGePoint3d center = ellipse.center(); OdGeVector3d dir = ellipse.majorAxis(); dir.normalize(); double majorRadius = ellipse.majorRadius(); double minorRadius = ellipse.minorRadius(); return OdCsEllipse::create(center.convert2d(), dir.convert2d(), majorRadius, minorRadius); } void DWGAssocActionPE::CreateSolverConstraint(OdGeomConstraint* ipConstraint, bool original, InfoMUC* infoMUC /*= NULL*/) { if (ipConstraint == nullptr) return; OdArray apConsGeoms; ipConstraint->getConnectedGeometries(apConsGeoms); OdCsGeometryPtr args[4]; unsigned len = odmin(apConsGeoms.length(), 4); unsigned i = 0; for (; i < len; i++) args[i] = FindSolverObject(apConsGeoms[i]->nodeId()); for (; i < 4; i++) args[i] = nullptr; OdCsConstraintPtr solverCnstr; if (OdPointCoincidenceConstraint * pCoincidence = OdPointCoincidenceConstraint::cast(ipConstraint)) { solverCnstr = OdCsCoincidence::create(args[0], args[1]); } else if (OdPointCurveConstraint * pPointCurve = OdPointCurveConstraint::cast(ipConstraint)) { solverCnstr = OdCsCoincidence::create(args[0], args[1]); int iPoint = -1; if (args[0]->type() == OdCs::kPoint) { iPoint = 0; } else if (args[1]->type() == OdCs::kPoint) { iPoint = 1; } if (iPoint >= 0) // must always be so { OdCsPointPtr point = args[iPoint].dynamicCast(); OdCsGeometryPtr curve = args[1 - iPoint]; if (curve.isNull()) return; if (curve->type() == OdCs::kCircle) { if (infoMUC == NULL || curve.get() != infoMUC->_geomCs) { OdCsCirclePtr circle = curve.dynamicCast(); OdGeCircArc2d geArc; geArc.set(circle->center(), circle->radius()); const double param = geArc.paramOf(point->position()); OdCsCoincidencePtr coincidence = solverCnstr.dynamicCast(); _auxiliaryConstraintHelper.addCoincidenceParamLock(coincidence, param); } } else if (curve->type() == OdCs::kEllipse) { if (infoMUC == NULL || curve.get() != infoMUC->_geomCs) { OdCsEllipsePtr ellipse = curve.dynamicCast(); OdGeEllipArc2d geArc; geArc.set(ellipse->center(), ellipse->direction(), ellipse->direction().perpVector(), ellipse->majorRadius(), ellipse->minorRadius()); const double param = geArc.paramOf(point->position()); OdCsCoincidencePtr coincidence = solverCnstr.dynamicCast(); _auxiliaryConstraintHelper.addCoincidenceParamLock(coincidence, param); } } else if (curve->type() == OdCs::kLine && apConsGeoms[iPoint]->isKindOf(OdConstrainedImplicitPoint::desc())) { if (infoMUC == NULL || curve.get() != infoMUC->_geomCs) { bool bEllipAxis = false; if (infoMUC != NULL && infoMUC->_geomMUC && infoMUC->_geomMUC->isKindOf(OdConstrainedEllipse::desc())) { OdConstrainedEllipse* pEllip = OdConstrainedEllipse::cast(infoMUC->_geomMUC); OdGeEllipArc3d geEllip = pEllip->getOriginalOdGeEllipArc3d(); geEllip.setAngles(0, Oda2PI); if (geEllip.isOn(OdGePoint3d(point->position().x, point->position().y, 0), 1e-6)) // TODO: check constraint common connections? { bEllipAxis = true; } } if (!bEllipAxis) { // fix directed distance auto it = _mapCoincidense.find(curve.get()); if (it == _mapCoincidense.end()) { _mapCoincidense[curve.get()] = point; } else { const double dist = it->second->position().distanceTo(point->position()); OdCsDirectedDistancePtr csDist = OdCsDirectedDistance::create(it->second, args[iPoint], curve, dist); csDist->setAlignment(OdCsConstraint::Keep); // CORE-20076: the default value for alignment (Positive) should be changed to Keep _auxiliaryConstraintHelper.addAuxiliaryConstraint(csDist); //if (infoMUC && infoMUC->_ptCS) if (infoMUC && infoMUC->_ptMoveCoordinate.x != HUGE_VAL) { const double d1 = point->position().distanceSqrdTo(infoMUC->_ptMoveCoordinate); // _ptCS->position() const double d2 = it->second->position().distanceSqrdTo(infoMUC->_ptMoveCoordinate); _auxiliaryConstraintHelper.addAuxiliaryBoundedLineFixation(OdCsFixation::create(d1 > d2 ? point : it->second), d1 > d2 ? d1 : d2); } } } } } } } else if (OdColinearConstraint * pColinear = OdColinearConstraint::cast(ipConstraint)) { solverCnstr = OdCsCoincidence::create(args[0], args[1]); } else if (OdConcentricConstraint * pConcentric = OdConcentricConstraint::cast(ipConstraint)) { solverCnstr = OdCsConcentric::create(args[0], args[1]); } else if (OdPerpendicularConstraint * pPerpendicular = OdPerpendicularConstraint::cast(ipConstraint)) { solverCnstr = OdCsPerpendicularity::create(args[0], args[1]); //solverCnstr->setAlignment(OdCsConstraint::Undefined); } else if (OdHorizontalConstraint * pHorizontal = OdHorizontalConstraint::cast(ipConstraint)) { if ( len == 1 ) solverCnstr = OdCsHorizontality::create(args[0]); else if (apConsGeoms.size()==2) //2 points { OdCsGeometryPtr line = findCommonLine(OdConstrainedPoint::cast(apConsGeoms[0]), OdConstrainedPoint::cast(apConsGeoms[1])); solverCnstr = OdCsHorizontality::create(line); } else { ODA_FAIL_ONCE(); } } else if (OdVerticalConstraint * pVertical = OdVerticalConstraint::cast(ipConstraint)) { if ( len == 1 ) solverCnstr = OdCsVerticality::create(args[0]); else if (apConsGeoms.size() == 2) //2 points { OdCsGeometryPtr line = findCommonLine(OdConstrainedPoint::cast(apConsGeoms[0]), OdConstrainedPoint::cast(apConsGeoms[1])); solverCnstr = OdCsVerticality::create(line); } else { ODA_FAIL_ONCE(); } } else if (OdParallelConstraint * pParallel = OdParallelConstraint::cast(ipConstraint)) { solverCnstr = OdCsParallelism::create(args[0], args[1]); } else if (OdTangentConstraint * pTangent = OdTangentConstraint::cast(ipConstraint)) { solverCnstr = OdCsTangency::create(args[0], args[1]); solverCnstr->setAlignment(OdCsConstraint::Undefined); createTangentAuxiliaryConstraints(pTangent, args, apConsGeoms); } else if(OdEqualCurvatureConstraint * pEqualCur = OdEqualCurvatureConstraint::cast(ipConstraint)) { solverCnstr = OdCsEqualCurveProperty::create(args[0], args[1], OdCs::cptCurvature); //solverCnstr->setAlignment(OdCsConstraint::Keep); } else if (OdEqualRadiusConstraint * pEqualRadius = OdEqualRadiusConstraint::cast(ipConstraint)) { solverCnstr = OdCsEqualRadius::create(args[0], args[1]); } else if (OdEqualDistanceConstraint * pEqualDistance = OdEqualDistanceConstraint::cast(ipConstraint)) { solverCnstr = OdCsEqualDistance::create(args[0], args[1], args[2], args[3]); } else if (OdEqualLengthConstraint * pEqualLength = OdEqualLengthConstraint::cast(ipConstraint)) { ODA_ASSERT(len == 2); OdCsGeometryPtr aSolverPoints[2][2] = {{NULL, NULL}, {NULL, NULL}}; for (int t = 0; t < 2; t++) { OdConstrainedLine * pLn = OdConstrainedLine::cast(apConsGeoms[t]); ODA_ASSERT(pLn); OdArray apImplicitPoints; pLn->getConstrainedImplicitPoints(apImplicitPoints); unsigned int j = 0; while ((aSolverPoints[t][0] == NULL || aSolverPoints[t][1] == NULL) && j < apImplicitPoints.length()) { OdConstrainedImplicitPoint * pPt = apImplicitPoints[j++]; switch (pPt->pointType()) { case OdConstrainedImplicitPoint::kStartImplicit: aSolverPoints[t][0] = FindSolverObject(pPt->nodeId()); break; case OdConstrainedImplicitPoint::kEndImplicit: aSolverPoints[t][1] = FindSolverObject(pPt->nodeId()); break; } } ODA_ASSERT(aSolverPoints[t][0] && aSolverPoints[t][1]); } solverCnstr = OdCsEqualDistance::create(aSolverPoints[0][0], aSolverPoints[0][1], aSolverPoints[1][0], aSolverPoints[1][1]); } else if (OdSymmetricConstraint * pSymmetric = OdSymmetricConstraint::cast(ipConstraint)) { ODA_ASSERT(len == 3); OdCsGeometryPtr ln, arg1, arg2; OdConstrainedLine * pLine; if ((pLine = OdConstrainedLine::cast(apConsGeoms[2]))) { ln = args[2]; arg1 = args[0]; arg2 = args[1]; } else if ((pLine = OdConstrainedLine::cast(apConsGeoms[1]))) { ln = args[1]; arg1 = args[0]; arg2 = args[2]; } else if ((pLine = OdConstrainedLine::cast(apConsGeoms[0]))) { ln = args[0]; arg1 = args[1]; arg2 = args[2]; } else { ODA_ASSERT(false); //error! } solverCnstr = OdCsSymmetry::create(arg1, arg2, ln); OdCsFixationPtr fix = OdCsFixation::create(ln); _auxiliaryConstraintHelper.addAuxiliaryConstraint(fix); } else if (OdMidPointConstraint * pMidPoint = OdMidPointConstraint::cast(ipConstraint)) { ODA_ASSERT(len == 2); OdConstrainedPoint *pPt = OdConstrainedPoint::cast(apConsGeoms[0]); OdConstrainedCurve *pCurve = OdConstrainedCurve::cast(apConsGeoms[1]); ODA_VERIFY(pPt && pCurve); OdCsGeometryPtr pt = args[0], start = NULL, end = NULL; OdArray apImplicitPoints; pCurve->getConstrainedImplicitPoints(apImplicitPoints); for (unsigned int j = 0; j < apImplicitPoints.length(); ++j) { OdConstrainedImplicitPoint * pImplicitPt = apImplicitPoints[j]; switch (pImplicitPt->pointType()) { case OdConstrainedImplicitPoint::kStartImplicit: start = FindSolverObject(pImplicitPt->nodeId()); break; case OdConstrainedImplicitPoint::kEndImplicit: end = FindSolverObject(pImplicitPt->nodeId()); break; } } solverCnstr = OdCsMidPoint::create(start, end, pt); } else if (OdFixedConstraint * pFixed = OdFixedConstraint::cast(ipConstraint)) { solverCnstr = OdCsFixation::create(args[0]); } else if (OdExplicitConstraint * pDim = OdExplicitConstraint::cast(ipConstraint)) { double val; pDim->getMeasuredValue(val); if (OdDistanceConstraint * pDistance = OdDistanceConstraint::cast(pDim)) { OdGeVector3d dir = pDistance->direction(); OdConstrainedPoint* startPt = OdConstrainedPoint::cast(apConsGeoms[0]); OdConstrainedPoint* endPt = OdConstrainedPoint::cast(apConsGeoms[1]); if (startPt && endPt) { if (!dir.isZeroLength()) dir.normalize(); OdGePoint3d startPtCoord = original ? startPt->getOriginalPoint() : startPt->point(); OdGePoint3d endPtCoord = original ? endPt->getOriginalPoint() : endPt->point(); switch (pDistance->directionType()) { case OdDistanceConstraint::kNotDirected: solverCnstr = OdCsDistance::create(args[0], args[1], val); break; case OdDistanceConstraint::kFixedDirection: { if (fabs(dir.x) > OdGeContext::gTol.equalPoint() && fabs(dir.y) < OdGeContext::gTol.equalPoint()) { double sign = endPtCoord.x - startPtCoord.x > 0 ? 1.0 : -1.0; solverCnstr = OdCsHorizontalDistance::create(args[0], args[1], sign * val); } else if (dir.x == 0 && dir.y != 0) { double sign = endPtCoord.y - startPtCoord.y > 0 ? 1.0 : -1.0; solverCnstr = OdCsVerticalDistance::create(args[0], args[1], sign * val); } else { OdGeVector2d solverDir = OdGeVector2d(dir.y, -dir.x); CreateDistanceConstraint(startPtCoord, solverDir, args, solverCnstr, val); } } break; case OdDistanceConstraint::kPerpendicularToLine: { double sign = (endPtCoord.x - startPtCoord.x) > 0 ? 1.0 : -1.0; if (dir.isPerpendicularTo(OdGeVector3d::kYAxis)) { solverCnstr = OdCsVerticalDistance::create(args[0], args[1], sign * val); } else if (dir.isPerpendicularTo(OdGeVector3d::kXAxis)) { solverCnstr = OdCsHorizontalDistance::create(args[0], args[1], sign * val); } else { OdGeVector2d dir2d = dir.convert2d(); CreateDistanceConstraint(startPtCoord, dir2d, args, solverCnstr, val); } } break; case OdDistanceConstraint::kParallelToLine: { double sign = (endPtCoord.x - startPtCoord.x) > 0 ? 1.0 : -1.0; if (dir.isParallelTo(OdGeVector3d::kYAxis)) { solverCnstr = OdCsVerticalDistance::create(args[0], args[1], sign * val); } else if (dir.isParallelTo(OdGeVector3d::kXAxis)) { solverCnstr = OdCsHorizontalDistance::create(args[0], args[1], sign * val); } else { OdGeVector2d solverDir = OdGeVector2d(dir.y, -dir.x); CreateDistanceConstraint(startPtCoord, solverDir, args, solverCnstr, val); } } break; default: ODA_ASSERT_ONCE(false); } } } else if (Od3PointAngleConstraint * p3PointAngle = Od3PointAngleConstraint::cast(pDim)) { OdConstrainedPoint *centerPt = OdConstrainedPoint::cast(apConsGeoms[0]); OdConstrainedPoint *rightPt = OdConstrainedPoint::cast(apConsGeoms[1]); OdConstrainedPoint *leftPt = OdConstrainedPoint::cast(apConsGeoms[2]); OdConstrainedGeometryArray aGeomConnectedCenter; centerPt->getConnectedGeometries(aGeomConnectedCenter); OdConstrained2PointsConstructionLine* rightLine = nullptr; OdConstrained2PointsConstructionLine* leftLine = nullptr; for (auto it : aGeomConnectedCenter) { OdConstrained2PointsConstructionLine* line = OdConstrained2PointsConstructionLine::cast(it); if (!line) { continue; } OdConstrainedGeometryArray aPt; line->getConnectedGeometries(aPt); if (aPt.logicalLength() != 2) { ODA_ASSERT_ONCE(0); continue; } int iCenter = aPt[0]->nodeId() == centerPt->nodeId() ? 0 : 1; ODA_ASSERT_ONCE(aPt[iCenter]->nodeId() == centerPt->nodeId()); if (aPt[1 - iCenter]->nodeId() == rightPt->nodeId()) { rightLine = line; } else if (aPt[1 - iCenter]->nodeId() == leftPt->nodeId()) { leftLine = line; } } // invalid constraint if (!rightLine || !leftLine) { ODA_ASSERT_ONCE(0); return; } OdCsGeometryPtr lineRightId = FindSolverObject(rightLine->nodeId()); OdCsGeometryPtr lineLeftId = FindSolverObject(leftLine->nodeId()); val *= p3PointAngle->angleMultiplier(); switch ( p3PointAngle->sectorType() ) { case OdAngleConstraint::kParallelAntiClockwise: break; case OdAngleConstraint::kAntiParallelClockwise: val = OdaPI - val; break; case OdAngleConstraint::kParallelClockwise: val = Oda2PI - val; break; case OdAngleConstraint::kAntiParallelAntiClockwise: val = val + OdaPI; break; } solverCnstr = OdCsAngle::create(lineRightId, lineLeftId, val); } else if (OdAngleConstraint * pAngle = OdAngleConstraint::cast(pDim)) { val *= pAngle->angleMultiplier(); switch ( pAngle->sectorType() ) { case OdAngleConstraint::kParallelAntiClockwise: break; case OdAngleConstraint::kAntiParallelClockwise: val = OdaPI - val; break; case OdAngleConstraint::kParallelClockwise: val = Oda2PI - val; break; case OdAngleConstraint::kAntiParallelAntiClockwise: val = val + OdaPI; break; } solverCnstr = OdCsAngle::create(args[0], args[1], val); //solverCnstr->setAlignment(OdCsConstraint::Undefined); } else if (OdRadiusDiameterConstraint * pRadius = OdRadiusDiameterConstraint::cast(pDim)) { switch (pRadius->constrType()) { case OdRadiusDiameterConstraint::kCircleRadius: solverCnstr = OdCsRadiusFixation::create(args[0], val); break; case OdRadiusDiameterConstraint::kCircleDiameter: solverCnstr = OdCsRadiusFixation::create(args[0], val * 0.5); break; case OdRadiusDiameterConstraint::kMajorRadius: solverCnstr = OdCsRadiusFixation::create(args[0], val, OdCsConstraint::MajorRadius); break; case OdRadiusDiameterConstraint::kMinorRadius: solverCnstr = OdCsRadiusFixation::create(args[0], val, OdCsConstraint::MinorRadius); break; } } } else { return; } if (solverCnstr != NULL) { OdVector arguments = solverCnstr->arguments(); if(std::find(std::begin(arguments), std::end(arguments), nullptr) == std::end(arguments)) _ctx.constraints().append(solverCnstr); _aIdsConstraint[ipConstraint->nodeId()] = solverCnstr; } //add help parameters if ( len == 0 ) return; if (!solverCnstr.isNull()) { OdHelpParameter* pHelpParameter; for (i = 0; i < len; i++) { pHelpParameter = ipConstraint->getConnectedHelpParameterFor(apConsGeoms[i]); if (pHelpParameter == NULL) continue; double val = pHelpParameter->getValue(); if (solverCnstr->type() == OdCs::kCoincidence) { OdCsCoincidencePtr coincidence = solverCnstr.dynamicCast(); //coincidence->setIsParametric(true); coincidence->setHelpParameter(val); coincidence->setLockHelpParameter(true); } else if (solverCnstr->type() == OdCs::kTangency || solverCnstr->type() == OdCs::kEqualCurveProperty) { solverCnstr->setHelpParam(i, val); solverCnstr->setLockHelpParam(i, true); } else { // TODO: implement help parameters for other constraints ODA_ASSERT_ONCE(0); } } } if ( ipConstraint->isKindOf(OdTangentConstraint::desc()) ) { // TODO: nurbs is not implemented yet /*for ( i = 0; i < len; i++) { if ( LGSGetObjectType(_ctx, args[i]) == LGS_GEOOBJECT_NURBS ) { LGSUInt attr_val[ 1] = { LGS_ALIGN_KEEP }; LGSSetObjectAttribute(_ctx, solverCnstr, LGS_ATTR_ALIGNMENT, attr_val); return; } }*/ } // TODO: OdEqualCurvatureConstraint is not implemented yet /*if ( ipConstraint->isKindOf(OdEqualCurvatureConstraint::desc()) ) { LGSUInt attr_val[ 1] = { LGS_ALIGN_KEEP }; LGSSetObjectAttribute(_ctx, solverCnstr, LGS_ATTR_ALIGNMENT, attr_val); }*/ } void DWGAssocActionPE::CreateDistanceConstraint(OdGePoint3d& startPtCoord, OdGeVector2d& solverDir, OdCsGeometryPtr args[4], OdCsConstraintPtr& solverCnstr, double val) { OdCsLinePtr lineId = OdCsLine::create(startPtCoord.convert2d(), solverDir); _ctx.geometries().append(lineId); OdCsLinePtr lineOx = OdCsLine::create(startPtCoord.convert2d(), OdGeVector2d(1, 0)); _ctx.geometries().append(lineOx); _ctx.constraints().append(OdCsCoincidence::create(args[0], lineId)); solverCnstr = OdCsDistance::create(lineId, args[1], val); double angOx = acos(solverDir.x); if (solverDir.y < 0.0) angOx = Oda2PI - angOx; _ctx.constraints().append(OdCsAngle::create(lineOx, lineId, angOx)); } bool DWGAssocActionPE::UpdateDRXPoint(OdConstrainedPoint* ipPoint, OdCsPointPtr iPt) { OdGePoint2d pt = iPt->position(); // For test purpose only if (ipPoint == NULL) return false; if ( ipPoint->isKindOf(OdConstrainedImplicitPoint::desc()) ) { OdConstrainedImplicitPoint *pImplPt = OdConstrainedImplicitPoint::cast(ipPoint); if ( pImplPt->pointType() != OdConstrainedImplicitPoint::kDefineImplicit ) return true; } // update point position OdGePoint3d position; position.x = iPt->position().x; position.y = iPt->position().y; position.z = 0.0; ipPoint->setPoint(position); return true; } bool DWGAssocActionPE::UpdateDRXLine(OdConstrainedLine* ipLine, OdCsLinePtr iLn) { if (ipLine == NULL) return false; OdGeVector3d dir(0, 0, 0); if (!iLn.isNull()) { dir.x = iLn->direction().x; dir.y = iLn->direction().y; dir.z = 0.0; } if ( ipLine->isKindOf(OdConstrainedBoundedLine::desc()) ) { OdConstrainedBoundedLine* pBoundedLine = OdConstrainedBoundedLine::cast(ipLine); bool haveStart = false, haveEnd = false; OdGePoint3d start; OdGePoint3d end; getStartEndPoints(ipLine, start, end, haveStart, haveEnd); if ( !haveStart ) return false; if ( pBoundedLine->isRay() ) { ipLine->set(start, dir); return true; } pBoundedLine->set(start, end); } else { OdGePoint3d startPoint; startPoint.x = iLn->position().x; startPoint.y = iLn->position().y; startPoint.z = 0.0; ipLine->set(startPoint, dir); } return true; } bool DWGAssocActionPE::UpdateDRXCircle(OdConstrainedCircle* ipCircle, OdCsCirclePtr iCi) { if (ipCircle == NULL) return false; OdGePoint3d center; center.x = iCi->center().x; center.y = iCi->center().y; center.z = 0.0; double radius = iCi->radius(); if ( ipCircle->isKindOf(OdConstrainedArc::desc()) ) { OdConstrainedArc* pArc = OdConstrainedArc::cast(ipCircle); bool haveStart = false, haveEnd = false; OdGePoint3d start; OdGePoint3d end; getStartEndPoints(pArc, start, end, haveStart, haveEnd); if ( !haveStart || !haveEnd ) return false; pArc->set(center, radius, start, end); return true; } else { ipCircle->set(center, radius); return true; } } bool DWGAssocActionPE::UpdateDRXEllipse(OdConstrainedEllipse* ipEllipse, OdCsEllipsePtr iEl) { if (ipEllipse == NULL) return false; OdGePoint3d center; OdGeVector3d dir; double majorRadius = iEl->majorRadius(); double minorRadius = iEl->minorRadius(); center.x = iEl->center().x; center.y = iEl->center().y; dir.x = iEl->direction().x; dir.y = iEl->direction().y; center.z = 0.0; dir.z = 0.0; if ( ipEllipse->isKindOf(OdConstrainedBoundedEllipse::desc()) ) { OdConstrainedBoundedEllipse* pArc = OdConstrainedBoundedEllipse::cast(ipEllipse); bool haveStart = false, haveEnd = false; OdGePoint3d start; OdGePoint3d end; getStartEndPoints(pArc, start, end, haveStart, haveEnd); if ( !haveStart || !haveEnd ) return false; if ( majorRadius > minorRadius ) { pArc->set(center, dir, majorRadius, minorRadius, start, end); } else { dir = dir.perpVector(); dir.normalize(); pArc->set(center, dir, minorRadius, majorRadius, start, end); } return true; } else { if ( majorRadius > minorRadius ) { ipEllipse->set(center, dir, majorRadius, minorRadius); } else { dir = dir.perpVector(); dir.normalize(); ipEllipse->set(center, dir, minorRadius, majorRadius); } } return true; } bool DWGAssocActionPE::UpdateDRXRigidSet(OdConstrainedRigidSet* ipRigidSet, OdCsRigidSetPtr iRs) { if (!ipRigidSet || !iRs) return false; OdGePoint2d center2d = iRs->center(); OdGeVector3d center(center2d.x, center2d.y, 0.); OdGeMatrix3d matrix; matrix.setToTranslation(center); OdGeMatrix3d matrixRot; matrixRot.setToRotation(iRs->rotation(), OdGeVector3d::kZAxis); matrix.postMultBy(matrixRot); ipRigidSet->setTransform(matrix); return true; } bool DWGAssocActionPE::UpdateDRXSpline(OdConstrainedSpline* ipSpline, OdCsSplinePtr iSpline) { if (!ipSpline || !iSpline) return false; OdArray apImplicitPoints; ipSpline->getConstrainedImplicitPoints(apImplicitPoints); OdVector aControlPoints = iSpline->controlPoints(); unsigned int numCnstrainedSplineCP = apImplicitPoints.logicalLength(); unsigned int numSolverSplineCP = aControlPoints.logicalLength(); if (numSolverSplineCP >= numCnstrainedSplineCP) { for (unsigned int i = 0; i < numCnstrainedSplineCP; i++) { OdGePoint3d point; point.x = aControlPoints[i]->position().x; point.y = aControlPoints[i]->position().y; point.z = 0; ipSpline->setPoint(apImplicitPoints[i], point); } } else { // numSolverSplineCP < numCnstrainedSplineCP ODA_FAIL_ONCE(); return false; } return true; } void DWGAssocActionPE::UpdateFromSolver(OdDbAssoc2dConstraintGroup * ipConstraintGroup) { if (ipConstraintGroup == NULL) return; OdConstraintGroupNode* pNode; OdConstrainedGeometry* pGeom; for (unsigned int i = 0; i < _aIds.length(); i++) { pNode = ipConstraintGroup->getGroupNodePtr(_aIds[i]._drxId); pGeom = OdConstrainedGeometry::cast(pNode); if ( pGeom != NULL ) pGeom->DoPostEvaluateJob(); else continue; OdCsPointPtr pPoint = _aIds[i]._solverId.dynamicCast(); if ( pPoint && UpdateDRXPoint(OdConstrainedPoint::cast(pNode), pPoint) ) continue; OdCsLinePtr pLine = _aIds[i]._solverId.dynamicCast(); if ( pLine && UpdateDRXLine(OdConstrainedLine::cast(pNode), pLine) ) continue; OdCsCirclePtr pCircle = _aIds[i]._solverId.dynamicCast(); if ( pCircle && UpdateDRXCircle(OdConstrainedCircle::cast(pNode), pCircle) ) continue; OdCsEllipsePtr pEllipse = _aIds[i]._solverId.dynamicCast(); if ( pEllipse && UpdateDRXEllipse(OdConstrainedEllipse::cast(pNode), pEllipse) ) continue; OdCsRigidSetPtr pRigidSet = _aIds[i]._solverId.dynamicCast(); if ( pRigidSet && UpdateDRXRigidSet(OdConstrainedRigidSet::cast(pNode), pRigidSet) ) continue; OdCsSplinePtr pSpline = _aIds[i]._solverId.dynamicCast(); if ( pSpline && UpdateDRXSpline(OdConstrainedSpline::cast(pNode), pSpline) ) continue; } //ipConstraintGroup->updateDatabaseObjects(); } void DWGAssocActionPE::RestoreOriginalGeom(OdConstrainedCurve* pCurve) { pCurve->restoreOriginalGeometry(); DWGConstraintUtils::ImplicitPointArray aImplicitPoints; pCurve->getConstrainedImplicitPoints(aImplicitPoints); for (DWGConstraintUtils::ImplicitPointArray::value_type &point : aImplicitPoints) point->restoreOriginalGeometry(); } void DWGAssocActionPE::RestoreOriginalGeom(OdConstrainedGeometryPtrArray& aConstrainedGeometry) { for (OdConstrainedGeometryPtr &pConstrainedGeometry : aConstrainedGeometry) { if (pConstrainedGeometry->isKindOf(OdConstrainedCurve::desc())) RestoreOriginalGeom(OdConstrainedCurve::cast(pConstrainedGeometry.get())); else if (pConstrainedGeometry->isKindOf(OdConstrainedPoint::desc())) pConstrainedGeometry->restoreOriginalGeometry(); } } static void crossPoint(const OdGePoint3d& srcPt, const OdGeVector3d& srcVec, const OdGePoint3d& dstPt, const OdGeVector3d& dstVec, OdGePoint3d& xPoint) { xPoint = srcPt + srcVec*(dstVec.x*(dstPt.y - srcPt.y) - dstVec.y*(dstPt.x - srcPt.x))/ (dstVec.x*srcVec.y - dstVec.y*srcVec.x); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdGePoint3d& srcPtS, const OdGePoint3d& srcPtE, const OdGePoint3d& dstPtS, const OdGePoint3d& dstPtE) { const double tolSolver = 1e-6; OdGeVector3d origVec = srcPtE - srcPtS; OdGeVector3d newVec = dstPtE - dstPtS; double origLen = origVec.length(); double len = newVec.length(); if ( fabs(origLen - len) > OdGeContext::gTol.equalVector() ) { SolverTransfTyper res; res.setType(SolverTransfTyper::TransTypeComposite); return res; } else if ( fabs(origLen) < OdGeContext::gTol.equalVector() && fabs(len) < OdGeContext::gTol.equalVector() ) { return SolverTransfTyper(dstPtS - srcPtS); } if ( origVec.isCodirectionalTo(newVec, tolSolver) ) { return SolverTransfTyper(dstPtS - srcPtS); } else if ( origVec.isParallelTo(newVec, tolSolver) ) { OdGePoint3d center((dstPtS.x + srcPtS.x)/2.0, (dstPtS.y + srcPtS.y)/2.0, (dstPtS.z + srcPtS.z)/2.0); return SolverTransfTyper(center, OdaPI); } OdGeVector3d startPtVec = dstPtS - srcPtS; OdGeVector3d endPtVec = dstPtE - srcPtE; OdGePoint3d ptVec1, ptVec2; OdGeVector3d vec1, vec2; if (startPtVec.isZeroLength()) { double rotAng = origVec.angleTo(newVec, OdGeVector3d::kZAxis); return SolverTransfTyper(dstPtS, rotAng); } if (endPtVec.isZeroLength() || startPtVec.isParallelTo(endPtVec) ) { ptVec1 = srcPtS; ptVec2 = dstPtS; vec1 = origVec; vec2 = newVec; } else { ptVec1.set((dstPtS.x + srcPtS.x)/2.0, (dstPtS.y + srcPtS.y)/2.0, (dstPtS.z + srcPtS.z)/2.0); ptVec2.set((dstPtE.x + srcPtE.x)/2.0, (dstPtE.y + srcPtE.y)/2.0, (dstPtE.z + srcPtE.z)/2.0); vec1 = startPtVec.perpVector(); vec2 = endPtVec.perpVector(); } OdGePoint3d rotCn; crossPoint(ptVec1, vec1, ptVec2, vec2, rotCn); double rotAng = (srcPtS - rotCn).angleTo(dstPtS - rotCn, OdGeVector3d::kZAxis); ODA_ASSERT_ONCE(OdEqual((srcPtE - rotCn).angleTo(dstPtE - rotCn, OdGeVector3d::kZAxis), rotAng)); //double rotAng = oxAngle(vec2) - oxAngle(vec1); return SolverTransfTyper(rotCn, rotAng); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedGeometry* pGeom) { if ( pGeom->isKindOf(OdConstrainedCurve::desc()) ) return getTransformation(OdConstrainedCurve::cast(pGeom)); else if ( pGeom->isKindOf(OdConstrainedPoint::desc()) ) return getTransformation(OdConstrainedPoint::cast(pGeom)); else ODA_FAIL_ONCE(); return SolverTransfTyper(); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedPoint* pPoint) { return getTransformation(pPoint->getOriginalPoint(), pPoint->getOriginalPoint(), pPoint->point(), pPoint->point()); }/*getTransformation*/ SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedCurve* pCurve) { if ( pCurve->isKindOf(OdConstrainedBoundedLine::desc()) ) return getTransformation(OdConstrainedBoundedLine::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedLine::desc()) ) return getTransformation(OdConstrainedLine::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedArc::desc()) ) return getTransformation(OdConstrainedArc::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedCircle::desc()) ) return getTransformation(OdConstrainedCircle::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedBoundedEllipse::desc()) ) return getTransformation(OdConstrainedBoundedEllipse::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedEllipse::desc()) ) return getTransformation(OdConstrainedEllipse::cast(pCurve)); else if ( pCurve->isKindOf(OdConstrainedSpline::desc()) ) return getTransformation(OdConstrainedSpline::cast(pCurve)); else ODA_FAIL(); return SolverTransfTyper(); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedLine* pLine) { OdGeLine3d origLine = pLine->getOriginalOdGeLine3d(); OdGeLine3d line = pLine->getOdGeLine3d(); OdGeVector3d dir1 = origLine.direction(); OdGeVector3d dir2 = line.direction(); dir1.normalize(); dir2.normalize(); return getTransformation(origLine.evalPoint(0.0), origLine.evalPoint(0.0) + dir1, line.evalPoint(0.0), line.evalPoint(0.0) + dir2); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedBoundedLine* pLine) { if (pLine->isRay()) { return getTransformation(OdConstrainedLine::cast(pLine)); } OdGeLineSeg3d origLine = pLine->getOriginalOdGeLineSeg3d(); OdGeLineSeg3d line = pLine->getOdGeLineSeg3d(); return getTransformation(origLine.startPoint(), origLine.endPoint(), line.startPoint(), line.endPoint()); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedCircle* pCircle) { OdGeCircArc3d origArc = pCircle->getOriginalOdGeCircArc3d(); OdGeCircArc3d arc = pCircle->getOdGeCircArc3d(); if ( fabs(origArc.radius() - arc.radius()) > OdGeContext::gTol.equalPoint() ) { SolverTransfTyper res; res.setType(SolverTransfTyper::TransTypeComposite); return res; } return getTransformation(origArc.center(), origArc.center(), arc.center(), arc.center()); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedArc* pCircleArc) { OdGeCircArc3d origArc = pCircleArc->getOriginalOdGeCircArc3d(); OdGeCircArc3d arc = pCircleArc->getOdGeCircArc3d(); SolverTransfTyper centerTr = getTransformation(OdConstrainedCircle::cast(pCircleArc)); if ( centerTr.getType() == SolverTransfTyper::TransTypeComposite ) return centerTr; OdGePoint3d sPtOrig = origArc.startPoint(); OdGePoint3d ePtOrig = origArc.endPoint(); OdGePoint3d cPtOrig = origArc.center(); OdGePoint3d sPt = arc.startPoint(); OdGePoint3d ePt = arc.endPoint(); OdGePoint3d cPt = arc.center(); SolverTransfTyper startTr = getTransformation(cPtOrig, sPtOrig, cPt, sPt); if ( startTr.isFitTransform(ePtOrig, ePt) ) return startTr; centerTr.setType(SolverTransfTyper::TransTypeComposite); return centerTr; } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedEllipse* pEllipse) { OdGeEllipArc3d origEllipse = pEllipse->getOriginalOdGeEllipArc3d(); OdGeEllipArc3d ellipse = pEllipse->getOdGeEllipArc3d(); OdGeVector3d majorOrig = origEllipse.majorAxis(); OdGeVector3d major = ellipse.majorAxis(); OdGeVector3d minorOrig = origEllipse.minorAxis(); OdGeVector3d minor = ellipse.minorAxis(); /*if ( majorOrig != major || minorOrig != minor ) {*/ double originalMajorRadius = origEllipse.majorRadius(); double originalMinorRadius = origEllipse.minorRadius(); double majorRadius = ellipse.majorRadius(); double minorRadius = ellipse.minorRadius(); bool isRadiiEquals = (OdEqual(majorRadius, originalMajorRadius) && OdEqual(minorRadius, originalMinorRadius)); if (!isRadiiEquals) { SolverTransfTyper res; res.setType(SolverTransfTyper::TransTypeComposite); return res; } /*if (isRadiiEquals) { double rotationAngle = major.angleTo(majorOrig); OdGePoint3d ellipseCenter = ellipse.center(); OdGePoint3d ellipseOriginalCenter = origEllipse.center(); OdGePoint3d rotationCenter((ellipseCenter.x + ellipseOriginalCenter.x) / 2.0, (ellipseCenter.y + ellipseOriginalCenter.y) / 2.0, (ellipseCenter.z + ellipseOriginalCenter.z) / 2.0); SolverTransfTyper res(rotationCenter, rotationAngle); return res; } }*/ return getTransformation(origEllipse.center() + majorOrig * originalMajorRadius, origEllipse.center(), ellipse.center() + major * majorRadius, ellipse.center()); } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedBoundedEllipse* pEllipseArc) { OdGeEllipArc3d origEllipse = pEllipseArc->getOriginalOdGeEllipArc3d(); OdGeEllipArc3d ellipse = pEllipseArc->getOdGeEllipArc3d(); SolverTransfTyper centerTr = getTransformation(OdConstrainedEllipse::cast(pEllipseArc)); if ( centerTr.getType() == SolverTransfTyper::TransTypeComposite || centerTr.getType() == SolverTransfTyper::TransTypeRotate) return centerTr; OdGePoint3d originalCenterPoint = origEllipse.center(); OdGePoint3d centerPoint = ellipse.center(); if (centerPoint != originalCenterPoint) return centerTr; OdGePoint3d sPtOrig = origEllipse.startPoint(); OdGePoint3d ePtOrig = origEllipse.endPoint(); OdGePoint3d sPt = ellipse.startPoint(); OdGePoint3d ePt = ellipse.endPoint(); if ( centerTr.isFitTransform(ePtOrig, ePt) && centerTr.isFitTransform(sPtOrig, sPt)) return centerTr; centerTr.setType(SolverTransfTyper::TransTypeComposite); return centerTr; } SolverTransfTyper DWGAssocActionPE::getTransformation(const OdConstrainedSpline* pSpline) { OdGeNurbCurve3d nurb = pSpline->nurbSpline(); OdGeNurbCurve3d origNurb = pSpline->originalNurbSpline(); SolverTransfTyper tf = getTransformation(origNurb.controlPointAt(0), origNurb.controlPointAt(1), nurb.controlPointAt(0), nurb.controlPointAt(1)); if ( !isFitTransformation(pSpline, tf) ) tf.setType(SolverTransfTyper::TransTypeComposite); return tf; } void DWGAssocActionPE::getAllModifiedGeomPoints(const OdDbAssoc2dConstraintGroup* ipConstraintGroup, OdConstrainedGeometryPtrArray& aConstGeom) { OdArray aAllGeom; ipConstraintGroup->getConstrainedGeometries(aAllGeom); OdConstrainedGeometry* testGeom; unsigned int i, len = aAllGeom.length(); for( i = 0; i < len; i++ ) { testGeom = aAllGeom[i]; if ( testGeom->isModified() && testGeom->isKindOf(OdConstrainedPoint::desc()) && !testGeom->isKindOf(OdConstrainedImplicitPoint::desc())) aConstGeom.append(testGeom); } } void DWGAssocActionPE::getAllModifiedCurves(const OdDbAssoc2dConstraintGroup* ipConstraintGroup, OdConstrainedGeometryPtrArray& aConstGeom) { OdArray aAllGeom; ipConstraintGroup->getConstrainedGeometries(aAllGeom); OdConstrainedGeometry* testGeom; unsigned int i, len = aAllGeom.length(); for( i = 0; i < len; i++ ) { testGeom = aAllGeom[i]; if ( testGeom->isKindOf(OdConstrainedCurve::desc()) && testGeom->isModified() ) aConstGeom.append(testGeom); } } void DWGAssocActionPE::createTangentAuxiliaryConstraints(const OdTangentConstraint* /*pTangent*/, const OdCsGeometryPtr args[4], const OdArray& apConsGeoms) { OdCsLinePtr fixedAxis; for (unsigned int i = 0; i < 4; i++) { if (!args[i]) { continue; } else if (args[i]->type() == OdCs::kLine && !apConsGeoms[i]->isModified()) { const OdCsLinePtr csLine = args[i].dynamicCast(); #if 0 // makes EllipseTangentMoveGripPoint_CORE19516_SA work like in acad _auxiliaryConstraintHelper.addAuxiliaryConstraint(OdCsFixation::create(csLine)); #else // makes TangentConstraint_CORE25286_SA work like in acad if (fixedAxis.isNull()) { fixedAxis = OdCsLine::create(OdGePoint2d(), OdGeVector2d(1., 0.)); _ctx.geometries().append(fixedAxis); OdCsConstraintPtr fixationOX = OdCsFixation::create(fixedAxis); _ctx.constraints().append(fixationOX); } double angle = fixedAxis->direction().angleToCCW(csLine->direction()); OdCsAnglePtr angleConstraint = OdCsAngle::create(fixedAxis, csLine, angle); _auxiliaryConstraintHelper.addAuxiliaryConstraint(angleConstraint); #endif } } } void DWGAssocActionPE::deleteChangedPlainGeometries(OdDbAssoc2dConstraintGroup* constraintGroup, OdConstrainedGeometryPtrArray& constrainedGeometris) { for (OdConstrainedGeometry* constrainedGeometry : constrainedGeometris) { if (constrainedGeometry->numRefs() > 1 && constrainedGeometry->isPlainChanged()) { constraintGroup->deleteConstrainedGeometry(constrainedGeometry->geomDependencyId()); } } } void DWGAssocActionPE::getModifiedGeometries(OdDbAssoc2dConstraintGroup* constraintGroup, OdConstrainedGeometryPtrArray& constrainedCurves, OdConstrainedGeometryPtrArray& constrainedPoints) { getAllModifiedCurves(constraintGroup, constrainedCurves); deleteChangedPlainGeometries(constraintGroup, constrainedCurves); getAllModifiedGeomPoints(constraintGroup, constrainedPoints); deleteChangedPlainGeometries(constraintGroup, constrainedPoints); constrainedCurves.clear(); getAllModifiedCurves(constraintGroup, constrainedCurves); constrainedPoints.clear(); getAllModifiedGeomPoints(constraintGroup, constrainedPoints); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedGeometry* pGeom, SolverTransfTyper& tf) { if ( pGeom->isKindOf(OdConstrainedCurve::desc()) ) return isFitTransformation(OdConstrainedCurve::cast(pGeom), tf); else if ( pGeom->isKindOf(OdConstrainedPoint::desc()) ) return isFitTransformation(OdConstrainedPoint::cast(pGeom), tf); else ODA_FAIL_ONCE(); return false; } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedCurve* pCurve, SolverTransfTyper& tf) { if ( pCurve->isKindOf(OdConstrainedBoundedLine::desc()) ) return isFitTransformation(OdConstrainedBoundedLine::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedLine::desc()) ) return isFitTransformation(OdConstrainedLine::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedArc::desc()) ) return isFitTransformation(OdConstrainedArc::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedCircle::desc()) ) return isFitTransformation(OdConstrainedCircle::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedBoundedEllipse::desc()) ) return isFitTransformation(OdConstrainedBoundedEllipse::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedEllipse::desc()) ) return isFitTransformation(OdConstrainedEllipse::cast(pCurve), tf); else if ( pCurve->isKindOf(OdConstrainedSpline::desc()) ) return isFitTransformation(OdConstrainedSpline::cast(pCurve), tf); else ODA_FAIL(); return false; } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedPoint* pPoint, SolverTransfTyper& tf) { return tf.isFitTransform(pPoint->getOriginalPoint(), pPoint->point()); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedLine* pLine, SolverTransfTyper& tf) { OdGeLine3d origLine = pLine->getOriginalOdGeLine3d(); OdGeLine3d line = pLine->getOdGeLine3d(); return tf.isFitTransform(origLine.evalPoint(0.0), line.evalPoint(0.0)); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedBoundedLine* pLine, SolverTransfTyper& tf) { if ( pLine->isRay() ) { OdGeRay3d origRay = pLine->getOriginalOdGeRay3d(); OdGeRay3d ray = pLine->getOdGeRay3d(); return tf.isFitTransform(origRay.evalPoint(0.0), ray.evalPoint(0.0)); } else { OdGeLineSeg3d origLine = pLine->getOriginalOdGeLineSeg3d(); OdGeLineSeg3d line = pLine->getOdGeLineSeg3d(); return tf.isFitTransform(origLine.startPoint(), line.startPoint()) && tf.isFitTransform(origLine.endPoint(), line.endPoint()); } } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedCircle* pCircle, SolverTransfTyper& tf) { OdGeCircArc3d origCircle = pCircle->getOriginalOdGeCircArc3d(); OdGeCircArc3d circle = pCircle->getOdGeCircArc3d(); return tf.isFitTransform(origCircle.center(), circle.center()); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedArc* pCircleArc, SolverTransfTyper& tf) { OdGeCircArc3d origArc = pCircleArc->getOriginalOdGeCircArc3d(); OdGeCircArc3d arc = pCircleArc->getOdGeCircArc3d(); return tf.isFitTransform(origArc.center(), arc.center()) && tf.isFitTransform(origArc.startPoint(), arc.startPoint()) && tf.isFitTransform(origArc.endPoint(), arc.endPoint()); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedEllipse* pEllipse, SolverTransfTyper& tf) { OdGeEllipArc3d origEllipse = pEllipse->getOriginalOdGeEllipArc3d(); OdGeEllipArc3d ellipse = pEllipse->getOdGeEllipArc3d(); OdGePoint3d origMagorAxisEnd = origEllipse.center() + origEllipse.majorAxis(); OdGePoint3d magorAxisEnd = ellipse.center() + ellipse.majorAxis(); return tf.isFitTransform(origEllipse.center(), ellipse.center()) && tf.isFitTransform(origMagorAxisEnd, magorAxisEnd); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedBoundedEllipse* pEllipseArc, SolverTransfTyper& tf) { OdGeEllipArc3d origEllipse = pEllipseArc->getOriginalOdGeEllipArc3d(); OdGeEllipArc3d ellipse = pEllipseArc->getOdGeEllipArc3d(); OdGePoint3d origMagorAxisEnd = origEllipse.center() + origEllipse.majorAxis(); OdGePoint3d magorAxisEnd = ellipse.center() + ellipse.majorAxis(); return tf.isFitTransform(origEllipse.center(), ellipse.center()) && tf.isFitTransform(origMagorAxisEnd, magorAxisEnd) && tf.isFitTransform(origEllipse.startPoint(), ellipse.startPoint()) && tf.isFitTransform(origEllipse.endPoint(), ellipse.endPoint()); } bool DWGAssocActionPE::isFitTransformation(const OdConstrainedSpline* pSpline, SolverTransfTyper& tf) { OdGeNurbCurve3d nurb = pSpline->nurbSpline(); OdGeNurbCurve3d origNurb = pSpline->originalNurbSpline(); int size = nurb.numControlPoints(); for ( int i = 0; i < size; i++ ) { if ( !tf.isFitTransform(origNurb.controlPointAt(i), nurb.controlPointAt(i)) ) return false; } return true; } SolverTransfTyper DWGAssocActionPE::getCommonTransformation(const OdConstrainedGeometryPtrArray& aConstrainedGeometry, const OdArray& aTransforTyper) { SolverTransfTyper res; OdConstraintGroupNodeId resGeomId = 0; //find first rotate transformation unsigned int i, len = aConstrainedGeometry.length(); for ( i = 0; i < len; i++ ) if ( SolverTransfTyper::TransTypeRotate == aTransforTyper[i].getType() ) { res = aTransforTyper[i]; resGeomId = aConstrainedGeometry[i]->nodeId(); } if ( resGeomId == 0 ) { res = aTransforTyper[0]; resGeomId = aConstrainedGeometry[0]->nodeId(); } OdConstrainedGeometryPtr testGeom; for ( i = 0; i < len; i++ ) { testGeom = aConstrainedGeometry[i]; if ( testGeom->nodeId() == resGeomId ) continue; if ( testGeom->isKindOf(OdConstrainedCurve::desc()) ) { if ( !isFitTransformation(OdConstrainedCurve::cast(testGeom), res) ) { res.setType(SolverTransfTyper::TransTypeComposite); return res; } } else if ( testGeom->isKindOf(OdConstrainedPoint::desc()) ) { if ( !isFitTransformation(OdConstrainedPoint::cast(testGeom), res) ) { res.setType(SolverTransfTyper::TransTypeComposite); return res; } } else ODA_FAIL_ONCE(); } return res; } OdCsGeometryPtr DWGAssocActionPE::findCommonLine(const OdConstrainedPoint* pPointF, const OdConstrainedPoint* pPointS) { OdArray arrConGeomF; pPointF->getConnectedGeometries(arrConGeomF); OdArray arrConGeomS; pPointS->getConnectedGeometries(arrConGeomS); unsigned int i, j; for (i = 0; i < arrConGeomF.length(); i++) { for (j = 0; j < arrConGeomS.length(); j++) { if (arrConGeomF[i]->nodeId() == arrConGeomS[j]->nodeId()) { if (arrConGeomF[i]->isKindOf(OdConstrainedBoundedLine::desc()) || arrConGeomF[i]->isKindOf(OdConstrained2PointsConstructionLine::desc())) return FindSolverObject(arrConGeomF[i]->nodeId()); } } } return NULL; } void DWGAssocActionPE::getStartEndPoints(OdConstrainedCurve* pCurve, OdGePoint3d& start, OdGePoint3d& end, bool& haveStart, bool& haveEnd) { OdArray arrImplPt; pCurve->getConstrainedImplicitPoints(arrImplPt); OdConstraintGroupNodeId startPtId = OdConstraintGroupNode::kNullGroupNodeId; OdConstraintGroupNodeId endPtId = OdConstraintGroupNode::kNullGroupNodeId; unsigned int size = arrImplPt.length(); for (unsigned int i = 0; i < size; i++) { if (arrImplPt[i]->pointType() == OdConstrainedImplicitPoint::kStartImplicit) startPtId = arrImplPt[i]->nodeId(); else if (arrImplPt[i]->pointType() == OdConstrainedImplicitPoint::kEndImplicit) endPtId = arrImplPt[i]->nodeId(); } haveStart = getPoint(startPtId, start); haveEnd = getPoint(endPtId, end); } bool DWGAssocActionPE::getPoint(OdConstraintGroupNodeId id, OdGePoint3d& pt) { if (id == OdConstraintGroupNode::kNullGroupNodeId) return false; OdCsGeometryPtr solverId = FindSolverObject(id); if (solverId == NULL) return false; OdCs::OdCsType type = solverId->type(); if (type == OdCs::kPoint) { OdCsPointPtr p = solverId.dynamicCast(); pt.x = p->position().x; pt.y = p->position().y; } else { ODA_ASSERT_ONCE(0); return false; } pt.z = 0.0; return true; } DWGAssocActionPE::AuxiliaryConstraintsHelper::AuxiliaryConstraintsHelper() { } void DWGAssocActionPE::AuxiliaryConstraintsHelper::reset() { _nMainConstraints = 0; _iParamLock = 0; _constraintsAux.clear(); _fixationBoundedLine.clear(); _coincidenceParamLock.clear(); _allowOverconstrain = true; } void DWGAssocActionPE::AuxiliaryConstraintsHelper::addAuxiliaryConstraint(const OdCsConstraintPtr newElement) { _constraintsAux.push_back(newElement); } void DWGAssocActionPE::AuxiliaryConstraintsHelper::addAuxiliaryBoundedLineFixation(const OdCsFixationPtr newElement, double dist2) { _fixationBoundedLine[dist2] = newElement; } void DWGAssocActionPE::AuxiliaryConstraintsHelper::addCoincidenceParamLock(OdCsCoincidencePtr coincidence, double param) { ODA_ASSERT_ONCE(!coincidence->isParametric()); _coincidenceParamLock.push_back(std::make_pair(coincidence, param)); } static bool tryAddAux(OdCsConstraintSystem& system, OdCsOverDefinedChecker& checker, OdCsConstraintPtr auxConstraint, bool add2system = true) { // overdiagnostics checker.addObject(auxConstraint); OdConstraints overConstraints = checker.checkAndGetOverConstraints(); if (!overConstraints.isEmpty()) { ODA_ASSERT_ONCE(overConstraints.size() == 1 /*&& overConstraints[0] == auxConstraint*/); checker.removeConstraint(auxConstraint); return false; } if (add2system) { system.constraints().push_back(auxConstraint); } return true; } bool DWGAssocActionPE::AuxiliaryConstraintsHelper::addAuxiliaryConstraints(OdCsConstraintSystem& system) { _nMainConstraints = system.constraints().logicalLength(); //constraints.append(_constraintsAux); OdCsOverDefinedChecker checker; try { checker.addConstraintSystem(system); } catch (...) { // for now this can happen if the system contains spline // after CS-414 is done this shouldn't happen ODA_ASSERT_ONCE(0); return true; } OdConstraints overConstraints = checker.checkAndGetOverConstraints(); if (!overConstraints.isEmpty()) { // workaround until CS-445 and CS-446 are fixed std::set rsElems; for (auto geom : system.geometries()) { if (geom->type() == OdCs::kRigidSet) { OdCsRigidSetPtr rs = geom.dynamicCast(); for (auto elem : rs->elements()) { rsElems.insert(elem.get()); } } } OdConstraints constraintsToRemove; for (auto constr : overConstraints) { bool constraintInsideRS = true; for (auto arg : constr->arguments()) { if (rsElems.find(arg.get()) == rsElems.end()) { constraintInsideRS = false; break; } } if (!constraintInsideRS) { if (!this->_allowOverconstrain) { return false; } else { constraintsToRemove.push_back(constr); } } else { checker.removeConstraint(constr); } } // remove overdefining constraints while (!constraintsToRemove.isEmpty()) { OdCsConstraintPtr constr = constraintsToRemove.last(); constraintsToRemove.setLogicalLength(constraintsToRemove.logicalLength() - 1); checker.removeConstraint(constr); system.constraints().remove(constr, 0); --_nMainConstraints; constraintsToRemove = checker.checkAndGetOverConstraints(); } } for (auto& auxConstraint : _constraintsAux) { tryAddAux(system, checker, auxConstraint); } // the most distant points fixation will be deleted last for (auto it = _fixationBoundedLine.rbegin(); it != _fixationBoundedLine.rend(); ++it) { tryAddAux(system, checker, it->second); } for (auto it : _coincidenceParamLock) { if (it.first->isLockedParameter()) { continue; } checker.removeConstraint(it.first); it.first->setHelpParameter(it.second); it.first->setLockHelpParameter(true); if (!tryAddAux(system, checker, it.first, false)) { it.first->setLockHelpParameter(false); it.first->setIsParametric(false); checker.addObject(it.first); } } return true; } static void moveAuxConstraintsBack(OdConstraints& constraintsAux, OdCs::OdCsType type) { unsigned int i = 0; unsigned int constraintsAuxLength = constraintsAux.size(); while (i < constraintsAuxLength) { if (constraintsAux[i]->type() == type) { OdConstraints::value_type constraint = constraintsAux[i]; constraintsAux.removeAt(i); constraintsAux.push_back(constraint); constraintsAuxLength--; } else { i++; } } } void DWGAssocActionPE::AuxiliaryConstraintsHelper::reorderAuxiliaryConstraints() { moveAuxConstraintsBack(_constraintsAux, OdCs::kDirectedDistance); moveAuxConstraintsBack(_constraintsAux, OdCs::kAngle); } bool DWGAssocActionPE::AuxiliaryConstraintsHelper::deleteAuxiliaryConstraint(OdConstraints& constraints, bool removeAll) { ODA_ASSERT_ONCE(constraints.logicalLength() >= _nMainConstraints); bool nothingToDelete = true; // no need to delete aux constraints because they were added throug overdiag // ODA_ASSERT_ONCE(0); // shouldn't get here with overdiag // in case of MUC this situation is possible because overdiag can't detect "solved but not reached" case if (constraints.logicalLength() > _nMainConstraints) { if (!removeAll) { constraints.removeLast(); return false; } else { constraints.setLogicalLength(_nMainConstraints); nothingToDelete = false; } } if (_iParamLock < _coincidenceParamLock.logicalLength()) { if (!removeAll) { _coincidenceParamLock[_iParamLock].first->setLockHelpParameter(false); _coincidenceParamLock[_iParamLock].first->setIsParametric(false); ++_iParamLock; } else { for (; _iParamLock < _coincidenceParamLock.logicalLength(); ++_iParamLock) { _coincidenceParamLock[_iParamLock].first->setLockHelpParameter(false); _coincidenceParamLock[_iParamLock].first->setIsParametric(false); } } return false; } return nothingToDelete; } bool DWGAssocActionPE::AuxiliaryConstraintsHelper::auxConstraintLeft(const OdConstraints& constraints) const { if (constraints.logicalLength() > _nMainConstraints) { return true; } if (_iParamLock < _coincidenceParamLock.logicalLength()) { return true; } return false; } OdConstraintSolver::Result DWGAssocActionPE::AuxiliaryConstraintsHelper::solveWithAuxConstraints(OdCsConstraintSystem& ctx, OdCsMoveUnderConstraintsOptions* options /*= NULL*/) { OdConstraintSolver::Result modRes = OdConstraintSolver::NotSolved; const unsigned int nMainConstraints = ctx.constraints().logicalLength(); // check that main and aux dist constraints don't conflict for (unsigned int i = 0; i < nMainConstraints; ++i) { OdCsEqualDistancePtr constrDist = ctx.constraints()[i].dynamicCast(); if (!constrDist.isNull()) { for (unsigned int j = 0; j < _constraintsAux.logicalLength(); ++j) { OdCsDirectedDistancePtr aux = _constraintsAux[j].dynamicCast(); if (aux.isNull()) continue; const OdCsGeometry* pt1 = aux->arguments()[0].get(); const OdCsGeometry* pt2 = aux->arguments()[1].get(); const OdCsGeometry* pt11 = constrDist->arguments()[0].get(); const OdCsGeometry* pt12 = constrDist->arguments()[1].get(); const OdCsGeometry* pt21 = constrDist->arguments()[2].get(); const OdCsGeometry* pt22 = constrDist->arguments()[3].get(); // remove aux distance constraint that conflicts with main dist constraint if ((pt1 == pt11 && pt2 == pt12) || (pt1 == pt12 && pt2 == pt11) || (pt1 == pt21 && pt2 == pt22) || (pt1 == pt22 && pt2 == pt21)) { _constraintsAux.removeAt(j); --j; } } } } reorderAuxiliaryConstraints(); if (!addAuxiliaryConstraints(ctx)) { // system is broken, probably the last added constraint was bad return OdConstraintSolver::NotSolved; } do { // to restore the system if it is not solved OdCsMoveUnderConstraintsOptions MUCOptionsCopy; if (options) { //options->m_geomsToMove.clear(); MUCOptionsCopy = *options; } std::unique_ptr ctxClone(ctx.clone(options ? &MUCOptionsCopy : nullptr)); OdConstraintSolver solver(ctx); if (options) { modRes = solver.moveUnderConstraints(*options); } else { modRes = solver.solve(); } OdString iMsgName; iMsgName.format(L"--> solveWithAuxConstraints returns %d", modRes); DWGConstraintsTrace(iMsgName); // workaround until CS-247 is solved if (modRes == OdConstraintSolver::SolvedAndNotReached && options) { OdCsMUCValidator mucValidator(ctx, ctxClone.get(), MUCOptionsCopy); OdGeTol tolLoosen = solver.getTolerance(); tolLoosen.setEqualPoint(tolLoosen.equalPoint() * 50.); mucValidator.setTolerance(tolLoosen); if (mucValidator.validate()) { modRes = OdConstraintSolver::SolvedAndReached; } } if (modRes == OdConstraintSolver::SolvedAndReached || modRes == OdConstraintSolver::Solved || modRes == OdConstraintSolver::AlreadySolved || modRes == OdConstraintSolver::NotSolvedInput) { break; } if (auxConstraintLeft(ctx.constraints())) { // restore system initial state for (unsigned int i = 0; i < ctx.geometries().logicalLength(); ++i) { ctx.geometries()[i]->assignFrom(*ctxClone->geometries()[i]); } for (unsigned int i = 0; i < ctx.constraints().logicalLength(); ++i) { ctx.constraints()[i]->assignFrom(*ctxClone->constraints()[i]); } } } while (!deleteAuxiliaryConstraint(ctx.constraints(), true)); return modRes; }