1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: Model_SelectionNaming.cpp
4 // Created: 11 Aug 2015
5 // Author: Mikhail PONIKAROV
7 #include "Model_SelectionNaming.h"
8 #include "Model_Document.h"
9 #include <ModelAPI_Feature.h>
10 #include <Events_InfoMessage.h>
11 #include <ModelAPI_Session.h>
12 #include <ModelAPI_ResultPart.h>
13 #include <ModelAPI_ResultConstruction.h>
14 #include <ModelAPI_CompositeFeature.h>
16 #include <TopoDS_Iterator.hxx>
18 #include <TopoDS_Compound.hxx>
20 #include <TopExp_Explorer.hxx>
21 #include <TopTools_ListOfShape.hxx>
22 #include <TopTools_MapOfShape.hxx>
23 #include <TopTools_IndexedMapOfShape.hxx>
24 #include <TopTools_ListIteratorOfListOfShape.hxx>
25 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
26 #include <TopTools_MapIteratorOfMapOfShape.hxx>
27 #include <BRep_Builder.hxx>
28 #include <TNaming_Iterator.hxx>
29 #include <TNaming_Tool.hxx>
30 #include <TNaming_NamedShape.hxx>
31 #include <TNaming_Localizer.hxx>
32 #include <TDataStd_Name.hxx>
33 #include <TColStd_MapOfTransient.hxx>
37 #include <BRepTools.hxx>
40 Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab)
42 myLab = theSelectionLab;
45 std::string Model_SelectionNaming::getShapeName(
46 std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape)
49 // check if the subShape is already in DF
50 Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(theShape, myLab);
51 Handle(TDataStd_Name) anAttr;
52 if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document
53 if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
54 aName = TCollection_AsciiString(anAttr->Get()).ToCString();
56 const TDF_Label& aLabel = theDoc->findNamingName(aName);
57 static const std::string aPostFix("_");
58 TNaming_Iterator anItL(aNS);
59 for(int i = 1; anItL.More(); anItL.Next(), i++) {
60 if(anItL.NewShape() == theShape) {
62 aName += TCollection_AsciiString (i).ToCString();
72 bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
74 // a trivial case: F1 & F2, aNumber = 1, i.e. intersection gives 1 edge.
77 BB.MakeCompound(aCmp);
78 TopTools_ListIteratorOfListOfShape it(theAncestors);
79 for(;it.More();it.Next()) {
80 BB.Add(aCmp, it.Value());
81 theSMap.Add(it.Value());
84 TopTools_IndexedDataMapOfShapeListOfShape aMap2;
85 TopExp::MapShapesAndAncestors(aCmp, TopAbs_EDGE, TopAbs_FACE, aMap2);
86 for (int i = 1; i <= aMap2.Extent(); i++) {
87 const TopoDS_Shape& aKey = aMap2.FindKey(i);
88 const TopTools_ListOfShape& anAncestors = aMap2.FindFromIndex(i);
89 if(anAncestors.Extent() > 1) aNumber++;
91 if(aNumber > 1) return false;
95 std::string Model_SelectionNaming::namingName(ResultPtr& theContext,
96 std::shared_ptr<GeomAPI_Shape> theSubSh, const std::string& theDefaultName)
98 std::string aName("Undefined name");
99 if(!theContext.get() || theContext->shape()->isNull())
100 return !theDefaultName.empty() ? theDefaultName : aName;
101 if (!theSubSh.get() || theSubSh->isNull()) { // no subshape, so just the whole feature name
102 return theContext->data()->name();
104 TopoDS_Shape aSubShape = theSubSh->impl<TopoDS_Shape>();
105 TopoDS_Shape aContext = theContext->shape()->impl<TopoDS_Shape>();
107 if(aSubShape.ShapeType() == TopAbs_COMPOUND) {
108 BRepTools::Write(aSubShape, "Selection.brep");
109 BRepTools::Write(aContext, "Context.brep");
112 std::shared_ptr<Model_Document> aDoc =
113 std::dynamic_pointer_cast<Model_Document>(theContext->document());
115 // check if the subShape is already in DF
116 aName = getShapeName(aDoc, aSubShape);
117 if(aName.empty() ) { // not in the document!
118 TopAbs_ShapeEnum aType = aSubShape.ShapeType();
121 // the Face should be in DF. If it is not the case, it is an error ==> to be debugged
125 // name structure: F1 & F2 [& F3 & F4], where F1 & F2 the faces which gives the Edge in trivial case
126 // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces
127 if (BRep_Tool::Degenerated(TopoDS::Edge(aSubShape))) {
128 aName = "Degenerated_Edge";
131 TopTools_IndexedDataMapOfShapeListOfShape aMap;
132 TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap);
133 TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape
134 bool isTrivialCase(true);
135 if(aMap.Contains(aSubShape)) {
136 const TopTools_ListOfShape& anAncestors = aMap.FindFromKey(aSubShape);
137 // check that it is not a trivial case (F1 & F2: aNumber = 1)
138 isTrivialCase = isTrivial(anAncestors, aSMap);
141 TopTools_ListOfShape aListOfNbs;
142 if(!isTrivialCase) { // find Neighbors
143 TNaming_Localizer aLocalizer;
144 TopTools_MapOfShape aMap3;
145 aLocalizer.FindNeighbourg(aContext, aSubShape, aMap3);
146 //int n = aMap3.Extent();
147 TopTools_MapIteratorOfMapOfShape it(aMap3);
148 for(;it.More();it.Next()) {
149 const TopoDS_Shape& aNbShape = it.Key(); // neighbor edge
150 //TopAbs_ShapeEnum aType = aNbShape.ShapeType();
151 const TopTools_ListOfShape& aList = aMap.FindFromKey(aNbShape);
152 TopTools_ListIteratorOfListOfShape it2(aList);
153 for(;it2.More();it2.Next()) {
154 if(aSMap.Contains(it2.Value())) continue; // skip this Face
155 aListOfNbs.Append(it2.Value());
158 } // else a trivial case
160 // build name of the sub-shape Edge
161 for(int i=1; i <= aSMap.Extent(); i++) {
162 const TopoDS_Shape& aFace = aSMap.FindKey(i);
163 std::string aFaceName = getShapeName(aDoc, aFace);
167 aName += "&" + aFaceName;
169 TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
170 for (;itl.More();itl.Next()) {
171 std::string aFaceName = getShapeName(aDoc, itl.Value());
172 aName += "&" + aFaceName;
178 // name structure (Monifold Topology):
179 // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case.
180 // 2) F1 | F2 | F3 [|F4 [|Fn]] - redundant definition, but it should be kept as is to obtain safe recomputation
181 // 2) F1 | F2 - intersection of 2 faces definses a vertex - applicable for case
182 // when 1 faces is cylindrical, conical, spherical or revolution and etc.
183 // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell
184 // or compound of 2 open faces.
185 // 4) E1 | E2 - intesection of 2 edges defines a vertex - when we have a case of
186 // two independent edges (wire or compound)
187 // implemented 2 first cases
189 TopTools_IndexedDataMapOfShapeListOfShape aMap;
190 TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap);
191 const TopTools_ListOfShape& aList2 = aMap.FindFromKey(aSubShape);
192 TopTools_ListOfShape aList;
193 TopTools_MapOfShape aFMap;
195 TopTools_ListIteratorOfListOfShape itl2(aList2);
196 for (int i = 1;itl2.More();itl2.Next(),i++) {
197 if(aFMap.Add(itl2.Value()))
198 aList.Append(itl2.Value());
200 int n = aList.Extent();
201 bool isByFaces = n >= 3;
202 if(!isByFaces) { // open topology case or Compound case => via edges
203 TopTools_IndexedDataMapOfShapeListOfShape aMap;
204 TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_EDGE, aMap);
205 const TopTools_ListOfShape& aList22 = aMap.FindFromKey(aSubShape);
206 if(aList22.Extent() >= 2) { // regular solution
208 // bug! duplication; fix is below
210 TopTools_ListOfShape aListE;
211 TopTools_ListIteratorOfListOfShape itl2(aList22);
212 for (int i = 1;itl2.More();itl2.Next(),i++) {
213 if(aFMap.Add(itl2.Value()))
214 aListE.Append(itl2.Value());
217 TopTools_ListIteratorOfListOfShape itl(aListE);
218 for (int i = 1;itl.More();itl.Next(),i++) {
219 const TopoDS_Shape& anEdge = itl.Value();
220 std::string anEdgeName = getShapeName(aDoc, anEdge);
221 if (anEdgeName.empty()) { // edge is not in DS, trying by faces anyway
229 aName += "&" + anEdgeName;
232 else { // dangle vertex: if(aList22.Extent() == 1)
233 //it should be already in DF
237 TopTools_ListIteratorOfListOfShape itl(aList);
238 for (int i = 1;itl.More();itl.Next(),i++) {
239 const TopoDS_Shape& aFace = itl.Value();
240 std::string aFaceName = getShapeName(aDoc, aFace);
244 aName += "&" + aFaceName;
251 // aDoc->addNamingName(selectionLabel(), aName);
252 // the selected sub-shape will not be shared and as result it will not require registration
257 TopAbs_ShapeEnum translateType (const std::string& theType)
259 // map from the textual shape types to OCCT enumeration
260 static std::map<std::string, TopAbs_ShapeEnum> aShapeTypes;
262 if(aShapeTypes.size() == 0) {
263 aShapeTypes["compound"] = TopAbs_COMPOUND;
264 aShapeTypes["compounds"] = TopAbs_COMPOUND;
265 aShapeTypes["compsolid"] = TopAbs_COMPSOLID;
266 aShapeTypes["compsolids"] = TopAbs_COMPSOLID;
267 aShapeTypes["solid"] = TopAbs_SOLID;
268 aShapeTypes["solids"] = TopAbs_SOLID;
269 aShapeTypes["shell"] = TopAbs_SHELL;
270 aShapeTypes["shells"] = TopAbs_SHELL;
271 aShapeTypes["face"] = TopAbs_FACE;
272 aShapeTypes["faces"] = TopAbs_FACE;
273 aShapeTypes["wire"] = TopAbs_WIRE;
274 aShapeTypes["wires"] = TopAbs_WIRE;
275 aShapeTypes["edge"] = TopAbs_EDGE;
276 aShapeTypes["edges"] = TopAbs_EDGE;
277 aShapeTypes["vertex"] = TopAbs_VERTEX;
278 aShapeTypes["vertices"] = TopAbs_VERTEX;
279 aShapeTypes["COMPOUND"] = TopAbs_COMPOUND;
280 aShapeTypes["COMPOUNDS"] = TopAbs_COMPOUND;
281 aShapeTypes["COMPSOLID"] = TopAbs_COMPSOLID;
282 aShapeTypes["COMPSOLIDS"] = TopAbs_COMPSOLID;
283 aShapeTypes["SOLID"] = TopAbs_SOLID;
284 aShapeTypes["SOLIDS"] = TopAbs_SOLID;
285 aShapeTypes["SHELL"] = TopAbs_SHELL;
286 aShapeTypes["SHELLS"] = TopAbs_SHELL;
287 aShapeTypes["FACE"] = TopAbs_FACE;
288 aShapeTypes["FACES"] = TopAbs_FACE;
289 aShapeTypes["WIRE"] = TopAbs_WIRE;
290 aShapeTypes["WIRES"] = TopAbs_WIRE;
291 aShapeTypes["EDGE"] = TopAbs_EDGE;
292 aShapeTypes["EDGES"] = TopAbs_EDGE;
293 aShapeTypes["VERTEX"] = TopAbs_VERTEX;
294 aShapeTypes["VERTICES"] = TopAbs_VERTEX;
296 if (aShapeTypes.find(theType) != aShapeTypes.end())
297 return aShapeTypes[theType];
298 Events_InfoMessage("Model_SelectionNaming", "Shape type defined in XML is not implemented!").send();
302 const TopoDS_Shape getShapeFromNS(
303 const std::string& theSubShapeName, Handle(TNaming_NamedShape) theNS)
305 TopoDS_Shape aSelection;
306 std::string::size_type n = theSubShapeName.rfind('/');
307 if (n == std::string::npos) n = 0;
308 std::string aSubString = theSubShapeName.substr(n + 1);
309 n = aSubString.rfind('_');
310 if (n == std::string::npos) return aSelection;
311 aSubString = aSubString.substr(n+1);
312 int indx = atoi(aSubString.c_str());
314 TNaming_Iterator anItL(theNS);
315 for(int i = 1; anItL.More(); anItL.Next(), i++) {
317 return anItL.NewShape();
323 const TopoDS_Shape findFaceByName(
324 const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc)
327 std::string::size_type n, nb = theSubShapeName.rfind('/');
328 if (nb == std::string::npos) nb = 0;
329 std::string aSubString = theSubShapeName.substr(nb + 1);
330 n = aSubString.rfind('_');
331 if (n != std::string::npos) {
332 std::string aSubStr2 = aSubString.substr(0, n);
333 aSubString = theSubShapeName.substr(0, nb + 1);
334 aSubString = aSubString + aSubStr2;
336 aSubString = theSubShapeName;
338 const TDF_Label& aLabel = theDoc->findNamingName(aSubString);
339 if(aLabel.IsNull()) return aFace;
340 Handle(TNaming_NamedShape) aNS;
341 if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
342 aFace = getShapeFromNS(theSubShapeName, aNS);
347 size_t ParseName(const std::string& theSubShapeName, std::list<std::string>& theList)
349 std::string aName = theSubShapeName;
350 std::string aLastName;
351 size_t n1(0), n2(0); // n1 - start position, n2 - position of the delimiter
352 while ((n2 = aName.find('&', n1)) != std::string::npos) {
353 const std::string aName1 = aName.substr(n1, n2 - n1); //name of face
354 theList.push_back(aName1);
356 aLastName = aName.substr(n1);
358 if(!aLastName.empty())
359 theList.push_back(aLastName);
360 return theList.size();
363 const TopoDS_Shape findCommonShape(
364 const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList)
367 std::vector<TopTools_MapOfShape> aVec;
368 TopTools_MapOfShape aMap1, aMap2, aMap3, aMap4;
369 if(theList.Extent() > 1) {
370 aVec.push_back(aMap1);
371 aVec.push_back(aMap2);
373 if(theList.Extent() > 2)
374 aVec.push_back(aMap3);
375 if(theList.Extent() == 4)
376 aVec.push_back(aMap4);
379 TopTools_ListIteratorOfListOfShape it(theList);
380 for(int i = 0;it.More();it.Next(),i++) {
381 const TopoDS_Shape& aFace = it.Value();
383 TopExp_Explorer anExp (aFace, theType);
384 for(;anExp.More();anExp.Next()) {
385 const TopoDS_Shape& anEdge = anExp.Current();
386 if (!anEdge.IsNull())
387 aVec[i].Add(anExp.Current());
390 TopExp_Explorer anExp (aFace, TopAbs_VERTEX);
391 for(;anExp.More();anExp.Next()) {
392 const TopoDS_Shape& aVertex = anExp.Current();
393 if (!aVertex.IsNull())
394 aVec[i].Add(anExp.Current());
398 //trivial case: 2 faces
399 TopTools_ListOfShape aList;
400 TopTools_MapIteratorOfMapOfShape it2(aVec[0]);
401 for(;it2.More();it2.Next()) {
402 if(aVec[1].Contains(it2.Key())) {
404 if(theList.Extent() == 2)
407 aList.Append(it2.Key());
410 if(aList.Extent() && aVec.size() > 3) {// list of common edges ==> search ny neighbors
411 if(aVec[2].Extent() && aVec[3].Extent()) {
412 TopTools_ListIteratorOfListOfShape it(aList);
413 for(;it.More();it.Next()) {
414 const TopoDS_Shape& aCand = it.Value();
415 // not yet completelly implemented, to be rechecked
416 TopoDS_Vertex aV1, aV2;
417 TopExp::Vertices(TopoDS::Edge(aCand), aV1, aV2);
419 if(aVec[2].Contains(aV1)) aNum++;
420 else if(aVec[2].Contains(aV2)) aNum++;
421 if(aVec[3].Contains(aV1)) aNum++;
422 else if(aVec[3].Contains(aV2)) aNum++;
431 if(aList.Extent() && aVec.size() == 3) {
433 TopTools_ListIteratorOfListOfShape it(aList);
434 for(;it.More();it.Next()) {
435 const TopoDS_Shape& aCand = it.Value();
436 if(aVec[2].Contains(aCand)) {
445 std::string getContextName(const std::string& theSubShapeName)
448 std::string::size_type n = theSubShapeName.find('/');
449 if (n == std::string::npos) return theSubShapeName;
450 aName = theSubShapeName.substr(0, n);
454 /// Parses naming name of sketch sub-elements: takes indices and orientation
455 /// (if theOriented = true) from this name. Map theIDs constains indices ->
456 /// orientations and start/end vertices: negative is reversed, 2 - start, 3 - end
457 bool parseSubIndices(CompositeFeaturePtr theComp, //< to iterate names
458 const std::string& theName, const char* theShapeType,
459 std::map<int, int>& theIDs, const bool theOriented = false)
461 // collect all IDs in the name
462 std::map<std::string, int> aNames; // short name of sub -> ID of sub of theComp
463 const int aSubNum = theComp->numberOfSubs();
464 for(int a = 0; a < aSubNum; a++) {
465 FeaturePtr aSub = theComp->subFeature(a);
466 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
467 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
468 // there may be many shapes (circle and center)
469 for(; aRes != aResults.cend(); aRes++) {
470 ResultConstructionPtr aConstr =
471 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
473 aNames[Model_SelectionNaming::shortName(aConstr)] = theComp->subFeatureId(a);
478 size_t aPrevPos = theName.find("/") + 1, aLastNamePos;
479 bool isShape = false; // anyway the first world must be 'Vertex'
481 aLastNamePos = theName.find('-', aPrevPos);
482 std::string anID = theName.substr(aPrevPos, aLastNamePos - aPrevPos);
484 if (anID != theShapeType)
488 int anOrientation = 1; // default
489 if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
490 const char aSymbol = anID.back();
491 if (aSymbol == 'r') anOrientation = -1;
494 // check start/end symbols
495 if (anID.back() == 's') {
498 } else if (anID.back() == 'e') {
503 if (aNames.find(anID) != aNames.end()) {
504 theIDs[aNames[anID]] = anOrientation;
507 aPrevPos = aLastNamePos + 1;
508 } while (aLastNamePos != std::string::npos);
512 /// produces theEdge orientation relatively to theContext face
513 int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
515 if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE)
517 if (theEdge.Orientation() == TopAbs_FORWARD)
519 if (theEdge.Orientation() == TopAbs_REVERSED)
524 std::shared_ptr<GeomAPI_Shape> Model_SelectionNaming::findAppropriateFace(
525 std::shared_ptr<ModelAPI_Result>& theConstr,
526 NCollection_DataMap<Handle(Geom_Curve), int>& theCurves)
528 int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
529 int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
530 std::shared_ptr<GeomAPI_Shape> aResult;
531 ResultConstructionPtr aConstructionContext =
532 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theConstr);
533 if (!aConstructionContext.get())
535 for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
536 int aFound = 0, aNotFound = 0, aSameOrientation = 0;
538 TopoDS::Face(aConstructionContext->face(aFaceIndex)->impl<TopoDS_Shape>());
539 TopExp_Explorer anEdgesExp(aFace, TopAbs_EDGE);
540 TColStd_MapOfTransient alreadyProcessed; // to avoid counting edges with same curved (841)
541 for(; anEdgesExp.More(); anEdgesExp.Next()) {
542 TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
543 if (!anEdge.IsNull()) {
544 Standard_Real aFirst, aLast;
545 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
546 if (alreadyProcessed.Contains(aCurve))
548 alreadyProcessed.Add(aCurve);
549 if (theCurves.IsBound(aCurve)) {
551 int anOrient = theCurves.Find(aCurve);
552 if (anOrient != 0) { // extra comparision score is orientation
553 if (edgeOrientation(aFace, anEdge) == anOrient)
561 if (aFound + aNotFound != 0) {
562 if (aFound > aBestFound ||
563 (aFound == aBestFound && aSameOrientation > aBestOrient)) {
565 aBestOrient = aSameOrientation;
566 aResult = aConstructionContext->face(aFaceIndex);
573 std::string Model_SelectionNaming::shortName(
574 std::shared_ptr<ModelAPI_ResultConstruction>& theConstr, const int theEdgeVertexPos)
576 std::string aName = theConstr->data()->name();
577 // remove "-", "/" and "&" command-symbols
578 aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end());
579 aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end());
580 aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
581 // remove the last 's', 'e', 'f' and 'r' symbols: they are used as markers of start/end/forward/rewersed indicators
582 static const std::string aSyms("sefr");
583 while(aSyms.find(aName.back()) != std::string::npos) {
586 if (theEdgeVertexPos == 1) {
587 aName += "s"; // start
588 } else if (theEdgeVertexPos == 2) {
594 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
595 bool Model_SelectionNaming::selectSubShape(const std::string& theType,
596 const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc,
597 std::shared_ptr<GeomAPI_Shape>& theShapeToBeSelected, std::shared_ptr<ModelAPI_Result>& theCont)
599 if(theSubShapeName.empty() || theType.empty()) return false;
600 TopAbs_ShapeEnum aType = translateType(theType);
602 // check that it was selected in another document
603 size_t aSlash = theSubShapeName.find("/");
604 std::string aSubShapeName = theSubShapeName;
605 std::shared_ptr<Model_Document> aDoc = theDoc;
606 if (aSlash != std::string::npos) {
607 std::string aDocName = theSubShapeName.substr(0, aSlash);
608 DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
609 if (aDocName == aRootDoc->kind()) {
610 aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
612 for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) {
613 ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(
614 aRootDoc->object(ModelAPI_ResultPart::group(), a));
615 if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) {
616 aDoc = std::dynamic_pointer_cast<Model_Document>(aPart->partDoc());
620 if (aDoc != theDoc) { // so, the first word is the document name => reduce the string for the next manips
621 aSubShapeName = theSubShapeName.substr(aSlash + 1);
625 std::string aContName = getContextName(aSubShapeName);
626 if(aContName.empty()) return false;
627 ResultPtr aCont = aDoc->findByName(aContName);
628 // possible this is body where postfix is added to distinguish several shapes on the same label
629 int aSubShapeId = -1; // -1 means sub shape not found
630 if (!aCont.get() && aContName == aSubShapeName) {
631 size_t aPostIndex = aContName.rfind('_');
632 if (aPostIndex != std::string::npos) {
633 std::string aSubContName = aContName.substr(0, aPostIndex);
634 aCont = aDoc->findByName(aSubContName);
637 std::string aNum = aContName.substr(aPostIndex + 1);
638 aSubShapeId = std::stoi(aNum);
639 } catch (std::invalid_argument&) {
643 aContName = aSubContName;
649 TopoDS_Shape aSelection;
655 aSelection = findFaceByName(aSubShapeName, aDoc);
660 const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
661 if(!aLabel.IsNull()) {
662 Handle(TNaming_NamedShape) aNS;
663 if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
664 aSelection = getShapeFromNS(aSubShapeName, aNS);
671 const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
672 if(!aLabel.IsNull()) {
673 Handle(TNaming_NamedShape) aNS;
674 if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
675 aSelection = getShapeFromNS(aSubShapeName, aNS);
680 case TopAbs_COMPOUND:
681 case TopAbs_COMPSOLID:
684 default: {//TopAbs_SHAPE
685 /// case when the whole sketch is selected, so, selection type is compound, but there is no value
686 if (aCont.get() && aCont->shape().get()) {
687 if (aCont->shape()->impl<TopoDS_Shape>().ShapeType() == aType) {
690 } else if (aSubShapeId > 0) { // try to find sub-shape by the index
691 TopExp_Explorer anExp(aCont->shape()->impl<TopoDS_Shape>(), aType);
692 for(; aSubShapeId > 0 && anExp.More(); aSubShapeId--) {
696 std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
697 aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
698 theShapeToBeSelected = aShapeToBeSelected;
707 // another try to find edge or vertex by faces
708 std::list<std::string> aListofNames;
709 size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0;
710 if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) {
711 if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE
712 TopTools_ListOfShape aList;
713 std::list<std::string>::iterator it = aListofNames.begin();
714 for(; it != aListofNames.end(); it++){
715 const TopoDS_Shape aFace = findFaceByName(*it, aDoc);
719 aSelection = findCommonShape(aType, aList);
722 if (!aSelection.IsNull()) {// Select it
723 std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
724 aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
725 theShapeToBeSelected = aShapeToBeSelected;
729 // in case of construction, there is no registered names for all sub-elements,
730 // even for the main element; so, trying to find them by name (without "&" intersections)
732 size_t aConstrNamePos = aSubShapeName.find("/");
733 bool isFullName = aConstrNamePos == std::string::npos;
734 std::string aContrName = aContName;
735 ResultPtr aConstr = aDoc->findByName(aContrName);
736 if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
739 theShapeToBeSelected = aConstr->shape();
742 // for sketch sub-elements selected
743 CompositeFeaturePtr aComposite =
744 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aDoc->feature(aConstr));
745 if (aComposite.get()) {
746 if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
747 // collect all IDs in the name
748 std::map<int, int> anIDs;
749 if (!parseSubIndices(aComposite, aSubShapeName,
750 aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs))
753 const int aSubNum = aComposite->numberOfSubs();
754 for(int a = 0; a < aSubNum; a++) {
755 int aCompID = aComposite->subFeatureId(a);
756 if (anIDs.find(aCompID) != anIDs.end()) { // found the vertex/edge shape
757 FeaturePtr aSub = aComposite->subFeature(a);
758 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
759 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIt = aResults.cbegin();
760 // there may be many shapes (circle and center)
761 for(; aRIt != aResults.cend(); aRIt++) {
762 ResultConstructionPtr aRes =
763 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRIt);
765 int anOrientation = abs(anIDs[aCompID]);
766 TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
767 if (anOrientation == 1) {
768 if (aType == aShape.ShapeType()) {
769 theShapeToBeSelected = aRes->shape();
772 } else { // take first or second vertex of the edge
773 TopoDS_Shape aShape = aRes->shape()->impl<TopoDS_Shape>();
774 TopExp_Explorer anExp(aShape, aType);
775 for(; anExp.More() && anOrientation != 2; anOrientation--)
778 std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
779 aShapeToBeSelected->setImpl(new TopoDS_Shape(anExp.Current()));
780 theShapeToBeSelected = aShapeToBeSelected;
788 // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
789 } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) {
790 std::map<int, int> anIDs;
791 if (!parseSubIndices(aComposite, aSubShapeName,
792 aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true))
795 NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
796 const int aSubNum = aComposite->numberOfSubs();
797 for(int a = 0; a < aSubNum; a++) {
798 int aSubID = aComposite->subFeatureId(a);
799 if (anIDs.find(aSubID) != anIDs.end()) {
800 FeaturePtr aSub = aComposite->subFeature(a);
801 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
802 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
803 for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
804 ResultConstructionPtr aConstr =
805 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
806 if (aConstr->shape() && aConstr->shape()->isEdge()) {
807 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
808 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
809 if (!anEdge.IsNull()) {
810 Standard_Real aFirst, aLast;
811 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
812 allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
818 std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
819 if (aFoundFace.get()) {
820 if (aType == TopAbs_WIRE) { // just get a wire from face to have wire
821 TopExp_Explorer aWireExp(aFoundFace->impl<TopoDS_Shape>(), TopAbs_WIRE);
822 if (aWireExp.More()) {
823 theShapeToBeSelected.reset(new GeomAPI_Shape);
824 theShapeToBeSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
827 theShapeToBeSelected = aFoundFace;
831 } else if (aType == TopAbs_WIRE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
832 std::map<int, int> anIDs;
833 if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs))
836 NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
837 const int aSubNum = aComposite->numberOfSubs();
838 for(int a = 0; a < aSubNum; a++) {
839 int aSubID = aComposite->subFeatureId(a);
840 if (anIDs.find(aSubID) != anIDs.end()) {
841 FeaturePtr aSub = aComposite->subFeature(a);
842 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
843 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
844 for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
845 ResultConstructionPtr aConstr =
846 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
847 if (aConstr->shape() && aConstr->shape()->isEdge()) {
848 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
849 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
850 if (!anEdge.IsNull()) {
851 Standard_Real aFirst, aLast;
852 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
853 allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
859 std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
860 if (aFoundFace.get()) {
861 theShapeToBeSelected = aFoundFace;