]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_ResultConstruction.cpp
Salome HOME
Update due to the coding rules
[modules/shaper.git] / src / Model / Model_ResultConstruction.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include <Model_ResultConstruction.h>
22
23 #include <Model_Data.h>
24 #include <ModelAPI_CompositeFeature.h>
25 #include <Model_SelectionNaming.h>
26 #include <ModelAPI_Events.h>
27 #include <Config_PropManager.h>
28 #include <GeomAPI_PlanarEdges.h>
29 #include <GeomAPI_Shape.h>
30 #include <GeomAlgoAPI_SketchBuilder.h>
31 #include <Events_Loop.h>
32
33 #include <TDF_Reference.hxx>
34 #include <TDF_ChildIterator.hxx>
35 #include <TNaming_NamedShape.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TDataStd_Integer.hxx>
38 #include <TDataStd_IntPackedMap.hxx>
39 #include <TDataStd_Name.hxx>
40 #include <TDataStd_UAttribute.hxx>
41 #include <TColStd_MapOfTransient.hxx>
42 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
43 #include <BRep_Tool.hxx>
44 #include <BRep_Builder.hxx>
45 #include <TopoDS.hxx>
46 #include <TopoDS_Shape.hxx>
47 #include <TopoDS_Edge.hxx>
48 #include <TopoDS_Vertex.hxx>
49 #include <TopExp_Explorer.hxx>
50 #include <TNaming_Tool.hxx>
51 #include <Precision.hxx>
52
53 // identifier that it is full result selected, but in external document (for internal index is 0)
54 Standard_GUID kFULL_RESULT_ID("ee87e529-da6f-46af-be25-5e0fefde52f7");
55
56
57 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
58                                        std::string& theDefault)
59 {
60   theSection = "Visualization";
61   theName = "result_construction_color";
62   theDefault = DEFAULT_COLOR();
63 }
64
65 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
66 {
67   if (myShape != theShape) {
68     if (!theShape.get() || !theShape->isEqual(myShape)) {
69         static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
70         ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
71         if (theShape.get()) {
72           myFacesUpToDate = false;
73           myFaces.clear();
74         }
75     }
76     myShape = theShape;
77   }
78 }
79
80 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
81 {
82   return myShape;
83 }
84
85 Model_ResultConstruction::Model_ResultConstruction()
86 {
87   myIsInHistory = true;
88   myIsInfinite = false;
89   myFacesUpToDate = false;
90 }
91
92 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
93 {
94   myIsInHistory = isInHistory;
95 }
96
97 int Model_ResultConstruction::facesNum(const bool theUpdateNaming)
98 {
99   if (!myFacesUpToDate) {
100     std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
101       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(myShape);
102     if (aWirePtr.get()) {
103       std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
104       GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
105         aWirePtr->norm(), aWirePtr, aFaces);
106       std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFIter = aFaces.begin();
107       for(; aFIter != aFaces.end(); aFIter++) {
108         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
109         if (aFace.get() && !aFace->isNull())
110           myFaces.push_back(aFace);
111       }
112     }
113     myFacesUpToDate = true;
114
115     // update all the faces and sub-elements in the naming structure
116     if (theUpdateNaming) {
117       DocumentPtr anEmptyExt;
118       bool aNotExt = false;
119       TDF_Label aDataLab = startLabel(anEmptyExt, aNotExt);
120       TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
121       for(; aSubsIter.More(); aSubsIter.Next()) {
122         const TDF_Label aLab = aSubsIter.Value();
123         if (aLab.Tag() == 1) // skip the root shape label
124           continue;
125         Handle(TNaming_NamedShape) aNS;
126         if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
127           update(aLab.Tag() - 1, anEmptyExt, aNotExt);
128         }
129       }
130     }
131   }
132   return int(myFaces.size());
133 }
134
135 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
136 {
137   return myFaces[theIndex];
138 }
139
140 bool Model_ResultConstruction::isInfinite()
141 {
142   return myIsInfinite;
143 }
144
145 void Model_ResultConstruction::setInfinite(const bool theInfinite)
146 {
147   myIsInfinite = theInfinite;
148 }
149
150 void Model_ResultConstruction::setIsConcealed(const bool theValue)
151 {
152   // do nothing: the construction element is never concealed
153 }
154
155 static const int kSTART_VERTEX_DELTA = 1000000;
156
157 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, std::string theFullName,
158   const int theID, std::shared_ptr<Model_Document> theDoc,
159   bool theSelectionMode)
160 {
161   TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
162   TNaming_Builder aBuilder(aLab);
163   // wire never happens as sub, it must be generated to be found
164   // by SelectionNaming TNaming_Tool::NamedShape
165   if (theSelectionMode && theShape.ShapeType() != TopAbs_WIRE)
166     aBuilder.Select(theShape, theShape);
167   else
168     aBuilder.Generated(theShape);
169
170   theDoc->addNamingName(aLab, theFullName);
171   TDataStd_Name::Set(aLab, theFullName.c_str());
172 }
173
174 #include <TopTools_OrientedShapeMapHasher.hxx>
175
176 // generates a full-name for sub-element of the composite feature (sketch)
177 std::string fullName(CompositeFeaturePtr theComposite, const TopoDS_Shape& theSubShape,
178   Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)())
179 {
180   TopAbs_ShapeEnum aShapeType = theSubShape.ShapeType();
181   gp_Pnt aVertexPos;
182   NCollection_Map<TopoDS_Edge> allExactEdges;
183   NCollection_DataMap<TopoDS_Edge, TopoDS_Edge, Model_EdgesHasher> allEdges;
184   NCollection_DataMap<Handle(Geom_Curve), TopoDS_Edge, Model_CurvesHasher> allCurves;
185   /// map from edges from theSubShape to the found corresponded indices of the sub-components
186   NCollection_DataMap<TopoDS_Edge, NCollection_List<int>, TopTools_OrientedShapeMapHasher>
187     anEdgesCorrespondence;
188   if (aShapeType == TopAbs_VERTEX) { // compare positions
189     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(theSubShape));
190   } else {
191     for(TopExp_Explorer anEdgeExp(theSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
192       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
193       allExactEdges.Add(anEdge);
194       allEdges.Bind(anEdge, anEdge);
195       Standard_Real aFirst, aLast;
196       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
197       allCurves.Bind(aCurve, anEdge);
198       anEdgesCorrespondence.Bind(anEdge, NCollection_List<int>());
199     }
200   }
201   std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
202   std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
203   TColStd_PackedMapOfInteger aRefs; // indixes of sub-elements in composite
204
205
206   const int aSubNum = theComposite->numberOfSubs();
207   for(int a = 0; a < aSubNum; a++) {
208     FeaturePtr aSub = theComposite->subFeature(a);
209     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
210     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
211     // there may be many shapes (circle and center): register if at least one is in selection
212     for(; aRes != aResults.cend(); aRes++) {
213       ResultConstructionPtr aConstr =
214         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
215       if (!aConstr->shape()) {
216         continue;
217       }
218       if (aShapeType == TopAbs_VERTEX) {
219         if (aConstr->shape()->isVertex()) { // compare vertices positions
220           const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
221           gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
222           if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
223             aRefs.Add(theComposite->subFeatureId(a));
224             aSubNames[theComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
225           }
226         } else { // get first or last vertex of the edge: last is stored with additional delta
227           const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
228           int aDelta = kSTART_VERTEX_DELTA;
229           for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
230             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
231             if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
232               aRefs.Add(aDelta + theComposite->subFeatureId(a));
233               aSubNames[aDelta + theComposite->subFeatureId(a)] =
234                 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
235               break;
236             }
237             aDelta += kSTART_VERTEX_DELTA;
238           }
239         }
240       } else {
241         if (aConstr->shape()->isEdge()) {
242           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
243           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
244           if (anEdge.IsNull())
245             continue;
246           if (allEdges.IsBound(anEdge)) {
247             anEdgesCorrespondence.ChangeFind(allEdges.Find(anEdge)).Append(a);
248           } else {
249             Standard_Real aFirst, aLast;
250             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
251             if (allCurves.IsBound(aCurve)) {
252               anEdgesCorrespondence.ChangeFind(allCurves.Find(aCurve)).Append(a);
253             }
254           }
255         }
256       }
257     }
258   }
259
260   if (aShapeType != TopAbs_VERTEX) { // get best candidates from the correspondances
261     NCollection_DataMap<TopoDS_Edge, NCollection_List<int>, TopTools_OrientedShapeMapHasher>
262       ::Iterator aCorIter(anEdgesCorrespondence);
263     for(; aCorIter.More(); aCorIter.Next()) {
264       TopoDS_Edge anOrig = aCorIter.Key();
265       NCollection_List<int>::Iterator aCandidate(aCorIter.Value());
266       int aBestScore = 0;
267       int aBestIndex = -1;
268       ResultConstructionPtr aBestConstr;
269       for(; aCandidate.More(); aCandidate.Next()) {
270         FeaturePtr aSub = theComposite->subFeature(aCandidate.Value());
271         const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
272         std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
273         // there may be many shapes (circle and center): register if at least one is in selection
274         for(; aRes != aResults.cend(); aRes++) {
275           ResultConstructionPtr aConstr =
276             std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
277           if (!aConstr->shape() || !aConstr->shape()->isEdge())
278             continue;
279           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
280           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
281           if (anEdge.IsNull())
282             continue;
283           // detect score of the candidate
284           int aScore = 0;
285           if (anEdge.IsEqual(anOrig))
286             aScore = 10;
287           else if (anEdge.IsSame(anOrig))
288             aScore = 9;
289           else {
290             Standard_Real aFirst, aLast;
291             Handle(Geom_Curve) anOrigCurve = BRep_Tool::Curve(anOrig, aFirst, aLast);
292             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
293             if (anOrigCurve == aCurve) {
294               if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) {
295                 aScore = 8;
296               } else {
297                 aScore = 6;
298               }
299             } else {
300               if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) {
301                 aScore = 7;
302               } else if (Model_CurvesHasher::IsEqual(aCurve, anOrigCurve)) {
303                 aScore = 5;
304               }
305             }
306           }
307           if (aScore > aBestScore) {
308             aBestIndex = aCandidate.Value();
309             aBestScore = aScore;
310             aBestConstr = aConstr;
311           }
312         }
313       }
314       if (aBestIndex >= 0) {
315         int anID = theComposite->subFeatureId(aBestIndex);
316         aRefs.Add(anID);
317         aSubNames[anID] = Model_SelectionNaming::shortName(aBestConstr);
318         if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
319           // add edges to sub-label to support naming for edges selection
320           int anOrient = Model_SelectionNaming::edgeOrientation(theSubShape, anOrig);
321           anOrientations[anID] = anOrient;
322         }
323       }
324     }
325   }
326   std::stringstream aName;
327   // #1839 : do not store name of the feature in the tree, since this name could be changed
328   if (theSubShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole construction result
329     if (theSubShape.ShapeType() == TopAbs_FACE) aName<<"Face";
330     else if (theSubShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
331     else if (theSubShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
332     else if (theSubShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
333
334     // make a composite name from all sub-elements indexes: "1_2_3_4"
335     TColStd_MapIteratorOfPackedMapOfInteger aRef(aRefs);
336     for(; aRef.More(); aRef.Next()) {
337       aName<<"-"<<aSubNames[aRef.Key()];
338       if (anOrientations.find(aRef.Key()) != anOrientations.end()) {
339         if (anOrientations[aRef.Key()] == 1)
340           aName<<"f";
341         else if (anOrientations[aRef.Key()] == -1)
342           aName<<"r";
343       }
344     }
345   }
346   if (!theRefs.IsNull()) {
347     Handle(TColStd_HPackedMapOfInteger) aMap = new TColStd_HPackedMapOfInteger(aRefs);
348     theRefs->ChangeMap(aMap);
349   }
350   return aName.str();
351 }
352
353 // stores shape and name on sub-label of the main stored shape
354 static void saveSubName(CompositeFeaturePtr theComposite,
355   TDF_Label& theLab, const bool isSelectionMode, TopoDS_Shape aSub,
356   std::shared_ptr<Model_Document> theDoc, std::string theFullName)
357 {
358   // trying to store the edge of composite result, not sketch sub as it is
359   if (aSub.ShapeType() == TopAbs_EDGE) {
360     ResultPtr aRes = theComposite->firstResult();
361     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<Model_ResultConstruction>(aRes);
362     if (aConstr.get()) {
363       Standard_Real aSubFirst, aSubLast;
364       TopoDS_Edge aSubEdge = TopoDS::Edge(aSub);
365       Handle(Geom_Curve) aSubCurve = BRep_Tool::Curve(aSubEdge, aSubFirst, aSubLast);
366       for(int aFaceIndex = 0; aFaceIndex < aConstr->facesNum(); aFaceIndex++) {
367         GeomShapePtr aGFace = aConstr->face(aFaceIndex);
368         TopoDS_Shape aFace = aGFace->impl<TopoDS_Shape>();
369         for(TopExp_Explorer anExp(aFace, TopAbs_EDGE); anExp.More(); anExp.Next()) {
370           TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current());
371           Standard_Real aFirst, aLast;
372           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
373           if (Model_CurvesHasher::IsEqual(aCurve, aSubCurve) &&
374               ((fabs(aFirst - aSubFirst) < 1.e-9 &&  fabs(aLast - aSubLast) < 1.e-9)) ||
375               (fabs(aFirst - aSubLast) < 1.e-9 &&  fabs(aLast - aSubFirst) < 1.e-9)) {
376             aSub = anEdge;
377             break;
378           }
379         }
380       }
381     }
382   }
383
384   TNaming_Builder aBuilder(theLab);
385   if (isSelectionMode)
386     aBuilder.Select(aSub, aSub);
387   else
388     aBuilder.Generated(aSub);
389   theDoc->addNamingName(theLab, theFullName.c_str());
390   TDataStd_Name::Set(theLab, theFullName.c_str());
391 }
392
393
394 TDF_Label Model_ResultConstruction::startLabel(
395   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theExternal)
396 {
397   theExternal = theExtDoc.get() && theExtDoc != document();
398   if (theExternal) { // external document is used
399     std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theExtDoc);
400     return aDoc->extConstructionsLabel();
401   }
402   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
403   return aData->label();
404 }
405
406 int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSubShape,
407   const std::shared_ptr<ModelAPI_Document> theExtDoc, const int theIndex)
408 {
409   int anIndex; // resulting index of the sub-label
410   TopoDS_Shape aSubShape;
411   if (theSubShape.get()) {
412     aSubShape = theSubShape->impl<TopoDS_Shape>();
413   } else if (shape().get()) {
414     aSubShape = shape()->impl<TopoDS_Shape>();
415   }
416   // if external document requires this selection, put the naming structures to this doc
417   // to support the naming mechanism in this document correctly
418   bool anExternal;
419   TDF_Label aDataLab = startLabel(theExtDoc, anExternal);
420   if (theIndex == -1) {
421     anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape
422
423     if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext)
424       // iterate all the already presented shapes to see the same
425       TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
426       for(; aSubsIter.More(); aSubsIter.Next()) {
427         const TDF_Label aLab = aSubsIter.Value();
428         if (aLab.Tag() == 1) // skip the root shape label
429           continue;
430         Handle(TNaming_NamedShape) aNS;
431         if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
432           if (aNS->Get().IsSame(aSubShape)) {
433             return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do
434           }
435         }
436         anIndex = aLab.Tag(); // searching for the latest index
437       }
438       anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all
439     }
440   } else {
441     anIndex = theIndex + 1;
442   }
443
444   // set the naming structure at index
445   TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True);
446
447   // if the subshape is part of a result face, select the whole face (#1997)
448   bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
449   if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
450     // but before check that sub-vertex correctly detected as intersection of sketch edges (#2389)
451     int anEdgesNum = 2;
452     if (aSubShape.ShapeType() == TopAbs_VERTEX) {
453       anEdgesNum = 0;
454       ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
455       FeaturePtr aThisFeature = document()->feature(aThisPtr);
456       CompositeFeaturePtr aComposite =
457         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
458       if (aComposite.get()) {
459         const int aSubNum = aComposite->numberOfSubs();
460         for(int a = 0; a < aSubNum; a++) {
461           int aSubID = aComposite->subFeatureId(a);
462           FeaturePtr aSub = aComposite->subFeature(a);
463           const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
464           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
465           for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
466             ResultConstructionPtr aConstr =
467               std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
468             if (aConstr->shape() && aConstr->shape()->isEdge()) {
469               TopoDS_Shape aResShape = aConstr->shape()->impl<TopoDS_Shape>();
470               for(TopExp_Explorer anExp(aResShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
471                 if (aSubShape.IsSame(anExp.Current())) {
472                   anEdgesNum++;
473                   break;
474                 }
475               }
476             }
477           }
478         }
479       }
480     }
481     if (anEdgesNum > 1) {
482       for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
483         TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
484         for(; anExp.More(); anExp.Next()) {
485           if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
486             // here just store the face index (to update face if update of edge is needed)
487             TNaming_Builder aBuilder(aLab);
488             aBuilder.Select(aSubShape, aSubShape);
489             int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
490             TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
491             isSelectionMode = true;
492             break;
493           }
494         }
495       }
496     }
497   }
498
499   // external full result is not identified by index == 0, so, add here the ID
500   if (!theSubShape.get()) {
501     TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID);
502     // empty NS
503     TNaming_Builder aBuilder(aLab);
504     // store all sub-faces naming since faces may be used for extrusion, where all edges are needed
505     Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab);
506     std::list<int> aFacesIndexes;
507     for(int a = 0; a < facesNum(); a++) {
508       anIndices->Add(select(face(a), theExtDoc, -1));
509     }
510     return anIndex - 1;
511   }
512
513   { // this to have erased Builder after the shape was generated (NS on this label may be changed)
514     TNaming_Builder aBuilder(aLab);
515     if (aSubShape.IsNull()) {
516       return anIndex - 1; // just keep empty named shape
517     }
518     // wire never happens as sub, it must be generated to be found
519     // by SelectionNaming TNaming_Tool::NamedShape
520     if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) {
521       aBuilder.Select(aSubShape, aSubShape);
522     } else {
523       aBuilder.Generated(aSubShape);
524     }
525   }
526
527   if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection
528     return anIndex - 1;
529   }
530   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
531   FeaturePtr aThisFeature = document()->feature(aThisPtr);
532   CompositeFeaturePtr aComposite =
533     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
534   if (!aComposite || aComposite->numberOfSubs() == 0) {
535     // saving of context is enough: result construction contains exactly the needed shape
536     return anIndex - 1;
537   }
538
539   // identify the results of sub-object of the composite by edges
540   // save type of the selected shape in integer attribute
541   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
542   TDataStd_Integer::Set(aLab, (int)aShapeType);
543   gp_Pnt aVertexPos;
544   // curves of the sketch sub-elements are used, so, edges are not equal
545   TColStd_MapOfTransient allCurves;
546   if (aShapeType == TopAbs_VERTEX) { // compare positions
547     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
548   } else {
549     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
550       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
551       Standard_Real aFirst, aLast;
552       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
553       allCurves.Add(aCurve);
554     }
555   }
556   std::shared_ptr<Model_Document> aMyDoc =
557     std::dynamic_pointer_cast<Model_Document>(document());
558   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
559   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
560   const int aSubNum = aComposite->numberOfSubs();
561   // subs are placed on unique labels because of #2248: sketch curve may produce several edges,
562   // but #2401 - on stable labels
563   NCollection_Map<int> aUsedIDMap; // already used lab tags for placement of shapes
564
565   for(int a = 0; a < aSubNum; a++) {
566     FeaturePtr aSub = aComposite->subFeature(a);
567     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
568     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
569     // there may be many shapes (circle and center): register if at least one is in selection
570     for(; aRes != aResults.cend(); aRes++) {
571       ResultConstructionPtr aConstr =
572         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
573       if (!aConstr->shape()) {
574         continue;
575       }
576       if (aShapeType != TopAbs_VERTEX) {
577         if (aConstr->shape()->isEdge()) {
578           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
579           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
580           if (!anEdge.IsNull()) {
581             Standard_Real aFirst, aLast;
582             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
583             if (allCurves.Contains(aCurve)) {
584               int anID = aComposite->subFeatureId(a);
585               if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
586                 // add edges to sub-label to support naming for edges selection
587                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
588                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
589                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
590                   Standard_Real aFirst, aLast;
591                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
592                   if (Model_CurvesHasher::IsEqual(aFaceCurve, aCurve)) {
593                     while(aUsedIDMap.Contains(anID))
594                       anID += 100000;
595                     aUsedIDMap.Add(anID);
596                     TDF_Label aSubLab = aLab.FindChild(anID);
597                     std::string aFullNameSub = fullName(aComposite, anEdge);
598                     saveSubName(aComposite, aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
599
600                     int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
601                     if (anOrient != 0) {
602                       // store the orientation of edge relatively to face if needed
603                       TDataStd_Integer::Set(aSubLab, anOrient);
604                     }
605                   }
606                 }
607               } else { // put vertices of the selected edge to sub-labels
608                 // add edges to sub-label to support naming for edges selection
609                 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
610                       anEdgeExp.More(); anEdgeExp.Next()) {
611                     TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
612                     while(aUsedIDMap.Contains(anID))
613                       anID += 100000;
614                     aUsedIDMap.Add(anID);
615                     TDF_Label aSubLab = aLab.FindChild(anID);
616                     std::string aFullNameSub = fullName(aComposite, aV);
617                     saveSubName(aComposite, aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
618                 }
619               }
620             }
621           }
622         }
623       }
624     }
625   }
626   std::string aFullName = fullName(aComposite, aSubShape, aRefs);
627   // store the selected as primitive
628   registerSubShape(aLab, aSubShape, aFullName, 0, aMyDoc, isSelectionMode);
629   return anIndex - 1;
630 }
631
632 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape(const int theIndex,
633   const std::shared_ptr<ModelAPI_Document> theExtDoc)
634 {
635   std::shared_ptr<GeomAPI_Shape> aResult;
636   if (theIndex == 0)
637     return aResult; // the whole shape, so, NULL
638
639   bool isExt;
640   TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1);
641   if (!aLab.IsNull()) { // index is not bad
642     Handle(TNaming_NamedShape) aSelection;
643     if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
644       TopoDS_Shape aSelShape = aSelection->Get();
645       if (aSelShape.IsNull())
646         return aResult; // shape equal to context => null
647       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
648       aResult->setImpl(new TopoDS_Shape(aSelShape));
649     }
650   }
651
652   return aResult;
653 }
654
655 bool Model_ResultConstruction::update(const int theIndex,
656   const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theModified)
657 {
658   theModified = false;
659   bool anExt;
660   TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True);
661   if (theIndex == 0 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0
662     // it is just reference to construction, not sub-shape
663     // if there is a sketch, the sketch-naming must be updated
664     if (!isInfinite()) {
665       // update all faces named by the whole result
666       bool aRes = true;
667       Handle(TDataStd_IntPackedMap) anIndices;
668       if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) {
669         NCollection_Map<TopoDS_Shape> aFaces; // collect faces, updated in the tree
670         TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap());
671         Handle(TColStd_HPackedMapOfInteger) aNewPackedMap =
672           new TColStd_HPackedMapOfInteger; // with only faces that are ok
673         // iterate to find existing faces, updated
674         for(; anIndexIter.More(); anIndexIter.Next()) {
675           if (update(anIndexIter.Key(), theExtDoc, theModified)) {
676             GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc);
677             if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
678               aNewPackedMap->ChangeMap().Add(anIndexIter.Key());
679               aFaces.Add(aFace->impl<TopoDS_Shape>());
680             }
681           }
682         }
683         // then iterate all existing faces to find new faces
684         int aCurrentFacesNum = facesNum();
685         for(int a = 0; a < aCurrentFacesNum; a++) {
686           GeomShapePtr aFace = face(a);
687           if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
688             // add this one
689             int aNewFaceIndex = select(aFace, theExtDoc, -1);
690             if (aNewFaceIndex > 0) {
691               aNewPackedMap->ChangeMap().Add(aNewFaceIndex);
692             }
693           }
694         }
695         anIndices->ChangeMap(aNewPackedMap);
696       }
697       return aRes;
698     } else {
699       // check is this modified or not
700       std::shared_ptr<GeomAPI_Shape> aNewShape = shape();
701       TopoDS_Shape anOldSh;
702       Handle(TNaming_NamedShape) aNS;
703       if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
704         anOldSh = aNS->Get();
705       }
706       if (aNewShape.get()) {
707         if (anOldSh.IsNull())
708           theModified = true;
709         else {
710           std::shared_ptr<GeomAPI_Shape> anOldShape(new GeomAPI_Shape);
711           anOldShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(anOldSh));
712           theModified = !anOldShape->isEqual(aNewShape);
713         }
714       }
715       else if (!anOldSh.IsNull()) {
716         theModified = true;
717       }
718
719       // For correct naming selection, put the shape into the naming structure.
720       // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
721       TNaming_Builder aBuilder(aLab);
722       aBuilder.Generated(aNewShape->impl<TopoDS_Shape>());
723     }
724     return shape() && !shape()->isNull();
725   }
726   // construction: identification by the results indexes, recompute faces and
727   // take the face that more close by the indexes
728   ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
729   FeaturePtr aContextFeature = document()->feature(aThisPtr);
730
731   // sketch sub-element
732   if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
733   {
734     // update the referenced object if it is sub
735     Handle(TDF_Reference) aRef;
736     if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
737       int aFaceIndex = aRef->Get().Tag();
738       // don't check selection since face may disappear, but the shape stays correct
739       Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
740     }
741     // getting a type of selected shape
742     Handle(TDataStd_Integer) aTypeAttr;
743     if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
744       return false;
745     }
746     TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
747     // selected indexes will be needed in each "if"
748     Handle(TDataStd_IntPackedMap) aSubIds;
749     std::shared_ptr<GeomAPI_Shape> aNewSelected;
750     bool aNoIndexes =
751       !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
752     // for now working only with composite features
753     CompositeFeaturePtr aComposite =
754       std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
755     if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
756       return false;
757     }
758
759     if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) {
760       // compound is for the whole sketch selection
761       // If this is a wire with plane defined then it is a sketch-like object
762       if (!facesNum()) // no faces, update can not work correctly
763         return false;
764       // if there is no edges indexes, any face can be used: take the first
765       std::shared_ptr<GeomAPI_Shape> aNewSelected;
766       if (aNoIndexes) {
767         aNewSelected = face(0);
768       } else { // searching for most looks-like initial face by the indexes
769         // prepare edges of the current result for the fast searching
770         // curves and orientations of edges
771         NCollection_DataMap<Handle(Geom_Curve), int, Model_CurvesHasher> allCurves;
772         const int aSubNum = aComposite->numberOfSubs();
773         for(int a = 0; a < aSubNum; a++) {
774           int aSubID = aComposite->subFeatureId(a);
775           if (aSubIds->Contains(aSubID)) {
776             FeaturePtr aSub = aComposite->subFeature(a);
777             const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
778             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
779             for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
780               ResultConstructionPtr aConstr =
781                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
782               if (aConstr->shape() && aConstr->shape()->isEdge()) {
783                 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
784                 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
785                 if (!anEdge.IsNull()) {
786                   Standard_Real aFirst, aLast;
787                   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
788                   // searching for orientation information
789                   int anOrient = 0;
790                   Handle(TDataStd_Integer) anInt;
791                   if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) {
792                     anOrient = anInt->Get();
793                   }
794                   allCurves.Bind(aCurve, anOrient);
795                 }
796               }
797             }
798           }
799         }
800         aNewSelected = Model_SelectionNaming::findAppropriateFace(
801           aThisPtr, allCurves, aShapeType == TopAbs_WIRE);
802       }
803       if (aNewSelected) { // store this new selection
804         select(aNewSelected, theExtDoc, theIndex);
805         theModified = true;
806         return true;
807       } else {
808         // if the selection is not found, put the empty shape:
809         // it's better to have disappeared shape, than the old, the lost one
810         TNaming_Builder anEmptyBuilder(aLab);
811         return false;
812       }
813     } else if (aShapeType == TopAbs_EDGE) {
814       // just reselect the edge by the id
815       const int aSubNum = aComposite->numberOfSubs();
816       for(int a = 0; a < aSubNum; a++) {
817         // if aSubIds take any, the first appropriate
818         if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
819           // found the appropriate feature
820           FeaturePtr aFeature = aComposite->subFeature(a);
821           std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
822             aFeature->results().cbegin();
823           for(;aResIter != aFeature->results().cend(); aResIter++) {
824             ResultConstructionPtr aRes =
825               std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
826             if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
827               select(aRes->shape(), theExtDoc, theIndex);
828               theModified = true;
829               return true;
830             }
831           }
832         }
833       }
834     } else if (aShapeType == TopAbs_VERTEX) {
835       // just reselect the vertex by the id of edge
836       const int aSubNum = aComposite->numberOfSubs();
837       for(int a = 0; a < aSubNum; a++) {
838         // if aSubIds take any, the first appropriate
839         int aFeatureID = aComposite->subFeatureId(a);
840         if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
841           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
842           aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
843             // searching for deltas
844             int aVertexNum = 0;
845             if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
846             else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
847             // found the feature with appropriate edge
848             FeaturePtr aFeature = aComposite->subFeature(a);
849             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
850               aFeature->results().cbegin();
851             for(;aResIter != aFeature->results().cend(); aResIter++) {
852               ResultConstructionPtr aRes =
853                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
854               if (aRes && aRes->shape()) {
855                 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
856                   select(aRes->shape(), theExtDoc, theIndex);
857                   theModified = true;
858                   return true;
859                 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
860                   const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
861                   int aVIndex = 1;
862                   for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
863                     if (aVIndex == aVertexNum) { // found!
864                       std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
865                       aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
866                       select(aVertex, theExtDoc, theIndex);
867                       theModified = true;
868                       return true;
869                     }
870                     aVIndex++;
871                   }
872                 }
873               }
874             }
875         }
876       }
877     }
878   } else { // simple construction element: the selected is that needed
879     select(shape(), theExtDoc, theIndex);
880     theModified = true;
881     return true;
882   }
883   return false; // unknown case
884 }