1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Model_BodyBuilder.h>
23 #include <Model_Data.h>
24 #include <Model_Document.h>
25 #include <ModelAPI_Session.h>
26 #include <TNaming_Builder.hxx>
27 #include <TNaming_NamedShape.hxx>
28 #include <TNaming_Iterator.hxx>
29 #include <TNaming_Tool.hxx>
30 #include <TDataStd_Name.hxx>
31 #include <TDataStd_Integer.hxx>
33 #include <TopoDS_Face.hxx>
34 #include <TDF_ChildIterator.hxx>
35 #include <TDF_ChildIDIterator.hxx>
36 #include <TDF_Reference.hxx>
37 #include <TopTools_MapOfShape.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <TopTools_ListOfShape.hxx>
40 #include <TopTools_ListIteratorOfListOfShape.hxx>
41 #include <TopTools_DataMapOfShapeListOfShape.hxx>
42 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
43 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
44 #include <TopTools_MapIteratorOfMapOfShape.hxx>
45 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
46 #include <TopTools_IndexedMapOfShape.hxx>
47 #include <TopTools_DataMapOfShapeShape.hxx>
49 #include <BRepTools.hxx>
50 #include <BRep_Tool.hxx>
51 #include <BRepTools_History.hxx>
52 #include <GeomAPI_Shape.h>
53 #include <GeomAPI_ShapeExplorer.h>
54 #include <GeomAlgoAPI_MakeShape.h>
55 #include <GeomAlgoAPI_SortListOfShapes.h>
56 #include <Config_PropManager.h>
58 //#include <TCollection_AsciiString.hxx>
59 //#include <TDF_Tool.hxx>
60 //#define DEB_IMPORT 1
62 static const int INVALID_TAG = -1;
63 static const int GENERATED_VERTICES_TAG = 1;
64 static const int GENERATED_EDGES_TAG = 2;
65 static const int GENERATED_FACES_TAG = 3;
66 static const int MODIFIED_VERTICES_TAG = 4;
67 static const int MODIFIED_EDGES_TAG = 5;
68 static const int MODIFIED_FACES_TAG = 6;
69 static const int DELETED_TAG = 7;
70 static const int PRIMITIVES_START_TAG = 11;
72 static int getGenerationTag(const TopoDS_Shape& theShape) {
73 TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
75 case TopAbs_VERTEX: return GENERATED_VERTICES_TAG;
76 case TopAbs_EDGE: return GENERATED_EDGES_TAG;
77 case TopAbs_FACE: return GENERATED_FACES_TAG;
83 static int getModificationTag(const TopoDS_Shape& theShape) {
84 TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
86 case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG;
87 case TopAbs_EDGE: return MODIFIED_EDGES_TAG;
88 case TopAbs_FACE: return MODIFIED_FACES_TAG;
94 static TopAbs_ShapeEnum convertShapeType(const GeomAPI_Shape::ShapeType theType) {
96 case GeomAPI_Shape::VERTEX: return TopAbs_VERTEX;
97 case GeomAPI_Shape::EDGE: return TopAbs_EDGE;
98 case GeomAPI_Shape::WIRE: return TopAbs_WIRE;
99 case GeomAPI_Shape::FACE: return TopAbs_FACE;
100 case GeomAPI_Shape::SHELL: return TopAbs_SHELL;
101 case GeomAPI_Shape::SOLID: return TopAbs_SOLID;
102 case GeomAPI_Shape::COMPSOLID: return TopAbs_COMPSOLID;
103 case GeomAPI_Shape::COMPOUND: return TopAbs_COMPOUND;
104 case GeomAPI_Shape::SHAPE: return TopAbs_SHAPE;
109 static bool isAlreadyStored(const TNaming_Builder* theBuilder,
110 const TopoDS_Shape& theOldShape,
111 const TopoDS_Shape& theNewShape)
113 for (TNaming_Iterator aNamingIt(theBuilder->NamedShape());
117 if (aNamingIt.NewShape().IsSame(theNewShape)
118 && aNamingIt.OldShape().IsSame(theOldShape))
127 Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner)
128 : ModelAPI_BodyBuilder(theOwner),
129 myFreePrimitiveTag(PRIMITIVES_START_TAG)
133 void Model_BodyBuilder::store(const GeomShapePtr& theShape,
134 const bool theIsStoreSameShapes)
136 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
138 TDF_Label aShapeLab = aData->shapeLab();
141 // store the new shape as primitive
142 TNaming_Builder aBuilder(aShapeLab);
145 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
147 return; // null shape inside
149 if(!theIsStoreSameShapes) {
150 Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
151 if(!aNS.IsNull() && !aNS->IsEmpty()) {
152 // This shape is already in document, store reference instead of shape;
153 const TDF_Label aFoundLabel = aNS->Label();
154 TDF_Reference::Set(aShapeLab, aFoundLabel);
155 aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID());
160 aBuilder.Generated(aShape);
162 aShapeLab.ForgetAttribute(TDF_Reference::GetID());
163 if(!aBuilder.NamedShape()->IsEmpty()) {
164 Handle(TDataStd_Name) anAttr;
165 if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
166 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
168 std::shared_ptr<Model_Document> aDoc =
169 std::dynamic_pointer_cast<Model_Document>(document());
170 aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
177 void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
178 const GeomShapePtr& theToShape)
180 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
182 TDF_Label aShapeLab = aData->shapeLab();
185 // store the new shape as primitive
186 TNaming_Builder aBuilder(aShapeLab);
187 if (!theFromShape || !theToShape)
189 TopoDS_Shape aShapeBasis = theFromShape->impl<TopoDS_Shape>();
190 if (aShapeBasis.IsNull())
191 return; // null shape inside
192 TopoDS_Shape aShapeNew = theToShape->impl<TopoDS_Shape>();
193 if (aShapeNew.IsNull())
194 return; // null shape inside
195 aBuilder.Generated(aShapeBasis, aShapeNew);
197 if(!aBuilder.NamedShape()->IsEmpty()) {
198 Handle(TDataStd_Name) anAttr;
199 if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
200 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
202 std::shared_ptr<Model_Document> aDoc =
203 std::dynamic_pointer_cast<Model_Document>(document());
204 aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
211 TNaming_Builder* Model_BodyBuilder::builder(const int theTag)
213 std::map<int, TNaming_Builder*>::iterator aFind = myBuilders.find(theTag);
214 if (aFind == myBuilders.end()) {
215 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
216 myBuilders[theTag] = new TNaming_Builder(
217 theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
218 aFind = myBuilders.find(theTag);
220 return aFind->second;
223 void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
224 const GeomShapePtr& theNewShape,
225 const bool theIsCleanStored)
227 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
230 if (theIsCleanStored) clean();
231 // store the new shape as primitive
232 TNaming_Builder* aBuilder = builder(0);
233 if (!theOldShape || !theNewShape)
235 TopoDS_Shape aShapeOld = theOldShape->impl<TopoDS_Shape>();
236 if (aShapeOld.IsNull())
237 return; // null shape inside
238 TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
239 if (aShapeNew.IsNull())
240 return; // null shape inside
241 aBuilder->Modify(aShapeOld, aShapeNew);
242 if(!aBuilder->NamedShape()->IsEmpty()) {
243 Handle(TDataStd_Name) anAttr;
244 if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
245 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
247 std::shared_ptr<Model_Document> aDoc =
248 std::dynamic_pointer_cast<Model_Document>(document());
249 aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName);
256 void Model_BodyBuilder::storeWithoutNaming(const GeomShapePtr& theShape)
258 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
263 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
265 return; // null shape inside
266 TNaming_Builder aBuilder(aData->shapeLab());
267 aBuilder.Select(aShape, aShape);
271 void Model_BodyBuilder::clean()
273 TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>(data())->shapeLab();
276 std::map<int, TNaming_Builder*>::iterator aBuilder = myBuilders.begin();
277 for(; aBuilder != myBuilders.end(); aBuilder++) {
278 delete aBuilder->second;
279 // clear also shapes on cleaned sub-labels (#2241)
280 Handle(TNaming_NamedShape) aNS;
281 if (aLab.FindChild(aBuilder->first).FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
286 myPrimitivesNamesIndexMap.clear();
287 // remove the old reference (if any)
288 aLab.ForgetAttribute(TDF_Reference::GetID());
289 myFreePrimitiveTag = PRIMITIVES_START_TAG;
292 Model_BodyBuilder::~Model_BodyBuilder()
297 void Model_BodyBuilder::buildName(const int theTag, const std::string& theName)
299 std::string aName = theName;
300 std::string aPrefix = "";
302 case GENERATED_VERTICES_TAG: aPrefix = aName.empty() ? "Generated_Vertex" : "GV:"; break;
303 case GENERATED_EDGES_TAG: aPrefix = aName.empty() ? "Generated_Edge" : "GE:"; break;
304 case GENERATED_FACES_TAG: aPrefix = aName.empty() ? "Generated_Face" : "GF:"; break;
305 case MODIFIED_VERTICES_TAG: aPrefix = aName.empty() ? "Modified_Vertex" : "MV:"; break;
306 case MODIFIED_EDGES_TAG: aPrefix = aName.empty() ? "Modified_Edge" : "ME:"; break;
307 case MODIFIED_FACES_TAG: aPrefix = aName.empty() ? "Modified_Face" : "MF:"; break;
309 aName.insert(0, aPrefix);
311 TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str());
313 void Model_BodyBuilder::generated(const GeomShapePtr& theNewShape,
314 const std::string& theName)
316 GeomShapePtr aResultShape = shape();
318 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(theNewShape, false);
319 if (aNewShapeIsNotInResultShape) {
323 TopoDS_Shape aShape = theNewShape->impl<TopoDS_Shape>();
324 builder(myFreePrimitiveTag)->Generated(aShape);
325 if (!theName.empty()) {
326 std::string aName = theName;
327 if (myPrimitivesNamesIndexMap.find(theName) != myPrimitivesNamesIndexMap.end()) {
328 IndexTags& anIndexTags = myPrimitivesNamesIndexMap.find(theName)->second;
329 aName += "_" + std::to_string(++(anIndexTags.index));
330 anIndexTags.tags.push_back(myFreePrimitiveTag);
331 if (anIndexTags.index == 2) {
332 buildName(anIndexTags.tags.front(), theName + "_1");
336 IndexTags anIndexTags;
337 anIndexTags.index = 1;
338 anIndexTags.tags.push_back(myFreePrimitiveTag);
339 myPrimitivesNamesIndexMap[theName] = anIndexTags;
342 buildName(myFreePrimitiveTag, aName);
344 ++myFreePrimitiveTag;
347 void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape,
348 const GeomShapePtr& theNewShape,
349 const std::string& theName)
351 TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
352 TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
353 TopAbs_ShapeEnum aNewShapeType = aNewShape.ShapeType();
355 if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
356 // TODO: This is a workaround. New shape should be only vertex, edge or face.
357 TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
358 aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
359 for (TopExp_Explorer anExp(aNewShape, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
360 builder(aTag)->Generated(anOldShape, anExp.Current());
362 buildName(aTag, theName);
364 aTag = getGenerationTag(aNewShape);
365 if (aTag == INVALID_TAG) return;
366 builder(aTag)->Generated(anOldShape, aNewShape);
367 buildName(aTag, theName);
371 void Model_BodyBuilder::modified(const GeomShapePtr& theOldShape,
372 const GeomShapePtr& theNewShape,
373 const std::string& theName)
375 TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
376 TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
377 int aTag = getModificationTag(aNewShape);
378 if (aTag == INVALID_TAG) return;
379 builder(aTag)->Modify(anOldShape, aNewShape);
380 buildName(aTag, theName);
383 void Model_BodyBuilder::deleted(const GeomShapePtr& theOldShape)
385 TopoDS_Shape aShape = theOldShape->impl<TopoDS_Shape>();
386 builder(DELETED_TAG)->Delete(aShape);
389 void Model_BodyBuilder::loadDeletedShapes(const GeomMakeShapePtr& theAlgo,
390 const GeomShapePtr& theOldShape,
391 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
392 const GeomShapePtr& theShapesToExclude)
394 TopTools_MapOfShape anAlreadyProcessedShapes;
395 GeomShapePtr aResultShape = shape();
396 for (GeomAPI_ShapeExplorer anExp(theOldShape, theShapeTypeToExplore);
400 GeomShapePtr anOldSubShape = anExp.current();
401 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
402 if (!anAlreadyProcessedShapes.Add(anOldSubShape_)
403 || !theAlgo->isDeleted(anOldSubShape)
404 || aResultShape->isSubShape(anOldSubShape, false)
405 || (theShapesToExclude.get() && theShapesToExclude->isSubShape(anOldSubShape, false)))
410 ListOfShape aNewShapes;
411 if (BRepTools_History::IsSupportedType(anOldSubShape_)) { // to avoid crash in #2572
412 theAlgo->modified(anOldSubShape, aNewShapes);
415 if (aNewShapes.size() == 0
416 || (aNewShapes.size() == 1 && aNewShapes.front()->isSame(anOldSubShape))) {
417 builder(DELETED_TAG)->Delete(anOldSubShape_);
422 static void removeBadShapes(ListOfShape& theShapes)
424 ListOfShape::iterator anIt = theShapes.begin();
425 while (anIt != theShapes.end()) {
426 TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
427 bool aSkip = aNewShape.IsNull()
428 || (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
430 ListOfShape::iterator aRemoveIt = anIt++;
431 theShapes.erase(aRemoveIt);
438 // Keep only the shapes with minimal shape type
439 static void keepTopLevelShapes(ListOfShape& theShapes,
440 const TopoDS_Shape& theRoot,
441 const GeomShapePtr& theResultShape = GeomShapePtr())
443 GeomAPI_Shape::ShapeType aKeepShapeType = GeomAPI_Shape::SHAPE;
444 ListOfShape::iterator anIt = theShapes.begin();
445 while (anIt != theShapes.end()) {
446 TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
447 bool aSkip = aNewShape.IsNull() ||
448 (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
449 if (aSkip || theRoot.IsSame(aNewShape) || (theResultShape &&
450 (!theResultShape->isSubShape(*anIt, false) || theResultShape->isSame(*anIt)))) {
451 ListOfShape::iterator aRemoveIt = anIt++;
452 theShapes.erase(aRemoveIt);
454 GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
455 if (aType < aKeepShapeType) {
456 // found a shape with lesser shape type => remove all previous shapes
457 aKeepShapeType = aType;
458 theShapes.erase(theShapes.begin(), anIt);
460 } else if (aType > aKeepShapeType) {
461 // shapes with greater shape type should be removed from the list
462 ListOfShape::iterator aRemoveIt = anIt++;
463 theShapes.erase(aRemoveIt);
470 // returns an ancestor shape-type that used for naming-definition of the sub-type
471 TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) {
472 if (theSubType == TopAbs_VERTEX)
474 if (theSubType == TopAbs_EDGE)
476 return TopAbs_VERTEX; // bad case
479 void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
480 const GeomShapePtr& theOldShape,
481 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
482 const std::string& theName)
484 GeomShapePtr aResultShape = shape();
485 GeomShapePtr aShapeToExplore = theOldShape;
486 if (theAlgo->isNewShapesCollected(theOldShape, theShapeTypeToExplore)) {
487 // use optimized set of old shapes for this
488 GeomShapePtr aCompound = theAlgo->oldShapesForNew(theOldShape,
490 theShapeTypeToExplore);
491 if (aCompound.get()) aShapeToExplore = aCompound;
494 TopTools_MapOfShape anAlreadyProcessedShapes;
495 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
496 for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore);
497 anOldShapeExp.more();
498 anOldShapeExp.next())
500 GeomShapePtr anOldSubShape = anOldShapeExp.current();
501 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
503 // There is no sense to write history if shape already processed
504 // or old shape does not exist in the document.
505 bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
506 bool anOldSubShapeNotInTree = !TNaming_Tool::HasLabel(aData->shapeLab(), anOldSubShape_);
507 if (anOldSubShapeNotInTree) {// check this is in the module document
508 TDF_Label anAccess = std::dynamic_pointer_cast<Model_Document>(
509 ModelAPI_Session::get()->moduleDocument())->generalLabel();
510 anOldSubShapeNotInTree = !TNaming_Tool::HasLabel(anAccess, anOldSubShape_);
512 if (anOldSubShapeAlreadyProcessed
513 || anOldSubShapeNotInTree)
519 ListOfShape aNewShapes;
520 theAlgo->modified(anOldSubShape, aNewShapes);
522 for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
523 aNewShapesIt != aNewShapes.cend();
526 GeomShapePtr aNewShape = *aNewShapesIt;
527 const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
528 bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
530 bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
531 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
532 if (aNewShapeIsSameAsOldShape
533 || aNewShapeIsNotInResultShape)
538 TNaming_Builder* aBuilder;
539 if (aResultShape->isSame(aNewShape)) {
540 // keep the modification evolution on the root level (2241 - history propagation issue)
541 aBuilder = builder(0);
542 TDF_Label aShapeLab = aBuilder->NamedShape()->Label();
543 Handle(TDF_Reference) aRef;
544 if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
545 // Store only in case if it does not have reference.
549 // Check if new shape was already stored.
550 if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue;
552 if (!aBuilder->NamedShape().IsNull() &&
553 ((isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_GENERATED)
554 || (!isGenerated && aBuilder->NamedShape()->Evolution() != TNaming_MODIFY)))
556 myBuilders.erase(0); // clear old builder to avoid different evolutions crash
557 aBuilder = builder(0);
560 int aTag = isGenerated ? getGenerationTag(aNewShape_)
561 : getModificationTag(aNewShape_);
562 aBuilder = builder(aTag);
564 // Check if new shape was already stored.
565 if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_)) continue;
567 buildName(aTag, theName);
570 isGenerated ? aBuilder->Generated(anOldSubShape_, aNewShape_)
571 : aBuilder->Modify(anOldSubShape_, aNewShape_);
576 void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
577 const GeomShapePtr& theOldShape,
578 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
579 const std::string& theName)
581 GeomShapePtr aResultShape = shape();
582 TopTools_MapOfShape anAlreadyProcessedShapes;
583 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
584 for (GeomAPI_ShapeExplorer anOldShapeExp(theOldShape, theShapeTypeToExplore);
585 anOldShapeExp.more();
586 anOldShapeExp.next())
588 GeomShapePtr anOldSubShape = anOldShapeExp.current();
589 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
591 // There is no sense to write history if shape already processed
592 // or old shape does not exist in the document.
593 bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
594 bool anOldSubShapeNotInTree = !TNaming_Tool::HasLabel(aData->shapeLab(), anOldSubShape_);
595 if (anOldSubShapeNotInTree) {// check this is in the module document
596 TDF_Label anAccess = std::dynamic_pointer_cast<Model_Document>(
597 ModelAPI_Session::get()->moduleDocument())->generalLabel();
598 anOldSubShapeNotInTree = !TNaming_Tool::HasLabel(anAccess, anOldSubShape_);
600 if (anOldSubShapeAlreadyProcessed
601 || anOldSubShapeNotInTree)
607 ListOfShape aNewShapes;
608 theAlgo->generated(anOldSubShape, aNewShapes);
610 keepTopLevelShapes(aNewShapes, anOldSubShape_);
612 for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
613 aNewShapesIt != aNewShapes.cend();
616 GeomShapePtr aNewShape = *aNewShapesIt;
617 const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
619 bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
620 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
621 if (aNewShapeIsSameAsOldShape
622 || aNewShapeIsNotInResultShape)
627 TopAbs_ShapeEnum aNewShapeType = aNewShape_.ShapeType();
628 if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
629 // TODO: This is a workaround. New shape should be only edge or face.
630 TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE
632 int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
633 for (TopExp_Explorer anExp(aNewShape_, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
634 builder(aTag)->Generated(anOldSubShape_, anExp.Current());
636 buildName(aTag, theName);
639 int aTag = getGenerationTag(aNewShape_);
640 if (aTag == INVALID_TAG) return;
641 builder(aTag)->Generated(anOldSubShape_, aNewShape_);
642 buildName(aTag, theName);
648 //=======================================================================
649 int getDangleShapes(const TopoDS_Shape& theShapeIn,
650 const TopAbs_ShapeEnum theGeneratedFrom,
651 TopTools_DataMapOfShapeShape& theDangles)
654 TopTools_IndexedDataMapOfShapeListOfShape subShapeAndAncestors;
655 TopAbs_ShapeEnum GeneratedTo;
656 if (theGeneratedFrom == TopAbs_FACE) GeneratedTo = TopAbs_EDGE;
657 else if (theGeneratedFrom == TopAbs_EDGE) GeneratedTo = TopAbs_VERTEX;
658 else return Standard_False;
659 TopExp::MapShapesAndAncestors(theShapeIn, GeneratedTo, theGeneratedFrom, subShapeAndAncestors);
660 for (Standard_Integer i = 1; i <= subShapeAndAncestors.Extent(); i++) {
661 const TopoDS_Shape& mayBeDangle = subShapeAndAncestors.FindKey(i);
662 const TopTools_ListOfShape& ancestors = subShapeAndAncestors.FindFromIndex(i);
663 if (ancestors.Extent() == 1) theDangles.Bind(ancestors.First(), mayBeDangle);
665 return theDangles.Extent();
668 //=======================================================================
669 void loadGeneratedDangleShapes(
670 const TopoDS_Shape& theShapeIn,
671 const TopAbs_ShapeEnum theGeneratedFrom,
672 TNaming_Builder * theBuilder)
674 TopTools_DataMapOfShapeShape dangles;
675 if (!getDangleShapes(theShapeIn, theGeneratedFrom, dangles)) return;
676 TopTools_DataMapIteratorOfDataMapOfShapeShape itr(dangles);
677 for (; itr.More(); itr.Next())
678 theBuilder->Generated(itr.Key(), itr.Value());
681 //=======================================================================
682 void Model_BodyBuilder::loadNextLevels(GeomShapePtr theShape,
683 const std::string& theName)
685 if(theShape->isNull()) return;
686 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
688 if (aShape.ShapeType() == TopAbs_SOLID) {
689 TopExp_Explorer expl(aShape, TopAbs_FACE);
690 for (; expl.More(); expl.Next()) {
691 builder(myFreePrimitiveTag)->Generated(expl.Current());
692 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
693 aName = theName + "_" + aStr.ToCString();
694 buildName(myFreePrimitiveTag, aName);
695 ++myFreePrimitiveTag;
698 else if (aShape.ShapeType() == TopAbs_SHELL || aShape.ShapeType() == TopAbs_FACE) {
699 // load faces and all the free edges
700 TopTools_IndexedMapOfShape Faces;
701 TopExp::MapShapes(aShape, TopAbs_FACE, Faces);
702 if (Faces.Extent() > 1 || (aShape.ShapeType() == TopAbs_SHELL && Faces.Extent() == 1)) {
703 TopExp_Explorer expl(aShape, TopAbs_FACE);
704 for (; expl.More(); expl.Next()) {
705 builder(myFreePrimitiveTag)->Generated(expl.Current());
706 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
707 aName = theName + "_" + aStr.ToCString();
708 buildName(myFreePrimitiveTag, aName);
709 ++myFreePrimitiveTag;
712 TopTools_IndexedDataMapOfShapeListOfShape anEdgeAndNeighbourFaces;
713 TopExp::MapShapesAndAncestors(aShape, TopAbs_EDGE, TopAbs_FACE, anEdgeAndNeighbourFaces);
714 for (Standard_Integer i = 1; i <= anEdgeAndNeighbourFaces.Extent(); i++)
716 const TopTools_ListOfShape& aLL = anEdgeAndNeighbourFaces.FindFromIndex(i);
717 if (aLL.Extent() < 2) {
718 if (BRep_Tool::Degenerated(TopoDS::Edge(anEdgeAndNeighbourFaces.FindKey(i))))
720 builder(myFreePrimitiveTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
721 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
722 aName = theName + "_" + aStr.ToCString();
723 buildName(myFreePrimitiveTag, aName);
724 ++myFreePrimitiveTag;
726 TopTools_ListIteratorOfListOfShape anIter(aLL);
727 const TopoDS_Face& aFace = TopoDS::Face(anIter.Value());
729 if(aFace.IsEqual(anIter.Value())) {
730 builder(myFreePrimitiveTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
731 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
732 aName = theName + "_" + aStr.ToCString();
733 buildName(myFreePrimitiveTag, aName);
734 ++myFreePrimitiveTag;
738 } else if (aShape.ShapeType() == TopAbs_WIRE) {
739 TopTools_IndexedMapOfShape Edges;
740 BRepTools::Map3DEdges(aShape, Edges);
741 if (Edges.Extent() == 1) {
742 builder(myFreePrimitiveTag++)->Generated(Edges.FindKey(1));
743 TopExp_Explorer expl(aShape, TopAbs_VERTEX);
744 for (; expl.More(); expl.Next()) {
745 builder(myFreePrimitiveTag)->Generated(expl.Current());
746 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
747 aName = theName + "_" + aStr.ToCString();
748 buildName(myFreePrimitiveTag, aName);
749 ++myFreePrimitiveTag;
752 TopExp_Explorer expl(aShape, TopAbs_EDGE);
753 for (; expl.More(); expl.Next()) {
754 builder(myFreePrimitiveTag)->Generated(expl.Current());
755 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
756 aName = theName + "_" + aStr.ToCString();
757 buildName(myFreePrimitiveTag, aName);
758 ++myFreePrimitiveTag;
760 // and load generated vertices.
761 TopTools_DataMapOfShapeShape generated;
762 if (getDangleShapes(aShape, TopAbs_EDGE, generated))
764 TNaming_Builder* pBuilder = builder(myFreePrimitiveTag++);
765 loadGeneratedDangleShapes(aShape, TopAbs_EDGE, pBuilder);
768 } else if (aShape.ShapeType() == TopAbs_EDGE) {
769 TopExp_Explorer expl(aShape, TopAbs_VERTEX);
770 for (; expl.More(); expl.Next()) {
771 builder(myFreePrimitiveTag)->Generated(expl.Current());
772 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
773 aName = theName + "_" + aStr.ToCString();
774 buildName(myFreePrimitiveTag, aName);
775 ++myFreePrimitiveTag;
780 //=======================================================================
781 int findAmbiguities(const TopoDS_Shape& theShapeIn,
782 TopTools_ListOfShape& theList)
785 // edges -> ancestor faces list
786 TopTools_IndexedDataMapOfShapeListOfShape aSubShapeAndAncestors;
787 TopExp::MapShapesAndAncestors(theShapeIn, TopAbs_EDGE, TopAbs_FACE, aSubShapeAndAncestors);
788 // keeps the shapes which are already in the resulting list
789 TopTools_MapOfShape alreadyThere;
790 // map from faces identifier (combination of hash-codes) to list of edges produced such ID
791 NCollection_DataMap<int, NCollection_List<TopoDS_Shape> > aFacesIDs;
793 TopTools_IndexedDataMapOfShapeListOfShape::Iterator anAncestorsIter(aSubShapeAndAncestors);
794 for (; anAncestorsIter.More(); anAncestorsIter.Next()) {
795 const TopTools_ListOfShape& ancestors = anAncestorsIter.Value();
796 if (ancestors.Extent() < 2)
798 Standard_Integer anID = 0;
799 for(TopTools_ListIteratorOfListOfShape aFaceIt(ancestors); aFaceIt.More(); aFaceIt.Next()) {
800 anID ^= HashCode(aFaceIt.ChangeValue(), 1990657); // Pierpont prime
802 if (aFacesIDs.IsBound(anID)) { // there found same edge, check they really have same faces
803 const NCollection_List<TopoDS_Shape>& aSameFaces1 =
804 aSubShapeAndAncestors.FindFromKey(anAncestorsIter.Key());
805 NCollection_List<TopoDS_Shape>::Iterator aSameEdge(aFacesIDs.ChangeFind(anID));
806 for(; aSameEdge.More(); aSameEdge.Next()) {
807 const NCollection_List<TopoDS_Shape>& aSameFaces2 =
808 aSubShapeAndAncestors.FindFromKey(aSameEdge.Value());
809 if (aSameFaces2.Extent() != aSameFaces1.Extent()) // the number of faces is different
812 NCollection_List<TopoDS_Shape>::Iterator aFaceIter1(aSameFaces1);
813 for(; aFaceIter1.More(); aFaceIter1.Next()) {
814 NCollection_List<TopoDS_Shape>::Iterator aFaceIter2(aSameFaces2);
815 for(; aFaceIter2.More(); aFaceIter2.Next()) {
816 if (aFaceIter1.Value().IsSame(aFaceIter2.Value()))
819 if (!aFaceIter2.More()) // aFaceIter1 contains a face, which is not in aFaceIter2
822 if (!aFaceIter1.More()) { // all the faces are same => put to the result
823 if (alreadyThere.Add(aSameEdge.Value()))
824 theList.Append(aSameEdge.Value());
825 if (alreadyThere.Add(anAncestorsIter.Key()))
826 theList.Append(anAncestorsIter.Key());
829 } else { // ID is unique, just add this edge
830 aFacesIDs.Bind(anID, NCollection_List<TopoDS_Shape>());
832 aFacesIDs.ChangeFind(anID).Append(anAncestorsIter.Key()); // add to the list anyway
834 return theList.Extent();
837 //=======================================================================
838 void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
840 if(theShape->isNull()) return;
841 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
843 if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) {
844 TopoDS_Iterator itr(aShape);
845 for (; itr.More(); itr.Next()) {
846 builder(myFreePrimitiveTag)->Generated(itr.Value());
847 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
848 aName = theName + "_" + aStr.ToCString();
849 buildName(myFreePrimitiveTag, aName);
850 ++myFreePrimitiveTag;
851 if (itr.Value().ShapeType() == TopAbs_COMPOUND ||
852 itr.Value().ShapeType() == TopAbs_COMPSOLID)
854 GeomShapePtr itrShape(new GeomAPI_Shape());
855 itrShape->setImpl(new TopoDS_Shape(itr.Value()));
856 loadFirstLevel(itrShape, theName);
858 GeomShapePtr itrShape(new GeomAPI_Shape());
859 itrShape->setImpl(new TopoDS_Shape(itr.Value()));
860 loadNextLevels(itrShape, theName);
864 GeomShapePtr itrShape(new GeomAPI_Shape());
865 itrShape->setImpl(new TopoDS_Shape(aShape));
866 loadNextLevels(itrShape, theName);
868 TopTools_ListOfShape aList;
869 if(findAmbiguities(aShape, aList)) {
870 TopTools_ListIteratorOfListOfShape it(aList);
871 for (; it.More(); it.Next(), ++myFreePrimitiveTag) {
872 builder(myFreePrimitiveTag)->Generated(it.Value());
873 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
874 aName = theName + "_" + aStr.ToCString();
875 buildName(myFreePrimitiveTag, aName);
880 //=======================================================================
881 void Model_BodyBuilder::loadDisconnectedEdges(GeomShapePtr theShape, const std::string& theName)
883 if(theShape->isNull()) return;
884 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
885 TopTools_DataMapOfShapeListOfShape edgeNaborFaces;
886 TopTools_ListOfShape empty;
887 TopExp_Explorer explF(aShape, TopAbs_FACE);
888 for (; explF.More(); explF.Next()) {
889 const TopoDS_Shape& aFace = explF.Current();
890 TopExp_Explorer explV(aFace, TopAbs_EDGE);
891 for (; explV.More(); explV.Next()) {
892 const TopoDS_Shape& anEdge = explV.Current();
893 if (!edgeNaborFaces.IsBound(anEdge)) edgeNaborFaces.Bind(anEdge, empty);
894 Standard_Boolean faceIsNew = Standard_True;
895 TopTools_ListIteratorOfListOfShape itrF(edgeNaborFaces.Find(anEdge));
896 for (; itrF.More(); itrF.Next()) {
897 if (itrF.Value().IsSame(aFace)) {
898 faceIsNew = Standard_False;
903 edgeNaborFaces.ChangeFind(anEdge).Append(aFace);
907 TopTools_MapOfShape anEdgesToDelete;
908 TopExp_Explorer anEx(aShape,TopAbs_EDGE);
910 for(;anEx.More();anEx.Next()) {
911 Standard_Boolean aC0 = Standard_False;
912 TopoDS_Shape anEdge1 = anEx.Current();
913 if (edgeNaborFaces.IsBound(anEdge1)) {
914 const TopTools_ListOfShape& aList1 = edgeNaborFaces.Find(anEdge1);
915 if (aList1.Extent()<2) continue;
916 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(edgeNaborFaces);
917 for (; itr.More(); itr.Next()) {
918 TopoDS_Shape anEdge2 = itr.Key();
919 if(anEdgesToDelete.Contains(anEdge2)) continue;
920 if (anEdge1.IsSame(anEdge2)) continue;
921 const TopTools_ListOfShape& aList2 = itr.Value();
922 // compare lists of the neighbor faces of edge1 and edge2
923 if (aList1.Extent() == aList2.Extent()) {
924 Standard_Integer aMatches = 0;
925 for(TopTools_ListIteratorOfListOfShape aLIter1(aList1);aLIter1.More();aLIter1.Next())
926 for(TopTools_ListIteratorOfListOfShape aLIter2(aList2);aLIter2.More();aLIter2.Next())
927 if (aLIter1.Value().IsSame(aLIter2.Value())) aMatches++;
928 if (aMatches == aList1.Extent()) {
930 builder(myFreePrimitiveTag)->Generated(anEdge2);
931 anEdgesToDelete.Add(anEdge2);
932 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
933 aName = theName + "_" + aStr.ToCString();
934 buildName(myFreePrimitiveTag, aName);
935 ++myFreePrimitiveTag;
939 TopTools_MapIteratorOfMapOfShape itDelete(anEdgesToDelete);
940 for(;itDelete.More();itDelete.Next())
941 edgeNaborFaces.UnBind(itDelete.Key());
942 edgeNaborFaces.UnBind(anEdge1);
945 builder(myFreePrimitiveTag)->Generated(anEdge1);
946 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
947 aName = theName + "_" + aStr.ToCString();
948 buildName(myFreePrimitiveTag, aName);
949 ++myFreePrimitiveTag;
954 void Model_BodyBuilder::loadDisconnectedVertexes(GeomShapePtr theShape,
955 const std::string& theName)
957 if(theShape->isNull()) return;
958 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
959 TopTools_DataMapOfShapeListOfShape vertexNaborEdges;
960 TopTools_ListOfShape empty;
961 TopExp_Explorer explF(aShape, TopAbs_EDGE);
962 for (; explF.More(); explF.Next()) {
963 const TopoDS_Shape& anEdge = explF.Current();
964 TopExp_Explorer explV(anEdge, TopAbs_VERTEX);
965 for (; explV.More(); explV.Next()) {
966 const TopoDS_Shape& aVertex = explV.Current();
967 if (!vertexNaborEdges.IsBound(aVertex)) vertexNaborEdges.Bind(aVertex, empty);
968 Standard_Boolean faceIsNew = Standard_True;
969 TopTools_ListIteratorOfListOfShape itrF(vertexNaborEdges.Find(aVertex));
970 for (; itrF.More(); itrF.Next()) {
971 if (itrF.Value().IsSame(anEdge)) {
972 faceIsNew = Standard_False;
977 vertexNaborEdges.ChangeFind(aVertex).Append(anEdge);
982 TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itr(vertexNaborEdges);
983 for (; itr.More(); itr.Next()) {
984 const TopTools_ListOfShape& naborEdges = itr.Value();
985 if (naborEdges.Extent() < 2) {
986 builder(myFreePrimitiveTag)->Generated(itr.Key());
987 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
988 aName = theName + "_" + aStr.ToCString();
989 buildName(myFreePrimitiveTag, aName);
990 ++myFreePrimitiveTag;
995 GeomShapePtr Model_BodyBuilder::shape()
997 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
998 if (aData && aData->isValid()) {
999 TDF_Label aShapeLab = aData->shapeLab();
1000 Handle(TDF_Reference) aRef;
1001 if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
1002 aShapeLab = aRef->Get();
1004 Handle(TNaming_NamedShape) aName;
1005 if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
1006 TopoDS_Shape aShape = aName->Get();
1007 if (!aShape.IsNull()) {
1008 GeomShapePtr aRes(new GeomAPI_Shape);
1009 aRes->setImpl(new TopoDS_Shape(aShape));
1014 return GeomShapePtr();
1017 bool Model_BodyBuilder::isLatestEqual(const GeomShapePtr& theShape)
1019 if (theShape.get()) {
1020 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
1021 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
1023 TDF_Label aShapeLab = aData->shapeLab();
1024 Handle(TNaming_NamedShape) aName;
1025 if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
1026 TopoDS_Shape aLatest = TNaming_Tool::CurrentShape(aName);
1027 if (aLatest.IsNull())
1029 if (aLatest.IsEqual(aShape))
1031 // check sub-shapes for comp-solids:
1032 for (TopExp_Explorer anExp(aShape, aLatest.ShapeType()); anExp.More(); anExp.Next()) {
1033 if (aLatest.IsEqual(anExp.Current()))