+ // perform update of everything if it is not performed right now or any preview is blocked
+ if (!myIsProcessed && !myIsPreviewBlocked) {
+ myIsProcessed = true;
+ #ifdef DEB_UPDATE
+ std::cout<<"****** Start processing"<<std::endl;
+ #endif
+
+ while(!myModified.empty()) {
+ processFeature(myModified.begin()->first);
+ }
+ myIsProcessed = false;
+
+ // to update the object browser if something is updated/created during executions
+ static Events_Loop* aLoop = Events_Loop::loop();
+ static const Events_ID kCreatedEvent= aLoop->eventByName(EVENT_OBJECT_CREATED);
+ aLoop->flush(kCreatedEvent);
+ static const Events_ID kUpdatedEvent = aLoop->eventByName(EVENT_OBJECT_UPDATED);
+ aLoop->flush(kUpdatedEvent);
+
+ // flush to update display
+ if (theFlushRedisplay) {
+ static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ aLoop->flush(EVENT_DISP);
+ }
+ #ifdef DEB_UPDATE
+ std::cout<<"****** End processing"<<std::endl;
+ #endif
+ myProcessed.clear();
+ }
+}
+
+// collects all the features this feature depends on: reasons
+static void allReasons(FeaturePtr theFeature, std::set<FeaturePtr>& theReasons) {
+ std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aDeps;
+ theFeature->data()->referencesToObjects(aDeps);
+ std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >::iterator
+ anAttrsIter = aDeps.begin();
+ for(; anAttrsIter != aDeps.end(); anAttrsIter++) {
+ if (theFeature->attribute(anAttrsIter->first)->isArgument()) {
+ std::list<std::shared_ptr<ModelAPI_Object> >::iterator aDepIter = anAttrsIter->second.begin();
+ for(; aDepIter != anAttrsIter->second.end(); aDepIter++) {
+ FeaturePtr aDepFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(*aDepIter);
+ if (!aDepFeat.get()) { // so, it depends on the result and process the feature owner of it
+ ResultPtr aDepRes = std::dynamic_pointer_cast<ModelAPI_Result>(*aDepIter);
+ if (aDepRes.get()) {
+ aDepFeat = (*aDepIter)->document()->feature(aDepRes);
+ }
+ }
+ if (aDepFeat.get() && aDepFeat->data()->isValid()) {
+ theReasons.insert(aDepFeat);
+ }
+ }
+ }
+ }
+ if (theFeature->getKind() == "Part") {
+ // part is not depended on its subs directly, but subs must be iterated anyway
+ CompositeFeaturePtr aPart = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+ int aNum = aPart->numberOfSubs();
+ for(int a = 0; a < aNum; a++) {
+ FeaturePtr aSub = aPart->subFeature(a);
+ if (aSub.get() && aSub->data()->isValid()) {
+ theReasons.insert(aSub);
+ }
+ }
+ }
+}
+
+bool Model_Update::processFeature(FeaturePtr theFeature)
+{
+ 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;