X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_ResultBody.cpp;h=3d28be7c668bdff13d28f9f393dc037bfbaf798b;hb=c57b0044525edb117d2b10cca0a931eecb5681f5;hp=1fad264d8122ff265b11deea8178ad15d0ce9bce;hpb=ed165fd07e71c11885fdc5f475a8522a5914e00d;p=modules%2Fshaper.git diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 1fad264d8..3d28be7c6 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -1,117 +1,371 @@ -// File: Model_ResultBody.cpp -// Created: 08 Jul 2014 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2017 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 +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// 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 +// +// 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 + +// 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() +{ + myBuilder = new Model_BodyBuilder(this); + myLastConcealed = false; + updateSubs(shape()); // in case of open, etc. +} -Model_ResultBody::Model_ResultBody() +Model_ResultBody::~Model_ResultBody() { - setIsConcealed(false); + updateSubs(std::shared_ptr()); // erase sub-results + delete myBuilder; } -void Model_ResultBody::store(const boost::shared_ptr& theShape) +bool Model_ResultBody::generated(const GeomShapePtr& theNewShape, + const std::string& theName, const bool theCheckIsInResult) { - boost::shared_ptr aData = boost::dynamic_pointer_cast(data()); - if (aData) { - TDF_Label& aShapeLab = aData->shapeLab(); - // remove the previous history - clean(); - aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID()); - for(TDF_ChildIterator anIter(aShapeLab); anIter.More(); anIter.Next()) { - anIter.Value().ForgetAllAttributes(); + 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; } - // store the new shape as primitive - TNaming_Builder aBuilder(aShapeLab); - if (!theShape) - return; // bad shape - TopoDS_Shape aShape = theShape->impl(); - if (aShape.IsNull()) - return; // null shape inside - - aBuilder.Generated(aShape); + } else { // do for this directly + if (myBuilder->generated(theNewShape, theName, theCheckIsInResult)) + aResult = true; } + return aResult; } -boost::shared_ptr Model_ResultBody::shape() +void Model_ResultBody::loadGeneratedShapes(const std::shared_ptr& theAlgo, + const GeomShapePtr& theOldShape, + const GeomAPI_Shape::ShapeType theShapeTypeToExplore, + const std::string& theName) { - boost::shared_ptr aData = boost::dynamic_pointer_cast(data()); - if (aData) { - TDF_Label& aShapeLab = aData->shapeLab(); - Handle(TNaming_NamedShape) aName; - if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) { - TopoDS_Shape aShape = aName->Get(); - if (!aShape.IsNull()) { - boost::shared_ptr aRes(new GeomAPI_Shape); - aRes->setImpl(new TopoDS_Shape(aShape)); - return aRes; - } + 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); } + } else { // do for this directly + myBuilder->loadGeneratedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theName); } - return boost::shared_ptr(); } -boost::shared_ptr Model_ResultBody::owner() +void Model_ResultBody::loadModifiedShapes(const std::shared_ptr& theAlgo, + const GeomShapePtr& theOldShape, + const GeomAPI_Shape::ShapeType theShapeTypeToExplore, + const std::string& theName) { - return myOwner; + 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++) { + (*aSubIter)->loadModifiedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theName); + } + } else { // do for this directly + myBuilder->loadModifiedShapes(theAlgo, theOldShape, theShapeTypeToExplore, theName); + } } -void Model_ResultBody::clean() +int Model_ResultBody::numberOfSubs(bool forTree) const { - std::vector::iterator aBuilder = myBuilders.begin(); - for(; aBuilder != myBuilders.end(); aBuilder++) - delete *aBuilder; + return int(mySubs.size()); } -Model_ResultBody::~Model_ResultBody() +ResultBodyPtr Model_ResultBody::subResult(const int theIndex, bool forTree) const { - clean(); + if (theIndex >= int(mySubs.size())) + return ResultBodyPtr(); + return mySubs.at(theIndex); +} + +bool Model_ResultBody::isSub(ObjectPtr theObject, int& theIndex) const +{ + std::map::const_iterator aFound = mySubsMap.find(theObject); + if (aFound != mySubsMap.end()) { + theIndex = aFound->second; + return true; + } + return false; +} + +void Model_ResultBody::colorConfigInfo(std::string& theSection, std::string& theName, + std::string& theDefault) +{ + theSection = "Visualization"; + theName = "result_body_color"; + theDefault = DEFAULT_COLOR(); +} + +bool Model_ResultBody::setDisabled(std::shared_ptr theThis, const bool theFlag) +{ + bool aChanged = ModelAPI_ResultBody::setDisabled(theThis, theFlag); + if (aChanged) { // state is changed, so modifications are needed + updateSubs(shape(), false); // to set disabled/enabled + } + return aChanged; +} + +bool Model_ResultBody::isConcealed() +{ + return myLastConcealed; +} + +void Model_ResultBody::setIsConcealed(const bool theValue) +{ + if (ModelAPI_ResultBody::isConcealed() != theValue) { + ModelAPI_ResultBody::setIsConcealed(theValue); + updateConcealment(); + } } -TNaming_Builder* Model_ResultBody::builder(const int theTag) +// recursively check all subs for concealment flag, returns true if everybody have "flag" state, +// in theAll returns results with "flag" state +static bool checkAllSubs(ResultBodyPtr theParent, bool theFlag, std::list& theAll) { - if (myBuilders.size() < (unsigned int)theTag) { - myBuilders.insert(myBuilders.end(), theTag - myBuilders.size() + 1, NULL); + if (theParent->isConcealed() != theFlag) + theAll.push_back(theParent); + bool aResult = theParent->ModelAPI_ResultBody::isConcealed() == theFlag; + for(int a = 0; a < theParent->numberOfSubs(); a++) { + bool aSubRes = checkAllSubs(theParent->subResult(a), theFlag, theAll); + if (theFlag) + aResult = aResult || aSubRes; // concealed: one makes concealed everyone + else + aResult = aResult && aSubRes; // not concealed: all must be not concealed } - if (!myBuilders[theTag]) { - boost::shared_ptr aData = boost::dynamic_pointer_cast(data()); - myBuilders[theTag] = new TNaming_Builder(aData->shapeLab().FindChild(theTag)); + return aResult; +} + +void Model_ResultBody::updateConcealment() +{ + if (myLastConcealed != ModelAPI_ResultBody::isConcealed()) { + // check the whole tree of results: if one is concealed, everybody are concealed + ResultBodyPtr anOwner = std::dynamic_pointer_cast(data()->owner()); + if (!anOwner.get()) + return; // "this" is invalid + ResultBodyPtr aParent = ModelAPI_Tools::bodyOwner(anOwner); + while(aParent.get()) { + anOwner = aParent; + aParent = ModelAPI_Tools::bodyOwner(anOwner); + } + // iterate all results and collect all results whose state may be updated + std::list anUpdated; + bool aNewFlag = !myLastConcealed; + if (checkAllSubs(anOwner, aNewFlag, anUpdated)) { // state of everyone must be updated + std::list::iterator aRes = anUpdated.begin(); + for(; aRes != anUpdated.end(); aRes++) { + bool aLastConcealed = (*aRes)->isConcealed(); + if (aNewFlag != aLastConcealed) { + std::dynamic_pointer_cast(*aRes)->myLastConcealed = aNewFlag; + if (aNewFlag) { // become concealed, behaves like removed + ModelAPI_EventCreator::get()->sendDeleted(document(), groupName()); + } else { // become not-concealed, behaves like created + static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); + ModelAPI_EventCreator::get()->sendUpdated(*aRes, anEvent); + } + static Events_ID EVENT_DISP = // must be redisplayed in any case + Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); + ModelAPI_EventCreator::get()->sendUpdated(*aRes, EVENT_DISP); + } + } + } } - return myBuilders[theTag]; } -void Model_ResultBody::generated( - const boost::shared_ptr& theNewShape, const int theTag) +void Model_ResultBody::updateSubs(const std::shared_ptr& theThisShape, + const bool theShapeChanged) { - TopoDS_Shape aShape = theNewShape->impl(); - builder(theTag)->Generated(aShape); + 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(); + if (!aThisShape.IsNull() && (aThisShape.ShapeType() == TopAbs_COMPSOLID || + aThisShape.ShapeType() == TopAbs_COMPOUND)) { + bool aWasEmpty = mySubs.empty(); + Model_Objects* anObjects = std::dynamic_pointer_cast(document())->objects(); + unsigned int aSubIndex = 0; + TopoDS_Iterator aShapesIter(aThisShape); + for(; aShapesIter.More(); aShapesIter.Next(), aSubIndex++) { + std::shared_ptr aShape(new GeomAPI_Shape); + aShape->setImpl(new TopoDS_Shape(aShapesIter.Value())); + ResultBodyPtr aSub; + if (mySubs.size() <= aSubIndex) { // it is needed to create a new sub-result + 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]; + } + 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); + } + aSub->setDisabled(aSub, isDisabled()); + } + // erase left, unused results + while(mySubs.size() > aSubIndex) { + ResultBodyPtr anErased = *(mySubs.rbegin()); + if (anErased->ModelAPI_ResultBody::isConcealed()) { + anErased->ModelAPI_ResultBody::setIsConcealed(false); + std::dynamic_pointer_cast(anErased)->updateConcealment(); + } + anErased->setDisabled(anErased, true); + mySubsMap.erase(anErased); + mySubs.pop_back(); + } + if (aWasEmpty) { // erase all subs + // 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()); + if (anErased->ModelAPI_ResultBody::isConcealed()) { + anErased->ModelAPI_ResultBody::setIsConcealed(false); + std::dynamic_pointer_cast(anErased)->updateConcealment(); + } + anErased->setDisabled(anErased, true); // even if it is invalid (to erase subs on abort/undo) + mySubs.pop_back(); + } + mySubsMap.clear(); + // redisplay this because result with and without subs are displayed differently + aECreator->sendUpdated(data()->owner(), EVENT_DISP); + } } -void Model_ResultBody::generated(const boost::shared_ptr& theOldShape, - const boost::shared_ptr& theNewShape, const int theTag) +void Model_ResultBody::updateSubs( + const GeomShapePtr& theThisShape, const std::list& theOlds, + const std::shared_ptr theMakeShape, const bool isGenerated) { - TopoDS_Shape anOldShape = theOldShape->impl(); - TopoDS_Shape aNewShape = theNewShape->impl(); - builder(theTag)->Generated(anOldShape, aNewShape); + myAlgo = theMakeShape; + myOlds = theOlds; + myIsGenerated = isGenerated; + updateSubs(theThisShape, true); + myAlgo.reset(); + myOlds.clear(); } -void Model_ResultBody::modified(const boost::shared_ptr& theOldShape, - const boost::shared_ptr& theNewShape, const int theTag) +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() { - TopoDS_Shape anOldShape = theOldShape->impl(); - TopoDS_Shape aNewShape = theNewShape->impl(); - builder(theTag)->Modify(anOldShape, aNewShape); + myBuilder->cleanCash(); + for (std::vector::const_iterator aSubIter = mySubs.cbegin(); + aSubIter != mySubs.cend(); ++aSubIter) + { + const ResultBodyPtr& aSub = *aSubIter; + aSub->cleanCash(); + } } -void Model_ResultBody::deleted(const boost::shared_ptr& theOldShape, - const int theTag) +void Model_ResultBody::computeOldForSub(const GeomShapePtr& theSub, + const std::list& theAllOlds, std::list& theOldForSub) { - TopoDS_Shape aShape = theOldShape->impl(); - builder(theTag)->Delete(aShape); + std::list::const_iterator aRootOlds = theAllOlds.cbegin(); + for(; aRootOlds != theAllOlds.cend(); aRootOlds++) { + ListOfShape aNews; + myIsGenerated ? myAlgo->generated(*aRootOlds, aNews) : myAlgo->modified(*aRootOlds, aNews); + // MakeShape may return alone old shape if there is no history information for this input + if (aNews.size() == 1 && aNews.front()->isEqual(*aRootOlds)) + aNews.clear(); + if (aNews.empty()) { // try to iterate to sub-elements (for intersection of solids this is face) + std::list theAllSubOlds; + for(GeomAPI_ShapeIterator aSubOld(*aRootOlds); aSubOld.more(); aSubOld.next()) { + GeomShapePtr aSub = aSubOld.current(); + if (aSub.get() && !aSub->isNull()) + theAllSubOlds.push_back(aSub); + } + computeOldForSub(theSub, theAllSubOlds, theOldForSub); + } + for(ListOfShape::iterator aNewIter = aNews.begin(); aNewIter != aNews.end(); aNewIter++) { + if (theSub->isSame(*aNewIter)) { // found old that was used for new theSubShape creation + theOldForSub.push_back(*aRootOlds); + break; + } + } + } }