X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_SelectionNaming.cpp;h=1b1c51e9ec70901a076e22a19d15503fb263dae5;hb=b73fb7468bea81901dbeed8e229d742f788ec282;hp=68311d6f24a7bf0dd69984589568dedf3ad29398;hpb=b355b9b8ffa5fad1240e5c322301744b32d4534a;p=modules%2Fshaper.git diff --git a/src/Model/Model_SelectionNaming.cpp b/src/Model/Model_SelectionNaming.cpp index 68311d6f2..1b1c51e9e 100644 --- a/src/Model/Model_SelectionNaming.cpp +++ b/src/Model/Model_SelectionNaming.cpp @@ -1,13 +1,35 @@ -// 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 +#include +#include +#include +#include +#include #include #include @@ -25,62 +47,139 @@ #include #include #include +#include #include -#include -#include #include #include +#include #ifdef DEB_NAMING #include #endif -/// added to the index in the packed map to signalize that the vertex of edge is selected -/// (multiplied by the index of the edge) -static const int kSTART_VERTEX_DELTA = 1000000; - 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) + std::shared_ptr theDoc, const TopoDS_Shape& theShape, + 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(); - if(!aName.empty()) { - const TDF_Label& aLabel = theDoc->findNamingName(aName); - /* MPV: the same shape with the same name may be duplicated on different labels (selection of the same construction object) - if(!aLabel.IsEqual(aNS->Label())) { - //aName.erase(); //something is wrong, to be checked!!! - aName += "_SomethingWrong"; - return 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 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; } - - bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap) { // a trivial case: F1 & F2, aNumber = 1, i.e. intersection gives 1 edge. @@ -89,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()); } @@ -104,14 +205,158 @@ 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) + 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::dynamic_pointer_cast(theContext->document()); + if (theContext->groupName() == ModelAPI_ResultPart::group()) { + ResultPartPtr aPart = std::dynamic_pointer_cast(theContext); + int 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 - return theContext->data()->name(); + // but if it is in another Part, add this part name + std::string aPartName; + if (theAnotherDoc) + aPartName = theContext->document()->kind() + "/"; // PartSet + return aPartName + theContext->data()->name(); } TopoDS_Shape aSubShape = theSubSh->impl(); TopoDS_Shape aContext = theContext->shape()->impl(); @@ -121,25 +366,24 @@ std::string Model_SelectionNaming::namingName(ResultPtr& theContext, BRepTools::Write(aContext, "Context.brep"); } #endif - std::shared_ptr aDoc = - std::dynamic_pointer_cast(theContext->document()); + aName = getShapeName(aDoc, aSubShape, theContext, theAnotherDoc, + theContext->shape()->isEqual(theSubSh)); - // check if the subShape is already in DF - aName = getShapeName(aDoc, aSubShape); 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 @@ -147,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; @@ -164,104 +411,95 @@ 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); - 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()); - 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); - 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); + std::string aFaceName = getShapeName(aDoc, aFace, theContext, theAnotherDoc, false); if(i == 1) aName = aFaceName; - else + else aName += "&" + aFaceName; } } } break; } - // register name - // aDoc->addNamingName(selectionLabel(), aName); - // the selected sub-shape will not be shared and as result it will not require registration } return aName; } @@ -307,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; } @@ -315,13 +554,20 @@ 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('_'); - if (n == std::string::npos) return aSelection; - aSubString = aSubString.substr(n+1); - int 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); for(int i = 1; anItL.More(); anItL.Next(), i++) { @@ -329,25 +575,27 @@ 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); - n = aSubString.rfind('_'); - if (n != std::string::npos) { - std::string aSubStr2 = aSubString.substr(0, n); - aSubString = theSubShapeName.substr(0, nb + 1); - aSubString = aSubString + aSubStr2; - } else - aSubString = theSubShapeName; - - const TDF_Label& aLabel = theDoc->findNamingName(aSubString); + std::string aSubString = theSubShapeName; + + 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, + theContextIsUnique ? theDetectedContext : anEmpty); + } + } if(aLabel.IsNull()) return aFace; Handle(TNaming_NamedShape) aNS; if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { @@ -359,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); } @@ -372,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 @@ -479,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); @@ -499,17 +665,18 @@ bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names } else { int anOrientation = 1; // default if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r' - const char aSymbol = anID.back(); - if (aSymbol == 'r') anOrientation = -1; - anID.pop_back(); + std::string::iterator aSymbol = anID.end() - 1; + if (*aSymbol == 'r') anOrientation = -1; + anID.erase(aSymbol); // remove last symbol } // check start/end symbols - if (anID.back() == 's') { + std::string::iterator aBack = anID.end() - 1; + if (*aBack == 's') { anOrientation *= 2; - anID.pop_back(); - } else if (anID.back() == 'e') { + anID.erase(aBack); // remove last symbol + } else if (*aBack == 'e') { anOrientation *= 3; - anID.pop_back(); + anID.erase(aBack); // remove last symbol } if (aNames.find(anID) != aNames.end()) { @@ -524,59 +691,75 @@ bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names /// produces theEdge orientation relatively to theContext face int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge) { - if (theContext.ShapeType() != TopAbs_FACE) + if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE) return 0; - TopoDS_Face aContext = TopoDS::Face(theContext); - 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); + } + } } } } @@ -591,11 +774,15 @@ 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"); - while(aSyms.find(aName.back()) != std::string::npos) { - aName.pop_back(); + std::string::iterator aSuffix = aName.end() - 1; + while(aSyms.find(*aSuffix) != std::string::npos) { + --aSuffix; } + aName.erase(aSuffix + 1, aName.end()); + if (theEdgeVertexPos == 1) { aName += "s"; // start } else if (theEdgeVertexPos == 2) { @@ -605,47 +792,103 @@ 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) { if(theSubShapeName.empty() || theType.empty()) return false; TopAbs_ShapeEnum aType = translateType(theType); - std::string aContName = getContextName(theSubShapeName); + + // check that it was selected in another document + size_t aSlash = theSubShapeName.find("/"); + std::string aSubShapeName = theSubShapeName; + 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); + } else { + for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) { + ResultPartPtr aPart = std::dynamic_pointer_cast( + 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 + 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 = theDoc->findByName(aContName); - //if(!aCont.get() || aCont->shape()->isNull()) return false; - //TopoDS_Shape aContext = aCont->shape()->impl(); - //TopAbs_ShapeEnum aContType = aContext.ShapeType(); - //if(aType <= aContType) return false; // not applicable + 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())*/) && + aContName == aSubShapeName) { + size_t aPostIndex = aContName.rfind('_'); + if (aPostIndex != std::string::npos) { + 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); + aSubShapeId = std::stoi(aNum); + } catch (std::invalid_argument&) { + aSubShapeId = -1; + } + if (aSubShapeId > 0) { + aContName = aSubContName; + aCont = aSubCont; + } + } + } + } + static const ResultPtr anEmpty; TopoDS_Shape aSelection; - switch (aType) + switch (aType) { case TopAbs_FACE: + case TopAbs_WIRE: { - aSelection = findFaceByName(theSubShapeName, theDoc); + aSelection = findFaceByName(aSubShapeName, aDoc, aCont, anUniqueContext); } break; case TopAbs_EDGE: - { - const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName); + { + const TDF_Label& aLabel = + aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aSelection = getShapeFromNS(theSubShapeName, aNS); + aSelection = getShapeFromNS(aSubShapeName, aNS); } } } break; case TopAbs_VERTEX: { - const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName); + const TDF_Label& aLabel = + aDoc->findNamingName(aSubShapeName, anUniqueContext ? aCont : anEmpty); if(!aLabel.IsNull()) { Handle(TNaming_NamedShape) aNS; if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) { - aSelection = getShapeFromNS(theSubShapeName, aNS); + aSelection = getShapeFromNS(aSubShapeName, aNS); } } } @@ -654,63 +897,99 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, case TopAbs_COMPSOLID: case TopAbs_SOLID: case TopAbs_SHELL: - case TopAbs_WIRE: default: {//TopAbs_SHAPE - /// case when the whole sketch is selected, so, selection type is compound, but there is no value - if (aCont.get() && aCont->shape().get() && - aCont->shape()->impl().ShapeType() == aType) { - theCont = aCont; - return true; + /// 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; + return true; + } else if (aSubShapeId > 0) { // try to find sub-shape by the index + TopExp_Explorer anExp(aCont->shape()->impl(), aType); + for(; aSubShapeId > 1 && anExp.More(); aSubShapeId--) { + anExp.Next(); + } + if (anExp.More()) { + std::shared_ptr aShapeToBeSelected(new GeomAPI_Shape()); + aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current())); + theShapeToBeSelected = aShapeToBeSelected; + theCont = aCont; + return true; + } + } } 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(theSubShapeName, 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 + size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0; + 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, theDoc); + 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) { - size_t aConstrNamePos = theSubShapeName.find("/"); + if (aSelection.IsNull() && aN < 2) { + size_t aConstrNamePos = aSubShapeName.find("/"); bool isFullName = aConstrNamePos == std::string::npos; - std::string aContrName = - isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos); - ResultPtr aConstr = theDoc->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) { - theShapeToBeSelected = aConstr->shape(); + // For the full construction selection shape must be empty. + //theShapeToBeSelected = aConstr->shape(); return true; } // for sketch sub-elements selected - CompositeFeaturePtr aComposite = - std::dynamic_pointer_cast(theDoc->feature(aConstr)); + 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, theSubShapeName, - 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++) { @@ -721,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(); @@ -747,12 +1040,15 @@ bool Model_SelectionNaming::selectSubShape(const std::string& theType, } } } - } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r" + // 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, theSubShapeName, "Face", anIDs, true)) + 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); @@ -761,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(); @@ -775,14 +1071,76 @@ 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 (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; + + // 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); + if (anIDs.find(aSubID) != anIDs.end()) { + FeaturePtr aSub = aComposite->subFeature(a); + const std::list >& aResults = aSub->results(); + std::list >::const_iterator aRes; + for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + std::dynamic_pointer_cast(*aRes); + if (aConstr->shape() && aConstr->shape()->isEdge()) { + const TopoDS_Shape& aResShape = aConstr->shape()->impl(); + TopoDS_Edge anEdge = TopoDS::Edge(aResShape); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1); + } + } + } + } + } + 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; }