+
+//***********************************************************************
+// Fills the references list by all references of the feature from the references map.
+// This is a recusive method to find references by next found feature in the map of references.
+// \param theFeature a feature to find references
+// \param theReferencesMap a map of references
+// \param theReferences an out container of references
+void addRefsToFeature(const FeaturePtr& theFeature,
+ const std::map<FeaturePtr, std::set<FeaturePtr> >& theReferencesMap,
+ std::map<FeaturePtr, std::set<FeaturePtr> >& theProcessedReferences,
+ int theRecLevel,
+ std::set<FeaturePtr>& theReferences)
+{
+ if (theRecLevel > RECURSE_TOP_LEVEL)
+ return;
+ theRecLevel++;
+
+ // if the feature is already processed, get the ready references from the map
+ if (theProcessedReferences.find(theFeature) != theProcessedReferences.end()) {
+ std::set<FeaturePtr> aReferences = theProcessedReferences.at(theFeature);
+ theReferences.insert(aReferences.begin(), aReferences.end());
+ return;
+ }
+
+ if (theReferencesMap.find(theFeature) == theReferencesMap.end())
+ return; // this feature is not in the selection list, so exists without references to it
+ std::set<FeaturePtr> aMainReferences = theReferencesMap.at(theFeature);
+
+ std::set<FeaturePtr>::const_iterator anIt = aMainReferences.begin(),
+ aLast = aMainReferences.end();
+#ifdef DEBUG_REMOVE_FEATURES_RECURSE
+ std::string aSpacing;
+ for (int i = 0; i < theRecLevel; i++)
+ aSpacing.append(" ");
+#endif
+
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aRefFeature = *anIt;
+#ifdef DEBUG_REMOVE_FEATURES_RECURSE
+ std::cout << aSpacing << " Ref: " << getFeatureInfo(aRefFeature) << std::endl;
+#endif
+ if (theReferences.find(aRefFeature) == theReferences.end())
+ theReferences.insert(aRefFeature);
+ addRefsToFeature(aRefFeature, theReferencesMap, theProcessedReferences,
+ theRecLevel, theReferences);
+ }
+}
+
+// For each feature from the feature list it searches references to the feature and append them
+// to the references map. This is a recusive method.
+// \param theFeature a feature to find references
+// \param theReferencesMap a map of references
+// \param theReferences an out container of references
+void findReferences(const std::set<FeaturePtr>& theFeatures,
+ std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
+ const bool theUseComposite, const bool theUseRecursion, int theRecLevel)
+{
+ if (theRecLevel > RECURSE_TOP_LEVEL)
+ return;
+ theRecLevel++;
+ std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
+ aLast = theFeatures.end();
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aFeature = *anIt;
+ if (aFeature.get() && theReferences.find(aFeature) == theReferences.end()) {
+ DocumentPtr aSelFeatureDoc = aFeature->document();
+ std::set<FeaturePtr> aSelRefFeatures;
+ aSelFeatureDoc->refsToFeature(aFeature, aSelRefFeatures, false/*do not emit signals*/);
+ if (theUseComposite) { // do not filter selection
+ theReferences[aFeature] = aSelRefFeatures;
+ }
+ else { // filter references to skip composition features of the current feature
+ std::set<FeaturePtr> aFilteredFeatures;
+ std::set<FeaturePtr>::const_iterator anIt = aSelRefFeatures.begin(),
+ aLast = aSelRefFeatures.end();
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aCFeature = *anIt;
+ CompositeFeaturePtr aComposite =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCFeature);
+ if (aComposite.get() && aComposite->isSub(aFeature))
+ continue; /// composite of the current feature should be skipped
+ aFilteredFeatures.insert(aCFeature);
+ }
+ theReferences[aFeature] = aFilteredFeatures;
+ }
+ if (theUseRecursion) {
+#ifdef DEBUG_CYCLING_1550
+ findReferences(aSelRefFeatures, theReferences, theUseComposite,
+ theUseRecursion, theRecLevel);
+#else
+ findReferences(theReferences[aFeature], theReferences, theUseComposite, theUseRecursion,
+ theRecLevel);
+#endif
+ }
+ }
+ }
+}
+
+void findAllReferences(const std::set<FeaturePtr>& theFeatures,
+ std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
+ const bool theUseComposite,
+ const bool theUseRecursion)
+{
+ // For dependencies, find main_list:
+ // sk_1(ext_1, vertex_1)
+ // ext_1(bool_1, sk_3)
+ // vertex_1()
+ // sk_2(ext_2)
+ // ext_2(bool_2)
+ // sk_3()
+ // Information: bool_1 is not selected, ext_2(bool_2) exists
+ // find all referenced features
+ std::map<FeaturePtr, std::set<FeaturePtr> > aMainList;
+ int aRecLevel = 0;
+ findReferences(theFeatures, aMainList, theUseComposite, theUseRecursion, aRecLevel);
+
+#ifdef DEBUG_REMOVE_FEATURES
+ printMapInfo(aMainList, "firstDependencies");
+#endif
+ // find all dependencies for each object:
+ // sk_1(ext_1, vertex_1) + (sk_3, bool_1)
+ // ext_1(bool_1, sk_3)
+ // vertex_1()
+ // sk_2(ext_2) + (bool_1)
+ // ext_2(bool_1)
+ // sk_3()
+ std::map<FeaturePtr, std::set<FeaturePtr> >::const_iterator aMainIt = aMainList.begin(),
+ aMainLast = aMainList.end();
+ for (; aMainIt != aMainLast; aMainIt++) {
+ FeaturePtr aMainListFeature = aMainIt->first;
+
+ //std::string aName = aMainListFeature->name();
+ std::set<FeaturePtr> aMainRefList = aMainIt->second;
+
+#ifdef DEBUG_REMOVE_FEATURES_RECURSE
+ char aBuf[50];
+ int n = sprintf(aBuf, "%d", aMainRefList.size());
+ std::string aSize(aBuf);
+ std::cout << "_findAllReferences for the Feature: " << getFeatureInfo(aMainListFeature)
+ << ", references size = " << aSize << std::endl;
+#endif
+ std::set<FeaturePtr>::const_iterator anIt = aMainRefList.begin(),
+ aLast = aMainRefList.end();
+ std::set<FeaturePtr> aResultRefList;
+ aResultRefList.insert(aMainRefList.begin(), aMainRefList.end());
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aFeature = *anIt;
+ int aRecLevel = 0;
+#ifdef DEBUG_REMOVE_FEATURES_RECURSE
+ std::cout << " Ref: " << getFeatureInfo(aFeature) << std::endl;
+#endif
+ aRecLevel++;
+ addRefsToFeature(aFeature, aMainList, theReferences,
+ aRecLevel, aResultRefList/*aMainRefList*/);
+ }
+ theReferences[aMainListFeature] = aResultRefList;
+ }
+#ifdef DEBUG_REMOVE_FEATURES_RECURSE
+ std::cout << std::endl;
+#endif
+
+#ifdef DEBUG_REMOVE_FEATURES
+ printMapInfo(theReferences, "allDependencies");
+#endif
+}
+
+void findRefsToFeatures(const std::set<FeaturePtr>& theFeatures,
+ const std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
+ std::set<FeaturePtr>& theFeaturesRefsTo)
+{
+ std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
+ aLast = theFeatures.end();
+ for (; anIt != aLast; anIt++) {
+ FeaturePtr aFeature = *anIt;
+ if (theReferences.find(aFeature) == theReferences.end())
+ continue;
+ std::set<FeaturePtr> aRefList = theReferences.at(aFeature);
+ std::set<FeaturePtr>::const_iterator aRefIt = aRefList.begin(), aRefLast = aRefList.end();
+ for (; aRefIt != aRefLast; aRefIt++) {
+ FeaturePtr aRefFeature = *aRefIt;
+ CompositeFeaturePtr aComposite =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aRefFeature);
+ if (aComposite.get() && aComposite->isSub(aFeature))
+ continue; /// composite of the current feature should not be removed
+
+ if (theFeatures.find(aRefFeature) == theFeatures.end() && // it is not selected
+ theFeaturesRefsTo.find(aRefFeature) == theFeaturesRefsTo.end()) // it is not added
+ theFeaturesRefsTo.insert(aRefFeature);
+ }
+ }
+}
+
+void getConcealedResults(const FeaturePtr& theFeature,
+ std::list<std::shared_ptr<ModelAPI_Result> >& theResults)
+{
+ SessionPtr aSession = ModelAPI_Session::get();
+
+ std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > > aRefs;
+ theFeature->data()->referencesToObjects(aRefs);
+ std::list<std::pair<std::string, std::list<ObjectPtr> > >::const_iterator
+ anIt = aRefs.begin(), aLast = aRefs.end();
+ std::set<ResultPtr> alreadyThere; // to avoid duplications
+ for (; anIt != aLast; anIt++) {
+ if (!aSession->validators()->isConcealed(theFeature->getKind(), anIt->first))
+ continue; // use only concealed attributes
+ std::list<ObjectPtr> anObjects = (*anIt).second;
+ std::list<ObjectPtr>::const_iterator anOIt = anObjects.begin(), anOLast = anObjects.end();
+ for (; anOIt != anOLast; anOIt++) {
+ ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(*anOIt);
+ if (aResult && aResult->isConcealed()) {
+ if (alreadyThere.find(aResult) == alreadyThere.end()) // issue 1712, avoid duplicates
+ alreadyThere.insert(aResult);
+ else continue;
+ theResults.push_back(aResult);
+ }
+ }
+ }
+}
+
+std::pair<std::string, bool> getDefaultName(
+ const std::shared_ptr<ModelAPI_Result>& theResult,
+ const int theResultIndex)
+{
+ typedef std::list< std::pair < std::string, std::list<ObjectPtr> > > ListOfReferences;
+
+ SessionPtr aSession = ModelAPI_Session::get();
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theResult->data()->owner());
+
+ ResultCompSolidPtr aCompSolidRes = compSolidOwner(theResult);
+ if (aCompSolidRes) {
+ // names of sub-solids in CompSolid should be default (for example,
+ // result of boolean operation 'Boolean_1_1' is a CompSolid which is renamed to 'MyBOOL',
+ // however, sub-elements of 'MyBOOL' should be named 'Boolean_1_1_1', 'Boolean_1_1_2' etc.)
+ std::ostringstream aDefaultName;
+ aDefaultName << anOwner->name();
+ // compute default name of CompSolid (name of feature + index of CompSolid's result)
+ int aCompSolidResultIndex = 0;
+ const std::list<ResultPtr>& aResults = anOwner->results();
+ for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+ anIt != aResults.end(); ++anIt, ++aCompSolidResultIndex)
+ if (aCompSolidRes == *anIt)
+ break;
+ aDefaultName << "_" << (aCompSolidResultIndex + 1) << "_" << (theResultIndex + 1);
+ return std::pair<std::string, bool>(aDefaultName.str(), false);
+ }
+
+ DataPtr aData = anOwner->data();
+
+ ListOfReferences aReferences;
+ aData->referencesToObjects(aReferences);
+
+ // find first result with user-defined name
+ ListOfReferences::const_iterator aFoundRef = aReferences.end();
+ for (ListOfReferences::const_iterator aRefIt = aReferences.begin();
+ aRefIt != aReferences.end(); ++aRefIt) {
+ bool isConcealed = aSession->validators()->isConcealed(anOwner->getKind(), aRefIt->first);
+ bool isMainArg = isConcealed &&
+ aSession->validators()->isMainArgument(anOwner->getKind(), aRefIt->first);
+ if (isConcealed) {
+ // check the referred object is a Body
+ // (for example, ExtrusionCut has a sketch as a first attribute which is concealing)
+ bool isBody = aRefIt->second.size() > 1 || (aRefIt->second.size() == 1 &&
+ aRefIt->second.front()->groupName() == ModelAPI_ResultBody::group());
+ if (isBody && (isMainArg || aFoundRef == aReferences.end() ||
+ aData->isPrecedingAttribute(aRefIt->first, aFoundRef->first)))
+ aFoundRef = aRefIt;
+
+ if (isMainArg)
+ break;
+ }
+ }
+
+ // find an object which is concealed by theResult
+ if (aFoundRef != aReferences.end() && !aFoundRef->second.empty()) {
+ // store number of references for each object
+ std::map<ResultPtr, int> aNbRefToObject;
+ // search the object by result index
+ std::list<ObjectPtr>::const_iterator anObjIt = aFoundRef->second.begin();
+ int aResultIndex = theResultIndex;
+ while (--aResultIndex >= 0) {
+ ResultPtr aCurRes = std::dynamic_pointer_cast<ModelAPI_Result>(*anObjIt);
+ ResultCompSolidPtr aParentCompSolid = ModelAPI_Tools::compSolidOwner(aCurRes);
+ if (aParentCompSolid)
+ aCurRes = aParentCompSolid;
+ if (aNbRefToObject.find(aCurRes) == aNbRefToObject.end())
+ aNbRefToObject[aCurRes] = 1;
+ else
+ aNbRefToObject[aCurRes] += 1;
+
+ ++anObjIt;
+ if (anObjIt == aFoundRef->second.end()) {
+ anObjIt = aFoundRef->second.begin();
+ break;
+ }
+ }
+ // check the result is a Body
+ if ((*anObjIt)->groupName() == ModelAPI_ResultBody::group()) {
+ // check the result is part of CompSolid
+ ResultPtr anObjRes = std::dynamic_pointer_cast<ModelAPI_Result>(*anObjIt);
+ ResultCompSolidPtr aParentCompSolid = ModelAPI_Tools::compSolidOwner(anObjRes);
+ if (aParentCompSolid)
+ anObjRes = aParentCompSolid;
+
+ // return name of reference result only if it has been renamed by the user,
+ // in other case compose a default name
+ if (anObjRes->data()->hasUserDefinedName()) {
+ std::stringstream aName;
+ aName << anObjRes->data()->name();
+ std::map<ResultPtr, int>::iterator aFound = aNbRefToObject.find(anObjRes);
+ if (aFound != aNbRefToObject.end()) {
+ // to generate unique name, add suffix if there are several results
+ // referring to the same shape
+ aName << "_" << aFound->second + 1;
+ }
+ return std::pair<std::string, bool>(aName.str(), true);
+ }
+ }
+ }
+
+ // compose default name by the name of the feature and the index of result
+ std::stringstream aDefaultName;
+ aDefaultName << anOwner->name();
+ // if there are several results (issue #899: any number of result),
+ // add unique prefix starting from second
+ if (theResultIndex > 0 || theResult->groupName() == ModelAPI_ResultBody::group())
+ aDefaultName << "_" << theResultIndex + 1;
+ return std::pair<std::string, bool>(aDefaultName.str(), false);
+}
+
+std::string getDefaultName(const ResultPtr& theResult)
+{
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theResult->data()->owner());
+
+ // names of sub-solids in CompSolid should be default (for example,
+ // result of boolean operation 'Boolean_1_1' is a CompSolid which is renamed to 'MyBOOL',
+ // however, sub-elements of 'MyBOOL' should be named 'Boolean_1_1_1', 'Boolean_1_1_2' etc.)
+ std::ostringstream aDefaultName;
+ aDefaultName << anOwner->name();
+
+ ResultPtr aResToSearch = theResult;
+ ResultCompSolidPtr aCompSolidRes = compSolidOwner(theResult);
+ if (aCompSolidRes)
+ aResToSearch = aCompSolidRes;
+
+ // obtain index of result
+ int aResIndex = 1;
+ const std::list<ResultPtr>& aResults = anOwner->results();
+ for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+ anIt != aResults.end(); ++anIt, ++aResIndex)
+ if (aResToSearch == *anIt)
+ break;
+
+ // compute default name of CompSolid (name of feature + index of CompSolid's result)
+ aDefaultName << "_" << aResIndex;
+
+ if (aCompSolidRes) {
+ // obtain index of result in compsolid and compose a default name
+ int aNbSubs = aCompSolidRes->numberOfSubs();
+ for (int anIndex = 0; anIndex < aNbSubs; ++anIndex)
+ if (aCompSolidRes->subResult(anIndex) == theResult) {
+ aDefaultName << "_" << (anIndex + 1);
+ break;
+ }
+ }
+
+ return aDefaultName.str();
+}
+
+} // namespace ModelAPI_Tools