#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
#include <Model_Events.h>
#include <SketchPlugin_Constraint.h>
myParams.clear();
myEntities.clear();
myConstraints.clear();
+
+ myTempConstraints.clear();
+ myTempPointWhereDragged.clear();
+ myTempPointWDrgdID = 0;
// Initialize workplane
myWorkplane.h = SLVS_E_UNKNOWN;
myEntities.clear();
myConstraints.clear();
myConstraintMap.clear();
+ myTempConstraints.clear();
+ myTempPointWhereDragged.clear();
// If the group with maximal identifier is deleted, decrease the indexer
if (myID == myGroupIndexer)
theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i])
);
if (!aCAttrRef) continue;
- if (myEntityMap.find(aCAttrRef->attr()) != myEntityMap.end())
+ if (!aCAttrRef->isFeature() &&
+ myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end())
+ return true;
+ if (aCAttrRef->isFeature() &&
+ myEntityFeatMap.find(aCAttrRef->feature()) != myEntityFeatMap.end())
return true;
}
myNeedToSolve = true;
aConstrIter->valA = aDistance;
}
+ // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter
+ if (aConstrType == SLVS_C_DIAMETER)
+ aDistance *= 2.0;
}
Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
theConstraint->data()->attribute(aConstraintAttributes[indAttr])
);
if (!aConstrAttr) continue;
- aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
+
+ // For the length constraint the start and end points of the line should be added to the entities list instead of line
+ if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare("SketchConstraintLength") == 0)
+ {
+ boost::shared_ptr<ModelAPI_Data> aData = aConstrAttr->feature()->data();
+ aConstrEnt[indAttr] = changeEntity(aData->attribute(LINE_ATTR_START));
+ aConstrEnt[indAttr+1] = changeEntity(aData->attribute(LINE_ATTR_END));
+ break; // there should be no other entities
+ }
+ else if (aConstrAttr->isFeature())
+ aConstrEnt[indAttr] = changeEntity(aConstrAttr->feature());
+ else
+ aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
}
if (aConstrMapIter == myConstraintMap.end())
{
+ // Several points may be coincident, it is not necessary to store all constraints between them.
+ // Try to find sequence of coincident points which connects the points of new constraint
+ if (aConstrType == SLVS_C_POINTS_COINCIDENT &&
+ !addCoincidentPoints(aConstrEnt[0], aConstrEnt[1]))
+ {
+ myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes
+ return false;
+ }
+
// Create SolveSpace constraint structure
Slvs_Constraint aConstraint =
Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
{
// If the entity is already in the group, try to find it
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
- aEntIter = myEntityMap.find(theEntity);
+ aEntIter = myEntityAttrMap.find(theEntity);
std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
- if (aEntIter == myEntityMap.end()) // no such entity => should be created
+ if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
aParamIter = myParams.end();
else
{ // the entity already exists
int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
aParamIter = myParams.begin() + aParamPos;
}
+ const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists
// Look over supported types of entities
Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// New entity
Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
myEntities.push_back(aPtEntity);
- myEntityMap[theEntity] = aPtEntity.h;
+ myEntityAttrMap[theEntity] = aPtEntity.h;
return aPtEntity.h;
}
Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// New entity
Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
myEntities.push_back(aPt2DEntity);
- myEntityMap[theEntity] = aPt2DEntity.h;
+ myEntityAttrMap[theEntity] = aPt2DEntity.h;
return aPt2DEntity.h;
}
{
Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter);
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// New entity
Slvs_Entity aDistance = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue);
myEntities.push_back(aDistance);
- myEntityMap[theEntity] = aDistance.h;
+ myEntityAttrMap[theEntity] = aDistance.h;
return aDistance.h;
}
+ /// \todo Other types of entities
+
+ // Unsupported or wrong entity type
+ return SLVS_E_UNKNOWN;
+}
+
+
+// ============================================================================
+// Function: changeEntity
+// Class: SketchSolver_ConstraintGroup
+// Purpose: create/update the element defined by the feature affected by any constraint
+// ============================================================================
+Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(
+ boost::shared_ptr<ModelAPI_Feature> theEntity)
+{
+ // If the entity is already in the group, try to find it
+ std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::const_iterator
+ aEntIter = myEntityFeatMap.find(theEntity);
+ // defines that the entity already exists
+ const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end());
+
// SketchPlugin features
- boost::shared_ptr<SketchPlugin_Feature> aFeature =
+ boost::shared_ptr<SketchPlugin_Feature> aFeature;
boost::dynamic_pointer_cast<SketchPlugin_Feature>(theEntity);
if (aFeature)
{ // Verify the feature by its kind
Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(LINE_ATTR_START));
Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(LINE_ATTR_END));
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// New entity
Slvs_Entity aLineEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd);
myEntities.push_back(aLineEntity);
- myEntityMap[theEntity] = aLineEntity.h;
+ myEntityFeatMap[theEntity] = aLineEntity.h;
return aLineEntity.h;
}
// Circle
Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_CENTER));
Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_RADIUS));
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// New entity
Slvs_Entity aCircleEntity =
Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, myWorkplane.normal, aRadius);
myEntities.push_back(aCircleEntity);
- myEntityMap[theEntity] = aCircleEntity.h;
+ myEntityFeatMap[theEntity] = aCircleEntity.h;
return aCircleEntity.h;
}
// Arc
Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(ARC_ATTR_START));
Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(ARC_ATTR_END));
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
Slvs_Entity anArcEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID,
myWorkplane.h, myWorkplane.normal, aCenter, aStart, aEnd);
myEntities.push_back(anArcEntity);
- myEntityMap[theEntity] = anArcEntity.h;
+ myEntityFeatMap[theEntity] = anArcEntity.h;
return anArcEntity.h;
}
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
{
Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(POINT_ATTR_COORD));
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (isEntExists)
return aEntIter->second;
// Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
- myEntityMap[theEntity] = aPoint;
+ myEntityFeatMap[theEntity] = aPoint;
return aPoint;
}
}
- /// \todo Other types of entities
+ /// \todo Other types of features
// Unsupported or wrong entity type
return SLVS_E_UNKNOWN;
// Try to find existent normal
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
- aEntIter = myEntityMap.find(theNorm);
+ aEntIter = myEntityAttrMap.find(theNorm);
std::vector<Slvs_Param>::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise
- if (aEntIter == myEntityMap.end()) // no such entity => should be created
+ if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created
aParamIter = myParams.end();
else
{ // the entity already exists, update it
for (int i = 0; i < 4; i++)
aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
- if (aEntIter != myEntityMap.end()) // the entity already exists
+ if (aEntIter != myEntityAttrMap.end()) // the entity already exists
return aEntIter->second;
// Create a normal
Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
myEntities.push_back(aNormal);
- myEntityMap[theNorm] = aNormal.h;
+ myEntityAttrMap[theNorm] = aNormal.h;
return aNormal.h;
}
myConstrSolver.setParameters(myParams);
myConstrSolver.setEntities(myEntities);
myConstrSolver.setConstraints(myConstraints);
+ myConstrSolver.setDraggedParameters(myTempPointWhereDragged);
- if (myConstrSolver.solve() == SLVS_RESULT_OKAY)
+ int aResult = myConstrSolver.solve();
+ if (aResult == SLVS_RESULT_OKAY)
{ // solution succeeded, store results into correspondent attributes
// Obtain result into the same list of parameters
if (!myConstrSolver.getResult(myParams))
return;
+ // We should go through the attributes map, because only attributes have valued parameters
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- anEntIter = myEntityMap.begin();
- for ( ; anEntIter != myEntityMap.end(); anEntIter++)
+ anEntIter = myEntityAttrMap.begin();
+ for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++)
updateAttribute(anEntIter->first, anEntIter->second);
}
/// \todo Implement error handling
if (theGroup.myConstraintMap.empty())
return ;
- // NOTE: The possibility, that some elements are placed into both groups, is around 0,
- // so the objects should be copied with changing the indexes
-
- // Maps between old and new indexes of SolveSpace elements:
- std::map<Slvs_hParam, Slvs_hParam> aParamMap;
- std::map<Slvs_hEntity, Slvs_hEntity> anEntityMap;
+ // Map between old and new indexes of SolveSpace constraints
std::map<Slvs_hConstraint, Slvs_hConstraint> aConstrMap;
- // Go through copying constraints
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = theGroup.myConstraints.begin();
- for ( ; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
+ // Add all constraints from theGroup to the current group
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+ aConstrIter = theGroup.myConstraintMap.begin();
+ for ( ; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++)
+ if (changeConstraint(aConstrIter->first))
+ aConstrMap[aConstrIter->second] = myConstrMaxID; // the constraint was added => store its ID
+
+ // Add temporary constraints from theGroup
+ std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
+ for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++)
{
- Slvs_Constraint aConstraintCopy = *aConstrIter;
- // Go through constraint entities
- Slvs_hEntity* anEntities[CONSTRAINT_ATTR_SIZE] = {
- &(aConstraintCopy.ptA), &(aConstraintCopy.ptB),
- &(aConstraintCopy.entityA), &(aConstraintCopy.entityB)
- };
- for (int indEnt = 0; indEnt < CONSTRAINT_ATTR_SIZE; indEnt++)
- {
- if (*(anEntities[indEnt]) == 0)
- continue;
- if (anEntityMap.find(*(anEntities[indEnt])) != anEntityMap.end())
- { // entity is already copied
- *(anEntities[indEnt]) = anEntityMap[*(anEntities[indEnt])];
- continue;
- }
+ std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(*aTempConstrIter);
+ if (aFind != aConstrMap.end())
+ myTempConstraints.push_back(aFind->second);
+ }
- // Copy entity
- Slvs_Entity anEntityCopy = theGroup.myEntities[Search(*(anEntities[indEnt]), theGroup.myEntities)];
- // Go through entity parameters
- const int aNbEntParams = 4; // maximal number of entity parameters
- for (int indPrm = 0; indPrm < aNbEntParams; indPrm++)
+ if (myTempPointWhereDragged.empty())
+ myTempPointWhereDragged = theGroup.myTempPointWhereDragged;
+ else if (!theGroup.myTempPointWhereDragged.empty())
+ { // Need to create additional transient constraint
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+ aFeatureIter = theGroup.myEntityAttrMap.begin();
+ for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++)
+ if (aFeatureIter->second == myTempPointWDrgdID)
{
- if (anEntityCopy.param[indPrm] == 0)
- continue;
- if (aParamMap.find(anEntityCopy.param[indPrm]) != aParamMap.end())
- {
- anEntityCopy.param[indPrm] = aParamMap[anEntityCopy.param[indPrm]];
- continue;
- }
-
- Slvs_Param aParamCopy = theGroup.myParams[Search(anEntityCopy.param[indPrm], theGroup.myParams)];
- aParamMap[aParamCopy.h] = ++myParamMaxID;
- aParamCopy.h = myParamMaxID;
- myParams.push_back(aParamCopy);
+ addTemporaryConstraintWhereDragged(aFeatureIter->first);
+ break;
}
-
- anEntityMap[anEntityCopy.h] = ++myEntityMaxID;
- anEntityCopy.h = myEntityMaxID;
- myEntities.push_back(anEntityCopy);
- *(anEntities[indEnt]) = anEntityCopy.h;
- }
-
- aConstraintCopy.h = ++myConstrMaxID;
- myConstraints.push_back(aConstraintCopy);
- aConstrMap[aConstrIter->h] = aConstraintCopy.h;
}
- // Append maps of SketchPlugin to SolveSpace parameters
- std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
- aSPConstrMapIter = theGroup.myConstraintMap.begin();
- for ( ; aSPConstrMapIter!= theGroup.myConstraintMap.end(); aSPConstrMapIter++)
+ myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
+}
+
+// ============================================================================
+// Function: splitGroup
+// Class: SketchSolver_ConstraintGroup
+// Purpose: divide the group into several subgroups
+// ============================================================================
+void SketchSolver_ConstraintGroup::splitGroup(std::vector<SketchSolver_ConstraintGroup*>& theCuts)
+{
+ // Divide constraints and entities into several groups
+ std::vector< std::set<Slvs_hEntity> > aGroupsEntities;
+ std::vector< std::set<Slvs_hConstraint> > aGroupsConstr;
+ int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current)
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
{
- std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(aSPConstrMapIter->second);
- if (aFind != aConstrMap.end())
- myConstraintMap[aSPConstrMapIter->first] = aFind->second;
+ Slvs_hEntity aConstrEnt[] = {
+ aConstrIter->ptA, aConstrIter->ptB,
+ aConstrIter->entityA, aConstrIter->entityB};
+ std::vector<int> anIndexes;
+ // Go through the groupped entities and find even one of entities of current constraint
+ std::vector< std::set<Slvs_hEntity> >::iterator aGrEntIter;
+ for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++)
+ {
+ bool isFound = false;
+ for (int i = 0; i < 4 && !isFound; i++)
+ if (aConstrEnt[i] != 0)
+ isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end());
+ if (isFound)
+ anIndexes.push_back(aGrEntIter - aGroupsEntities.begin());
+ }
+ // Add new group if no one is found
+ if (anIndexes.empty())
+ {
+ std::set<Slvs_hEntity> aNewGrEnt;
+ for (int i = 0; i < 4; i++)
+ if (aConstrEnt[i] != 0)
+ aNewGrEnt.insert(aConstrEnt[i]);
+ std::set<Slvs_hConstraint> aNewGrConstr;
+ aNewGrConstr.insert(aConstrIter->h);
+
+ aGroupsEntities.push_back(aNewGrEnt);
+ aGroupsConstr.push_back(aNewGrConstr);
+ if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size())
+ aMaxNbEntities = aGroupsEntities.size() - 1;
+ }
+ else if (anIndexes.size() == 1)
+ { // Add entities indexes into the found group
+ aGrEntIter = aGroupsEntities.begin() + anIndexes.front();
+ for (int i = 0; i < 4; i++)
+ if (aConstrEnt[i] != 0)
+ aGrEntIter->insert(aConstrEnt[i]);
+ aGroupsConstr[anIndexes.front()].insert(aConstrIter->h);
+ if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size())
+ aMaxNbEntities = aGrEntIter - aGroupsEntities.begin();
+ }
+ else
+ { // There are found several connected groups, merge them
+ std::vector< std::set<Slvs_hEntity> >::iterator aFirstGroup =
+ aGroupsEntities.begin() + anIndexes.front();
+ std::vector< std::set<Slvs_hConstraint> >::iterator aFirstConstr =
+ aGroupsConstr.begin() + anIndexes.front();
+ std::vector<int>::iterator anInd = anIndexes.begin();
+ for (++anInd; anInd != anIndexes.end(); anInd++)
+ {
+ aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end());
+ aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end());
+ }
+ if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size())
+ aMaxNbEntities = anIndexes.front();
+ // Remove merged groups
+ for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--)
+ {
+ aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd));
+ aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd));
+ }
+ }
}
- std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
- aSPEntMapIter = theGroup.myEntityMap.begin();
- for ( ; aSPEntMapIter != theGroup.myEntityMap.end(); aSPEntMapIter++) {
- std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFind = anEntityMap.find(aSPEntMapIter->second);
- if (aFind != anEntityMap.end())
- myEntityMap[aSPEntMapIter->first] = aFind->second;
- }
+ if (aGroupsEntities.size() <= 1)
+ return ;
- // Add temporary constraints
- std::list<Slvs_hConstraint>::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin();
- for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++)
+ // Remove the group with maximum elements as it will be left in the current group
+ aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities);
+ aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities);
+
+ // Add new groups of constraints and divide current group
+ std::vector<SketchSolver_ConstraintGroup*> aNewGroups;
+ for (int i = aGroupsEntities.size(); i > 0; i--)
{
- std::map<Slvs_hConstraint, Slvs_hConstraint>::iterator aFind = aConstrMap.find(*aTempConstrIter);
- if (aFind != aConstrMap.end())
- myTempConstraints.push_back(aFind->second);
+ SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch);
+ aNewGroups.push_back(aG);
+ }
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+ aConstrMapIter = myConstraintMap.begin();
+ int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint)
+ while (aConstrMapIter != myConstraintMap.end())
+ {
+ std::vector< std::set<Slvs_hConstraint> >::const_iterator aGIter = aGroupsConstr.begin();
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroup = aNewGroups.begin();
+ for ( ; aGIter != aGroupsConstr.end(); aGIter++, aGroup++)
+ if (aGIter->find(aConstrMapIter->second) != aGIter->end())
+ {
+ (*aGroup)->changeConstraint(aConstrMapIter->first);
+ removeConstraint(aConstrMapIter->first);
+ // restore iterator
+ aConstrMapIter = myConstraintMap.begin();
+ for (int i = 0; i < aConstrMapPos; i++)
+ aConstrMapIter++;
+ break;
+ }
+ if (aGIter == aGroupsConstr.end())
+ {
+ aConstrMapIter++;
+ aConstrMapPos++;
+ }
}
- myTempConstraints.sort();
- myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve;
+ theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end());
}
// ============================================================================
// ============================================================================
bool SketchSolver_ConstraintGroup::updateGroup()
{
- // Check for valid sketch
- if (!mySketch->data()->isValid())
- return true;
-
- // Fast check for constraint validity. If all constraints are valid, no need to update the group
std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
aConstrIter = myConstraintMap.rbegin();
bool isAllValid = true;
- for ( ; isAllValid && aConstrIter != myConstraintMap.rend(); aConstrIter++)
- if (!aConstrIter->first->data()->isValid())
- isAllValid = false;
- if (isAllValid)
- return false;
-
- // Remove invalid constraints.
- // There only constraint will be deleted (parameters and entities) will be removed below
- std::list< boost::shared_ptr<SketchPlugin_Constraint> > aConstrToDelete;
- std::map<Slvs_hEntity, bool> anEntToDelete; // entities will be removed if no valid constraints use them
- for (aConstrIter = myConstraintMap.rbegin(); aConstrIter != myConstraintMap.rend(); aConstrIter++)
+ bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed
+ while (isAllValid && aConstrIter != myConstraintMap.rend())
{
- bool isValid = aConstrIter->first->data()->isValid();
-
- int aConstrPos = Search(aConstrIter->second, myConstraints);
- if (aConstrPos < (int)myConstraints.size())
+ if (!aConstrIter->first->data()->isValid())
{
- Slvs_hEntity aConstrEnt[] = {
- myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
- myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB};
- for (int i = 0; i < 4; i++)
- if (aConstrEnt[i] != SLVS_E_UNKNOWN)
- {
- if (anEntToDelete.find(aConstrEnt[i]) == anEntToDelete.end())
- anEntToDelete[aConstrEnt[i]] = !isValid;
- else if (isValid) // constraint is valid => no need to remove its entities
- anEntToDelete[aConstrEnt[i]] = false;
- }
- if (!isValid)
- {
- myConstraints.erase(myConstraints.begin() + aConstrPos);
- if (aConstrIter->second == myConstrMaxID) // When the constraint with highest ID is removed, decrease indexer
- myConstrMaxID--;
- aConstrToDelete.push_front(aConstrIter->first);
- }
+ if (aConstrIter->first->getKind().compare("SketchConstraintCoincidence") == 0)
+ isCCRemoved = true;
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::reverse_iterator
+ aCopyIter = aConstrIter++;
+ removeConstraint(aCopyIter->first);
+ isAllValid = false;
}
+ else aConstrIter++;
}
- std::list< boost::shared_ptr<SketchPlugin_Constraint> >::iterator aDelIter;
- for (aDelIter = aConstrToDelete.begin(); aDelIter != aConstrToDelete.end(); aDelIter++)
- myConstraintMap.erase(*aDelIter);
- // Remove invalid and unused entities
- std::map<Slvs_hEntity, bool>::reverse_iterator aEDelIter;
- for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++)
- if (aEDelIter->second)
- {
- int anEntPos = Search(aEDelIter->first, myEntities);
- std::vector<Slvs_Entity>::iterator aEntIter = myEntities.begin() + anEntPos;
- // Number of parameters for the entity
- int aNbParams = 0;
- while (aEntIter->param[aNbParams]) aNbParams++;
- if (aNbParams == 0) continue;
- // Decrease parameter indexer if there are deleted parameter with higher IDs
- if (aEntIter->param[aNbParams-1] == myParamMaxID)
- myParamMaxID -= aNbParams;
- // Remove parameters of the entity
- int aParamPos = Search(aEntIter->param[0], myParams);
- myParams.erase(myParams.begin() + aParamPos,
- myParams.begin() + aParamPos + aNbParams);
-
- // Remove entity
- if (aEDelIter->first == myEntityMaxID)
- myEntityMaxID--;
- myEntities.erase(myEntities.begin() + anEntPos);
- // Remove such entity from myEntityMap
- std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
- anEntMapIter = myEntityMap.begin();
- for ( ; anEntMapIter != myEntityMap.end(); anEntMapIter++)
- if (anEntMapIter->second == aEDelIter->first)
- break;
- if (anEntMapIter != myEntityMap.end())
- myEntityMap.erase(anEntMapIter);
- }
+ // Probably, need to update coincidence constraints
+ if (isCCRemoved && !myExtraCoincidence.empty())
+ {
+ // Make a copy, because the new list of unused constrtaints will be generated
+ std::set< boost::shared_ptr<SketchPlugin_Constraint> > anExtraCopy = myExtraCoincidence;
+ myExtraCoincidence.clear();
+
+ std::set< boost::shared_ptr<SketchPlugin_Constraint> >::iterator
+ aCIter = anExtraCopy.begin();
+ for ( ; aCIter != anExtraCopy.end(); aCIter++)
+ if ((*aCIter)->data()->isValid())
+ changeConstraint(*aCIter);
+ }
- return false;
+ return !isAllValid;
}
// ============================================================================
void SketchSolver_ConstraintGroup::updateEntityIfPossible(
boost::shared_ptr<ModelAPI_Attribute> theEntity)
{
- if (myEntityMap.find(theEntity) != myEntityMap.end())
+ if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end())
{
// If the attribute is a point and it is changed (the group needs to rebuild),
// probably user has dragged this point into this position,
{
// Find identifier of the entity
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
- anEntIter = myEntityMap.find(theEntity);
+ anEntIter = myEntityAttrMap.find(theEntity);
+ if (anEntIter == myEntityAttrMap.end())
+ return ;
+
+ // If this is a first dragged point, its parameters should be placed
+ // into Slvs_System::dragged field to avoid system inconsistense
+ if (myTempPointWhereDragged.empty())
+ {
+ int anEntPos = Search(anEntIter->second, myEntities);
+ Slvs_hParam* aDraggedParam = myEntities[anEntPos].param;
+ for (int i = 0; i < 4; i++, aDraggedParam++)
+ if (*aDraggedParam != 0)
+ myTempPointWhereDragged.push_back(*aDraggedParam);
+ myTempPointWDrgdID = myEntities[anEntPos].h;
+ return ;
+ }
- // Create SLVS_C_WHERE_DRAGGED constraint
+ // Get identifiers of all dragged points
+ std::set<Slvs_hEntity> aDraggedPntID;
+ aDraggedPntID.insert(myTempPointWDrgdID);
+ std::list<Slvs_hConstraint>::iterator aTmpCoIter = myTempConstraints.begin();
+ for ( ; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++)
+ {
+ unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints);
+ if (aConstrPos < myConstraints.size())
+ aDraggedPntID.insert(myConstraints[aConstrPos].ptA);
+ }
+ // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED
+ std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+ for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+ {
+ if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end())
+ continue; // the entity was not found in current set
+
+ // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points
+ std::set<Slvs_hEntity>::const_iterator aDrgIter = aDraggedPntID.begin();
+ for ( ; aDrgIter != aDraggedPntID.end(); aDrgIter++)
+ if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end())
+ return ; // the SLVS_C_WHERE_DRAGGED constraint already exists
+ }
+
+ // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty
Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
myConstraints.push_back(aWDConstr);
std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
{
- int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+ unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+ if (aConstrPos >= myConstraints.size())
+ continue;
myConstraints.erase(myConstraints.begin() + aConstrPos);
// If the removing constraint has higher index, decrease the indexer
myConstrMaxID--;
}
myTempConstraints.clear();
+
+ // Clear basic dragged point
+ myTempPointWhereDragged.clear();
+}
+
+// ============================================================================
+// Function: removeConstraint
+// Class: SketchSolver_ConstraintGroup
+// Purpose: remove constraint and all unused entities
+// ============================================================================
+void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::iterator
+ anIterToRemove = myConstraintMap.find(theConstraint);
+ if (anIterToRemove == myConstraintMap.end())
+ return ;
+
+ Slvs_hConstraint aCnstrToRemove = anIterToRemove->second;
+ // Remove constraint from the map
+ myConstraintMap.erase(anIterToRemove);
+
+ // Find unused entities
+ int aConstrPos = Search(aCnstrToRemove, myConstraints);
+ std::set<Slvs_hEntity> anEntToRemove;
+ Slvs_hEntity aCnstEnt[] = {myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB,
+ myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB};
+ for (int i = 0; i < 4; i++)
+ if (aCnstEnt[i] != 0)
+ anEntToRemove.insert(aCnstEnt[i]);
+ myConstraints.erase(myConstraints.begin() + aConstrPos);
+ if (aCnstrToRemove == myConstrMaxID)
+ myConstrMaxID--;
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for ( ; aConstrIter != myConstraints.end(); aConstrIter++)
+ {
+ Slvs_hEntity aEnts[] = {aConstrIter->ptA, aConstrIter->ptB,
+ aConstrIter->entityA, aConstrIter->entityB};
+ for (int i = 0; i < 4; i++)
+ if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end())
+ anEntToRemove.erase(aEnts[i]);
+ }
+
+ if (anEntToRemove.empty())
+ return ;
+
+ // Remove unused entities
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
+ anEntAttrIter = myEntityAttrMap.begin();
+ while (anEntAttrIter != myEntityAttrMap.end())
+ {
+ if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end())
+ {
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
+ aRemovedIter = anEntAttrIter;
+ anEntAttrIter++;
+ myEntityAttrMap.erase(aRemovedIter);
+ }
+ else anEntAttrIter++;
+ }
+ std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+ anEntFeatIter = myEntityFeatMap.begin();
+ while (anEntFeatIter != myEntityFeatMap.end())
+ {
+ if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end())
+ {
+ std::map<boost::shared_ptr<ModelAPI_Feature>, Slvs_hEntity>::iterator
+ aRemovedIter = anEntFeatIter;
+ anEntFeatIter++;
+ myEntityFeatMap.erase(aRemovedIter);
+ }
+ else anEntFeatIter++;
+ }
+ std::set<Slvs_hEntity>::const_reverse_iterator aRemIter = anEntToRemove.rbegin();
+ for ( ; aRemIter != anEntToRemove.rend(); aRemIter++)
+ {
+ unsigned int anEntPos = Search(*aRemIter, myEntities);
+ if (anEntPos >= myEntities.size())
+ continue;
+ unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams);
+ if (aParamPos >= myParams.size())
+ continue;
+ int aNbParams = 0;
+ while (myEntities[anEntPos].param[aNbParams] != 0)
+ aNbParams++;
+ if (myEntities[anEntPos].param[aNbParams-1] == myParamMaxID)
+ myParamMaxID -= aNbParams;
+ myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams);
+ if (*aRemIter == myEntityMaxID)
+ myEntityMaxID--;
+ myEntities.erase(myEntities.begin() + anEntPos);
+
+ // Remove entity's ID from the lists of conincident points
+ std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+ for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++)
+ aCoPtIter->erase(*aRemIter);
+ }
+ if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty())
+ myCoincidentPoints.clear();
+}
+
+
+// ============================================================================
+// Function: addCoincidentPoints
+// Class: SketchSolver_ConstraintGroup
+// Purpose: add coincident point the appropriate list of such points
+// ============================================================================
+bool SketchSolver_ConstraintGroup::addCoincidentPoints(
+ const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
+{
+ std::vector< std::set<Slvs_hEntity> >::iterator aCoPtIter = myCoincidentPoints.begin();
+ std::vector< std::set<Slvs_hEntity> >::iterator aFirstFound = myCoincidentPoints.end();
+ while (aCoPtIter != myCoincidentPoints.end())
+ {
+ bool isFound[2] = { // indicate which point ID was already in coincidence constraint
+ aCoPtIter->find(thePoint1) != aCoPtIter->end(),
+ aCoPtIter->find(thePoint2) != aCoPtIter->end(),
+ };
+ if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one
+ return false;
+ if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1]))
+ {
+ if (aFirstFound != myCoincidentPoints.end())
+ { // there are two groups of coincident points connected by created constraint => merge them
+ int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin();
+ int aCurrentShift = aCoPtIter - myCoincidentPoints.begin();
+ aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end());
+ myCoincidentPoints.erase(aCoPtIter);
+ aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift;
+ aCoPtIter = myCoincidentPoints.begin() + aCurrentShift;
+ continue;
+ }
+ else
+ {
+ aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1);
+ aFirstFound = aCoPtIter;
+ }
+ }
+ aCoPtIter++;
+ }
+ // No points were found, need to create new set
+ if (aFirstFound == myCoincidentPoints.end())
+ {
+ std::set<Slvs_hEntity> aNewSet;
+ aNewSet.insert(thePoint1);
+ aNewSet.insert(thePoint2);
+ myCoincidentPoints.push_back(aNewSet);
+ }
+
+ return true;
}
+
// ========================================================
// ========= Auxiliary functions ===============
// ========================================================