Salome HOME
5f5d588ee22180e90dded0a2437a8f4ba2d7c872
[modules/shaper.git] / src / Model / Model_ResultConstruction.cpp
1 // Copyright (C) 2014-2021  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 email : webmaster.salome@opencascade.com
18 //
19
20 #include <Model_ResultConstruction.h>
21
22 #include <Model_Data.h>
23 #include <ModelAPI_CompositeFeature.h>
24 #include <GeomAlgoAPI_SketchBuilder.h>
25 #include <GeomAPI_Tools.h>
26 #include <ModelAPI_Events.h>
27 #include <Model_Document.h>
28 #include <GeomAPI_PlanarEdges.h>
29 #include <GeomAPI_Shape.h>
30 #include <Events_Loop.h>
31 #include <GeomDataAPI_Point.h>
32 #include <GeomDataAPI_Dir.h>
33
34 #include <TDF_ChildIDIterator.hxx>
35 #include <TNaming_NamedShape.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TDataStd_IntPackedMap.hxx>
38 #include <TDataStd_Name.hxx>
39 #include <TDataStd_UAttribute.hxx>
40 #include <BRep_Builder.hxx>
41 #include <TopoDS.hxx>
42 #include <TopoDS_Edge.hxx>
43 #include <TopoDS_Vertex.hxx>
44 #include <TopoDS_ListOfShape.hxx>
45 #include <TopExp_Explorer.hxx>
46 #include <TopTools_MapOfShape.hxx>
47 #include <NCollection_IndexedDataMap.hxx>
48
49 #include <algorithm>
50
51 typedef NCollection_IndexedDataMap<TopoDS_Face, TColStd_ListOfInteger> MapFaceToEdgeIndices;
52
53 /// Convert each edge of sketch to corresponding integer value
54 /// \param[in]  theComposite      sketch feature
55 /// \param[out] theCurvesIndices  map curve to its index
56 /// \param[out] theEdgesIndices   indexed edge
57 /// \param[out] theEdgesNames     indexed name for edge
58 static void indexingSketchEdges(
59     const CompositeFeaturePtr& theComposite,
60     NCollection_DataMap<Handle(Geom_Curve), int>& theCurvesIndices,
61     NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
62     std::map<int, std::wstring>& theEdgesNames);
63
64 /// Convert each face to the list of indices of its edges
65 /// \param[in]  theFaces          list of faces to proceed
66 /// \param[in]  theCurvesIndices  index of each curve
67 /// \param[out] theFaceEdges      map face to indices of its edges
68 static void faceToEdgeIndices(
69     const ListOfShape& theFaces,
70     const NCollection_DataMap<Handle(Geom_Curve), int>& theCurvesIndices,
71     MapFaceToEdgeIndices& theFaceEdges);
72
73 /// Assign faces to tags for the specified label
74 /// \param theDocument        current document
75 /// \param theShapeLabel      label to store shapes
76 /// \param theName            name of the object
77 /// \param theShape           shape to be stored to the label
78 /// \param theFacesOrder      faces to be assigned to specified tag
79 /// \param theUnorderedFaces  faces which may be stored to any tag
80 /// \param theFaceEdges       indices of edges for each face
81 /// \param theEdgesIndices    indices of edges
82 /// \param theEdgesNames      named of edges
83 static void storeFacesOnLabel(std::shared_ptr<Model_Document>& theDocument,
84                               TDF_Label& theShapeLabel,
85                               const std::wstring& theName,
86                               const TopoDS_Shape& theShape,
87                               NCollection_DataMap<int, TopoDS_Face>& theFacesOrder,
88                               NCollection_List<TopoDS_Face>& theUnorderedFaces,
89                               const MapFaceToEdgeIndices& theFaceEdges,
90                               const NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
91                               const std::map<int, std::wstring>& theEdgesNames);
92
93
94 // identifier of the infinite result
95 Standard_GUID kIS_INFINITE("dea8cc5a-53f2-49c1-94e8-a947bed20a9f");
96 // identifier of the result not in history
97 Standard_GUID kIS_IN_HISTORY("a9aec01c-805e-44d1-b5d2-a63f06522f8a");
98
99 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
100                                        std::string& theDefault)
101 {
102   theSection = "Visualization";
103   theName = RESULT_COLOR_NAME();
104   theDefault = DEFAULT_COLOR();
105 }
106
107 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
108 {
109   if (myShape != theShape) {
110     storeShape(theShape);
111     if (!theShape.get() || !theShape->isEqual(myShape)) {
112       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
113       ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
114     }
115     myShape = theShape;
116   }
117 }
118
119 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
120 {
121   return myShape;
122 }
123
124 static std::wstring shortName(
125   std::shared_ptr<ModelAPI_ResultConstruction>& theConstr)
126 {
127   std::wstring aName = theConstr->data()->name();
128   // remove "-", "/" and "&" command-symbols
129   aName.erase(std::remove(aName.begin(), aName.end(), '-'), aName.end());
130   aName.erase(std::remove(aName.begin(), aName.end(), '/'), aName.end());
131   aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
132   // remove the last 's', 'e', 'f' and 'r' symbols:
133   // they are used as markers of start/end/forward/reversed indicators
134   static const std::wstring aSyms(L"sefr");
135   std::wstring::iterator aSuffix = aName.end() - 1;
136   while(aSyms.find(*aSuffix) != std::wstring::npos) {
137     --aSuffix;
138   }
139   aName.erase(aSuffix + 1, aName.end());
140   return aName;
141 }
142
143 bool Model_ResultConstruction::updateShape()
144 {
145   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
146   if (aData && aData->isValid()) {
147     TDF_Label aShapeLab = aData->shapeLab();
148     Handle(TNaming_NamedShape) aNS;
149     if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
150       TopoDS_Shape aShape = aNS->Get();
151       if (!aShape.IsNull()) {
152         if (aShape.ShapeType() == TopAbs_COMPOUND) {
153           // restore the sketch planar edges object
154           std::shared_ptr<GeomAPI_PlanarEdges> aBigWire(new GeomAPI_PlanarEdges);
155           aBigWire->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
156           FeaturePtr aSketch =
157             document()->feature(std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner()));
158           std::shared_ptr<GeomDataAPI_Point> anOrigin =
159             std::dynamic_pointer_cast<GeomDataAPI_Point>(aSketch->data()->attribute("Origin"));
160           std::shared_ptr<GeomDataAPI_Dir> aDirX =
161             std::dynamic_pointer_cast<GeomDataAPI_Dir>(aSketch->data()->attribute("DirX"));
162           std::shared_ptr<GeomDataAPI_Dir> aNorm =
163             std::dynamic_pointer_cast<GeomDataAPI_Dir>(aSketch->data()->attribute("Norm"));
164           if (anOrigin.get() && aDirX.get() && aNorm.get()) {
165             aBigWire->setPlane(anOrigin->pnt(), aDirX->dir(), aNorm->dir());
166             myShape = aBigWire;
167             return true;
168           }
169         }
170         // just restore shape
171         GeomShapePtr aGShape(new GeomAPI_Shape);
172         aGShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
173         myShape = GeomAPI_Tools::getTypedShape(aGShape); // restore the sketch sub-components
174         return true;
175       }
176     }
177   }
178   return false;
179 }
180
181 Model_ResultConstruction::Model_ResultConstruction()
182 {
183 }
184
185 bool Model_ResultConstruction::isInHistory()
186 {
187   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
188   if (aData.get() && aData->isValid()) {
189     return !aData->label().IsAttribute(kIS_IN_HISTORY); // by default no attribute, but in history
190   }
191   return true;  // unknown case
192 }
193
194 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
195 {
196   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
197   if (aData.get() && aData->isValid()) {
198     if (!isInHistory)
199       TDataStd_UAttribute::Set(aData->label(), kIS_IN_HISTORY);
200     else
201       aData->label().ForgetAttribute(kIS_IN_HISTORY);
202   }
203 }
204
205 bool Model_ResultConstruction::isInfinite()
206 {
207   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
208   if (aData.get() && aData->isValid()) {
209     return aData->label().IsAttribute(kIS_INFINITE);
210   }
211   return false;  // unknown case
212 }
213
214 void Model_ResultConstruction::setInfinite(const bool theInfinite)
215 {
216   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
217   if (aData.get() && aData->isValid()) {
218     if (theInfinite)
219       TDataStd_UAttribute::Set(aData->label(), kIS_INFINITE);
220     else
221       aData->label().ForgetAttribute(kIS_INFINITE);
222   }
223 }
224
225 int Model_ResultConstruction::facesNum(const bool /*theUpdateNaming*/)
226 {
227   int aResult = 0;
228   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
229   if (aData.get() && aData->isValid()) {
230     TDF_Label aShapeLab = aData->shapeLab();
231     TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
232     for (; anOldIter.More(); anOldIter.Next()) {
233       aResult++;
234     }
235   }
236   return aResult;
237 }
238
239 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
240 {
241   std::shared_ptr<GeomAPI_Face> aResult;
242   int anIndex = 0;
243   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
244   if (aData.get() && aData->isValid()) {
245     TDF_Label aShapeLab = aData->shapeLab();
246     TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
247     for (; anOldIter.More(); anOldIter.Next()) {
248       if (anIndex == theIndex) {
249         Handle(TNaming_NamedShape) aNS;
250         anOldIter.Value()->Label().FindAttribute(TNaming_NamedShape::GetID(), aNS);
251         aResult.reset(new GeomAPI_Face);
252         aResult->setImpl(new TopoDS_Shape(aNS->Get()));
253         break;
254       }
255       anIndex++;
256     }
257   }
258   return aResult;
259 }
260
261 void Model_ResultConstruction::setIsConcealed(const bool theValue, const bool theForced)
262 {
263   // the construction element may be concealed only by "delete" feature
264   if (!theValue || theForced) {
265     ModelAPI_ResultConstruction::setIsConcealed(theValue, theForced);
266   }
267 }
268
269 void Model_ResultConstruction::storeShape(std::shared_ptr<GeomAPI_Shape> theShape)
270 {
271   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
272   if (aData && aData->isValid()) {
273     std::wstring aMyName = data()->name();
274     TDF_Label aShapeLab = aData->shapeLab();
275     if (!theShape.get() || theShape->isNull()) {
276       aShapeLab.ForgetAllAttributes();
277       TDataStd_Name::Set(aShapeLab, aMyName.c_str()); // restore name forgotten
278       return;
279     }
280     std::shared_ptr<Model_Document> aMyDoc =
281       std::dynamic_pointer_cast<Model_Document>(document());
282     const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
283     if (isInfinite() || aShape.ShapeType() == TopAbs_VERTEX) {
284       aShapeLab.ForgetAllAttributes(); // clear all previously stored
285       TNaming_Builder aBuilder(aShapeLab);
286       aBuilder.Generated(aShape);
287       TDataStd_Name::Set(aShapeLab, aMyName.c_str());
288       aMyDoc->addNamingName(aShapeLab, aMyName);
289     } else if (aShape.ShapeType() == TopAbs_EDGE) { // store sub-vertices on sub-labels
290       aShapeLab.ForgetAllAttributes(); // clear all previously stored
291       TNaming_Builder aBuilder(aShapeLab);
292       aBuilder.Generated(aShape);
293
294       TopExp_Explorer anExp(aShape, TopAbs_VERTEX);
295       for(int anIndex = 1; anExp.More(); anExp.Next(), anIndex++) {
296         TDF_Label aSubLab = aShapeLab.FindChild(anIndex);
297         TNaming_Builder aSubBuilder(aSubLab);
298         aSubBuilder.Generated(anExp.Current());
299         std::wstring aVertexName = aMyName + L"_" +
300           (anIndex == 1 ? L"StartVertex" : L"EndVertex");
301         TDataStd_Name::Set(aSubLab, aVertexName.c_str());
302         aMyDoc->addNamingName(aSubLab, aVertexName);
303       }
304       TDataStd_Name::Set(aShapeLab, aMyName.c_str());
305       aMyDoc->addNamingName(aShapeLab, aMyName);
306     } else { // this is probably sketch, so, work with it as with composite
307       std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
308         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theShape);
309       if (!aWirePtr.get())
310         return; // unknown case
311       ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
312       FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr);
313       CompositeFeaturePtr aComposite =
314         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
315       if (!aComposite || aComposite->numberOfSubs() == 0)
316         return; // unknown case
317       // collect indices of curves of current composite
318       NCollection_DataMap<Handle(Geom_Curve), int> aCurvesIndices;
319       NCollection_DataMap<int, TopoDS_Edge> anEdgeIndices;
320       std::map<int, std::wstring> aComponentsNames; // names of components that lay on index
321       indexingSketchEdges(aComposite, aCurvesIndices, anEdgeIndices, aComponentsNames);
322
323       GeomAlgoAPI_SketchBuilder aSketchBuilder(aWirePtr->origin(), aWirePtr->dirX(),
324                                                aWirePtr->norm(), aWirePtr);
325       const ListOfShape& aFaces = aSketchBuilder.faces();
326       // order is important to store faces in the same order if sketch is created from scratch
327       MapFaceToEdgeIndices aNewIndices; // edges indices
328       faceToEdgeIndices(aFaces, aCurvesIndices, aNewIndices);
329
330       NCollection_DataMap<int, TopoDS_Face> aFacesOrder; // faces -> tag where they must be set
331       NCollection_List<TopoDS_Face> anUnorderedFaces; // faces that may be located at any index
332       // searching for the best new candidate to old location
333       MapFaceToEdgeIndices::Iterator aNewIter(aNewIndices);
334       for (; aNewIter.More(); aNewIter.Next()) {
335         double aBestFound = 0, aBestNotFound = 1.e+100;
336         int aBestTag = 0;
337         const TColStd_ListOfInteger& aNewInd = aNewIter.Value();
338         // old faces indices where they where located
339         TDF_ChildIDIterator anOldIter(aShapeLab, TDataStd_IntPackedMap::GetID());
340         for (; anOldIter.More(); anOldIter.Next()) {
341           int aTag = anOldIter.Value()->Label().Tag();
342           if (aFacesOrder.IsBound(aTag))
343             continue; // already found a best candidate
344           Handle(TDataStd_IntPackedMap) anOldIndices =
345             Handle(TDataStd_IntPackedMap)::DownCast(anOldIter.Value());
346           double aFound = 0, aNotFound = 0;
347           TColStd_ListOfInteger::Iterator aNewIndIter(aNewInd);
348           for (; aNewIndIter.More(); aNewIndIter.Next()) {
349             if (anOldIndices->Contains(aNewIndIter.Value())) {
350               aFound += 1.;
351             }
352             else if (anOldIndices->Contains(-aNewIndIter.Value())) { // different orientation
353               aFound += 0.001;
354             }
355             else {
356               aNotFound += 1.;
357             }
358           }
359           if (aNotFound <= aBestNotFound) { // less and equal to find better "found": #2859
360             if (aFound > aBestFound) {
361               aBestNotFound = aNotFound;
362               aBestFound = aFound;
363               aBestTag = aTag;
364             }
365           }
366         }
367         if (aBestTag != 0) { // found an appropriate face
368           aFacesOrder.Bind(aBestTag, aNewIter.Key());
369         } else {
370           anUnorderedFaces.Append(aNewIter.Key());
371         }
372       }
373       storeFacesOnLabel(aMyDoc, aShapeLab, aMyName, aShape, aFacesOrder, anUnorderedFaces,
374                         aNewIndices, anEdgeIndices, aComponentsNames);
375     }
376   }
377 }
378
379 void Model_ResultConstruction::setFacesOrder(const std::list<GeomFacePtr>& theFaces)
380 {
381   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
382   if (aData && aData->isValid()) {
383     std::wstring aMyName = data()->name();
384     TDF_Label aShapeLab = aData->shapeLab();
385     GeomShapePtr aResShape = shape();
386     if (!aResShape.get() || aResShape->isNull()) {
387       // do nothing
388       return;
389     }
390     std::shared_ptr<Model_Document> aMyDoc =
391         std::dynamic_pointer_cast<Model_Document>(document());
392     const TopoDS_Shape& aShape = aResShape->impl<TopoDS_Shape>();
393     if (aShape.ShapeType() != TopAbs_VERTEX &&
394         aShape.ShapeType() != TopAbs_EDGE) {
395       ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
396       FeaturePtr aThisFeature = aMyDoc->feature(aThisPtr);
397       CompositeFeaturePtr aComposite =
398         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
399       if (!aComposite || aComposite->numberOfSubs() == 0)
400         return; // unknown case
401       // collect indices of curves of current composite
402       NCollection_DataMap<Handle(Geom_Curve), int> aCurvesIndices;
403       NCollection_DataMap<int, TopoDS_Edge> anEdgeIndices;
404       std::map<int, std::wstring> aComponentsNames; // names of components that lay on index
405       indexingSketchEdges(aComposite, aCurvesIndices, anEdgeIndices, aComponentsNames);
406
407       ListOfShape aFaces;
408       NCollection_DataMap<int, TopoDS_Face> aFacesOrder; // faces -> tag where they must be set
409       NCollection_List<TopoDS_Face> anUnorderedFaces; // unordered faces are empty in this case
410       int aTagId = 0;
411       for (std::list<GeomFacePtr>::const_iterator aFIt = theFaces.begin();
412            aFIt != theFaces.end(); ++aFIt) {
413         aFaces.push_back(*aFIt);
414         aFacesOrder.Bind(++aTagId, (*aFIt)->impl<TopoDS_Face>());
415       }
416
417       MapFaceToEdgeIndices aNewIndices; // edges indices
418       faceToEdgeIndices(aFaces, aCurvesIndices, aNewIndices);
419
420       storeFacesOnLabel(aMyDoc, aShapeLab, aMyName, aShape, aFacesOrder, anUnorderedFaces,
421                         aNewIndices, anEdgeIndices, aComponentsNames);
422     }
423   }
424 }
425
426 // ==========================     Auxiliary functions     =========================================
427
428 void storeFacesOnLabel(std::shared_ptr<Model_Document>& theDocument,
429                        TDF_Label& theShapeLabel,
430                        const std::wstring& theName,
431                        const TopoDS_Shape& theShape,
432                        NCollection_DataMap<int, TopoDS_Face>& theFacesOrder,
433                        NCollection_List<TopoDS_Face>& theUnorderedFaces,
434                        const MapFaceToEdgeIndices& theFaceEdges,
435                        const NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
436                        const std::map<int, std::wstring>& theEdgesNames)
437 {
438   theShapeLabel.ForgetAllAttributes(); // clear all previously stored
439   TDataStd_Name::Set(theShapeLabel, theName.c_str()); // restore name forgotten
440   TNaming_Builder aBuilder(theShapeLabel); // store the compound to get it ready on open of document
441   aBuilder.Generated(theShape);
442   theDocument->addNamingName(theShapeLabel, theName);
443   // set new faces to the labels
444   NCollection_List<TopoDS_Face>::Iterator anUnordered(theUnorderedFaces);
445   for (int aCurrentTag = 1; !theFacesOrder.IsEmpty() || anUnordered.More(); aCurrentTag++) {
446     TopoDS_Face aFaceToPut;
447     if (theFacesOrder.IsBound(aCurrentTag)) {
448       aFaceToPut = theFacesOrder.Find(aCurrentTag);
449       theFacesOrder.UnBind(aCurrentTag);
450     }
451     else if (anUnordered.More()) {
452       aFaceToPut = anUnordered.Value();
453       anUnordered.Next();
454     }
455
456     if (aFaceToPut.IsNull())
457       continue;
458
459     TopTools_MapOfShape aFaceEdges;
460     for (TopExp_Explorer anEdges(aFaceToPut, TopAbs_EDGE); anEdges.More(); anEdges.Next())
461       aFaceEdges.Add(anEdges.Current());
462
463     TDF_Label aLab = theShapeLabel.FindChild(aCurrentTag);
464     TNaming_Builder aFaceBuilder(aLab);
465     aFaceBuilder.Generated(aFaceToPut);
466     // store also indices of the new face edges
467     Handle(TDataStd_IntPackedMap) aNewMap = TDataStd_IntPackedMap::Set(aLab);
468     const TColStd_ListOfInteger& aNewInd = theFaceEdges.FindFromKey(aFaceToPut);
469     std::wstringstream aName;
470     aName<<"Face";
471     TopExp_Explorer aPutEdges(aFaceToPut, TopAbs_EDGE);
472     TNaming_Builder *anEdgesBuilder = 0, *aVerticesBuilder = 0;
473     for(TColStd_ListOfInteger::Iterator anIter(aNewInd); anIter.More(); anIter.Next()) {
474       int anIndex = anIter.Value();
475       int aModIndex = anIndex > 0 ? anIndex : -anIndex;
476       aNewMap->Add(anIndex);
477       aName<<"-"<<theEdgesNames.find(aModIndex)->second;
478       if (anIter.Value() > 0)
479         aName<<"f";
480       else
481         aName<<"r";
482       // collect all edges of the face which are modified in sub-label of the face
483       if (theEdgesIndices.IsBound(aModIndex) &&
484           !aFaceEdges.Contains(theEdgesIndices.Find(aModIndex))) {
485         if (!anEdgesBuilder) {
486           TDF_Label anEdgesLabel = aLab.FindChild(1);
487           anEdgesBuilder = new TNaming_Builder(anEdgesLabel);
488           std::ostringstream aSubName;
489           // tag is needed for Test1922 to distinguish sub-edges of different faces
490           aSubName<<"SubEdge_"<<aCurrentTag;
491           TDataStd_Name::Set(anEdgesLabel, aSubName.str().c_str());
492         }
493         anEdgesBuilder->Modify(theEdgesIndices.Find(aModIndex), aPutEdges.Current());
494       }
495       // put also modified vertices, otherwise vertex of original edge has no history
496       if (theEdgesIndices.IsBound(aModIndex)) {
497         TopExp_Explorer aVExpOld(theEdgesIndices.Find(aModIndex), TopAbs_VERTEX);
498         TopExp_Explorer aVExpNew(aPutEdges.Current(), TopAbs_VERTEX);
499         for(; aVExpNew.More() && aVExpOld.More(); aVExpNew.Next(), aVExpOld.Next()) {
500           if (!aVExpOld.Current().IsSame(aVExpNew.Current())) {
501             if (!aVerticesBuilder) {
502               TDF_Label aVertLabel = aLab.FindChild(2);
503               aVerticesBuilder = new TNaming_Builder(aVertLabel);
504               std::ostringstream aSubName;
505               // tag is needed for Test1922 to distinguish sub-edges of different faces
506               aSubName<<"SubVertex_"<<aCurrentTag;
507               TDataStd_Name::Set(aVertLabel, aSubName.str().c_str());
508             }
509             aVerticesBuilder->Modify(aVExpOld.Current(), aVExpNew.Current());
510
511           }
512         }
513       }
514       aPutEdges.Next();
515     }
516     if (anEdgesBuilder)
517       delete anEdgesBuilder;
518     if (aVerticesBuilder)
519       delete aVerticesBuilder;
520     TDataStd_Name::Set(aLab, TCollection_ExtendedString(aName.str().c_str()));
521     theDocument->addNamingName(aLab, aName.str());
522     // put also wires to sub-labels to correctly select them instead of collection by edges
523     int aWireTag = 3; // first tag is for SubEdge-s, second - for vertices
524     for(TopExp_Explorer aWires(aFaceToPut, TopAbs_WIRE); aWires.More(); aWires.Next()) {
525       TDF_Label aWireLab = aLab.FindChild(aWireTag);
526       TNaming_Builder aWireBuilder(aWireLab);
527       aWireBuilder.Generated(aWires.Current());
528       std::wostringstream aWireName;
529       aWireName<<aName.str()<<L"_wire";
530       if (aWireTag > 3)
531         aWireName<<"_"<<aWireTag - 2;
532       TDataStd_Name::Set(aWireLab, aWireName.str().c_str());
533       theDocument->addNamingName(aWireLab, aWireName.str());
534       aWireTag++;
535     }
536   }
537 }
538
539 void indexingSketchEdges(const CompositeFeaturePtr& theComposite,
540                          NCollection_DataMap<Handle(Geom_Curve), int>& theCurvesIndices,
541                          NCollection_DataMap<int, TopoDS_Edge>& theEdgesIndices,
542                          std::map<int, std::wstring>& theEdgesNames)
543 {
544   const int aSubNum = theComposite->numberOfSubs();
545   for (int a = 0; a < aSubNum; a++) {
546     FeaturePtr aSub = theComposite->subFeature(a);
547     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
548     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
549     for (; aRes != aResults.cend(); aRes++) {
550       ResultConstructionPtr aConstr =
551         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
552       if (aConstr->shape() && aConstr->shape()->isEdge()) {
553         TopoDS_Edge anEdge = TopoDS::Edge(aConstr->shape()->impl<TopoDS_Shape>());
554         Standard_Real aFirst, aLast;
555         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
556         theCurvesIndices.Bind(aCurve, a);
557         theEdgesIndices.Bind(a, anEdge);
558         theEdgesNames[a] = shortName(aConstr);
559       }
560     }
561   }
562 }
563
564 void faceToEdgeIndices(const ListOfShape& theFaces,
565                        const NCollection_DataMap<Handle(Geom_Curve), int>& theCurvesIndices,
566                        MapFaceToEdgeIndices& theFaceEdges)
567 {
568   std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFIter = theFaces.begin();
569   for (; aFIter != theFaces.end(); aFIter++) {
570     std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
571     // put them to a label, trying to keep the same faces on the same labels
572     if (aFace.get() && !aFace->isNull()) {
573       TopoDS_Face aTopoFace = TopoDS::Face(aFace->impl<TopoDS_Shape>());
574       theFaceEdges.Add(aTopoFace, TColStd_ListOfInteger());
575       // keep new indices of sub-elements used in this face
576       for (TopExp_Explorer anEdges(aTopoFace, TopAbs_EDGE); anEdges.More(); anEdges.Next()) {
577         TopoDS_Edge anEdge = TopoDS::Edge(anEdges.Current());
578         Standard_Real aFirst, aLast;
579         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
580         if (theCurvesIndices.IsBound(aCurve)) {
581           int anIndex = theCurvesIndices.Find(aCurve);
582           if ((aFirst > aLast) != (anEdge.Orientation() == TopAbs_REVERSED))
583             anIndex = -anIndex;
584           theFaceEdges.ChangeFromKey(aTopoFace).Append(anIndex);
585         }
586       }
587     }
588   }
589 }