]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_BodyBuilder.cpp
Salome HOME
Updated modified shapes storing.
[modules/shaper.git] / src / Model / Model_BodyBuilder.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_BodyBuilder.h>
22
23 #include <Model_Data.h>
24 #include <Model_Document.h>
25 #include <TNaming_Builder.hxx>
26 #include <TNaming_NamedShape.hxx>
27 #include <TNaming_Iterator.hxx>
28 #include <TNaming_Tool.hxx>
29 #include <TDataStd_Name.hxx>
30 #include <TDataStd_Integer.hxx>
31 #include <TopoDS.hxx>
32 #include <TopoDS_Face.hxx>
33 #include <TDF_ChildIterator.hxx>
34 #include <TDF_ChildIDIterator.hxx>
35 #include <TDF_Reference.hxx>
36 #include <TopTools_MapOfShape.hxx>
37 #include <TopExp_Explorer.hxx>
38 #include <TopTools_ListOfShape.hxx>
39 #include <TopTools_ListIteratorOfListOfShape.hxx>
40 #include <TopTools_DataMapOfShapeListOfShape.hxx>
41 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
42 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
43 #include <TopTools_MapIteratorOfMapOfShape.hxx>
44 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
45 #include <TopTools_IndexedMapOfShape.hxx>
46 #include <TopTools_DataMapOfShapeShape.hxx>
47 #include <TopExp.hxx>
48 #include <BRepTools.hxx>
49 #include <BRep_Tool.hxx>
50 #include <BRepTools_History.hxx>
51 #include <GeomAPI_Shape.h>
52 #include <GeomAPI_ShapeExplorer.h>
53 #include <GeomAlgoAPI_MakeShape.h>
54 #include <GeomAlgoAPI_SortListOfShapes.h>
55 #include <Config_PropManager.h>
56 // DEB
57 //#include <TCollection_AsciiString.hxx>
58 //#include <TDF_Tool.hxx>
59 //#define DEB_IMPORT 1
60
61 static const int INVALID_TAG            = -1;
62 static const int GENERATED_VERTICES_TAG = 1;
63 static const int GENERATED_EDGES_TAG    = 2;
64 static const int GENERATED_FACES_TAG    = 3;
65 static const int MODIFIED_VERTICES_TAG  = 4;
66 static const int MODIFIED_EDGES_TAG     = 5;
67 static const int MODIFIED_FACES_TAG     = 6;
68 static const int DELETED_TAG            = 7;
69 static const int PRIMITIVES_START_TAG   = 11;
70
71 static int getGenerationTag(const TopoDS_Shape& theShape) {
72   TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
73   switch (aShapeType) {
74     case TopAbs_VERTEX: return GENERATED_VERTICES_TAG;
75     case TopAbs_EDGE:   return GENERATED_EDGES_TAG;
76     case TopAbs_FACE:   return GENERATED_FACES_TAG;
77   }
78
79   return INVALID_TAG;
80 }
81
82 static int getModificationTag(const TopoDS_Shape& theShape) {
83   TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
84   switch (aShapeType) {
85     case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG;
86     case TopAbs_EDGE:   return MODIFIED_EDGES_TAG;
87     case TopAbs_FACE:   return MODIFIED_FACES_TAG;
88   }
89
90   return INVALID_TAG;
91 }
92
93 static TopAbs_ShapeEnum convertShapeType(const GeomAPI_Shape::ShapeType theType) {
94   switch (theType) {
95     case GeomAPI_Shape::VERTEX:    return TopAbs_VERTEX;
96     case GeomAPI_Shape::EDGE:      return TopAbs_EDGE;
97     case GeomAPI_Shape::WIRE:      return TopAbs_WIRE;
98     case GeomAPI_Shape::FACE:      return TopAbs_FACE;
99     case GeomAPI_Shape::SHELL:     return TopAbs_SHELL;
100     case GeomAPI_Shape::SOLID:     return TopAbs_SOLID;
101     case GeomAPI_Shape::COMPSOLID: return TopAbs_COMPSOLID;
102     case GeomAPI_Shape::COMPOUND:  return TopAbs_COMPOUND;
103     case GeomAPI_Shape::SHAPE:     return TopAbs_SHAPE;
104   }
105   return TopAbs_SHAPE;
106 }
107
108 static bool isAlreadyStored(const TNaming_Builder* theBuilder,
109                             const TopoDS_Shape& theOldShape,
110                             const TopoDS_Shape& theNewShape)
111 {
112   for (TNaming_Iterator aNamingIt(theBuilder->NamedShape());
113     aNamingIt.More();
114     aNamingIt.Next())
115   {
116     if (aNamingIt.NewShape().IsSame(theNewShape)
117       && aNamingIt.OldShape().IsSame(theOldShape))
118     {
119       return true;
120     }
121   }
122
123   return false;
124 }
125
126 Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner)
127 : ModelAPI_BodyBuilder(theOwner),
128   myPrimitiveTag(PRIMITIVES_START_TAG),
129   myDividedIndex(1),
130   myVIndex(1),
131   myEIndex(1),
132   myFIndex(1)
133 {
134 }
135
136 // Converts evolution of naming shape to selection evelution and back to avoid
137 // naming support on the disabled results. Deeply in the labels tree, recursively.
138 static void evolutionToSelectionRec(TDF_Label theLab, const bool theFlag) {
139   std::list<std::pair<TopoDS_Shape, TopoDS_Shape> > aShapePairs; // to store old and new shapes
140   Handle(TNaming_NamedShape) aName;
141   int anEvolution = -1;
142   if (theLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
143     TNaming_Evolution aNSEvol = aName->Evolution();
144     if ((aNSEvol == TNaming_SELECTED && theFlag) ||
145         (aNSEvol != TNaming_SELECTED && !theFlag)) { // nothing to do, it is already correct
146       return;
147     }
148     anEvolution = (int)(aNSEvol);
149     if (!theFlag) {
150       Handle(TDataStd_Integer) anAttrEvol;
151       if (theLab.FindAttribute(TDataStd_Integer::GetID(), anAttrEvol)) {
152         anEvolution = anAttrEvol->Get();
153       }
154     } else {
155       TDataStd_Integer::Set(theLab, anEvolution);
156     }
157
158     for(TNaming_Iterator anIter(aName); anIter.More(); anIter.Next()) {
159       // iterator goes in reversed order relatively to the Builder, to, make the list reversed
160       aShapePairs.push_front(std::pair<TopoDS_Shape, TopoDS_Shape>
161         (anIter.OldShape(), anIter.NewShape()));
162     }
163
164     // create new
165     TNaming_Builder aBuilder(theLab);
166     TNaming_Evolution anEvol = (TNaming_Evolution)(anEvolution);
167     std::list<std::pair<TopoDS_Shape, TopoDS_Shape> >::iterator aPairsIter = aShapePairs.begin();
168     for(; aPairsIter != aShapePairs.end(); aPairsIter++) {
169       if (theFlag) { // disabled => make selection
170         if (anEvolution == TNaming_DELETE) // issue 2274 : don't put too many same null shapes
171           aBuilder.Select(aPairsIter->first, aPairsIter->first);
172         else if (anEvolution == TNaming_PRIMITIVE)
173           aBuilder.Select(aPairsIter->second, aPairsIter->second);
174         else
175           aBuilder.Select(aPairsIter->second, aPairsIter->first);
176       } else if (anEvol == TNaming_GENERATED) {
177         aBuilder.Generated(aPairsIter->first, aPairsIter->second);
178       } else if (anEvol == TNaming_MODIFY) {
179         aBuilder.Modify(aPairsIter->first, aPairsIter->second);
180       } else if (anEvol == TNaming_DELETE) {
181         aBuilder.Delete(aPairsIter->first);
182       } else if (anEvol == TNaming_PRIMITIVE) {
183         aBuilder.Generated(aPairsIter->second);
184       } else if (anEvol == TNaming_SELECTED) {
185         aBuilder.Select(aPairsIter->second, aPairsIter->first);
186       }
187     }
188   }
189   // recursive call for all sub-labels
190   TDF_ChildIterator anIter(theLab, Standard_False);
191   for(; anIter.More(); anIter.Next()) {
192     evolutionToSelectionRec(anIter.Value(), theFlag);
193   }
194 }
195
196 void Model_BodyBuilder::evolutionToSelection(const bool theFlag)
197 {
198   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
199   if (!aData || !aData->isValid()) // unknown case
200     return;
201   TDF_Label& aShapeLab = aData->shapeLab();
202   evolutionToSelectionRec(aShapeLab, theFlag);
203 }
204
205 void Model_BodyBuilder::store(const GeomShapePtr& theShape,
206                               const bool theIsStoreSameShapes)
207 {
208   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
209   if (aData) {
210     TDF_Label& aShapeLab = aData->shapeLab();
211     // clean builders
212     clean();
213     // store the new shape as primitive
214     TNaming_Builder aBuilder(aShapeLab);
215     if (!theShape)
216       return;  // bad shape
217     TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
218     if (aShape.IsNull())
219       return;  // null shape inside
220
221     if(!theIsStoreSameShapes) {
222       Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
223       if(!aNS.IsNull() && !aNS->IsEmpty()) {
224         // This shape is already in document, store reference instead of shape;
225         const TDF_Label aFoundLabel = aNS->Label();
226         TDF_Reference::Set(aShapeLab, aFoundLabel);
227         aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID());
228         return;
229       }
230     }
231
232     aBuilder.Generated(aShape);
233     // register name
234     aShapeLab.ForgetAttribute(TDF_Reference::GetID());
235     if(!aBuilder.NamedShape()->IsEmpty()) {
236       Handle(TDataStd_Name) anAttr;
237       if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
238         std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
239         if(!aName.empty()) {
240           std::shared_ptr<Model_Document> aDoc =
241             std::dynamic_pointer_cast<Model_Document>(document());
242           aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
243         }
244       }
245     }
246   }
247 }
248
249 void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
250   const GeomShapePtr& theToShape)
251 {
252   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
253   if (aData) {
254     TDF_Label& aShapeLab = aData->shapeLab();
255     // clean builders
256     clean();
257     // store the new shape as primitive
258     TNaming_Builder aBuilder(aShapeLab);
259     if (!theFromShape || !theToShape)
260       return;  // bad shape
261     TopoDS_Shape aShapeBasis = theFromShape->impl<TopoDS_Shape>();
262     if (aShapeBasis.IsNull())
263       return;  // null shape inside
264     TopoDS_Shape aShapeNew = theToShape->impl<TopoDS_Shape>();
265     if (aShapeNew.IsNull())
266       return;  // null shape inside
267     aBuilder.Generated(aShapeBasis, aShapeNew);
268     // register name
269     if(!aBuilder.NamedShape()->IsEmpty()) {
270       Handle(TDataStd_Name) anAttr;
271       if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
272         std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
273         if(!aName.empty()) {
274           std::shared_ptr<Model_Document> aDoc =
275             std::dynamic_pointer_cast<Model_Document>(document());
276           aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
277         }
278       }
279     }
280   }
281 }
282
283 TNaming_Builder* Model_BodyBuilder::builder(const int theTag)
284 {
285   std::map<int, TNaming_Builder*>::iterator aFind = myBuilders.find(theTag);
286   if (aFind == myBuilders.end()) {
287     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
288     myBuilders[theTag] = new TNaming_Builder(
289       theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
290     aFind = myBuilders.find(theTag);
291   }
292   return aFind->second;
293 }
294
295 void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
296                                       const GeomShapePtr& theNewShape,
297                                       const bool theIsCleanStored)
298 {
299   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
300   if (aData) {
301     TDF_Label& aShapeLab = aData->shapeLab();
302     // clean builders
303     if (theIsCleanStored) clean();
304     // store the new shape as primitive
305     TNaming_Builder* aBuilder = builder(0);
306     if (!theOldShape || !theNewShape)
307       return;  // bad shape
308     TopoDS_Shape aShapeOld = theOldShape->impl<TopoDS_Shape>();
309     if (aShapeOld.IsNull())
310       return;  // null shape inside
311     TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
312     if (aShapeNew.IsNull())
313       return;  // null shape inside
314     aBuilder->Modify(aShapeOld, aShapeNew);
315     if(!aBuilder->NamedShape()->IsEmpty()) {
316       Handle(TDataStd_Name) anAttr;
317       if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
318         std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
319         if(!aName.empty()) {
320           std::shared_ptr<Model_Document> aDoc =
321             std::dynamic_pointer_cast<Model_Document>(document());
322           aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName);
323         }
324       }
325     }
326   }
327 }
328
329 void  Model_BodyBuilder::storeWithoutNaming(const GeomShapePtr& theShape)
330 {
331   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
332   if (aData) {
333     clean();
334     if (!theShape.get())
335       return; // bad shape
336     TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
337     if (aShape.IsNull())
338       return;  // null shape inside
339     TNaming_Builder aBuilder(aData->shapeLab());
340     aBuilder.Select(aShape, aShape);
341   }
342 }
343
344 void Model_BodyBuilder::clean()
345 {
346   TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>(data())->shapeLab();
347   if (aLab.IsNull())
348     return;
349   std::map<int, TNaming_Builder*>::iterator aBuilder = myBuilders.begin();
350   for(; aBuilder != myBuilders.end(); aBuilder++) {
351     delete aBuilder->second;
352     // clear also shapes on cleaned sub-labels (#2241)
353     Handle(TNaming_NamedShape) aNS;
354     if (aLab.FindChild(aBuilder->first).FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
355       aNS->Clear();
356     }
357   }
358   myBuilders.clear();
359   // remove the old reference (if any)
360   aLab.ForgetAttribute(TDF_Reference::GetID());
361   myPrimitiveTag = PRIMITIVES_START_TAG;
362   myDividedIndex = 1;
363   myVIndex = 1;
364   myEIndex = 1;
365   myFIndex = 1;
366 }
367
368 Model_BodyBuilder::~Model_BodyBuilder()
369 {
370   clean();
371 }
372
373 void Model_BodyBuilder::buildName(const int theTag, const std::string& theName)
374 {
375   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(document());
376   std::string aName = theName;
377   switch (theTag) {
378     case GENERATED_VERTICES_TAG: aName += aName.empty() ? "Generated_Vertex" : "_GV"; break;
379     case GENERATED_EDGES_TAG:    aName += aName.empty() ? "Generated_Edge"   : "_GE"; break;
380     case GENERATED_FACES_TAG:    aName += aName.empty() ? "Generated_Face"   : "_GF"; break;
381     case MODIFIED_VERTICES_TAG:  aName += aName.empty() ? "Modified_Vertex"  : "_MV"; break;
382     case MODIFIED_EDGES_TAG:     aName += aName.empty() ? "Modified_Edge"    : "_ME"; break;
383     case MODIFIED_FACES_TAG:     aName += aName.empty() ? "Modified_Face"    : "_MF"; break;
384   }
385
386   TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str());
387 }
388 void Model_BodyBuilder::generated(const GeomShapePtr& theNewShape,
389                                   const std::string& theName)
390 {
391   TopoDS_Shape aShape = theNewShape->impl<TopoDS_Shape>();
392   builder(myPrimitiveTag)->Generated(aShape);
393   if (!theName.empty()) {
394     buildName(myPrimitiveTag, theName);
395   }
396
397   ++myPrimitiveTag;
398 }
399
400 void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape,
401                                   const GeomShapePtr& theNewShape,
402                                   const std::string& theName)
403 {
404   TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
405   TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
406   TopAbs_ShapeEnum aNewShapeType = aNewShape.ShapeType();
407   int aTag;
408   if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
409     // TODO: This is a workaround. New shape should be only vertex, edge or face.
410     TopAbs_ShapeEnum anExplodeShapeType = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
411     aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
412     for (TopExp_Explorer anExp(aNewShape, anExplodeShapeType); anExp.More(); anExp.Next()) {
413       builder(aTag)->Generated(anOldShape, anExp.Current());
414       buildName(aTag, theName);
415     }
416   } else {
417     aTag = getGenerationTag(aNewShape);
418     if (aTag == INVALID_TAG) return;
419     builder(aTag)->Generated(anOldShape, aNewShape);
420     buildName(aTag, theName);
421   }
422 }
423
424 void Model_BodyBuilder::modified(const GeomShapePtr& theOldShape,
425                                  const GeomShapePtr& theNewShape,
426                                  const std::string& theName)
427 {
428   TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
429   TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
430   int aTag = getModificationTag(aNewShape);
431   if (aTag == INVALID_TAG) return;
432   builder(aTag)->Modify(anOldShape, aNewShape);
433   buildName(aTag, theName);
434 }
435
436 void Model_BodyBuilder::deleted(const GeomShapePtr& theOldShape)
437 {
438   TopoDS_Shape aShape = theOldShape->impl<TopoDS_Shape>();
439   builder(DELETED_TAG)->Delete(aShape);
440 }
441
442 void Model_BodyBuilder::loadDeletedShapes(const GeomMakeShapePtr& theAlgo,
443                                           const GeomShapePtr& theOldShape,
444                                           const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
445                                           const GeomShapePtr& theShapesToExclude)
446 {
447   TopTools_MapOfShape anAlreadyProcessedShapes;
448   GeomShapePtr aResultShape = shape();
449   for (GeomAPI_ShapeExplorer anExp(theOldShape, theShapeTypeToExplore);
450        anExp.more();
451        anExp.next())
452   {
453     GeomShapePtr anOldSubShape = anExp.current();
454     const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
455     if (!anAlreadyProcessedShapes.Add(anOldSubShape_)
456         || !theAlgo->isDeleted(anOldSubShape)
457         || aResultShape->isSubShape(anOldSubShape, false)
458         || (theShapesToExclude.get() && theShapesToExclude->isSubShape(anOldSubShape, false)))
459     {
460       continue;
461     }
462
463     ListOfShape aNewShapes;
464     if (BRepTools_History::IsSupportedType(anOldSubShape_)) { // to avoid crash in #2572
465       theAlgo->modified(anOldSubShape, aNewShapes);
466     }
467
468     if (aNewShapes.size() == 0
469         || (aNewShapes.size() == 1 && aNewShapes.front()->isSame(anOldSubShape))) {
470       builder(DELETED_TAG)->Delete(anOldSubShape_);
471     }
472   }
473 }
474
475 static void removeBadShapes(ListOfShape& theShapes)
476 {
477   ListOfShape::iterator anIt = theShapes.begin();
478   while (anIt != theShapes.end()) {
479     TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
480     bool aSkip = aNewShape.IsNull()
481       || (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
482     if (aSkip) {
483       ListOfShape::iterator aRemoveIt = anIt++;
484       theShapes.erase(aRemoveIt);
485     } else {
486       ++anIt;
487     }
488   }
489 }
490
491 // Keep only the shapes with minimal shape type
492 static void keepTopLevelShapes(ListOfShape& theShapes, const TopoDS_Shape& theRoot,
493   const GeomShapePtr& theResultShape = GeomShapePtr())
494 {
495   GeomAPI_Shape::ShapeType aKeepShapeType = GeomAPI_Shape::SHAPE;
496   ListOfShape::iterator anIt = theShapes.begin();
497   while (anIt != theShapes.end()) {
498     TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
499     bool aSkip = aNewShape.IsNull() ||
500       (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
501     if (aSkip || theRoot.IsSame(aNewShape) || (theResultShape &&
502         (!theResultShape->isSubShape(*anIt, false) || theResultShape->isSame(*anIt)))) {
503       ListOfShape::iterator aRemoveIt = anIt++;
504       theShapes.erase(aRemoveIt);
505     } else {
506       GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
507       if (aType < aKeepShapeType) {
508         // found a shape with lesser shape type => remove all previous shapes
509         aKeepShapeType = aType;
510         theShapes.erase(theShapes.begin(), anIt);
511         ++anIt;
512       } else if (aType > aKeepShapeType) {
513         // shapes with greater shape type should be removed from the list
514         ListOfShape::iterator aRemoveIt = anIt++;
515         theShapes.erase(aRemoveIt);
516       } else
517         ++anIt;
518     }
519   }
520 }
521
522 // returns an ancestor shape-type thaty used for naming-definition of the sub-type
523 TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) {
524   if (theSubType == TopAbs_VERTEX)
525     return TopAbs_EDGE;
526   if (theSubType == TopAbs_EDGE)
527     return TopAbs_FACE;
528   return TopAbs_VERTEX; // bad case
529 }
530
531 void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
532                                            const GeomShapePtr& theOldShape,
533                                            const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
534                                            const std::string& theName)
535 {
536   GeomShapePtr aResultShape = shape();
537   GeomShapePtr aShapeToExplore = theOldShape;
538   if (theAlgo->isNewShapesCollected(theOldShape, theShapeTypeToExplore)) {
539     // use optimized set of old shapes for this
540     GeomShapePtr aCompound = theAlgo->oldShapesForNew(theOldShape,
541                                                       aResultShape,
542                                                       theShapeTypeToExplore);
543     if (aCompound.get()) aShapeToExplore = aCompound;
544   }
545
546   TopTools_MapOfShape anAlreadyProcessedShapes;
547   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
548   for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore);
549        anOldShapeExp.more();
550        anOldShapeExp.next())
551   {
552     GeomShapePtr anOldSubShape = anOldShapeExp.current();
553     const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
554
555     // There is no sense to write history if shape already processed
556     // or old shape does not exist in the document.
557     bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
558     bool anOldSubShapeNotInTree = TNaming_Tool::NamedShape(anOldSubShape_, aData->shapeLab())
559                                   .IsNull();
560     if (anOldSubShapeAlreadyProcessed
561         || anOldSubShapeNotInTree)
562     {
563       continue;
564     }
565
566     // Get new shapes.
567     ListOfShape aNewShapes;
568     theAlgo->modified(anOldSubShape, aNewShapes);
569
570     for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
571          aNewShapesIt != aNewShapes.cend();
572          ++aNewShapesIt)
573     {
574       GeomShapePtr aNewShape = *aNewShapesIt;
575       const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
576       bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
577
578       bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
579       bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
580       if (aNewShapeIsSameAsOldShape
581           || aNewShapeIsNotInResultShape)
582       {
583         continue;
584       }
585
586       TNaming_Builder* aBuilder;
587       if (aResultShape->isSame(aNewShape)) {
588         // keep the modification evolution on the root level (2241 - history propagation issue)
589         aBuilder = builder(0);
590         TDF_Label aShapeLab = aBuilder->NamedShape()->Label();
591         Handle(TDF_Reference) aRef;
592         if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
593           // Store only in case if it does not have reference.
594           continue;
595         }
596
597         // Check if new shape was already stored.
598         if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue;
599
600         if (!aBuilder->NamedShape().IsNull() &&
601             ((isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_GENERATED)
602               || (!isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_MODIFY)))
603         {
604           myBuilders.erase(0); // clear old builder to avoid different evolutions crash
605           aBuilder = builder(0);
606         }
607       } else {
608         int aTag = isGenerated ? getGenerationTag(aNewShape_)
609                                : getModificationTag(aNewShape_);
610         aBuilder = builder(aTag);
611
612         // Check if new shape was already stored.
613         if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue;
614
615         buildName(aTag, theName);
616       }
617
618       isGenerated ? aBuilder->Generated(anOldSubShape_, aNewShape_)
619                   : aBuilder->Modify(anOldSubShape_, aNewShape_);
620     }
621   }
622 }
623
624 void Model_BodyBuilder::loadAndOrientGeneratedShapes (
625   GeomAlgoAPI_MakeShape* theMS,
626   GeomShapePtr  theShapeIn,
627   const int  theKindOfShape,
628   const int  theTag,
629   const std::string& theName,
630   GeomAPI_DataMapOfShapeShape& theSubShapes)
631 {
632   TopoDS_Shape aShapeIn = theShapeIn->impl<TopoDS_Shape>();
633   TopTools_MapOfShape aView;
634   bool isBuilt = !theName.empty();
635   TopExp_Explorer aShapeExplorer (aShapeIn, (TopAbs_ShapeEnum)theKindOfShape);
636   for (; aShapeExplorer.More(); aShapeExplorer.Next ()) {
637     const TopoDS_Shape& aRoot = aShapeExplorer.Current ();
638     if (!aView.Add(aRoot)) continue;
639     //if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull())
640     //  continue; // there is no sense to write history if old shape does not exist in the document
641     ListOfShape aList;
642     GeomShapePtr aRShape(new GeomAPI_Shape());
643     aRShape->setImpl((new TopoDS_Shape(aRoot)));
644     theMS->generated(aRShape, aList);
645     keepTopLevelShapes(aList, aRoot);
646     std::list<GeomShapePtr >::const_iterator
647       anIt = aList.begin(), aLast = aList.end();
648     for (; anIt != aLast; anIt++) {
649       TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
650       if (theSubShapes.isBound(*anIt)) {
651         GeomShapePtr aMapShape(theSubShapes.find(*anIt));
652         aNewShape.Orientation(aMapShape->impl<TopoDS_Shape>().Orientation());
653       }
654       if (!aRoot.IsSame (aNewShape)) {
655         builder(theTag)->Generated(aRoot,aNewShape);
656         if(isBuilt)
657           buildName(theTag, theName);
658       }
659       TopAbs_ShapeEnum aGenShapeType = aNewShape.ShapeType();
660       if(aGenShapeType == TopAbs_WIRE || aGenShapeType == TopAbs_SHELL) {
661         TopAbs_ShapeEnum anExplodeShapeType =
662           aGenShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
663         const TDF_Label aLabel = builder(theTag)->NamedShape()->Label();
664         int aTag = 1;
665         std::shared_ptr<Model_Document> aDoc =
666           std::dynamic_pointer_cast<Model_Document>(document());
667         for(TopExp_Explorer anExp(aNewShape, anExplodeShapeType); anExp.More(); anExp.Next()) {
668           TDF_Label aChildLabel = aLabel.FindChild(aTag);
669           TNaming_Builder aBuilder(aChildLabel);
670           aBuilder.Generated(aRoot, anExp.Current());
671           TCollection_AsciiString aChildName =
672             TCollection_AsciiString((theName + "_").c_str()) + aTag;
673           TDataStd_Name::Set(aChildLabel, aChildName.ToCString());
674           aTag++;
675         }
676       }
677     }
678   }
679 }
680
681 //=======================================================================
682 int getDangleShapes(const TopoDS_Shape&           theShapeIn,
683   const TopAbs_ShapeEnum        theGeneratedFrom,
684   TopTools_DataMapOfShapeShape& theDangles)
685 {
686   theDangles.Clear();
687   TopTools_IndexedDataMapOfShapeListOfShape subShapeAndAncestors;
688   TopAbs_ShapeEnum GeneratedTo;
689   if (theGeneratedFrom == TopAbs_FACE) GeneratedTo = TopAbs_EDGE;
690   else if (theGeneratedFrom == TopAbs_EDGE) GeneratedTo = TopAbs_VERTEX;
691   else return Standard_False;
692   TopExp::MapShapesAndAncestors(theShapeIn, GeneratedTo, theGeneratedFrom, subShapeAndAncestors);
693   for (Standard_Integer i = 1; i <= subShapeAndAncestors.Extent(); i++) {
694     const TopoDS_Shape& mayBeDangle = subShapeAndAncestors.FindKey(i);
695     const TopTools_ListOfShape& ancestors = subShapeAndAncestors.FindFromIndex(i);
696     if (ancestors.Extent() == 1) theDangles.Bind(ancestors.First(), mayBeDangle);
697   }
698   return theDangles.Extent();
699 }
700
701 //=======================================================================
702 void loadGeneratedDangleShapes(
703   const TopoDS_Shape&      theShapeIn,
704   const TopAbs_ShapeEnum   theGeneratedFrom,
705   TNaming_Builder *        theBuilder)
706 {
707   TopTools_DataMapOfShapeShape dangles;
708   if (!getDangleShapes(theShapeIn, theGeneratedFrom, dangles)) return;
709   TopTools_DataMapIteratorOfDataMapOfShapeShape itr(dangles);
710   for (; itr.More(); itr.Next())
711     theBuilder->Generated(itr.Key(), itr.Value());
712 }
713
714 //=======================================================================
715 void Model_BodyBuilder::loadNextLevels(GeomShapePtr theShape,
716   const std::string& theName, int&  theTag)
717 {
718   if(theShape->isNull()) return;
719   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
720   std::string aName;
721   if (aShape.ShapeType() == TopAbs_SOLID) {
722     TopExp_Explorer expl(aShape, TopAbs_FACE);
723     for (; expl.More(); expl.Next()) {
724       builder(theTag)->Generated(expl.Current());
725       TCollection_AsciiString aStr(theTag);
726       aName = theName + aStr.ToCString();
727       buildName(theTag, aName);
728       theTag++;
729     }
730   }
731   else if (aShape.ShapeType() == TopAbs_SHELL || aShape.ShapeType() == TopAbs_FACE) {
732     // load faces and all the free edges
733     TopTools_IndexedMapOfShape Faces;
734     TopExp::MapShapes(aShape, TopAbs_FACE, Faces);
735     if (Faces.Extent() > 1 || (aShape.ShapeType() == TopAbs_SHELL && Faces.Extent() == 1)) {
736       TopExp_Explorer expl(aShape, TopAbs_FACE);
737       for (; expl.More(); expl.Next()) {
738         builder(theTag)->Generated(expl.Current());
739         TCollection_AsciiString aStr(theTag);
740         aName = theName + aStr.ToCString();
741         buildName(theTag, aName);
742         theTag++;
743       }
744     }
745     TopTools_IndexedDataMapOfShapeListOfShape anEdgeAndNeighbourFaces;
746     TopExp::MapShapesAndAncestors(aShape, TopAbs_EDGE, TopAbs_FACE, anEdgeAndNeighbourFaces);
747     for (Standard_Integer i = 1; i <= anEdgeAndNeighbourFaces.Extent(); i++)
748     {
749       const TopTools_ListOfShape& aLL = anEdgeAndNeighbourFaces.FindFromIndex(i);
750       if (aLL.Extent() < 2) {
751         if (BRep_Tool::Degenerated(TopoDS::Edge(anEdgeAndNeighbourFaces.FindKey(i))))
752           continue;
753         builder(theTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
754         TCollection_AsciiString aStr(theTag);
755         aName = theName + aStr.ToCString();
756         buildName(theTag, aName);
757         theTag++;
758       } else {
759         TopTools_ListIteratorOfListOfShape anIter(aLL);
760         const TopoDS_Face& aFace = TopoDS::Face(anIter.Value());
761         anIter.Next();
762         if(aFace.IsEqual(anIter.Value())) {
763           builder(theTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
764           TCollection_AsciiString aStr(theTag);
765           aName = theName + aStr.ToCString();
766           buildName(theTag, aName);
767           theTag++;
768         }
769       }
770     }
771   } else if (aShape.ShapeType() == TopAbs_WIRE) {
772     TopTools_IndexedMapOfShape Edges;
773     BRepTools::Map3DEdges(aShape, Edges);
774     if (Edges.Extent() == 1) {
775       builder(theTag++)->Generated(Edges.FindKey(1));
776       TopExp_Explorer expl(aShape, TopAbs_VERTEX);
777       for (; expl.More(); expl.Next()) {
778         builder(theTag)->Generated(expl.Current());
779         TCollection_AsciiString aStr(theTag);
780         aName = theName + aStr.ToCString();
781         buildName(theTag, aName);
782         theTag++;
783       }
784     } else {
785       TopExp_Explorer expl(aShape, TopAbs_EDGE);
786       for (; expl.More(); expl.Next()) {
787         builder(theTag)->Generated(expl.Current());
788         TCollection_AsciiString aStr(theTag);
789         aName = theName + aStr.ToCString();
790         buildName(theTag, aName);
791         theTag++;
792       }
793       // and load generated vertices.
794       TopTools_DataMapOfShapeShape generated;
795       if (getDangleShapes(aShape, TopAbs_EDGE, generated))
796       {
797         TNaming_Builder* pBuilder = builder(theTag++);
798         loadGeneratedDangleShapes(aShape, TopAbs_EDGE, pBuilder);
799       }
800     }
801   } else if (aShape.ShapeType() == TopAbs_EDGE) {
802     TopExp_Explorer expl(aShape, TopAbs_VERTEX);
803     for (; expl.More(); expl.Next()) {
804       builder(theTag)->Generated(expl.Current());
805       TCollection_AsciiString aStr(theTag);
806       aName = theName + aStr.ToCString();
807       buildName(theTag, aName);
808       theTag++;
809     }
810   }
811 }
812
813 //=======================================================================
814 int findAmbiguities(const TopoDS_Shape&           theShapeIn,
815   TopTools_ListOfShape&   theList)
816 {
817   theList.Clear();
818   // edges -> ancestor faces list
819   TopTools_IndexedDataMapOfShapeListOfShape aSubShapeAndAncestors;
820   TopExp::MapShapesAndAncestors(theShapeIn, TopAbs_EDGE, TopAbs_FACE, aSubShapeAndAncestors);
821   // keeps the shapes which are already in the resulting list
822   TopTools_MapOfShape alreadyThere;
823   // map from faces identifier (combination of hash-codes) to list of edges produced such ID
824   NCollection_DataMap<int, NCollection_List<TopoDS_Shape> > aFacesIDs;
825
826   TopTools_IndexedDataMapOfShapeListOfShape::Iterator anAncestorsIter(aSubShapeAndAncestors);
827   for (; anAncestorsIter.More(); anAncestorsIter.Next()) {
828     const TopTools_ListOfShape& ancestors = anAncestorsIter.Value();
829     if (ancestors.Extent() < 2)
830       continue;
831     Standard_Integer anID = 0;
832     for(TopTools_ListIteratorOfListOfShape aFaceIt(ancestors); aFaceIt.More(); aFaceIt.Next()) {
833       anID ^= HashCode(aFaceIt.ChangeValue(), 1990657); // Pierpont prime
834     }
835     if (aFacesIDs.IsBound(anID)) { // there found same edge, check they really have same faces
836       const NCollection_List<TopoDS_Shape>& aSameFaces1 =
837         aSubShapeAndAncestors.FindFromKey(anAncestorsIter.Key());
838       NCollection_List<TopoDS_Shape>::Iterator aSameEdge(aFacesIDs.ChangeFind(anID));
839       for(; aSameEdge.More(); aSameEdge.Next()) {
840         const NCollection_List<TopoDS_Shape>& aSameFaces2 =
841           aSubShapeAndAncestors.FindFromKey(aSameEdge.Value());
842         if (aSameFaces2.Extent() != aSameFaces1.Extent()) // the number of faces is different
843           break;
844
845         NCollection_List<TopoDS_Shape>::Iterator aFaceIter1(aSameFaces1);
846         for(; aFaceIter1.More(); aFaceIter1.Next()) {
847           NCollection_List<TopoDS_Shape>::Iterator aFaceIter2(aSameFaces2);
848           for(; aFaceIter2.More(); aFaceIter2.Next()) {
849             if (aFaceIter1.Value().IsSame(aFaceIter2.Value()))
850               break;
851           }
852           if (!aFaceIter2.More()) // aFaceIter1 contains a face, which is not in aFaceIter2
853             break;
854         }
855         if (!aFaceIter1.More()) { // all the faces are same => put to the result
856           if (alreadyThere.Add(aSameEdge.Value()))
857             theList.Append(aSameEdge.Value());
858           if (alreadyThere.Add(anAncestorsIter.Key()))
859             theList.Append(anAncestorsIter.Key());
860         }
861       }
862     } else { // ID is unique, just add this edge
863       aFacesIDs.Bind(anID, NCollection_List<TopoDS_Shape>());
864     }
865     aFacesIDs.ChangeFind(anID).Append(anAncestorsIter.Key()); // add to the list anyway
866   }
867   return theList.Extent();
868 }
869
870 //=======================================================================
871 void Model_BodyBuilder::loadFirstLevel(
872   GeomShapePtr theShape, const std::string& theName, int&  theTag)
873 {
874   if(theShape->isNull()) return;
875   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
876   std::string aName;
877   if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) {
878     TopoDS_Iterator itr(aShape);
879     for (; itr.More(); itr.Next()) {
880       builder(theTag)->Generated(itr.Value());
881       TCollection_AsciiString aStr(theTag);
882       aName = theName + aStr.ToCString();
883       buildName(theTag, aName);
884       if(!theName.empty()) buildName(theTag, aName);
885       theTag++;
886       if (itr.Value().ShapeType() == TopAbs_COMPOUND ||
887         itr.Value().ShapeType() == TopAbs_COMPSOLID)
888       {
889         GeomShapePtr itrShape(new GeomAPI_Shape());
890         itrShape->setImpl(new TopoDS_Shape(itr.Value()));
891         loadFirstLevel(itrShape, theName, theTag);
892       } else {
893         GeomShapePtr itrShape(new GeomAPI_Shape());
894         itrShape->setImpl(new TopoDS_Shape(itr.Value()));
895         loadNextLevels(itrShape, theName, theTag);
896       }
897     }
898   } else {
899     GeomShapePtr itrShape(new GeomAPI_Shape());
900     itrShape->setImpl(new TopoDS_Shape(aShape));
901     loadNextLevels(itrShape, theName, theTag);
902   }
903   TopTools_ListOfShape   aList;
904   if(findAmbiguities(aShape, aList)) {
905     TopTools_ListIteratorOfListOfShape it(aList);
906     for (; it.More(); it.Next(),theTag++) {
907       builder(theTag)->Generated(it.Value());
908       TCollection_AsciiString aStr(theTag);
909       aName = theName + aStr.ToCString();
910       buildName(theTag, aName);
911     }
912   }
913 }
914
915 //=======================================================================
916 void Model_BodyBuilder::loadDisconnectedEdges(
917   GeomShapePtr theShape, const std::string& theName, int&  theTag)
918 {
919   if(theShape->isNull()) return;
920   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
921   TopTools_DataMapOfShapeListOfShape edgeNaborFaces;
922   TopTools_ListOfShape empty;
923   TopExp_Explorer explF(aShape, TopAbs_FACE);
924   for (; explF.More(); explF.Next()) {
925     const TopoDS_Shape& aFace = explF.Current();
926     TopExp_Explorer explV(aFace, TopAbs_EDGE);
927     for (; explV.More(); explV.Next()) {
928       const TopoDS_Shape& anEdge = explV.Current();
929       if (!edgeNaborFaces.IsBound(anEdge)) edgeNaborFaces.Bind(anEdge, empty);
930       Standard_Boolean faceIsNew = Standard_True;
931       TopTools_ListIteratorOfListOfShape itrF(edgeNaborFaces.Find(anEdge));
932       for (; itrF.More(); itrF.Next()) {
933         if (itrF.Value().IsSame(aFace)) {
934           faceIsNew = Standard_False;
935           break;
936         }
937       }
938       if (faceIsNew)
939         edgeNaborFaces.ChangeFind(anEdge).Append(aFace);
940     }
941   }
942
943   TopTools_MapOfShape anEdgesToDelete;
944   TopExp_Explorer anEx(aShape,TopAbs_EDGE);
945   std::string aName;
946   for(;anEx.More();anEx.Next()) {
947     Standard_Boolean aC0 = Standard_False;
948     TopoDS_Shape anEdge1 = anEx.Current();
949     if (edgeNaborFaces.IsBound(anEdge1)) {
950       const TopTools_ListOfShape& aList1 = edgeNaborFaces.Find(anEdge1);
951       if (aList1.Extent()<2) continue;
952       TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(edgeNaborFaces);
953       for (; itr.More(); itr.Next()) {
954         TopoDS_Shape anEdge2 = itr.Key();
955         if(anEdgesToDelete.Contains(anEdge2)) continue;
956         if (anEdge1.IsSame(anEdge2)) continue;
957         const TopTools_ListOfShape& aList2 = itr.Value();
958         // compare lists of the neighbour faces of edge1 and edge2
959         if (aList1.Extent() == aList2.Extent()) {
960           Standard_Integer aMatches = 0;
961           for(TopTools_ListIteratorOfListOfShape aLIter1(aList1);aLIter1.More();aLIter1.Next())
962             for(TopTools_ListIteratorOfListOfShape aLIter2(aList2);aLIter2.More();aLIter2.Next())
963               if (aLIter1.Value().IsSame(aLIter2.Value())) aMatches++;
964           if (aMatches == aList1.Extent()) {
965             aC0=Standard_True;
966             builder(theTag)->Generated(anEdge2);
967             anEdgesToDelete.Add(anEdge2);
968             TCollection_AsciiString aStr(theTag);
969             aName = theName + aStr.ToCString();
970             buildName(theTag, aName);
971             theTag++;
972           }
973         }
974       }
975       TopTools_MapIteratorOfMapOfShape itDelete(anEdgesToDelete);
976       for(;itDelete.More();itDelete.Next())
977         edgeNaborFaces.UnBind(itDelete.Key());
978       edgeNaborFaces.UnBind(anEdge1);
979     }
980     if (aC0) {
981       builder(theTag)->Generated(anEdge1);
982       TCollection_AsciiString aStr(theTag);
983       aName = theName + aStr.ToCString();
984       buildName(theTag, aName);
985       theTag++;
986     }
987   }
988 }
989
990 void Model_BodyBuilder::loadDisconnectedVertexes(GeomShapePtr theShape,
991                                                  const std::string& theName, int&  theTag)
992 {
993   if(theShape->isNull()) return;
994   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
995   TopTools_DataMapOfShapeListOfShape vertexNaborEdges;
996   TopTools_ListOfShape empty;
997   TopExp_Explorer explF(aShape, TopAbs_EDGE);
998   for (; explF.More(); explF.Next()) {
999     const TopoDS_Shape& anEdge = explF.Current();
1000     TopExp_Explorer explV(anEdge, TopAbs_VERTEX);
1001     for (; explV.More(); explV.Next()) {
1002       const TopoDS_Shape& aVertex = explV.Current();
1003       if (!vertexNaborEdges.IsBound(aVertex)) vertexNaborEdges.Bind(aVertex, empty);
1004       Standard_Boolean faceIsNew = Standard_True;
1005       TopTools_ListIteratorOfListOfShape itrF(vertexNaborEdges.Find(aVertex));
1006       for (; itrF.More(); itrF.Next()) {
1007         if (itrF.Value().IsSame(anEdge)) {
1008           faceIsNew = Standard_False;
1009           break;
1010         }
1011       }
1012       if (faceIsNew) {
1013         vertexNaborEdges.ChangeFind(aVertex).Append(anEdge);
1014       }
1015     }
1016   }
1017   std::string aName;
1018   TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(vertexNaborEdges);
1019   for (; itr.More(); itr.Next()) {
1020     const TopTools_ListOfShape& naborEdges = itr.Value();
1021     if (naborEdges.Extent() < 2) {
1022       builder(theTag)->Generated(itr.Key());
1023       TCollection_AsciiString aStr(theTag);
1024       aName = theName + aStr.ToCString();
1025       buildName(theTag, aName);
1026       theTag++;
1027     }
1028   }
1029 }
1030
1031 GeomShapePtr Model_BodyBuilder::shape()
1032 {
1033   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
1034   if (aData && aData->isValid()) {
1035     TDF_Label aShapeLab = aData->shapeLab();
1036     Handle(TDF_Reference) aRef;
1037     if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
1038       aShapeLab = aRef->Get();
1039     }
1040     Handle(TNaming_NamedShape) aName;
1041     if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
1042       TopoDS_Shape aShape = aName->Get();
1043       if (!aShape.IsNull()) {
1044         GeomShapePtr aRes(new GeomAPI_Shape);
1045         aRes->setImpl(new TopoDS_Shape(aShape));
1046         return aRes;
1047       }
1048     }
1049   }
1050   return GeomShapePtr();
1051 }
1052
1053 bool Model_BodyBuilder::isLatestEqual(const GeomShapePtr& theShape)
1054 {
1055   if (theShape.get()) {
1056     TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
1057     std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
1058     if (aData) {
1059       TDF_Label& aShapeLab = aData->shapeLab();
1060       Handle(TNaming_NamedShape) aName;
1061       if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
1062         TopoDS_Shape aLatest = TNaming_Tool::CurrentShape(aName);
1063         if (aLatest.IsNull())
1064           return false;
1065         if (aLatest.IsEqual(aShape))
1066           return true;
1067         // check sub-shapes for comp-solids:
1068         for (TopExp_Explorer anExp(aShape, aLatest.ShapeType()); anExp.More(); anExp.Next()) {
1069           if (aLatest.IsEqual(anExp.Current()))
1070             return true;
1071         }
1072       }
1073     }
1074   }
1075   return false;
1076 }