X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_BodyBuilder.cpp;h=d397d0a9b3f4176d8a862af9d6d89d1b81a4c46e;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=ae6f60d88c93282077cf244a42cf82681c75ef08;hpb=2e60d80d7d0b998fded953311cc8d2931ef5bb4b;p=modules%2Fshaper.git diff --git a/src/Model/Model_BodyBuilder.cpp b/src/Model/Model_BodyBuilder.cpp old mode 100755 new mode 100644 index ae6f60d88..d397d0a9b --- a/src/Model/Model_BodyBuilder.cpp +++ b/src/Model/Model_BodyBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2024 CEA, EDF // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,27 +12,32 @@ // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include +#include + #include #include +#include #include #include #include #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -55,9 +60,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; @@ -74,6 +81,7 @@ static int getGenerationTag(const TopoDS_Shape& theShape) { case TopAbs_VERTEX: return GENERATED_VERTICES_TAG; case TopAbs_EDGE: return GENERATED_EDGES_TAG; case TopAbs_FACE: return GENERATED_FACES_TAG; + default: break; // [to avoid compilation warning] } return INVALID_TAG; @@ -85,26 +93,12 @@ static int getModificationTag(const TopoDS_Shape& theShape) { case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG; case TopAbs_EDGE: return MODIFIED_EDGES_TAG; case TopAbs_FACE: return MODIFIED_FACES_TAG; + default: break; // [to avoid compilation warning] } return INVALID_TAG; } -static TopAbs_ShapeEnum convertShapeType(const GeomAPI_Shape::ShapeType theType) { - switch (theType) { - case GeomAPI_Shape::VERTEX: return TopAbs_VERTEX; - case GeomAPI_Shape::EDGE: return TopAbs_EDGE; - case GeomAPI_Shape::WIRE: return TopAbs_WIRE; - case GeomAPI_Shape::FACE: return TopAbs_FACE; - case GeomAPI_Shape::SHELL: return TopAbs_SHELL; - case GeomAPI_Shape::SOLID: return TopAbs_SOLID; - case GeomAPI_Shape::COMPSOLID: return TopAbs_COMPSOLID; - case GeomAPI_Shape::COMPOUND: return TopAbs_COMPOUND; - case GeomAPI_Shape::SHAPE: return TopAbs_SHAPE; - } - return TopAbs_SHAPE; -} - static bool isAlreadyStored(const TNaming_Builder* theBuilder, const TopoDS_Shape& theOldShape, const TopoDS_Shape& theNewShape) @@ -129,12 +123,59 @@ Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner) { } +/// 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, TDF_Label& theOriginalLabel) +{ + bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape); + if (aResult) { //check evolution and a label of this shape + for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next()) + { + Handle(TNaming_NamedShape) aNS; + if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aNS->Evolution() != TNaming_SELECTED) { + theOriginalLabel = aNS->Label(); + return true; + } + } + } + } + if (!theAccess2.IsNull()) { + static const TDF_Label anEmpty; + 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::store(const GeomShapePtr& theShape, const bool theIsStoreSameShapes) { std::shared_ptr aData = std::dynamic_pointer_cast(data()); if (aData) { - TDF_Label& aShapeLab = aData->shapeLab(); + TDF_Label aShapeLab = aData->shapeLab(); // clean builders clean(); // store the new shape as primitive @@ -146,8 +187,11 @@ void Model_BodyBuilder::store(const GeomShapePtr& theShape, return; // null shape inside if(!theIsStoreSameShapes) { - Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab); - if(!aNS.IsNull() && !aNS->IsEmpty()) { + Handle(TNaming_NamedShape) aNS; + if (TNaming_Tool::HasLabel(aShapeLab, aShape)) + aNS = TNaming_Tool::NamedShape(aShape, aShapeLab); + // the last condition is for the issue 2751 : existing shape may be found in compound-NS + if(!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShape)) { // This shape is already in document, store reference instead of shape; const TDF_Label aFoundLabel = aNS->Label(); TDF_Reference::Set(aShapeLab, aFoundLabel); @@ -162,7 +206,7 @@ void Model_BodyBuilder::store(const GeomShapePtr& theShape, if(!aBuilder.NamedShape()->IsEmpty()) { Handle(TDataStd_Name) anAttr; if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) { - std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString()); + std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString()); if(!aName.empty()) { std::shared_ptr aDoc = std::dynamic_pointer_cast(document()); @@ -174,15 +218,14 @@ void Model_BodyBuilder::store(const GeomShapePtr& theShape, } void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape, - const GeomShapePtr& theToShape) + const GeomShapePtr& theToShape, const bool theIsCleanStored) { std::shared_ptr aData = std::dynamic_pointer_cast(data()); if (aData) { - TDF_Label& aShapeLab = aData->shapeLab(); // clean builders - clean(); - // store the new shape as primitive - TNaming_Builder aBuilder(aShapeLab); + if (theIsCleanStored) + clean(); + TNaming_Builder* aBuilder = builder(0); if (!theFromShape || !theToShape) return; // bad shape TopoDS_Shape aShapeBasis = theFromShape->impl(); @@ -191,29 +234,81 @@ void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape, TopoDS_Shape aShapeNew = theToShape->impl(); if (aShapeNew.IsNull()) return; // null shape inside - aBuilder.Generated(aShapeBasis, aShapeNew); + + // There is no sense to write history if old shape does not exist in the document. + TDF_Label anAccess2 = std::dynamic_pointer_cast( + ModelAPI_Session::get()->moduleDocument())->generalLabel(); + TDF_Label anOriginalLabel; + if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeBasis, anOriginalLabel)) { + if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway + aBuilder->Generated(aShapeNew); + } + } else { + if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before + myBuilders.erase(0); + aBuilder = builder(0); + } + + aBuilder->Generated(aShapeBasis, aShapeNew); + // store information about the external document reference to restore old shape on open + storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label()); + } + // register name - if(!aBuilder.NamedShape()->IsEmpty()) { + if(!aBuilder->NamedShape()->IsEmpty()) { Handle(TDataStd_Name) anAttr; - if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) { - std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString()); + if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) { + std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString()); if(!aName.empty()) { std::shared_ptr aDoc = std::dynamic_pointer_cast(document()); - aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName); + aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName); } } } } } +void Model_BodyBuilder::storeGenerated(const std::list& theFromShapes, + const GeomShapePtr& theToShape, const std::shared_ptr theMakeShape) +{ + bool aStored = false; + std::list::const_iterator anOldIter = theFromShapes.cbegin(); + for (; anOldIter != theFromShapes.cend(); anOldIter++) { + bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire(); + if (!aStore) { + ListOfShape aNews; // check this old really generates theToShape + theMakeShape->generated(*anOldIter, aNews); + ListOfShape::iterator aNewIter = aNews.begin(); + for (; aNewIter != aNews.end(); aNewIter++) { + if (theToShape->isSame(*aNewIter)) + break; + } + aStore = aNewIter != aNews.end(); + } + if (aStore) { + storeGenerated(*anOldIter, theToShape, !aStored); + TNaming_Builder* aBuilder = builder(0); + aStored = !aBuilder->NamedShape()->IsEmpty(); + } + } + if (!aStored) { // store as PRIMITIVE, but clean in any way + store(theToShape); + return; + } +} + +static TDF_Label builderLabel(DataPtr theData, const int theTag ) +{ + std::shared_ptr aData = std::dynamic_pointer_cast(theData); + return theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag); +} + TNaming_Builder* Model_BodyBuilder::builder(const int theTag) { std::map::iterator aFind = myBuilders.find(theTag); if (aFind == myBuilders.end()) { - std::shared_ptr aData = std::dynamic_pointer_cast(data()); - myBuilders[theTag] = new TNaming_Builder( - theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag)); + myBuilders[theTag] = new TNaming_Builder(builderLabel(data(), theTag)); aFind = myBuilders.find(theTag); } return aFind->second; @@ -227,7 +322,6 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape, if (aData) { // clean builders if (theIsCleanStored) clean(); - // store the new shape as primitive TNaming_Builder* aBuilder = builder(0); if (!theOldShape || !theNewShape) return; // bad shape @@ -237,11 +331,48 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape, TopoDS_Shape aShapeNew = theNewShape->impl(); if (aShapeNew.IsNull()) return; // null shape inside - aBuilder->Modify(aShapeOld, aShapeNew); + + // There is no sense to write history if old shape does not exist in the document. + TDF_Label anAccess2 = std::dynamic_pointer_cast( + ModelAPI_Session::get()->moduleDocument())->generalLabel(); + TDF_Label anOriginalLabel; + TopTools_ListOfShape anOldList; + if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeOld, anOriginalLabel)) { + // check this could be a compund by the whole feature selection + if (aShapeOld.ShapeType() == TopAbs_COMPOUND) { + for(TopoDS_Iterator aCompIter(aShapeOld); aCompIter.More(); aCompIter.Next()) { + if (isShapeInTree(aData->shapeLab(), anAccess2, aCompIter.Value(), anOriginalLabel)) { + anOldList.Append(aCompIter.Value()); + } else { + anOldList.Clear(); + break; + } + } + } + } else { + anOldList.Append(aShapeOld); + } + if (anOldList.IsEmpty()) { + if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway + aBuilder->Generated(aShapeNew); + } + } else { + if (aBuilder->NamedShape()->Evolution() == TNaming_PRIMITIVE) { // erase primitive before + myBuilders.erase(0); + aBuilder = builder(0); + } + TopTools_ListIteratorOfListOfShape anOldIter(anOldList); + for(; anOldIter.More(); anOldIter.Next()) { + aBuilder->Modify(anOldIter.Value(), aShapeNew); + } + // store information about the external document reference to restore old shape on open + storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label()); + } + if(!aBuilder->NamedShape()->IsEmpty()) { Handle(TDataStd_Name) anAttr; - if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) { - std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString()); + if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) { + std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString()); if(!aName.empty()) { std::shared_ptr aDoc = std::dynamic_pointer_cast(document()); @@ -252,18 +383,52 @@ void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape, } } -void Model_BodyBuilder::storeWithoutNaming(const GeomShapePtr& theShape) +void Model_BodyBuilder::storeModified(const std::list& theOldShapes, + const GeomShapePtr& theNewShape, const std::shared_ptr theMakeShape) { - std::shared_ptr aData = std::dynamic_pointer_cast(data()); - if (aData) { - clean(); - if (!theShape.get()) - return; // bad shape - TopoDS_Shape aShape = theShape->impl(); - if (aShape.IsNull()) - return; // null shape inside - TNaming_Builder aBuilder(aData->shapeLab()); - aBuilder.Select(aShape, aShape); + bool aStored = false; + std::list::const_iterator anOldIter = theOldShapes.cbegin(); + for(; anOldIter != theOldShapes.cend(); anOldIter++) { + // compounds may cause crash if call "modified" + bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire() || + (*anOldIter)->isCompSolid(); + if (!aStore) { + ListOfShape aNews; // check this old really modifies theNewShape + theMakeShape->modified(*anOldIter, aNews); + ListOfShape::iterator aNewIter = aNews.begin(); + for(; aNewIter != aNews.end(); aNewIter++) { + if (theNewShape->isSame(*aNewIter)) + break; + } + aStore = aNewIter != aNews.end(); + } + if (aStore) { + storeModified(*anOldIter, theNewShape, !aStored); + TNaming_Builder* aBuilder = builder(0); + aStored = !aBuilder->NamedShape()->IsEmpty(); + } + } + if (!aStored) { + // check the new shape is already in the tree, so, no need to store primitive, just reference + std::shared_ptr aData = std::dynamic_pointer_cast(data()); + if (aData.get()) { + TDF_Label aShapeLab = aData->shapeLab(); + TopoDS_Shape aShapeNew = theNewShape->impl(); + Handle(TNaming_NamedShape) aNS; + if (TNaming_Tool::HasLabel(aShapeLab, aShapeNew)) + aNS = TNaming_Tool::NamedShape(aShapeNew, aShapeLab); + // the last condition is for the issue 2751 : existing shape may be found in compound-NS + if (!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShapeNew)) { + // This shape is already in document, store reference instead of shape; + const TDF_Label aFoundLabel = aNS->Label(); + TDF_Reference::Set(aShapeLab, aFoundLabel); + myBuilders.erase(0); + aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID()); + return; + } + } + store(theNewShape); // store as PRIMITIVE, but clean in any way + return; } } @@ -274,17 +439,25 @@ void Model_BodyBuilder::clean() return; std::map::iterator aBuilder = myBuilders.begin(); for(; aBuilder != myBuilders.end(); aBuilder++) { + Handle(TNaming_NamedShape) aNS = aBuilder->second->NamedShape(); 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)) { - aNS->Clear(); - } + if (!aNS.IsNull() && !aNS->Label().IsNull()) + aNS->Label().ForgetAttribute(TNaming_NamedShape::GetID()); } myBuilders.clear(); + myPrimitivesNamesIndexMap.clear(); // 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); + } +} + +void Model_BodyBuilder::cleanCash() +{ + myPrimitivesNamesIndexMap.clear(); } Model_BodyBuilder::~Model_BodyBuilder() @@ -306,17 +479,43 @@ void Model_BodyBuilder::buildName(const int theTag, const std::string& theName) } aName.insert(0, aPrefix); - TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str()); + TDataStd_Name::Set(builderLabel(data(), theTag), aName.c_str()); } -void Model_BodyBuilder::generated(const GeomShapePtr& theNewShape, - const std::string& theName) +bool Model_BodyBuilder::generated(const GeomShapePtr& theNewShape, + const std::string& theName, + const bool theCheckIsInResult) { + GeomShapePtr aResultShape = shape(); + if (theCheckIsInResult) { + bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(theNewShape, false); + if (aNewShapeIsNotInResultShape) { + return false; + } + } + TopoDS_Shape aShape = theNewShape->impl(); builder(myFreePrimitiveTag)->Generated(aShape); if (!theName.empty()) { - buildName(myFreePrimitiveTag, theName); + std::string aName = theName; + if (myPrimitivesNamesIndexMap.find(theName) != myPrimitivesNamesIndexMap.end()) { + IndexTags& anIndexTags = myPrimitivesNamesIndexMap.find(theName)->second; + aName += "_" + std::to_string(++(anIndexTags.index)); + anIndexTags.tags.push_back(myFreePrimitiveTag); + if (anIndexTags.index == 2) { + buildName(anIndexTags.tags.front(), theName + "_1"); + } + } + else { + IndexTags anIndexTags; + anIndexTags.index = 1; + anIndexTags.tags.push_back(myFreePrimitiveTag); + myPrimitivesNamesIndexMap[theName] = anIndexTags; + } + + buildName(myFreePrimitiveTag, aName); } ++myFreePrimitiveTag; + return true; } void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape, @@ -330,7 +529,7 @@ void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape, if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) { // TODO: This is a workaround. New shape should be only vertex, edge or face. TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE; - aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG; + aTag = aNewShapeType == TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG; for (TopExp_Explorer anExp(aNewShape, aShapeTypeToExplore); anExp.More(); anExp.Next()) { builder(aTag)->Generated(anOldShape, anExp.Current()); } @@ -355,12 +554,6 @@ void Model_BodyBuilder::modified(const GeomShapePtr& theOldShape, buildName(aTag, theName); } -void Model_BodyBuilder::deleted(const GeomShapePtr& theOldShape) -{ - TopoDS_Shape aShape = theOldShape->impl(); - builder(DELETED_TAG)->Delete(aShape); -} - void Model_BodyBuilder::loadDeletedShapes(const GeomMakeShapePtr& theAlgo, const GeomShapePtr& theOldShape, const GeomAPI_Shape::ShapeType theShapeTypeToExplore, @@ -394,22 +587,6 @@ void Model_BodyBuilder::loadDeletedShapes(const GeomMakeShapePtr& theAlgo, } } -static void removeBadShapes(ListOfShape& theShapes) -{ - ListOfShape::iterator anIt = theShapes.begin(); - while (anIt != theShapes.end()) { - TopoDS_Shape aNewShape = (*anIt)->impl(); - bool aSkip = aNewShape.IsNull() - || (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape))); - if (aSkip) { - ListOfShape::iterator aRemoveIt = anIt++; - theShapes.erase(aRemoveIt); - } else { - ++anIt; - } - } -} - // Keep only the shapes with minimal shape type static void keepTopLevelShapes(ListOfShape& theShapes, const TopoDS_Shape& theRoot, @@ -442,15 +619,6 @@ static void keepTopLevelShapes(ListOfShape& theShapes, } } -// returns an ancestor shape-type thaty used for naming-definition of the sub-type -TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) { - if (theSubType == TopAbs_VERTEX) - return TopAbs_EDGE; - if (theSubType == TopAbs_EDGE) - return TopAbs_FACE; - return TopAbs_VERTEX; // bad case -} - void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, const GeomShapePtr& theOldShape, const GeomAPI_Shape::ShapeType theShapeTypeToExplore, @@ -466,6 +634,11 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, if (aCompound.get()) aShapeToExplore = aCompound; } + // Store all types of subshapes in the map to use them for checking + // if the new shapes are sub-shapes of this result + TopTools_MapOfShape aResultShapeSubMap; + TopExp::MapShapes(aResultShape->impl(), aResultShapeSubMap); + TopTools_MapOfShape anAlreadyProcessedShapes; std::shared_ptr aData = std::dynamic_pointer_cast(data()); for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore); @@ -477,11 +650,14 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, // There is no sense to write history if shape already processed // or old shape does not exist in the document. - bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_); - bool anOldSubShapeNotInTree = TNaming_Tool::NamedShape(anOldSubShape_, aData->shapeLab()) - .IsNull(); - if (anOldSubShapeAlreadyProcessed - || anOldSubShapeNotInTree) + if (!anAlreadyProcessedShapes.Add(anOldSubShape_)) + { + continue; + } + + TDF_Label anAccess2 = std::dynamic_pointer_cast(ModelAPI_Session::get()->moduleDocument())->generalLabel(); + TDF_Label anOriginalLabel; + if (!isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel)) { continue; } @@ -489,57 +665,35 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, // Get new shapes. ListOfShape aNewShapes; theAlgo->modified(anOldSubShape, aNewShapes); - for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin(); aNewShapesIt != aNewShapes.cend(); ++aNewShapesIt) { GeomShapePtr aNewShape = *aNewShapesIt; const TopoDS_Shape& aNewShape_ = aNewShape->impl(); - bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType(); - bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape); - bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false); - if (aNewShapeIsSameAsOldShape - || aNewShapeIsNotInResultShape) - { + if (anOldSubShape->isSame(aNewShape)) continue; - } - TNaming_Builder* aBuilder; - if (aResultShape->isSame(aNewShape)) { - // keep the modification evolution on the root level (2241 - history propagation issue) - aBuilder = builder(0); - TDF_Label aShapeLab = aBuilder->NamedShape()->Label(); - Handle(TDF_Reference) aRef; - if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) { - // Store only in case if it does not have reference. - continue; - } + if (aResultShape->isSame(aNewShape)) + continue; // it is stored on the root level (2241 - history propagation issue) - // Check if new shape was already stored. - if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue; - - if (!aBuilder->NamedShape().IsNull() && - ((isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_GENERATED) - || (!isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_MODIFY))) - { - myBuilders.erase(0); // clear old builder to avoid different evolutions crash - aBuilder = builder(0); - } - } else { - int aTag = isGenerated ? getGenerationTag(aNewShape_) - : getModificationTag(aNewShape_); - aBuilder = builder(aTag); - - // Check if new shape was already stored. - if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue; + // Look in the map instead of aResultShape->isSubShape(aNewShape, false) + // to avoid many iterations of sub-shapes hierarchy that leads to performance issues + if (!aResultShapeSubMap.Contains(aNewShape_)) + continue; - buildName(aTag, theName); - } + const bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType(); + int aTag = isGenerated ? getGenerationTag(aNewShape_) : getModificationTag(aNewShape_); + TNaming_Builder*aBuilder = builder(aTag); + if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) + continue; // new shape was already stored. + buildName(aTag, theName); 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()); } } } @@ -547,9 +701,12 @@ void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo, void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, const GeomShapePtr& theOldShape, const GeomAPI_Shape::ShapeType theShapeTypeToExplore, - const std::string& theName) + const std::string& theName, + const bool theSaveOldIfNotInTree) { + GeomShapePtr aResultShape = shape(); TopTools_MapOfShape anAlreadyProcessedShapes; + std::shared_ptr aData = std::dynamic_pointer_cast(data()); for (GeomAPI_ShapeExplorer anOldShapeExp(theOldShape, theShapeTypeToExplore); anOldShapeExp.more(); anOldShapeExp.next()) @@ -557,8 +714,23 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, GeomShapePtr anOldSubShape = anOldShapeExp.current(); const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl(); - // There is no sense to write history if shape already processed. - if (!anAlreadyProcessedShapes.Add(anOldSubShape_)) continue; + // There is no sense to write history if shape already processed + // or old shape does not exist in the document. + bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_); + TDF_Label anAccess2 = std::dynamic_pointer_cast( + ModelAPI_Session::get()->moduleDocument())->generalLabel(); + TDF_Label anOriginalLabel; + bool anOldSubShapeNotInTree = + !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel); + if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) { + // The second condition is added due to #20170 because sub-shape must be added to real parent + // shape, not the reference. The naming name of pure reference is not registered in document. + if (theSaveOldIfNotInTree && !aData->shapeLab().IsAttribute(TDF_Reference::GetID())) { + std::string aSelectionName = theName + "Selected"; + generated(anOldSubShape, aSelectionName, false); + } else + continue; + } // Get new shapes. ListOfShape aNewShapes; @@ -573,27 +745,40 @@ void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo, GeomShapePtr aNewShape = *aNewShapesIt; const TopoDS_Shape& aNewShape_ = aNewShape->impl(); + bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape); + bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false); + if (aNewShapeIsSameAsOldShape || aNewShapeIsNotInResultShape) { + continue; + } + + if (aResultShape->isSame(aNewShape)) + continue; // it is stored on the root level + TopAbs_ShapeEnum aNewShapeType = aNewShape_.ShapeType(); if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) { // TODO: This is a workaround. New shape should be only edge or face. TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE; - int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG; + int aTag = aNewShapeType == 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, builderLabel(data(), aTag)); } buildName(aTag, theName); - } - else { + } else { int aTag = getGenerationTag(aNewShape_); 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, builderLabel(data(), aTag)); } } } } +// LCOV_EXCL_START //======================================================================= int getDangleShapes(const TopoDS_Shape& theShapeIn, const TopAbs_ShapeEnum theGeneratedFrom, @@ -626,6 +811,7 @@ void loadGeneratedDangleShapes( for (; itr.More(); itr.Next()) theBuilder->Generated(itr.Key(), itr.Value()); } +// LCOV_EXCL_STOP //======================================================================= void Model_BodyBuilder::loadNextLevels(GeomShapePtr theShape, @@ -786,8 +972,12 @@ int findAmbiguities(const TopoDS_Shape& theShapeIn, //======================================================================= void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& theName) { - if(theShape->isNull()) return; - TopoDS_Shape aShape = theShape->impl(); + GeomShapePtr aShapePtr = shape(); + if (theShape->isNull() || !aShapePtr.get()) + return; + TopoDS_Shape aShape = shape()->impl(); + if (aShape.IsNull()) + return; std::string aName; if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) { TopoDS_Iterator itr(aShape); @@ -826,121 +1016,6 @@ void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& } } -//======================================================================= -void Model_BodyBuilder::loadDisconnectedEdges(GeomShapePtr theShape, const std::string& theName) -{ - if(theShape->isNull()) return; - TopoDS_Shape aShape = theShape->impl(); - TopTools_DataMapOfShapeListOfShape edgeNaborFaces; - TopTools_ListOfShape empty; - TopExp_Explorer explF(aShape, TopAbs_FACE); - for (; explF.More(); explF.Next()) { - const TopoDS_Shape& aFace = explF.Current(); - TopExp_Explorer explV(aFace, TopAbs_EDGE); - for (; explV.More(); explV.Next()) { - const TopoDS_Shape& anEdge = explV.Current(); - if (!edgeNaborFaces.IsBound(anEdge)) edgeNaborFaces.Bind(anEdge, empty); - Standard_Boolean faceIsNew = Standard_True; - TopTools_ListIteratorOfListOfShape itrF(edgeNaborFaces.Find(anEdge)); - for (; itrF.More(); itrF.Next()) { - if (itrF.Value().IsSame(aFace)) { - faceIsNew = Standard_False; - break; - } - } - if (faceIsNew) - edgeNaborFaces.ChangeFind(anEdge).Append(aFace); - } - } - - TopTools_MapOfShape anEdgesToDelete; - TopExp_Explorer anEx(aShape,TopAbs_EDGE); - std::string aName; - for(;anEx.More();anEx.Next()) { - Standard_Boolean aC0 = Standard_False; - TopoDS_Shape anEdge1 = anEx.Current(); - if (edgeNaborFaces.IsBound(anEdge1)) { - const TopTools_ListOfShape& aList1 = edgeNaborFaces.Find(anEdge1); - if (aList1.Extent()<2) continue; - TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(edgeNaborFaces); - for (; itr.More(); itr.Next()) { - TopoDS_Shape anEdge2 = itr.Key(); - if(anEdgesToDelete.Contains(anEdge2)) continue; - if (anEdge1.IsSame(anEdge2)) continue; - const TopTools_ListOfShape& aList2 = itr.Value(); - // compare lists of the neighbour faces of edge1 and edge2 - if (aList1.Extent() == aList2.Extent()) { - Standard_Integer aMatches = 0; - for(TopTools_ListIteratorOfListOfShape aLIter1(aList1);aLIter1.More();aLIter1.Next()) - for(TopTools_ListIteratorOfListOfShape aLIter2(aList2);aLIter2.More();aLIter2.Next()) - if (aLIter1.Value().IsSame(aLIter2.Value())) aMatches++; - if (aMatches == aList1.Extent()) { - aC0=Standard_True; - builder(myFreePrimitiveTag)->Generated(anEdge2); - anEdgesToDelete.Add(anEdge2); - TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1); - aName = theName + "_" + aStr.ToCString(); - buildName(myFreePrimitiveTag, aName); - ++myFreePrimitiveTag; - } - } - } - TopTools_MapIteratorOfMapOfShape itDelete(anEdgesToDelete); - for(;itDelete.More();itDelete.Next()) - edgeNaborFaces.UnBind(itDelete.Key()); - edgeNaborFaces.UnBind(anEdge1); - } - if (aC0) { - builder(myFreePrimitiveTag)->Generated(anEdge1); - TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1); - aName = theName + "_" + aStr.ToCString(); - buildName(myFreePrimitiveTag, aName); - ++myFreePrimitiveTag; - } - } -} - -void Model_BodyBuilder::loadDisconnectedVertexes(GeomShapePtr theShape, - const std::string& theName) -{ - if(theShape->isNull()) return; - TopoDS_Shape aShape = theShape->impl(); - TopTools_DataMapOfShapeListOfShape vertexNaborEdges; - TopTools_ListOfShape empty; - TopExp_Explorer explF(aShape, TopAbs_EDGE); - for (; explF.More(); explF.Next()) { - const TopoDS_Shape& anEdge = explF.Current(); - TopExp_Explorer explV(anEdge, TopAbs_VERTEX); - for (; explV.More(); explV.Next()) { - const TopoDS_Shape& aVertex = explV.Current(); - if (!vertexNaborEdges.IsBound(aVertex)) vertexNaborEdges.Bind(aVertex, empty); - Standard_Boolean faceIsNew = Standard_True; - TopTools_ListIteratorOfListOfShape itrF(vertexNaborEdges.Find(aVertex)); - for (; itrF.More(); itrF.Next()) { - if (itrF.Value().IsSame(anEdge)) { - faceIsNew = Standard_False; - break; - } - } - if (faceIsNew) { - vertexNaborEdges.ChangeFind(aVertex).Append(anEdge); - } - } - } - std::string aName; - TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(vertexNaborEdges); - for (; itr.More(); itr.Next()) { - const TopTools_ListOfShape& naborEdges = itr.Value(); - if (naborEdges.Extent() < 2) { - builder(myFreePrimitiveTag)->Generated(itr.Key()); - TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1); - aName = theName + "_" + aStr.ToCString(); - buildName(myFreePrimitiveTag, aName); - ++myFreePrimitiveTag; - } - } -} - GeomShapePtr Model_BodyBuilder::shape() { std::shared_ptr aData = std::dynamic_pointer_cast(data()); @@ -962,28 +1037,3 @@ GeomShapePtr Model_BodyBuilder::shape() } return GeomShapePtr(); } - -bool Model_BodyBuilder::isLatestEqual(const GeomShapePtr& theShape) -{ - if (theShape.get()) { - TopoDS_Shape aShape = theShape->impl(); - std::shared_ptr aData = std::dynamic_pointer_cast(data()); - if (aData) { - TDF_Label& aShapeLab = aData->shapeLab(); - Handle(TNaming_NamedShape) aName; - if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) { - TopoDS_Shape aLatest = TNaming_Tool::CurrentShape(aName); - if (aLatest.IsNull()) - return false; - if (aLatest.IsEqual(aShape)) - return true; - // check sub-shapes for comp-solids: - for (TopExp_Explorer anExp(aShape, aLatest.ShapeType()); anExp.More(); anExp.Next()) { - if (aLatest.IsEqual(anExp.Current())) - return true; - } - } - } - } - return false; -}