X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FModel_SelectionNaming.cpp;h=1b1c51e9ec70901a076e22a19d15503fb263dae5;hb=b73fb7468bea81901dbeed8e229d742f788ec282;hp=a3f9ace283ec807898b03917b39d74b25a49e16d;hpb=07a45a94a93a5f1cc3d39f53328c12be074ff69b;p=modules%2Fshaper.git diff --git a/src/Model/Model_SelectionNaming.cpp b/src/Model/Model_SelectionNaming.cpp index a3f9ace28..1b1c51e9e 100644 --- a/src/Model/Model_SelectionNaming.cpp +++ b/src/Model/Model_SelectionNaming.cpp @@ -1,12 +1,27 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: Model_SelectionNaming.cpp -// Created: 11 Aug 2015 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// #include "Model_SelectionNaming.h" #include "Model_Document.h" #include "Model_Objects.h" +#include "Model_Data.h" #include #include #include @@ -14,6 +29,7 @@ #include #include #include +#include #include #include @@ -31,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -45,43 +62,121 @@ Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab) myLab = theSelectionLab; } +// searches named shape by the shape in the given document (identified by the label) +// tries to find s shape nearest to the context-label +static Handle(TNaming_NamedShape) shapeToNS(const TDF_Label theLabAccess, + const TopoDS_Shape& theShape, const TDF_Label& theContextLab) +{ + Handle(TNaming_NamedShape) aResult; + if (!TNaming_Tool::HasLabel(theLabAccess, theShape)) // no shape in the document + return aResult; + int aContextLabDepth = theContextLab.IsNull() ? 100 : theContextLab.Depth(); + TNaming_SameShapeIterator aNSIter(theShape, theLabAccess); + for(; aNSIter.More(); aNSIter.Next()) { + TDF_Label aLabel = aNSIter.Label(); + Handle(TNaming_NamedShape) aNS; + if (aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + if (aNS->Evolution() != TNaming_SELECTED && aNS->Evolution() != TNaming_DELETE) { + // check this is new shape in this named shape + bool aIsNew = false; + for(TNaming_Iterator aNSIter(aNS); aNSIter.More(); aNSIter.Next()) + if (!aNSIter.NewShape().IsNull() && aNSIter.NewShape().IsSame(theShape)) + aIsNew = true; + if (!aIsNew) + continue; + // check this is the context-shape + while(aLabel.Depth() > aContextLabDepth) + aLabel = aLabel.Father(); + if (aLabel.IsEqual(theContextLab)) + return aNS; + if (aResult.IsNull()) // take the first, otherwise it will get shapes from results, etc + aResult = aNS; // keep some result anyway - if there are no context labels return any + } + } + } + return aResult; +} + std::string Model_SelectionNaming::getShapeName( std::shared_ptr theDoc, const TopoDS_Shape& theShape, - const bool theAddContextName) + ResultPtr& theContext, const bool theAnotherDoc, const bool theWholeContext) { std::string aName; + // add the result name to the name of the shape + // (it was in BodyBuilder, but did not work on Result rename) + bool isNeedContextName = theContext->shape().get() != NULL; // check if the subShape is already in DF - Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(theShape, myLab); + std::shared_ptr aData = + std::dynamic_pointer_cast(theContext->data()); + TDF_Label aContextDataLab(aData.get() && aData->isValid() ? aData->label() : TDF_Label()); + Handle(TNaming_NamedShape) aNS = shapeToNS(myLab, theShape, aContextDataLab); Handle(TDataStd_Name) anAttr; - if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document + if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) { - aName = TCollection_AsciiString(anAttr->Get()).ToCString(); - // indexes are added to sub-shapes not primitives (primitives must not be located at the same label) - if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && theAddContextName) { - const TDF_Label& aLabel = aNS->Label();//theDoc->findNamingName(aName); - static const std::string aPostFix("_"); - TNaming_Iterator anItL(aNS); - for(int i = 1; anItL.More(); anItL.Next(), i++) { - if(anItL.NewShape() == theShape) { - aName += aPostFix; - aName += TCollection_AsciiString (i).ToCString(); - break; + if (isNeedContextName && aData && aContextDataLab.IsEqual(aNS->Label())) { + // do nothing because this context name will be added later in this method + } else { + aName = TCollection_AsciiString(anAttr->Get()).ToCString(); + // indexes are added to sub-shapes not primitives + // (primitives must not be located at the same label) + if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && isNeedContextName) { + const TDF_Label& aLabel = aNS->Label(); + static const std::string aPostFix("_"); + TNaming_Iterator anItL(aNS); + for(int i = 1; anItL.More(); anItL.Next(), i++) { + // in #1766 IsEqual produced no index of the face + if(anItL.NewShape().IsSame(theShape)) { + aName += aPostFix; + aName += TCollection_AsciiString (i).ToCString(); + break; + } } } - } - if (theAddContextName && aName.find("/") == std::string::npos) { // searching for the context object - for(TDF_Label anObjL = aNS->Label(); anObjL.Depth() > 4; anObjL = anObjL.Father()) { - int aDepth = anObjL.Depth(); - if (aDepth == 5 || aDepth == 7) { - ObjectPtr anObj = theDoc->objects()->object(anObjL); - if (anObj) { - aName = anObj->data()->name() + "/" + aName; + // if a shape is under another context, use this name, not theContext + std::shared_ptr aContextData = + std::dynamic_pointer_cast(theContext->data()); + // for constructions the naming is in arguments and has no evolution, so, apply this only + // for bodies + if (isNeedContextName && theContext->groupName() == ModelAPI_ResultBody::group() && + !aNS->Label().IsDescendant(aContextData->label())) { + isNeedContextName = false; + TDF_Label aNSDataLab = aNS->Label(); + if (aNSDataLab.Depth() % 2 == 0) + aNSDataLab = aNSDataLab.Father(); + ObjectPtr aNewContext = theDoc->objects()->object(aNSDataLab); + while(!aNewContext.get() && aNSDataLab.Depth() > 5) { + aNSDataLab = aNSDataLab.Father().Father(); + aNewContext = theDoc->objects()->object(aNSDataLab); + } + if (aNewContext.get()) { + // this is to avoid duplicated names of results problem + std::string aContextName = aNewContext->data()->name(); + // myLab corresponds to the current time + TDF_Label aCurrentLab = myLab; + while(aCurrentLab.Depth() > 3) + aCurrentLab = aCurrentLab.Father(); + + int aNumInHistoryNames = + theDoc->numberOfNameInHistory(aNewContext, aCurrentLab); + while(aNumInHistoryNames > 1) { // add "_" before name the needed number of times + aContextName = "_" + aContextName; + aNumInHistoryNames--; } + + aName = aContextName + "/" + aName; } } } } } + + // Name is empty and this is full context, it just add the whole context name that must be added + bool isEmptyName = aName.empty(); + if (isNeedContextName && (!isEmptyName || theWholeContext)) { + aName = theContext->data()->name() + (isEmptyName ? "" : ("/" + aName)); + if (theAnotherDoc) + aName = theContext->document()->kind() + "/" + aName; // PartSet + } return aName; } @@ -93,6 +188,8 @@ bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfS BB.MakeCompound(aCmp); TopTools_ListIteratorOfListOfShape it(theAncestors); for(;it.More();it.Next()) { + if (theSMap.Contains(it.Value())) + continue; BB.Add(aCmp, it.Value()); theSMap.Add(it.Value()); } @@ -108,21 +205,150 @@ bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfS return true; } +const TopoDS_Shape findCommonShape( + const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList) +{ + if(theList.Extent() < 1) { + return TopoDS_Shape(); + } else if (theList.Extent() == 1) { // check that sub-shape is bounded by this alone shape + TopTools_MapOfShape aSubsInShape; + TopExp_Explorer anExp(theList.First(), theType); + for(; anExp.More(); anExp.Next()) { + if (aSubsInShape.Contains(anExp.Current())) { // found duplicate + return anExp.Current(); + } + aSubsInShape.Add(anExp.Current()); + } + } + + // Store in maps sub-shapes from each face. + std::vector aVec; + for(TopTools_ListIteratorOfListOfShape anIt(theList); anIt.More(); anIt.Next()) { + const TopoDS_Shape aFace = anIt.Value(); + TopTools_MapOfShape aMap; + for(TopExp_Explorer anExp(aFace, theType); anExp.More(); anExp.Next()) { + const TopoDS_Shape& aSubShape = anExp.Current(); + aMap.Add(anExp.Current()); + } + aVec.push_back(aMap); + } + + // Find sub-shape shared between all faces. + TopoDS_Shape aSharedShape; + for(TopTools_MapIteratorOfMapOfShape anIt(aVec[0]); anIt.More(); anIt.Next()) { + const TopoDS_Shape& aSubShape = anIt.Value(); + int aSharedNb = 1; + for(int anIndex = 1; anIndex < aVec.size(); ++anIndex) { + if(aVec[anIndex].Contains(aSubShape)) { + ++aSharedNb; + } + } + if(aSharedNb == theList.Extent()) { + if(aSharedShape.IsNull()) { + aSharedShape = aSubShape; + } else { + // More than one shape shared between all faces, return null shape in this case. + return TopoDS_Shape(); + } + } + } + + return aSharedShape; +} + +// searches theType shape that contains theConnectionType sub-shapes in each shape from the List, +// so, implements the neighbours searching +/* +const TopoDS_Shape findCommonShapeByNB(const TopAbs_ShapeEnum theType, + const TopAbs_ShapeEnum theConnectionType, const TopTools_ListOfShape& theList) +{ +TopTools_MapOfShape aCheckedShapes; // already checked shapes of type theType + TopoDS_Shape aResult; // theType result shape + for(TopTools_ListIteratorOfListOfShape anIt(theList); anIt.More(); anIt.Next()) { // iterate all + for(TopExp_Explorer anExp(anIt.ChangeValue(), theType); anExp.More(); anExp.Next()) { + if (aCheckedShapes.Contains(anExp.Current())) + continue; // already checked + aCheckedShapes.Add(anExp.Current()); + TopTools_MapOfShape aConnectors; // all connectors of the checked theType shape + for(TopExp_Explorer aCExp(anExp.Current(), theConnectionType); aCExp.More(); aCExp.Next()) { + aConnectors.Add(aCExp.Current()); + } + // check that all shapes from the List contain the connector sub-shapes + bool aFound = true; + for(TopTools_ListIteratorOfListOfShape anIt2(theList); anIt2.More() && aFound; anIt2.Next()) { + if (anIt2.Value().IsSame(anIt.Value())) + continue; + aFound = false; + for(TopExp_Explorer anE(anIt2.ChangeValue(), theConnectionType); anE.More(); anE.Next()) { + if (aConnectors.Contains(anE.Current())) { + aFound = true; + break; + } + } + } + if (aFound) { + if (!aResult.IsNull()) // more than one result + return TopoDS_Shape(); + aResult = anExp.Current(); + } + } + } + return aResult; +}*/ + +std::string Model_SelectionNaming::vertexNameByEdges(TopoDS_Shape theContext, TopoDS_Shape theSub, + std::shared_ptr theDoc, ResultPtr& theContextRes, const bool theAnotherDoc) +{ + std::string aResult; + TopTools_IndexedDataMapOfShapeListOfShape aMap; + TopExp::MapShapesAndAncestors(theContext, TopAbs_VERTEX, TopAbs_EDGE, aMap); + const TopTools_ListOfShape& aList22 = aMap.FindFromKey(theSub); + if(aList22.Extent() >= 2) { // regular solution + TopTools_MapOfShape aFMap; + TopTools_ListOfShape aListE; + TopTools_ListIteratorOfListOfShape itl2(aList22); + for (int i = 1;itl2.More();itl2.Next(),i++) { + if(aFMap.Add(itl2.Value())) + aListE.Append(itl2.Value()); + } + TopTools_ListIteratorOfListOfShape itl(aListE); + for (int i = 1;itl.More();itl.Next(),i++) { + const TopoDS_Shape& anEdge = itl.Value(); + std::string anEdgeName = getShapeName(theDoc, anEdge, theContextRes, theAnotherDoc, false); + if (anEdgeName.empty()) { // edge is not in DS + aResult.clear(); + return aResult; + } + if(i == 1) + aResult = anEdgeName; + else + aResult += "&" + anEdgeName; + } + } + return aResult; +} + std::string Model_SelectionNaming::namingName(ResultPtr& theContext, std::shared_ptr theSubSh, const std::string& theDefaultName, const bool theAnotherDoc) { std::string aName("Undefined name"); - if(!theContext.get() || theContext->shape()->isNull()) + if(!theContext.get() + || !theContext->shape().get() + || theContext->shape()->isNull()) { return !theDefaultName.empty() ? theDefaultName : aName; - + } + // if it is in result of another part - std::shared_ptr aDoc = + std::shared_ptr aDoc = std::dynamic_pointer_cast(theContext->document()); if (theContext->groupName() == ModelAPI_ResultPart::group()) { ResultPartPtr aPart = std::dynamic_pointer_cast(theContext); int anIndex; - return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex); + if (theSubSh.get()) + return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex); + else + return aPart->data()->name(); } if (!theSubSh.get() || theSubSh->isNull()) { // no subshape, so just the whole feature name @@ -140,26 +366,24 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, BRepTools::Write(aContext, "Context.brep"); } #endif + aName = getShapeName(aDoc, aSubShape, theContext, theAnotherDoc, + theContext->shape()->isEqual(theSubSh)); - // add the result name to the name of the shape (it was in BodyBuilder, but did not work on Result rename) - bool isNeedContextName = theContext->shape().get() && !theContext->shape()->isEqual(theSubSh); - - // check if the subShape is already in DF - aName = getShapeName(aDoc, aSubShape, isNeedContextName); if(aName.empty() ) { // not in the document! TopAbs_ShapeEnum aType = aSubShape.ShapeType(); switch (aType) { case TopAbs_FACE: - // the Face should be in DF. If it is not the case, it is an error ==> to be debugged + // the Face should be in DF. If it is not the case, it is an error ==> to be debugged break; case TopAbs_EDGE: { - // name structure: F1 & F2 [& F3 & F4], where F1 & F2 the faces which gives the Edge in trivial case - // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces + // name structure: F1 & F2 [& F3 & F4], + // where F1 & F2 the faces which gives the Edge in trivial case + // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces if (BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) { aName = "Degenerated_Edge"; break; - } + } TopTools_IndexedDataMapOfShapeListOfShape aMap; TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap); TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape @@ -167,10 +391,13 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, if(aMap.Contains(aSubShape)) { const TopTools_ListOfShape& anAncestors = aMap.FindFromKey(aSubShape); // check that it is not a trivial case (F1 & F2: aNumber = 1) - isTrivialCase = isTrivial(anAncestors, aSMap); - } else + isTrivialCase = isTrivial(anAncestors, aSMap); + if (!isTrivialCase) { // another try: check that common shape can be processed anyway + isTrivialCase = !findCommonShape(TopAbs_EDGE, anAncestors).IsNull(); + } + } else break; - TopTools_ListOfShape aListOfNbs; + TopTools_MapOfShape aNbs; if(!isTrivialCase) { // find Neighbors TNaming_Localizer aLocalizer; TopTools_MapOfShape aMap3; @@ -184,95 +411,89 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, TopTools_ListIteratorOfListOfShape it2(aList); for(;it2.More();it2.Next()) { if(aSMap.Contains(it2.Value())) continue; // skip this Face - aListOfNbs.Append(it2.Value()); + aNbs.Add(it2.Value()); } } } // else a trivial case // build name of the sub-shape Edge - for(int i=1; i <= aSMap.Extent(); i++) { - const TopoDS_Shape& aFace = aSMap.FindKey(i); - std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName); - if(i == 1) + // iterate faces of the context to get stable order, not map-order + TopTools_MapOfShape aStoredFaces; // to avoid duplicates + for(TopExp_Explorer aContExp(aContext, TopAbs_FACE); aContExp.More(); aContExp.Next()) { + const TopoDS_Shape& aFace = aContExp.Current(); + if (aStoredFaces.Contains(aFace) || !(aSMap.Contains(aFace) || aNbs.Contains(aFace))) + continue; + aStoredFaces.Add(aFace); + std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false); + if(aName.empty()) aName = aFaceName; - else + else aName += "&" + aFaceName; } - TopTools_ListIteratorOfListOfShape itl(aListOfNbs); - for (;itl.More();itl.Next()) { - std::string aFaceName = getShapeName(aDoc, itl.Value(), isNeedContextName); - aName += "&" + aFaceName; - } } break; case TopAbs_VERTEX: - // name structure (Monifold Topology): + // name structure (Monifold Topology): // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case. - // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition, but it should be kept as is to obtain safe recomputation + // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition, + // but it should be kept as is to obtain safe recomputation // 2) F1 | F2 - intersection of 2 faces definses a vertex - applicable for case // when 1 faces is cylindrical, conical, spherical or revolution and etc. // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell // or compound of 2 open faces. - // 4) E1 | E2 - intesection of 2 edges defines a vertex - when we have a case of + // 4) E1 | E2 - intesection of 2 edges defines a vertex - when we have a case of // two independent edges (wire or compound) // implemented 2 first cases { TopTools_IndexedDataMapOfShapeListOfShape aMap; TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap); - const TopTools_ListOfShape& aList2 = aMap.FindFromKey(aSubShape); TopTools_ListOfShape aList; TopTools_MapOfShape aFMap; - // fix is below - TopTools_ListIteratorOfListOfShape itl2(aList2); - for (int i = 1;itl2.More();itl2.Next(),i++) { - if(aFMap.Add(itl2.Value())) - aList.Append(itl2.Value()); - } + // simetimes when group is moved in history, naming may be badly updated, so + // avoid crash in FindFromKey (issue 1842) + if (aMap.Contains(aSubShape)) { + const TopTools_ListOfShape& aList2 = aMap.FindFromKey(aSubShape); + // fix is below + TopTools_ListIteratorOfListOfShape itl2(aList2); + for (int i = 1;itl2.More();itl2.Next(),i++) { + if(aFMap.Add(itl2.Value())) + aList.Append(itl2.Value()); + } + } else + break; int n = aList.Extent(); bool isByFaces = n >= 3; + if (isByFaces) { // check that by faces vertex is identified uniquly (2317) + TopoDS_Shape aVertex = findCommonShape(TopAbs_VERTEX, aList); + isByFaces = !aVertex.IsNull() && aVertex.ShapeType() == TopAbs_VERTEX; + } + if(!isByFaces) { // open topology case or Compound case => via edges - TopTools_IndexedDataMapOfShapeListOfShape aMap; - TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_EDGE, aMap); - const TopTools_ListOfShape& aList22 = aMap.FindFromKey(aSubShape); - if(aList22.Extent() >= 2) { // regular solution - - // bug! duplication; fix is below - aFMap.Clear(); - TopTools_ListOfShape aListE; - TopTools_ListIteratorOfListOfShape itl2(aList22); - for (int i = 1;itl2.More();itl2.Next(),i++) { - if(aFMap.Add(itl2.Value())) - aListE.Append(itl2.Value()); - } - n = aListE.Extent(); - TopTools_ListIteratorOfListOfShape itl(aListE); - for (int i = 1;itl.More();itl.Next(),i++) { - const TopoDS_Shape& anEdge = itl.Value(); - std::string anEdgeName = getShapeName(aDoc, anEdge, isNeedContextName); - if (anEdgeName.empty()) { // edge is not in DS, trying by faces anyway - isByFaces = true; - aName.clear(); - break; + aName = vertexNameByEdges(aContext, aSubShape, aDoc, theContext, theAnotherDoc); + isByFaces = aName.empty(); + if (isByFaces) { // try to find a vertex in sketch faces + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(theContext); + if (aConstr.get() && aConstr->facesNum()) { + for(int aFace = aConstr->facesNum() - 1; isByFaces && aFace >= 0; aFace--) { + std::shared_ptr aGFace = aConstr->face(aFace); + aName = vertexNameByEdges(aGFace->impl(), aSubShape, + aDoc, theContext, theAnotherDoc); + isByFaces = aName.empty(); } - if(i == 1) - aName = anEdgeName; - else - aName += "&" + anEdgeName; } - }//reg - else { // dangle vertex: if(aList22.Extent() == 1) - //it should be already in DF } - } + } + if (isByFaces) { TopTools_ListIteratorOfListOfShape itl(aList); for (int i = 1;itl.More();itl.Next(),i++) { const TopoDS_Shape& aFace = itl.Value(); - std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName); + std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false); if(i == 1) aName = aFaceName; - else + else aName += "&" + aFaceName; } } @@ -280,7 +501,6 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, break; } } - return aName; } @@ -325,7 +545,8 @@ TopAbs_ShapeEnum translateType (const std::string& theType) } if (aShapeTypes.find(theType) != aShapeTypes.end()) return aShapeTypes[theType]; - Events_InfoMessage("Model_SelectionNaming", "Shape type defined in XML is not implemented!").send(); + Events_InfoMessage("Model_SelectionNaming", + "Shape type defined in XML is not implemented!").send(); return TopAbs_SHAPE; } @@ -333,16 +554,19 @@ const TopoDS_Shape getShapeFromNS( const std::string& theSubShapeName, Handle(TNaming_NamedShape) theNS) { TopoDS_Shape aSelection; - std::string::size_type n = theSubShapeName.rfind('/'); - if (n == std::string::npos) n = 0; + std::string::size_type n = theSubShapeName.rfind('/'); + if (n == std::string::npos) n = -1; std::string aSubString = theSubShapeName.substr(n + 1); n = aSubString.rfind('_'); - int indx; - if (n == std::string::npos) {// for primitives this is a first - indx = 1; - } else { - aSubString = aSubString.substr(n+1); - indx = atoi(aSubString.c_str()); + int indx = 1; + if (n != std::string::npos) {// for primitives this is a first + // if we have here the same name as theSubShapeName, there is no index in compound, it is whole + Handle(TDataStd_Name) aName; + if (!theNS->Label().FindAttribute(TDataStd_Name::GetID(), aName) || + aName->Get() != aSubString.c_str()) { + aSubString = aSubString.substr(n+1); + indx = atoi(aSubString.c_str()); + } } TNaming_Iterator anItL(theNS); @@ -351,24 +575,25 @@ const TopoDS_Shape getShapeFromNS( return anItL.NewShape(); } } - return aSelection; + return aSelection; } const TopoDS_Shape findFaceByName( - const std::string& theSubShapeName, std::shared_ptr theDoc) + const std::string& theSubShapeName, std::shared_ptr theDoc, + const ResultPtr theDetectedContext, bool theContextIsUnique) { TopoDS_Shape aFace; - //std::string::size_type n, nb = theSubShapeName.rfind('/'); - //if (nb == std::string::npos) nb = 0; - //std::string aSubString = theSubShapeName.substr(nb + 1); std::string aSubString = theSubShapeName; - TDF_Label aLabel = theDoc->findNamingName(aSubString); + static const ResultPtr anEmpty; + TDF_Label aLabel = theDoc->findNamingName(aSubString, + theContextIsUnique ? theDetectedContext : anEmpty); if (aLabel.IsNull()) { // try to remove additional artificial suffix std::string::size_type n = aSubString.rfind('_'); if (n != std::string::npos) { aSubString = aSubString.substr(0, n); - aLabel = theDoc->findNamingName(aSubString); + aLabel = theDoc->findNamingName(aSubString, + theContextIsUnique ? theDetectedContext : anEmpty); } } if(aLabel.IsNull()) return aFace; @@ -382,11 +607,11 @@ const TopoDS_Shape findFaceByName( size_t ParseName(const std::string& theSubShapeName, std::list& theList) { std::string aName = theSubShapeName; - std::string aLastName; + std::string aLastName = aName; size_t n1(0), n2(0); // n1 - start position, n2 - position of the delimiter while ((n2 = aName.find('&', n1)) != std::string::npos) { const std::string aName1 = aName.substr(n1, n2 - n1); //name of face - theList.push_back(aName1); + theList.push_back(aName1); n1 = n2 + 1; aLastName = aName.substr(n1); } @@ -395,102 +620,20 @@ size_t ParseName(const std::string& theSubShapeName, std::list& t return theList.size(); } -const TopoDS_Shape findCommonShape( - const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList) -{ - TopoDS_Shape aShape; - std::vector aVec; - TopTools_MapOfShape aMap1, aMap2, aMap3, aMap4; - if(theList.Extent() > 1) { - aVec.push_back(aMap1); - aVec.push_back(aMap2); - } - if(theList.Extent() > 2) - aVec.push_back(aMap3); - if(theList.Extent() == 4) - aVec.push_back(aMap4); - - //fill maps - TopTools_ListIteratorOfListOfShape it(theList); - for(int i = 0;it.More();it.Next(),i++) { - const TopoDS_Shape& aFace = it.Value(); - if(i < 2) { - TopExp_Explorer anExp (aFace, theType); - for(;anExp.More();anExp.Next()) { - const TopoDS_Shape& anEdge = anExp.Current(); - if (!anEdge.IsNull()) - aVec[i].Add(anExp.Current()); - } - } else { - TopExp_Explorer anExp (aFace, TopAbs_VERTEX); - for(;anExp.More();anExp.Next()) { - const TopoDS_Shape& aVertex = anExp.Current(); - if (!aVertex.IsNull()) - aVec[i].Add(anExp.Current()); - } - } - } - //trivial case: 2 faces - TopTools_ListOfShape aList; - TopTools_MapIteratorOfMapOfShape it2(aVec[0]); - for(;it2.More();it2.Next()) { - if(aVec[1].Contains(it2.Key())) { - aShape = it2.Key(); - if(theList.Extent() == 2) - break; - else - aList.Append(it2.Key()); - } - } - if(aList.Extent() && aVec.size() > 3) {// list of common edges ==> search ny neighbors - if(aVec[2].Extent() && aVec[3].Extent()) { - TopTools_ListIteratorOfListOfShape it(aList); - for(;it.More();it.Next()) { - const TopoDS_Shape& aCand = it.Value(); - // not yet completelly implemented, to be rechecked - TopoDS_Vertex aV1, aV2; - TopExp::Vertices(TopoDS::Edge(aCand), aV1, aV2); - int aNum(0); - if(aVec[2].Contains(aV1)) aNum++; - else if(aVec[2].Contains(aV2)) aNum++; - if(aVec[3].Contains(aV1)) aNum++; - else if(aVec[3].Contains(aV2)) aNum++; - if(aNum == 2) { - aShape = aCand; - break; - } - } - } - } - - if(aList.Extent() && aVec.size() == 3) { - - TopTools_ListIteratorOfListOfShape it(aList); - for(;it.More();it.Next()) { - const TopoDS_Shape& aCand = it.Value(); - if(aVec[2].Contains(aCand)) { - aShape = aCand; - break; - } - } - } - return aShape; -} - std::string getContextName(const std::string& theSubShapeName) { std::string aName; - std::string::size_type n = theSubShapeName.find('/'); + std::string::size_type n = theSubShapeName.find('/'); if (n == std::string::npos) return theSubShapeName; aName = theSubShapeName.substr(0, n); return aName; } -/// Parses naming name of sketch sub-elements: takes indices and orientation -/// (if theOriented = true) from this name. Map theIDs constains indices -> +/// Parses naming name of sketch sub-elements: takes indices and orientation +/// (if theOriented = true) from this name. Map theIDs constains indices -> /// orientations and start/end vertices: negative is reversed, 2 - start, 3 - end bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names - const std::string& theName, const char* theShapeType, + const std::string& theName, const char* theShapeType, std::map& theIDs, const bool theOriented = false) { // collect all IDs in the name @@ -502,7 +645,7 @@ bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names std::list >::const_iterator aRes = aResults.cbegin(); // there may be many shapes (circle and center) for(; aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(*aRes); if (aConstr.get()) { aNames[Model_SelectionNaming::shortName(aConstr)] = theComp->subFeatureId(a); @@ -550,56 +693,73 @@ int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoD { if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE) return 0; - if (theEdge.Orientation() == TopAbs_FORWARD) + if (theEdge.Orientation() == TopAbs_FORWARD) return 1; - if (theEdge.Orientation() == TopAbs_REVERSED) + if (theEdge.Orientation() == TopAbs_REVERSED) return -1; return 0; // unknown } std::shared_ptr Model_SelectionNaming::findAppropriateFace( - std::shared_ptr& theConstr, - NCollection_DataMap& theCurves) + std::shared_ptr& theConstr, + NCollection_DataMap& theCurves, const bool theIsWire) { int aBestFound = 0; // best number of found edges (not percentage: issue 1019) int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation std::shared_ptr aResult; - ResultConstructionPtr aConstructionContext = + ResultConstructionPtr aConstructionContext = std::dynamic_pointer_cast(theConstr); if (!aConstructionContext.get()) return aResult; for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) { int aFound = 0, aNotFound = 0, aSameOrientation = 0; - TopoDS_Face aFace = + TopoDS_Face aFace = TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl()); - TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE); - TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841) - for(; anEdgesExp.More(); anEdgesExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (alreadyProcessed.Contains(aCurve)) - continue; - alreadyProcessed.Add(aCurve); - if (theCurves.IsBound(aCurve)) { - aFound++; - int anOrient = theCurves.Find(aCurve); - if (anOrient != 0) { // extra comparision score is orientation - if (edgeOrientation(aFace, anEdge) == anOrient) - aSameOrientation++; + std::list aFacesWires; // faces or wires to iterate + if (theIsWire) { + for(TopExp_Explorer aWires(aFace, TopAbs_WIRE); aWires.More(); aWires.Next()) { + aFacesWires.push_back(aWires.Current()); + } + } else { + aFacesWires.push_back(aFace); + } + std::list::iterator aFW = aFacesWires.begin(); + for(; aFW != aFacesWires.end(); aFW++) { + TopExp_Explorer anEdgesExp(*aFW, TopAbs_EDGE); + TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841) + for(; anEdgesExp.More(); anEdgesExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (alreadyProcessed.Contains(aCurve)) + continue; + alreadyProcessed.Add(aCurve); + if (theCurves.IsBound(aCurve)) { + aFound++; + int anOrient = theCurves.Find(aCurve); + if (anOrient != 0) { // extra comparision score is orientation + if (edgeOrientation(aFace, anEdge) == anOrient) + aSameOrientation++; + } + } else { + aNotFound++; } - } else { - aNotFound++; } } - } - if (aFound + aNotFound != 0) { - if (aFound > aBestFound || - (aFound == aBestFound && aSameOrientation > aBestOrient)) { - aBestFound = aFound; - aBestOrient = aSameOrientation; - aResult = aConstructionContext->face(aFaceIndex); + if (aFound + aNotFound != 0) { + if (aFound > aBestFound || + (aFound == aBestFound && aSameOrientation > aBestOrient)) { + aBestFound = aFound; + aBestOrient = aSameOrientation; + if (theIsWire) { + std::shared_ptr aWire(new GeomAPI_Wire); + aWire->setImpl(new TopoDS_Shape(*aFW)); + aResult = aWire; + } else { + aResult = aConstructionContext->face(aFaceIndex); + } + } } } } @@ -614,7 +774,8 @@ std::string Model_SelectionNaming::shortName( aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end()); aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end()); aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end()); - // remove the last 's', 'e', 'f' and 'r' symbols: they are used as markers of start/end/forward/rewersed indicators + // remove the last 's', 'e', 'f' and 'r' symbols: + // they are used as markers of start/end/forward/rewersed indicators static const std::string aSyms("sefr"); std::string::iterator aSuffix = aName.end() - 1; while(aSyms.find(*aSuffix) != std::string::npos) { @@ -631,7 +792,7 @@ std::string Model_SelectionNaming::shortName( } // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT -bool Model_SelectionNaming::selectSubShape(const std::string& theType, +bool Model_SelectionNaming::selectSubShape(const std::string& theType, const std::string& theSubShapeName, std::shared_ptr theDoc, std::shared_ptr& theShapeToBeSelected, std::shared_ptr& theCont) { @@ -644,6 +805,7 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, std::shared_ptr aDoc = theDoc; if (aSlash != std::string::npos) { std::string aDocName = theSubShapeName.substr(0, aSlash); + ResultPartPtr aFoundPart; DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); if (aDocName == aRootDoc->kind()) { aDoc = std::dynamic_pointer_cast(aRootDoc); @@ -653,26 +815,34 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, aRootDoc->object(ModelAPI_ResultPart::group(), a)); if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) { aDoc = std::dynamic_pointer_cast(aPart->partDoc()); + aFoundPart = aPart; + break; } } } - if (aDoc != theDoc) { // so, the first word is the document name => reduce the string for the next manips + if (aDoc != theDoc) { + // so, the first word is the document name => reduce the string for the next manips aSubShapeName = theSubShapeName.substr(aSlash + 1); + if (aSubShapeName.empty() && aFoundPart.get()) { // the whole Part result + theCont = aFoundPart; + return true; + } } } std::string aContName = getContextName(aSubShapeName); if(aContName.empty()) return false; - ResultPtr aCont = aDoc->findByName(aContName); + bool anUniqueContext = false; + ResultPtr aCont = aDoc->findByName(aContName, aSubShapeName, anUniqueContext); // possible this is body where postfix is added to distinguish several shapes on the same label int aSubShapeId = -1; // -1 means sub shape not found // for result body the name wihtout "_" has higher priority than with it: it is always added - if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) && + if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) && aContName == aSubShapeName) { size_t aPostIndex = aContName.rfind('_'); if (aPostIndex != std::string::npos) { - std::string aSubContName = aContName.substr(0, aPostIndex); - ResultPtr aSubCont = aDoc->findByName(aSubContName); + std::string anEmpty, aSubContName = aContName.substr(0, aPostIndex); + ResultPtr aSubCont = aDoc->findByName(aSubContName, anEmpty, anUniqueContext); if (aSubCont.get()) { try { std::string aNum = aContName.substr(aPostIndex + 1); @@ -689,18 +859,20 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, } + static const ResultPtr anEmpty; TopoDS_Shape aSelection; - switch (aType) + switch (aType) { case TopAbs_FACE: case TopAbs_WIRE: { - aSelection = findFaceByName(aSubShapeName, aDoc); + aSelection = findFaceByName(aSubShapeName, aDoc, aCont, anUniqueContext); } break; case TopAbs_EDGE: - { - const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName); + { + const TDF_Label& aLabel = + aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { @@ -711,7 +883,8 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, break; case TopAbs_VERTEX: { - const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName); + const TDF_Label& aLabel = + aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { @@ -725,7 +898,8 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, case TopAbs_SOLID: case TopAbs_SHELL: default: {//TopAbs_SHAPE - /// case when the whole sketch is selected, so, selection type is compound, but there is no value + /// case when the whole sketch is selected, so, + /// selection type is compound, but there is no value if (aCont.get() && aCont->shape().get()) { if (aCont->shape()->impl().ShapeType() == aType) { theCont = aCont; @@ -747,35 +921,51 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, return false; } } + if (!aSelection.IsNull() && + aSelection.ShapeType() != aType && aSelection.ShapeType() != TopAbs_COMPOUND) + aSelection.Nullify(); // to avoid selection of face instead of edge that is described by face // another try to find edge or vertex by faces std::list aListofNames; size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0; - if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) { - if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE + if ((aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) || + (!aSelection.IsNull() && aSelection.ShapeType() != aType)) { // edge by one face as example + if(aN >= 1) { TopTools_ListOfShape aList; std::list::iterator it = aListofNames.begin(); - for(; it != aListofNames.end(); it++){ - const TopoDS_Shape aFace = findFaceByName(*it, aDoc); + for(; it != aListofNames.end(); it++) { + ResultPtr aFaceContext = aCont; + if (it != aListofNames.begin()) { // there may be other context for different sub-faces + std::string aContName = getContextName(*it); + if(!aContName.empty()) { + aFaceContext = aDoc->findByName(aContName, *it, anUniqueContext); + } + } + TopoDS_Shape aFace = findFaceByName(*it, aDoc, aFaceContext, anUniqueContext); + if (aFace.IsNull() && aFaceContext.get() && + aFaceContext->groupName() == ModelAPI_ResultConstruction::group() ) { + // search the construction sub-elements for the intersection if they are in the tree + size_t aSlash = it->find("/"); + if (aSlash != std::string::npos) { + std::string aSubShapeName = it->substr(aSlash + 1); + aFace = findFaceByName(aSubShapeName, aDoc, aFaceContext, true); + } + } if(!aFace.IsNull()) - aList.Append(aFace); + aList.Append(aFace); } aSelection = findCommonShape(aType, aList); + //if (aSelection.IsNull() && aType == TopAbs_EDGE) { // try to find selection by neighbours + // aSelection = findCommonShapeByNB(aType, TopAbs_VERTEX, aList); + //} } } - if (!aSelection.IsNull()) {// Select it - std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); - aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); - theShapeToBeSelected = aShapeToBeSelected; - theCont = aCont; - return true; - } // in case of construction, there is no registered names for all sub-elements, // even for the main element; so, trying to find them by name (without "&" intersections) - if (aN == 0) { + if (aSelection.IsNull() && aN < 2) { size_t aConstrNamePos = aSubShapeName.find("/"); bool isFullName = aConstrNamePos == std::string::npos; - std::string aContrName = aContName; - ResultPtr aConstr = aDoc->findByName(aContrName); + std::string anEmpty, aContrName = aContName; + ResultPtr aConstr = aDoc->findByName(aContrName, anEmpty, anUniqueContext); if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) { theCont = aConstr; if (isFullName) { @@ -784,15 +974,22 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, return true; } // for sketch sub-elements selected - CompositeFeaturePtr aComposite = + CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aDoc->feature(aConstr)); if (aComposite.get()) { if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) { // collect all IDs in the name + bool isVertexByEdge = false; std::map anIDs; - if (!parseSubIndices(aComposite, aSubShapeName, - aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs)) - return false; + if (!parseSubIndices(aComposite, aSubShapeName, + aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs)) { + // there is a case when vertex is identified by one circle-edge (2253) + if (aType == TopAbs_VERTEX && + parseSubIndices(aComposite, aSubShapeName, "Edge", anIDs)) + isVertexByEdge = true; + else + return false; + } const int aSubNum = aComposite->numberOfSubs(); for(int a = 0; a < aSubNum; a++) { @@ -803,18 +1000,32 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, std::list >::const_iterator aRIt = aResults.cbegin(); // there may be many shapes (circle and center) for(; aRIt != aResults.cend(); aRIt++) { - ResultConstructionPtr aRes = + ResultConstructionPtr aRes = std::dynamic_pointer_cast(*aRIt); if (aRes) { int anOrientation = abs(anIDs[aCompID]); TopoDS_Shape aShape = aRes->shape()->impl(); if (anOrientation == 1) { - if (aType == aShape.ShapeType()) { + if (!isVertexByEdge && aType == aShape.ShapeType()) { theShapeToBeSelected = aRes->shape(); return true; + } else if (isVertexByEdge && aType != aShape.ShapeType()) { + // check that there is only one vertex produces by and circular edge + TopoDS_Shape aShape = aRes->shape()->impl(); + TopExp_Explorer anExp(aShape, TopAbs_VERTEX); + if (anExp.More()) + aShape = anExp.Current(); + anExp.Next(); + if (!anExp.More() || anExp.Current().IsSame(aShape)) { + std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aShape)); + theShapeToBeSelected = aShapeToBeSelected; + return true; + } } } else { // take first or second vertex of the edge TopoDS_Shape aShape = aRes->shape()->impl(); + if (aShape.ShapeType() == TopAbs_VERTEX) continue; TopExp_Explorer anExp(aShape, aType); for(; anExp.More() && anOrientation != 2; anOrientation--) anExp.Next(); @@ -832,11 +1043,12 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) { std::map anIDs; - if (!parseSubIndices(aComposite, aSubShapeName, + if (!parseSubIndices(aComposite, aSubShapeName, aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true)) return false; - NCollection_DataMap allCurves; // curves and orientations of edges + // curves and orientations of edges + NCollection_DataMap allCurves; const int aSubNum = aComposite->numberOfSubs(); for(int a = 0; a < aSubNum; a++) { int aSubID = aComposite->subFeatureId(a); @@ -845,7 +1057,7 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, const std::list >& aResults = aSub->results(); std::list >::const_iterator aRes; for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(*aRes); if (aConstr->shape() && aConstr->shape()->isEdge()) { const TopoDS_Shape& aResShape = aConstr->shape()->impl(); @@ -859,25 +1071,20 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, } } } - std::shared_ptr aFoundFace = findAppropriateFace(aConstr, allCurves); - if (aFoundFace.get()) { - if (aType == TopAbs_WIRE) { // just get a wire from face to have wire - TopExp_Explorer aWireExp(aFoundFace->impl(), TopAbs_WIRE); - if (aWireExp.More()) { - theShapeToBeSelected.reset(new GeomAPI_Shape); - theShapeToBeSelected->setImpl(new TopoDS_Shape(aWireExp.Current())); - } else return false; - } else { - theShapeToBeSelected = aFoundFace; - } + std::shared_ptr aFoundFW = + findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE); + if (aFoundFW.get()) { + theShapeToBeSelected = aFoundFW; return true; } - } else if (aType == TopAbs_WIRE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" + } else if (aType == TopAbs_WIRE) { + // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" std::map anIDs; if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs)) return false; - NCollection_DataMap allCurves; // curves and orientations of edges + // curves and orientations of edges + NCollection_DataMap allCurves; const int aSubNum = aComposite->numberOfSubs(); for(int a = 0; a < aSubNum; a++) { int aSubID = aComposite->subFeatureId(a); @@ -886,7 +1093,7 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, const std::list >& aResults = aSub->results(); std::list >::const_iterator aRes; for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = + ResultConstructionPtr aConstr = std::dynamic_pointer_cast(*aRes); if (aConstr->shape() && aConstr->shape()->isEdge()) { const TopoDS_Shape& aResShape = aConstr->shape()->impl(); @@ -900,14 +1107,40 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, } } } - std::shared_ptr aFoundFace = findAppropriateFace(aConstr, allCurves); - if (aFoundFace.get()) { - theShapeToBeSelected = aFoundFace; + std::shared_ptr aFoundFW = + findAppropriateFace(aConstr, allCurves, aType == TopAbs_WIRE); + if (aFoundFW.get()) { + theShapeToBeSelected = aFoundFW; return true; } } } } + } else if (aSelection.IsNull() && aN >= 2 && aType == TopAbs_VERTEX) { + // support of shape name as intersection separated by "&" + static std::string anEdgeType = "edge"; // for now it works only with su-edges + std::list::iterator aSubNames = aListofNames.begin(); + TopTools_ListOfShape aSubsList; + for(; aSubNames != aListofNames.end(); aSubNames++) { + std::string aSubName = *aSubNames; + std::shared_ptr aSubShapeFound; + std::shared_ptr aContextFound; + if (selectSubShape(anEdgeType, aSubName, theDoc, aSubShapeFound, aContextFound)) { + if (aSubShapeFound.get()) + aSubsList.Append(aSubShapeFound->impl()); + } + } + aSelection = findCommonShape(TopAbs_VERTEX, aSubsList); + } + if (!aSelection.IsNull()) { + // Select it (must be after N=0 checking, + // since for simple constructions the shape must be null) + std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); + aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection)); + theShapeToBeSelected = aShapeToBeSelected; + theCont = aCont; + return true; } + return false; }