// Author: Artem ZHIDKOV
#include "SketchSolver_Manager.h"
+#include "SketchSolver_Error.h"
#include <Events_Loop.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_Object.h>
#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeString.h>
#include <SketchPlugin_Constraint.h>
+#include <SketchPlugin_ConstraintAngle.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCollinear.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMiddle.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+#include <SketchPlugin_MultiRotation.h>
+#include <SketchPlugin_MultiTranslation.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Sketch.h>
#include <SketchPlugin_Feature.h>
+#include <assert.h>
#include <list>
#include <set>
#include <memory>
+#include <sstream>
+
+static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
// Initialization of constraint manager self pointer
SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
+
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED));
}
SketchSolver_Manager::~SketchSolver_Manager()
void SketchSolver_Manager::processEvent(
const std::shared_ptr<Events_Message>& theMessage)
{
+ checkConflictingConstraints(theMessage);
if (myIsComputed)
return;
myIsComputed = true;
+
+ // Shows that the message has at least one feature applicable for solver
+ bool hasProperFeature = false;
+
if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
|| theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
|| theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
- // Shows the message has at least one feature applicable for solver
- bool hasProperFeature = false;
+ bool isUpdateFlushed = stopSendUpdate();
bool isMovedEvt = theMessage->eventID()
== Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
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();
}
}
+ bool needToUpdate = false;
// Solve the set of constraints
if (hasProperFeature)
- resolveConstraints(isMovedEvt); // send update for movement in any case
+ needToUpdate = resolveConstraints();
+
+ // Features may be updated => now send events, but for all changed at once
+ if (isUpdateFlushed)
+ allowSendUpdate();
+ // send update for movement in any case
+ if (needToUpdate || isMovedEvt)
+ Events_Loop::loop()->flush(anUpdateEvent);
+
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
break;
if (aFGrIter != aFeatureGroups.end()) {
- std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+ hasProperFeature = true;
+ std::list<SketchSolver_Group*> aGroupsToResolve;
+ std::list<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
std::list<SketchSolver_Group*> aSeparatedGroups;
while (aGroupIter != myGroups.end()) {
if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
delete *aGroupIter;
- int aShift = aGroupIter - myGroups.begin();
- myGroups.erase(aGroupIter);
- aGroupIter = myGroups.begin() + aShift;
+ std::list<SketchSolver_Group*>::iterator aRemoveIt = aGroupIter++;
+ myGroups.erase(aRemoveIt);
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() ||
+ (*aGroupIter)->isFailed())
+ aGroupsToResolve.push_back(*aGroupIter);
}
aGroupIter++;
}
- if (aSeparatedGroups.size() > 0)
+ if (aSeparatedGroups.size() > 0) {
myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
+ aGroupsToResolve.insert(aGroupsToResolve.end(),
+ aSeparatedGroups.begin(), aSeparatedGroups.end());
+ }
+
+ if (!aGroupsToResolve.empty())
+ resolveConstraints(aGroupsToResolve);
}
}
+
+ if (hasProperFeature)
+ degreesOfFreedom();
myIsComputed = false;
}
+void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptr<Events_Message>& theMessage)
+{
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_SOLVER_REPAIRED)) {
+ std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
+ std::dynamic_pointer_cast<ModelAPI_SolverFailedMessage>(theMessage);
+ std::set<ObjectPtr> aSentObjs = aMessage->objects();
+ if (!aSentObjs.empty()) {
+ // Obtain sketch where the constraints are placed.
+ // It is enough to check only one constraint.
+ CompositeFeaturePtr aSketch;
+ FeaturePtr aConstraint = ModelAPI_Feature::feature(*aSentObjs.begin());
+ std::list<SketchSolver_Group*>::const_iterator aGrIt = myGroups.begin();
+ for (; aGrIt != myGroups.end(); ++aGrIt)
+ if ((*aGrIt)->isInteract(aConstraint)) {
+ aSketch = (*aGrIt)->getWorkplane();
+ break;
+ }
+
+ // Search failed groups built on the same sketch
+ if (aSketch) {
+ for (aGrIt = myGroups.begin(); aGrIt != myGroups.end(); ++aGrIt) {
+ SketchSolver_Group* aGroup = *aGrIt;
+ if (aGroup->isBaseWorkplane(aSketch) && aGroup->isFailed() &&
+ !aGroup->isInteract(aConstraint)) {
+ // reset error message on the sketch
+ aGroup->getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(
+ SketchSolver_Error::CONSTRAINTS());
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
// ============================================================================
// Function: changeWorkplane
// Purpose: update workplane by given parameters of the sketch
bool aResult = true; // changed when a workplane wrongly updated
bool isUpdated = false;
// Try to update specified workplane in all groups
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ std::list<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
isUpdated = true;
return true;
} else if (aGroups.size() == 1) { // Only one group => add feature into it
GroupID aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ std::list<SketchSolver_Group*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if ((*aGroupIter)->getId() == aGroupId) {
// If the group is empty, the feature is not added (the constraint only)
std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
// Search first group
- std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
+ std::list<SketchSolver_Group*>::iterator aFirstGroupIter;
for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
if ((*aFirstGroupIter)->getId() == *aGroupsIter)
break;
return false;
// Append other groups to the first one
- std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ std::list<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter;
+ ++anOtherGroupIter;
for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
if ((*anOtherGroupIter)->getId() == *aGroupsIter)
break;
if (anOtherGroupIter == myGroups.end()) { // Group disappears
- anOtherGroupIter = aFirstGroupIter + 1;
+ anOtherGroupIter = aFirstGroupIter;
+ ++anOtherGroupIter;
continue;
}
(*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
- int aShiftFirst = aFirstGroupIter - myGroups.begin();
- int aShiftOther = anOtherGroupIter - myGroups.begin();
- delete *anOtherGroupIter;
- myGroups.erase(anOtherGroupIter);
- aFirstGroupIter = myGroups.begin() + aShiftFirst;
- anOtherGroupIter = myGroups.begin() + aShiftOther;
+ std::list<SketchSolver_Group*>::iterator aRemoveIt = anOtherGroupIter++;
+ delete *aRemoveIt;
+ myGroups.erase(aRemoveIt);
}
if (aConstraint)
- return (*aFirstGroupIter)->changeConstraint(aConstraint);
- return (*aFirstGroupIter)->updateFeature(theFeature);
+ (*aFirstGroupIter)->changeConstraint(aConstraint);
+ else
+ (*aFirstGroupIter)->updateFeature(theFeature);
+ // groups are merged => need to resolve them
+ return true;
}
// Something goes wrong
// 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)
{
- std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+ 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 = (*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())
+ isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved;
+ }
+ return isMoved;
}
// ============================================================================
std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
- std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+ std::list<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
if (!(*aGroupIter)->isEmpty())
// Already verified workplanes
std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
- std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+ std::list<SketchSolver_Group*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
if (aVerified.find(aWP) != aVerified.end())
// Function: resolveConstraints
// Purpose: change entities according to available constraints
// ============================================================================
-void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate)
+bool SketchSolver_Manager::resolveConstraints(const std::list<SketchSolver_Group*>& theGroups)
{
- //myIsComputed = true;
bool needToUpdate = false;
- static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ const std::list<SketchSolver_Group*>& aGroupsToResolve = theGroups.empty() ? myGroups : theGroups;
+ std::list<SketchSolver_Group*>::const_iterator aGroupIter = aGroupsToResolve.begin();
+ for (; aGroupIter != aGroupsToResolve.end(); aGroupIter++)
+ if ((*aGroupIter)->resolveConstraints())
+ needToUpdate = true;
+ 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
+// ============================================================================
+void SketchSolver_Manager::degreesOfFreedom()
+{
+ static std::map<std::string, int> aDoFDelta; // indicates how many DoF adds or decreases a feature
+ static bool isNeedInit = true;
+ if (isNeedInit) {
+ aDoFDelta[SketchPlugin_Point::ID()] = 2;
+ aDoFDelta[SketchPlugin_Line::ID()] = 4;
+ aDoFDelta[SketchPlugin_Circle::ID()] = 3;
+ aDoFDelta[SketchPlugin_Arc::ID()] = 5;
+
+ aDoFDelta[SketchPlugin_ConstraintAngle::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintCollinear::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintDistance::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintEqual::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintHorizontal::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintLength::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintMiddle::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintParallel::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintPerpendicular::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintRadius::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintTangent::ID()] = -1;
+ aDoFDelta[SketchPlugin_ConstraintVertical::ID()] = -1;
+
+ isNeedInit = false;
+ }
+
+ std::map<CompositeFeaturePtr, int> aSketchDoF;
+
+ std::list<SketchSolver_Group*>::const_iterator aGroupIt = myGroups.begin();
+ for (; aGroupIt != myGroups.end(); ++aGroupIt) {
+ CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane();
+ 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;
+ }
+
+ // check conflicting constraints in the group
+ if ((*aGroupIt)->isFailed())
+ aSketchDoF[aSketch] = -1;
+ // check the sketch is already processed
+ 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) {
+ FeaturePtr aFeature = aSketch->subFeature(i);
+ // check DoF delta for invariant types
+ std::map<std::string, int>::const_iterator aFound = aDoFDelta.find(aFeature->getKind());
+ if (aFound != aDoFDelta.end()) {
+ aDoF += aFound->second;
+ continue;
+ }
+
+ // 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)
+ 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 (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>(
+ aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ assert(aRefAttr);
+ if (!aRefAttr->isObject())
+ aDoF -= 2; // attribute is a point
+ else {
+ FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object());
+ if (anAttr)
+ aDoF -= aDoFDelta[anAttr->getKind()];
+ }
+ }
+ else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() ||
+ aFeature->getKind() == SketchPlugin_MultiRotation::ID() ||
+ aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) {
+ int aNbCopies = 1;
+ std::string anAttrName;
+ if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID())
+ anAttrName = SketchPlugin_Constraint::ENTITY_B();
+ else {
+ if (aFeature->getKind() == SketchPlugin_MultiRotation::ID())
+ aNbCopies = aFeature->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1;
+ else if (aFeature->getKind() == SketchPlugin_MultiTranslation::ID())
+ aNbCopies = aFeature->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1;
+ anAttrName = SketchPlugin_Constraint::ENTITY_A();
+ }
+
+ AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ aFeature->attribute(anAttrName));
+ std::list<ObjectPtr> anObjList = aRefListOfShapes->list();
+ std::list<ObjectPtr>::const_iterator anObjIt = anObjList.begin();
+ for (; anObjIt != anObjList.end(); ++anObjIt) {
+ 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);
+ }
+ }
+
+ aSketchDoF[aSketch] = aDoF;
+ }
+
+ // Check the degrees of freedom are changed
+ std::map<CompositeFeaturePtr, int>::const_iterator aDoFIt = aSketchDoF.begin();
+ std::map<CompositeFeaturePtr, int>::iterator aFound;
+ for (; aDoFIt != aSketchDoF.end(); ++aDoFIt) {
+ if (aDoFIt->second < 0)
+ continue; // conflicting constraints on the current sketch
+ aFound = myDoF.find(aDoFIt->first);
+ if (aFound != myDoF.end() && aFound->second == aDoFIt->second)
+ continue; // nothing is changed
+ myDoF[aDoFIt->first] = aDoFIt->second;
+ // change attribute value
+ std::ostringstream aStream;
+ if (aDoFIt->second == 0)
+ aStream << "Sketch fully fixed (DOF = " << aDoFIt->second << ")";
+ else
+ aStream << "DOF (degree of freedom) = " << aDoFIt->second;
+ aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStream.str());
+ }
+}
+
+bool SketchSolver_Manager::stopSendUpdate() const
+{
// to avoid redisplay of each segment on update by solver one by one in the viewer
bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
if (isUpdateFlushed) {
Events_Loop::loop()->setFlushed(anUpdateEvent, false);
}
+ return isUpdateFlushed;
+}
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if ((*aGroupIter)->resolveConstraints())
- needToUpdate = true;
-
- // Features may be updated => now send events, but for all changed at once
- if (isUpdateFlushed) {
- Events_Loop::loop()->setFlushed(anUpdateEvent, true);
- }
- // Must be before flush because on "Updated" flush the results may be produced
- // and the creation event is appeared with many new objects. If myIsComputed these
- // events are missed in processEvents and some elements are not added.
- //myIsComputed = false;
- if (needToUpdate || theForceUpdate)
- Events_Loop::loop()->flush(anUpdateEvent);
+void SketchSolver_Manager::allowSendUpdate() const
+{
+ Events_Loop::loop()->setFlushed(anUpdateEvent, true);
}