X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_BodyBuilder.cpp;h=1a8ea5507f9518ca3810ac4bb6ba615e21bbfe6d;hb=a3396dc1a64ca41f35bc1be0dcd4c7b66384ecf5;hp=c9384e4e0903fbcccc85b1287c4d0b69965e02ff;hpb=f9807be75fb0d22b17ad84597eada6389548da0f;p=modules%2Fshaper.git diff --git a/src/Model/Model_BodyBuilder.cpp b/src/Model/Model_BodyBuilder.cpp index c9384e4e0..1a8ea5507 100755 --- a/src/Model/Model_BodyBuilder.cpp +++ b/src/Model/Model_BodyBuilder.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include // DEB //#include @@ -93,7 +95,12 @@ static void evolutionToSelectionRec(TDF_Label theLab, const bool theFlag) { std::list >::iterator aPairsIter = aShapePairs.begin(); for(; aPairsIter != aShapePairs.end(); aPairsIter++) { if (theFlag) { // disabled => make selection - aBuilder.Select(aPairsIter->second, aPairsIter->first); + if (anEvolution == TNaming_DELETE) // issue 2274 : don't put too many same null shapes + aBuilder.Select(aPairsIter->first, aPairsIter->first); + else if (anEvolution == TNaming_PRIMITIVE) + aBuilder.Select(aPairsIter->second, aPairsIter->second); + else + aBuilder.Select(aPairsIter->second, aPairsIter->first); } else if (anEvol == TNaming_GENERATED) { aBuilder.Generated(aPairsIter->first, aPairsIter->second); } else if (anEvol == TNaming_MODIFY) { @@ -208,7 +215,8 @@ void Model_BodyBuilder::storeModified(const std::shared_ptr& theO if (aData) { TDF_Label& aShapeLab = aData->shapeLab(); // clean builders - clean(); + if (theDecomposeSolidsTag != -2) + clean(); // store the new shape as primitive TNaming_Builder aBuilder(aShapeLab); if (!theOldShape || !theNewShape) @@ -251,10 +259,21 @@ void Model_BodyBuilder::storeWithoutNaming(const std::shared_ptr void Model_BodyBuilder::clean() { + TDF_Label aLab = std::dynamic_pointer_cast(data())->shapeLab(); + if (aLab.IsNull()) + return; std::map::iterator aBuilder = myBuilders.begin(); - for(; aBuilder != myBuilders.end(); aBuilder++) + for(; aBuilder != myBuilders.end(); aBuilder++) { delete aBuilder->second; + // clear also shapes on cleaned sub-labels (#2241) + Handle(TNaming_NamedShape) aNS; + if (aLab.FindChild(aBuilder->first).FindAttribute(TNaming_NamedShape::GetID(), aNS)) { + aNS->Clear(); + } + } myBuilders.clear(); + // remove the old reference (if any) + aLab.ForgetAttribute(TDF_Reference::GetID()); } Model_BodyBuilder::~Model_BodyBuilder() @@ -267,7 +286,8 @@ TNaming_Builder* Model_BodyBuilder::builder(const int theTag) std::map::iterator aFind = myBuilders.find(theTag); if (aFind == myBuilders.end()) { std::shared_ptr aData = std::dynamic_pointer_cast(data()); - myBuilders[theTag] = new TNaming_Builder(aData->shapeLab().FindChild(theTag)); + myBuilders[theTag] = new TNaming_Builder( + theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag)); aFind = myBuilders.find(theTag); } return aFind->second; @@ -340,17 +360,63 @@ void Model_BodyBuilder::loadDeletedShapes (GeomAlgoAPI_MakeShape* theMS, TopoDS_Shape aShapeIn = theShapeIn->impl(); TopTools_MapOfShape aView; TopExp_Explorer ShapeExplorer (aShapeIn, (TopAbs_ShapeEnum)theKindOfShape); + GeomShapePtr aResultShape = shape(); for (; ShapeExplorer.More(); ShapeExplorer.Next ()) { const TopoDS_Shape& aRoot = ShapeExplorer.Current (); if (!aView.Add(aRoot)) continue; std::shared_ptr aRShape(new GeomAPI_Shape()); aRShape->setImpl((new TopoDS_Shape(aRoot))); if (theMS->isDeleted (aRShape)) { - builder(theTag)->Delete(aRoot); + if (!aResultShape->isSubShape(aRShape, false)) { + ListOfShape aHist; + theMS->modified(aRShape, aHist); + if (aHist.size() == 0 || (aHist.size() == 1 && aHist.front()->isSame(aRShape))) + builder(theTag)->Delete(aRoot); + } + } + } +} + +// Keep only the shapes with minimal shape type +static void keepTopLevelShapes(ListOfShape& theShapes, const TopoDS_Shape& theRoot, + const GeomShapePtr& theResultShape = GeomShapePtr()) +{ + GeomAPI_Shape::ShapeType aKeepShapeType = GeomAPI_Shape::SHAPE; + ListOfShape::iterator anIt = theShapes.begin(); + while (anIt != theShapes.end()) { + TopoDS_Shape aNewShape = (*anIt)->impl(); + bool aSkip = aNewShape.IsNull() || + (aNewShape.ShapeType() == TopAbs_EDGE && BRep_Tool::Degenerated(TopoDS::Edge(aNewShape))); + if (aSkip || theRoot.IsSame(aNewShape) || (theResultShape && + (!theResultShape->isSubShape(*anIt, false) || theResultShape->isSame(*anIt)))) { + ListOfShape::iterator aRemoveIt = anIt++; + theShapes.erase(aRemoveIt); + } else { + GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType(); + if (aType < aKeepShapeType) { + // found a shape with lesser shape type => remove all previous shapes + aKeepShapeType = aType; + theShapes.erase(theShapes.begin(), anIt); + ++anIt; + } else if (aType > aKeepShapeType) { + // shapes with greater shape type should be removed from the list + ListOfShape::iterator aRemoveIt = anIt++; + theShapes.erase(aRemoveIt); + } else + ++anIt; } } } +// returns an ancestor shape-type thaty used for naming-definition of the sub-type +TopAbs_ShapeEnum typeOfAncestor(const TopAbs_ShapeEnum theSubType) { + if (theSubType == TopAbs_VERTEX) + return TopAbs_EDGE; + if (theSubType == TopAbs_EDGE) + return TopAbs_FACE; + return TopAbs_VERTEX; // bad case +} + void Model_BodyBuilder::loadAndOrientModifiedShapes ( GeomAlgoAPI_MakeShape* theMS, std::shared_ptr theShapeIn, @@ -369,16 +435,29 @@ void Model_BodyBuilder::loadAndOrientModifiedShapes ( GeomShapePtr aResultShape = shape(); TopoDS_Shape aShapeIn = theShapeIn->impl(); TopTools_MapOfShape aView; + std::shared_ptr aData = std::dynamic_pointer_cast(data()); TopExp_Explorer aShapeExplorer (aShapeIn, (TopAbs_ShapeEnum)theKindOfShape); for (; aShapeExplorer.More(); aShapeExplorer.Next ()) { const TopoDS_Shape& aRoot = aShapeExplorer.Current (); if (!aView.Add(aRoot)) continue; - if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull()) - continue; // there is no sence to write history is old shape does not persented in document + + bool aNotInTree = + TNaming_Tool::NamedShape(aRoot, aData->shapeLab()).IsNull(); + if (aNotInTree && !theIsStoreSeparate) { + // there is no sense to write history if old shape does not exist in the document + continue; // but if it is stored separately, it will be builded as a primitive + } ListOfShape aList; std::shared_ptr aRShape(new GeomAPI_Shape()); aRShape->setImpl((new TopoDS_Shape(aRoot))); theMS->modified(aRShape, aList); + if (!theIsStoreSeparate) + keepTopLevelShapes(aList, aRoot, aResultShape); + // sort the list of images before naming + GeomAlgoAPI_SortListOfShapes::sort(aList); + + // to trace situation where several objects are produced by one parent (#2317) + int aSameParentShapes = -1; std::list >::const_iterator anIt = aList.begin(), aLast = aList.end(); for (; anIt != aLast; anIt++) { @@ -389,26 +468,97 @@ void Model_BodyBuilder::loadAndOrientModifiedShapes ( } GeomShapePtr aGeomNewShape(new GeomAPI_Shape()); aGeomNewShape->setImpl(new TopoDS_Shape(aNewShape)); - if(!aRoot.IsSame(aNewShape) && aResultShape->isSubShape(aGeomNewShape)) { + if(!aRoot.IsSame(aNewShape) && aResultShape->isSubShape(aGeomNewShape, false) && + !aResultShape->isSame(*anIt)) { // to avoid put of same shape on main label and sub + int aBuilderTag = aTag; + if (!theIsStoreSeparate) { + aSameParentShapes++; + } else if (aNotInTree) { // check this new shape can not be represented as + // a sub-shape of higher level sub-shapes + TopAbs_ShapeEnum aNewType = aNewShape.ShapeType(); + TopAbs_ShapeEnum anAncestorType = typeOfAncestor(aNewType); + if (anAncestorType != TopAbs_VERTEX) { + bool aFound = false; + TopoDS_Shape aResultTShape = aResultShape->impl(); + TopExp_Explorer anAncestorExp(aResultTShape, anAncestorType); + for(; anAncestorExp.More() && !aFound; anAncestorExp.Next()) { + if (aResultTShape.IsSame(anAncestorExp.Current())) + continue; + TopExp_Explorer aSubExp(anAncestorExp.Current(), aNewType); + for(; aSubExp.More(); aSubExp.Next()) { + if (aNewShape.IsSame(aSubExp.Current())) { + aFound = true; + break; + } + } + } + if (aFound) { + continue; // not need to store this shape in the BRep structure + } + } + } + + static const int THE_ANCHOR_TAG = 100000; + int aCurShapeType = (int)((*anIt)->shapeType()); + bool needSuffix = false; // suffix for the name based on the shape type + if (aSameParentShapes > 0) { // store in other label + aBuilderTag = THE_ANCHOR_TAG - aSameParentShapes * 10 - aCurShapeType; + needSuffix = true; + } else if (aCurShapeType != theKindOfShape) { + // modified shape has different type => set another tag + // to avoid shapes of different types on the same label + aBuilderTag = THE_ANCHOR_TAG - aCurShapeType; + needSuffix = true; + } + std::string aSuffix; + if (needSuffix) { + switch (aCurShapeType) { + case GeomAPI_Shape::VERTEX: aSuffix = "_v"; break; + case GeomAPI_Shape::EDGE: aSuffix = "_e"; break; + case GeomAPI_Shape::FACE: aSuffix = "_f"; break; + default: break; + } + } + if(theIsStoreAsGenerated) { // Here we store shapes as generated, to avoid problem when one parent shape produce // several child shapes. In this case naming could not determine which shape to select. - builder(aTag)->Generated(aRoot,aNewShape); + builder(aBuilderTag)->Generated(aRoot, aNewShape); + } else if (aNotInTree) { + // not in tree -> store as primitive (stored as separated) + builder(aBuilderTag)->Generated(aNewShape); + } else if (aNewShape.ShapeType() > aRoot.ShapeType()) { + // if lower-level type is produced, make it as generated + builder(aBuilderTag)->Generated(aRoot, aNewShape); } else { - builder(aTag)->Modify(aRoot,aNewShape); + builder(aBuilderTag)->Modify(aRoot, aNewShape); } if(isBuilt) { - if(theIsStoreSeparate) { + aStream.str(std::string()); + aStream.clear(); + aStream << theName; + if(theIsStoreSeparate) + aStream << "_" << anIndex++; + + if (aSameParentShapes > 0) { aStream.str(std::string()); aStream.clear(); - aStream << theName << "_" << anIndex++; - aName = aStream.str(); + aStream << aName << "_" << aSameParentShapes << "divided"; } - buildName(aTag, aName); + + aStream << aSuffix; + buildName(aBuilderTag, aStream.str()); } if(theIsStoreSeparate) { aTag++; } + } else if (aResultShape->isSame(*anIt)) { + // keep the modification evolution on the root level (2241 - history propagation issue) + if(theIsStoreAsGenerated) { + builder(0)->Generated(aRoot, aNewShape); + } else { + builder(0)->Modify(aRoot, aNewShape); + } } } } @@ -429,12 +579,13 @@ void Model_BodyBuilder::loadAndOrientGeneratedShapes ( for (; aShapeExplorer.More(); aShapeExplorer.Next ()) { const TopoDS_Shape& aRoot = aShapeExplorer.Current (); if (!aView.Add(aRoot)) continue; - if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull()) - continue; // there is no sence to write history is old shape does not persented in document + //if (TNaming_Tool::NamedShape(aRoot, builder(theTag)->NamedShape()->Label()).IsNull()) + // continue; // there is no sense to write history if old shape does not exist in the document ListOfShape aList; std::shared_ptr aRShape(new GeomAPI_Shape()); aRShape->setImpl((new TopoDS_Shape(aRoot))); theMS->generated(aRShape, aList); + keepTopLevelShapes(aList, aRoot); std::list >::const_iterator anIt = aList.begin(), aLast = aList.end(); for (; anIt != aLast; anIt++) { @@ -564,7 +715,7 @@ void Model_BodyBuilder::loadNextLevels(std::shared_ptr theShape, TopTools_IndexedMapOfShape Edges; BRepTools::Map3DEdges(aShape, Edges); if (Edges.Extent() == 1) { - builder(++theTag)->Generated(Edges.FindKey(1)); + builder(theTag++)->Generated(Edges.FindKey(1)); TopExp_Explorer expl(aShape, TopAbs_VERTEX); for (; expl.More(); expl.Next()) { builder(theTag)->Generated(expl.Current()); @@ -606,42 +757,57 @@ void Model_BodyBuilder::loadNextLevels(std::shared_ptr theShape, int findAmbiguities(const TopoDS_Shape& theShapeIn, TopTools_ListOfShape& theList) { - int aNumEdges(0); theList.Clear(); - TopTools_IndexedDataMapOfShapeListOfShape subShapeAndAncestors; - TopAbs_ShapeEnum aTS(TopAbs_EDGE); - TopAbs_ShapeEnum aTA(TopAbs_FACE); - TopTools_MapOfShape aMap1, aMap2; // map1 - for edge ancestors; map2 - for keys => edges - TopTools_ListOfShape aKeyList; - TopExp::MapShapesAndAncestors(theShapeIn, aTS, aTA, subShapeAndAncestors); - for (Standard_Integer i = 1; i <= subShapeAndAncestors.Extent(); i++) { - const TopoDS_Shape& aKeyEdge1 = subShapeAndAncestors.FindKey(i); - const TopTools_ListOfShape& ancestors1 = subShapeAndAncestors.FindFromIndex(i); - aMap1.Clear(); - TopTools_ListIteratorOfListOfShape it(ancestors1); - for(;it.More();it.Next()) aMap1.Add(it.Value()); // fill map with key ancestors => aKey1 - for (Standard_Integer j = 1; j <= subShapeAndAncestors.Extent(); j++) { - if (i == j) continue; - const TopoDS_Shape& aKeyEdge2 = subShapeAndAncestors.FindKey(j); - const TopTools_ListOfShape& ancestors2 = subShapeAndAncestors.FindFromIndex(j); - if(ancestors1.Extent() == ancestors2.Extent() && ancestors1.Extent() > 1) { - int aNum (ancestors2.Extent()); - TopTools_ListIteratorOfListOfShape it(ancestors2); - for(;it.More();it.Next()) - if(aMap1.Contains(it.Value())) aNum--; - if(aNum == 0) { - if(aMap2.Add(aKeyEdge1)) - aKeyList.Append(aKeyEdge1); - if(aMap2.Add(aKeyEdge2)) - aKeyList.Append(aKeyEdge2); + // edges -> ancestor faces list + TopTools_IndexedDataMapOfShapeListOfShape aSubShapeAndAncestors; + TopExp::MapShapesAndAncestors(theShapeIn, TopAbs_EDGE, TopAbs_FACE, aSubShapeAndAncestors); + // keeps the shapes which are already in the resulting list + TopTools_MapOfShape alreadyThere; + // map from faces identifier (combination of hash-codes) to list of edges produced such ID + NCollection_DataMap > aFacesIDs; + + TopTools_IndexedDataMapOfShapeListOfShape::Iterator anAncestorsIter(aSubShapeAndAncestors); + for (; anAncestorsIter.More(); anAncestorsIter.Next()) { + const TopTools_ListOfShape& ancestors = anAncestorsIter.Value(); + if (ancestors.Extent() < 2) + continue; + Standard_Integer anID = 0; + for(TopTools_ListIteratorOfListOfShape aFaceIt(ancestors); aFaceIt.More(); aFaceIt.Next()) { + anID ^= HashCode(aFaceIt.ChangeValue(), 1990657); // Pierpont prime + } + if (aFacesIDs.IsBound(anID)) { // there found same edge, check they really have same faces + const NCollection_List& aSameFaces1 = + aSubShapeAndAncestors.FindFromKey(anAncestorsIter.Key()); + NCollection_List::Iterator aSameEdge(aFacesIDs.ChangeFind(anID)); + for(; aSameEdge.More(); aSameEdge.Next()) { + const NCollection_List& aSameFaces2 = + aSubShapeAndAncestors.FindFromKey(aSameEdge.Value()); + if (aSameFaces2.Extent() != aSameFaces1.Extent()) // the number of faces is different + break; + + NCollection_List::Iterator aFaceIter1(aSameFaces1); + for(; aFaceIter1.More(); aFaceIter1.Next()) { + NCollection_List::Iterator aFaceIter2(aSameFaces2); + for(; aFaceIter2.More(); aFaceIter2.Next()) { + if (aFaceIter1.Value().IsSame(aFaceIter2.Value())) + break; + } + if (!aFaceIter2.More()) // aFaceIter1 contains a face, which is not in aFaceIter2 + break; + } + if (!aFaceIter1.More()) { // all the faces are same => put to the result + if (alreadyThere.Add(aSameEdge.Value())) + theList.Append(aSameEdge.Value()); + if (alreadyThere.Add(anAncestorsIter.Key())) + theList.Append(anAncestorsIter.Key()); } } - } // at the end ==> List of edges to be named in addition + } else { // ID is unique, just add this edge + aFacesIDs.Bind(anID, NCollection_List()); + } + aFacesIDs.ChangeFind(anID).Append(anAncestorsIter.Key()); // add to the list anyway } - aNumEdges = aKeyList.Extent(); - if(aNumEdges) - theList.Assign(aKeyList); - return aNumEdges; + return theList.Extent(); } //======================================================================= @@ -653,12 +819,13 @@ void Model_BodyBuilder::loadFirstLevel( std::string aName; if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) { TopoDS_Iterator itr(aShape); - for (; itr.More(); itr.Next(),theTag++) { + for (; itr.More(); itr.Next()) { builder(theTag)->Generated(itr.Value()); TCollection_AsciiString aStr(theTag); aName = theName + aStr.ToCString(); buildName(theTag, aName); if(!theName.empty()) buildName(theTag, aName); + theTag++; if (itr.Value().ShapeType() == TopAbs_COMPOUND || itr.Value().ShapeType() == TopAbs_COMPSOLID) {