+ static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
+
+ if (!theFeature->data()->isValid()) { // deleted feature, just remove from all containers
+ if (myModified.find(theFeature) != myModified.end())
+ myModified.erase(theFeature);
+ return false;
+ }
+
+ if (theFeature->isPersistentResult()) {
+ if (!std::dynamic_pointer_cast<Model_Document>((theFeature)->document())->executeFeatures())
+ return false;
+ }
+
+ if (myProcessed.find(theFeature) == myProcessed.end()) {
+ myProcessed[theFeature] = 0;
+ } else {
+ int aCount = myProcessed[theFeature];
+ if (aCount > 100) {
+ // too many repetition of processing (in VS it may crash on 330 with stack overflow)
+ Events_InfoMessage("Model_Update",
+ "Feature '%1' is updated in infinitive loop").arg(theFeature->data()->name()).send();
+ // to stop iteration
+ myModified.clear();
+ return false;
+ }
+ myProcessed[theFeature] = aCount + 1;
+ }
+
+ // check this feature is not yet checked or processed
+ bool aIsModified = myModified.find(theFeature) != myModified.end();
+ if (!aIsModified && myIsFinish) { // get info about the modification for features without preview
+ if (theFeature->data()->execState() == ModelAPI_StateMustBeUpdated) {
+ aIsModified = true;
+ std::set<std::shared_ptr<ModelAPI_Feature> > aNewSet;
+ // contains itself, so, we don't know which was the reason and the reason is any
+ aNewSet.insert(theFeature);
+ myModified[theFeature] = aNewSet;
+ }
+ }
+
+#ifdef DEB_UPDATE
+ std::cout<<"* Process feature "<<theFeature->name()<<std::endl;
+#endif
+
+ // update the sketch plane before the sketch sub-elements are recomputed
+ // (otherwise sketch will update plane, modify subs, after executed, but with old subs edges)
+ if (aIsModified && theFeature->getKind() == "Sketch") {
+#ifdef DEB_UPDATE
+ std::cout << "****** Update sketch args " << theFeature->name() << std::endl;
+#endif
+ AttributeSelectionPtr anExtSel = theFeature->selection("External");
+ if (anExtSel.get()) {
+ ResultPtr aContext = anExtSel->context();
+ if (aContext.get() && aContext->document().get()) {
+ FeaturePtr anExtBase = aContext->document()->feature(aContext);
+ if (anExtBase.get()) {
+ processFeature(anExtBase);
+ }
+ std::shared_ptr<GeomDataAPI_Point> anOrigin =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theFeature->attribute("Origin"));
+ double anOX = anOrigin->x(), anOY = anOrigin->y(), anOZ = anOrigin->z();
+ std::shared_ptr<GeomDataAPI_Dir> aDir =
+ std::dynamic_pointer_cast<GeomDataAPI_Dir>(theFeature->attribute("DirX"));
+ double aDX = aDir->x(), aDY = aDir->y(), aDZ = aDir->z();
+ std::shared_ptr<GeomDataAPI_Dir> aNorm =
+ std::dynamic_pointer_cast<GeomDataAPI_Dir>(theFeature->attribute("Norm"));
+ double aNX = aNorm->x(), aNY = aNorm->y(), aNZ = aNorm->z();
+ // update sketch plane
+ updateArguments(theFeature);
+ theFeature->attributeChanged("External"); // to recompute origin, direction and normal
+ // check it is updated, so all must be changed
+ if (anOrigin->x() != anOX || anOrigin->y() != anOY || anOrigin->z() != anOZ ||
+ aDir->x() != aDX || aDir->y() != aDY || aDir->z() != aDZ ||
+ aNorm->x() != aNX || aNorm->y() != aNY || aNorm->z() != aNZ)
+ {
+ std::set<FeaturePtr> aWholeR;
+ allReasons(theFeature, aWholeR);
+ std::set<FeaturePtr>::iterator aRIter = aWholeR.begin();
+ for (; aRIter != aWholeR.end(); aRIter++) {
+ if ((*aRIter)->data()->selection("External").get())
+ (*aRIter)->attributeChanged("External");
+ }
+ }
+ }
+ }
+ }
+
+ if (!aIsModified) { // no modification is needed
+ return false;
+ }
+
+ // evaluate parameter before the sub-elements update:
+ // it updates dependencies on evaluation (#1085)
+ if (theFeature->getKind() == "Parameter") {
+ theFeature->execute();
+ }
+
+ bool isReferencedInvalid = false;
+ // check all features this feature depended on (recursive call of updateFeature)
+ std::set<FeaturePtr>& aReasons = myModified[theFeature];
+ bool allSubsUsed = aReasons.find(theFeature) != aReasons.end();
+ if (allSubsUsed) {
+ // add all subs in aReasons and temporary remove "theFeature" to avoid processing itself
+ allReasons(theFeature, aReasons);
+ aReasons.erase(theFeature);
+ }
+ // take reasons one by one (they may be added during the feature process
+ // (circle by the radius of sketch)
+ std::set<FeaturePtr> aProcessedReasons;
+ while(!aReasons.empty()) {
+ FeaturePtr aReason = *(aReasons.begin());
+#ifdef DEB_UPDATE
+ //cout<<theFeature->name()<<" process next reason "<<aReason->name()<<endl;
+#endif
+ if (aReason != theFeature && (aReason)->data()->isValid()) {
+ if (processFeature(aReason))
+ aIsModified = true;
+ // check validity of aReason once again because it may be removed by dependent feature
+ // (e.g. by SketchPlugin_IntersectionPoint)
+ if (!aReason->data()->isValid() ||
+ aReason->data()->execState() == ModelAPI_StateInvalidArgument)
+ isReferencedInvalid = true;
+ }
+ // searching for the next not used reason
+ aProcessedReasons.insert(aReason);
+ // check theFeature is still in the list of modified, because it may be removed sometimes
+ // while updating SketchPlugin_Ellipse
+ if (myModified.find(theFeature) != myModified.end())
+ aReasons.erase(aReason);
+ else
+ break;
+ }
+ // restore the modified reasons: they will be used in the update of arguments
+ if (allSubsUsed) { // restore theFeature in this set
+ aProcessedReasons.insert(theFeature);
+ }
+ myModified[theFeature] = aProcessedReasons;
+
+ // do not execute the composite that contains the current
+ bool isPostponedMain = false;
+ CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+ if (theFeature->getKind() == "ExtrusionSketch" && aCompos.get()) {
+ CompositeFeaturePtr aCurrentOwner =
+ ModelAPI_Tools::compositeOwner(theFeature->document()->currentFeature(false));
+ isPostponedMain = aCurrentOwner.get() && aCompos->isSub(aCurrentOwner);
+ } else if (theFeature->getKind() == "Sketch" &&
+ std::dynamic_pointer_cast<Model_Document>((theFeature)->document())->executeFeatures()) {
+ // send event that sketch is prepared to be recomputed
+ static Events_ID anID = Events_Loop::eventByName("SketchPrepared");
+ std::shared_ptr<Events_Message> aMsg(new Events_Message(anID, this));
+ Events_Loop* aLoop = Events_Loop::loop();
+ // in case it is finish operation, flush for the sketch other events (#2450)
+ aLoop->flush(aLoop->eventByName(EVENT_OBJECT_UPDATED));
+ aLoop->send(aMsg);
+ // check that sub-elements of sketch are updated => sketch must be re-processed
+ std::set<FeaturePtr> aWholeR;
+ allReasons(theFeature, aWholeR);
+ std::set<FeaturePtr>::iterator aRIter = aWholeR.begin();
+ for(; aRIter != aWholeR.end(); aRIter++) {
+ if (myModified.find(*aRIter) != myModified.end()) {
+ processFeature(theFeature);
+ return true;