+
+std::shared_ptr<ModelAPI_Feature> Model_Document::featureById(const int theId)
+{
+ return myObjs->featureById(theId);
+}
+
+void Model_Document::synchronizeTransactions()
+{
+ Model_Document* aRoot =
+ std::dynamic_pointer_cast<Model_Document>(ModelAPI_Session::get()->moduleDocument()).get();
+ if (aRoot == this)
+ return; // don't need to synchronise root with root
+
+ std::shared_ptr<Model_Session> aSession =
+ std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
+ while(myRedos.size() > aRoot->myRedos.size()) { // remove redos in this
+ aSession->setCheckTransactions(false);
+ redo();
+ aSession->setCheckTransactions(true);
+ }
+ /* this case can not be reproduced in any known case for the current moment, so, just comment
+ while(myRedos.size() < aRoot->myRedos.size()) { // add more redos in this
+ undoInternal(false, true);
+ }*/
+}
+
+/// Feature that is used for selection in the Part document by the external request
+class Model_SelectionInPartFeature : public ModelAPI_Feature {
+public:
+ /// Nothing to do in constructor
+ Model_SelectionInPartFeature() : ModelAPI_Feature() {}
+
+ /// Returns the unique kind of a feature
+ virtual const std::string& getKind() {
+ static std::string MY_KIND("InternalSelectionInPartFeature");
+ return MY_KIND;
+ }
+ /// Request for initialization of data model of the object: adding all attributes
+ virtual void initAttributes() {
+ data()->addAttribute("selection", ModelAPI_AttributeSelectionList::typeId());
+ }
+ /// Nothing to do in the execution function
+ virtual void execute() {}
+
+};
+
+//! Returns the feature that is used for calculation of selection externally from the document
+AttributeSelectionListPtr Model_Document::selectionInPartFeature()
+{
+ // return already created, otherwise create
+ if (!mySelectionFeature.get() || !mySelectionFeature->data()->isValid()) {
+ // create a new one
+ mySelectionFeature = FeaturePtr(new Model_SelectionInPartFeature);
+
+ TDF_Label aFeatureLab = generalLabel().FindChild(TAG_SELECTION_FEATURE);
+ std::shared_ptr<Model_Data> aData(new Model_Data);
+ aData->setLabel(aFeatureLab.FindChild(1));
+ aData->setObject(mySelectionFeature);
+ mySelectionFeature->setDoc(myObjs->owner());
+ mySelectionFeature->setData(aData);
+ std::string aName = id() + "_Part";
+ mySelectionFeature->data()->setName(aName);
+ mySelectionFeature->setDoc(myObjs->owner());
+ mySelectionFeature->initAttributes();
+ mySelectionFeature->init(); // to make it enabled and Update correctly
+ // this update may cause recomputation of the part after selection on it, that is not needed
+ mySelectionFeature->data()->blockSendAttributeUpdated(true);
+ }
+ return mySelectionFeature->selectionList("selection");
+}
+
+FeaturePtr Model_Document::lastFeature()
+{
+ if (myObjs)
+ return myObjs->lastFeature();
+ return FeaturePtr();
+}
+
+static Handle(TNaming_NamedShape) searchForOriginalShape(TopoDS_Shape theShape, TDF_Label aMain) {
+ Handle(TNaming_NamedShape) aResult;
+ while(!theShape.IsNull()) { // searching for the very initial shape that produces this one
+ TopoDS_Shape aShape = theShape;
+ theShape.Nullify();
+ // to avoid crash of TNaming_SameShapeIterator if pure shape does not exists
+ if (!TNaming_Tool::HasLabel(aMain, aShape))
+ break;
+ for(TNaming_SameShapeIterator anIter(aShape, aMain); anIter.More(); anIter.Next()) {
+ TDF_Label aNSLab = anIter.Label();
+ Handle(TNaming_NamedShape) aNS;
+ if (aNSLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
+ for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) {
+ if (aShapesIter.Evolution() == TNaming_SELECTED ||
+ aShapesIter.Evolution() == TNaming_DELETE)
+ continue; // don't use the selection evolution
+ if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape
+ aResult = aNS;
+ if (aResult->Evolution() == TNaming_MODIFY)
+ theShape = aShapesIter.OldShape();
+ // otherwise may me searching for another item of this shape with longer history
+ if (!theShape.IsNull())
+ break;
+ }
+ }
+ }
+ }
+ }
+ return aResult;
+}
+
+std::shared_ptr<ModelAPI_Feature> Model_Document::producedByFeature(
+ std::shared_ptr<ModelAPI_Result> theResult,
+ const std::shared_ptr<GeomAPI_Shape>& theShape)
+{
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
+ if (!aBody.get()) {
+ return feature(theResult); // for not-body just returns the feature that produced this result
+ }
+ // otherwise get the shape and search the very initial label for it
+ TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
+ if (aShape.IsNull())
+ return FeaturePtr();
+
+ // for compsolids and compounds all the naming is located in the main object, so, try to use
+ // it first
+ ResultBodyPtr aMain = ModelAPI_Tools::bodyOwner(theResult);
+ while (aMain.get()) { // get the top-most main
+ ResultBodyPtr aNextMain = ModelAPI_Tools::bodyOwner(aMain);
+ if (aNextMain.get())
+ aMain = aNextMain;
+ else break;
+ }
+ if (aMain.get()) {
+ FeaturePtr aMainRes = producedByFeature(aMain, theShape);
+ if (aMainRes)
+ return aMainRes;
+ }
+
+ std::shared_ptr<Model_Data> aBodyData = std::dynamic_pointer_cast<Model_Data>(theResult->data());
+ if (!aBodyData.get() || !aBodyData->isValid())
+ return FeaturePtr();
+
+ TopoDS_Shape anOldShape; // old shape in the pair oldshape->theShape in the named shape
+ TopoDS_Shape aShapeContainer; // old shape of the shape that contains aShape as sub-element
+ Handle(TNaming_NamedShape) aCandidatInThis, aCandidatContainer;
+ TDF_Label aBodyLab = aBodyData->label();
+ // use childs and this label (the lowest priority)
+ TDF_ChildIDIterator aNSIter(aBodyLab, TNaming_NamedShape::GetID(), Standard_True);
+ bool aUseThis = !aNSIter.More();
+ while(anOldShape.IsNull() && (aNSIter.More() || aUseThis)) {
+ Handle(TNaming_NamedShape) aNS;
+ if (aUseThis) {
+ if (!aBodyLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
+ break;
+ } else {
+ aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value());
+ }
+ for(TNaming_Iterator aShapesIter(aNS); aShapesIter.More(); aShapesIter.Next()) {
+ if (aShapesIter.Evolution() == TNaming_SELECTED || aShapesIter.Evolution() == TNaming_DELETE)
+ continue; // don't use the selection evolution
+ if (aShapesIter.NewShape().IsSame(aShape)) { // found the original shape
+ aCandidatInThis = aNS;
+ if (aCandidatInThis->Evolution() == TNaming_MODIFY)
+ anOldShape = aShapesIter.OldShape();
+ // otherwise may me searching for another item of this shape with longer history
+ if (!anOldShape.IsNull())
+ break;
+ }
+ // check that the shape contains aShape as sub-shape to fill container
+ if (aShapesIter.NewShape().ShapeType() < aShape.ShapeType() && aCandidatContainer.IsNull()) {
+ TopExp_Explorer anExp(aShapesIter.NewShape(), aShape.ShapeType());
+ for(; anExp.More(); anExp.Next()) {
+ if (aShape.IsSame(anExp.Current())) {
+ aCandidatContainer = aNS;
+ aShapeContainer = aShapesIter.NewShape();
+ }
+ }
+ }
+ }
+ // iterate to the next label or to the body label in the end
+ if (!aUseThis)
+ aNSIter.Next();
+ if (!aNSIter.More()) {
+ if (aUseThis)
+ break;
+ aUseThis = true;
+ }
+ }
+ if (aCandidatInThis.IsNull()) {
+ // to fix 1512: searching for original shape of this shape
+ // if modification of it is not in this result
+ aCandidatInThis = searchForOriginalShape(aShape, myDoc->Main());
+ if (aCandidatInThis.IsNull()) {
+ if (aCandidatContainer.IsNull())
+ return FeaturePtr();
+ // with the lower priority use the higher level shape that contains aShape
+ aCandidatInThis = aCandidatContainer;
+ anOldShape = aShapeContainer;
+ } else {
+ // to stop the searching by the following searchForOriginalShape
+ anOldShape.Nullify();
+ }
+ }
+
+ Handle(TNaming_NamedShape) aNS = searchForOriginalShape(anOldShape, myDoc->Main());
+ if (!aNS.IsNull())
+ aCandidatInThis = aNS;
+
+ FeaturePtr aResult;
+ TDF_Label aResultLab = aCandidatInThis->Label();
+ while(aResultLab.Depth() > 3)
+ aResultLab = aResultLab.Father();
+ FeaturePtr aFeature = myObjs->feature(aResultLab);
+ if (aFeature.get()) {
+ if (!aResult.get() || myObjs->isLater(aResult, aFeature)) {
+ aResult = aFeature;
+ }
+ }
+ return aResult;
+}
+
+bool Model_Document::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const
+{
+ return myObjs->isLater(theLater, theCurrent);
+}
+
+void Model_Document::storeNodesState(const std::list<bool>& theStates)
+{
+ TDF_Label aLab = generalLabel().FindChild(TAG_NODES_STATE);
+ aLab.ForgetAllAttributes();
+ if (!theStates.empty()) {
+ Handle(TDataStd_BooleanArray) anArray =
+ TDataStd_BooleanArray::Set(aLab, 0, int(theStates.size()) - 1);
+ std::list<bool>::const_iterator aState = theStates.begin();
+ for(int anIndex = 0; aState != theStates.end(); aState++, anIndex++) {
+ anArray->SetValue(anIndex, *aState);
+ }
+ }
+}
+
+void Model_Document::restoreNodesState(std::list<bool>& theStates) const
+{
+ TDF_Label aLab = generalLabel().FindChild(TAG_NODES_STATE);
+ Handle(TDataStd_BooleanArray) anArray;
+ if (aLab.FindAttribute(TDataStd_BooleanArray::GetID(), anArray)) {
+ int anUpper = anArray->Upper();
+ for(int anIndex = 0; anIndex <= anUpper; anIndex++) {
+ theStates.push_back(anArray->Value(anIndex) == Standard_True);
+ }
+ }
+}
+
+void Model_Document::eraseAllFeatures()
+{
+ if (myObjs)
+ myObjs->eraseAllFeatures();
+}
+
+void Model_Document::setExecuteFeatures(const bool theFlag)
+{
+ myExecuteFeatures = theFlag;
+ const std::set<int> aSubs = subDocuments();
+ std::set<int>::iterator aSubIter = aSubs.begin();
+ for (; aSubIter != aSubs.end(); aSubIter++) {
+ if (!subDoc(*aSubIter)->myObjs)
+ continue;
+ subDoc(*aSubIter)->setExecuteFeatures(theFlag);
+ }
+}
+
+void Model_Document::appendTransactionToPrevious()
+{
+ Transaction anAppended = myTransactions.back();
+ myTransactions.pop_back();
+ if (!myTransactions.empty()) { // if it is empty, just forget the appended
+ myTransactions.back().myOCAFNum += anAppended.myOCAFNum;
+ }
+ // propagate the same action to sub-documents
+ const std::set<int> aSubs = subDocuments();
+ for (std::set<int>::iterator aSubIter = aSubs.begin(); aSubIter != aSubs.end(); aSubIter++) {
+ subDoc(*aSubIter)->appendTransactionToPrevious();
+ }
+}
+
+/// GUID for keeping information about the auto-recomputation state
+static const Standard_GUID kAutoRecomputationID("8493fb74-0674-4912-a100-1cf46c7cfab3");
+
+void Model_Document::setAutoRecomutationState(const bool theState)
+{
+ if (theState)
+ generalLabel().FindChild(TAG_CURRENT_TRANSACTION).ForgetAttribute(kAutoRecomputationID);
+ else
+ TDataStd_UAttribute::Set(
+ generalLabel().FindChild(TAG_CURRENT_TRANSACTION), kAutoRecomputationID);
+}
+
+bool Model_Document::autoRecomutationState() const
+{
+ return !generalLabel().FindChild(TAG_CURRENT_TRANSACTION).IsAttribute(kAutoRecomputationID);
+}