for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
std::shared_ptr<SketchPlugin_Feature> aSFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
- if (aSFeature) {
- moveEntity(aSFeature);
+ if (aSFeature && moveEntity(aSFeature)) {
+ // Want to avoid recalculation of DoF too frequently.
+ // So, set the flag when the feature is really moved.
hasProperFeature = true;
}
}
+ if (!hasProperFeature) // in this iteration it will compute nothing, so, no problem with recursion
+ // it is important that solver flushes signal updated after processing move signal as there is
+ // optimization that relies on this update, might be found by key "optimization"
+ myIsComputed = false;
} else {
std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
break;
if (aFGrIter != aFeatureGroups.end()) {
+ hasProperFeature = true;
std::list<SketchSolver_Group*> aGroupsToResolve;
std::list<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
std::list<SketchSolver_Group*> aSeparatedGroups;
delete *aGroupIter;
std::list<SketchSolver_Group*>::iterator aRemoveIt = aGroupIter++;
myGroups.erase(aRemoveIt);
- hasProperFeature = true;
continue;
}
if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
(*aGroupIter)->splitGroup(aSeparatedGroups);
- //if (!(*aGroupIter)->getWorkplane()->string(
- // SketchPlugin_Sketch::SOLVER_ERROR())->value().empty())
+ if (!(*aGroupIter)->getWorkplane()->string(
+ SketchPlugin_Sketch::SOLVER_ERROR())->value().empty() ||
+ (*aGroupIter)->isFailed())
aGroupsToResolve.push_back(*aGroupIter);
- hasProperFeature = true;
}
aGroupIter++;
}
// Function: moveEntity
// Purpose: update element moved on the sketch, which is used by constraints
// ============================================================================
-void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
+bool SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
{
bool isMoved = false;
std::list<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
for (; aGroupIt != myGroups.end(); aGroupIt++)
- if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) {
- (*aGroupIt)->moveFeature(theFeature);
- isMoved = true;
- }
+ if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+ isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved;
if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) {
// Workaround to move arc.
// If the arc has not been constrained, we will push it into empty group and apply movement.
for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++)
if ((*aGroupIt)->isEmpty())
- (*aGroupIt)->moveFeature(theFeature);
+ isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved;
}
+ return isMoved;
}
// ============================================================================
return needToUpdate;
}
+
+// Obtain points and their copies for Mirror, Multi-Rotation and Multi-Translation constraints
+static void collectPointsAndCopies(FeaturePtr theConstraint, std::list<std::set<AttributePtr> >& thePoints)
+{
+ typedef std::list<std::string> strlist;
+ static strlist aPointAttributes(1, SketchPlugin_Point::COORD_ID());
+ static strlist aLineAttributes;
+ if (aLineAttributes.empty()) {
+ aLineAttributes.push_back(SketchPlugin_Line::START_ID());
+ aLineAttributes.push_back(SketchPlugin_Line::END_ID());
+ };
+ static strlist aCircleAttributes(1, SketchPlugin_Circle::CENTER_ID());
+ static strlist anArcAttributes;
+ if (anArcAttributes.empty()) {
+ anArcAttributes.push_back(SketchPlugin_Arc::CENTER_ID());
+ anArcAttributes.push_back(SketchPlugin_Arc::START_ID());
+ anArcAttributes.push_back(SketchPlugin_Arc::END_ID());
+ };
+
+ static std::map<std::string, strlist> aFeatureAttributes;
+ if (aFeatureAttributes.empty()) {
+ aFeatureAttributes[SketchPlugin_Point::ID()] = aPointAttributes;
+ aFeatureAttributes[SketchPlugin_Line::ID()] = aLineAttributes;
+ aFeatureAttributes[SketchPlugin_Circle::ID()] = aCircleAttributes;
+ aFeatureAttributes[SketchPlugin_Arc::ID()] = anArcAttributes;
+ }
+
+
+ std::set<AttributePtr> aPoints;
+ if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
+ AttributeRefListPtr aBaseRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
+ AttributeRefListPtr aMirrRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
+
+ std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+ std::list<ObjectPtr> aMirrList = aMirrRefList->list();
+ std::list<ObjectPtr>::const_iterator aBIt, aMIt;
+ for (aBIt = aBaseList.begin(), aMIt = aMirrList.begin();
+ aBIt != aBaseList.end() && aMIt != aMirrList.end(); ++aBIt, ++aMIt) {
+ FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aBIt);
+ FeaturePtr aMirrFeature = ModelAPI_Feature::feature(*aMIt);
+
+ strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()];
+ strlist::iterator anIt = anAttrList.begin();
+ for (; anIt != anAttrList.end(); ++anIt) {
+ aPoints.clear();
+ aPoints.insert(aBaseFeature->attribute(*anIt));
+ aPoints.insert(aMirrFeature->attribute(*anIt));
+ thePoints.push_back(aPoints);
+ }
+ }
+ }
+ else { // the "Multi" constraints
+ std::string aNbObjName;
+ if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID())
+ aNbObjName = SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID();
+ else
+ aNbObjName = SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID();
+ int aNbCopies = theConstraint->integer(aNbObjName)->value();
+
+ AttributeRefListPtr aRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
+ std::list<ObjectPtr> aFullList = aRefList->list();
+ std::list<ObjectPtr>::const_iterator anObjIt = aFullList.begin();
+ std::list<ObjectPtr>::const_iterator aCopyIt;
+ while (anObjIt != aFullList.end()) {
+ FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*anObjIt);
+ strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()];
+ strlist::iterator anIt = anAttrList.begin();
+ for (; anIt != anAttrList.end(); ++anIt) {
+ aPoints.clear();
+ aCopyIt = anObjIt;
+ for (int i = 0; i < aNbCopies; ++i, ++aCopyIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*aCopyIt);
+ aPoints.insert(aFeature->attribute(*anIt));
+ }
+ thePoints.push_back(aPoints);
+ }
+ anObjIt = aCopyIt;
+ }
+ }
+}
+
// ============================================================================
// Function: degreesOfFreedom
// Purpose: calculate DoFs for each sketch
std::list<SketchSolver_Group*>::const_iterator aGroupIt = myGroups.begin();
for (; aGroupIt != myGroups.end(); ++aGroupIt) {
CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane();
- if (!aSketch->data()->isValid()) {
+ bool isSketchValid = aSketch->data() && aSketch->data()->isValid();
+
+ if (isSketchValid) {
+ std::shared_ptr<GeomDataAPI_Dir> aNormal =
+ std::dynamic_pointer_cast<GeomDataAPI_Dir>(aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
+ isSketchValid = aNormal && aNormal->isInitialized();
+ }
+
+ if (!isSketchValid) {
myDoF.erase(aSketch);
continue;
}
if (aSketchDoF.find(aSketch) != aSketchDoF.end() || aSketchDoF[aSketch] < 0)
continue;
+ std::set<AttributePtr> aCoincidentPoints;
+ std::list<std::set<AttributePtr> > aPointsInMultiConstraints;
int aDoF = 0;
int aNbSubs = aSketch->numberOfSubs();
for (int i = 0; i < aNbSubs; ++i) {
// DoF delta in specific cases
if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
+ AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()};
for (int j = 0; j < 2; ++j) {
AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j)));
if (!aRefAttr)
continue;
bool isPoint = !aRefAttr->isObject();
- if (!isPoint) {
+ if (isPoint)
+ aCoincPoint[j] = aRefAttr->attr();
+ else {
FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object());
isPoint = anAttr && anAttr->getKind() == SketchPlugin_Point::ID();
+ if (isPoint)
+ aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID());
}
- if (isPoint)
- aDoF -= 1;
}
+ if (aCoincPoint[0] && aCoincPoint[1]) {
+ // point-point coincidence
+ if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() ||
+ aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end())
+ aDoF -= 2;
+ // check the coincident point is used in "multi" constraints
+ std::list<std::set<AttributePtr> >::const_iterator
+ aPtIt = aPointsInMultiConstraints.begin();
+ bool isFound[2] = {false, false};
+ for (; aPtIt != aPointsInMultiConstraints.end(); ++aPtIt) {
+ if ((!isFound[0] && (isFound[0] = (aPtIt->find(aCoincPoint[0]) != aPtIt->end())))
+ || (!isFound[1] && (isFound[1] = (aPtIt->find(aCoincPoint[1]) != aPtIt->end()))))
+ aCoincidentPoints.insert(aPtIt->begin(), aPtIt->end());
+ if (isFound[0] && isFound[1])
+ break;
+ }
+ } else
+ aDoF -= 1;
+ for (int j = 0; j < 2; ++j)
+ if (aCoincPoint[j])
+ aCoincidentPoints.insert(aCoincPoint[j]);
}
else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) {
AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
aDoF -= 2; // attribute is a point
else {
FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object());
- assert(anAttr);
- aDoF -= aDoFDelta[anAttr->getKind()];
+ if (anAttr)
+ aDoF -= aDoFDelta[anAttr->getKind()];
}
}
else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() ||
FeaturePtr aSub = ModelAPI_Feature::feature(*anObjIt);
aDoF -= aDoFDelta[aSub->getKind()] * aNbCopies;
}
+ // collect points and their copies for correct calculation of DoF for coincident points
+ collectPointsAndCopies(aFeature, aPointsInMultiConstraints);
}
}