From 8bc4b47541ca9e7b347643c18b0e80f271d8db4b Mon Sep 17 00:00:00 2001 From: mpv Date: Mon, 19 Nov 2018 09:16:54 +0300 Subject: [PATCH] Refactoring of the Selector package: split selection algorithms to separated classes. --- src/Model/Model_AttributeSelection.cpp | 90 +- src/Model/Model_AttributeSelection.h | 4 + src/Selector/CMakeLists.txt | 16 + src/Selector/Selector_Algo.cpp | 420 ++++++ src/Selector/Selector_Algo.h | 165 +++ src/Selector/Selector_AlgoWithSubs.cpp | 59 + src/Selector/Selector_AlgoWithSubs.h | 51 + src/Selector/Selector_Container.cpp | 180 +++ src/Selector/Selector_Container.h | 64 + src/Selector/Selector_FilterByNeighbors.cpp | 354 +++++ src/Selector/Selector_FilterByNeighbors.h | 66 + src/Selector/Selector_Intersect.cpp | 316 ++++ src/Selector/Selector_Intersect.h | 64 + src/Selector/Selector_Modify.cpp | 329 +++++ src/Selector/Selector_Modify.h | 73 + src/Selector/Selector_NExplode.h | 2 +- src/Selector/Selector_Primitive.cpp | 81 ++ src/Selector/Selector_Primitive.h | 62 + src/Selector/Selector_Selector.cpp | 1430 +------------------ src/Selector/Selector_Selector.h | 57 +- src/Selector/Selector_WeakName.cpp | 139 ++ src/Selector/Selector_WeakName.h | 64 + src/SketchPlugin/SketchPlugin_Point.cpp | 2 +- 23 files changed, 2613 insertions(+), 1475 deletions(-) create mode 100644 src/Selector/Selector_Algo.cpp create mode 100644 src/Selector/Selector_Algo.h create mode 100644 src/Selector/Selector_AlgoWithSubs.cpp create mode 100644 src/Selector/Selector_AlgoWithSubs.h create mode 100644 src/Selector/Selector_Container.cpp create mode 100644 src/Selector/Selector_Container.h create mode 100644 src/Selector/Selector_FilterByNeighbors.cpp create mode 100644 src/Selector/Selector_FilterByNeighbors.h create mode 100644 src/Selector/Selector_Intersect.cpp create mode 100644 src/Selector/Selector_Intersect.h create mode 100644 src/Selector/Selector_Modify.cpp create mode 100644 src/Selector/Selector_Modify.h create mode 100644 src/Selector/Selector_Primitive.cpp create mode 100644 src/Selector/Selector_Primitive.h create mode 100644 src/Selector/Selector_WeakName.cpp create mode 100644 src/Selector/Selector_WeakName.h diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7ca2ca089..3d97c91c9 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -592,16 +592,10 @@ bool Model_AttributeSelection::update() if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) anOldShape = aNS->Get(); - Selector_Selector aSelector(aSelLab); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSelector.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } - if (aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector - TopoDS_Shape aContextShape = aContext->shape()->impl(); - aResult = aSelector.solve(aContextShape); - } - aResult = setInvalidIfFalse(aSelLab, aResult); + TopoDS_Shape aContextShape = aContext->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + aResult = aSelector.restore(aContextShape); + setInvalidIfFalse(aSelLab, aResult); TopoDS_Shape aNewShape; if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) @@ -625,19 +619,11 @@ bool Model_AttributeSelection::update() std::shared_ptr aConstructionContext = std::dynamic_pointer_cast(aContext); if (!aConstructionContext->isInfinite()) { - Selector_Selector aSelector(aSelLab); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSelector.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } - - aResult = aSelector.restore(); + TopoDS_Shape aContextShape = aContext->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); TopoDS_Shape anOldShape = aSelector.value(); - if (aResult) { - TopoDS_Shape aContextShape = aContext->shape()->impl(); - aResult = aSelector.solve(aContextShape); - } - aResult = setInvalidIfFalse(aSelLab, aResult); + aResult = aSelector.restore(aContextShape); + setInvalidIfFalse(aSelLab, aResult); if (aResult && !anOldShape.IsEqual(aSelector.value())) owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed } else { @@ -673,30 +659,20 @@ void Model_AttributeSelection::selectBody( TopoDS_Shape aNewSub = theSubShape->impl(); bool aSelectorOk = true; - Selector_Selector aSel(aSelLab); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSel.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } + Selector_Selector aSelector(aSelLab, baseDocumentLab()); try { - aSelectorOk = aSel.select(aContext, aNewSub, myIsGeometricalSelection); + aSelectorOk = aSelector.select(aContext, aNewSub, myIsGeometricalSelection); if (aSelectorOk) { - aSel.store(); - aSelectorOk = aSel.solve(aContext); + aSelectorOk = aSelector.store(aContext); } } catch(...) { aSelectorOk = false; } - Handle(TNaming_NamedShape) aSelectorShape; - if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape)) - { - TopoDS_Shape aShape = aSelectorShape->Get(); - if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType()) - aSelectorOk = false; - } - if (!aSelectorOk) { - setInvalidIfFalse(aSelLab, false); + if (aSelectorOk) { + TopoDS_Shape aShape = aSelector.value(); + aSelectorOk = !aShape.IsNull() && aShape.ShapeType() == aNewSub.ShapeType(); } + setInvalidIfFalse(aSelLab, aSelectorOk); } } @@ -803,13 +779,9 @@ std::string Model_AttributeSelection::namingName(const std::string& theDefaultNa } } - Selector_Selector aSelector(aSelLab); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSelector.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } + Selector_Selector aSelector(aSelLab, baseDocumentLab()); std::string aResult; - if (aSelector.restore()) + if (aSelector.restore(aCont->shape()->impl())) aResult = aSelector.name(this); if (aCenterType != NOT_CENTER) { aResult += centersMap()[aCenterType]; @@ -915,11 +887,7 @@ void Model_AttributeSelection::selectSubShape( } } - Selector_Selector aSelector(selectionLabel()); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSelector.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } + Selector_Selector aSelector(selectionLabel(), baseDocumentLab()); myRestoreDocument = aDoc; TDF_Label aContextLabel = aSelector.restoreByName( aSubShapeName, aShapeType, this, myIsGeometricalSelection); @@ -940,8 +908,7 @@ void Model_AttributeSelection::selectSubShape( bool aToUnblock = false; aToUnblock = !owner()->data()->blockSendAttributeUpdated(true); myRef.setValue(aContext); - aSelector.store(); - aSelector.solve(aContextShape); + aSelector.store(aContextShape); owner()->data()->sendAttributeUpdated(this); if (aToUnblock) owner()->data()->blockSendAttributeUpdated(false); @@ -1806,13 +1773,18 @@ void Model_AttributeSelection::combineGeometrical() if (aFeature.get()) return; - Selector_Selector aSelector(aSelLab); - if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) { - aSelector.setBaseDocument(std::dynamic_pointer_cast - (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel()); - } - if (aSelector.restore()) { - TopoDS_Shape aContextShape = context()->shape()->impl(); + Selector_Selector aSelector(aSelLab, baseDocumentLab()); + TopoDS_Shape aContextShape = context()->shape()->impl(); + if (aSelector.restore(aContextShape)) { aSelector.combineGeometrical(aContextShape); } } + +TDF_Label Model_AttributeSelection::baseDocumentLab() +{ + if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) + return std::dynamic_pointer_cast + (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel(); + static TDF_Label anEmpty; + return anEmpty; +} diff --git a/src/Model/Model_AttributeSelection.h b/src/Model/Model_AttributeSelection.h index a624e5cf0..9512a3a73 100644 --- a/src/Model/Model_AttributeSelection.h +++ b/src/Model/Model_AttributeSelection.h @@ -208,6 +208,10 @@ protected: return myIsGeometricalSelection; }; + /// Returns the module document label if this selection attribute is not in this document. + /// Returns null label otherwise. + TDF_Label baseDocumentLab(); + friend class Model_Data; friend class Model_AttributeSelectionList; }; diff --git a/src/Selector/CMakeLists.txt b/src/Selector/CMakeLists.txt index 38af7997f..cfc38feca 100644 --- a/src/Selector/CMakeLists.txt +++ b/src/Selector/CMakeLists.txt @@ -23,12 +23,28 @@ INCLUDE(Common) SET(PROJECT_HEADERS Selector.h Selector_Selector.h + Selector_Algo.h + Selector_Primitive.h + Selector_AlgoWithSubs.h + Selector_Intersect.h + Selector_Container.h + Selector_Modify.h + Selector_FilterByNeighbors.h + Selector_WeakName.h Selector_NameGenerator.h Selector_NExplode.h ) SET(PROJECT_SOURCES Selector_Selector.cpp + Selector_Algo.cpp + Selector_Primitive.cpp + Selector_AlgoWithSubs.cpp + Selector_Intersect.cpp + Selector_Container.cpp + Selector_Modify.cpp + Selector_FilterByNeighbors.cpp + Selector_WeakName.cpp Selector_NameGenerator.cpp Selector_NExplode.cpp ) diff --git a/src/Selector/Selector_Algo.cpp b/src/Selector/Selector_Algo.cpp new file mode 100644 index 000000000..c64e012d5 --- /dev/null +++ b/src/Selector/Selector_Algo.cpp @@ -0,0 +1,420 @@ +// 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 +#include +#include + +/// type of the selection, integer keeps the Selector_Type value +static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6"); +// geometrical naming indicator +static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657"); + + +// 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"); + +Selector_Algo::Selector_Algo() +{ + myGeometricalNaming = false; // default values + myAlwaysGeometricalNaming = false; +} + +#define SET_ALGO_FLAGS(algo) \ + algo->myLab = theAccess; \ + algo->myBaseDocumentLab = theBaseDocument; \ + algo->myGeometricalNaming = theGeometricalNaming; \ + algo->myUseNeighbors = theUseNeighbors; \ + algo->myUseIntersections = theUseIntersections; \ + algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming; + +Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue, + const TDF_Label theAccess, const TDF_Label theBaseDocument, + const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections, + const bool theAlwaysGeometricalNaming) +{ + Selector_Algo* aResult = NULL; + if (theValue.IsNull() || theContext.IsNull()) + return aResult; + + // check the value shape can be named as it is, or it is needed to construct it from the + // higher level shapes (like a box vertex by faces that form this vertex) + bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue); + if (aIsFound) { // additional check for selection and delete evolution only: also could not use + aIsFound = false; + for(TNaming_SameShapeIterator aShapes(theValue, theAccess); aShapes.More(); aShapes.Next()) + { + Handle(TNaming_NamedShape) aNS; + if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED || + aNS->Evolution() == TNaming_PRIMITIVE) { + aIsFound = true; + break; + } + } + } + } + // searching in the base document + if (!aIsFound && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue)) + { + TNaming_SameShapeIterator aShapes(theValue, theBaseDocument); + for(; aShapes.More(); aShapes.Next()) + { + Handle(TNaming_NamedShape) aNS; + if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED || + aNS->Evolution() == TNaming_PRIMITIVE) { + aIsFound = true; + break; + } + } + } + } + if (!aIsFound) { + TopAbs_ShapeEnum aSelectionType = theValue.ShapeType(); + if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID || + aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE) + { + Selector_Container* aContainer = new Selector_Container; + SET_ALGO_FLAGS(aContainer); + if (aContainer->select(theContext, theValue)) + return aContainer; + delete aContainer; + return false; + } + Selector_Intersect* anIntersect = new Selector_Intersect; + SET_ALGO_FLAGS(anIntersect); + bool aGoodIntersector = anIntersect->select(theContext, theValue); + // weak intersector is bad for not use neighbors and has lower priority than neighbors + if (aGoodIntersector && anIntersect->myWeakIndex == -1) { + return anIntersect; + } + if (!theUseNeighbors) { + delete anIntersect; + return false; + } + // searching by neighbors + Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors; + SET_ALGO_FLAGS(aNBs); + if (aNBs->select(theContext, theValue)) { + delete anIntersect; + return aNBs; + } + delete aNBs; + if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index + return anIntersect; + } + delete anIntersect; + + // pure weak naming: there is no sense to use pure weak naming for neighbors selection + if (theUseNeighbors) { + Selector_WeakName* aWeak = new Selector_WeakName; + SET_ALGO_FLAGS(aWeak); + if (aWeak->select(theContext, theValue)) { + return aWeak; + } + delete aWeak; + } + return NULL; // not found value in the tree, not found context shape in the tree also + } + // searching for the base shapes of the value + Handle(TNaming_NamedShape) aPrimitiveNS; + NCollection_List aModifList; + for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) { + TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument; + if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue)) + continue; + for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next()) + { + Handle(TNaming_NamedShape) aNS; + if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + TNaming_Evolution anEvolution = aNS->Evolution(); + if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE + aPrimitiveNS = aNS; + break; + } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { + // check this is a new shape + TNaming_Iterator aNSIter(aNS); + for(; aNSIter.More(); aNSIter.Next()) + if (aNSIter.NewShape().IsSame(theValue)) + break; + if (aNSIter.More()) // new was found + aModifList.Append(aNS); + } + } + } + } + + if (!aPrimitiveNS.IsNull()) { + Selector_Primitive* aPrimitive = new Selector_Primitive; + SET_ALGO_FLAGS(aPrimitive); + aPrimitive->select(aPrimitiveNS->Label()); + return aPrimitive; + } else { + Selector_Modify* aModify = new Selector_Modify; + SET_ALGO_FLAGS(aModify); + bool aGoodModify = aModify->select(aModifList, theContext, theValue); + // weak intersector is bad for not use neighbors and has lower priority than neighbors + if (aGoodModify && aModify->myWeakIndex == -1) { + return aModify; + } + if (!theUseNeighbors) { + delete aModify; + return false; + } + // searching by neighbors + Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors; + SET_ALGO_FLAGS(aNBs); + if (aNBs->select(theContext, theValue)) { + delete aModify; + return aNBs; + } + delete aNBs; + + if (aGoodModify) { // if neighbors are bad, use modify algo with weak index + return aModify; + } + delete aModify; + } + + return NULL; // invalid case +} + +Selector_Algo* Selector_Algo::relesectWithAllGeometry( + Selector_Algo* theOldAlgo, const TopoDS_Shape theContext) +{ + return select(theContext, theOldAlgo->value(), + theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true); +} + +void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast) +{ + Handle(TDataStd_ReferenceArray) anArray = + TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent()); + Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document + const TDF_Label aThisDocRoot = myLab.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(myLab, 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; + } +} + +bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast) +{ + const TDF_Label aThisDocRoot = myLab.Root(); + Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document + TDataStd_ListOfExtendedString::Iterator anIter; + Handle(TDataStd_ReferenceArray) anArray; + if (myLab.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 (myBaseDocumentLab.IsNull()) + return false; + if (anEntries.IsNull()) { + if (!myLab.FindAttribute(kBASE_LIST, anEntries)) + return false; + anIter.Initialize(anEntries->List()); + } + if (!anIter.More()) + return false; + TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab); + anIter.Next(); + } + if (anIndex == anUpper) { + theLast = aLab; + } else { + theRef.Append(aLab); + } + } + return true; + } + return false; +} + +void Selector_Algo::store(const TopoDS_Shape theShape) +{ + TNaming_Builder aBuilder(myLab); + aBuilder.Select(theShape, theShape); +} + +bool Selector_Algo::sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) { + if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType()) + { + if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces + TopLoc_Location aLoc1, aLoc2; + TopoDS_Face aFace1 = TopoDS::Face(theShape1); + Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1); + TopoDS_Face aFace2 = TopoDS::Face(theShape2); + Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2); + return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2); + } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves + TopLoc_Location aLoc1, aLoc2; + Standard_Real aFirst, aLast; + TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1); + Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast); + TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2); + Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast); + return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2); + } + } + return false; +} + +TopoDS_Shape Selector_Algo::value() +{ + Handle(TNaming_NamedShape) aNS; + if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + return aNS->Get(); + return TopoDS_Shape(); // empty, error shape +} + +Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab) +{ + Handle(TDataStd_Integer) aTypeAttr; + if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr)) + return NULL; + Selector_Type aType = Selector_Type(aTypeAttr->Get()); + Selector_Algo* aResult = NULL; + switch (aType) { + case SELTYPE_CONTAINER: { + aResult = new Selector_Container; + break; + } + case SELTYPE_INTERSECT: { + aResult = new Selector_Intersect; + break; + } + case SELTYPE_MODIFICATION: { + aResult = new Selector_Modify; + break; + } + case SELTYPE_PRIMITIVE: { + aResult = new Selector_Primitive; + break; + } + case SELTYPE_FILTER_BY_NEIGHBOR: { + aResult = new Selector_FilterByNeighbors; + break; + } + case SELTYPE_WEAK_NAMING: { + aResult = new Selector_WeakName; + break; + } + default: { // unknown case + } + } + if (aResult) { + bool aGeomNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING); + aResult->myLab = theLab; + aResult->myBaseDocumentLab = myBaseDocumentLab; + aResult->myGeometricalNaming = aGeomNaming; + aResult->myUseNeighbors = myUseNeighbors; + aResult->myUseIntersections = myUseIntersections; + if (!aResult->restore()) { + delete aResult; + aResult = NULL; + } + } + return aResult; +} + +Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab, + std::string theName, const TopAbs_ShapeEnum theShapeType, + Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab) +{ + Selector_Algo* aResult = NULL; + if (theName[0] == '[') { // intersection or container + switch(theShapeType) { + case TopAbs_COMPOUND: + case TopAbs_COMPSOLID: + case TopAbs_SHELL: + case TopAbs_WIRE: + aResult = new Selector_Container; + break; + case TopAbs_VERTEX: + case TopAbs_EDGE: + case TopAbs_FACE: + aResult = new Selector_Intersect; + break; + default:; + } + } else if (theName[0] == '(') { // filter by neighbors + aResult = new Selector_FilterByNeighbors; + } if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier + } else if (theName.find('&') != std::string::npos) { // modification + aResult = new Selector_Modify; + } else { // primitive + aResult = new Selector_Primitive; + } + if (aResult) { + aResult->myLab = theLab; + aResult->myBaseDocumentLab = theBaseDocLab; + theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator); + if (theContextLab.IsNull()) { + delete aResult; + aResult = NULL; + } + } + return aResult; +} + +void Selector_Algo::storeType(const Selector_Type theType) +{ + TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType)); +} diff --git a/src/Selector/Selector_Algo.h b/src/Selector/Selector_Algo.h new file mode 100644 index 000000000..b58e99df0 --- /dev/null +++ b/src/Selector/Selector_Algo.h @@ -0,0 +1,165 @@ +// 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 +// + +#ifndef Selector_Algo_H_ +#define Selector_Algo_H_ + +#include "Selector.h" + +#include +#include +#include +#include + +class Selector_NameGenerator; + +/**\class Selector_Selector + * \ingroup DataModel + * \brief Base class for all kinds of selection algorithms. + */ +class Selector_Algo +{ + TopAbs_ShapeEnum myShapeType; ///< type of this shape + + TDF_Label myLab; ///< label where this also may be located + TDF_Label myBaseDocumentLab; ///< an access-label of the document that may contain initial shapes + bool myGeometricalNaming; ///< flag that indicates that geometrical naming selection is enabled + bool myAlwaysGeometricalNaming; ///< to enable geometrical naming from beginning, at select + bool myUseNeighbors; ///< to use neighbors algorithms + bool myUseIntersections; ///< to use intersections algorithms + +public: + /// Type of a selector algorithm: on this type depends what is stored in this label and how to + /// restore it on update. + enum Selector_Type { + SELTYPE_CONTAINER, ///< just a container of sub-elements, keeps the shape type of container + SELTYPE_INTERSECT, ///< sub-shape is intersection of higher level objects + SELTYPE_PRIMITIVE, ///< sub-shape found as a primitive on some label + SELTYPE_MODIFICATION, ///< modification of base shapes to the final label + SELTYPE_FILTER_BY_NEIGHBOR, ///< identification by neighbor shapes in context + SELTYPE_WEAK_NAMING, ///< pure weak naming by weak index in context + }; + + /// Initializes the algorithm + SELECTOR_EXPORT Selector_Algo(); + + /// Initializes the selector structure on the label. + /// Stores the name data to restore after modification. + /// \param theContext whole shape that contains the selected sub-shape + /// \param theValue selected subshape + /// \param theGeometricalNaming treats selection with equal surfaces as one + /// \param theUseNeighbors enables searching algorithm by neighbors + /// \param theUseIntersections enables searching algorithm by intersection of higher level shapes + SELECTOR_EXPORT static Selector_Algo* select( + const TopoDS_Shape theContext, const TopoDS_Shape theValue, + const TDF_Label theAccess, const TDF_Label theBaseDocument, + const bool theGeometricalNaming = false, + const bool theUseNeighbors = true, const bool theUseIntersections = true, + const bool theAlwaysGeometricalNaming = false); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() = 0; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() = 0; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) = 0; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) = 0; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) = 0; + /// Returns the current sub-shape value (null if can not resolve) + SELECTOR_EXPORT TopoDS_Shape value(); + /// Restores sub-algorithm of a given type by the storage-label + SELECTOR_EXPORT Selector_Algo* restoreByLab(TDF_Label theLab); + /// Restores the selected sub-algorithm by the naming name. + /// Returns not empty label of the context. + SELECTOR_EXPORT static Selector_Algo* restoreByName( + TDF_Label theLab, TDF_Label theBaseDocLab, std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator, + TDF_Label& theContextLab); + + /// Returns true if the given shapes are based on the same geometry + static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2); + + /// Creates a new selection algorithm for selection of all topology based on the same geometry + SELECTOR_EXPORT static Selector_Algo* relesectWithAllGeometry( + Selector_Algo* theOldAlgo, const TopoDS_Shape theContext); + +protected: + /// Returns label where this algorithm is attached to, or just an access label to the document + const TDF_Label& label() const + {return myLab;} + /// Stores the array of references to theLab: references to elements of ref-list, then the last + void storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast); + /// Restores references to the labels: references to elements of ref-list, then the last + bool restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast); + /// Stores result of selection at the given label + void store(const TopoDS_Shape theShape); + /// Returns an access-label of the document that may contain initial shapes + const TDF_Label& baseDocument() const + {return myBaseDocumentLab;} + /// Returns the geometrical naming flag + bool geometricalNaming() const + {return myGeometricalNaming;} + /// Returns always geometrical naming flag + bool alwaysGeometricalNaming() const + {return myAlwaysGeometricalNaming;} + /// Returns use neighbors flag + bool useNeighbors() const + {return myUseNeighbors;} + /// Returns use intersections flag + bool useIntersections() const + {return myUseIntersections;} + /// Returns GUID for the weak index (integer attribute) of the sub-shape + static const Standard_GUID& weakID() + { + static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87"); + return kWEAK_INDEX; + } + /// Returns GUID for the type of the shape, stored in case it is intersection or container + static const Standard_GUID& shapeTypeID() + { + static const Standard_GUID kSHAPE_TYPE("864b3267-cb9d-4107-bf58-c3ce1775b171"); + return kSHAPE_TYPE; + } + /// string identifier of the weak name in modification or intersection types of algorithm + static const std::string& weakNameID() + { + static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_"; + return kWEAK_NAME_IDENTIFIER; + } + /// string identifier of the pure weak name + static const std::string& pureWeakNameID() + { + static const std::string kPURE_WEAK_NAME_IDENTIFIER = "_weak_name_"; + return kPURE_WEAK_NAME_IDENTIFIER; + } + /// Stores the type of an algorithm in the data tree (in myLab) + void storeType(const Selector_Type theType); +}; + +#endif diff --git a/src/Selector/Selector_AlgoWithSubs.cpp b/src/Selector/Selector_AlgoWithSubs.cpp new file mode 100644 index 000000000..32229e516 --- /dev/null +++ b/src/Selector/Selector_AlgoWithSubs.cpp @@ -0,0 +1,59 @@ +// 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 + +Selector_AlgoWithSubs::Selector_AlgoWithSubs() : Selector_Algo() +{} + +void Selector_AlgoWithSubs::clearSubAlgos() +{ + std::list::iterator anAlgo = mySubSelList.begin(); + for(; anAlgo != mySubSelList.end(); anAlgo++) { + delete *anAlgo; + } + mySubSelList.clear(); +} + +Selector_AlgoWithSubs::~Selector_AlgoWithSubs() +{ + clearSubAlgos(); +} + +TDF_Label Selector_AlgoWithSubs::newSubLabel() +{ + return label().FindChild(int(mySubSelList.size() + 1)); +} + +bool Selector_AlgoWithSubs::append(Selector_Algo* theAlgo, const bool theEraseIfNull) +{ + if (theAlgo) { + mySubSelList.push_back(theAlgo); + return true; + } + if (theEraseIfNull) + clearSubAlgos(); + return false; +} + +const std::list& Selector_AlgoWithSubs::list() const +{ + return mySubSelList; +} diff --git a/src/Selector/Selector_AlgoWithSubs.h b/src/Selector/Selector_AlgoWithSubs.h new file mode 100644 index 000000000..58734a31f --- /dev/null +++ b/src/Selector/Selector_AlgoWithSubs.h @@ -0,0 +1,51 @@ +// 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 +// + +#ifndef Selector_AlgoWithSubs_H_ +#define Selector_AlgoWithSubs_H_ + +#include "Selector_Algo.h" + +#include + +/**\class Selector_AlgoWithSubs + * \ingroup DataModel + * \brief Kind of selection algorithm: generic algorithm that contains sub-algorithms inside. + * It is base for Container, Intersection and FilterByNeighbours algorithms. + */ +class Selector_AlgoWithSubs: public Selector_Algo +{ + std::list mySubSelList; ///< list of sub-algorithms +public: + /// Initializes selector + Selector_AlgoWithSubs(); + /// Destructor + virtual ~Selector_AlgoWithSubs(); + /// Erases the sub-algorithms stored + void clearSubAlgos(); + /// Returns the next label for a new sub-selector created + TDF_Label newSubLabel(); + /// Appends a new algorithm to the list, erases list if it is null (failed) + bool append(Selector_Algo* theAlgo, const bool theEraseIfNull = true); + /// Returns the stored list of sub-algorithms. + const std::list& list() const; +}; + +#endif diff --git a/src/Selector/Selector_Container.cpp b/src/Selector/Selector_Container.cpp new file mode 100644 index 000000000..32d7134ee --- /dev/null +++ b/src/Selector/Selector_Container.cpp @@ -0,0 +1,180 @@ +// 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 + +Selector_Container::Selector_Container() : Selector_AlgoWithSubs() +{} + +bool Selector_Container::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + myShapeType = theValue.ShapeType(); + + // iterate all sub-shapes and select them on sublabels + for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) { + Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, aSubIter.Value(), + newSubLabel(), baseDocument(), + false, useNeighbors(), useIntersections()); //for subs no geometrical naming allowed + if (!append(aSubAlgo)) + return false; + } + return true; +} + +void Selector_Container::store() +{ + storeType(Selector_Algo::SELTYPE_CONTAINER); + // store all sub-selectors + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + (*aSubSel)->store(); + } + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); +} + +bool Selector_Container::restore() +{ + Handle(TDataStd_Integer) aShapeTypeAttr; + if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr)) + return false; + myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); + // restore sub-selectors + bool aSubResult = true; + for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) { + Selector_Algo* aSubSel = restoreByLab(aSub.Value()); + if (!append(aSubSel, false)) { + break; // some empty label left in the end + } + } + return true; +} + +TDF_Label Selector_Container::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + myShapeType = theShapeType; + TDF_Label aContext; + for(size_t aStart = 0; aStart != std::string::npos; aStart = theName.find('[', aStart + 1)) { + size_t anEndPos = theName.find(']', aStart + 1); + if (anEndPos != std::string::npos) { + std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1); + TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE; + switch (myShapeType) { + case TopAbs_COMPSOLID: aSubShapeType = TopAbs_SOLID; break; + case TopAbs_WIRE: aSubShapeType = TopAbs_EDGE; break; + default:; + } + TDF_Label aSubContext; + Selector_Algo* aSubSel = + Selector_Algo::restoreByName( + label(), baseDocument(), aSubStr, aSubShapeType, theNameGenerator, aSubContext); + if (!append(aSubSel)) + return TDF_Label(); + + if (aSubContext.IsNull()) { + delete aSubSel; + clearSubAlgos(); + return TDF_Label(); + } + if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { + if (!theNameGenerator->isLater(aContext, aSubContext)) + aContext = aSubContext; + } else { + aContext = aSubContext; + } + } else + return TDF_Label(); // invalid parentheses + } + return aContext; +} + +bool Selector_Container::solve(const TopoDS_Shape& theContext) +{ + TopoDS_Shape aResult; + + TopoDS_Builder aBuilder; + switch(myShapeType) { + case TopAbs_COMPOUND: { + TopoDS_Compound aComp; + aBuilder.MakeCompound(aComp); + aResult = aComp; + break; + } + case TopAbs_COMPSOLID: { + TopoDS_CompSolid aComp; + aBuilder.MakeCompSolid(aComp); + aResult = aComp; + break; + } + case TopAbs_SHELL: { + TopoDS_Shell aShell; + aBuilder.MakeShell(aShell); + aResult = aShell; + break; + } + case TopAbs_WIRE: { + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + aResult = aWire; + break; + } + } + TopoDS_ListOfShape aSubSelectorShapes; + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + if (!(*aSubSel)->solve(theContext)) { + return false; + } + aBuilder.Add(aResult, (*aSubSel)->value()); + } + if (!aResult.IsNull()) { + Selector_Algo::store(aResult); + return true; + } + return false; +} + +std::string Selector_Container::name(Selector_NameGenerator* theNameGenerator) +{ + std::string aResult; + // add names of sub-components one by one in "[]" + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + aResult += '['; + aResult += (*aSubSel)->name(theNameGenerator); + aResult += ']'; + } + return aResult; +} diff --git a/src/Selector/Selector_Container.h b/src/Selector/Selector_Container.h new file mode 100644 index 000000000..668b651b3 --- /dev/null +++ b/src/Selector/Selector_Container.h @@ -0,0 +1,64 @@ +// 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 +// + +#ifndef Selector_Container_H_ +#define Selector_Container_H_ + +#include "Selector_AlgoWithSubs.h" + +#include + +/**\class Selector_Container + * \ingroup DataModel + * \brief Kind of selection algorithm: selected shape is a container of sub-shapes that must + * be named one by one. + */ +class Selector_Container: public Selector_AlgoWithSubs +{ + TopAbs_ShapeEnum myShapeType; ///< type of this container +public: + /// Initializes the selection of this kind + SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; +private: + /// Initializes selector + Selector_Container(); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/Selector/Selector_FilterByNeighbors.cpp b/src/Selector/Selector_FilterByNeighbors.cpp new file mode 100644 index 000000000..43221ba64 --- /dev/null +++ b/src/Selector/Selector_FilterByNeighbors.cpp @@ -0,0 +1,354 @@ +// 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 + +// array of the neighbor levels +static const Standard_GUID kLEVELS_ARRAY("ee4c4b45-e859-4e86-aa4f-6eac68e0ca1f"); + +Selector_FilterByNeighbors::Selector_FilterByNeighbors() : Selector_AlgoWithSubs() +{} + +/// Searches neighbor of theLevel of neighborhood to theValue in theContex +static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue, + const int theLevel, TopTools_MapOfShape& theResult) +{ + TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes + if (theValue.ShapeType() == TopAbs_FACE) + aConnectorType = TopAbs_EDGE; + TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors + for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) { + aNBConnectors.Add(aValExp.Current()); + } + + TopTools_MapOfShape alreadyProcessed; + alreadyProcessed.Add(theValue); + + for(int aLevel = 1; aLevel <= theLevel; aLevel++) { + TopoDS_ListOfShape aGoodCandidates; + TopExp_Explorer aCandidate(theContext, theValue.ShapeType()); + for(; aCandidate.More(); aCandidate.Next()) { + if (alreadyProcessed.Contains(aCandidate.Current())) + continue; + TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType); + for(; aCandConnector.More(); aCandConnector.Next()) { + if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor + break; + } + if (aCandConnector.More()) { + if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors + theResult.Add(aCandidate.Current()); + } else { // add to the NB of the current level + aGoodCandidates.Append(aCandidate.Current()); + } + } + } + if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors + for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) { + TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType); + for(; aGoodConnector.More(); aGoodConnector.Next()) { + aNBConnectors.Add(aGoodConnector.Current()); + } + alreadyProcessed.Add(aGood.Value()); + } + } + } +} + +/// Searches the neighbor shape by neighbors defined in theNB in theContext shape +static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext, + const std::list >& theNB, const bool theGeometrical) +{ + // searching for neighbors with minimum level + int aMinLevel = 0; + std::list >::const_iterator aNBIter = theNB.cbegin(); + for(; aNBIter != theNB.cend(); aNBIter++) { + if (aMinLevel == 0 || aNBIter->second < aMinLevel) { + aMinLevel = aNBIter->second; + } + } + // collect all neighbors which are neighbors of sub-shapes with minimum level + bool aFirst = true; + TopoDS_ListOfShape aMatches; + for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) { + if (aNBIter->second == aMinLevel) { + TopTools_MapOfShape aThisNBs; + findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs); + // aMatches must contain common part of all NBs lists + for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) { + if (aFirst) { + aMatches.Append(aThisNB.Value()); + } else { + // remove all in aMatches which are not in this NBs + for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) { + if (aThisNBs.Contains(aMatch.Value())) { + aMatch.Next(); + } else { + aMatches.Remove(aMatch); + } + } + } + } + aFirst = false; + } + } + if (aMatches.IsEmpty()) + return TopoDS_Shape(); // not found any candidate + if (aMatches.Extent() == 1) + return aMatches.First(); // already found good candidate + TopoDS_Compound aResultCompound; // in case of geometrical name and many candidates + // iterate all matches to find by other (higher level) neighbors the best candidate + TopoDS_Shape aGoodCandidate; + TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map + for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) { + bool aValidCadidate = true; + for(int aLevel = aMinLevel + 1; true; aLevel++) { + bool aFooundHigherLevel = false; + TopoDS_ListOfShape aLevelNBs; + for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) { + if (aNBIter->second == aLevel) + aLevelNBs.Append(aNBIter->first); + else if (aNBIter->second >= aLevel) + aFooundHigherLevel = true; + } + if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate + if (aGoodCandidate.IsNull()) { + aGoodCandidate = aCandidate.Value(); + } else { // another good candidate + if (theGeometrical && Selector_Algo::sameGeometry(aGoodCandidate, aCandidate.Value())) { + if (!aGoodCandidates.Add(aCandidate.Value())) + break; + static TopoDS_Builder aBuilder; + if (aResultCompound.IsNull()) { + aBuilder.MakeCompound(aResultCompound); + aBuilder.Add(aResultCompound, aGoodCandidate); + } + aBuilder.Add(aResultCompound, aCandidate.Value()); + } else + return TopoDS_Shape(); + } + } + if (!aLevelNBs.IsEmpty()) { + TopTools_MapOfShape aNBsOfCandidate; + findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate); + // check all stored neighbors are in the map of real neighbors + for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) { + if (!aNBsOfCandidate.Contains(aLevIter.Value())) { + aValidCadidate = false; + break; + } + } + } + if (!aValidCadidate) // candidate is not valid, break the checking + break; + } + } + if (!aResultCompound.IsNull()) + return aResultCompound; + return aGoodCandidate; +} + +bool Selector_FilterByNeighbors::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + myShapeType = theValue.ShapeType(); + // searching by neighbors + std::list > aNBs; /// neighbor sub-shape -> level of neighborhood + for(int aLevel = 1; true; aLevel++) { + TopTools_MapOfShape aNewNB; + findNeighbors(theContext, theValue, aLevel, aNewNB); + if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration + break; + } + // iterate by the order in theContext to keep same naming names + TopExp_Explorer anOrder(theContext, theValue.ShapeType()); + for (; anOrder.More(); anOrder.Next()) { + if (aNewNB.Contains(anOrder.Current())) { + TopoDS_Shape aNewNBShape = anOrder.Current(); + // check which can be named correctly, without "by neighbors" type + Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, aNewNBShape, + newSubLabel(), baseDocument(), geometricalNaming(), false, false); + if (aSubAlgo) { + // add to list of good NBs + aNBs.push_back(std::pair(aNewNBShape, aLevel)); + } + delete aSubAlgo; // don't keep this sub-algo until all subs and whole validity are checked + } + } + TopoDS_Shape aResult = findNeighbor(theContext, aNBs, geometricalNaming()); + if (!aResult.IsNull() && aResult.IsSame(theValue)) { + std::list >::iterator aNBIter = aNBs.begin(); + for(; aNBIter != aNBs.end(); aNBIter++) { + Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, aNBIter->first, + newSubLabel(), baseDocument(), geometricalNaming(), false, false); + if (append(aSubAlgo)) { + myNBLevel.push_back(aNBIter->second); + } else { + delete aSubAlgo; + } + } + return true; + } + } + return false; +} + +void Selector_FilterByNeighbors::store() +{ + storeType(Selector_Algo::SELTYPE_FILTER_BY_NEIGHBOR); + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); + // store numbers of levels corresponded to the neighbors in sub-selectors + Handle(TDataStd_IntegerArray) anArray = + TDataStd_IntegerArray::Set(label(), kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1); + std::list::iterator aLevel = myNBLevel.begin(); + for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) { + anArray->SetValue(anIndex, *aLevel); + } + // store all sub-selectors + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + (*aSubSel)->store(); + } +} + +bool Selector_FilterByNeighbors::restore() +{ + Handle(TDataStd_Integer) aShapeTypeAttr; + if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr)) + return false; + myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); + // restore levels indices + Handle(TDataStd_IntegerArray) anArray; + if (!label().FindAttribute(kLEVELS_ARRAY, anArray)) + return false; + for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) { + myNBLevel.push_back(anArray->Value(anIndex)); + } + // restore sub-selectors + bool aSubResult = true; + for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) { + Selector_Algo* aSubSel = restoreByLab(aSub.Value()); + if (!append(aSubSel, false)) { + break; // some empty label left in the end + } + } + return true; +} + +TDF_Label Selector_FilterByNeighbors::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + myShapeType = theShapeType; + TDF_Label aContext; + for (size_t aStart = 0; aStart != std::string::npos; + aStart = theName.find('(', aStart + 1)) { + size_t anEndPos = theName.find(')', aStart + 1); + if (anEndPos != std::string::npos) { + std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1); + TDF_Label aSubContext; + Selector_Algo* aSubSel = + Selector_Algo::restoreByName( + label(), baseDocument(), aSubStr, myShapeType, theNameGenerator, aSubContext); + if (!append(aSubSel)) + return TDF_Label(); + + if (aSubContext.IsNull()) { + delete aSubSel; + clearSubAlgos(); + return TDF_Label(); + } + if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { + if (!theNameGenerator->isLater(aContext, aSubContext)) + aContext = aSubContext; + } else { + aContext = aSubContext; + } + if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital + aContext = theNameGenerator->newestContext(aContext); + + // searching for the level index + std::string aLevel; + for (anEndPos++; anEndPos != std::string::npos && + theName[anEndPos] != '(' && theName[anEndPos] != 0; + anEndPos++) { + aLevel += theName[anEndPos]; + } + if (aLevel.empty()) + myNBLevel.push_back(1); // by default it is 1 + else { + int aNum = atoi(aLevel.c_str()); + if (aNum > 0) + myNBLevel.push_back(aNum); + else + return TDF_Label(); // invalid number + } + } else + return TDF_Label(); // invalid parentheses + } + return aContext; +} + +bool Selector_FilterByNeighbors::solve(const TopoDS_Shape& theContext) +{ + TopoDS_Shape aResult; + + std::list > aNBs; /// neighbor sub-shape -> level of neighborhood + std::list::iterator aLevel = myNBLevel.begin(); + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++, aLevel++) { + if (!(*aSubSel)->solve(theContext)) { + return false; + } + aNBs.push_back(std::pair((*aSubSel)->value(), *aLevel)); + } + aResult = findNeighbor(theContext, aNBs, geometricalNaming()); + if (!aResult.IsNull()) { + Selector_Algo::store(aResult); + return true; + } + return false; +} + +std::string Selector_FilterByNeighbors::name(Selector_NameGenerator* theNameGenerator) +{ + // (nb1)level_if_more_than_1(nb2)level_if_more_than_1(nb3)level_if_more_than_1 + std::string aResult; + std::list::iterator aLevel = myNBLevel.begin(); + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++, aLevel++) { + aResult += "(" + (*aSubSel)->name(theNameGenerator) + ")"; + if (*aLevel > 1) { + std::ostringstream aLevelStr; + aLevelStr<<*aLevel; + aResult += aLevelStr.str(); + } + } + return aResult; +} diff --git a/src/Selector/Selector_FilterByNeighbors.h b/src/Selector/Selector_FilterByNeighbors.h new file mode 100644 index 000000000..721e4a923 --- /dev/null +++ b/src/Selector/Selector_FilterByNeighbors.h @@ -0,0 +1,66 @@ +// 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 +// + +#ifndef Selector_FilterByNeighbors_H_ +#define Selector_FilterByNeighbors_H_ + +#include "Selector_AlgoWithSubs.h" + +#include + +/**\class Selector_FilterByNeighbors + * \ingroup DataModel + * \brief Kind of selection algorithm: selected shape is identified by neighbor faces of + * the same type. Or neighbors of neighbors are considered, etc. + * be named one by one. + */ +class Selector_FilterByNeighbors: public Selector_AlgoWithSubs +{ + TopAbs_ShapeEnum myShapeType; ///< type of this shape + std::list myNBLevel; ///< list of integers corresponding to subs neighborhood level +public: + /// Initializes the selection of this kind + SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; +private: + /// Initializes selector + Selector_FilterByNeighbors(); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/Selector/Selector_Intersect.cpp b/src/Selector/Selector_Intersect.cpp new file mode 100644 index 000000000..8d1a3de88 --- /dev/null +++ b/src/Selector/Selector_Intersect.cpp @@ -0,0 +1,316 @@ +// 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 + +Selector_Intersect::Selector_Intersect() : Selector_AlgoWithSubs() +{ + myWeakIndex = -1; // no index by default +} + +// returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection) +static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType, + TopoDS_ListOfShape& theResults) +{ + TopoDS_ListOfShape::iterator aSubSel = theShapes.begin(); + for(; aSubSel != theShapes.end(); aSubSel++) { + TopTools_MapOfShape aCurrentMap; + for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) { + if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin()) + theResults.Append(anExp.Current()); + } + if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap + for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) { + if (aCurrentMap.Contains(aComIter.Value())) + aComIter.Next(); + else + theResults.Remove(aComIter); + } + } + } +} + +bool Selector_Intersect::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + myShapeType = theValue.ShapeType(); + TopAbs_ShapeEnum aSelectionType = myShapeType; + // try to find the shape of the higher level type in the context shape + bool aFacesTried = false; // for identification of vertices, faces are tried, then edges + TopoDS_ListOfShape aLastCommon; // store not good commons, but which may be used for weak naming + TopoDS_ListOfShape aLastIntersectors; + while(aSelectionType != TopAbs_FACE || !aFacesTried) { + if (aSelectionType == TopAbs_FACE) { + if (theValue.ShapeType() != TopAbs_VERTEX) + break; + aFacesTried = true; + aSelectionType = TopAbs_EDGE; + } else + aSelectionType = TopAbs_FACE; + TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue + TopoDS_ListOfShape anIntList; // same as anIntersectors + for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) { + if (aSelectionType == TopAbs_EDGE && + BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current()))) + continue; + TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType()); + for(; aSubExp.More(); aSubExp.Next()) { + if (aSubExp.Current().IsSame(theValue)) { + if (anIntersectors.Add(aSelExp.Current())) + anIntList.Append(aSelExp.Current()); + break; + } + } + } + // check that solution is only one + TopoDS_ListOfShape aCommon; + commonShapes(anIntList, theValue.ShapeType(), aCommon); + if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) { + // name the intersectors + TopoDS_ListOfShape::Iterator anInt(anIntList); + for (; anInt.More(); anInt.Next()) { + Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(), + newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), false); + if (!append(aSubAlgo)) + break; // if some selector is failed, stop and search another solution + } + if (!anInt.More()) { // all intersectors were correctly named + return true; + } + } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) { + aLastCommon = aCommon; + aLastIntersectors = anIntList; + } + } + if (aLastCommon.Extent() > 1) { + if (alwaysGeometricalNaming()) { + TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon); + TopoDS_Shape aFirst = aCommonIter.Value(); + for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { + if (!sameGeometry(aFirst, aCommonIter.Value())) + break; + } + if (!aCommonIter.More()) { // all geometry is same, result is a compound + return true; + } + } + // weak naming to distinguish commons coming from intersection + Selector_NExplode aNexp(aLastCommon); + myWeakIndex = aNexp.index(theValue); + if (myWeakIndex != -1) { + // name the intersectors + TopoDS_ListOfShape::Iterator anInt(aLastIntersectors); + for (; anInt.More(); anInt.Next()) { + Selector_Algo* aSubAlgo = Selector_Algo::select(theContext, anInt.Value(), + newSubLabel(), baseDocument(), geometricalNaming(), useNeighbors(), useIntersections()); + if (!append(aSubAlgo)) + break; // if some selector is failed, stop and search another solution + } + if (!anInt.More()) { // all intersectors were correctly named + return true; + } + } + } + return false; // solution does not found +} + +void Selector_Intersect::store() +{ + storeType(Selector_Algo::SELTYPE_INTERSECT); + // store all sub-selectors + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + (*aSubSel)->store(); + } + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); + if (myWeakIndex != -1) { + TDataStd_Integer::Set(label(), weakID(), myWeakIndex); + } +} + +bool Selector_Intersect::restore() +{ + Handle(TDataStd_Integer) aShapeTypeAttr; + if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr)) + return false; + myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); + // restore sub-selectors + bool aSubResult = true; + for(TDF_ChildIterator aSub(label(), false); aSub.More(); aSub.Next()) { + Selector_Algo* aSubSel = restoreByLab(aSub.Value()); + if (!append(aSubSel, false)) { + break; // some empty label left in the end + } + } + Handle(TDataStd_Integer) aWeakInt; + if (label().FindAttribute(weakID(), aWeakInt)) { + myWeakIndex = aWeakInt->Get(); + } + return true; +} + +TDF_Label Selector_Intersect::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + myShapeType = theShapeType; + TDF_Label aContext; + for(size_t aStart = 0; aStart != std::string::npos; aStart = theName.find('[', aStart + 1)) { + size_t anEndPos = theName.find(']', aStart + 1); + if (anEndPos != std::string::npos) { + std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1); + if (aSubStr.find(weakNameID()) == 0) { // weak name identifier + std::string aWeakIndex = aSubStr.substr(weakNameID().size()); + myWeakIndex = atoi(aWeakIndex.c_str()); + continue; + } + TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE; + if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) { + char aShapeChar = theName[anEndPos + 1]; + if (theName[anEndPos + 1] != '[') { + switch(aShapeChar) { + case 'c': aSubShapeType = TopAbs_COMPOUND; break; + case 'o': aSubShapeType = TopAbs_COMPSOLID; break; + case 's': aSubShapeType = TopAbs_SOLID; break; + case 'h': aSubShapeType = TopAbs_SHELL; break; + case 'w': aSubShapeType = TopAbs_WIRE; break; + case 'e': aSubShapeType = TopAbs_EDGE; break; + case 'v': aSubShapeType = TopAbs_VERTEX; break; + default:; + } + } + } + TDF_Label aSubContext; + Selector_Algo* aSubSel = + Selector_Algo::restoreByName( + label(), baseDocument(), aSubStr, aSubShapeType, theNameGenerator, aSubContext); + if (!append(aSubSel)) + return TDF_Label(); + + if (aSubContext.IsNull()) { + delete aSubSel; + clearSubAlgos(); + return TDF_Label(); + } + if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { + if (!theNameGenerator->isLater(aContext, aSubContext)) + aContext = aSubContext; + } else { + aContext = aSubContext; + } + } else + return TDF_Label(); // invalid parentheses + } + return aContext; +} + +bool Selector_Intersect::solve(const TopoDS_Shape& theContext) +{ + TopoDS_Shape aResult; + TopoDS_ListOfShape aSubSelectorShapes; + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + if (!(*aSubSel)->solve(theContext)) { + return false; + } + aSubSelectorShapes.Append((*aSubSel)->value()); + } + TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result) + commonShapes(aSubSelectorShapes, myShapeType, aCommon); + if (aCommon.Extent() != 1) { + if (myWeakIndex != -1) { + Selector_NExplode aNexp(aCommon); + aResult = aNexp.shape(myWeakIndex); + } else if (geometricalNaming() && aCommon.Extent() > 1) { + // check results are on the same geometry, create compound + TopoDS_ListOfShape::Iterator aCommonIter(aCommon); + TopoDS_Shape aFirst = aCommonIter.Value(); + for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { + if (!sameGeometry(aFirst, aCommonIter.Value())) + break; + } + if (!aCommonIter.More()) { // all geometry is same, create a result compound + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) { + aBuilder.Add(aCompound, aCommonIter.Value()); + } + aResult = aCompound; + } + } else { + return false; + } + } else { + aResult = aCommon.First(); + } + if (!aResult.IsNull()) { + Selector_Algo::store(aResult); + return true; + } + return false; +} + +std::string Selector_Intersect::name(Selector_NameGenerator* theNameGenerator) +{ + std::string aResult; + // add names of sub-components one by one in "[]" +optionally [weak_name_1] + std::list::const_iterator aSubSel = list().cbegin(); + for(; aSubSel != list().cend(); aSubSel++) { + aResult += '['; + aResult += (*aSubSel)->name(theNameGenerator); + aResult += ']'; + TopoDS_Shape aSubVal = (*aSubSel)->value(); + if (!aSubVal.IsNull()) { + TopAbs_ShapeEnum aSubType = aSubVal.ShapeType(); + if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored + switch(aSubType) { + case TopAbs_COMPOUND: aResult += "c"; break; + case TopAbs_COMPSOLID: aResult += "o"; break; + case TopAbs_SOLID: aResult += "s"; break; + case TopAbs_SHELL: aResult += "h"; break; + case TopAbs_WIRE: aResult += "w"; break; + case TopAbs_EDGE: aResult += "e"; break; + case TopAbs_VERTEX: aResult += "v"; break; + default:; + } + } + } + } + if (myWeakIndex != -1) { + std::ostringstream aWeakStr; + aWeakStr<<"["< +// + +#ifndef Selector_Intersect_H_ +#define Selector_Intersect_H_ + +#include "Selector_AlgoWithSubs.h" + +#include + +/**\class Selector_Intersect + * \ingroup DataModel + * \brief Kind of selection algorithm: sub-shape is intersection of higher level objects. + */ +class Selector_Intersect: public Selector_AlgoWithSubs +{ + TopAbs_ShapeEnum myShapeType; ///< type of this shape + int myWeakIndex; ///< weak index in case intersection produces several shapes +public: + /// Initializes the selection of this kind + SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; +private: + /// Initializes selector + Selector_Intersect(); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/Selector/Selector_Modify.cpp b/src/Selector/Selector_Modify.cpp new file mode 100644 index 000000000..f764e1d39 --- /dev/null +++ b/src/Selector/Selector_Modify.cpp @@ -0,0 +1,329 @@ +// 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 + +Selector_Modify::Selector_Modify() : Selector_Algo() +{ + myWeakIndex = -1; // no index by default +} + +// adds to theResult all labels that contain initial shapes for theValue located in theFinal +static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal, + const TopoDS_Shape& theValue, + bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult) +{ + bool aFoundAnyShape = false; + TNaming_SameShapeIterator aLabIter(theValue, theAccess); + for(; aLabIter.More(); aLabIter.Next()) { + Handle(TNaming_NamedShape) aNS; + if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aMustBeAtFinal && aNS != theFinal) + continue; // looking for old at the same final label only + TNaming_Evolution anEvolution = aNS->Evolution(); + if (anEvolution == TNaming_PRIMITIVE) { + // check that this is not in the results already + const TDF_Label aResult = aNS->Label(); + TDF_LabelList::Iterator aResIter(theResult); + for(; aResIter.More(); aResIter.Next()) { + if (aResIter.Value().IsEqual(aResult)) + break; + } + if (!aResIter.More()) // not found, so add this new + theResult.Append(aResult); + aFoundAnyShape = true; + } + if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { + for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) { + if (aThisIter.NewShape().IsSame(theValue)) { + // continue recursively, null NS means that any NS are ok + findBases(theAccess, theFinal, aThisIter.OldShape(), + false, theAdditionalDocument, theResult); + aFoundAnyShape = true; + } + } + } + } + } + if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document + static TDF_Label anEmpty; + if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue)) + findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue, + false, anEmpty, theResult); + } +} + +/// Returns in theResults all shapes with history started in theBase and ended in theFinal +static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase, + const TDF_Label& theFinal, + const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults) +{ + if (TNaming_Tool::HasLabel(anAccess, theBase)) { + for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next()) + { + TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution(); + if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { + if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) { + theResults.Add(aBaseIter.Shape()); + } else { + findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults); + } + } + } + } + if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label + static TDF_Label anEmpty; + findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults); + } +} + +void Selector_Modify::findModificationResult(TopoDS_ListOfShape& theCommon) { + for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) { + TDF_Label anAdditionalDoc; // this document if base is started in extra document + if (aBase.Value().Root() != label().Root()) { + anAdditionalDoc = label(); + } + TopTools_MapOfShape aFinals; + for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) { + findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals); + } + if (!aFinals.IsEmpty()) { + if (theCommon.IsEmpty()) { // just copy all to common + for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) { + theCommon.Append(aFinal.Key()); + } + } else { // keep only shapes presented in both lists + for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) { + if (aFinals.Contains(aCommon.Value())) { + aCommon.Next(); + } else { // common is not found, remove it + theCommon.Remove(aCommon); + } + } + } + } + } +} + +bool Selector_Modify::select(NCollection_List& theModifList, + const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + if (theModifList.Extent() > 1) { // searching for the best modification result: by context + Handle(TNaming_NamedShape) aCandidate; + NCollection_List::Iterator aModIter(theModifList); + for (; !theModifList.IsEmpty() && aModIter.More(); aModIter.Next()) { + aCandidate = aModIter.Value(); + TDF_Label aFatherLab = aCandidate->Label().Father(); + Handle(TNaming_NamedShape) aFatherNS; + if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) { + for (TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) { + if (theContext.IsSame(anIter.NewShape())) { // found the best modification + theModifList.Clear(); + break; + } + } + } + } + // take the best candidate, or the last in the iteration + theModifList.Clear(); + theModifList.Append(aCandidate); + } + + if (!theModifList.IsEmpty()) { + // searching for all the base shapes of this modification + findBases(label(), theModifList.First(), theValue, true, baseDocument(), myBases); + if (!myBases.IsEmpty()) { + myFinal = theModifList.First()->Label(); + TopoDS_ListOfShape aCommon; + findModificationResult(aCommon); + // trying to search by neighbors + if (aCommon.Extent() > 1) { // more complicated selection + if (alwaysGeometricalNaming()) { + TopoDS_ListOfShape::Iterator aCommonIter(aCommon); + TopoDS_Shape aFirst = aCommonIter.Value(); + for (aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { + if (!sameGeometry(aFirst, aCommonIter.Value())) + break; + } + if (!aCommonIter.More()) { // all geometry is same, result is a compound + return true; + } + } + } + } + // weak naming case + TopoDS_ListOfShape aCommon; + myFinal = theModifList.First()->Label(); + Handle(TNaming_NamedShape) aNS; + if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) { + const TopoDS_Shape& aNewShape = aFinalIter.NewShape(); + if (!aNewShape.IsNull()) + aCommon.Append(aNewShape); + } + } + Selector_NExplode aNexp(aCommon); + myWeakIndex = aNexp.index(theValue); + return myWeakIndex != -1; + } + return false; +} + +void Selector_Modify::store() +{ + storeType(Selector_Algo::SELTYPE_MODIFICATION); + storeBaseArray(myBases, myFinal); + if (myWeakIndex != -1) { + TDataStd_Integer::Set(label(), weakID(), myWeakIndex); + } +} + +bool Selector_Modify::restore() +{ + if (restoreBaseArray(myBases, myFinal)) { + Handle(TDataStd_Integer) aWeakInt; + if (label().FindAttribute(weakID(), aWeakInt)) { + myWeakIndex = aWeakInt->Get(); + } + return true; + } + return false; +} + +TDF_Label Selector_Modify::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + TDF_Label aContext; + for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) { + if (aStart != 0) + aStart++; + anEnd = theName.find('&', aStart); + std::string aSubStr = + theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart); + if (aSubStr.find(weakNameID()) == 0) { // weak name identifier + std::string aWeakIndex = aSubStr.substr(weakNameID().size()); + myWeakIndex = atoi(aWeakIndex.c_str()); + continue; + } + TDF_Label aSubContext, aValue; + if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue)) + return TDF_Label(); // can not restore + if(aSubContext.IsNull() || aValue.IsNull()) + return TDF_Label(); // can not restore + if (myFinal.IsNull()) { + myFinal = aValue; + aContext = aSubContext; + } else + myBases.Append(aValue); + } + return aContext; +} + +bool Selector_Modify::solve(const TopoDS_Shape& theContext) +{ + TopoDS_Shape aResult; + if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index + TopoDS_ListOfShape aCommon; + Handle(TNaming_NamedShape) aNS; + if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) { + const TopoDS_Shape& aNewShape = aFinalIter.NewShape(); + if (!aNewShape.IsNull()) + aCommon.Append(aNewShape); + } + } + Selector_NExplode aNexp(aCommon); + aResult = aNexp.shape(myWeakIndex); + } else { // standard case + TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases + findModificationResult(aFinalsCommon); + if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape + aResult = aFinalsCommon.First(); + } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) { + Selector_NExplode aNExp(aFinalsCommon); + aResult = aNExp.shape(myWeakIndex); + } else if (aFinalsCommon.Extent() > 1 && geometricalNaming()) {// if same geometry - compound + TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon); + TopoDS_Shape aFirst = aCommonIter.Value(); + for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { + if (!sameGeometry(aFirst, aCommonIter.Value())) + break; + } + if (!aCommonIter.More()) { // all geometry is same, create a result compound + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) { + aBuilder.Add(aCompound, aCommonIter.Value()); + } + aResult = aCompound; + } + + } + } + + if (!aResult.IsNull()) { + Selector_Algo::store(aResult); + return true; + } + return false; +} + +std::string Selector_Modify::name(Selector_NameGenerator* theNameGenerator) +{ + // final&base1&base2 +optionally: [weak_name_1] + std::string aResult; + Handle(TDataStd_Name) aName; + if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName)) + return ""; + aResult += theNameGenerator->contextName(myFinal) + "/" + + std::string(TCollection_AsciiString(aName->Get()).ToCString()); + for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) { + if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName)) + return ""; + aResult += "&"; + aResult += theNameGenerator->contextName(*aBase) + "/" + + std::string(TCollection_AsciiString(aName->Get()).ToCString()); + } + if (myWeakIndex != -1) { + std::ostringstream aWeakStr; + aWeakStr<<"&"< +// + +#ifndef Selector_Modify_H_ +#define Selector_Modify_H_ + +#include "Selector_Algo.h" + +#include + +#include + +/**\class Selector_Modify + * \ingroup DataModel + * \brief Kind of selection algorithm: sub-shape is modification of primitive at some + * final stage. + */ +class Selector_Modify: public Selector_Algo +{ + TDF_Label myFinal; ///< final label of the primitive or generation, where the value is + TDF_LabelList myBases; ///< initial labels that contain shapes that produce the modification + int myWeakIndex; ///< weak index in case modification produces several shapes +public: + /// Initializes the selection of this kind by list of named shapes where the modification results + /// are presented and the selected value. + SELECTOR_EXPORT bool select(NCollection_List& theModifList, + const TopoDS_Shape theContext, const TopoDS_Shape theValue); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; + +private: + /// Initializes selector + Selector_Modify(); + /// Searches the final shapes presented in all results from bases basing on modification fields + void findModificationResult(TopoDS_ListOfShape& theCommon); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/Selector/Selector_NExplode.h b/src/Selector/Selector_NExplode.h index dc4d0064b..cb23b4d24 100644 --- a/src/Selector/Selector_NExplode.h +++ b/src/Selector/Selector_NExplode.h @@ -45,7 +45,7 @@ class Selector_NExplode SELECTOR_EXPORT TopoDS_Shape shape(const int theIndex); protected: - TopoDS_ListOfShape mySorted; ///< keepthe the ordered list of shapes + TopoDS_ListOfShape mySorted; ///< keep the ordered list of shapes }; #endif diff --git a/src/Selector/Selector_Primitive.cpp b/src/Selector/Selector_Primitive.cpp new file mode 100644 index 000000000..15c617da0 --- /dev/null +++ b/src/Selector/Selector_Primitive.cpp @@ -0,0 +1,81 @@ +// 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 + + +Selector_Primitive::Selector_Primitive() : Selector_Algo() +{ +} + +void Selector_Primitive::select(const TDF_Label theFinalLabel) +{ + myFinal = theFinalLabel; +} + +void Selector_Primitive::store() +{ + storeType(Selector_Algo::SELTYPE_PRIMITIVE); + static const TDF_LabelList anEmptyRefList; + storeBaseArray(anEmptyRefList, myFinal); +} + +bool Selector_Primitive::restore() +{ + static TDF_LabelList anEmptyRefList; + return restoreBaseArray(anEmptyRefList, myFinal); +} + +TDF_Label Selector_Primitive::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + TDF_Label aContext; + if (theNameGenerator->restoreContext(theName, aContext, myFinal)) { + if (myFinal.IsNull()) + aContext.Nullify(); + } + return aContext; +} + +bool Selector_Primitive::solve(const TopoDS_Shape& theContext) +{ + Handle(TNaming_NamedShape) aNS; + if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + Selector_Algo::store(aNS->Get()); + return true; + } + return false; +} + +std::string Selector_Primitive::name(Selector_NameGenerator* theNameGenerator) +{ + Handle(TDataStd_Name) aName; + if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName)) + return ""; + std::string aResult = theNameGenerator->contextName(myFinal); + if (!aResult.empty()) + aResult += "/" + std::string(TCollection_AsciiString(aName->Get()).ToCString()); + return aResult; +} diff --git a/src/Selector/Selector_Primitive.h b/src/Selector/Selector_Primitive.h new file mode 100644 index 000000000..ea8b23a89 --- /dev/null +++ b/src/Selector/Selector_Primitive.h @@ -0,0 +1,62 @@ +// 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 +// + +#ifndef Selector_Primitive_H_ +#define Selector_Primitive_H_ + +#include "Selector_Algo.h" + +/**\class Selector_Primitive + * \ingroup DataModel + * \brief Kind of selection algorithm: exact referencing to alone shape in the data structure. + */ +class Selector_Primitive: public Selector_Algo +{ + TDF_Label myFinal; ///< final label of the where the value is +public: + /// Initializes the selection of this kind + /// \param theLabel the final label with the primitive shape + SELECTOR_EXPORT void select(const TDF_Label theFinalLabel); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; +private: + /// Initializes selector + Selector_Primitive(); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index 0a5c87ac3..62d1ad0cb 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D + // 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 @@ -21,1113 +21,51 @@ #include #include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/// type of the selection, integer keeps the Selector_Type value -static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6"); -/// type of the shape, stored in case it is intersection or container -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 -static const Standard_GUID kWEAK_INDEX("e9373a61-cabc-4ee8-aabf-aea47c62ed87"); -// geometrical naming indicator -static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657"); - -// string identifier of the weak name in modification or intersection types of algorithm -static const std::string kWEAK_NAME_IDENTIFIER = "weak_name_"; -// string identifier of the pure weak name algorithm -static const std::string kPUREWEAK_NAME_IDENTIFIER = "_weak_name_"; - - -Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab) -{ - myWeakIndex = -1; - myAlwaysGeometricalNaming = false; -} - -TDF_Label Selector_Selector::label() -{ - return myLab; -} - -void Selector_Selector::setBaseDocument(const TDF_Label theAccess) -{ - myBaseDocumentLab = theAccess; -} - -// adds to theResult all labels that contain initial shapes for theValue located in theFinal -static void findBases(TDF_Label theAccess, Handle(TNaming_NamedShape) theFinal, - const TopoDS_Shape& theValue, - bool aMustBeAtFinal, const TDF_Label& theAdditionalDocument, TDF_LabelList& theResult) -{ - bool aFoundAnyShape = false; - TNaming_SameShapeIterator aLabIter(theValue, theAccess); - for(; aLabIter.More(); aLabIter.Next()) { - Handle(TNaming_NamedShape) aNS; - if (aLabIter.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - if (aMustBeAtFinal && aNS != theFinal) - continue; // looking for old at the same final label only - TNaming_Evolution anEvolution = aNS->Evolution(); - if (anEvolution == TNaming_PRIMITIVE) { - // check that this is not in the results already - const TDF_Label aResult = aNS->Label(); - TDF_LabelList::Iterator aResIter(theResult); - for(; aResIter.More(); aResIter.Next()) { - if (aResIter.Value().IsEqual(aResult)) - break; - } - if (!aResIter.More()) // not found, so add this new - theResult.Append(aResult); - aFoundAnyShape = true; - } - if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { - for(TNaming_Iterator aThisIter(aNS); aThisIter.More(); aThisIter.Next()) { - if (aThisIter.NewShape().IsSame(theValue)) { - // continue recursively, null NS means that any NS are ok - findBases(theAccess, theFinal, aThisIter.OldShape(), - false, theAdditionalDocument, theResult); - aFoundAnyShape = true; - } - } - } - } - } - if (!aFoundAnyShape && !theAdditionalDocument.IsNull()) { // try to find in additional document - static TDF_Label anEmpty; - if (TNaming_Tool::HasLabel(theAdditionalDocument, theValue)) - findBases(theAdditionalDocument, Handle(TNaming_NamedShape)(), theValue, - false, anEmpty, theResult); - } -} - -// returns the sub-shapes of theSubType which belong to all theShapes (so, common or intersection) -static void commonShapes(const TopoDS_ListOfShape& theShapes, TopAbs_ShapeEnum theSubType, - TopoDS_ListOfShape& theResults) -{ - TopoDS_ListOfShape::iterator aSubSel = theShapes.begin(); - for(; aSubSel != theShapes.end(); aSubSel++) { - TopTools_MapOfShape aCurrentMap; - for(TopExp_Explorer anExp(*aSubSel, theSubType); anExp.More(); anExp.Next()) { - if (aCurrentMap.Add(anExp.Current()) && aSubSel == theShapes.begin()) - theResults.Append(anExp.Current()); - } - if (aSubSel != theShapes.begin()) { // remove from common shapes not in aCurrentMap - for(TopoDS_ListOfShape::Iterator aComIter(theResults); aComIter.More(); ) { - if (aCurrentMap.Contains(aComIter.Value())) - aComIter.Next(); - else - theResults.Remove(aComIter); - } - } - } -} - -/// Searches neighbor of theLevel of neighborhood to theValue in theContex -static void findNeighbors(const TopoDS_Shape theContext, const TopoDS_Shape theValue, - const int theLevel, TopTools_MapOfShape& theResult) -{ - TopAbs_ShapeEnum aConnectorType = TopAbs_VERTEX; // type of the connector sub-shapes - if (theValue.ShapeType() == TopAbs_FACE) - aConnectorType = TopAbs_EDGE; - TopTools_MapOfShape aNBConnectors; // connector shapes that already belong to neighbors - for(TopExp_Explorer aValExp(theValue, aConnectorType); aValExp.More(); aValExp.Next()) { - aNBConnectors.Add(aValExp.Current()); - } - - TopTools_MapOfShape alreadyProcessed; - alreadyProcessed.Add(theValue); - - for(int aLevel = 1; aLevel <= theLevel; aLevel++) { - TopoDS_ListOfShape aGoodCandidates; - TopExp_Explorer aCandidate(theContext, theValue.ShapeType()); - for(; aCandidate.More(); aCandidate.Next()) { - if (alreadyProcessed.Contains(aCandidate.Current())) - continue; - TopExp_Explorer aCandConnector(aCandidate.Current(), aConnectorType); - for(; aCandConnector.More(); aCandConnector.Next()) { - if (aNBConnectors.Contains(aCandConnector.Current())) // candidate is neighbor - break; - } - if (aCandConnector.More()) { - if (aLevel == theLevel) { // add a NB into result: it is connected to other neighbors - theResult.Add(aCandidate.Current()); - } else { // add to the NB of the current level - aGoodCandidates.Append(aCandidate.Current()); - } - } - } - if (aLevel != theLevel) { // good candidates are added to neighbor of this level by connectors - for(TopoDS_ListOfShape::Iterator aGood(aGoodCandidates); aGood.More(); aGood.Next()) { - TopExp_Explorer aGoodConnector(aGood.Value(), aConnectorType); - for(; aGoodConnector.More(); aGoodConnector.Next()) { - aNBConnectors.Add(aGoodConnector.Current()); - } - alreadyProcessed.Add(aGood.Value()); - } - } - } -} +#include +#include +#include +#include -/// Returns true if the given shapes are based on the same geometry -static bool sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) { - if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType()) - { - if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces - TopLoc_Location aLoc1, aLoc2; - TopoDS_Face aFace1 = TopoDS::Face(theShape1); - Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1); - TopoDS_Face aFace2 = TopoDS::Face(theShape2); - Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2); - return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2); - } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves - TopLoc_Location aLoc1, aLoc2; - Standard_Real aFirst, aLast; - TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1); - Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast); - TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2); - Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast); - return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2); - } - } - return false; -} +Selector_Selector::Selector_Selector(TDF_Label theLab, TDF_Label theBaseDocLab) : + myLab(theLab), myBaseDocumentLab(theBaseDocLab), myAlgo(NULL) +{} -/// Searches the neighbor shape by neighbors defined in theNB in theContext shape -static const TopoDS_Shape findNeighbor(const TopoDS_Shape theContext, - const std::list >& theNB, const bool theGeometrical) +Selector_Selector::~Selector_Selector() { - // searching for neighbors with minimum level - int aMinLevel = 0; - std::list >::const_iterator aNBIter = theNB.cbegin(); - for(; aNBIter != theNB.cend(); aNBIter++) { - if (aMinLevel == 0 || aNBIter->second < aMinLevel) { - aMinLevel = aNBIter->second; - } - } - // collect all neighbors which are neighbors of sub-shapes with minimum level - bool aFirst = true; - TopoDS_ListOfShape aMatches; - for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) { - if (aNBIter->second == aMinLevel) { - TopTools_MapOfShape aThisNBs; - findNeighbors(theContext, aNBIter->first, aMinLevel, aThisNBs); - // aMatches must contain common part of all NBs lists - for(TopTools_MapOfShape::Iterator aThisNB(aThisNBs); aThisNB.More(); aThisNB.Next()) { - if (aFirst) { - aMatches.Append(aThisNB.Value()); - } else { - // remove all in aMatches which are not in this NBs - for(TopoDS_ListOfShape::Iterator aMatch(aMatches); aMatch.More(); ) { - if (aThisNBs.Contains(aMatch.Value())) { - aMatch.Next(); - } else { - aMatches.Remove(aMatch); - } - } - } - } - aFirst = false; - } - } - if (aMatches.IsEmpty()) - return TopoDS_Shape(); // not found any candidate - if (aMatches.Extent() == 1) - return aMatches.First(); // already found good candidate - TopoDS_Compound aResultCompound; // in case of geometrical name and many candidates - // iterate all matches to find by other (higher level) neighbors the best candidate - TopoDS_Shape aGoodCandidate; - TopTools_MapOfShape aGoodCandidates; // already added good candidates to the map - for(TopoDS_ListOfShape::Iterator aCandidate(aMatches); aCandidate.More(); aCandidate.Next()) { - bool aValidCadidate = true; - for(int aLevel = aMinLevel + 1; true; aLevel++) { - bool aFooundHigherLevel = false; - TopoDS_ListOfShape aLevelNBs; - for(aNBIter = theNB.cbegin(); aNBIter != theNB.cend(); aNBIter++) { - if (aNBIter->second == aLevel) - aLevelNBs.Append(aNBIter->first); - else if (aNBIter->second >= aLevel) - aFooundHigherLevel = true; - } - if (!aFooundHigherLevel && aLevelNBs.IsEmpty()) { // iterated all, so, good candidate - if (aGoodCandidate.IsNull()) { - aGoodCandidate = aCandidate.Value(); - } else { // another good candidate - if (theGeometrical && sameGeometry(aGoodCandidate, aCandidate.Value())) { - if (!aGoodCandidates.Add(aCandidate.Value())) - break; - static TopoDS_Builder aBuilder; - if (aResultCompound.IsNull()) { - aBuilder.MakeCompound(aResultCompound); - aBuilder.Add(aResultCompound, aGoodCandidate); - } - aBuilder.Add(aResultCompound, aCandidate.Value()); - } else - return TopoDS_Shape(); - } - } - if (!aLevelNBs.IsEmpty()) { - TopTools_MapOfShape aNBsOfCandidate; - findNeighbors(theContext, aCandidate.Value(), aLevel, aNBsOfCandidate); - // check all stored neighbors are in the map of real neighbors - for(TopoDS_ListOfShape::Iterator aLevIter(aLevelNBs); aLevIter.More(); aLevIter.Next()) { - if (!aNBsOfCandidate.Contains(aLevIter.Value())) { - aValidCadidate = false; - break; - } - } - } - if (!aValidCadidate) // candidate is not valid, break the checking - break; - } - } - if (!aResultCompound.IsNull()) - return aResultCompound; - return aGoodCandidate; + if (myAlgo) + delete myAlgo; } bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue, - const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections) + const bool theGeometricalNaming) { if (theValue.IsNull() || theContext.IsNull()) return false; - myGeometricalNaming = theGeometricalNaming; - // check the value shape can be named as it is, or it is needed to construct it from the - // higher level shapes (like a box vertex by faces that form this vertex) - bool aIsFound = TNaming_Tool::HasLabel(myLab, theValue); - if (aIsFound) { // additional check for selection and delete evolution only: also could not use - aIsFound = false; - for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next()) - { - Handle(TNaming_NamedShape) aNS; - if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED || - aNS->Evolution() == TNaming_PRIMITIVE) { - aIsFound = true; - break; - } - } - } - } - // searching in the base document - if (!aIsFound && !myBaseDocumentLab.IsNull() && - TNaming_Tool::HasLabel(myBaseDocumentLab, theValue)) - { - TNaming_SameShapeIterator aShapes(theValue, myBaseDocumentLab); - for(; aShapes.More(); aShapes.Next()) - { - Handle(TNaming_NamedShape) aNS; - if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED || - aNS->Evolution() == TNaming_PRIMITIVE) { - aIsFound = true; - break; - } - } - } - } - if (!aIsFound) { - TopAbs_ShapeEnum aSelectionType = theValue.ShapeType(); - myShapeType = aSelectionType; - if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID || - aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE) - { // iterate all sub-shapes and select them on sublabels - for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) { - if (!selectBySubSelector(theContext, aSubIter.Value(), - false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed - return false; // if some selector is failed, everything is failed - } - } - myType = SELTYPE_CONTAINER; - return true; - } - - // try to find the shape of the higher level type in the context shape - bool aFacesTried = false; // for identification of vertices, faces are tried, then edges - TopoDS_ListOfShape aLastCommon; // to store the commons not good, but may be used for weak - TopoDS_ListOfShape aLastIntersectors; - while(theUseIntersections && (aSelectionType != TopAbs_FACE || !aFacesTried)) { - if (aSelectionType == TopAbs_FACE) { - if (theValue.ShapeType() != TopAbs_VERTEX) - break; - aFacesTried = true; - aSelectionType = TopAbs_EDGE; - } else - aSelectionType = TopAbs_FACE; - TopTools_MapOfShape anIntersectors; // shapes of aSelectionType that contain theValue - TopoDS_ListOfShape anIntList; // same as anIntersectors - for(TopExp_Explorer aSelExp(theContext, aSelectionType); aSelExp.More(); aSelExp.Next()) { - if (aSelectionType == TopAbs_EDGE && - BRep_Tool::Degenerated(TopoDS::Edge(aSelExp.Current()))) - continue; - TopExp_Explorer aSubExp(aSelExp.Current(), theValue.ShapeType()); - for(; aSubExp.More(); aSubExp.Next()) { - if (aSubExp.Current().IsSame(theValue)) { - if (anIntersectors.Add(aSelExp.Current())) - anIntList.Append(aSelExp.Current()); - break; - } - } - } - // check that solution is only one - TopoDS_ListOfShape aCommon; - commonShapes(anIntList, theValue.ShapeType(), aCommon); - if (aCommon.Extent() == 1 && aCommon.First().IsSame(theValue)) { - // name the intersectors - mySubSelList.clear(); - TopoDS_ListOfShape::Iterator anInt(anIntList); - for (; anInt.More(); anInt.Next()) { - if (!selectBySubSelector(theContext, anInt.Value(), - theGeometricalNaming, theUseNeighbors, false)) { - break; // if some selector is failed, stop and search another solution - } - } - if (!anInt.More()) { // all intersectors were correctly named - myType = SELTYPE_INTERSECT; - return true; - } - } else if (aCommon.Extent() > 1 && aLastCommon.IsEmpty()) { - aLastCommon = aCommon; - aLastIntersectors = anIntList; - } - } - - if (!theUseNeighbors) - return false; - - // searching by neighbors - std::list > aNBs; /// neighbor sub-shape -> level of neighborhood - for(int aLevel = 1; true; aLevel++) { - TopTools_MapOfShape aNewNB; - findNeighbors(theContext, theValue, aLevel, aNewNB); - if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration - break; - } - // iterate by the order in theContext to keep same naming names - TopExp_Explorer anOrder(theContext, theValue.ShapeType()); - for (; anOrder.More(); anOrder.Next()) { - if (aNewNB.Contains(anOrder.Current())) { - TopoDS_Shape aNewNBShape = anOrder.Current(); - // check which can be named correctly, without "by neighbors" type - Selector_Selector aSelector(myLab.FindChild(1)); - aSelector.setBaseDocument(myBaseDocumentLab); - if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false, false)) { - // add to list of good NBs - aNBs.push_back(std::pair(aNewNBShape, aLevel)); - } - } - } - TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming); - if (!aResult.IsNull() && aResult.IsSame(theValue)) { - std::list >::iterator aNBIter = aNBs.begin(); - for(; aNBIter != aNBs.end(); aNBIter++) { - if (!selectBySubSelector(theContext, aNBIter->first, - theGeometricalNaming, false, false)) { - return false; // something is wrong because before this selection was ok - } - myNBLevel.push_back(aNBIter->second); - - } - myType = SELTYPE_FILTER_BY_NEIGHBOR; - return true; - } - } - - if (aLastCommon.Extent() > 1) { - if (myAlwaysGeometricalNaming) { - TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon); - TopoDS_Shape aFirst = aCommonIter.Value(); - for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { - if (!sameGeometry(aFirst, aCommonIter.Value())) - break; - } - if (!aCommonIter.More()) { // all geometry is same, result is a compound - myType = SELTYPE_INTERSECT; - return true; - } - } - // weak naming to distinguish commons coming from intersection - Selector_NExplode aNexp(aLastCommon); - myWeakIndex = aNexp.index(theValue); - if (myWeakIndex != -1) { - // name the intersectors - mySubSelList.clear(); - TopoDS_ListOfShape::Iterator anInt(aLastIntersectors); - for (; anInt.More(); anInt.Next()) { - if (!selectBySubSelector(theContext, anInt.Value(), - theGeometricalNaming, theUseNeighbors, theUseIntersections)) { - break; // if some selector is failed, stop and search another solution - } - } - if (!anInt.More()) { // all intersectors were correctly named - myType = SELTYPE_INTERSECT; - return true; - } - } - } - - // pure weak naming: there is no sense to use pure weak naming for neighbors selection - if (theUseNeighbors) { - myType = SELTYPE_WEAK_NAMING; - Selector_NExplode aNexp(theContext, theValue.ShapeType()); - myWeakIndex = aNexp.index(theValue); - if (myWeakIndex != -1) { - myShapeType = theValue.ShapeType(); - // searching for context shape label to store in myFinal - myFinal.Nullify(); - if (TNaming_Tool::HasLabel(myLab, theContext)) { - for(TNaming_SameShapeIterator aShapes(theContext, myLab); aShapes.More(); aShapes.Next()) - { - Handle(TNaming_NamedShape) aNS; - if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - TNaming_Evolution anEvolution = aNS->Evolution(); - if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED || - anEvolution == TNaming_MODIFY) { - // check this is a new shape - for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) { - if (aNSIter.NewShape().IsSame(theContext)) { - myFinal = aNS->Label(); - break; - } - } - } - } - } - } - return true; // could be final empty (in case it is called recursively) or not - } - } - - return false; - } - // searching for the base shapes of the value - Handle(TNaming_NamedShape) aPrimitiveNS; - NCollection_List aModifList; - for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) { - TDF_Label aLab = aUseExternal == 0 ? myLab : myBaseDocumentLab; - if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue)) - continue; - for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next()) - { - Handle(TNaming_NamedShape) aNS; - if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - TNaming_Evolution anEvolution = aNS->Evolution(); - if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE - aPrimitiveNS = aNS; - break; - } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { - // check this is a new shape - TNaming_Iterator aNSIter(aNS); - for(; aNSIter.More(); aNSIter.Next()) - if (aNSIter.NewShape().IsSame(theValue)) - break; - if (aNSIter.More()) // new was found - aModifList.Append(aNS); - } - } - } - } - if (!aPrimitiveNS.IsNull()) { - myType = SELTYPE_PRIMITIVE; - myFinal = aPrimitiveNS->Label(); - return true; - } - - if (aModifList.Extent() > 1) { // searching for the best modification result: by context - Handle(TNaming_NamedShape) aCandidate; - NCollection_List::Iterator aModIter(aModifList); - for(; !aModifList.IsEmpty() && aModIter.More(); aModIter.Next()) { - aCandidate = aModIter.Value(); - TDF_Label aFatherLab = aCandidate->Label().Father(); - Handle(TNaming_NamedShape) aFatherNS; - if (aFatherLab.FindAttribute(TNaming_NamedShape::GetID(), aFatherNS)) { - for(TNaming_Iterator anIter(aFatherNS); anIter.More(); anIter.Next()) { - if (theContext.IsSame(anIter.NewShape())) { // found the best modification - aModifList.Clear(); - break; - } - } - } - } - // take the best candidate, or the last in the iteration - aModifList.Clear(); - aModifList.Append(aCandidate); - } - - if (!aModifList.IsEmpty()) { - // searching for all the base shapes of this modification - findBases(myLab, aModifList.First(), theValue, true, myBaseDocumentLab, myBases); - if (!myBases.IsEmpty()) { - myFinal = aModifList.First()->Label(); - TopoDS_ListOfShape aCommon; - findModificationResult(aCommon); - // trying to search by neighbors - if (aCommon.Extent() > 1) { // more complicated selection - if (myAlwaysGeometricalNaming) { - TopoDS_ListOfShape::Iterator aCommonIter(aCommon); - TopoDS_Shape aFirst = aCommonIter.Value(); - for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { - if (!sameGeometry(aFirst, aCommonIter.Value())) - break; - } - if (!aCommonIter.More()) { // all geometry is same, result is a compound - myType = SELTYPE_MODIFICATION; - return true; - } - } - if (!theUseNeighbors) - return false; - - // searching by neighbors - std::list > aNBs;//neighbor sub-shape -> level of neighborhood - for(int aLevel = 1; true; aLevel++) { - TopTools_MapOfShape aNewNB; - findNeighbors(theContext, theValue, aLevel, aNewNB); - if (aNewNB.Extent() == 0) { // there are no neighbors of the given level, stop iteration - break; - } - // iterate by the order in theContext to keep same naming names - TopExp_Explorer anOrder(theContext, theValue.ShapeType()); - for (; anOrder.More(); anOrder.Next()) { - if (aNewNB.Contains(anOrder.Current())) { - TopoDS_Shape aNewNBShape = anOrder.Current(); - // check which can be named correctly, without "by neighbors" type - Selector_Selector aSelector(myLab.FindChild(1)); - if (!myBaseDocumentLab.IsNull()) - aSelector.setBaseDocument(myBaseDocumentLab); - if (aSelector.select(theContext, aNewNBShape, theGeometricalNaming, false)) { - // add to list of good NBs - aNBs.push_back(std::pair(aNewNBShape, aLevel)); - } - } - } - TopoDS_Shape aResult = findNeighbor(theContext, aNBs, theGeometricalNaming); - if (!aResult.IsNull() && aResult.IsSame(theValue)) { - std::list >::iterator aNBIter = aNBs.begin(); - for(; aNBIter != aNBs.end(); aNBIter++) { - if (!selectBySubSelector(theContext, aNBIter->first, - theGeometricalNaming, theUseNeighbors, theUseIntersections)) { - return false; // something is wrong because before this selection was ok - } - myNBLevel.push_back(aNBIter->second); - - } - myType = SELTYPE_FILTER_BY_NEIGHBOR; - return true; - } - } - // filter by neighbors did not help - if (aCommon.Extent() > 1) { - if (myAlwaysGeometricalNaming) { - TopoDS_ListOfShape::Iterator aCommonIter(aCommon); - TopoDS_Shape aFirst = aCommonIter.Value(); - for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { - if (!sameGeometry(aFirst, aCommonIter.Value())) - break; - } - if (!aCommonIter.More()) { // all geometry is same, result is a compound - myType = SELTYPE_FILTER_BY_NEIGHBOR; - return true; - } - } - // weak naming between the common results - Selector_NExplode aNexp(aCommon); - myWeakIndex = aNexp.index(theValue); - if (myWeakIndex == -1) - return false; - } - } - } - myType = SELTYPE_MODIFICATION; - if (myBases.IsEmpty()) { // selection based on the external shape, weak name by finals compound - TopoDS_ListOfShape aCommon; - myFinal = aModifList.First()->Label(); - Handle(TNaming_NamedShape) aNS; - if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) { - const TopoDS_Shape& aNewShape = aFinalIter.NewShape(); - if (!aNewShape.IsNull()) - aCommon.Append(aNewShape); - } - } - Selector_NExplode aNexp(aCommon); - myWeakIndex = aNexp.index(theValue); - if (myWeakIndex == -1) - return false; - } - return true; - } + myAlgo = Selector_Algo::select(theContext, theValue, myLab, myBaseDocumentLab, + theGeometricalNaming, true, true); - // not found a good result - 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) - TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING); - switch(myType) { - case SELTYPE_CONTAINER: - case SELTYPE_INTERSECT: { - TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType); - // store also all sub-selectors - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++) { - aSubSel->store(); - } - if (myWeakIndex != -1) { - TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); - } - break; - } - case SELTYPE_PRIMITIVE: { - storeBaseArray(myLab, anEmptyRefList, myFinal); - break; - } - case SELTYPE_MODIFICATION: { - storeBaseArray(myLab, myBases, myFinal); - if (myWeakIndex != -1) { - TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); - } - break; - } - case SELTYPE_FILTER_BY_NEIGHBOR: { - TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType); - // store numbers of levels corresponded to the neighbors in sub-selectors - Handle(TDataStd_IntegerArray) anArray = - TDataStd_IntegerArray::Set(myLab, kLEVELS_ARRAY, 0, int(myNBLevel.size()) - 1); - std::list::iterator aLevel = myNBLevel.begin(); - for(int anIndex = 0; aLevel != myNBLevel.end(); aLevel++, anIndex++) { - anArray->SetValue(anIndex, *aLevel); - } - // store all sub-selectors - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++) { - aSubSel->store(); - } - break; - } - case SELTYPE_WEAK_NAMING: { - TDataStd_Integer::Set(myLab, kWEAK_INDEX, myWeakIndex); - TDataStd_Integer::Set(myLab, kSHAPE_TYPE, (int)myShapeType); - if (!myFinal.IsNull()) { - storeBaseArray(myLab, anEmptyRefList, myFinal); - } - break; - } - default: { // unknown case - break; - } - } + return myAlgo != NULL; } -/// 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) +bool Selector_Selector::store(const TopoDS_Shape theContext) { - 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; + myAlgo->store(); + return myAlgo->solve(theContext); // to update the selection shape on the label } - -bool Selector_Selector::restore() +bool Selector_Selector::restore(const TopoDS_Shape theContext) { - Handle(TDataStd_Integer) aTypeAttr; - if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr)) - return false; - myGeometricalNaming = myLab.IsAttribute(kGEOMETRICAL_NAMING); - myType = Selector_Type(aTypeAttr->Get()); - switch(myType) { - case SELTYPE_CONTAINER: - case SELTYPE_INTERSECT: { - Handle(TDataStd_Integer) aShapeTypeAttr; - if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr)) - return false; - myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); - // restore sub-selectors - bool aSubResult = true; - mySubSelList.clear(); - for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) { - mySubSelList.push_back(Selector_Selector(aSub.Value()->Label())); - mySubSelList.back().setBaseDocument(myBaseDocumentLab); - if (!mySubSelList.back().restore()) - aSubResult = false; - } - Handle(TDataStd_Integer) aWeakInt; - if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) { - myWeakIndex = aWeakInt->Get(); - } - return aSubResult; - } - case SELTYPE_PRIMITIVE: { - return restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal); - } - case SELTYPE_MODIFICATION: { - if (restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) { - Handle(TDataStd_Integer) aWeakInt; - if (myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) { - myWeakIndex = aWeakInt->Get(); - } - return true; - } - return false; - } - case SELTYPE_FILTER_BY_NEIGHBOR: { - Handle(TDataStd_Integer) aShapeTypeAttr; - if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr)) - return false; - myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); - // restore sub-selectors - bool aSubResult = true; - mySubSelList.clear(); - for(TDF_ChildIDIterator aSub(myLab, kSEL_TYPE, false); aSub.More(); aSub.Next()) { - mySubSelList.push_back(Selector_Selector(aSub.Value()->Label())); - mySubSelList.back().setBaseDocument(myBaseDocumentLab); - if (!mySubSelList.back().restore()) - aSubResult = false; - } - // restore levels indices - Handle(TDataStd_IntegerArray) anArray; - if (!myLab.FindAttribute(kLEVELS_ARRAY, anArray)) - return false; - for(int anIndex = 0; anIndex <= anArray->Upper(); anIndex++) { - myNBLevel.push_back(anArray->Value(anIndex)); - } - return true; - } - case SELTYPE_WEAK_NAMING: { - Handle(TDataStd_Integer) aWeakInt; - if (!myLab.FindAttribute(kWEAK_INDEX, aWeakInt)) - return false; - myWeakIndex = aWeakInt->Get(); - Handle(TDataStd_Integer) aShapeTypeAttr; - if (!myLab.FindAttribute(kSHAPE_TYPE, aShapeTypeAttr)) - return false; - myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); - if (!restoreBaseArray(myLab, myBaseDocumentLab, myBases, myFinal)) - return false; + if (myAlgo->restoreByLab(myLab)) { + myAlgo->solve(theContext); // to update the selection shape on the label return true; } - default: { // unknown case - } - } return false; } -/// Returns in theResults all shapes with history started in theBase and ended in theFinal -static void findFinals(const TDF_Label& anAccess, const TopoDS_Shape& theBase, - const TDF_Label& theFinal, - const TDF_Label& theAdditionalDoc, TopTools_MapOfShape& theResults) -{ - if (TNaming_Tool::HasLabel(anAccess, theBase)) { - for(TNaming_NewShapeIterator aBaseIter(theBase, anAccess); aBaseIter.More(); aBaseIter.Next()) - { - TNaming_Evolution anEvolution = aBaseIter.NamedShape()->Evolution(); - if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { - if (aBaseIter.NamedShape()->Label().IsEqual(theFinal)) { - theResults.Add(aBaseIter.Shape()); - } else { - findFinals(anAccess, aBaseIter.Shape(), theFinal, theAdditionalDoc, theResults); - } - } - } - } - if (!theAdditionalDoc.IsNull()) { // search additionally by the additional access label - static TDF_Label anEmpty; - findFinals(theAdditionalDoc, theBase, theFinal, anEmpty, theResults); - } -} - -void Selector_Selector::findModificationResult(TopoDS_ListOfShape& theCommon) { - for(TDF_LabelList::Iterator aBase(myBases); aBase.More(); aBase.Next()) { - TDF_Label anAdditionalDoc; // this document if base is started in extra document - if (aBase.Value().Root() != myLab.Root()) { - anAdditionalDoc = myLab; - } - TopTools_MapOfShape aFinals; - for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) { - findFinals(aBase.Value(), aBaseShape.NewShape(), myFinal, anAdditionalDoc, aFinals); - } - if (!aFinals.IsEmpty()) { - if (theCommon.IsEmpty()) { // just copy all to common - for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) { - theCommon.Append(aFinal.Key()); - } - } else { // keep only shapes presented in both lists - for(TopoDS_ListOfShape::Iterator aCommon(theCommon); aCommon.More(); ) { - if (aFinals.Contains(aCommon.Value())) { - aCommon.Next(); - } else { // common is not found, remove it - theCommon.Remove(aCommon); - } - } - } - } - } -} - -bool Selector_Selector::solve(const TopoDS_Shape& theContext) -{ - TopoDS_Shape aResult; // null if invalid - switch(myType) { - case SELTYPE_CONTAINER: { - TopoDS_Builder aBuilder; - switch(myShapeType) { - case TopAbs_COMPOUND: { - TopoDS_Compound aComp; - aBuilder.MakeCompound(aComp); - aResult = aComp; - break; - } - case TopAbs_COMPSOLID: { - TopoDS_CompSolid aComp; - aBuilder.MakeCompSolid(aComp); - aResult = aComp; - break; - } - case TopAbs_SHELL: { - TopoDS_Shell aShell; - aBuilder.MakeShell(aShell); - aResult = aShell; - break; - } - case TopAbs_WIRE: { - TopoDS_Wire aWire; - aBuilder.MakeWire(aWire); - aResult = aWire; - break; - } - } - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++) { - if (!aSubSel->solve(theContext)) { - return false; - } - aBuilder.Add(aResult, aSubSel->value()); - } - break; - } - case SELTYPE_INTERSECT: { - TopoDS_ListOfShape aSubSelectorShapes; - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++) { - if (!aSubSel->solve(theContext)) { - return false; - } - aSubSelectorShapes.Append(aSubSel->value()); - } - TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result) - commonShapes(aSubSelectorShapes, myShapeType, aCommon); - if (aCommon.Extent() != 1) { - if (myWeakIndex != -1) { - Selector_NExplode aNexp(aCommon); - aResult = aNexp.shape(myWeakIndex); - } else if (myGeometricalNaming && aCommon.Extent() > 1) { - // check results are on the same geometry, create compound - TopoDS_ListOfShape::Iterator aCommonIter(aCommon); - TopoDS_Shape aFirst = aCommonIter.Value(); - for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { - if (!sameGeometry(aFirst, aCommonIter.Value())) - break; - } - if (!aCommonIter.More()) { // all geometry is same, create a result compound - TopoDS_Builder aBuilder; - TopoDS_Compound aCompound; - aBuilder.MakeCompound(aCompound); - for(aCommonIter.Initialize(aCommon); aCommonIter.More(); aCommonIter.Next()) { - aBuilder.Add(aCompound, aCommonIter.Value()); - } - aResult = aCompound; - } - } else { - return false; - } - } else { - aResult = aCommon.First(); - } - break; - } - case SELTYPE_PRIMITIVE: { - Handle(TNaming_NamedShape) aNS; - if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aResult = aNS->Get(); - } - break; - } - case SELTYPE_MODIFICATION: { - if (myBases.IsEmpty() && myWeakIndex > 0) { // weak name by the final shapes index - TopoDS_ListOfShape aCommon; - Handle(TNaming_NamedShape) aNS; - if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - for(TNaming_Iterator aFinalIter(aNS); aFinalIter.More(); aFinalIter.Next()) { - const TopoDS_Shape& aNewShape = aFinalIter.NewShape(); - if (!aNewShape.IsNull()) - aCommon.Append(aNewShape); - } - } - Selector_NExplode aNexp(aCommon); - aResult = aNexp.shape(myWeakIndex); - } else { // standard case - TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases - findModificationResult(aFinalsCommon); - if (aFinalsCommon.Extent() == 1) { // result is valid: found only one shape - aResult = aFinalsCommon.First(); - } else if (aFinalsCommon.Extent() > 1 && myWeakIndex > 0) { - Selector_NExplode aNExp(aFinalsCommon); - aResult = aNExp.shape(myWeakIndex); - } else if (aFinalsCommon.Extent() > 1 && myGeometricalNaming) {// if same geometry - compound - TopoDS_ListOfShape::Iterator aCommonIter(aFinalsCommon); - TopoDS_Shape aFirst = aCommonIter.Value(); - for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) { - if (!sameGeometry(aFirst, aCommonIter.Value())) - break; - } - if (!aCommonIter.More()) { // all geometry is same, create a result compound - TopoDS_Builder aBuilder; - TopoDS_Compound aCompound; - aBuilder.MakeCompound(aCompound); - for(aCommonIter.Initialize(aFinalsCommon); aCommonIter.More(); aCommonIter.Next()) { - aBuilder.Add(aCompound, aCommonIter.Value()); - } - aResult = aCompound; - } - - } - } - break; - } - case SELTYPE_FILTER_BY_NEIGHBOR: { - std::list > aNBs; /// neighbor sub-shape -> level of neighborhood - std::list::iterator aLevel = myNBLevel.begin(); - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) { - if (!aSubSel->solve(theContext)) { - return false; - } - aNBs.push_back(std::pair(aSubSel->value(), *aLevel)); - } - aResult = findNeighbor(theContext, aNBs, myGeometricalNaming); - break; - } - case SELTYPE_WEAK_NAMING: { - TopoDS_Shape aContext; - if (myFinal.IsNull()) { - aContext = theContext; - } else { - Handle(TNaming_NamedShape) aNS; - if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aContext = aNS->Get(); - } - } - if (!aContext.IsNull()) { - Selector_NExplode aNexp(aContext, myShapeType); - aResult = aNexp.shape(myWeakIndex); - } - } - default: { // unknown case - } - } - - TNaming_Builder aBuilder(myLab); - if (!aResult.IsNull()) { - aBuilder.Select(aResult, aResult); - return true; - } - return false; // builder just erases the named shape in case of error -} - TopoDS_Shape Selector_Selector::value() { Handle(TNaming_NamedShape) aNS; @@ -1137,305 +75,63 @@ TopoDS_Shape Selector_Selector::value() } std::string Selector_Selector::name(Selector_NameGenerator* theNameGenerator) { - switch(myType) { - case SELTYPE_CONTAINER: - case SELTYPE_INTERSECT: { - std::string aResult; - // add names of sub-components one by one in "[]" +optionally [weak_name_1] - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++) { - aResult += '['; - aResult += aSubSel->name(theNameGenerator); - aResult += ']'; - TopoDS_Shape aSubVal = aSubSel->value(); - if (!aSubVal.IsNull()) { - TopAbs_ShapeEnum aSubType = aSubVal.ShapeType(); - if (aSubType != TopAbs_FACE) { // in case the sub shape type must be stored - switch(aSubType) { - case TopAbs_COMPOUND: aResult += "c"; break; - case TopAbs_COMPSOLID: aResult += "o"; break; - case TopAbs_SOLID: aResult += "s"; break; - case TopAbs_SHELL: aResult += "h"; break; - case TopAbs_WIRE: aResult += "w"; break; - case TopAbs_EDGE: aResult += "e"; break; - case TopAbs_VERTEX: aResult += "v"; break; - default: - ; - } - } - } - } - if (myWeakIndex != -1) { - std::ostringstream aWeakStr; - aWeakStr<<"["<contextName(myFinal) + "/" + - std::string(TCollection_AsciiString(aName->Get()).ToCString()); - } - case SELTYPE_MODIFICATION: { - // final&base1&base2 +optionally: [weak_name_1] - std::string aResult; - Handle(TDataStd_Name) aName; - if (!myFinal.FindAttribute(TDataStd_Name::GetID(), aName)) - return ""; - aResult += theNameGenerator->contextName(myFinal) + "/" + - std::string(TCollection_AsciiString(aName->Get()).ToCString()); - for(TDF_LabelList::iterator aBase = myBases.begin(); aBase != myBases.end(); aBase++) { - if (!aBase->FindAttribute(TDataStd_Name::GetID(), aName)) - return ""; - aResult += "&"; - aResult += theNameGenerator->contextName(*aBase) + "/" + - std::string(TCollection_AsciiString(aName->Get()).ToCString()); - } - if (myWeakIndex != -1) { - std::ostringstream aWeakStr; - aWeakStr<<"&"<::iterator aLevel = myNBLevel.begin(); - std::list::iterator aSubSel = mySubSelList.begin(); - for(; aSubSel != mySubSelList.end(); aSubSel++, aLevel++) { - aResult += "(" + aSubSel->name(theNameGenerator) + ")"; - if (*aLevel > 1) { - std::ostringstream aLevelStr; - aLevelStr<<*aLevel; - aResult += aLevelStr.str(); - } - } - return aResult; - } - case SELTYPE_WEAK_NAMING: { - // _weak_naming_1_Context - std::ostringstream aWeakStr; - aWeakStr<contextName(myFinal); - return aResult; - } - default: { // unknown case - } - }; - return ""; + return myAlgo->name(theNameGenerator); } TDF_Label Selector_Selector::restoreByName( std::string theName, const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming) { - myGeometricalNaming = theGeometricalNaming; - if (theName[0] == '[') { // intersection or container - switch(theShapeType) { - case TopAbs_COMPOUND: - case TopAbs_COMPSOLID: - case TopAbs_SHELL: - case TopAbs_WIRE: - myType = SELTYPE_CONTAINER; - break; - case TopAbs_VERTEX: - case TopAbs_EDGE: - case TopAbs_FACE: - myType = SELTYPE_INTERSECT; - break; - default: - return TDF_Label(); // unknown case - } - myShapeType = theShapeType; - TDF_Label aContext; - for(size_t aStart = 0; aStart != std::string::npos; - aStart = theName.find('[', aStart + 1)) { - size_t anEndPos = theName.find(']', aStart + 1); - if (anEndPos != std::string::npos) { - std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1); - if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier - std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size()); - myWeakIndex = atoi(aWeakIndex.c_str()); - continue; - } - TopAbs_ShapeEnum aSubShapeType = TopAbs_FACE; - if (anEndPos != std::string::npos && anEndPos + 1 < theName.size()) { - char aShapeChar = theName[anEndPos + 1]; - if (theName[anEndPos + 1] != '[') { - switch(aShapeChar) { - case 'c': aSubShapeType = TopAbs_COMPOUND; break; - case 'o': aSubShapeType = TopAbs_COMPSOLID; break; - case 's': aSubShapeType = TopAbs_SOLID; break; - case 'h': aSubShapeType = TopAbs_SHELL; break; - case 'w': aSubShapeType = TopAbs_WIRE; break; - case 'e': aSubShapeType = TopAbs_EDGE; break; - case 'v': aSubShapeType = TopAbs_VERTEX; break; - default:; - } - } - } - mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1))); - mySubSelList.back().setBaseDocument(myBaseDocumentLab); - TDF_Label aSubContext = mySubSelList.back().restoreByName( - aSubStr, aSubShapeType, theNameGenerator, theGeometricalNaming); - if (aSubContext.IsNull()) - return aSubContext; // invalid sub-selection parsing - if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { - if (!theNameGenerator->isLater(aContext, aSubContext)) - aContext = aSubContext; - } else { - aContext = aSubContext; - } - } else - return TDF_Label(); // invalid parentheses - } - return aContext; - } else if (theName[0] == '(') { // filter by neighbors - myType = SELTYPE_FILTER_BY_NEIGHBOR; - TDF_Label aContext; - for(size_t aStart = 0; aStart != std::string::npos; - aStart = theName.find('(', aStart + 1)) { - size_t anEndPos = theName.find(')', aStart + 1); - if (anEndPos != std::string::npos) { - std::string aSubStr = theName.substr(aStart + 1, anEndPos - aStart - 1); - mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1))); - mySubSelList.back().setBaseDocument(myBaseDocumentLab); - TDF_Label aSubContext = mySubSelList.back().restoreByName( - aSubStr, theShapeType, theNameGenerator, theGeometricalNaming); - if (aSubContext.IsNull()) - return aSubContext; // invalid sub-selection parsing - if (!aContext.IsNull() && !aContext.IsEqual(aSubContext)) { - if (!theNameGenerator->isLater(aContext, aSubContext)) - aContext = aSubContext; - } else { - aContext = aSubContext; - } - if (!aContext.IsNull()) // for filters by neighbor the latest context shape is vital - aContext = theNameGenerator->newestContext(aContext); - - // searching for the level index - std::string aLevel; - for(anEndPos++; anEndPos != std::string::npos && - theName[anEndPos] != '(' && theName[anEndPos] != 0; - anEndPos++) { - aLevel += theName[anEndPos]; - } - if (aLevel.empty()) - myNBLevel.push_back(1); // by default it is 1 - else { - int aNum = atoi(aLevel.c_str()); - if (aNum > 0) - myNBLevel.push_back(aNum); - else - return TDF_Label(); // invalid number - } - } else - return TDF_Label(); // invalid parentheses - } - return aContext; - } if (theName.find(kPUREWEAK_NAME_IDENTIFIER) == 0) { // weak naming identifier - myType = SELTYPE_WEAK_NAMING; - std::string aWeakIndex = theName.substr(kPUREWEAK_NAME_IDENTIFIER.size()); - std::size_t aContextPosition = aWeakIndex.find("_"); - myWeakIndex = atoi(aWeakIndex.c_str()); - myShapeType = theShapeType; - TDF_Label aContext; - if (aContextPosition != std::string::npos) { // context is also defined - std::string aContextName = aWeakIndex.substr(aContextPosition + 1); - theNameGenerator->restoreContext(aContextName, aContext, myFinal); - } - return aContext; - } else if (theName.find('&') == std::string::npos) { // without '&' it can be only primitive - myType = SELTYPE_PRIMITIVE; - TDF_Label aContext; - if (theNameGenerator->restoreContext(theName, aContext, myFinal)) { - if (!myFinal.IsNull()) - return aContext; - } - } else { // modification - myType = SELTYPE_MODIFICATION; - TDF_Label aContext; - for(size_t anEnd, aStart = 0; aStart != std::string::npos; aStart = anEnd) { - if (aStart != 0) - aStart++; - anEnd = theName.find('&', aStart); - std::string aSubStr = - theName.substr(aStart, anEnd == std::string::npos ? anEnd : anEnd - aStart); - if (aSubStr.find(kWEAK_NAME_IDENTIFIER) == 0) { // weak name identifier - std::string aWeakIndex = aSubStr.substr(kWEAK_NAME_IDENTIFIER.size()); - myWeakIndex = atoi(aWeakIndex.c_str()); - continue; - } - TDF_Label aSubContext, aValue; - if (!theNameGenerator->restoreContext(aSubStr, aSubContext, aValue)) - return TDF_Label(); // can not restore - if(aSubContext.IsNull() || aValue.IsNull()) - return TDF_Label(); // can not restore - if (myFinal.IsNull()) { - myFinal = aValue; - aContext = aSubContext; - } else - myBases.Append(aValue); - } - return aContext; + TDF_Label aResult; + myAlgo = Selector_Algo::restoreByName( + myLab, myBaseDocumentLab, theName, theShapeType, theNameGenerator, aResult); + if (myAlgo) { + return aResult; } return TDF_Label(); } -bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext, - const TopoDS_Shape theValue, const bool theGeometricalNaming, - const bool theUseNeighbors, const bool theUseIntersections) -{ - mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1))); - if (!myBaseDocumentLab.IsNull()) - mySubSelList.back().setBaseDocument(myBaseDocumentLab); - if (!mySubSelList.back().select(theContext, theValue, - theGeometricalNaming, theUseNeighbors, theUseIntersections)) { - mySubSelList.clear(); // if one of the selector is failed, all become invalid - return false; - } - return true; -} - void Selector_Selector::combineGeometrical(const TopoDS_Shape theContext) { TopoDS_Shape aValue = value(); if (aValue.IsNull() || aValue.ShapeType() == TopAbs_COMPOUND) return; - myAlwaysGeometricalNaming = true; - mySubSelList.clear(); - myBases.Clear(); - myWeakIndex = -1; - if (select(theContext, aValue, true)) { - store(); - solve(theContext); - return; - } - // if can not select, select the compound in a custom way - TopTools_MapOfShape aMap; - TopoDS_ListOfShape aList; - for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) { - if (aMap.Add(anExp.Current())) { - if (sameGeometry(aValue, anExp.Current())) - aList.Append(anExp.Current()); - } - } - if (aList.Size() > 1) { - TopoDS_Builder aBuilder; - TopoDS_Compound aCompound; - aBuilder.MakeCompound(aCompound); - for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) { - aBuilder.Add(aCompound, aListIter.Value()); + + Selector_Algo* aNewAlgo = Selector_Algo::relesectWithAllGeometry(myAlgo, theContext); + if (aNewAlgo) { + aNewAlgo->store(); + aNewAlgo->solve(theContext); + delete myAlgo; + myAlgo = aNewAlgo; + } else { + // if can not select, select the compound in a custom way + TopTools_MapOfShape aMap; + TopoDS_ListOfShape aList; + for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) { + if (aMap.Add(anExp.Current())) { + if (myAlgo->sameGeometry(aValue, anExp.Current())) + aList.Append(anExp.Current()); + } } - if (select(theContext, aCompound, true)) { - store(); - solve(theContext); + if (aList.Size() > 1) { + TopoDS_Builder aBuilder; + TopoDS_Compound aCompound; + aBuilder.MakeCompound(aCompound); + for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) { + aBuilder.Add(aCompound, aListIter.Value()); + } + Selector_Algo* aNewAlgo = Selector_Algo::relesectWithAllGeometry(myAlgo, theContext); + if (aNewAlgo) { + aNewAlgo->store(); + aNewAlgo->solve(theContext); + delete myAlgo; + myAlgo = aNewAlgo; + } } } } + +bool Selector_Selector::solve(const TopoDS_Shape theContext) +{ + return myAlgo->solve(theContext); +} diff --git a/src/Selector/Selector_Selector.h b/src/Selector/Selector_Selector.h index 46f2db6e5..d3e5b8a3b 100644 --- a/src/Selector/Selector_Selector.h +++ b/src/Selector/Selector_Selector.h @@ -24,11 +24,10 @@ #include "Selector.h" #include -#include #include -#include class Selector_NameGenerator; +class Selector_Algo; /**\class Selector_Selector * \ingroup DataModel @@ -37,41 +36,16 @@ class Selector_NameGenerator; */ class Selector_Selector { - /// Type of a selector: on this type depends what is stored in this label and how to - /// restore it on update. - enum Selector_Type { - SELTYPE_CONTAINER, ///< just a container of sub-elements, keeps the shape type of container - SELTYPE_INTERSECT, ///< sub-shape is intersection of higher level objects - SELTYPE_PRIMITIVE, ///< sub-shape found as a primitive on some label - SELTYPE_MODIFICATION, ///< modification of base shapes to the final label - SELTYPE_FILTER_BY_NEIGHBOR, ///< identification by neighbor shapes in context - SELTYPE_WEAK_NAMING, ///< pure weak naming by weak index in context - }; - - Selector_Type myType; ///< Type of this selector. - TopAbs_ShapeEnum myShapeType; ///< type of this shape: in container, intersection or neighbors - std::list mySubSelList; ///< list of sub-selectors if needed - TDF_Label myFinal; ///< final label of the primitive or generation, where the value is - TDF_LabelList myBases; ///< initial labels that contain shapes that produce the modification - int myWeakIndex; ///< index of the shape among commons for the modification type (-1 - not set) - - std::list myNBLevel; ///< list of integers corresponding to mySubSelList neighborhood level - TDF_Label myLab; ///< main label where selector is performed - TDF_Label myBaseDocumentLab; ///< an access-label to the document that may contain initial shapes - - bool myGeometricalNaming; ///< flag that indicates that geometrical naming selection is enabled - bool myAlwaysGeometricalNaming; /// to enable geometrical naming from beginning, at select + Selector_Algo* myAlgo; ///< root algorithm of the selector public: /// Initializes selector on the label - SELECTOR_EXPORT Selector_Selector(TDF_Label theLab); - /// Returns label of this selector - SELECTOR_EXPORT TDF_Label label(); + SELECTOR_EXPORT Selector_Selector(TDF_Label theLab, TDF_Label theBaseDocLab = TDF_Label()); - /// Sets the base document access label. - SELECTOR_EXPORT void setBaseDocument(const TDF_Label theAccess); + /// Destructor + SELECTOR_EXPORT ~Selector_Selector(); /// Initializes the selector structure on the label. /// Stores the name data to restore after modification. @@ -81,15 +55,14 @@ public: /// \param theUseNeighbors enables searching algorithm by neighbors /// \param theUseIntersections enables searching algorithm by intersection of higher level shapes SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue, - const bool theGeometricalNaming = false, - const bool theUseNeighbors = true, const bool theUseIntersections = true); + const bool theGeometricalNaming = false); /// Stores the name to the label and sub-labels tree - SELECTOR_EXPORT void store(); + SELECTOR_EXPORT bool store(const TopoDS_Shape theContext); /// Restores the selected shape by the topological naming kept in the data structure /// Returns true if it can restore structure correctly - SELECTOR_EXPORT bool restore(); + SELECTOR_EXPORT bool restore(const TopoDS_Shape theContext); /// Restores the selected shape by the topological name string. /// Returns not empty label of the context. @@ -97,9 +70,6 @@ public: std::string theName, const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator, const bool theGeometricalNaming = false); - /// Updates the current shape by the stored topological name - SELECTOR_EXPORT bool solve(const TopoDS_Shape& theContext); - /// Returns the current sub-shape value (null if can not resolve) SELECTOR_EXPORT TopoDS_Shape value(); @@ -109,15 +79,8 @@ public: /// Makes the current local selection becomes all sub-shapes with same base geometry. SELECTOR_EXPORT void combineGeometrical(const TopoDS_Shape theContext); -private: - - /// Create and keep in the list the sub-selector that select the given value. - /// Returns true if selection is correct. - bool selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue, - const bool theGeometricalNaming = false, const bool theUseNeighbors = true, - const bool theUseIntersections = true); - /// Searches the final shapes presented in all results from bases basing on modification fields - void findModificationResult(TopoDS_ListOfShape& theCommon); + /// Stores the selected shape in he tree and returns true if shape found correctly + SELECTOR_EXPORT bool solve(const TopoDS_Shape theContext); }; #endif diff --git a/src/Selector/Selector_WeakName.cpp b/src/Selector/Selector_WeakName.cpp new file mode 100644 index 000000000..6ede1c385 --- /dev/null +++ b/src/Selector/Selector_WeakName.cpp @@ -0,0 +1,139 @@ +// 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 + +Selector_WeakName::Selector_WeakName() : Selector_Algo() +{ +} + +bool Selector_WeakName::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + myShapeType = theValue.ShapeType(); + Selector_NExplode aNexp(theContext, myShapeType); + myWeakIndex = aNexp.index(theValue); + if (myWeakIndex != -1) { + // searching for context shape label to store in myFinal + if (TNaming_Tool::HasLabel(label(), theContext)) { + for(TNaming_SameShapeIterator aShapes(theContext, label()); aShapes.More(); aShapes.Next()) + { + Handle(TNaming_NamedShape) aNS; + if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + TNaming_Evolution anEvolution = aNS->Evolution(); + if (anEvolution == TNaming_PRIMITIVE || anEvolution == TNaming_GENERATED || + anEvolution == TNaming_MODIFY) { + // check this is a new shape + for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) { + if (aNSIter.NewShape().IsSame(theContext)) { + myContext = aNS->Label(); + break; + } + } + } + } + } + } + return true; + } + return false; +} + +void Selector_WeakName::store() +{ + static const TDF_LabelList anEmptyRefList; + storeType(Selector_Algo::SELTYPE_WEAK_NAMING); + storeBaseArray(anEmptyRefList, myContext); + TDataStd_Integer::Set(label(), weakID(), myWeakIndex); + TDataStd_Integer::Set(label(), shapeTypeID(), (int)myShapeType); +} + +bool Selector_WeakName::restore() +{ + Handle(TDataStd_Integer) aWeakInt; + if (!label().FindAttribute(weakID(), aWeakInt)) + return false; + myWeakIndex = aWeakInt->Get(); + Handle(TDataStd_Integer) aShapeTypeAttr; + if (!label().FindAttribute(shapeTypeID(), aShapeTypeAttr)) + return false; + myShapeType = TopAbs_ShapeEnum(aShapeTypeAttr->Get()); + static TDF_LabelList anEmptyRefList; + return restoreBaseArray(anEmptyRefList, myContext); +} + +TDF_Label Selector_WeakName::restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) +{ + std::string aWeakIndex = theName.substr(pureWeakNameID().size()); + std::size_t aContextPosition = aWeakIndex.find("_"); + myWeakIndex = atoi(aWeakIndex.c_str()); + myShapeType = theShapeType; + TDF_Label aContext; + if (aContextPosition != std::string::npos) { // context is also defined + std::string aContextName = aWeakIndex.substr(aContextPosition + 1); + if (theNameGenerator->restoreContext(aContextName, aContext, myContext)) { + if (myContext.IsNull()) + aContext.Nullify(); + } + } + return aContext; +} + +bool Selector_WeakName::solve(const TopoDS_Shape& theContext) +{ + + TopoDS_Shape aContext; + if (myContext.IsNull()) { + aContext = theContext; + } else { + Handle(TNaming_NamedShape) aNS; + if (myContext.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + aContext = aNS->Get(); + } + } + if (!aContext.IsNull()) { + Selector_NExplode aNexp(aContext, myShapeType); + TopoDS_Shape aResult = aNexp.shape(myWeakIndex); + if (!aResult.IsNull()) { + Selector_Algo::store(aResult); + return true; + } + } + return false; +} + +std::string Selector_WeakName::name(Selector_NameGenerator* theNameGenerator) +{ + // _weak_naming_1_Context + std::ostringstream aWeakStr; + aWeakStr<contextName(myContext); + return aResult; +} diff --git a/src/Selector/Selector_WeakName.h b/src/Selector/Selector_WeakName.h new file mode 100644 index 000000000..7f1016a8b --- /dev/null +++ b/src/Selector/Selector_WeakName.h @@ -0,0 +1,64 @@ +// 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 +// + +#ifndef Selector_WeakName_H_ +#define Selector_WeakName_H_ + +#include "Selector_Algo.h" + +/**\class Selector_WeakName + * \ingroup DataModel + * \brief Kind of selection algorithm: if other algorithms fail, this stores the geometrical + * index of the selected shape. Pure weak naming approach. + */ +class Selector_WeakName: public Selector_Algo +{ + TopAbs_ShapeEnum myShapeType; ///< type of this shape + int myWeakIndex; ///< weak index in case modification produces several shapes + TDF_Label myContext; ///< context shape label +public: + /// Initializes the selection of this kind + SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + + /// Stores the name to the label and sub-labels tree + SELECTOR_EXPORT virtual void store() override; + + /// Restores the selected shape by the topological naming kept in the data structure + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT virtual bool restore() override; + + /// Restores the selected shape by the topological name string. + /// Returns not empty label of the context. + SELECTOR_EXPORT virtual TDF_Label restoreByName(std::string theName, + const TopAbs_ShapeEnum theShapeType, Selector_NameGenerator* theNameGenerator) override; + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT virtual bool solve(const TopoDS_Shape& theContext) override; + + /// Returns the naming name of the selection + SELECTOR_EXPORT virtual std::string name(Selector_NameGenerator* theNameGenerator) override; +private: + /// Initializes selector + Selector_WeakName(); + + friend class Selector_Algo; +}; + +#endif diff --git a/src/SketchPlugin/SketchPlugin_Point.cpp b/src/SketchPlugin/SketchPlugin_Point.cpp index 252ecf181..d2f727f71 100644 --- a/src/SketchPlugin/SketchPlugin_Point.cpp +++ b/src/SketchPlugin/SketchPlugin_Point.cpp @@ -67,7 +67,7 @@ bool SketchPlugin_Point::isFixed() { } void SketchPlugin_Point::attributeChanged(const std::string& theID) { - // the second condition for unability to move external point anywhere + // the second condition for inability to move external point anywhere if (theID == EXTERNAL_ID() || isFixed()) { std::shared_ptr aSelection = data()->selection(EXTERNAL_ID())->value(); if (!aSelection) { -- 2.39.2