X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_ResultBody.cpp;h=c5bedb6bae96d0c57bbaea334ff4e774b974df0c;hb=8d04b5f4360b23cf376beff9c5e7c12d0e6a5f1e;hp=c68a4ae4b54f2107f56759a0fa7c5bcfbc99ed29;hpb=e139a7ce9d4f98a1622bdc438da9599e59f404ff;p=modules%2Fshaper.git diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index c68a4ae4b..c5bedb6ba 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,10 +12,9 @@ // // 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 @@ -27,11 +26,20 @@ #include #include #include +#include #include +#include +#include #include #include +#include +#include +// if this attribute exists, the shape is connected topology +Standard_GUID kIsConnectedTopology("e51392e0-3a4d-405d-8e36-bbfe19858ef5"); +// if this attribute exists, the connected topology flag must be recomputed +Standard_GUID kUpdateConnectedTopology("01ef7a45-0bec-4266-b0b4-4aa570921818"); Model_ResultBody::Model_ResultBody() : ModelAPI_ResultBody() { @@ -46,43 +54,62 @@ Model_ResultBody::~Model_ResultBody() delete myBuilder; } -void Model_ResultBody::loadAndOrientModifiedShapes(GeomAlgoAPI_MakeShape* theMS, - std::shared_ptr theShapeIn, const int theKindOfShape, const int theTag, - const std::string& theName, GeomAPI_DataMapOfShapeShape& theSubShapes, - const bool theIsStoreSeparate, - const bool theIsStoreAsGenerated, - const bool theSplitInSubs) +bool Model_ResultBody::generated(const GeomShapePtr& theNewShape, + const std::string& theName, const bool theCheckIsInResult) { - if (theSplitInSubs && mySubs.size()) { // consists of subs + bool aResult = false; + if (mySubs.size()) { // consists of subs + for (std::vector::const_iterator aSubIter = mySubs.cbegin(); + aSubIter != mySubs.cend(); + ++aSubIter) + { + const ResultBodyPtr& aSub = *aSubIter; + if (aSub->generated(theNewShape, theName, theCheckIsInResult)) + aResult = true; + } + } else { // do for this directly + if (myBuilder->generated(theNewShape, theName, theCheckIsInResult)) + aResult = true; + } + return aResult; +} + +void Model_ResultBody::loadGeneratedShapes(const std::shared_ptr& theAlgo, + const GeomShapePtr& theOldShape, + const GeomAPI_Shape::ShapeType theShapeTypeToExplore, + const std::string& theName, + const bool theSaveOldIfNotInTree) +{ + if (mySubs.size()) { // consists of subs + for (std::vector::const_iterator aSubIter = mySubs.cbegin(); + aSubIter != mySubs.cend(); + ++aSubIter) + { + const ResultBodyPtr& aSub = *aSubIter; + aSub->loadGeneratedShapes( + theAlgo, theOldShape, theShapeTypeToExplore, theName, theSaveOldIfNotInTree); + } + } else { // do for this directly + myBuilder->loadGeneratedShapes( + theAlgo, theOldShape, theShapeTypeToExplore, theName, theSaveOldIfNotInTree); + } +} + +void Model_ResultBody::loadModifiedShapes(const std::shared_ptr& theAlgo, + const GeomShapePtr& theOldShape, + const GeomAPI_Shape::ShapeType theShapeTypeToExplore, + const std::string& theName) +{ + if (mySubs.size()) { // consists of subs + // optimization of getting of new shapes for specific sub-result + if (!theAlgo->isNewShapesCollected(theOldShape, theShapeTypeToExplore)) + theAlgo->collectNewShapes(theOldShape, theShapeTypeToExplore); std::vector::const_iterator aSubIter = mySubs.cbegin(); for(; aSubIter != mySubs.cend(); aSubIter++) { - // check that sub-shape was also created as modification of ShapeIn - /* to find when it is needed later to enable: to store modification of sub-bodies not only as primitives - GeomShapePtr aSubGeomShape = (*aSubIter)->shape(); - if (!theIsStoreAsGenerated && aSubGeomShape.get() && !aSubGeomShape->isNull()) { - TopoDS_Shape aSubShape = aSubGeomShape->impl(); - TopoDS_Shape aWholeIn = theShapeIn->impl(); - for(TopExp_Explorer anExp(aWholeIn, aSubShape.ShapeType()); anExp.More(); anExp.Next()) { - ListOfShape aHistory; - std::shared_ptr aSubIn(new GeomAPI_Shape()); - aSubIn->setImpl((new TopoDS_Shape(anExp.Current()))); - theMS->modified(aSubIn, aHistory); - std::list >::const_iterator anIt = aHistory.begin(); - for (; anIt != aHistory.end(); anIt++) { - if ((*anIt)->isSame(aSubGeomShape)) { - (*aSubIter)->storeModified(aSubIn, aSubGeomShape, -2); // -2 is to avoid clearing - } - } - } - }*/ - (*aSubIter)->loadAndOrientModifiedShapes( - theMS, theShapeIn, theKindOfShape, theTag, theName, theSubShapes, theIsStoreSeparate, - theIsStoreAsGenerated, theSplitInSubs); + (*aSubIter)->loadModifiedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theName); } } else { // do for this directly - myBuilder->loadAndOrientModifiedShapes( - theMS, theShapeIn, theKindOfShape, theTag, theName, theSubShapes, theIsStoreSeparate, - theIsStoreAsGenerated); + myBuilder->loadModifiedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theName); } } @@ -98,9 +125,9 @@ ResultBodyPtr Model_ResultBody::subResult(const int theIndex, bool forTree) cons return mySubs.at(theIndex); } -bool Model_ResultBody::isSub(ObjectPtr theObject, int& theIndex) const +bool Model_ResultBody::isSub(ObjectPtr theResult, int& theIndex) const { - std::map::const_iterator aFound = mySubsMap.find(theObject); + std::map::const_iterator aFound = mySubsMap.find(theResult); if (aFound != mySubsMap.end()) { theIndex = aFound->second; return true; @@ -120,8 +147,7 @@ bool Model_ResultBody::setDisabled(std::shared_ptr theThis, con { bool aChanged = ModelAPI_ResultBody::setDisabled(theThis, theFlag); if (aChanged) { // state is changed, so modifications are needed - myBuilder->evolutionToSelection(theFlag); - updateSubs(shape()); // to set disabled/enabled + updateSubs(shape(), false); // to set disabled/enabled } return aChanged; } @@ -131,10 +157,10 @@ bool Model_ResultBody::isConcealed() return myLastConcealed; } -void Model_ResultBody::setIsConcealed(const bool theValue) +void Model_ResultBody::setIsConcealed(const bool theValue, const bool theForced) { if (ModelAPI_ResultBody::isConcealed() != theValue) { - ModelAPI_ResultBody::setIsConcealed(theValue); + ModelAPI_ResultBody::setIsConcealed(theValue, theForced); updateConcealment(); } } @@ -192,12 +218,21 @@ void Model_ResultBody::updateConcealment() } } -void Model_ResultBody::updateSubs(const std::shared_ptr& theThisShape) +void Model_ResultBody::updateSubs(const std::shared_ptr& theThisShape, + const bool theShapeChanged) { static Events_Loop* aLoop = Events_Loop::loop(); static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); static Events_ID EVENT_UPD = aLoop->eventByName(EVENT_OBJECT_UPDATED); static const ModelAPI_EventCreator* aECreator = ModelAPI_EventCreator::get(); + // erase flag that topology is connected: the shape is new + if (theShapeChanged && data().get()) { + TDF_Label aDataLab = std::dynamic_pointer_cast(data())->label(); + if (!aDataLab.IsNull()) { + TDataStd_UAttribute::Set(aDataLab, kUpdateConnectedTopology); + isConnectedTopology(); // to store this flag in transaction, #2630 + } + } // iterate all sub-solids of compsolid to make sub-results synchronized with them TopoDS_Shape aThisShape; if (theThisShape.get()) aThisShape = theThisShape->impl(); @@ -215,11 +250,23 @@ void Model_ResultBody::updateSubs(const std::shared_ptr& theThisS aSub = anObjects->createBody(this->data(), aSubIndex); mySubs.push_back(aSub); mySubsMap[aSub] = int(mySubs.size() - 1); + if (isConcealed()) { // for issue #2579 note7 + aSub->ModelAPI_ResultBody::setIsConcealed(true); + std::dynamic_pointer_cast(aSub)->updateConcealment(); + } } else { // just update shape of this result aSub = mySubs[aSubIndex]; } - if (!aShape->isEqual(aSub->shape())) { - aSub->store(aShape, false); + GeomShapePtr anOldSubShape = aSub->shape(); + if (!aShape->isEqual(anOldSubShape)) { + if (myAlgo.get()) { + std::list anOldForSub; + computeOldForSub(aShape, myOlds, anOldForSub); + myIsGenerated ? aSub->storeGenerated(anOldForSub, aShape, myAlgo) : + aSub->storeModified(anOldForSub, aShape, myAlgo); + } else { + aSub->store(aShape, false); + } aECreator->sendUpdated(aSub, EVENT_DISP); aECreator->sendUpdated(aSub, EVENT_UPD); } @@ -240,6 +287,7 @@ void Model_ResultBody::updateSubs(const std::shared_ptr& theThisS // redisplay this because result with and without subs are displayed differently aECreator->sendUpdated(data()->owner(), EVENT_DISP); } + cleanCash(); } else if (!mySubs.empty()) { // erase all subs while(!mySubs.empty()) { ResultBodyPtr anErased = *(mySubs.rbegin()); @@ -256,16 +304,133 @@ void Model_ResultBody::updateSubs(const std::shared_ptr& theThisS } } -bool Model_ResultBody::isLatestEqual(const std::shared_ptr& theShape) +void Model_ResultBody::updateSubs( + const GeomShapePtr& theThisShape, const std::list& theOlds, + const std::shared_ptr theMakeShape, const bool isGenerated) { - if (myBuilder->isLatestEqual(theShape)) - return true; - // also check that it is asked for sub-elements - std::vector::const_iterator aSubIter = mySubs.cbegin(); - for(; aSubIter != mySubs.cend(); aSubIter++) { - if (aSubIter->get() && (*aSubIter)->isLatestEqual(theShape)) { - return true; + myAlgo = theMakeShape; + myOlds = theOlds; + myIsGenerated = isGenerated; + // to avoid changing of "isDisabled" flag in the "updateSubs" cycle + isDisabled(); + + updateSubs(theThisShape, true); + myAlgo.reset(); + myOlds.clear(); + myHistoryCash.Clear(); +} + + +bool Model_ResultBody::isConnectedTopology() +{ + TDF_Label aDataLab = std::dynamic_pointer_cast(data())->label(); + if (!aDataLab.IsNull()) { + if (aDataLab.IsAttribute(kUpdateConnectedTopology)) { // recompute state + aDataLab.ForgetAttribute(kUpdateConnectedTopology); + GeomShapePtr aShape = shape(); + if (aShape.get() && aShape->isConnectedTopology()) { + TDataStd_UAttribute::Set(aDataLab, kIsConnectedTopology); + } else { + aDataLab.ForgetAttribute(kIsConnectedTopology); + } + } + return aDataLab.IsAttribute(kIsConnectedTopology); + } + return false; // invalid case +} + +void Model_ResultBody::cleanCash() +{ + myBuilder->cleanCash(); + for (std::vector::const_iterator aSubIter = mySubs.cbegin(); + aSubIter != mySubs.cend(); ++aSubIter) + { + const ResultBodyPtr& aSub = *aSubIter; + aSub->cleanCash(); + } +} + +// adds to the theSubSubs map all sub-shapes of theSub if it is compound of compsolid +static void collectSubs( + const GeomShapePtr theSub, TopTools_MapOfShape& theSubSubs, const bool theOneLevelMore) +{ + if (theSub->isNull()) + return; + if (theSubSubs.Add(theSub->impl())) { + bool aIsComp = theSub->isCompound() || theSub->isCompSolid(); + if (aIsComp) { + for(GeomAPI_ShapeIterator anIter(theSub); anIter.more(); anIter.next()) + collectSubs(anIter.current(), theSubSubs, theOneLevelMore); + } else if (theOneLevelMore) { + GeomAPI_Shape::ShapeType aSubType = GeomAPI_Shape::ShapeType(int(theSub->shapeType()) + 1); + if (aSubType == GeomAPI_Shape::SHAPE) + return; + if (aSubType == GeomAPI_Shape::SHELL) + aSubType = GeomAPI_Shape::FACE; + if (aSubType == GeomAPI_Shape::WIRE) + aSubType = GeomAPI_Shape::EDGE; + + for(GeomAPI_ShapeExplorer anExp(theSub, aSubType); anExp.more(); anExp.next()) { + collectSubs(anExp.current(), theSubSubs, false); + } + } + } +} + +void Model_ResultBody::computeOldForSub(const GeomShapePtr& theSub, + const std::list& theAllOlds, std::list& theOldForSub) +{ + // the old can be also used for sub-shape of theSub; collect all subs of compound or compsolid + TopTools_MapOfShape aSubSubs; + collectSubs(theSub, aSubSubs, false); + + std::list::const_iterator aRootOlds = theAllOlds.cbegin(); + for (; aRootOlds != theAllOlds.cend(); aRootOlds++) { + // use sub-shapes of olds too if they are compounds or compsolids + TopTools_MapOfShape anOldSubs; + // iterate one level more (for intersection of solids this is face) + collectSubs(*aRootOlds, anOldSubs, true); + for (TopTools_MapOfShape::Iterator anOldIter(anOldSubs); anOldIter.More(); anOldIter.Next()) { + TopoDS_Shape anOldShape = anOldIter.Value(); + if (anOldShape.ShapeType() == TopAbs_COMPOUND || anOldShape.ShapeType() == TopAbs_SHELL || + anOldShape.ShapeType() == TopAbs_WIRE) + continue; // container old-shapes are not supported by the history, may cause crash + GeomShapePtr anOldSub(new GeomAPI_Shape); + anOldSub->setImpl(new TopoDS_Shape(anOldShape)); + + ListOfShape aNews; + if (myHistoryCash.IsBound(anOldShape)) { + const TopTools_ListOfShape& aList = myHistoryCash.Find(anOldShape); + for(TopTools_ListIteratorOfListOfShape anIter(aList); anIter.More(); anIter.Next()) { + GeomShapePtr aShape(new GeomAPI_Shape); + aShape->setImpl(new TopoDS_Shape(anIter.Value())); + aNews.push_back(aShape); + } + } else { + myIsGenerated ? myAlgo->generated(anOldSub, aNews) : myAlgo->modified(anOldSub, aNews); + // MakeShape may return alone old shape if there is no history information for this input + if (aNews.size() == 1 && aNews.front()->isEqual(anOldSub)) + aNews.clear(); + // store result in the history + TopTools_ListOfShape aList; + for (ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) { + aList.Append((*aNewIter)->impl()); + } + myHistoryCash.Bind(anOldShape, aList); + } + + for (ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) { + if (aSubSubs.Contains((*aNewIter)->impl())) { + // check list already contains this sub + std::list::iterator aResIter = theOldForSub.begin(); + for(; aResIter != theOldForSub.end(); aResIter++) + if ((*aResIter)->isSame(anOldSub)) + break; + if (aResIter == theOldForSub.end()) + theOldForSub.push_back(anOldSub); // found old used for new theSubShape creation + break; + } + } } } - return false; }