From 1a7281af4aeb1c5fe521989cc66e4e8c5870a576 Mon Sep 17 00:00:00 2001 From: nds Date: Fri, 10 Jul 2015 17:52:10 +0300 Subject: [PATCH] Issue #711 Fatal error when Create extrusion cut Chash by mpv: in sketch of Extrusion cut try to move over external edge, result is crash. It is caused by recursive delete of referenced features to the external edge. The extrusion cut was in the list of deleted features. --- .../FeaturesPlugin_ExtrusionBoolean.cpp | 0 src/FeaturesPlugin/extrusioncut_widget.xml | 1 + src/FeaturesPlugin/extrusionfuse_widget.xml | 1 + src/FeaturesPlugin/revolutioncut_widget.xml | 1 + src/FeaturesPlugin/revolutionfuse_widget.xml | 1 + src/XGUI/XGUI_Tools.cpp | 116 ++++++++++++++++++ src/XGUI/XGUI_Tools.h | 32 +++++ src/XGUI/XGUI_Workshop.cpp | 93 +------------- 8 files changed, 154 insertions(+), 91 deletions(-) mode change 100644 => 100755 src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp diff --git a/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp b/src/FeaturesPlugin/FeaturesPlugin_ExtrusionBoolean.cpp old mode 100644 new mode 100755 diff --git a/src/FeaturesPlugin/extrusioncut_widget.xml b/src/FeaturesPlugin/extrusioncut_widget.xml index 0b9f14a6e..9d749ae27 100755 --- a/src/FeaturesPlugin/extrusioncut_widget.xml +++ b/src/FeaturesPlugin/extrusioncut_widget.xml @@ -73,4 +73,5 @@ type_choice="Solids" concealment="true"> + diff --git a/src/FeaturesPlugin/extrusionfuse_widget.xml b/src/FeaturesPlugin/extrusionfuse_widget.xml index 70579aa19..380dd7692 100644 --- a/src/FeaturesPlugin/extrusionfuse_widget.xml +++ b/src/FeaturesPlugin/extrusionfuse_widget.xml @@ -73,4 +73,5 @@ type_choice="Solids" concealment="true"> + diff --git a/src/FeaturesPlugin/revolutioncut_widget.xml b/src/FeaturesPlugin/revolutioncut_widget.xml index 93bfdcf06..32218ce9c 100644 --- a/src/FeaturesPlugin/revolutioncut_widget.xml +++ b/src/FeaturesPlugin/revolutioncut_widget.xml @@ -81,4 +81,5 @@ type_choice="Solids" concealment="true"> + diff --git a/src/FeaturesPlugin/revolutionfuse_widget.xml b/src/FeaturesPlugin/revolutionfuse_widget.xml index 6bbcd3270..599058cb4 100644 --- a/src/FeaturesPlugin/revolutionfuse_widget.xml +++ b/src/FeaturesPlugin/revolutionfuse_widget.xml @@ -81,4 +81,5 @@ type_choice="Solids" concealment="true"> + diff --git a/src/XGUI/XGUI_Tools.cpp b/src/XGUI/XGUI_Tools.cpp index 47de40270..b835629a7 100644 --- a/src/XGUI/XGUI_Tools.cpp +++ b/src/XGUI/XGUI_Tools.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -123,4 +124,119 @@ bool allDocumentsActivated(QString& theNotActivatedNames) return anAllPartActivated; } +//************************************************************** +void refsToFeatureInFeatureDocument(const ObjectPtr& theObject, std::set& theRefFeatures) +{ + FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); + if (aFeature.get()) { + DocumentPtr aFeatureDoc = aFeature->document(); + // 1. find references in the current document + aFeatureDoc->refsToFeature(aFeature, theRefFeatures, false); + } +} + +//************************************************************** +bool isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature) +{ + bool isSub = false; + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(theFeature); + if (aComposite.get()) { + isSub = aComposite->isSub(theObject); + // the recursive is possible, the parameters are sketch circle and extrusion cut. They are + // separated by composite sketch feature + if (!isSub) { + int aNbSubs = aComposite->numberOfSubs(); + for (int aSub = 0; aSub < aNbSubs && !isSub; aSub++) { + isSub = isSubOfComposite(theObject, aComposite->subFeature(aSub)); + } + } + } + return isSub; +} + +//************************************************************** +void refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, const ObjectPtr& theObject, + std::set& theRefFeatures) +{ + FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); + if (!aFeature.get()) + return; + + // 1. find references in the current document + std::set aRefFeatures; + refsToFeatureInFeatureDocument(theObject, aRefFeatures); + std::set::const_iterator anIt = aRefFeatures.begin(), + aLast = aRefFeatures.end(); + for (; anIt != aLast; anIt++) { + if (!isSubOfComposite(theSourceObject, *anIt)) + theRefFeatures.insert(*anIt); + } + + // 2. find references in all documents if the document of the feature is + // "PartSet". Features of this document can be used in all other documents + DocumentPtr aFeatureDoc = aFeature->document(); + + SessionPtr aMgr = ModelAPI_Session::get(); + DocumentPtr aModuleDoc = aMgr->moduleDocument(); + if (aFeatureDoc == aModuleDoc) { + // the feature and results of the feature should be found in references + std::list aObjects; + aObjects.push_back(aFeature); + typedef std::list > ResultsList; + const ResultsList& aResults = aFeature->results(); + ResultsList::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + ResultPtr aRes = *aRIter; + if (aRes.get()) + aObjects.push_back(aRes); + } + // get all opened documents; found features in the documents; + // get a list of objects where a feature refers; + // search in these objects the deleted objects. + SessionPtr aMgr = ModelAPI_Session::get(); + std::list anOpenedDocs = aMgr->allOpenedDocuments(); + std::list::const_iterator anIt = anOpenedDocs.begin(), + aLast = anOpenedDocs.end(); + std::list > > aRefs; + for (; anIt != aLast; anIt++) { + DocumentPtr aDocument = *anIt; + if (aDocument == aFeatureDoc) + continue; // this document has been already processed in 1.1 + + int aFeaturesCount = aDocument->size(ModelAPI_Feature::group()); + for (int aId = 0; aId < aFeaturesCount; aId++) { + ObjectPtr anObject = aDocument->object(ModelAPI_Feature::group(), aId); + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + if (!aFeature.get()) + continue; + + aRefs.clear(); + aFeature->data()->referencesToObjects(aRefs); + std::list > >::iterator aRef = aRefs.begin(); + bool aHasReferenceToObject = false; + for(; aRef != aRefs.end() && !aHasReferenceToObject; aRef++) { + std::list::iterator aRefObj = aRef->second.begin(); + for(; aRefObj != aRef->second.end() && !aHasReferenceToObject; aRefObj++) { + std::list::const_iterator aObjIt = aObjects.begin(); + for(; aObjIt != aObjects.end() && !aHasReferenceToObject; aObjIt++) { + aHasReferenceToObject = *aObjIt == *aRefObj; + } + } + } + if (aHasReferenceToObject && !isSubOfComposite(theSourceObject, aFeature)) + theRefFeatures.insert(aFeature); + } + } + } + + // Run recursion. It is possible recusive dependency, like the folowing: plane, extrusion uses plane, + // axis is built on extrusion. Delete of a plane should check the dependency from the axis also. + std::set aRecursiveRefFeatures; + std::set::const_iterator aFeatureIt = theRefFeatures.begin(); + for (; aFeatureIt != theRefFeatures.end(); ++aFeatureIt) { + refsToFeatureInAllDocuments(theSourceObject, *aFeatureIt, aRecursiveRefFeatures); + } + theRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end()); +} + } diff --git a/src/XGUI/XGUI_Tools.h b/src/XGUI/XGUI_Tools.h index a3fba88c9..4869f3037 100644 --- a/src/XGUI/XGUI_Tools.h +++ b/src/XGUI/XGUI_Tools.h @@ -83,6 +83,38 @@ bool XGUI_EXPORT canRemoveOrRename(QWidget* theParent, const QObjectPtrList& aLi \return a boolean value */ bool XGUI_EXPORT allDocumentsActivated(QString& theNotActivatedNames); + +/*! + Returns a container of referenced feature to the current object in the object document. + \param theObject an object, which will be casted to a feature type + \param theRefFeatures an output container + */ +void XGUI_EXPORT refsToFeatureInFeatureDocument(const ObjectPtr& theObject, + std::set& theRefFeatures); + +/*! + Returns true if the object if a sub child of the feature. The feature is casted to the + composite one. If it is possible, the sub object check happens. The method is applyed + recursively to the feature subs. + \param theObject a candidate to be a sub object + \param theFeature a candidate to be a composite feature + \return a boolean value + */ +bool XGUI_EXPORT isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature); + +/*! + Returns a container of references feature to the source object. The search happens in the object + document and in other Part documents if the object belongs to the PartSet. The search is recursive, + in other words it is applyed to set of the found objects until it is possible. + It do not returns the referenced features to the object if this references is a composite feature + which has the object as a sub object. + \param theSourceObject an object, which references are searched + \param theObject an intermediate recursive object, should be set in the source object + \return a boolean value + */ +void XGUI_EXPORT refsToFeatureInAllDocuments(const ObjectPtr& theSourceObject, + const ObjectPtr& theObject, + std::set& theRefFeatures); }; #endif diff --git a/src/XGUI/XGUI_Workshop.cpp b/src/XGUI/XGUI_Workshop.cpp index f70dcb903..755f4b732 100644 --- a/src/XGUI/XGUI_Workshop.cpp +++ b/src/XGUI/XGUI_Workshop.cpp @@ -1086,95 +1086,6 @@ void XGUI_Workshop::moveObjects() aMgr->finishOperation(); } -//************************************************************** -void refsToFeatureInFeatureDocument(const ObjectPtr& theObject, std::set& theRefFeatures) -{ - FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); - if (aFeature.get()) { - DocumentPtr aFeatureDoc = aFeature->document(); - // 1. find references in the current document - aFeatureDoc->refsToFeature(aFeature, theRefFeatures, false); - } -} - -//************************************************************** -void refsToFeatureInAllDocuments(const ObjectPtr& theObject, std::set& theRefFeatures) -{ - FeaturePtr aFeature = ModelAPI_Feature::feature(theObject); - if (!aFeature.get()) - return; - - // 1. find references in the current document - refsToFeatureInFeatureDocument(theObject, theRefFeatures); - - - // 2. find references in all documents if the document of the feature is - // "PartSet". Features of this document can be used in all other documents - DocumentPtr aFeatureDoc = aFeature->document(); - - SessionPtr aMgr = ModelAPI_Session::get(); - DocumentPtr aModuleDoc = aMgr->moduleDocument(); - if (aFeatureDoc == aModuleDoc) { - // the feature and results of the feature should be found in references - std::list aObjects; - aObjects.push_back(aFeature); - typedef std::list > ResultsList; - const ResultsList& aResults = aFeature->results(); - ResultsList::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - ResultPtr aRes = *aRIter; - if (aRes.get()) - aObjects.push_back(aRes); - } - // get all opened documents; found features in the documents; - // get a list of objects where a feature refers; - // search in these objects the deleted objects. - SessionPtr aMgr = ModelAPI_Session::get(); - std::list anOpenedDocs = aMgr->allOpenedDocuments(); - std::list::const_iterator anIt = anOpenedDocs.begin(), - aLast = anOpenedDocs.end(); - std::list > > aRefs; - for (; anIt != aLast; anIt++) { - DocumentPtr aDocument = *anIt; - if (aDocument == aFeatureDoc) - continue; // this document has been already processed in 1.1 - - int aFeaturesCount = aDocument->size(ModelAPI_Feature::group()); - for (int aId = 0; aId < aFeaturesCount; aId++) { - ObjectPtr anObject = aDocument->object(ModelAPI_Feature::group(), aId); - FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); - if (!aFeature.get()) - continue; - - aRefs.clear(); - aFeature->data()->referencesToObjects(aRefs); - std::list > >::iterator aRef = aRefs.begin(); - bool aHasReferenceToObjetc = false; - for(; aRef != aRefs.end() && !aHasReferenceToObjetc; aRef++) { - std::list::iterator aRefObj = aRef->second.begin(); - for(; aRefObj != aRef->second.end() && !aHasReferenceToObjetc; aRefObj++) { - std::list::const_iterator aObjIt = aObjects.begin(); - for(; aObjIt != aObjects.end() && !aHasReferenceToObjetc; aObjIt++) { - aHasReferenceToObjetc = *aObjIt == *aRefObj; - } - } - } - if (aHasReferenceToObjetc) - theRefFeatures.insert(aFeature); - } - } - } - - // Run recursion. It is possible recusive dependency, like the folowing: plane, extrusion uses plane, - // axis is built on extrusion. Delete of a plane should check the dependency from the axis also. - std::set aRecursiveRefFeatures; - std::set::const_iterator aFeatureIt = theRefFeatures.begin(); - for (; aFeatureIt != theRefFeatures.end(); ++aFeatureIt) { - refsToFeatureInAllDocuments(*aFeatureIt, aRecursiveRefFeatures); - } - theRefFeatures.insert(aRecursiveRefFeatures.begin(), aRecursiveRefFeatures.end()); -} - //************************************************************** bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, const std::set& theIgnoredFeatures, @@ -1194,7 +1105,7 @@ bool XGUI_Workshop::deleteFeatures(const QObjectPtrList& theList, // 1. find all referenced features std::set aRefFeatures; foreach (ObjectPtr aDeletedObj, theList) { - refsToFeatureInAllDocuments(aDeletedObj, aRefFeatures); + XGUI_Tools::refsToFeatureInAllDocuments(aDeletedObj, aDeletedObj, aRefFeatures); } // 2. warn about the references remove, break the delete operation if the user chose it if (theAskAboutDeleteReferences && !aRefFeatures.empty()) { @@ -1324,7 +1235,7 @@ bool XGUI_Workshop::canMoveFeature() std::set aPlacedFeatures(aFeaturesBetween.begin(), aFeaturesBetween.end()); // 2. Get all reference features to the selected object in the document std::set aRefFeatures; - refsToFeatureInFeatureDocument(aObject, aRefFeatures); + XGUI_Tools::refsToFeatureInFeatureDocument(aObject, aRefFeatures); if (aRefFeatures.empty()) continue; -- 2.39.2