From e7d00b991ec45ce6f8f421a589681ccc6e4a47ac Mon Sep 17 00:00:00 2001 From: mpv Date: Thu, 8 Nov 2018 17:09:06 +0300 Subject: [PATCH] Make selection of sketch elements created in another document (PartSet) working after save/open. --- src/Model/Model_BodyBuilder.cpp | 55 ++++++++++++-- src/Model/Model_Document.cpp | 92 +++++++++++++++++++++++- src/Selector/Selector_Selector.cpp | 111 ++++++++++++++++++++--------- 3 files changed, 218 insertions(+), 40 deletions(-) diff --git a/src/Model/Model_BodyBuilder.cpp b/src/Model/Model_BodyBuilder.cpp index c137ecc8d..952309d8a 100755 --- a/src/Model/Model_BodyBuilder.cpp +++ b/src/Model/Model_BodyBuilder.cpp @@ -30,11 +30,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -57,9 +59,11 @@ #include // DEB //#include -//#include //#define DEB_IMPORT 1 +/// reference to the shape in external document: sting list attribute identifier +static const Standard_GUID kEXTERNAL_SHAPE_REF("9aa5dd14-6d34-4a8d-8786-05842fd7bbbd"); + static const int INVALID_TAG = -1; static const int GENERATED_VERTICES_TAG = 1; static const int GENERATED_EDGES_TAG = 2; @@ -279,7 +283,8 @@ void Model_BodyBuilder::clean() delete aBuilder->second; // clear also shapes on cleaned sub-labels (#2241) Handle(TNaming_NamedShape) aNS; - if (aLab.FindChild(aBuilder->first).FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + TDF_Label aSubLab = aLab.FindChild(aBuilder->first); + if (aSubLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { aNS->Clear(); } } @@ -288,6 +293,10 @@ void Model_BodyBuilder::clean() // remove the old reference (if any) aLab.ForgetAttribute(TDF_Reference::GetID()); myFreePrimitiveTag = PRIMITIVES_START_TAG; + TDF_ChildIDIterator anEntriesIter(aLab, kEXTERNAL_SHAPE_REF, true); + for(; anEntriesIter.More(); anEntriesIter.Next()) { + anEntriesIter.Value()->Label().ForgetAttribute(kEXTERNAL_SHAPE_REF); + } } Model_BodyBuilder::~Model_BodyBuilder() @@ -478,8 +487,9 @@ TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) { } /// Checks that shape is presented in the tree with not-selection evolution +/// In theOriginalLabel it returns label where NS of old sub-shape is stored static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2, - TopoDS_Shape theShape) + TopoDS_Shape theShape, TDF_Label& theOriginalLabel) { bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape); if (aResult) { //check evolution and a label of this shape @@ -488,6 +498,7 @@ static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAcces static Handle(TNaming_NamedShape) aNS; if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { if (aNS->Evolution() != TNaming_SELECTED) { + theOriginalLabel = aNS->Label(); return true; } } @@ -495,11 +506,33 @@ static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAcces } if (!theAccess2.IsNull()) { static const TDF_Label anEmpty; - return isShapeInTree(theAccess2, anEmpty, theShape); + return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel); } return false; } +/// Stores entry to the external label in the entries list at this label +static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis) +{ + // store information about the external document reference to restore old shape on open + if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) { + Handle(TDataStd_ExtStringList) anEntries; + if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) { + anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF); + } + TCollection_AsciiString anEntry; + TDF_Tool::Entry(theExternal, anEntry); + // check it already contains this entry + TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List()); + for(; anIter.More(); anIter.Next()) + if (anIter.Value() == anEntry) + break; + if (!anIter.More()) { + anEntries->Append(anEntry); + } + } +} + void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, const GeomShapePtr& theOldShape, const GeomAPI_Shape::ShapeType theShapeTypeToExplore, @@ -529,7 +562,9 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_); TDF_Label anAccess2 = std::dynamic_pointer_cast( ModelAPI_Session::get()->moduleDocument())->generalLabel(); - bool anOldSubShapeNotInTree = !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_); + TDF_Label anOriginalLabel; + bool anOldSubShapeNotInTree = + !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel); if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) { continue; } @@ -588,6 +623,8 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, isGenerated ? aBuilder->Generated(anOldSubShape_, aNewShape_) : aBuilder->Modify(anOldSubShape_, aNewShape_); + // store information about the external document reference to restore old shape on open + storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label()); } } } @@ -612,7 +649,9 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_); TDF_Label anAccess2 = std::dynamic_pointer_cast( ModelAPI_Session::get()->moduleDocument())->generalLabel(); - bool anOldSubShapeNotInTree = !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_); + TDF_Label anOriginalLabel; + bool anOldSubShapeNotInTree = + !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel); if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) { continue; } @@ -646,6 +685,8 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG; for (TopExp_Explorer anExp(aNewShape_, aShapeTypeToExplore); anExp.More(); anExp.Next()) { builder(aTag)->Generated(anOldSubShape_, anExp.Current()); + // store information about the external document reference to restore old shape on open + storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label()); } buildName(aTag, theName); } @@ -654,6 +695,8 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, if (aTag == INVALID_TAG) return; builder(aTag)->Generated(anOldSubShape_, aNewShape_); buildName(aTag, theName); + // store information about the external document reference to restore old shape on open + storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label()); } } } diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index 2214929f8..0f9fbcea5 100755 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -51,13 +52,18 @@ #include #include #include +#include #include +#include #include #include #include #include #include #include +#include +#include +#include #include #include @@ -92,6 +98,9 @@ static const int TAG_NODES_STATE = 4; ///< array, tag of the Object Browser node ///< naming structures constructions selected from other document static const int TAG_EXTERNAL_CONSTRUCTIONS = 5; +/// reference to the shape in external document: sting list attribute identifier +static const Standard_GUID kEXTERNAL_SHAPE_REF("9aa5dd14-6d34-4a8d-8786-05842fd7bbbd"); + Model_Document::Model_Document(const int theID, const std::string theKind) : myID(theID), myKind(theKind), myIsActive(false), myIsSetCurrentFeature(false), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format @@ -136,6 +145,82 @@ bool Model_Document::isRoot() const return this == Model_Session::get()->moduleDocument().get(); } +/// Makes all modification and generation naming shapes that have old shapes corresponding to +/// shapes in a root document be equal to this root document +static void updateShapesFromRoot(const TDF_Label theThisAccess, const TDF_Label theRootAccess) +{ + TopTools_DataMapOfShapeShape aCurrentToRoot; // shapes that must be updated: from this to root + TDF_ChildIDIterator aThisIter(theThisAccess.Root(), kEXTERNAL_SHAPE_REF, true); + for(; aThisIter.More(); aThisIter.Next()) { + aCurrentToRoot.Clear(); + Handle(TNaming_NamedShape) aNS; + if (!aThisIter.Value()->Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) + continue; + if (aNS->Evolution() != TNaming_GENERATED && aNS->Evolution() != TNaming_MODIFY) + continue; + for (TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) { + const TopoDS_Shape& anOld = aNSIter.OldShape(); + if (anOld.IsNull()) + continue; + TNaming_OldShapeIterator aNewIter(anOld, theThisAccess); + for (; aNewIter.More(); aNewIter.Next()) { + TNaming_Evolution anEvolution = aNewIter.NamedShape()->Evolution(); + if (anEvolution != TNaming_SELECTED && anEvolution != TNaming_DELETE) + break; + } + if (aNewIter.More()) + continue; + GeomShapePtr anOldShape(new GeomAPI_Shape), aRootShape(new GeomAPI_Shape); + anOldShape->setImpl(new TopoDS_Shape(anOld)); + anOldShape = GeomAPI_Tools::getTypedShape(anOldShape); + + // search the same shape in the root document + Handle(TDataStd_ExtStringList) anEntries = + Handle(TDataStd_ExtStringList)::DownCast(aThisIter.Value()); + TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List()); + for (; anIter.More(); anIter.Next()) { + TDF_Label aRootLab; + TDF_Tool::Label(theRootAccess.Data(), anIter.Value(), aRootLab); + if (aRootLab.IsNull()) + continue; + Handle(TNaming_NamedShape) aRootNS; + if (!aRootLab.FindAttribute(TNaming_NamedShape::GetID(), aRootNS)) + continue; + TNaming_Iterator aRootShapes(aRootNS); + for (; aRootShapes.More(); aRootShapes.Next()) { + if (aRootShapes.NewShape().IsNull()) + continue; + aRootShape->setImpl(new TopoDS_Shape(aRootShapes.NewShape())); + aRootShape = GeomAPI_Tools::getTypedShape(aRootShape); + if (!anOldShape->isEqual(aRootShape)) // special checking by geometry + continue; + // found a good corresponded shape + if (!anOld.IsEqual(aRootShapes.NewShape())) + aCurrentToRoot.Bind(anOld, aRootShapes.NewShape()); + } + } + } + if (!aCurrentToRoot.IsEmpty()) { // update the whole named shape content + TopTools_ListOfShape anOld, aNew; + TNaming_Evolution anEvol = aNS->Evolution(); + for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) { + anOld.Prepend(aCurrentToRoot.IsBound(aNSIter.OldShape()) ? + aCurrentToRoot.Find(aNSIter.OldShape()) : aNSIter.OldShape()); + aNew.Prepend(aNSIter.NewShape()); + } + TNaming_Builder aBuilder(aNS->Label()); + TopTools_ListOfShape::Iterator anOldIter(anOld), aNewIter(aNew); + for(; anOldIter.More(); anOldIter.Next(), aNewIter.Next()) { + if (anEvol == TNaming_GENERATED) { + aBuilder.Generated(anOldIter.Value(), aNewIter.Value()); + } else if (anEvol == TNaming_MODIFY) { + aBuilder.Modify(anOldIter.Value(), aNewIter.Value()); + } + } + } + } +} + bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis) { Handle(Model_Application) anApp = Model_Application::getApplication(); @@ -225,7 +310,7 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum // update the current features status setCurrentFeature(currentFeature(false), false); aSession->setCheckTransactions(true); - aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); + aSession->setActiveDocument(aSession->moduleDocument(), false); // this is done in Part result "activate", so no needed here. Causes not-blue active part. // aSession->setActiveDocument(anApp->getDocument(myID), true); @@ -239,7 +324,10 @@ bool Model_Document::load(const char* theDirName, const char* theFileName, Docum anApp->setLoadByDemand(aPart->data()->name(), aPart->data()->document(ModelAPI_ResultPart::DOC_REF())->docId()); } - + if (!isRoot()) { + updateShapesFromRoot(myDoc->Main(), + std::dynamic_pointer_cast(aSession->moduleDocument())->generalLabel()); + } } else { // open failed, but new document was created to work with it: inform the model aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false); } diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index 5ea73e6af..4f5f62f2e 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -39,11 +38,14 @@ #include #include +#include +#include #include #include #include #include #include +#include #include @@ -54,6 +56,9 @@ static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171"); // reference attribute that contains the reference to labels where the "from" or "base" shapes // of selection are located static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f"); +// if the base array contains reference to the root label, this means that it refers to an +// external document and this list contains a tag in the document +static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a"); // array of the neighbor levels static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f"); // weak index (integer) of the sub-shape @@ -649,8 +654,37 @@ bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape return false; } +/// Stores the array of references to the label: references to elements of ref-list, then the last +static void storeBaseArray(const TDF_Label& theLab, + const TDF_LabelList& theRef, const TDF_Label& theLast) +{ + Handle(TDataStd_ReferenceArray) anArray = + TDataStd_ReferenceArray::Set(theLab, kBASE_ARRAY, 0, theRef.Extent()); + Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document + const TDF_Label aThisDocRoot = theLab.Root(); + TDF_LabelList::Iterator aBIter(theRef); + for(int anIndex = 0; true; aBIter.Next(), anIndex++) { + const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast; + // check this is a label of this document + if (aLab.Root().IsEqual(aThisDocRoot)) { + anArray->SetValue(anIndex, aLab); + } else { // store reference to external document as an entry-string + if (anEntries.IsNull()) { + anEntries = TDataStd_ExtStringList::Set(theLab, kBASE_LIST); + } + TCollection_AsciiString anEntry; + TDF_Tool::Entry(aLab, anEntry); + anEntries->Append(anEntry); + anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference + } + if (!aBIter.More()) + break; + } +} + void Selector_Selector::store() { + static const TDF_LabelList anEmptyRefList; myLab.ForgetAllAttributes(true); // remove old naming data TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType); if (myGeometricalNaming) @@ -670,19 +704,11 @@ void Selector_Selector::store() break; } case SELTYPE_PRIMITIVE: { - Handle(TDataStd_ReferenceArray) anArray = - TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0); - anArray->SetValue(0, myFinal); + storeBaseArray(myLab, anEmptyRefList, myFinal); break; } case SELTYPE_MODIFICATION: { - Handle(TDataStd_ReferenceArray) anArray = - TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent()); - TDF_LabelList::Iterator aBIter(myBases); - for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) { - anArray->SetValue(anIndex, aBIter.Value()); - } - anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array + storeBaseArray(myLab, myBases, myFinal); if (myWeakIndex != -1) { TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); } @@ -707,11 +733,8 @@ void Selector_Selector::store() case SELTYPE_WEAK_NAMING: { TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType); - // store myFinal in the base array if (!myFinal.IsNull()) { - Handle(TDataStd_ReferenceArray) anArray = - TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0); - anArray->SetValue(0, myFinal); + storeBaseArray(myLab, anEmptyRefList, myFinal); } break; } @@ -721,6 +744,43 @@ void Selector_Selector::store() } } +/// Restores references to the labels: references to elements of ref-list, then the last +static bool restoreBaseArray(const TDF_Label& theLab, const TDF_Label& theBaseDocumetnLab, + TDF_LabelList& theRef, TDF_Label& theLast) +{ + const TDF_Label aThisDocRoot = theLab.Root(); + Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document + TDataStd_ListOfExtendedString::Iterator anIter; + Handle(TDataStd_ReferenceArray) anArray; + if (theLab.FindAttribute(kBASE_ARRAY, anArray)) { + int anUpper = anArray->Upper(); + for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) { + TDF_Label aLab = anArray->Value(anIndex); + if (aLab.IsEqual(aThisDocRoot)) { // external document reference + if (theBaseDocumetnLab.IsNull()) + return false; + if (anEntries.IsNull()) { + if (!theLab.FindAttribute(kBASE_LIST, anEntries)) + return false; + anIter.Initialize(anEntries->List()); + } + if (!anIter.More()) + return false; + TDF_Tool::Label(theBaseDocumetnLab.Data(), anIter.Value(), aLab); + anIter.Next(); + } + if (anIndex == anUpper) { + theLast = aLab; + } else { + theRef.Append(aLab); + } + } + return true; + } + return false; +} + + bool Selector_Selector::restore() { Handle(TDataStd_Integer) aTypeAttr; @@ -751,21 +811,10 @@ bool Selector_Selector::restore() return aSubResult; } case SELTYPE_PRIMITIVE: { - Handle(TDataStd_ReferenceArray) anArray; - if (myLab.FindAttribute(kBASE_ARRAY, anArray)) { - myFinal = anArray->Value(0); - return true; - } - return false; + return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal); } case SELTYPE_MODIFICATION: { - Handle(TDataStd_ReferenceArray) anArray; - if (myLab.FindAttribute(kBASE_ARRAY, anArray)) { - int anUpper = anArray->Upper(); - for(int anIndex = 0; anIndex < anUpper; anIndex++) { - myBases.Append(anArray->Value(anIndex)); - } - myFinal = anArray->Value(anUpper); + if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) { Handle(TDataStd_Integer) aWeakInt; if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) { myWeakIndex = aWeakInt->Get(); @@ -806,10 +855,8 @@ bool Selector_Selector::restore() if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr)) return false; myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); - Handle(TDataStd_ReferenceArray) anArray; - if (myLab.FindAttribute(kBASE_ARRAY, anArray)) { - myFinal = anArray->Value(0); - } + if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) + return false; return true; } default: { // unknown case -- 2.39.2