From a6be32b3e251122bcc4eac178040ef81c5c2dc35 Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 30 May 2016 10:32:51 +0300 Subject: [PATCH] Fix for the issue 1526: optimization of isConnectedTopology calls --- src/GeomAPI/GeomAPI_Shape.cpp | 16 +++++++++++----- src/Model/Model_ResultBody.cpp | 1 + src/Model/Model_ResultBody.h | 1 + src/ModelAPI/ModelAPI_ResultBody.cpp | 13 +++++++++++++ src/ModelAPI/ModelAPI_ResultBody.h | 13 +++++++++++++ src/PartSet/PartSet_IconFactory.cpp | 8 ++++++-- 6 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index 0ee2a087c..43627a1dd 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -131,15 +131,21 @@ bool GeomAPI_Shape::isConnectedTopology() const NCollection_List aNew; // very new connected to new connected NCollection_List::Iterator aNotIter(aNotConnected); while(aNotIter.More()) { + // optimization to avoid TopExp_Explorer double-cycle, collect all vertices in the list first + NCollection_List aNotVertices; + for(TopExp_Explorer anExp1(aNotIter.Value(), TopAbs_VERTEX); anExp1.More(); anExp1.Next()) { + aNotVertices.Append(anExp1.Current()); + } + bool aConnected = false; NCollection_List::Iterator aNewIter(aNewConnected); for(; !aConnected && aNewIter.More(); aNewIter.Next()) { // checking topological connecion of aNotIter and aNewIter (if shapes are connected, vertices are connected for sure) - TopExp_Explorer anExp1(aNotIter.Value(), TopAbs_VERTEX); - for(; !aConnected && anExp1.More(); anExp1.Next()) { - TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX); - for(; anExp2.More(); anExp2.Next()) { - if (anExp1.Current().IsSame(anExp2.Current())) { + TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX); + for(; !aConnected && anExp2.More(); anExp2.Next()) { + NCollection_List::Iterator aNotIter(aNotVertices); + for(; aNotIter.More(); aNotIter.Next()) { + if (aNotIter.Value().IsSame(anExp2.Current())) { aConnected = true; break; } diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 5fb26d843..714d984e8 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -19,6 +19,7 @@ Model_ResultBody::Model_ResultBody() { myBuilder = new Model_BodyBuilder(this); myWasConcealed = false; + myConnect = ConnectionNotComputed; } void Model_ResultBody::initAttributes() diff --git a/src/Model/Model_ResultBody.h b/src/Model/Model_ResultBody.h index bbb23da35..be5ac8e1d 100644 --- a/src/Model/Model_ResultBody.h +++ b/src/Model/Model_ResultBody.h @@ -32,6 +32,7 @@ class Model_ResultBody : public ModelAPI_ResultBody /// Flag that stores the previous state of "concealed": if it is changed, /// The event is used to redisplay the body. bool myWasConcealed; + public: /// Request for initialization of data model of the result: adding all attributes virtual void initAttributes(); diff --git a/src/ModelAPI/ModelAPI_ResultBody.cpp b/src/ModelAPI/ModelAPI_ResultBody.cpp index 6792f18bc..bdf9947d2 100644 --- a/src/ModelAPI/ModelAPI_ResultBody.cpp +++ b/src/ModelAPI/ModelAPI_ResultBody.cpp @@ -12,6 +12,7 @@ ModelAPI_ResultBody::ModelAPI_ResultBody() : myBuilder(0) { + myConnect = ConnectionNotComputed; } ModelAPI_ResultBody::~ModelAPI_ResultBody() @@ -29,6 +30,7 @@ void ModelAPI_ResultBody::store(const std::shared_ptr& theShape, const bool theIsStoreSameShapes) { myBuilder->store(theShape, theIsStoreSameShapes); + myConnect = ConnectionNotComputed; static Events_Loop* aLoop = Events_Loop::loop(); static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); @@ -40,6 +42,7 @@ void ModelAPI_ResultBody::storeGenerated(const std::shared_ptr& t const std::shared_ptr& theToShape) { myBuilder->storeGenerated(theFromShape, theToShape); + myConnect = ConnectionNotComputed; static Events_Loop* aLoop = Events_Loop::loop(); static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); @@ -52,6 +55,7 @@ void ModelAPI_ResultBody::storeModified(const std::shared_ptr& th const int theDecomposeSolidsTag) { myBuilder->storeModified(theOldShape, theNewShape, theDecomposeSolidsTag); + myConnect = ConnectionNotComputed; static Events_Loop* aLoop = Events_Loop::loop(); static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); @@ -62,6 +66,7 @@ void ModelAPI_ResultBody::storeModified(const std::shared_ptr& th void ModelAPI_ResultBody::storeWithoutNaming(const std::shared_ptr& theShape) { myBuilder->storeWithoutNaming(theShape); + myConnect = ConnectionNotComputed; static Events_Loop* aLoop = Events_Loop::loop(); static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); @@ -142,3 +147,11 @@ void ModelAPI_ResultBody::loadDisconnectedVertexes(std::shared_ptrloadDisconnectedVertexes(theShape, theName, theTag); } + +bool ModelAPI_ResultBody::isConnectedTopology() +{ + if (myConnect == ConnectionNotComputed) { + myConnect = shape()->isConnectedTopology() ? IsConnected : IsNotConnected; + } + return myConnect == IsConnected; +} diff --git a/src/ModelAPI/ModelAPI_ResultBody.h b/src/ModelAPI/ModelAPI_ResultBody.h index ad5846e0f..119978c6f 100644 --- a/src/ModelAPI/ModelAPI_ResultBody.h +++ b/src/ModelAPI/ModelAPI_ResultBody.h @@ -44,6 +44,15 @@ public: return RESULT_BODY_COLOR; } + /// Iternal enumeration for storage the information of connected topology flag + enum ConnectedTopologyFlag { + ConnectionNotComputed, ///< not yet computed + IsConnected, ///< the topology is connected + IsNotConnected ///< the topology is connected + }; + /// Keeps (not persistently) the connected topology flag + ConnectedTopologyFlag myConnect; + /// \brief Stores the shape (called by the execution method). /// param[in] theShape shape to store. /// param[in] theIsStoreSameShapes if false stores reference to the same shape if it is already in document. @@ -118,6 +127,10 @@ public: // is equal to the given shape MODELAPI_EXPORT virtual bool isLatestEqual(const std::shared_ptr& theShape) = 0; + /// Returns true is the topology is connected. Cashes this information for the current shape, + /// so it is more effective to use this method than directly GeomAPI_Shape. + MODELAPI_EXPORT virtual bool isConnectedTopology(); + protected: /// Default constructor accessible only from Model_Objects MODELAPI_EXPORT ModelAPI_ResultBody(); diff --git a/src/PartSet/PartSet_IconFactory.cpp b/src/PartSet/PartSet_IconFactory.cpp index 2beae8cc1..1636a6ca2 100644 --- a/src/PartSet/PartSet_IconFactory.cpp +++ b/src/PartSet/PartSet_IconFactory.cpp @@ -79,8 +79,12 @@ QIcon PartSet_IconFactory::getIcon(ObjectPtr theObj) GeomShapePtr aShape = aResult->shape(); if(aShape.get()) { switch(aShape->shapeType()) { - case GeomAPI_Shape::COMPOUND: return aShape->isConnectedTopology() ? - QIcon(":pictures/compoundofsolids.png") : QIcon(":pictures/compound.png"); + case GeomAPI_Shape::COMPOUND: { + ResultBodyPtr aBody = std::dynamic_pointer_cast(aResult); + if (aBody.get() && aBody->isConnectedTopology()) + return QIcon(":pictures/compoundofsolids.png"); + return QIcon(":pictures/compound.png"); + } case GeomAPI_Shape::COMPSOLID: return QIcon(":pictures/compsolid.png"); case GeomAPI_Shape::SOLID: return QIcon(":pictures/solid.png"); case GeomAPI_Shape::SHELL: return QIcon(":pictures/shell.png"); -- 2.39.2