Salome HOME
Issue #2027 Sketcher Trim Feature
[modules/shaper.git] / src / ModelAPI / ModelAPI_Tools.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        ModelAPI_Tools.cpp
4 // Created:     06 Aug 2014
5 // Author:      Vitaly Smetannikov
6
7 #include "ModelAPI_Tools.h"
8 #include <ModelAPI_Session.h>
9 #include <ModelAPI_Document.h>
10 #include <ModelAPI_Object.h>
11 #include <ModelAPI_AttributeDouble.h>
12 #include <ModelAPI_ResultParameter.h>
13 #include <ModelAPI_ResultPart.h>
14 #include <ModelAPI_AttributeDocRef.h>
15 #include <ModelAPI_Validator.h>
16 #include <list>
17 #include <map>
18 #include <iostream>
19
20 #include <Events_Loop.h>
21 #include <ModelAPI_Events.h>
22
23 #define RECURSE_TOP_LEVEL 50
24
25 //#define DEBUG_REMOVE_FEATURES
26 //#define DEBUG_REMOVE_FEATURES_RECURSE
27 //#define DEBUG_CYCLING_1550
28
29 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
30 #include <sstream>
31 std::string getFeatureInfo(FeaturePtr theFeature)
32 {
33   if (!theFeature.get())
34     return "";
35   //std::ostringstream aPtrStr;
36   //aPtrStr << "[" << theFeature.get() << "] ";
37   std::string aFeatureInfo = /*aPtrStr.str() + */theFeature->name();
38   CompositeFeaturePtr aComposite = ModelAPI_Tools::compositeOwner(theFeature);
39   if (aComposite.get()) {
40       aFeatureInfo = aFeatureInfo + "[in " + aComposite->name() + "]";
41   }
42   return aFeatureInfo;
43 }
44 #endif
45
46 #ifdef DEBUG_REMOVE_FEATURES
47 void printMapInfo(const std::map<FeaturePtr, std::set<FeaturePtr> >& theMainList,
48                   const std::string& thePrefix)
49 {
50   std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = theMainList.begin(),
51                                                               aMainLast = theMainList.end();
52   std::string anInfo;
53   for (; aMainIt != aMainLast; aMainIt++) {
54     FeaturePtr aMainListFeature = aMainIt->first;
55     std::set<FeaturePtr> aMainRefList = aMainIt->second;
56     std::set<FeaturePtr>::const_iterator anIt = aMainRefList.begin(), aLast = aMainRefList.end();
57     std::string aRefsInfo;
58     for (; anIt != aLast; anIt++) {
59       aRefsInfo += (*anIt)->name().c_str();
60       if (anIt != aLast)
61         aRefsInfo += ", ";
62     }
63     if (!aRefsInfo.empty()) {
64       anInfo = anInfo + aMainListFeature->name().c_str() + ": " + aRefsInfo + "\n";
65     }
66   }
67   std::cout << thePrefix.c_str() << " [feature: references to]: \n" << anInfo.c_str() << std::endl;
68 }
69
70 void printListInfo(const std::set<FeaturePtr>& theMainList,
71                   const std::string& thePrefix)
72 {
73   std::set<FeaturePtr>::const_iterator aMainIt = theMainList.begin(),
74                                        aMainLast = theMainList.end();
75   std::string anInfo;
76   for (; aMainIt != aMainLast; aMainIt++) {
77     FeaturePtr aRefFeature = *aMainIt;
78     anInfo += aRefFeature->name().c_str();
79     if (aMainIt != aMainLast)
80       anInfo += ", ";
81   }
82   std::cout << thePrefix.c_str() << ": " << anInfo.c_str() << std::endl;
83 }
84 #endif
85
86 namespace ModelAPI_Tools {
87
88 std::shared_ptr<GeomAPI_Shape> shape(const ResultPtr& theResult)
89 {
90   return theResult->shape();
91 }
92
93 void shapesOfType(const FeaturePtr& theFeature,
94                   const GeomAPI_Shape::ShapeType& theType,
95                   std::set<ResultPtr>& theShapeResults)
96 {
97   theShapeResults.clear();
98   std::list<ResultPtr> aResults = theFeature->results();
99   std::list<ResultPtr>::const_iterator aRIter = aResults.cbegin();
100   for (; aRIter != aResults.cend(); aRIter++) {
101     ResultPtr aResult = *aRIter;
102     GeomShapePtr aShape = aResult->shape();
103     if (aShape.get() && aShape->shapeType() == theType)
104       theShapeResults.insert(aResult);
105   }
106 }
107
108 const char* toString(ModelAPI_ExecState theExecState)
109 {
110 #define TO_STRING(__NAME__) case __NAME__: return #__NAME__;
111   switch (theExecState) {
112   TO_STRING(ModelAPI_StateDone)
113   TO_STRING(ModelAPI_StateMustBeUpdated)
114   TO_STRING(ModelAPI_StateExecFailed)
115   TO_STRING(ModelAPI_StateInvalidArgument)
116   TO_STRING(ModelAPI_StateNothing)
117   default: return "Unknown ExecState.";
118   }
119 #undef TO_STRING
120 }
121
122 std::string getFeatureError(const FeaturePtr& theFeature)
123 {
124   std::string anError;
125   if (!theFeature.get() || !theFeature->data()->isValid() || theFeature->isAction())
126     return anError;
127
128   // to be removed later, this error should be got from the feature
129   if (theFeature->data()->execState() == ModelAPI_StateDone ||
130       theFeature->data()->execState() == ModelAPI_StateMustBeUpdated)
131     return anError;
132
133   // set error indication
134   anError = theFeature->error();
135   if (anError.empty()) {
136     bool isDone = ( theFeature->data()->execState() == ModelAPI_StateDone
137                  || theFeature->data()->execState() == ModelAPI_StateMustBeUpdated );
138     if (!isDone) {
139       anError = toString(theFeature->data()->execState());
140       // If the feature is Composite and error is StateInvalidArgument,
141       // error text should include error of first invalid sub-feature. Otherwise
142       // it is not clear what is the reason of the invalid argument.
143       if (theFeature->data()->execState() == ModelAPI_StateInvalidArgument) {
144         CompositeFeaturePtr aComposite =
145                     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
146         if (aComposite) {
147           for (int i = 0, aSize = aComposite->numberOfSubs(); i < aSize; i++) {
148             FeaturePtr aSubFeature = aComposite->subFeature(i);
149             std::string aSubFeatureError = getFeatureError(aSubFeature);
150             if (!aSubFeatureError.empty()) {
151               anError = anError + " in " + aSubFeature->getKind() + ".\n" + aSubFeatureError;
152               break;
153             }
154           }
155         }
156       }
157     }
158   }
159
160   return anError;
161 }
162
163 ObjectPtr objectByName(const DocumentPtr& theDocument, const std::string& theGroup,
164                        const std::string& theName)
165 {
166   for (int anIndex = 0; anIndex < theDocument->size(theGroup); ++anIndex) {
167     ObjectPtr anObject = theDocument->object(theGroup, anIndex);
168     if (anObject->data()->name() == theName)
169       return anObject;
170   }
171   // not found
172   return ObjectPtr();
173 }
174
175 bool findVariable(const DocumentPtr& theDocument, FeaturePtr theSearcher,
176                   const std::string& theName, double& outValue, ResultParameterPtr& theParam)
177 {
178   ObjectPtr aParamObj = objectByName(theDocument, ModelAPI_ResultParameter::group(), theName);
179   theParam = std::dynamic_pointer_cast<ModelAPI_ResultParameter>(aParamObj);
180   if (!theParam.get())
181     return false;
182   // avoid usage of parameters created later than the initial parameter
183   if (theSearcher.get() && theDocument->isLater(theDocument->feature(theParam), theSearcher))
184     return false;
185   AttributeDoublePtr aValueAttribute = theParam->data()->real(ModelAPI_ResultParameter::VALUE());
186   outValue = aValueAttribute->value();
187   return true;
188 }
189
190 bool findVariable(FeaturePtr theSearcher, const std::string& theName, double& outValue,
191                   ResultParameterPtr& theParam, const DocumentPtr& theDocument)
192 {
193   SessionPtr aSession = ModelAPI_Session::get();
194   std::list<DocumentPtr> aDocList;
195   DocumentPtr aDocument = theDocument.get() ? theDocument : aSession->activeDocument();
196   if (findVariable(aDocument, theSearcher, theName, outValue, theParam))
197     return true;
198   DocumentPtr aRootDocument = aSession->moduleDocument();
199   if (aDocument != aRootDocument) {
200     // any parameters in PartSet is okindependently on the Part position (issu #1504)
201     if (findVariable(aRootDocument, FeaturePtr(), theName, outValue, theParam))
202       return true;
203   }
204   return false;
205 }
206
207 ResultPtr findPartResult(const DocumentPtr& theMain, const DocumentPtr& theSub)
208 {
209   // to optimize and avoid of crash on partset document close
210   // (don't touch the sub-document structure)
211   if (theMain != theSub) {
212     for (int a = theMain->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) {
213       ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(
214           theMain->object(ModelAPI_ResultPart::group(), a));
215       if (aPart && aPart->data()->document(ModelAPI_ResultPart::DOC_REF())->value() == theSub) {
216         return aPart;
217       }
218     }
219   }
220   return ResultPtr();
221 }
222
223 FeaturePtr findPartFeature(const DocumentPtr& theMain, const DocumentPtr& theSub)
224 {
225   // to optimize and avoid of crash on partset document close
226   // (don't touch the sub-document structure)
227   if (theMain != theSub) {
228     // iteration from top to bottom to avoid finding the movement documents before the original
229     int aSize = theMain->size(ModelAPI_Feature::group());
230     for (int a = 0; a < aSize; a++) {
231       FeaturePtr aPartFeat = std::dynamic_pointer_cast<ModelAPI_Feature>(
232           theMain->object(ModelAPI_Feature::group(), a));
233       if (aPartFeat.get()) {
234         const std::list<std::shared_ptr<ModelAPI_Result> >& aResList = aPartFeat->results();
235         std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResList.begin();
236         for(; aRes != aResList.end(); aRes++) {
237           ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRes);
238           if (aPart.get()) {
239             if (aPart->isActivated() && aPart->partDoc() == theSub)
240               return aPartFeat;
241           } else break; // if the first is not Part, others are also not
242         }
243       }
244     }
245   }
246   return FeaturePtr();
247 }
248
249 CompositeFeaturePtr compositeOwner(const FeaturePtr& theFeature)
250 {
251   if (theFeature.get() && theFeature->data()->isValid()) {
252     const std::set<std::shared_ptr<ModelAPI_Attribute> >& aRefs = theFeature->data()->refsToMe();
253     std::set<std::shared_ptr<ModelAPI_Attribute> >::const_iterator aRefIter = aRefs.begin();
254     for(; aRefIter != aRefs.end(); aRefIter++) {
255       CompositeFeaturePtr aComp = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>
256         ((*aRefIter)->owner());
257       if (aComp.get() && aComp->data()->isValid() && aComp->isSub(theFeature))
258         return aComp;
259     }
260   }
261   return CompositeFeaturePtr(); // not found
262 }
263
264 ResultCompSolidPtr compSolidOwner(const ResultPtr& theSub)
265 {
266   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theSub);
267   if (aBody.get()) {
268     FeaturePtr aFeatureOwner = aBody->document()->feature(aBody);
269     if (aFeatureOwner.get()) {
270       std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
271         aFeatureOwner->results().cbegin();
272       for(; aResIter != aFeatureOwner->results().cend(); aResIter++) {
273         ResultCompSolidPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aResIter);
274         if (aComp && aComp->isSub(aBody))
275           return aComp;
276       }
277     }
278   }
279   return ResultCompSolidPtr(); // not found
280 }
281
282 bool hasSubResults(const ResultPtr& theResult)
283 {
284   ResultCompSolidPtr aCompSolid = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(theResult);
285   return aCompSolid.get() && aCompSolid->numberOfSubs() > 0;
286 }
287
288 void allResults(const FeaturePtr& theFeature, std::list<ResultPtr>& theResults)
289 {
290   if (!theFeature.get()) // safety: for empty feature no results
291     return;
292   const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = theFeature->results();
293   std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
294   for (; aRIter != aResults.cend(); aRIter++) {
295     theResults.push_back(*aRIter);
296     // iterate sub-bodies of compsolid
297     ResultCompSolidPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
298     if (aComp.get()) {
299       int aNumSub = aComp->numberOfSubs();
300       for(int a = 0; a < aNumSub; a++) {
301         theResults.push_back(aComp->subResult(a));
302       }
303     }
304   }
305 }
306
307 //******************************************************************
308 bool allDocumentsActivated(std::string& theNotActivatedNames)
309 {
310   theNotActivatedNames = "";
311   bool anAllPartActivated = true;
312
313   DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
314   int aSize = aRootDoc->size(ModelAPI_ResultPart::group());
315   for (int i = 0; i < aSize; i++) {
316     ObjectPtr aObject = aRootDoc->object(ModelAPI_ResultPart::group(), i);
317     ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aObject);
318     if (!aPart->isActivated()) {
319       anAllPartActivated = false;
320       if (!theNotActivatedNames.empty())
321         theNotActivatedNames += ", ";
322       theNotActivatedNames += aObject->data()->name().c_str();
323     }
324   }
325   return anAllPartActivated;
326 }
327
328 bool removeFeaturesAndReferences(const std::set<FeaturePtr>& theFeatures,
329                                  const bool theFlushRedisplay,
330                                  const bool theUseComposite,
331                                  const bool theUseRecursion)
332 {
333 #ifdef DEBUG_REMOVE_FEATURES
334   printListInfo(theFeatures, "selection: ");
335 #endif
336
337   std::map<FeaturePtr, std::set<FeaturePtr> > aReferences;
338   ModelAPI_Tools::findAllReferences(theFeatures, aReferences, theUseComposite, theUseRecursion);
339 #ifdef DEBUG_REMOVE_FEATURES
340   printMapInfo(aReferences, "allDependencies: ");
341 #endif
342
343   std::set<FeaturePtr> aFeaturesRefsTo;
344   ModelAPI_Tools::findRefsToFeatures(theFeatures, aReferences, aFeaturesRefsTo);
345 #ifdef DEBUG_REMOVE_FEATURES
346   printListInfo(aFeaturesRefsTo, "references: ");
347 #endif
348
349   std::set<FeaturePtr> aFeatures = theFeatures;
350   if (!aFeaturesRefsTo.empty())
351     aFeatures.insert(aFeaturesRefsTo.begin(), aFeaturesRefsTo.end());
352 #ifdef DEBUG_REMOVE_FEATURES
353   printListInfo(aFeatures, "removeFeatures: ");
354 #endif
355
356   return ModelAPI_Tools::removeFeatures(aFeatures, false);
357 }
358
359 bool removeFeatures(const std::set<FeaturePtr>& theFeatures,
360                     const bool theFlushRedisplay)
361 {
362   bool isDone = false;
363   std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
364                                        aLast = theFeatures.end();
365   for (; anIt != aLast; anIt++) {
366     FeaturePtr aFeature = *anIt;
367     if (aFeature.get()) {
368       DocumentPtr aDoc = aFeature->document();
369       // flush REDISPLAY signal after remove feature
370       aDoc->removeFeature(aFeature);
371       isDone = true;
372     }
373   }
374   if (isDone && theFlushRedisplay) {
375     // the redisplay signal should be flushed in order to erase
376     // the feature presentation in the viewer
377     // if should be done after removeFeature() of document
378     Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY));
379   }
380   return true;
381 }
382
383 // Fills the references list by all references of the feature from the references map.
384 // This is a recusive method to find references by next found feature in the map of references.
385 // \param theFeature a feature to find references
386 // \param theReferencesMap a map of references
387 // \param theReferences an out container of references
388 void addRefsToFeature(const FeaturePtr& theFeature,
389                       const std::map<FeaturePtr, std::set<FeaturePtr> >& theReferencesMap,
390                       std::map<FeaturePtr, std::set<FeaturePtr> >& theProcessedReferences,
391                       int theRecLevel,
392                       std::set<FeaturePtr>& theReferences)
393 {
394   if (theRecLevel > RECURSE_TOP_LEVEL)
395     return;
396   theRecLevel++;
397
398   // if the feature is already processed, get the ready references from the map
399   if (theProcessedReferences.find(theFeature) != theProcessedReferences.end()) {
400     std::set<FeaturePtr> aReferences = theProcessedReferences.at(theFeature);
401     theReferences.insert(aReferences.begin(), aReferences.end());
402     return;
403   }
404
405   if (theReferencesMap.find(theFeature) == theReferencesMap.end())
406     return; // this feature is not in the selection list, so exists without references to it
407   std::set<FeaturePtr> aMainReferences = theReferencesMap.at(theFeature);
408
409   std::set<FeaturePtr>::const_iterator anIt = aMainReferences.begin(),
410                                        aLast = aMainReferences.end();
411 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
412   std::string aSpacing;
413   for (int i = 0; i < theRecLevel; i++)
414     aSpacing.append(" ");
415 #endif
416
417   for (; anIt != aLast; anIt++) {
418     FeaturePtr aRefFeature = *anIt;
419 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
420   std::cout << aSpacing << " Ref: " << getFeatureInfo(aRefFeature) << std::endl;
421 #endif
422     if (theReferences.find(aRefFeature) == theReferences.end())
423       theReferences.insert(aRefFeature);
424     addRefsToFeature(aRefFeature, theReferencesMap, theProcessedReferences,
425                      theRecLevel, theReferences);
426   }
427 }
428
429 // For each feature from the feature list it searches references to the feature and append them
430 // to the references map. This is a recusive method.
431 // \param theFeature a feature to find references
432 // \param theReferencesMap a map of references
433 // \param theReferences an out container of references
434 void findReferences(const std::set<FeaturePtr>& theFeatures,
435                     std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
436                     const bool theUseComposite, const bool theUseRecursion, int theRecLevel)
437 {
438   if (theRecLevel > RECURSE_TOP_LEVEL)
439     return;
440   theRecLevel++;
441   std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
442                                         aLast = theFeatures.end();
443   for (; anIt != aLast; anIt++) {
444     FeaturePtr aFeature = *anIt;
445     if (aFeature.get() && theReferences.find(aFeature) == theReferences.end()) {
446       DocumentPtr aSelFeatureDoc = aFeature->document();
447       std::set<FeaturePtr> aSelRefFeatures;
448       aSelFeatureDoc->refsToFeature(aFeature, aSelRefFeatures, false/*do not emit signals*/);
449       if (theUseComposite) { // do not filter selection
450         theReferences[aFeature] = aSelRefFeatures;
451       }
452       else { // filter references to skip composition features of the current feature
453         std::set<FeaturePtr> aFilteredFeatures;
454         std::set<FeaturePtr>::const_iterator anIt = aSelRefFeatures.begin(),
455                                              aLast = aSelRefFeatures.end();
456         for (; anIt != aLast; anIt++) {
457           FeaturePtr aCFeature = *anIt;
458           CompositeFeaturePtr aComposite =
459             std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCFeature);
460           if (aComposite.get() && aComposite->isSub(aFeature))
461             continue; /// composite of the current feature should be skipped
462           aFilteredFeatures.insert(aCFeature);
463         }
464         theReferences[aFeature] = aFilteredFeatures;
465       }
466       if (theUseRecursion) {
467 #ifdef DEBUG_CYCLING_1550
468         findReferences(aSelRefFeatures, theReferences, theUseComposite,
469                        theUseRecursion, theRecLevel);
470 #else
471         findReferences(theReferences[aFeature], theReferences, theUseComposite, theUseRecursion,
472                        theRecLevel);
473 #endif
474       }
475     }
476   }
477 }
478
479 void findAllReferences(const std::set<FeaturePtr>& theFeatures,
480                        std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
481                        const bool theUseComposite,
482                        const bool theUseRecursion)
483 {
484   // For dependencies, find main_list:
485   // sk_1(ext_1, vertex_1)
486   // ext_1(bool_1, sk_3)
487   // vertex_1()
488   // sk_2(ext_2)
489   // ext_2(bool_2)
490   // sk_3()
491   // Information: bool_1 is not selected, ext_2(bool_2) exists
492   // find all referenced features
493   std::map<FeaturePtr, std::set<FeaturePtr> > aMainList;
494   int aRecLevel = 0;
495   findReferences(theFeatures, aMainList, theUseComposite, theUseRecursion, aRecLevel);
496
497 #ifdef DEBUG_REMOVE_FEATURES
498   printMapInfo(aMainList, "firstDependencies");
499 #endif
500   // find all dependencies for each object:
501   // sk_1(ext_1, vertex_1) + (sk_3, bool_1)
502   // ext_1(bool_1, sk_3)
503   // vertex_1()
504   // sk_2(ext_2) + (bool_1)
505   // ext_2(bool_1)
506   // sk_3()
507   std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = aMainList.begin(),
508                                                               aMainLast = aMainList.end();
509   for (; aMainIt != aMainLast; aMainIt++) {
510     FeaturePtr aMainListFeature = aMainIt->first;
511
512     //std::string aName = aMainListFeature->name();
513     std::set<FeaturePtr> aMainRefList = aMainIt->second;
514
515 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
516     char aBuf[50];
517     int n = sprintf(aBuf, "%d", aMainRefList.size());
518     std::string aSize(aBuf);
519     std::cout << "_findAllReferences for the Feature: " << getFeatureInfo(aMainListFeature)
520               << ", references size = " << aSize << std::endl;
521 #endif
522     std::set<FeaturePtr>::const_iterator anIt = aMainRefList.begin(),
523                                          aLast = aMainRefList.end();
524     std::set<FeaturePtr> aResultRefList;
525     aResultRefList.insert(aMainRefList.begin(), aMainRefList.end());
526     for (; anIt != aLast; anIt++) {
527       FeaturePtr aFeature = *anIt;
528       int aRecLevel = 0;
529 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
530       std::cout << " Ref: " << getFeatureInfo(aFeature) << std::endl;
531 #endif
532       aRecLevel++;
533       addRefsToFeature(aFeature, aMainList, theReferences,
534                        aRecLevel, aResultRefList/*aMainRefList*/);
535     }
536     theReferences[aMainListFeature] = aResultRefList;
537   }
538 #ifdef DEBUG_REMOVE_FEATURES_RECURSE
539     std::cout << std::endl;
540 #endif
541
542 #ifdef DEBUG_REMOVE_FEATURES
543   printMapInfo(theReferences, "allDependencies");
544 #endif
545 }
546
547 void findRefsToFeatures(const std::set<FeaturePtr>& theFeatures,
548                         const std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
549                         std::set<FeaturePtr>& theFeaturesRefsTo)
550 {
551   std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
552                                        aLast = theFeatures.end();
553   for (; anIt != aLast; anIt++) {
554     FeaturePtr aFeature = *anIt;
555     if (theReferences.find(aFeature) == theReferences.end())
556       continue;
557     std::set<FeaturePtr> aRefList = theReferences.at(aFeature);
558     std::set<FeaturePtr>::const_iterator aRefIt = aRefList.begin(), aRefLast = aRefList.end();
559     for (; aRefIt != aRefLast; aRefIt++) {
560       FeaturePtr aRefFeature = *aRefIt;
561       CompositeFeaturePtr aComposite =
562         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aRefFeature);
563       if (aComposite.get() && aComposite->isSub(aFeature))
564         continue; /// composite of the current feature should not be removed
565
566       if (theFeatures.find(aRefFeature) == theFeatures.end() && // it is not selected
567           theFeaturesRefsTo.find(aRefFeature) == theFeaturesRefsTo.end()) // it is not added
568         theFeaturesRefsTo.insert(aRefFeature);
569     }
570   }
571 }
572
573 void getConcealedResults(const FeaturePtr& theFeature,
574                          std::list<std::shared_ptr<ModelAPI_Result> >& theResults)
575 {
576   SessionPtr aSession = ModelAPI_Session::get();
577
578   std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
579   theFeature->data()->referencesToObjects(aRefs);
580   std::list<std::pair<std::string, std::list<ObjectPtr> > >::const_iterator
581                                                   anIt = aRefs.begin(), aLast = aRefs.end();
582   std::set<ResultPtr> alreadyThere; // to avoid duplications
583   for (; anIt != aLast; anIt++) {
584     if (!aSession->validators()->isConcealed(theFeature->getKind(), anIt->first))
585       continue; // use only concealed attributes
586     std::list<ObjectPtr> anObjects = (*anIt).second;
587     std::list<ObjectPtr>::const_iterator anOIt = anObjects.begin(), anOLast = anObjects.end();
588     for (; anOIt != anOLast; anOIt++) {
589       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(*anOIt);
590       if (aResult && aResult->isConcealed()) {
591         if (alreadyThere.find(aResult) == alreadyThere.end()) // issue 1712, avoid duplicates
592           alreadyThere.insert(aResult);
593         else continue;
594         theResults.push_back(aResult);
595       }
596     }
597   }
598 }
599
600 } // namespace ModelAPI_Tools