From c98934f28850127f6ff336b4d7ef82b82bbcd2ef Mon Sep 17 00:00:00 2001 From: azv Date: Wed, 9 Sep 2015 10:15:52 +0300 Subject: [PATCH] Strange behavior of Angle constraint (issue #912) Recalculate positions of the attributes to avoid conflicting constraints while changing the value of angle several times --- .../SketchPlugin_ConstraintAngle.cpp | 2 +- .../SketchSolver_ConstraintAngle.cpp | 91 ++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp index 693fa9c84..9fbe2d84f 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintAngle.cpp @@ -163,7 +163,7 @@ double SketchPlugin_ConstraintAngle::calculateAngle() std::shared_ptr aDirB(new GeomAPI_Dir2d(aEndB->xy()->decreased(anInter->xy()))); anAngle = aDirA->angle(aDirB) * 180.0 / PI; - return anAngle; + return fabs(anAngle); } void SketchPlugin_ConstraintAngle::move(double theDeltaX, double theDeltaY) diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp index cfad93f19..998d70f53 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp @@ -1,5 +1,10 @@ #include +#include +#include +#include +#include + #include void SketchSolver_ConstraintAngle::getAttributes( @@ -15,6 +20,9 @@ void SketchSolver_ConstraintAngle::adjustConstraint() { Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); + bool isFixed[2][2]; + std::shared_ptr aPoints[2][2]; // start and end points of lines + Slvs_hConstraint aFixedConstraint; double aLineDir[2][2] = { {0.0, 0.0}, {0.0, 0.0} }; Slvs_hEntity anEnt[2] = {aConstraint.entityA, aConstraint.entityB}; for (int i = 0; i < 2; i++) { @@ -22,8 +30,13 @@ void SketchSolver_ConstraintAngle::adjustConstraint() double aCoef = -1.0; for (int j = 0; j < 2; j++, aCoef += 2.0) { const Slvs_Entity& aPoint = myStorage->getEntity(aLine.point[j]); - for (int k = 0; k < 2; k++) - aLineDir[i][k] += aCoef * myStorage->getParameter(aPoint.param[k]).val; + double aCoords[2]; + for (int k = 0; k < 2; k++) { + aCoords[k] = myStorage->getParameter(aPoint.param[k]).val; + aLineDir[i][k] += aCoef * aCoords[k]; + } + isFixed[i][j] = myStorage->isPointFixed(aPoint.h, aFixedConstraint, true); + aPoints[i][j] = std::shared_ptr(new GeomAPI_Pnt2d(aCoords[0], aCoords[1])); } } double aDot = aLineDir[0][0] * aLineDir[1][0] + aLineDir[0][1] * aLineDir[1][1]; @@ -31,6 +44,78 @@ void SketchSolver_ConstraintAngle::adjustConstraint() aConstraint.other = aDot * (90.0 - fabs(aConstraint.valA)) < 0.0; if ((90.0 - fabs(aConstraint.valA)) * (90.0 - fabs(myAngle)) < 0.0) aConstraint.other = !aConstraint.other; - myAngle = aConstraint.valA; myStorage->updateConstraint(aConstraint); + + if (fabs(myAngle - aConstraint.valA) < tolerance) + return; // the angle was not changed, no need to recalculate positions of lines + myAngle = aConstraint.valA; + + if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1]) + return; // both lines are fixed => no need to update them + + // Recalculate positions of lines to avoid conflicting constraints + // while changing angle value several times + std::shared_ptr aLine[2] = { + std::shared_ptr(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])), + std::shared_ptr(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1])) + }; + std::shared_ptr anIntersection = aLine[0]->intersect(aLine[1]); + if (!anIntersection) + return; + double aDist[2][2]; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + aDist[i][j] = anIntersection->distance(aPoints[i][j]); + std::shared_ptr aDir[2]; + for (int i = 0; i < 2; i++) + if (aDist[i][1] > aDist[i][0]) + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][1]->xy()->decreased(anIntersection->xy()))); + else + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][0]->xy()->decreased(anIntersection->xy()))); + + double cosA = cos(myAngle * PI / 180.0); + double sinA = sin(myAngle * PI / 180.0); + if (aDir[0]->cross(aDir[1]) < 0.0) + sinA *= -1.0; + int aLineToUpd = 1; + if (isFixed[1][0] && isFixed[1][1]) { + sinA *= -1.0; + aLineToUpd = 0; + } + double x = aDir[1-aLineToUpd]->x() * cosA - aDir[1-aLineToUpd]->y() * sinA; + double y = aDir[1-aLineToUpd]->x() * sinA + aDir[1-aLineToUpd]->y() * cosA; + + std::shared_ptr aNewPoints[2]; + for (int i = 0; i < 2; i++) { + aNewPoints[i] = std::shared_ptr( + new GeomAPI_Pnt2d(anIntersection->x() + x * aDist[aLineToUpd][i], + anIntersection->y() + y * aDist[aLineToUpd][i])); + } + + std::shared_ptr aDelta; + if (isFixed[aLineToUpd][0] && !isFixed[aLineToUpd][1]) + aDelta = aPoints[aLineToUpd][0]->xy()->decreased(aNewPoints[0]->xy()); + else if (!isFixed[aLineToUpd][0] && isFixed[aLineToUpd][1]) + aDelta = aPoints[aLineToUpd][1]->xy()->decreased(aNewPoints[1]->xy()); + if (aDelta) { + for (int i = 0; i < 2; i++) { + aNewPoints[i]->setX(aNewPoints[i]->x() + aDelta->x()); + aNewPoints[i]->setY(aNewPoints[i]->y() + aDelta->y()); + } + } + + // Update positions of points + const Slvs_Entity& anUpdLine = myStorage->getEntity(anEnt[aLineToUpd]); + Slvs_Param aParam; + for (int i = 0; i < 2; i++) { + const Slvs_Entity& aPoint = myStorage->getEntity(anUpdLine.point[i]); + aParam = myStorage->getParameter(aPoint.param[0]); + aParam.val = aNewPoints[i]->x(); + myStorage->updateParameter(aParam); + aParam = myStorage->getParameter(aPoint.param[1]); + aParam.val = aNewPoints[i]->y(); + myStorage->updateParameter(aParam); + } } -- 2.39.2