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