From 0a90e07193a237900913ac3eb11cde08526a8964 Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 15 Jun 2015 14:57:18 +0300 Subject: [PATCH] Issue #600: Problem with multi-rotation when one of points of selected objects is used as a center of rotation --- .../SketchSolver_ConstraintMultiRotation.cpp | 75 +++++++++++++++++++ .../SketchSolver_ConstraintMultiRotation.h | 5 ++ 2 files changed, 80 insertions(+) diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp index ab3a4e570..0e8ec23d6 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -16,6 +16,18 @@ #include +static double squareDistance( + StoragePtr theStorage, const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) +{ + Slvs_Entity aPoint1 = theStorage->getEntity(thePoint1); + Slvs_Entity aPoint2 = theStorage->getEntity(thePoint2); + double x1 = theStorage->getParameter(aPoint1.param[0]).val; + double y1 = theStorage->getParameter(aPoint1.param[1]).val; + double x2 = theStorage->getParameter(aPoint2.param[0]).val; + double y2 = theStorage->getParameter(aPoint2.param[1]).val; + return (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2); +} + void SketchSolver_ConstraintMultiRotation::getAttributes( Slvs_hEntity& theCenter, double& theAngle, std::vector >& thePoints, @@ -118,6 +130,8 @@ void SketchSolver_ConstraintMultiRotation::process() if (!myErrorMsg.empty()) return; + myAuxLines.clear(); + // Create lines between neighbor rotated points and make angle between them equal to anAngle. // Also these lines should have equal lengths. Slvs_Constraint aConstraint; @@ -131,6 +145,7 @@ void SketchSolver_ConstraintMultiRotation::process() aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]); aPrevLine.h = myStorage->addEntity(aPrevLine); + std::vector anEqualLines(1, aPrevLine.h); for (size_t i = 1; i < aSize; i++) { Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[i]); @@ -151,7 +166,10 @@ void SketchSolver_ConstraintMultiRotation::process() mySlvsConstraints.push_back(aConstraint.h); aPrevLine = aLine; + anEqualLines.push_back(aPrevLine.h); } + + myAuxLines.push_back(anEqualLines); } // Equal radii constraints for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) { @@ -229,6 +247,63 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint() return; } + // Check the lengths of auxiliary lines are zero. + // If they become zero, remove corresponding Angle constraints. + // It they become non-zero (but were zero recently), add Angle constraint. + std::vector::iterator aConstr = mySlvsConstraints.begin(); + std::map anEqualLines; + bool isFirstRemoved = false; + for (; aConstr != mySlvsConstraints.end(); + isFirstRemoved ? aConstr = mySlvsConstraints.begin() : ++aConstr) { + isFirstRemoved = false; + Slvs_Constraint aConstraint = myStorage->getConstraint(*aConstr); + if (aConstraint.type == SLVS_C_ANGLE || aConstraint.type == SLVS_C_EQUAL_LENGTH_LINES) { + Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA); + // Line length became zero => remove constraint + if (squareDistance(myStorage, aLine.point[0], aLine.point[1]) < tolerance * tolerance) { + myStorage->removeConstraint(aConstraint.h); + isFirstRemoved = aConstr == mySlvsConstraints.begin(); + std::vector::iterator aTmpIter = aConstr--; + mySlvsConstraints.erase(aTmpIter); + } + // Store the lines into the map + anEqualLines[aConstraint.entityB] = aConstraint.entityA; + } + } + // Create Angle and Equal constraints for non-degenerated lines + AuxLinesList::iterator anIt = myAuxLines.begin(); + for (; anIt != myAuxLines.end(); ++anIt) { + if (anEqualLines.find(anIt->back()) != anEqualLines.end()) + continue; + + std::vector::iterator anEqLinesIt = anIt->begin(); + Slvs_hEntity aPrevLine = (*anEqLinesIt); + // Check the length of the line + Slvs_Entity aLine = myStorage->getEntity(aPrevLine); + if (squareDistance(myStorage, aLine.point[0], aLine.point[1]) < tolerance * tolerance) + continue; + + for (++anEqLinesIt; anEqLinesIt != anIt->end(); ++anEqLinesIt) { + Slvs_hEntity aLine = (*anEqLinesIt); + // Equal length constraint + Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aPrevLine, aLine); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + // Angle constraint + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_ANGLE, myGroup->getWorkplaneId(), fabs(myAngle), SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, + aPrevLine, aLine); + if (myAngle < 0.0) // clockwise rotation + aConstraint.other = true; + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + + aPrevLine = aLine; + } + } + // Obtain coordinates of rotation center Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter); double aCenterXY[2]; diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h index e9d0bd147..df01392f5 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -10,6 +10,10 @@ #include "SketchSolver.h" #include +#include + +typedef std::vector< std::vector > AuxLinesList; + /** \class SketchSolver_ConstraintMultiRotation * \ingroup Plugins * \brief Convert rotated features to the list of SolveSpace constraints @@ -60,6 +64,7 @@ private: size_t myNumberOfCopies; ///< number of previous copies of initial objects Slvs_hEntity myRotationCenter; ///< ID of center of rotation double myAngle; ///< angle of rotation + AuxLinesList myAuxLines; ///< list of auxiliary lines, created to make clear rotation }; #endif -- 2.39.2