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 <TNaming_SameShapeIterator.hxx>
31 #include <TDataStd_Name.hxx>
32 #include <TDataStd_Integer.hxx>
33 #include <TDataStd_ExtStringList.hxx>
35 #include <TopoDS_Face.hxx>
36 #include <TDF_ChildIterator.hxx>
37 #include <TDF_ChildIDIterator.hxx>
38 #include <TDF_Reference.hxx>
39 #include <TDF_Tool.hxx>
40 #include <TopTools_MapOfShape.hxx>
41 #include <TopExp_Explorer.hxx>
42 #include <TopTools_ListOfShape.hxx>
43 #include <TopTools_ListIteratorOfListOfShape.hxx>
44 #include <TopTools_DataMapOfShapeListOfShape.hxx>
45 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
46 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
47 #include <TopTools_MapIteratorOfMapOfShape.hxx>
48 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
49 #include <TopTools_IndexedMapOfShape.hxx>
50 #include <TopTools_DataMapOfShapeShape.hxx>
52 #include <BRepTools.hxx>
53 #include <BRep_Tool.hxx>
54 #include <BRepTools_History.hxx>
55 #include <GeomAPI_Shape.h>
56 #include <GeomAPI_ShapeExplorer.h>
57 #include <GeomAlgoAPI_MakeShape.h>
58 #include <GeomAlgoAPI_SortListOfShapes.h>
59 #include <Config_PropManager.h>
61 //#include <TCollection_AsciiString.hxx>
62 //#define DEB_IMPORT 1
64 /// reference to the shape in external document: sting list attribute identifier
65 static const Standard_GUID kEXTERNAL_SHAPE_REF("9aa5dd14-6d34-4a8d-8786-05842fd7bbbd");
67 static const int INVALID_TAG = -1;
68 static const int GENERATED_VERTICES_TAG = 1;
69 static const int GENERATED_EDGES_TAG = 2;
70 static const int GENERATED_FACES_TAG = 3;
71 static const int MODIFIED_VERTICES_TAG = 4;
72 static const int MODIFIED_EDGES_TAG = 5;
73 static const int MODIFIED_FACES_TAG = 6;
74 static const int DELETED_TAG = 7;
75 static const int PRIMITIVES_START_TAG = 11;
77 static int getGenerationTag(const TopoDS_Shape& theShape) {
78 TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
80 case TopAbs_VERTEX: return GENERATED_VERTICES_TAG;
81 case TopAbs_EDGE: return GENERATED_EDGES_TAG;
82 case TopAbs_FACE: return GENERATED_FACES_TAG;
88 static int getModificationTag(const TopoDS_Shape& theShape) {
89 TopAbs_ShapeEnum aShapeType = theShape.ShapeType();
91 case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG;
92 case TopAbs_EDGE: return MODIFIED_EDGES_TAG;
93 case TopAbs_FACE: return MODIFIED_FACES_TAG;
99 static bool isAlreadyStored(const TNaming_Builder* theBuilder,
100 const TopoDS_Shape& theOldShape,
101 const TopoDS_Shape& theNewShape)
103 for (TNaming_Iterator aNamingIt(theBuilder->NamedShape());
107 if (aNamingIt.NewShape().IsSame(theNewShape)
108 && aNamingIt.OldShape().IsSame(theOldShape))
117 Model_BodyBuilder::Model_BodyBuilder(ModelAPI_Object* theOwner)
118 : ModelAPI_BodyBuilder(theOwner),
119 myFreePrimitiveTag(PRIMITIVES_START_TAG)
123 void Model_BodyBuilder::store(const GeomShapePtr& theShape,
124 const bool theIsStoreSameShapes)
126 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
128 TDF_Label aShapeLab = aData->shapeLab();
131 // store the new shape as primitive
132 TNaming_Builder aBuilder(aShapeLab);
135 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
137 return; // null shape inside
139 if(!theIsStoreSameShapes) {
140 Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
141 // the last condition is for the issue 2751 : existing shape may be found in compound-NS
142 if(!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShape)) {
143 // This shape is already in document, store reference instead of shape;
144 const TDF_Label aFoundLabel = aNS->Label();
145 TDF_Reference::Set(aShapeLab, aFoundLabel);
146 aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID());
151 aBuilder.Generated(aShape);
153 aShapeLab.ForgetAttribute(TDF_Reference::GetID());
154 if(!aBuilder.NamedShape()->IsEmpty()) {
155 Handle(TDataStd_Name) anAttr;
156 if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
157 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
159 std::shared_ptr<Model_Document> aDoc =
160 std::dynamic_pointer_cast<Model_Document>(document());
161 aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
168 void Model_BodyBuilder::storeGenerated(const GeomShapePtr& theFromShape,
169 const GeomShapePtr& theToShape, const bool theIsCleanStored)
171 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
173 TDF_Label aShapeLab = aData->shapeLab();
175 if (theIsCleanStored)
177 // store the new shape as primitive
178 TNaming_Builder aBuilder(aShapeLab);
179 if (!theFromShape || !theToShape)
181 TopoDS_Shape aShapeBasis = theFromShape->impl<TopoDS_Shape>();
182 if (aShapeBasis.IsNull())
183 return; // null shape inside
184 TopoDS_Shape aShapeNew = theToShape->impl<TopoDS_Shape>();
185 if (aShapeNew.IsNull())
186 return; // null shape inside
187 aBuilder.Generated(aShapeBasis, aShapeNew);
189 if(!aBuilder.NamedShape()->IsEmpty()) {
190 Handle(TDataStd_Name) anAttr;
191 if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
192 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
194 std::shared_ptr<Model_Document> aDoc =
195 std::dynamic_pointer_cast<Model_Document>(document());
196 aDoc->addNamingName(aBuilder.NamedShape()->Label(), aName);
203 void Model_BodyBuilder::storeGenerated(const std::list<GeomShapePtr>& theFromShapes,
204 const GeomShapePtr& theToShape, const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
206 bool aStored = false;
207 std::list<GeomShapePtr>::const_iterator anOldIter = theFromShapes.cbegin();
208 for(; anOldIter != theFromShapes.cend(); anOldIter++) {
209 ListOfShape aNews; // check this old really generates theToShape
210 theMakeShape->generated(*anOldIter, aNews);
211 ListOfShape::iterator aNewIter = aNews.begin();
212 for(; aNewIter != aNews.end(); aNewIter++) {
213 if (theToShape->isSame(*aNewIter))
216 if (aNewIter != aNews.end()) {
217 storeGenerated(*anOldIter, theToShape, !aStored);
218 TNaming_Builder* aBuilder = builder(0);
219 aStored = !aBuilder->NamedShape()->IsEmpty();
222 if (!aStored) { // store as PRIMITIVE, but clean in any way
228 TNaming_Builder* Model_BodyBuilder::builder(const int theTag)
230 std::map<int, TNaming_Builder*>::iterator aFind = myBuilders.find(theTag);
231 if (aFind == myBuilders.end()) {
232 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
233 myBuilders[theTag] = new TNaming_Builder(
234 theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
235 aFind = myBuilders.find(theTag);
237 return aFind->second;
240 void Model_BodyBuilder::storeModified(const GeomShapePtr& theOldShape,
241 const GeomShapePtr& theNewShape,
242 const bool theIsCleanStored)
244 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
247 if (theIsCleanStored) clean();
248 // store the new shape as primitive
249 TNaming_Builder* aBuilder = builder(0);
250 if (!theOldShape || !theNewShape)
252 TopoDS_Shape aShapeOld = theOldShape->impl<TopoDS_Shape>();
253 if (aShapeOld.IsNull())
254 return; // null shape inside
255 TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
256 if (aShapeNew.IsNull())
257 return; // null shape inside
258 aBuilder->Modify(aShapeOld, aShapeNew);
259 if(!aBuilder->NamedShape()->IsEmpty()) {
260 Handle(TDataStd_Name) anAttr;
261 if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
262 std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
264 std::shared_ptr<Model_Document> aDoc =
265 std::dynamic_pointer_cast<Model_Document>(document());
266 aDoc->addNamingName(aBuilder->NamedShape()->Label(), aName);
273 void Model_BodyBuilder::storeModified(const std::list<GeomShapePtr>& theOldShapes,
274 const GeomShapePtr& theNewShape, const std::shared_ptr<GeomAlgoAPI_MakeShape> theMakeShape)
276 bool aStored = false;
277 std::list<GeomShapePtr>::const_iterator anOldIter = theOldShapes.cbegin();
278 for(; anOldIter != theOldShapes.cend(); anOldIter++) {
279 ListOfShape aNews; // check this old really modifies theNewShape
280 theMakeShape->modified(*anOldIter, aNews);
281 ListOfShape::iterator aNewIter = aNews.begin();
282 for(; aNewIter != aNews.end(); aNewIter++) {
283 if (theNewShape->isSame(*aNewIter))
286 if (aNewIter != aNews.end()) {
287 storeModified(*anOldIter, theNewShape, !aStored);
288 TNaming_Builder* aBuilder = builder(0);
289 aStored = !aBuilder->NamedShape()->IsEmpty();
292 if (!aStored) { // store as PRIMITIVE, but clean in any way
298 void Model_BodyBuilder::clean()
300 TDF_Label aLab = std::dynamic_pointer_cast<Model_Data>(data())->shapeLab();
303 std::map<int, TNaming_Builder*>::iterator aBuilder = myBuilders.begin();
304 for(; aBuilder != myBuilders.end(); aBuilder++) {
305 Handle(TNaming_NamedShape) aNS = aBuilder->second->NamedShape();
306 delete aBuilder->second;
307 if (!aNS.IsNull() && !aNS->Label().IsNull())
308 aNS->Label().ForgetAttribute(TNaming_NamedShape::GetID());
311 myPrimitivesNamesIndexMap.clear();
312 // remove the old reference (if any)
313 aLab.ForgetAttribute(TDF_Reference::GetID());
314 myFreePrimitiveTag = PRIMITIVES_START_TAG;
315 TDF_ChildIDIterator anEntriesIter(aLab, kEXTERNAL_SHAPE_REF, true);
316 for(; anEntriesIter.More(); anEntriesIter.Next()) {
317 anEntriesIter.Value()->Label().ForgetAttribute(kEXTERNAL_SHAPE_REF);
321 void Model_BodyBuilder::cleanCash()
323 myPrimitivesNamesIndexMap.clear();
326 Model_BodyBuilder::~Model_BodyBuilder()
331 void Model_BodyBuilder::buildName(const int theTag, const std::string& theName)
333 std::string aName = theName;
334 std::string aPrefix = "";
336 case GENERATED_VERTICES_TAG: aPrefix = aName.empty() ? "Generated_Vertex" : "GV:"; break;
337 case GENERATED_EDGES_TAG: aPrefix = aName.empty() ? "Generated_Edge" : "GE:"; break;
338 case GENERATED_FACES_TAG: aPrefix = aName.empty() ? "Generated_Face" : "GF:"; break;
339 case MODIFIED_VERTICES_TAG: aPrefix = aName.empty() ? "Modified_Vertex" : "MV:"; break;
340 case MODIFIED_EDGES_TAG: aPrefix = aName.empty() ? "Modified_Edge" : "ME:"; break;
341 case MODIFIED_FACES_TAG: aPrefix = aName.empty() ? "Modified_Face" : "MF:"; break;
343 aName.insert(0, aPrefix);
345 TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str());
347 bool Model_BodyBuilder::generated(const GeomShapePtr& theNewShape,
348 const std::string& theName,
349 const bool theCheckIsInResult)
351 GeomShapePtr aResultShape = shape();
352 if (theCheckIsInResult) {
353 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(theNewShape, false);
354 if (aNewShapeIsNotInResultShape) {
359 TopoDS_Shape aShape = theNewShape->impl<TopoDS_Shape>();
360 builder(myFreePrimitiveTag)->Generated(aShape);
361 if (!theName.empty()) {
362 std::string aName = theName;
363 if (myPrimitivesNamesIndexMap.find(theName) != myPrimitivesNamesIndexMap.end()) {
364 IndexTags& anIndexTags = myPrimitivesNamesIndexMap.find(theName)->second;
365 aName += "_" + std::to_string(++(anIndexTags.index));
366 anIndexTags.tags.push_back(myFreePrimitiveTag);
367 if (anIndexTags.index == 2) {
368 buildName(anIndexTags.tags.front(), theName + "_1");
372 IndexTags anIndexTags;
373 anIndexTags.index = 1;
374 anIndexTags.tags.push_back(myFreePrimitiveTag);
375 myPrimitivesNamesIndexMap[theName] = anIndexTags;
378 buildName(myFreePrimitiveTag, aName);
380 ++myFreePrimitiveTag;
384 void Model_BodyBuilder::generated(const GeomShapePtr& theOldShape,
385 const GeomShapePtr& theNewShape,
386 const std::string& theName)
388 TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
389 TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
390 TopAbs_ShapeEnum aNewShapeType = aNewShape.ShapeType();
392 if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
393 // TODO: This is a workaround. New shape should be only vertex, edge or face.
394 TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
395 aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
396 for (TopExp_Explorer anExp(aNewShape, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
397 builder(aTag)->Generated(anOldShape, anExp.Current());
399 buildName(aTag, theName);
401 aTag = getGenerationTag(aNewShape);
402 if (aTag == INVALID_TAG) return;
403 builder(aTag)->Generated(anOldShape, aNewShape);
404 buildName(aTag, theName);
408 void Model_BodyBuilder::modified(const GeomShapePtr& theOldShape,
409 const GeomShapePtr& theNewShape,
410 const std::string& theName)
412 TopoDS_Shape anOldShape = theOldShape->impl<TopoDS_Shape>();
413 TopoDS_Shape aNewShape = theNewShape->impl<TopoDS_Shape>();
414 int aTag = getModificationTag(aNewShape);
415 if (aTag == INVALID_TAG) return;
416 builder(aTag)->Modify(anOldShape, aNewShape);
417 buildName(aTag, theName);
420 void Model_BodyBuilder::loadDeletedShapes(const GeomMakeShapePtr& theAlgo,
421 const GeomShapePtr& theOldShape,
422 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
423 const GeomShapePtr& theShapesToExclude)
425 TopTools_MapOfShape anAlreadyProcessedShapes;
426 GeomShapePtr aResultShape = shape();
427 for (GeomAPI_ShapeExplorer anExp(theOldShape, theShapeTypeToExplore);
431 GeomShapePtr anOldSubShape = anExp.current();
432 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
433 if (!anAlreadyProcessedShapes.Add(anOldSubShape_)
434 || !theAlgo->isDeleted(anOldSubShape)
435 || aResultShape->isSubShape(anOldSubShape, false)
436 || (theShapesToExclude.get() && theShapesToExclude->isSubShape(anOldSubShape, false)))
441 ListOfShape aNewShapes;
442 if (BRepTools_History::IsSupportedType(anOldSubShape_)) { // to avoid crash in #2572
443 theAlgo->modified(anOldSubShape, aNewShapes);
446 if (aNewShapes.size() == 0
447 || (aNewShapes.size() == 1 && aNewShapes.front()->isSame(anOldSubShape))) {
448 builder(DELETED_TAG)->Delete(anOldSubShape_);
453 // Keep only the shapes with minimal shape type
454 static void keepTopLevelShapes(ListOfShape& theShapes,
455 const TopoDS_Shape& theRoot,
456 const GeomShapePtr& theResultShape = GeomShapePtr())
458 GeomAPI_Shape::ShapeType aKeepShapeType = GeomAPI_Shape::SHAPE;
459 ListOfShape::iterator anIt = theShapes.begin();
460 while (anIt != theShapes.end()) {
461 TopoDS_Shape aNewShape = (*anIt)->impl<TopoDS_Shape>();
462 bool aSkip = aNewShape.IsNull() ||
463 (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape)));
464 if (aSkip || theRoot.IsSame(aNewShape) || (theResultShape &&
465 (!theResultShape->isSubShape(*anIt, false) || theResultShape->isSame(*anIt)))) {
466 ListOfShape::iterator aRemoveIt = anIt++;
467 theShapes.erase(aRemoveIt);
469 GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
470 if (aType < aKeepShapeType) {
471 // found a shape with lesser shape type => remove all previous shapes
472 aKeepShapeType = aType;
473 theShapes.erase(theShapes.begin(), anIt);
475 } else if (aType > aKeepShapeType) {
476 // shapes with greater shape type should be removed from the list
477 ListOfShape::iterator aRemoveIt = anIt++;
478 theShapes.erase(aRemoveIt);
485 /// Checks that shape is presented in the tree with not-selection evolution
486 /// In theOriginalLabel it returns label where NS of old sub-shape is stored
487 static bool isShapeInTree(const TDF_Label& theAccess1, const TDF_Label& theAccess2,
488 TopoDS_Shape theShape, TDF_Label& theOriginalLabel)
490 bool aResult = TNaming_Tool::HasLabel(theAccess1, theShape);
491 if (aResult) { //check evolution and a label of this shape
492 for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
494 static Handle(TNaming_NamedShape) aNS;
495 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
496 if (aNS->Evolution() != TNaming_SELECTED) {
497 theOriginalLabel = aNS->Label();
503 if (!theAccess2.IsNull()) {
504 static const TDF_Label anEmpty;
505 return isShapeInTree(theAccess2, anEmpty, theShape, theOriginalLabel);
510 /// Stores entry to the external label in the entries list at this label
511 static void storeExternalReference(const TDF_Label& theExternal, const TDF_Label theThis)
513 // store information about the external document reference to restore old shape on open
514 if (!theExternal.IsNull() && !theExternal.Root().IsEqual(theThis.Root())) {
515 Handle(TDataStd_ExtStringList) anEntries;
516 if (!theThis.FindAttribute(kEXTERNAL_SHAPE_REF, anEntries)) {
517 anEntries = TDataStd_ExtStringList::Set(theThis, kEXTERNAL_SHAPE_REF);
519 TCollection_AsciiString anEntry;
520 TDF_Tool::Entry(theExternal, anEntry);
521 // check it already contains this entry
522 TDataStd_ListOfExtendedString::Iterator anIter(anEntries->List());
523 for(; anIter.More(); anIter.Next())
524 if (anIter.Value() == anEntry)
526 if (!anIter.More()) {
527 anEntries->Append(anEntry);
532 void Model_BodyBuilder::loadModifiedShapes(const GeomMakeShapePtr& theAlgo,
533 const GeomShapePtr& theOldShape,
534 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
535 const std::string& theName)
537 GeomShapePtr aResultShape = shape();
538 GeomShapePtr aShapeToExplore = theOldShape;
539 if (theAlgo->isNewShapesCollected(theOldShape, theShapeTypeToExplore)) {
540 // use optimized set of old shapes for this
541 GeomShapePtr aCompound = theAlgo->oldShapesForNew(theOldShape,
543 theShapeTypeToExplore);
544 if (aCompound.get()) aShapeToExplore = aCompound;
547 TopTools_MapOfShape anAlreadyProcessedShapes;
548 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
549 for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore);
550 anOldShapeExp.more();
551 anOldShapeExp.next())
553 GeomShapePtr anOldSubShape = anOldShapeExp.current();
554 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
556 // There is no sense to write history if shape already processed
557 // or old shape does not exist in the document.
558 bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
559 TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
560 ModelAPI_Session::get()->moduleDocument())->generalLabel();
561 TDF_Label anOriginalLabel;
562 bool anOldSubShapeNotInTree =
563 !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
564 if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
569 ListOfShape aNewShapes;
570 theAlgo->modified(anOldSubShape, aNewShapes);
572 for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
573 aNewShapesIt != aNewShapes.cend();
576 GeomShapePtr aNewShape = *aNewShapesIt;
577 const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
578 bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
580 bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
581 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
582 if (aNewShapeIsSameAsOldShape || aNewShapeIsNotInResultShape)
585 if (aResultShape->isSame(aNewShape))
586 continue; // it is stored on the root level (2241 - history propagation issue)
588 int aTag = isGenerated ? getGenerationTag(aNewShape_) : getModificationTag(aNewShape_);
589 TNaming_Builder*aBuilder = builder(aTag);
590 if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_))
591 continue; // new shape was already stored.
593 buildName(aTag, theName);
594 isGenerated ? aBuilder->Generated(anOldSubShape_, aNewShape_)
595 : aBuilder->Modify(anOldSubShape_, aNewShape_);
596 // store information about the external document reference to restore old shape on open
597 storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
602 void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
603 const GeomShapePtr& theOldShape,
604 const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
605 const std::string& theName)
607 GeomShapePtr aResultShape = shape();
608 TopTools_MapOfShape anAlreadyProcessedShapes;
609 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
610 for (GeomAPI_ShapeExplorer anOldShapeExp(theOldShape, theShapeTypeToExplore);
611 anOldShapeExp.more();
612 anOldShapeExp.next())
614 GeomShapePtr anOldSubShape = anOldShapeExp.current();
615 const TopoDS_Shape& anOldSubShape_ = anOldSubShape->impl<TopoDS_Shape>();
617 // There is no sense to write history if shape already processed
618 // or old shape does not exist in the document.
619 bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
620 TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
621 ModelAPI_Session::get()->moduleDocument())->generalLabel();
622 TDF_Label anOriginalLabel;
623 bool anOldSubShapeNotInTree =
624 !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
625 if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
630 ListOfShape aNewShapes;
631 theAlgo->generated(anOldSubShape, aNewShapes);
633 keepTopLevelShapes(aNewShapes, anOldSubShape_);
635 for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
636 aNewShapesIt != aNewShapes.cend();
639 GeomShapePtr aNewShape = *aNewShapesIt;
640 const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
642 bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
643 bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
644 if (aNewShapeIsSameAsOldShape || aNewShapeIsNotInResultShape) {
648 TopAbs_ShapeEnum aNewShapeType = aNewShape_.ShapeType();
649 if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
650 // TODO: This is a workaround. New shape should be only edge or face.
651 TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE
653 int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
654 for (TopExp_Explorer anExp(aNewShape_, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
655 builder(aTag)->Generated(anOldSubShape_, anExp.Current());
656 // store information about the external document reference to restore old shape on open
657 storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
659 buildName(aTag, theName);
661 int aTag = getGenerationTag(aNewShape_);
662 if (aTag == INVALID_TAG) return;
663 builder(aTag)->Generated(anOldSubShape_, aNewShape_);
664 buildName(aTag, theName);
665 // store information about the external document reference to restore old shape on open
666 storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
673 //=======================================================================
674 int getDangleShapes(const TopoDS_Shape& theShapeIn,
675 const TopAbs_ShapeEnum theGeneratedFrom,
676 TopTools_DataMapOfShapeShape& theDangles)
679 TopTools_IndexedDataMapOfShapeListOfShape subShapeAndAncestors;
680 TopAbs_ShapeEnum GeneratedTo;
681 if (theGeneratedFrom == TopAbs_FACE) GeneratedTo = TopAbs_EDGE;
682 else if (theGeneratedFrom == TopAbs_EDGE) GeneratedTo = TopAbs_VERTEX;
683 else return Standard_False;
684 TopExp::MapShapesAndAncestors(theShapeIn, GeneratedTo, theGeneratedFrom, subShapeAndAncestors);
685 for (Standard_Integer i = 1; i <= subShapeAndAncestors.Extent(); i++) {
686 const TopoDS_Shape& mayBeDangle = subShapeAndAncestors.FindKey(i);
687 const TopTools_ListOfShape& ancestors = subShapeAndAncestors.FindFromIndex(i);
688 if (ancestors.Extent() == 1) theDangles.Bind(ancestors.First(), mayBeDangle);
690 return theDangles.Extent();
693 //=======================================================================
694 void loadGeneratedDangleShapes(
695 const TopoDS_Shape& theShapeIn,
696 const TopAbs_ShapeEnum theGeneratedFrom,
697 TNaming_Builder * theBuilder)
699 TopTools_DataMapOfShapeShape dangles;
700 if (!getDangleShapes(theShapeIn, theGeneratedFrom, dangles)) return;
701 TopTools_DataMapIteratorOfDataMapOfShapeShape itr(dangles);
702 for (; itr.More(); itr.Next())
703 theBuilder->Generated(itr.Key(), itr.Value());
707 //=======================================================================
708 void Model_BodyBuilder::loadNextLevels(GeomShapePtr theShape,
709 const std::string& theName)
711 if(theShape->isNull()) return;
712 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
714 if (aShape.ShapeType() == TopAbs_SOLID) {
715 TopExp_Explorer expl(aShape, TopAbs_FACE);
716 for (; expl.More(); expl.Next()) {
717 builder(myFreePrimitiveTag)->Generated(expl.Current());
718 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
719 aName = theName + "_" + aStr.ToCString();
720 buildName(myFreePrimitiveTag, aName);
721 ++myFreePrimitiveTag;
724 else if (aShape.ShapeType() == TopAbs_SHELL || aShape.ShapeType() == TopAbs_FACE) {
725 // load faces and all the free edges
726 TopTools_IndexedMapOfShape Faces;
727 TopExp::MapShapes(aShape, TopAbs_FACE, Faces);
728 if (Faces.Extent() > 1 || (aShape.ShapeType() == TopAbs_SHELL && Faces.Extent() == 1)) {
729 TopExp_Explorer expl(aShape, TopAbs_FACE);
730 for (; expl.More(); expl.Next()) {
731 builder(myFreePrimitiveTag)->Generated(expl.Current());
732 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
733 aName = theName + "_" + aStr.ToCString();
734 buildName(myFreePrimitiveTag, aName);
735 ++myFreePrimitiveTag;
738 TopTools_IndexedDataMapOfShapeListOfShape anEdgeAndNeighbourFaces;
739 TopExp::MapShapesAndAncestors(aShape, TopAbs_EDGE, TopAbs_FACE, anEdgeAndNeighbourFaces);
740 for (Standard_Integer i = 1; i <= anEdgeAndNeighbourFaces.Extent(); i++)
742 const TopTools_ListOfShape& aLL = anEdgeAndNeighbourFaces.FindFromIndex(i);
743 if (aLL.Extent() < 2) {
744 if (BRep_Tool::Degenerated(TopoDS::Edge(anEdgeAndNeighbourFaces.FindKey(i))))
746 builder(myFreePrimitiveTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
747 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
748 aName = theName + "_" + aStr.ToCString();
749 buildName(myFreePrimitiveTag, aName);
750 ++myFreePrimitiveTag;
752 TopTools_ListIteratorOfListOfShape anIter(aLL);
753 const TopoDS_Face& aFace = TopoDS::Face(anIter.Value());
755 if(aFace.IsEqual(anIter.Value())) {
756 builder(myFreePrimitiveTag)->Generated(anEdgeAndNeighbourFaces.FindKey(i));
757 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
758 aName = theName + "_" + aStr.ToCString();
759 buildName(myFreePrimitiveTag, aName);
760 ++myFreePrimitiveTag;
764 } else if (aShape.ShapeType() == TopAbs_WIRE) {
765 TopTools_IndexedMapOfShape Edges;
766 BRepTools::Map3DEdges(aShape, Edges);
767 if (Edges.Extent() == 1) {
768 builder(myFreePrimitiveTag++)->Generated(Edges.FindKey(1));
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;
778 TopExp_Explorer expl(aShape, TopAbs_EDGE);
779 for (; expl.More(); expl.Next()) {
780 builder(myFreePrimitiveTag)->Generated(expl.Current());
781 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
782 aName = theName + "_" + aStr.ToCString();
783 buildName(myFreePrimitiveTag, aName);
784 ++myFreePrimitiveTag;
786 // and load generated vertices.
787 TopTools_DataMapOfShapeShape generated;
788 if (getDangleShapes(aShape, TopAbs_EDGE, generated))
790 TNaming_Builder* pBuilder = builder(myFreePrimitiveTag++);
791 loadGeneratedDangleShapes(aShape, TopAbs_EDGE, pBuilder);
794 } else if (aShape.ShapeType() == TopAbs_EDGE) {
795 TopExp_Explorer expl(aShape, TopAbs_VERTEX);
796 for (; expl.More(); expl.Next()) {
797 builder(myFreePrimitiveTag)->Generated(expl.Current());
798 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
799 aName = theName + "_" + aStr.ToCString();
800 buildName(myFreePrimitiveTag, aName);
801 ++myFreePrimitiveTag;
806 //=======================================================================
807 int findAmbiguities(const TopoDS_Shape& theShapeIn,
808 TopTools_ListOfShape& theList)
811 // edges -> ancestor faces list
812 TopTools_IndexedDataMapOfShapeListOfShape aSubShapeAndAncestors;
813 TopExp::MapShapesAndAncestors(theShapeIn, TopAbs_EDGE, TopAbs_FACE, aSubShapeAndAncestors);
814 // keeps the shapes which are already in the resulting list
815 TopTools_MapOfShape alreadyThere;
816 // map from faces identifier (combination of hash-codes) to list of edges produced such ID
817 NCollection_DataMap<int, NCollection_List<TopoDS_Shape> > aFacesIDs;
819 TopTools_IndexedDataMapOfShapeListOfShape::Iterator anAncestorsIter(aSubShapeAndAncestors);
820 for (; anAncestorsIter.More(); anAncestorsIter.Next()) {
821 const TopTools_ListOfShape& ancestors = anAncestorsIter.Value();
822 if (ancestors.Extent() < 2)
824 Standard_Integer anID = 0;
825 for(TopTools_ListIteratorOfListOfShape aFaceIt(ancestors); aFaceIt.More(); aFaceIt.Next()) {
826 anID ^= HashCode(aFaceIt.ChangeValue(), 1990657); // Pierpont prime
828 if (aFacesIDs.IsBound(anID)) { // there found same edge, check they really have same faces
829 const NCollection_List<TopoDS_Shape>& aSameFaces1 =
830 aSubShapeAndAncestors.FindFromKey(anAncestorsIter.Key());
831 NCollection_List<TopoDS_Shape>::Iterator aSameEdge(aFacesIDs.ChangeFind(anID));
832 for(; aSameEdge.More(); aSameEdge.Next()) {
833 const NCollection_List<TopoDS_Shape>& aSameFaces2 =
834 aSubShapeAndAncestors.FindFromKey(aSameEdge.Value());
835 if (aSameFaces2.Extent() != aSameFaces1.Extent()) // the number of faces is different
838 NCollection_List<TopoDS_Shape>::Iterator aFaceIter1(aSameFaces1);
839 for(; aFaceIter1.More(); aFaceIter1.Next()) {
840 NCollection_List<TopoDS_Shape>::Iterator aFaceIter2(aSameFaces2);
841 for(; aFaceIter2.More(); aFaceIter2.Next()) {
842 if (aFaceIter1.Value().IsSame(aFaceIter2.Value()))
845 if (!aFaceIter2.More()) // aFaceIter1 contains a face, which is not in aFaceIter2
848 if (!aFaceIter1.More()) { // all the faces are same => put to the result
849 if (alreadyThere.Add(aSameEdge.Value()))
850 theList.Append(aSameEdge.Value());
851 if (alreadyThere.Add(anAncestorsIter.Key()))
852 theList.Append(anAncestorsIter.Key());
855 } else { // ID is unique, just add this edge
856 aFacesIDs.Bind(anID, NCollection_List<TopoDS_Shape>());
858 aFacesIDs.ChangeFind(anID).Append(anAncestorsIter.Key()); // add to the list anyway
860 return theList.Extent();
863 //=======================================================================
864 void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
866 if(theShape->isNull()) return;
867 TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
869 if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) {
870 TopoDS_Iterator itr(aShape);
871 for (; itr.More(); itr.Next()) {
872 builder(myFreePrimitiveTag)->Generated(itr.Value());
873 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
874 aName = theName + "_" + aStr.ToCString();
875 buildName(myFreePrimitiveTag, aName);
876 ++myFreePrimitiveTag;
877 if (itr.Value().ShapeType() == TopAbs_COMPOUND ||
878 itr.Value().ShapeType() == TopAbs_COMPSOLID)
880 GeomShapePtr itrShape(new GeomAPI_Shape());
881 itrShape->setImpl(new TopoDS_Shape(itr.Value()));
882 loadFirstLevel(itrShape, theName);
884 GeomShapePtr itrShape(new GeomAPI_Shape());
885 itrShape->setImpl(new TopoDS_Shape(itr.Value()));
886 loadNextLevels(itrShape, theName);
890 GeomShapePtr itrShape(new GeomAPI_Shape());
891 itrShape->setImpl(new TopoDS_Shape(aShape));
892 loadNextLevels(itrShape, theName);
894 TopTools_ListOfShape aList;
895 if(findAmbiguities(aShape, aList)) {
896 TopTools_ListIteratorOfListOfShape it(aList);
897 for (; it.More(); it.Next(), ++myFreePrimitiveTag) {
898 builder(myFreePrimitiveTag)->Generated(it.Value());
899 TCollection_AsciiString aStr(myFreePrimitiveTag - PRIMITIVES_START_TAG + 1);
900 aName = theName + "_" + aStr.ToCString();
901 buildName(myFreePrimitiveTag, aName);
906 GeomShapePtr Model_BodyBuilder::shape()
908 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
909 if (aData && aData->isValid()) {
910 TDF_Label aShapeLab = aData->shapeLab();
911 Handle(TDF_Reference) aRef;
912 if (aShapeLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
913 aShapeLab = aRef->Get();
915 Handle(TNaming_NamedShape) aName;
916 if (aShapeLab.FindAttribute(TNaming_NamedShape::GetID(), aName)) {
917 TopoDS_Shape aShape = aName->Get();
918 if (!aShape.IsNull()) {
919 GeomShapePtr aRes(new GeomAPI_Shape);
920 aRes->setImpl(new TopoDS_Shape(aShape));
925 return GeomShapePtr();