Slvs_hEntity getId(AttributePtr theAttribute) const;
/// \brief Adds a feature to constraint and create its analogue in SolveSpace
- void addFeature(FeaturePtr theFeature);
+ virtual void addFeature(FeaturePtr theFeature);
/// \brief Shows error message
const std::string& error() const
void SketchSolver_ConstraintMultiRotation::getAttributes(
Slvs_hEntity& theCenter, double& theAngle,
- std::vector<std::vector<Slvs_hEntity> >& thePoints,
- std::vector<std::vector<Slvs_hEntity> >& theCircular)
+ std::vector< std::vector<Slvs_hEntity> >& thePoints,
+ std::vector< std::vector<Slvs_hEntity> >& theEntities)
{
DataPtr aData = myBaseConstraint->data();
theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
// Also all circles and arc collected too, because they will be constrained by equal radii.
FeaturePtr aFeature;
ResultConstructionPtr aRC;
- std::vector<Slvs_hEntity> aPoints[2]; // lists of points of features
- std::vector<Slvs_hEntity> aCircs; // list of circular objects
+ static const size_t MAX_POINTS = 3;
+ std::vector<Slvs_hEntity> aPoints[MAX_POINTS]; // lists of points of features
+ std::vector<Slvs_hEntity> anEntities;
std::list<ObjectPtr> anObjectList = aRefList->list();
std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
while (anObjectIter != anObjectList.end()) {
- aPoints[0].clear();
- aPoints[1].clear();
- aCircs.clear();
+ for (size_t i = 0; i < MAX_POINTS; ++i)
+ aPoints[i].clear();
+ anEntities.clear();
for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
aFeature = ModelAPI_Feature::feature(*anObjectIter);
if (!aFeature)
continue;
anEntityID = changeEntity(aFeature, aType);
+ anEntities.push_back(anEntityID);
Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
switch (aType) {
case SLVS_E_POINT_IN_2D:
break;
case SLVS_E_CIRCLE:
aPoints[0].push_back(anEntity.point[0]); // center of circle
- aCircs.push_back(anEntityID);
break;
case SLVS_E_ARC_OF_CIRCLE:
- aPoints[0].push_back(anEntity.point[1]); // start point of arc
- aPoints[1].push_back(anEntity.point[2]); // end point of arc
- aCircs.push_back(anEntityID);
+ aPoints[0].push_back(anEntity.point[0]); // center of arc
+ aPoints[1].push_back(anEntity.point[1]); // start point of arc
+ aPoints[2].push_back(anEntity.point[2]); // end point of arc
break;
default:
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
}
}
- if (!aPoints[0].empty())
- thePoints.push_back(aPoints[0]);
- if (!aPoints[1].empty())
- thePoints.push_back(aPoints[1]);
- if (!aCircs.empty())
- theCircular.push_back(aCircs);
+ for (size_t i = 0; i < MAX_POINTS; ++i)
+ if (!aPoints[i].empty())
+ thePoints.push_back(aPoints[i]);
+ if (!anEntities.empty())
+ theEntities.push_back(anEntities);
}
}
if (!mySlvsConstraints.empty()) // some data is changed, update constraint
update(myBaseConstraint);
- Slvs_hEntity aCenter;
- std::vector<std::vector<Slvs_hEntity> > aPointsAndCopies;
- std::vector<std::vector<Slvs_hEntity> > aCircsAndCopies;
- getAttributes(aCenter, myAngle, aPointsAndCopies, aCircsAndCopies);
+ std::vector<std::vector<Slvs_hEntity> > anEntitiesAndCopies;
+ getAttributes(myRotationCenter, myAngle, myPointsAndCopies, anEntitiesAndCopies);
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;
- myRotationCenter = aCenter;
- Slvs_Entity aPrevLine;
- std::vector<std::vector<Slvs_hEntity> >::iterator aCopyIter = aPointsAndCopies.begin();
- for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) {
- size_t aSize = aCopyIter->size();
- if (aSize <= 1) continue;
-
- aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
- myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]);
- aPrevLine.h = myStorage->addEntity(aPrevLine);
- std::vector<Slvs_hEntity> 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]);
- aLine.h = myStorage->addEntity(aLine);
- // Equal length 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.h, aLine.h);
- 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.h, aLine.h);
- if (myAngle < 0.0) // clockwise rotation
- aConstraint.other = true;
- aConstraint.h = myStorage->addConstraint(aConstraint);
- 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++) {
- size_t aSize = aCopyIter->size();
- for (size_t i = 0; i < aSize - 1; i++) {
- aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
- SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
- (*aCopyIter)[i], (*aCopyIter)[i+1]);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- }
- }
-
// Set the rotation center unchanged during constraint recalculation
+ Slvs_Constraint aConstraint;
if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) {
aConstraint = Slvs_MakeConstraint(
SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
mySlvsConstraints.push_back(aConstraint.h);
}
+ // Set all objects unchanged (only initial object may be changed by user)
+ myCircsAndCopies.clear();
+ std::vector<std::vector<Slvs_hEntity> >::const_iterator anEntIt = anEntitiesAndCopies.begin();
+ std::vector<Slvs_hEntity>::const_iterator aCpIt;
+ for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+ std::vector<Slvs_hEntity> aCircs;
+ for (aCpIt = anEntIt->begin(); aCpIt != anEntIt->end(); ++aCpIt) {
+ const Slvs_Entity& anEntity = myStorage->getEntity(*aCpIt);
+ std::vector<Slvs_hConstraint> aNewConstr;
+ if (anEntity.type == SLVS_E_CIRCLE) {
+ aCircs.push_back(anEntity.distance);
+ // for circles we fix only center
+ aNewConstr = myStorage->fixEntity(anEntity.point[0]);
+ } else
+ aNewConstr = myStorage->fixEntity(*aCpIt);
+ mySlvsConstraints.insert(mySlvsConstraints.end(), aNewConstr.begin(), aNewConstr.end());
+ }
+
+ if (!aCircs.empty())
+ myCircsAndCopies.push_back(aCircs);
+ }
+
adjustConstraint();
}
myFeatureMap[aFIter->first] = anEntity;
}
+ // Clear list of rotated points
+ myPointsAndCopies.clear();
+
return true;
}
+void SketchSolver_ConstraintMultiRotation::addFeature(FeaturePtr theFeature)
+{
+ SketchSolver_Constraint::addFeature(theFeature);
+
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
+ if (aFeatIt == myFeatureMap.end())
+ return;
+
+ // store list of points of the feature
+ const Slvs_Entity& theEntity = myStorage->getEntity(aFeatIt->second);
+ for (int i = 0; i < 4; i++)
+ if (theEntity.point[i] != SLVS_E_UNKNOWN)
+ myPointsJustUpdated.insert(theEntity.point[i]);
+}
+
void SketchSolver_ConstraintMultiRotation::adjustConstraint()
{
if (abs(myAngle) < tolerance) {
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<Slvs_hConstraint>::iterator aConstr = mySlvsConstraints.begin();
- std::map<Slvs_hEntity, Slvs_hEntity> 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<Slvs_hConstraint>::iterator aTmpIter = aConstr;
- if (!isFirstRemoved)
- --aConstr;
- mySlvsConstraints.erase(aTmpIter);
+ std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
+ std::list<Slvs_Constraint>::const_iterator aCoIt;
+
+ // Check overconstrained on rotation center (if it is coincident with other fixed point)
+ Slvs_hConstraint aFixedCenter;
+ if (myStorage->isPointFixed(myRotationCenter, aFixedCenter, false)) {
+ Slvs_hConstraint aFixed;
+ for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt)
+ if ((aCoIt->ptA == myRotationCenter && myStorage->isPointFixed(aCoIt->ptB, aFixed, true)) ||
+ (aCoIt->ptB == myRotationCenter && myStorage->isPointFixed(aCoIt->ptA, aFixed, true))) {
+ // Un-fix the center
+ myStorage->removeConstraint(aFixedCenter);
+ std::vector<Slvs_hConstraint>::iterator aSCIt = mySlvsConstraints.begin();
+ for (; aSCIt != mySlvsConstraints.end(); ++aSCIt)
+ if (*aSCIt == aFixedCenter) {
+ mySlvsConstraints.erase(aSCIt);
+ break;
+ }
}
- // 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<Slvs_hEntity>::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
double cosA = cos(myAngle * PI / 180.0);
double sinA = sin(myAngle * PI / 180.0);
+ double aVec[2]; // coordinates of vector defining a direction from rotation center to a point
+
// Update positions of all points to satisfy angles
- std::list<Slvs_Constraint> aConstrAngle = myStorage->getConstraintsByType(SLVS_C_ANGLE);
- std::list<Slvs_Constraint>::iterator anAngIt = aConstrAngle.begin();
- std::vector<Slvs_hConstraint>::iterator aCIt;
- Slvs_hConstraint aFixed; // temporary variable
- double aVec[2]; // coordinates of vector defining a line
- Slvs_Param aTarget[2]; // parameter to be changed
- for (; anAngIt != aConstrAngle.end(); anAngIt++) {
- for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++)
- if (anAngIt->h == *aCIt)
- break;
- if (aCIt == mySlvsConstraints.end())
- continue;
- Slvs_Entity aLineA = myStorage->getEntity(anAngIt->entityA);
- Slvs_Entity aLineB = myStorage->getEntity(anAngIt->entityB);
- if (myStorage->isPointFixed(aLineB.point[1], aFixed))
- continue;
- Slvs_Entity aPointA = myStorage->getEntity(aLineA.point[1]);
- Slvs_Entity aPointB = myStorage->getEntity(aLineB.point[1]);
- for (int i = 0; i < 2; i++) {
- aVec[i] = myStorage->getParameter(aPointA.param[i]).val - aCenterXY[i];
- aTarget[i] = myStorage->getParameter(aPointB.param[i]);
+ std::vector< std::vector<Slvs_hEntity> >::const_iterator aPointsIter = myPointsAndCopies.begin();
+ std::vector<Slvs_hEntity>::const_iterator aCopyIter;
+ for (; aPointsIter != myPointsAndCopies.end(); ++aPointsIter) {
+ aCopyIter = aPointsIter->begin();
+ const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
+ for (int i = 0; i < 2; i++)
+ aVec[i] = myStorage->getParameter(anInitial.param[i]).val - aCenterXY[i];
+
+ // if the point is coincident with another one which is temporary fixed (moved by user),
+ // we will update its position correspondingly
+ Slvs_hConstraint aFixed;
+ for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt) {
+ if ((aCoIt->ptA == anInitial.h && myStorage->isPointFixed(aCoIt->ptB, aFixed, true)) ||
+ (aCoIt->ptB == anInitial.h && myStorage->isPointFixed(aCoIt->ptA, aFixed, true))) {
+ Slvs_hEntity anOtherId = aCoIt->ptA == anInitial.h ? aCoIt->ptB : aCoIt->ptA;
+ if (!myStorage->isTemporary(aFixed) &&
+ myPointsJustUpdated.find(anOtherId) == myPointsJustUpdated.end())
+ continue; // nothing to change
+
+ const Slvs_Entity& anOtherPnt = myStorage->getEntity(anOtherId);
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param anInitParam = myStorage->getParameter(anInitial.param[i]);
+ const Slvs_Param& anOtherParam = myStorage->getParameter(anOtherPnt.param[i]);
+ anInitParam.val = anOtherParam.val;
+ myStorage->updateParameter(anInitParam);
+ aVec[i] = anOtherParam.val - aCenterXY[i];
+ }
+ }
}
- aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
- aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
- myStorage->updateParameter(aTarget[0]);
- myStorage->updateParameter(aTarget[1]);
- anAngIt->valA = myAngle;
- myStorage->updateConstraint(*anAngIt);
+ // update copied points
+ aCopyIter = aPointsIter->begin();
+ for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
+ // rotate direction
+ double aTemp = aVec[0] * cosA - aVec[1] * sinA;
+ aVec[1] = aVec[0] * sinA + aVec[1] * cosA;
+ aVec[0] = aTemp;
+
+ const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter);
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]);
+ aParam.val = aCenterXY[i] + aVec[i];
+ myStorage->updateParameter(aParam);
+ }
+ }
}
- // update positions of centers of arcs for correct radius calculation
- std::list<Slvs_Constraint> aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt;
- for (anAngIt = aRadii.begin(); anAngIt != aRadii.end(); anAngIt++) {
- int aNbFound = 0; // number of arcs used in translation
- for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++)
- if (aFeatIt->second == anAngIt->entityA || aFeatIt->second == anAngIt->entityB) {
- if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID())
- aNbFound++;
- else
- break;
- }
- if (aNbFound != 2)
- continue;
- // two arcs were found, update their centers
- Slvs_Entity anArcA = myStorage->getEntity(anAngIt->entityA);
- Slvs_Entity anArcB = myStorage->getEntity(anAngIt->entityB);
- if (myStorage->isPointFixed(anArcB.point[0], aFixed))
- continue;
- Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]);
- Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]);
- for (int i = 0; i < 2; i++) {
- aVec[i] = myStorage->getParameter(aCenterA.param[i]).val - aCenterXY[i];
- aTarget[i] = myStorage->getParameter(aCenterB.param[i]);
+ for (aPointsIter = myCircsAndCopies.begin(); aPointsIter != myCircsAndCopies.end(); ++aPointsIter) {
+ aCopyIter = aPointsIter->begin();
+ const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
+ const Slvs_Param& anInitRad = myStorage->getParameter(anInitial.param[0]);
+ for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
+ const Slvs_Entity& aCopy = myStorage->getEntity(*aCopyIter);
+ Slvs_Param aCopyRad = myStorage->getParameter(aCopy.param[0]);
+ aCopyRad.val = anInitRad.val;
+ myStorage->updateParameter(aCopyRad);
}
- aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA;
- aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA;
- myStorage->updateParameter(aTarget[0]);
- myStorage->updateParameter(aTarget[1]);
}
+
+ myPointsJustUpdated.clear();
}
#include <vector>
-typedef std::vector< std::vector<Slvs_hEntity> > AuxLinesList;
-
/** \class SketchSolver_ConstraintMultiRotation
* \ingroup Plugins
* \brief Convert rotated features to the list of SolveSpace constraints
/// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+ /// \brief Adds a feature to constraint and create its analogue in SolveSpace
+ virtual void addFeature(FeaturePtr theFeature);
+
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
virtual void process();
/// \param[out] theCenter ID of central point of rotation
/// \param[out] theAngle rotation angle
/// \param[out] thePoints list of IDs of initial points and their rotated copies
- /// \param[out] theCircular list of IDs of arcs and circles and their copies
+ /// \param[out] theEntities list of IDs of entities and their rotated copies
void getAttributes(Slvs_hEntity& theCenter, double& theAngle,
- std::vector<std::vector<Slvs_hEntity> >& thePoints,
- std::vector<std::vector<Slvs_hEntity> >& theCircular);
+ std::vector< std::vector<Slvs_hEntity> >& thePoints,
+ std::vector< std::vector<Slvs_hEntity> >& theEntities);
/// \brief This method is used in derived objects to check consistence of constraint.
virtual void adjustConstraint();
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
+ std::vector< std::vector<Slvs_hEntity> > myPointsAndCopies; ///< list of initial points and their rotated copies
+ std::vector< std::vector<Slvs_hEntity> > myCircsAndCopies; ///< list of circles and their copies (to change their radii together)
+
+ std::set<Slvs_hEntity> myPointsJustUpdated; ///< list of points touched by user
};
#endif
void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
{
Slvs_Constraint anEqual;
- if (isAxisParallel(theLine)) {
+ if (myStorage->isAxisParallel(theLine.h)) {
// Fix one point and a line length
Slvs_hConstraint aFixed;
if (!myStorage->isPointFixed(theLine.point[0], aFixed, true) &&
!myStorage->isPointFixed(theLine.point[1], aFixed, true))
fixPoint(theLine.point[0]);
- if (!isUsedInEqual(theLine, anEqual)) {
+ if (!myStorage->isUsedInEqual(theLine.h, anEqual)) {
// Check the distance is not set yet
std::list<Slvs_Constraint> aDistConstr = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
std::list<Slvs_Constraint>::const_iterator aDIt = aDistConstr.begin();
}
return;
}
- else if (isUsedInEqual(theLine, anEqual)) {
+ else if (myStorage->isUsedInEqual(theLine.h, anEqual)) {
// Check another entity of Equal is already fixed
Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
if (myStorage->isEntityFixed(anOtherEntID, true)) {
bool isFixRadius = true;
// Verify the arc is under Equal constraint
Slvs_Constraint anEqual;
- if (isUsedInEqual(theCircle, anEqual)) {
+ if (myStorage->isUsedInEqual(theCircle.h, anEqual)) {
// Check another entity of Equal is already fixed
Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
if (myStorage->isEntityFixed(anOtherEntID, true))
// Verify the arc is under Equal constraint
Slvs_Constraint anEqual;
- if (isUsedInEqual(theArc, anEqual)) {
+ if (myStorage->isUsedInEqual(theArc.h, anEqual)) {
// Check another entity of Equal is already fixed
Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
if (myStorage->isEntityFixed(anOtherEntID, true)) {
}
}
}
-
-bool SketchSolver_ConstraintRigid::isUsedInEqual(
- const Slvs_Entity& theEntity, Slvs_Constraint& theEqual) const
-{
- // Check the entity is used in Equal constraint
- std::list<Slvs_Constraint> anEqualConstr = myStorage->getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
- std::list<Slvs_Constraint> anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN);
- anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
- anAddList = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS);
- anEqualConstr.insert(anEqualConstr.end(), anAddList.begin(), anAddList.end());
-
- std::list<Slvs_Constraint>::const_iterator anEqIter = anEqualConstr.begin();
- for (; anEqIter != anEqualConstr.end(); anEqIter++)
- if (anEqIter->entityA == theEntity.h || anEqIter->entityB == theEntity.h) {
- theEqual = *anEqIter;
- return true;
- }
- return false;
-}
-
-bool SketchSolver_ConstraintRigid::isAxisParallel(const Slvs_Entity& theEntity) const
-{
- std::list<Slvs_Constraint> aConstr = myStorage->getConstraintsByType(SLVS_C_HORIZONTAL);
- std::list<Slvs_Constraint> aVert = myStorage->getConstraintsByType(SLVS_C_VERTICAL);
- aConstr.insert(aConstr.end(), aVert.begin(), aVert.end());
-
- std::list<Slvs_Constraint>::const_iterator anIter = aConstr.begin();
- for (; anIter != aConstr.end(); anIter++)
- if (anIter->entityA == theEntity.h)
- return true;
- return false;
-}
/// There will be fixed start and end points and the radius of the arc.
void fixArc(const Slvs_Entity& theArc);
- /// \brief Verifies the entity is used in any equal constraint
- /// \param[in] theEntity entity to be found
- /// \param[out] theEqual constraint, which uses the entity
- /// \return \c true, if the Equal constrait is found
- bool isUsedInEqual(const Slvs_Entity& theEntity, Slvs_Constraint& theEqual) const;
-
- /// \brief Check the entity is horizontal of vertical
- bool isAxisParallel(const Slvs_Entity& theEntity) const;
-
protected:
FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
};
#include <SketchPlugin_ConstraintRigid.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_Feature.h>
+#include <SketchPlugin_MultiRotation.h>
+#include <SketchPlugin_MultiTranslation.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
if (aConstraints.empty())
return false;
std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
+ std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
for (; aCIter != aConstraints.end(); aCIter++) {
ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
!aSolConIter->first->data()->isValid())
continue;
myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
+
+ if (aSolConIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
+ aSolConIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
+ aPostponed.insert(aSolConIter->second);
+ continue;
+ }
aSolConIter->second->addFeature(theFeature);
aSolConIter->second->update();
}
+
+ // Update postponed constraints
+ std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
+ for (; aSCIter != aPostponed.end(); ++aSCIter) {
+ (*aSCIter)->addFeature(theFeature);
+ (*aSCIter)->update();
+ }
return true;
}
else {
// To avoid overconstraint situation, we will remove temporary constraints one-by-one
// and try to find the case without overconstraint
+ bool isLastChance = false;
int aNbTemp = myStorage->numberTemporary();
while (true) {
aResult = myConstrSolver.solve();
- if (aResult == SLVS_RESULT_OKAY || aNbTemp <= 0)
+ if (aResult == SLVS_RESULT_OKAY || isLastChance)
break;
- aNbTemp = myStorage->deleteTemporaryConstraint();
+ if (aNbTemp <= 0) {
+ // try to update parameters and resolve once again
+ ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
+ for (; aConstrIt != myConstraints.end(); ++aConstrIt)
+ aConstrIt->second->update();
+ isLastChance = true;
+ } else
+ aNbTemp = myStorage->deleteTemporaryConstraint();
myStorage->initializeSolver(myConstrSolver);
}
}
#include <SketchSolver_Storage.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
#include <math.h>
/** \brief Search the entity/parameter with specified ID in the list of elements
}
+std::vector<Slvs_hConstraint> SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
+{
+ std::vector<Slvs_hConstraint> aNewConstraints;
+
+ int aPos = Search(theEntity, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ switch (myEntities[aPos].type) {
+ case SLVS_E_POINT_IN_2D:
+ case SLVS_E_POINT_IN_3D:
+ fixPoint(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_LINE_SEGMENT:
+ fixLine(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_CIRCLE:
+ fixCircle(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_ARC_OF_CIRCLE:
+ fixArc(myEntities[aPos], aNewConstraints);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return aNewConstraints;
+}
+
+void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Constraint aConstraint;
+ Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
+ bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
+ bool isForceUpdate = (isFixed && isTemporary(aConstrID));
+ if (!isForceUpdate) { // create new constraint
+ if (isFixed) return;
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
+ 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = addConstraint(aConstraint);
+ theCreated.push_back(aConstraint.h);
+ } else { // update already existent constraint
+ if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
+ return;
+ int aPos = Search(aConstrID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ myConstraints[aPos].ptA = thePoint.h;
+ }
+}
+
+void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Entity aPoint[2] = {
+ getEntity(theLine.point[0]),
+ getEntity(theLine.point[1])
+ };
+
+ Slvs_Constraint anEqual;
+ if (isAxisParallel(theLine.h)) {
+ // Fix one point and a line length
+ Slvs_hConstraint aFixed;
+ if (!isPointFixed(theLine.point[0], aFixed, true) &&
+ !isPointFixed(theLine.point[1], aFixed, true))
+ fixPoint(aPoint[0], theCreated);
+ if (!isUsedInEqual(theLine.h, anEqual)) {
+ // Check the distance is not set yet
+ std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
+ for (; aDistIt != myConstraints.end(); ++aDistIt)
+ if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
+ ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
+ (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
+ return;
+ // Calculate distance between points on the line
+ double aCoords[4];
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 2; j++) {
+ Slvs_Param aParam = getParameter(aPoint[i].param[j]);
+ aCoords[2*i+j] = aParam.val;
+ }
+
+ double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) +
+ (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
+ // fix line length
+ Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
+ SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
+ theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aDistance.h = addConstraint(aDistance);
+ theCreated.push_back(aDistance.h);
+ }
+ return;
+ }
+ else if (isUsedInEqual(theLine.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true)) {
+ // Fix start point of the line (if end point is not fixed yet) ...
+ Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
+ bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
+ if (isFixed == SLVS_E_UNKNOWN)
+ fixPoint(aPoint[0], theCreated);
+ // ... and create fixed point lying on this line
+ Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
+ // Firstly, search already fixed point on line
+ bool isPonLineFixed = false;
+ Slvs_hEntity aFixedPoint;
+ std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
+ for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
+ if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
+ isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
+ aFixedPoint = aPLIter->ptA;
+ }
+
+ if (isPonLineFixed) { // update existent constraint
+ copyEntity(aPointToCopy, aFixedPoint);
+ } else { // create new constraint
+ Slvs_hEntity aCopied = copyEntity(aPointToCopy);
+ Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
+ theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
+ aPonLine.h = addConstraint(aPonLine);
+ theCreated.push_back(aPonLine.h);
+ fixPoint(getEntity(aCopied), theCreated);
+ }
+ return;
+ }
+ }
+
+ // Fix both points
+ for (int i = 0; i < 2; i++)
+ fixPoint(aPoint[i], theCreated);
+}
+
+void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ bool isFixRadius = true;
+ // Verify the arc is under Equal constraint
+ Slvs_Constraint anEqual;
+ if (isUsedInEqual(theCircle.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true))
+ isFixRadius = false;
+ }
+
+ fixPoint(getEntity(theCircle.point[0]), theCreated);
+
+ if (isFixRadius) {
+ // Search the radius is already fixed
+ std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
+ for (; aDiamIter != myConstraints.end(); ++aDiamIter)
+ if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
+ return;
+
+ // Fix radius of a circle
+ const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
+ double aRadius = getParameter(aRadEnt.param[0]).val;
+ Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
+ theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
+ aFixedR.h = addConstraint(aFixedR);
+ theCreated.push_back(aFixedR.h);
+ }
+}
+
+void SketchSolver_Storage::fixArc(const Slvs_Entity& theArc,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Entity aPoint[3] = {
+ getEntity(theArc.point[0]),
+ getEntity(theArc.point[1]),
+ getEntity(theArc.point[2])
+ };
+
+ bool isFixRadius = true;
+ std::list<Slvs_Entity> aPointsToFix;
+ aPointsToFix.push_back(aPoint[1]);
+ aPointsToFix.push_back(aPoint[2]);
+
+ // Verify the arc is under Equal constraint
+ Slvs_Constraint anEqual;
+ if (isUsedInEqual(theArc.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true)) {
+ isFixRadius = false;
+ Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
+ if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
+ aPointsToFix.pop_back();
+ aPointsToFix.push_back(aPoint[0]);
+ }
+ }
+ }
+
+ Slvs_hConstraint aConstrID;
+ int aNbPointsToFix = 2; // number of fixed points for the arc
+ if (isPointFixed(theArc.point[0], aConstrID, true))
+ aNbPointsToFix--;
+
+ double anArcPoints[3][2];
+ for (int i = 0; i < 3; i++) {
+ const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
+ for (int j = 0; j < 2; j++)
+ anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
+ }
+
+ // Radius of the arc
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
+ std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
+ double aRadius = aCenter->distance(aStart);
+
+ // Update end point of the arc to be on a curve
+ std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
+ double aDistance = anEnd->distance(aCenter);
+ std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
+ if (aDistance < tolerance)
+ aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
+ else
+ aDir = aDir->multiplied(aRadius / aDistance);
+ double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
+ const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aParam = getParameter(aEndPoint.param[i]);
+ aParam.val = xy[i];
+ updateParameter(aParam);
+ }
+
+ std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
+ for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
+ fixPoint(*aPtIt, theCreated);
+
+ if (isFixRadius) {
+ // Fix radius of the arc
+ bool isExists = false;
+ std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+ for (; anIt != myConstraints.end() && !isExists; ++anIt)
+ if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
+ isExists = true;
+ if (!isExists) {
+ Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
+ theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
+ aFixedR.h = addConstraint(aFixedR);
+ theCreated.push_back(aFixedR.h);
+ }
+ }
+}
+
+
+bool SketchSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
+{
+ std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
+ for (; anIter != myConstraints.end(); anIter++)
+ if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) &&
+ anIter->entityA == theEntity)
+ return true;
+ return false;
+}
+
+bool SketchSolver_Storage::isUsedInEqual(
+ const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
+{
+ // Check the entity is used in Equal constraint
+ std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
+ for (; anEqIter != myConstraints.end(); anEqIter++)
+ if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
+ anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
+ anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
+ (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
+ theEqual = *anEqIter;
+ return true;
+ }
+ return false;
+}
+
+
+
// ========================================================
/// \brief Check two points are coincident
bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const;
+ /// \brief Check the entity is horizontal of vertical
+ bool isAxisParallel(const Slvs_hEntity& theEntity) const;
+
+ /// \brief Verifies the entity is used in any equal constraint
+ /// \param[in] theEntity entity to be found
+ /// \param[out] theEqual constraint, which uses the entity
+ /// \return \c true, if the Equal constrait is found
+ bool isUsedInEqual(const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const;
+
+ /// \brief Fixes specified entity
+ /// \param theEntity ID of the entity to be fixed
+ /// \return List of created constraints
+ std::vector<Slvs_hConstraint> fixEntity(const Slvs_hEntity& theEntity);
+
+private:
+ /// \brief Fixes specified point
+ /// \param [in] thePoint point to be fixed
+ /// \param [out] theCreated list of the Fixed constraints created
+ void fixPoint(const Slvs_Entity& thePoint, std::vector<Slvs_hConstraint>& theCreated);
+ /// \brief Fixes specified line
+ /// \param [in] theLine line to be fixed
+ /// \param [out] theCreated list of the Fixed constraints created
+ void fixLine(const Slvs_Entity& theLine, std::vector<Slvs_hConstraint>& theCreated);
+ /// \brief Fixes specified circle
+ /// \param [in] theCircle circle to be fixed
+ /// \param [out] theCreated list of the Fixed constraints created
+ void fixCircle(const Slvs_Entity& theCircle, std::vector<Slvs_hConstraint>& theCreated);
+ /// \brief Fixes specified arc
+ /// \param [in] theArc arc to be fixed
+ /// \param [out] theCreated list of the Fixed constraints created
+ void fixArc(const Slvs_Entity& theArc, std::vector<Slvs_hConstraint>& theCreated);
+
private:
Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
std::vector<Slvs_Param> myParameters; ///< list of parameters used in the current group of constraints (sorted by the identifier)