From 5751da6b145cb9ea48f79c634c4a891e7969a865 Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 24 Apr 2015 11:20:18 +0300 Subject: [PATCH] Fix the problem with unexpected movement of features during Mirror constraint execution --- src/SketchSolver/SketchSolver.h | 2 + src/SketchSolver/SketchSolver_Constraint.cpp | 66 +++---------- .../SketchSolver_ConstraintMirror.cpp | 96 ++++++++++++++----- .../SketchSolver_ConstraintMirror.h | 3 + .../SketchSolver_ConstraintMultiRotation.cpp | 2 - src/SketchSolver/SketchSolver_Group.cpp | 21 ++-- 6 files changed, 103 insertions(+), 87 deletions(-) diff --git a/src/SketchSolver/SketchSolver.h b/src/SketchSolver/SketchSolver.h index 77bb4029a..cc5013f6e 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -20,4 +20,6 @@ /// Tolerance for value of parameters const double tolerance = 1.e-10; +#define PI 3.1415926535897932 + #endif diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 918a8026b..efd447ab7 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -677,61 +678,16 @@ void SketchSolver_Constraint::calculateMiddlePoint( return; } - double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad; - double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad; - double aTanStart = abs(xStart) < tolerance ? yStart : yStart / xStart; - double aTanEnd = abs(xEnd) < tolerance ? yEnd : yEnd / xEnd; - double aCotStart = abs(yStart) < tolerance ? xStart : xStart / yStart; - double aCotEnd = abs(yEnd) < tolerance ? xEnd : xEnd / yEnd; - if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) { - if (anArcPoint[1][0] > 0.0) - yEnd = 2.0 - yEnd; - else - yStart = -2.0 - yStart; - } else { - if (aTanStart > aTanEnd) { - if (yStart > yEnd) { - yStart = 2.0 - yStart; - yEnd = -2.0 - yEnd; - } else { - yStart = -2.0 - yStart; - yEnd = 2.0 - yEnd; - } - } - } - if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) { - if (anArcPoint[1][1] > 0.0) - xEnd = 2.0 - xEnd; - else - xStart = -2.0 - xStart; - } else { - if (aCotStart < aCotEnd) { - if (xStart > xEnd) { - xStart = 2.0 - xStart; - xEnd = -2.0 - xEnd; - } else { - xStart = -2.0 - xStart; - xEnd = 2.0 - xEnd; - } - } - } - x = (1.0 - theCoeff) * xStart + theCoeff * xEnd; - y = (1.0 - theCoeff) * yStart + theCoeff * yEnd; - if (x > 1.0) x = 2.0 - x; - if (x < -1.0) x = -2.0 - x; - if (y > 1.0) y = 2.0 - y; - if (y < -1.0) y = -2.0 - y; - - aNorm = sqrt(x*x + y*y); - if (aNorm >= tolerance) { - x *= aRad / aNorm; - y *= aRad / aNorm; - } else { - x = -0.5 * (anArcPoint[2][1] + anArcPoint[1][1]); - y = -0.5 * (anArcPoint[2][0] + anArcPoint[1][0]); - } - theX = anArcPoint[0][0] + x; - theY = anArcPoint[0][1] + y; + std::shared_ptr aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); + std::shared_ptr aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1])); + double anAngle = aStartDir->angle(aEndDir); + if (anAngle < 0) + anAngle += 2.0 * PI; + anAngle *= theCoeff; + double aCos = cos(anAngle); + double aSin = sin(anAngle); + theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin; + theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos; } } diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index 50d578a66..e76afd2ca 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -192,17 +192,6 @@ void SketchSolver_ConstraintMirror::process() } } } - - // Set the mirror line unchanged during constraint recalculation - for (int i = 0; i < 2; i++) { - if (myStorage->isPointFixed(aMirrorLine.point[i], aConstraint.h, true)) - continue; - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0, - aMirrorLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } } @@ -293,6 +282,7 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( Slvs_hEntity aTmp = aMirrorPoint[2]; aMirrorPoint[2] = aMirrorPoint[1]; aMirrorPoint[1] = aTmp; + adjustArcPoints(theBase); } if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) { aBasePoint[0] = theBase.h; @@ -310,9 +300,14 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( // orthogonal direction aDir = std::shared_ptr(new GeomAPI_Dir2d(aDir->y(), -aDir->x())); + Slvs_hConstraint aFixed; // transient variable for (int i = 0; i < 4; i++) { if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN) continue; + // check the mirror point is not fixed + if (myStorage->isPointFixed(aMirrorPoint[i], aFixed, true)) + continue; + Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]); double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val; double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val; @@ -331,13 +326,41 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( } } -void SketchSolver_ConstraintMirror::adjustConstraint() +void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const { - // Search mirror between middle points on the arcs and recompute their coordinates - std::list aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE); - if (aPonCirc.empty()) - return; + Slvs_Param aParam; + Slvs_Entity aPoint; + double anArcParams[3][2]; + for (int i = 0; i < 3; i++) { + aPoint = myStorage->getEntity(theArc.point[i]); + for (int j = 0; j < 2; j++) { + aParam = myStorage->getParameter(aPoint.param[j]); + anArcParams[i][j] = aParam.val; + if (i > 0) + anArcParams[i][j] -= anArcParams[0][j]; + } + } + double aRad2 = anArcParams[1][0] * anArcParams[1][0] + anArcParams[1][1] * anArcParams[1][1]; + double aDist2 = anArcParams[2][0] * anArcParams[2][0] + anArcParams[2][1] * anArcParams[2][1]; + if (fabs(aRad2 - aDist2) < tolerance) + return; // nothing to update (last point already on the arc) + if (aDist2 < tolerance) + return; // unable to update + double aCoeff = sqrt(aRad2 / aDist2); + anArcParams[2][0] *= aCoeff; + anArcParams[2][1] *= aCoeff; + + // Update last point + aPoint = myStorage->getEntity(theArc.point[2]); + for (int i = 0; i < 2; i++) { + aParam = Slvs_MakeParam(aPoint.param[i], myGroup->getId(), + anArcParams[0][i] + anArcParams[2][i]); + myStorage->updateParameter(aParam); + } +} +void SketchSolver_ConstraintMirror::adjustConstraint() +{ AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast( myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) { @@ -353,6 +376,7 @@ void SketchSolver_ConstraintMirror::adjustConstraint() return; Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second); + Slvs_Constraint aMirror; double aStartEnd[4]; for (int i = 0; i < 2; i++) { Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]); @@ -360,7 +384,10 @@ void SketchSolver_ConstraintMirror::adjustConstraint() aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val; } - Slvs_Constraint aMirror; + // Search mirror between middle points on the arcs and recompute their coordinates + std::map aPointsOnCircles; + std::list aMirrorPonCirc; + std::list aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE); std::vector::iterator aConstrIter = mySlvsConstraints.begin(); for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) { aMirror = myStorage->getConstraint(*aConstrIter); @@ -378,24 +405,45 @@ void SketchSolver_ConstraintMirror::adjustConstraint() } if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN) continue; + aMirrorPonCirc.push_back(aMirror); + // Store point IDs to avoid their recalculation twice + aPointsOnCircles[aPonCircA.ptA] = aPonCircA.entityA; + aPointsOnCircles[aPonCircB.ptA] = aPonCircB.entityA; + } + + // Recalculate positions of mirroring points + std::list aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE); + std::list::iterator aMirIter = aMirrorList.begin(); + for (; aMirIter != aMirrorList.end(); aMirIter++) { + if (aPointsOnCircles.find(aMirIter->ptA) != aPointsOnCircles.end()) + continue; // Avoid mirroring points on circles + Slvs_Entity aBase = myStorage->getEntity(aMirIter->ptA); + Slvs_Entity aMirror = myStorage->getEntity(aMirIter->ptB); + makeMirrorEntity(aBase, aMirror, aStartEnd); + } - bool aNeedToResolve = myStorage->isNeedToResolve(); + bool aNeedToResolve = myStorage->isNeedToResolve(); + for (aMirIter = aMirrorPonCirc.begin(); aMirIter != aMirrorPonCirc.end(); aMirIter++) { // Calculate middle point for base arc and mirrored point on mirror arc - Slvs_Entity aBaseArc = myStorage->getEntity(aPonCircA.entityA); - Slvs_Entity aBasePoint = myStorage->getEntity(aPonCircA.ptA); + Slvs_Entity aBaseArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptA]); + Slvs_Entity aBasePoint = myStorage->getEntity(aMirIter->ptA); Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]); Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]); calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val); myStorage->updateParameter(aParamX); myStorage->updateParameter(aParamY); - Slvs_Entity aMirrorArc = myStorage->getEntity(aPonCircB.entityA); - Slvs_Entity aMirrorPoint = myStorage->getEntity(aPonCircB.ptA); + Slvs_Entity aMirrorArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptB]); + Slvs_Entity aMirrorPoint = myStorage->getEntity(aMirIter->ptB); aParamX = myStorage->getParameter(aMirrorPoint.param[0]); aParamY = myStorage->getParameter(aMirrorPoint.param[1]); calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val); myStorage->updateParameter(aParamX); myStorage->updateParameter(aParamY); - // To avoid looped recalculations of sketch - myStorage->setNeedToResolve(aNeedToResolve); + // make centers of arcs symmetric + aBasePoint = myStorage->getEntity(aBaseArc.point[0]); + aMirrorPoint = myStorage->getEntity(aMirrorArc.point[0]); + makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd); } + // Restore previous value to avoid looped recalculations of sketch + myStorage->setNeedToResolve(aNeedToResolve); } diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.h b/src/SketchSolver/SketchSolver_ConstraintMirror.h index e65dcb90b..26d97ff98 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.h +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.h @@ -66,6 +66,9 @@ private: const Slvs_Entity& theMirror, const double theMirrorLine[]) const; + /// \brief Precisely update last point to be on arc + void adjustArcPoints(const Slvs_Entity& theArc) const; + private: size_t myNumberOfObjects; ///< number of previously mirrored objects }; diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp index b9682f22d..2d439b2d1 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -15,8 +15,6 @@ #include -#define PI 3.1415926535897932 - void SketchSolver_ConstraintMultiRotation::getAttributes( Slvs_hEntity& theCenter, double& theAngle, std::vector >& thePoints, diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 41d5522f4..419cc3e87 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -236,12 +236,21 @@ bool SketchSolver_Group::changeConstraint( setTemporary(aConstraint); } } - //// Fix base features for mirror - //if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { - // AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - // theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_B())); - // fixFeaturesList(aRefList); - //} + // Fix mirror line + if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A())); + if (aRefAttr && aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); + if (aConstraint) { + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + setTemporary(aConstraint); + } + } + } if (!myFeatureStorage) myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); -- 2.39.2