#include <SketchSolver_Storage.h>
+#include <math.h>
+
/** \brief Search the entity/parameter with specified ID in the list of elements
* \param[in] theEntityID unique ID of the element
* \param[in] theEntities list of elements
myEntityMaxID(SLVS_E_UNKNOWN),
myConstrMaxID(SLVS_C_UNKNOWN),
myFixed(SLVS_E_UNKNOWN),
- myNeedToResolve(false)
+ myNeedToResolve(false),
+ myDuplicatedConstraint(false)
{
}
bool aResult = true;
int aPos = Search(theEntityID, myEntities);
if (aPos >= 0 && aPos < (int)myEntities.size()) {
- // Firstly, check the entity is not used elsewhere
+ // Firstly, check the entity and its attributes is not used elsewhere
+ std::set<Slvs_hEntity> anEntAndSubs;
+ anEntAndSubs.insert(theEntityID);
+ for (int i = 0; i < 4; i++)
+ if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
+ anEntAndSubs.insert(myEntities[aPos].point[i]);
+
std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
for (; anEntIter != myEntities.end(); anEntIter++) {
for (int i = 0; i < 4; i++)
- if (anEntIter->point[i] == theEntityID)
+ if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
return false;
- if (anEntIter->distance == theEntityID)
+ if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
return false;
}
std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
aConstrIter->entityA, aConstrIter->entityB,
aConstrIter->entityC, aConstrIter->entityD};
for (int i = 0; i < 6; i++)
- if (anEntIDs[i] == theEntityID)
+ if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
return false;
}
// The entity is not used, remove it and its parameters
// Entity is not found, return empty object
static Slvs_Entity aDummy;
- aDummy.h = 0;
+ aDummy.h = SLVS_E_UNKNOWN;
return aDummy;
}
-Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const
+Slvs_hEntity SketchSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
+{
+ int aPos = Search(theCopied, myEntities);
+ if (aPos < 0 || aPos >= (int)myEntities.size())
+ return SLVS_E_UNKNOWN;
+
+ Slvs_Entity aCopy = myEntities[aPos];
+ aCopy.h = SLVS_E_UNKNOWN;
+ int i = 0;
+ while (aCopy.point[i] != SLVS_E_UNKNOWN) {
+ aCopy.point[i] = copyEntity(aCopy.point[i]);
+ i++;
+ }
+ if (aCopy.param[0] != SLVS_E_UNKNOWN) {
+ aPos = Search(aCopy.param[0], myParameters);
+ i = 0;
+ while (aCopy.param[i] != SLVS_E_UNKNOWN) {
+ Slvs_Param aNewParam = myParameters[aPos];
+ aNewParam.h = SLVS_E_UNKNOWN;
+ aCopy.param[i] = addParameter(aNewParam);
+ i++;
+ aPos++;
+ }
+ }
+ return addEntity(aCopy);
+}
+
+void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
+{
+ int aPosFrom = Search(theFrom, myEntities);
+ int aPosTo = Search(theTo, myEntities);
+ if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() ||
+ aPosTo < 0 || aPosTo >= (int)myEntities.size())
+ return;
+
+ Slvs_Entity aEntFrom = myEntities[aPosFrom];
+ Slvs_Entity aEntTo = myEntities[aPosTo];
+ int i = 0;
+ while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
+ copyEntity(aEntFrom.point[i], aEntTo.point[i]);
+ i++;
+ }
+ if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
+ aPosFrom = Search(aEntFrom.param[0], myParameters);
+ aPosTo = Search(aEntTo.param[0], myParameters);
+ i = 0;
+ while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
+ myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
+ i++;
+ }
+ }
+}
+
+
+bool SketchSolver_Storage::isPointFixed(
+ const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
{
// Search the set of coincident points
+ std::set<Slvs_hEntity> aCoincident;
+ aCoincident.insert(thePointID);
std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
- if (aCPIter->find(thePointID) != aCPIter->end())
+ if (aCPIter->find(thePointID) != aCPIter->end()) {
+ aCoincident = *aCPIter;
break;
- if (aCPIter == myCoincidentPoints.end()) {
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aConstrIter->ptA == thePointID)
- return aConstrIter->h;
- return SLVS_E_UNKNOWN;
- }
+ }
// Search the Rigid constraint
std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
for (; aConstrIter != myConstraints.end(); aConstrIter++)
if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCPIter->find(aConstrIter->ptA) != aCPIter->end())
- return aConstrIter->h;
+ aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
+ theFixed = aConstrIter->h;
+ return true;
+ }
+
+ if (theAccurate) {
+ // Try to find the fixed entity which uses such point or its coincidence
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++) {
+ Slvs_hEntity aPt = anEntIter->point[i];
+ if (aPt != SLVS_E_UNKNOWN &&
+ (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
+ if (isEntityFixed(anEntIter->h, true))
+ return true;
+ }
+ }
+ }
+ }
return SLVS_E_UNKNOWN;
}
+bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
+{
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos < 0 || aPos >= (int)myEntities.size())
+ return false;
+
+ // Firstly, find how many points are under Rigid constraint
+ int aNbFixed = 0;
+ for (int i = 0; i < 4; i++) {
+ Slvs_hEntity aPoint = myEntities[aPos].point[i];
+ if (aPoint == SLVS_E_UNKNOWN)
+ continue;
+
+ std::set<Slvs_hEntity> aCoincident;
+ aCoincident.insert(aPoint);
+ std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
+ for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
+ if (aCPIter->find(aPoint) != aCPIter->end()) {
+ aCoincident = *aCPIter;
+ break;
+ }
+
+ // Search the Rigid constraint
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+ aCoincident.find(aConstrIter->ptA) != aCoincident.end())
+ aNbFixed++;
+ }
+
+ std::list<Slvs_Constraint> aList;
+ std::list<Slvs_Constraint>::iterator anIt;
+ Slvs_hConstraint aTempID; // used in isPointFixed() method
+
+ if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
+ if (aNbFixed == 2)
+ return true;
+ else if (aNbFixed == 0 || !theAccurate)
+ return false;
+ // Additional check (the line may be fixed if it is used by different constraints):
+ // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
+ aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
+ break;
+ if (anIt != aList.end()) {
+ aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ }
+ // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
+ aList = getConstraintsByType(SLVS_C_PARALLEL);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ break;
+ }
+ if (anIt != aList.end()) {
+ aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
+ (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
+ return true;
+ }
+ // 3. Another verifiers ...
+ } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
+ if (aNbFixed == 0)
+ return false;
+ // Search for Diameter constraint
+ aList = getConstraintsByType(SLVS_C_DIAMETER);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID)
+ return true;
+ if (!theAccurate)
+ return false;
+ // Additional check (the circle may be fixed if it is used by different constraints):
+ // 1. The circle is used in Equal constraint and another entity is fixed
+ aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ // 2. Another verifiers ...
+ } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
+ if (aNbFixed > 2)
+ return true;
+ else if (aNbFixed <= 1)
+ return false;
+ // Search for Diameter constraint
+ aList = getConstraintsByType(SLVS_C_DIAMETER);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID)
+ return true;
+ if (!theAccurate)
+ return false;
+ // Additional check (the arc may be fixed if it is used by different constraints):
+ // 1. The arc is used in Equal constraint and another entity is fixed
+ aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ // 2. Another verifiers ...
+ }
+ return false;
+}
+
Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
{
}
Slvs_Constraint aConstraint = theConstraint;
+
+ // Find a constraint with same type uses same arguments to show user overconstraint situation
+ std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); aCIt++) {
+ if (aConstraint.type != aCIt->type)
+ continue;
+ if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+ aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+ aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
+ myDuplicatedConstraint = true;
+ }
+
if (aConstraint.h > myConstrMaxID)
myConstrMaxID = aConstraint.h;
else
// remove temporary fixed point, if available
if (myFixed == theConstraintID)
myFixed = SLVS_E_UNKNOWN;
+ if (myDuplicatedConstraint) {
+ // Check the duplicated constraints are still available
+ myDuplicatedConstraint = false;
+ std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
+ std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
+ for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
+ for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
+ if (anIt1->type != anIt2->type)
+ continue;
+ if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
+ anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
+ anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
+ myDuplicatedConstraint = true;
+ }
+ }
}
return aResult;
}
return aDummy;
}
-void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
+{
+ std::list<Slvs_Constraint> aResult;
+ std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (aCIter->type == theConstraintType)
+ aResult.push_back(*aCIter);
+ return aResult;
+}
+
+
+void SketchSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
{
if (myFixed != SLVS_E_UNKNOWN)
return; // the point is already fixed
myFixed = theConstraintID;
}
+void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ myTemporaryConstraints.insert(theConstraintID);
+}
+
+void SketchSolver_Storage::removeTemporaryConstraints()
+{
+ myTemporaryConstraints.clear();
+}
+
+int SketchSolver_Storage::deleteTemporaryConstraint()
+{
+ if (myTemporaryConstraints.empty())
+ return 0;
+ // Search the point-on-line or a non-rigid constraint
+ std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
+ for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
+ int aPos = Search(*aCIt, myConstraints);
+ if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
+ break;
+ std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+ for (; anIt != myConstraints.end(); anIt++)
+ if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
+ break;
+ if (anIt != myConstraints.end())
+ break;
+ }
+ if (aCIt == myTemporaryConstraints.end())
+ aCIt = myTemporaryConstraints.begin();
+ bool aNewFixed = (*aCIt == myFixed);
+ removeConstraint(*aCIt);
+ myTemporaryConstraints.erase(aCIt);
+ if (aNewFixed) {
+ for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
+ int aPos = Search(*aCIt, myConstraints);
+ if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
+ myFixed = *aCIt;
+ break;
+ }
+ }
+ }
+ return (int)myTemporaryConstraints.size();
+}
+
+bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
+{
+ return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
+}
+
+
void SketchSolver_Storage::getRemoved(
std::set<Slvs_hParam>& theParameters,
std::set<Slvs_hEntity>& theEntities,
for (; aCIter != myCoincidentPoints.end(); aCIter++)
if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
return true;
+ // precise checking of coincidence
+ int aEnt1Pos = Search(thePoint1, myEntities);
+ int aEnt2Pos = Search(thePoint2, myEntities);
+ if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
+ aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
+ double aDist[2];
+ int aParamPos;
+ for (int i = 0; i < 2; i++) {
+ aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
+ aDist[i] = myParameters[aParamPos].val;
+ aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
+ aDist[i] -= myParameters[aParamPos].val;
+ }
+ if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
+ return true;
+ }
return false;
}
aResIndex--;
while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
aResIndex++;
- if (aResIndex == -1)
+ if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
aResIndex = aVecSize;
return aResIndex;
}