From c9fbce596d0a90295431b958ed99ba83eee1f0ea Mon Sep 17 00:00:00 2001 From: mpv Date: Tue, 9 Oct 2018 11:51:59 +0300 Subject: [PATCH] Simple implementation of all kinds of names except FILTER --- src/Model/CMakeLists.txt | 2 + src/Model/Model_AttributeSelection.cpp | 39 ++-- src/Selector/Selector_Selector.cpp | 290 ++++++++++++++++++++++--- src/Selector/Selector_Selector.h | 26 ++- 4 files changed, 310 insertions(+), 47 deletions(-) diff --git a/src/Model/CMakeLists.txt b/src/Model/CMakeLists.txt index 33ec73c00..27a8c6eb5 100644 --- a/src/Model/CMakeLists.txt +++ b/src/Model/CMakeLists.txt @@ -99,6 +99,7 @@ SET(PROJECT_LIBRARIES ModelAPI Events Config + Selector GeomData GeomAPI GeomAlgoAPI @@ -109,6 +110,7 @@ SET(PROJECT_INCLUDES ../ModelAPI ../Events ../Config + ../Selector ../GeomData ../GeomDataAPI ../GeomAlgoAPI diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 7b1259db3..c5f959489 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -686,21 +687,30 @@ bool Model_AttributeSelection::update() GeomShapePtr aValue = aNExplode.shape(aWeakId->Get()); return setInvalidIfFalse(aSelLab, aValue.get() != NULL); } - // body: just a named shape, use selection mechanism from OCCT - TNaming_Selector aSelector(aSelLab); + // body: just a named shape, use topological selection mechanism + bool aResult = false; TopoDS_Shape anOldShape; - if (!aSelector.NamedShape().IsNull()) { - anOldShape = aSelector.NamedShape()->Get(); + Handle(TNaming_NamedShape) aNS; + if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + anOldShape = aNS->Get(); + + Selector_Selector aSelector(aSelLab); + if (!aSelector.restore()) { // it is stored in old OCCT format, use TNaming_Selector + TNaming_Selector aSelector(aSelLab); + if (!aSelector.NamedShape().IsNull()) { + anOldShape = aSelector.NamedShape()->Get(); + } + aResult = aSelector.Solve(scope()) == Standard_True; + } else { + aResult = aSelector.solve(); } - bool aResult = aSelector.Solve(scope()) == Standard_True; - // must be before sending of updated attribute (1556) aResult = setInvalidIfFalse(aSelLab, aResult); + TopoDS_Shape aNewShape; - if (!aSelector.NamedShape().IsNull()) { - aNewShape = aSelector.NamedShape()->Get(); - } - if (anOldShape.IsNull() || aNewShape.IsNull() || - !anOldShape.IsEqual(aSelector.NamedShape()->Get())) { + if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + aNewShape = aNS->Get(); + + if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape)) { // shape type shoud not not changed: if shape becomes compound of such shapes, then split if (myParent && !anOldShape.IsNull() && !aNewShape.IsNull() && anOldShape.ShapeType() != aNewShape.ShapeType() && @@ -738,7 +748,6 @@ void Model_AttributeSelection::selectBody( const ResultPtr& theContext, const std::shared_ptr& theSubShape) { // perform the selection - TNaming_Selector aSel(selectionLabel()); TopoDS_Shape aContext; ResultBodyPtr aBody = std::dynamic_pointer_cast(theContext);//myRef.value() @@ -828,8 +837,12 @@ void Model_AttributeSelection::selectBody( aFeatureOwner->removeResults(0, false, false); } bool aSelectorOk = true; + //TNaming_Selector aSel(aSelLab); + Selector_Selector aSel(aSelLab); try { - aSel.Select(aNewSub, aNewContext); + //aSel.Select(aNewSub, aNewContext); + aSelectorOk = aSel.select(aNewContext, aNewSub); + aSel.store(); } catch(...) { aSelectorOk = false; } diff --git a/src/Selector/Selector_Selector.cpp b/src/Selector/Selector_Selector.cpp index 45880cab0..61de2fd44 100644 --- a/src/Selector/Selector_Selector.cpp +++ b/src/Selector/Selector_Selector.cpp @@ -20,11 +20,16 @@ #include +#include #include +#include #include #include #include +#include +#include #include +#include #include #include @@ -34,9 +39,11 @@ /// type of the selection, integerm 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_LIST("7c515b1a-9549-493d-9946-a4933a22f45f"); +static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f"); Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab) { @@ -55,12 +62,12 @@ static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& t if (aThisIter.NewShape().IsSame(theValue)) { const TopoDS_Shape& anOldShape = aThisIter.OldShape(); // searching for all old shapes in this sequence of modification - TNaming_NewShapeIterator aNSIter(anOldShape, theFinal->Label()); - for(; aNSIter.More(); aNSIter.Next()) { - TNaming_Evolution anEvolution = aNSIter.NamedShape()->Evolution(); + TNaming_OldShapeIterator anOldIter(anOldShape, theFinal->Label()); + for(; anOldIter.More(); anOldIter.Next()) { + TNaming_Evolution anEvolution = anOldIter.NamedShape()->Evolution(); if (anEvolution == TNaming_PRIMITIVE) { // found a good candidate, a base shape // check that this is not in the results already - const TDF_Label aResult = aNSIter.NamedShape()->Label(); + const TDF_Label aResult = anOldIter.NamedShape()->Label(); TDF_LabelList::Iterator aResIter(theResult); for(; aResIter.More(); aResIter.Next()) { if (aResIter.Value().IsEqual(aResult)) @@ -70,14 +77,14 @@ static void findBases(Handle(TNaming_NamedShape) theFinal, const TopoDS_Shape& t theResult.Append(aResult); } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { // continue recursively - findBases(aNSIter.NamedShape(), anOldShape, theResult); + findBases(anOldIter.NamedShape(), anOldShape, theResult); } } } } } -bool Selector_Selector::Select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +bool Selector_Selector::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue) { if (theValue.IsNull() || theContext.IsNull()) return false; @@ -85,17 +92,16 @@ bool Selector_Selector::Select(const TopoDS_Shape theContext, const TopoDS_Shape // higher level shapes (like a box vertex by faces that form this vertex) if (!TNaming_Tool::HasLabel(myLab, theValue)) { TopAbs_ShapeEnum aSelectionType = theValue.ShapeType(); + myShapeType = aSelectionType; if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID || - aSelectionType == TopAbs_SOLID) { // iterate all sub-shapes and select them on sublabels - std::list aSubSelList; + aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE) + { // iterate all sub-shapes and select them on sublabels for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) { - aSubSelList.push_back(Selector_Selector(myLab.FindChild(aSubSelList.size() + 1))); - if (!aSubSelList.back().Select(theContext, aSubIter.Value())) { + if (!selectBySubSelector(theContext, aSubIter.Value())) { return false; // if some selector is failed, everything is failed } } myType = SELTYPE_CONTAINER; - myShapeType = aSelectionType; return true; } @@ -115,21 +121,45 @@ bool Selector_Selector::Select(const TopoDS_Shape theContext, const TopoDS_Shape } //TODO: check if intersectors produce several subs, try to remove one of the intersector - // name the intersectors + //TODO: check that solution is only one + // name the intersectors + std::list aSubSelList; + TopTools_MapOfShape::Iterator anInt(anIntersectors); + for (; anInt.More(); anInt.Next()) { + if (!selectBySubSelector(theContext, anInt.Value())) { + break; // if some selector is failed, stop and search another solution + } + } + if (!anInt.More()) { // all intersectors were correctly named + myType = SELTYPE_INTERSECT; + return true; + } } + + // TODO: searching by neighbours + return false; } // searching for the base shapes of the value Handle(TNaming_NamedShape) aPrimitiveNS; NCollection_List aModifList; - for(TNaming_NewShapeIterator aNewShapes(theValue, myLab); aNewShapes.More(); aNewShapes.Next()) + for(TNaming_SameShapeIterator aShapes(theValue, myLab); aShapes.More(); aShapes.Next()) { - TNaming_Evolution anEvolution = aNewShapes.NamedShape()->Evolution(); - if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as primitive => PRIMITIVE - aPrimitiveNS = aNewShapes.NamedShape(); - break; - } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) { - aModifList.Append(aNewShapes.NamedShape()); + 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); + } } } @@ -172,30 +202,35 @@ bool Selector_Selector::Select(const TopoDS_Shape theContext, const TopoDS_Shape return false; } -void Selector_Selector::Store() +void Selector_Selector::store() { + myLab.ForgetAllAttributes(true); // remove old naming data TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)myType); switch(myType) { - case SELTYPE_CONTAINER: { - /// TODO - break; - } + case SELTYPE_CONTAINER: case SELTYPE_INTERSECT: { - /// TODO + 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(); + } break; } case SELTYPE_PRIMITIVE: { - Handle(TDataStd_ReferenceArray) anArray = TDataStd_ReferenceArray::Set(myLab, 0, 0); - anArray->SetValue(0, myBases.First()); + Handle(TDataStd_ReferenceArray) anArray = + TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, 0); + anArray->SetValue(0, myFinal); break; } case SELTYPE_MODIFICATION: { Handle(TDataStd_ReferenceArray) anArray = - TDataStd_ReferenceArray::Set(myLab, 0, myBases.Extent() - 1); + TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, myBases.Extent()); TDF_LabelList::Iterator aBIter(myBases); for(int anIndex = 0; aBIter.More(); aBIter.Next(), anIndex++) { anArray->SetValue(anIndex, aBIter.Value()); } + anArray->SetValue(myBases.Extent(), myFinal); // final is in the end of array break; } default: { // unknown case @@ -203,3 +238,200 @@ void Selector_Selector::Store() } } } + +bool Selector_Selector::restore() +{ + Handle(TDataStd_Integer) aTypeAttr; + if (!myLab.FindAttribute(kSEL_TYPE, aTypeAttr)) + return false; + 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())); + if (!mySubSelList.back().restore()) + aSubResult = false; + } + return aSubResult; + } + case SELTYPE_PRIMITIVE: { + Handle(TDataStd_ReferenceArray) anArray; + if (myLab.FindAttribute(kBASE_ARRAY, anArray)) { + myFinal = anArray->Value(0); + return true; + } + return false; + } + case SELTYPE_MODIFICATION: { + Handle(TDataStd_ReferenceArray) anArray; + if (myLab.FindAttribute(kBASE_ARRAY, anArray)) { + int anUpper = anArray->Upper(); + for(int anIndex = 0; anIndex < anUpper; anIndex++) { + myBases.Append(anArray->Value(anIndex)); + } + myFinal = anArray->Value(anUpper); + return true; + } + return false; + } + default: { // unknown case + } + } + return false; +} + +/// Returns in theResults all shapes with history started in theBase and ended in theFinal +static void findFinals(const TopoDS_Shape& theBase, const TDF_Label& theFinal, + TopTools_MapOfShape& theResults) +{ + for(TNaming_NewShapeIterator aBaseIter(theBase, theFinal); 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(aBaseIter.Shape(), theFinal, theResults); + } + } + } + +} + +bool Selector_Selector::solve() +{ + 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()) { + return false; + } + aBuilder.Add(aResult, aSubSel->value()); + } + break; + } + case SELTYPE_INTERSECT: { + TopoDS_ListOfShape aCommon; // common sub shapes in each sub-selector (a result) + std::list::iterator aSubSel = mySubSelList.begin(); + for(; aSubSel != mySubSelList.end(); aSubSel++) { + if (!aSubSel->solve()) { + return false; + } + TopoDS_Shape anArg = aSubSel->value(); + TopTools_MapOfShape aCurrentMap; + for(TopExp_Explorer anExp(anArg, myShapeType); anExp.More(); anExp.Next()) { + if (aCurrentMap.Add(anExp.Current()) && aSubSel == mySubSelList.begin()) + aCommon.Append(anExp.Current()); + } + if (aSubSel != mySubSelList.begin()) { // remove from common shapes not in aCurrentMap + for(TopoDS_ListOfShape::Iterator aComIter(aCommon); aComIter.More(); ) { + if (aCurrentMap.Contains(aComIter.Value())) + aComIter.Next(); + else + aCommon.Remove(aComIter); + } + } + } + if (aCommon.Extent() != 1) + return false; + aResult = aCommon.First(); + break; + } + case SELTYPE_PRIMITIVE: { + Handle(TNaming_NamedShape) aNS; + if (myFinal.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + aResult = aNS->Get(); + } + } + case SELTYPE_MODIFICATION: { + TopoDS_ListOfShape aFinalsCommon; // final shapes presented in all results from bases + TDF_LabelList::Iterator aBase(myBases); + for(; aBase.More(); aBase.Value()) { + TopTools_MapOfShape aFinals; + for(TNaming_Iterator aBaseShape(aBase.Value()); aBaseShape.More(); aBaseShape.Next()) + findFinals(aBaseShape.NewShape(), myFinal, aFinals); + if (!aFinals.IsEmpty()) { + if (aFinalsCommon.IsEmpty()) { // just copy all to common + for(TopTools_MapOfShape::Iterator aFinal(aFinals); aFinal.More(); aFinal.Next()) { + aFinalsCommon.Append(aFinal.Key()); + } + } else { // keep only shapes presented in both lists + TopoDS_ListOfShape::Iterator aCommon(aFinalsCommon); + for(; aCommon.More(); aCommon.Next()) { + if (aFinals.Contains(aCommon.Value())) { + aCommon.Next(); + } else { // common is not found, remove it + aFinalsCommon.Remove(aCommon); + } + } + } + } + } + if (aFinalsCommon.Extent() == 1) // only in this case result is valid: found only one shape + aResult = aFinalsCommon.First(); + } + 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; + if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) + return aNS->Get(); + return TopoDS_Shape(); // empty, error shape +} + +bool Selector_Selector::selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue) +{ + mySubSelList.push_back(Selector_Selector(myLab.FindChild(int(mySubSelList.size()) + 1))); + if (!mySubSelList.back().select(theContext, theValue)) { + mySubSelList.clear(); // if one of the selector is failed, all become invalid + return false; + } + return true; +} diff --git a/src/Selector/Selector_Selector.h b/src/Selector/Selector_Selector.h index dc4866018..7a9cdeda5 100644 --- a/src/Selector/Selector_Selector.h +++ b/src/Selector/Selector_Selector.h @@ -27,6 +27,8 @@ #include #include +#include + /**\class Selector_Selector * \ingroup DataModel * \brief Main object for selection of the sub-shapes in the parametrically updated @@ -46,6 +48,7 @@ class Selector_Selector Selector_Type myType; ///< Type of this selector. TopAbs_ShapeEnum myShapeType; ///< type of this shape: container or result of intersection + 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 @@ -53,19 +56,32 @@ class Selector_Selector public: /// Initializes selector on the label - Selector_Selector(TDF_Label theLab); + SELECTOR_EXPORT Selector_Selector(TDF_Label theLab); /// Returns label of this selector - TDF_Label label(); + SELECTOR_EXPORT TDF_Label label(); /// Initializes the selector structure on the label. /// Stores the name data to restore after modification. - bool Select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); + SELECTOR_EXPORT bool select(const TopoDS_Shape theContext, const TopoDS_Shape theValue); /// Stores the name to the label and sub-labels tree - void Store(); + SELECTOR_EXPORT void store(); /// Restores the selected shape by the topological naming kept in the data structure - //TopoDS_Shape Restore(); + /// Returns true if it can restore structure correctly + SELECTOR_EXPORT bool restore(); + + /// Updates the current shape by the stored topological name + SELECTOR_EXPORT bool solve(); + + /// Returns the current sub-shape value (null if can not resolve) + SELECTOR_EXPORT TopoDS_Shape value(); + +private: + + /// Create and keep in the list the sub-sulector that select the given value. + /// Returns true if selection is correct. + bool selectBySubSelector(const TopoDS_Shape theContext, const TopoDS_Shape theValue); }; #endif -- 2.39.2