diff --git a/resources/extract.png b/resources/extract.png index 528fe308a..cdbe85a83 100644 Binary files a/resources/extract.png and b/resources/extract.png differ diff --git a/src/GEOMAlgo/GEOMAlgo_Extractor.cxx b/src/GEOMAlgo/GEOMAlgo_Extractor.cxx index 34d92d0ab..bdbadab69 100644 --- a/src/GEOMAlgo/GEOMAlgo_Extractor.cxx +++ b/src/GEOMAlgo/GEOMAlgo_Extractor.cxx @@ -28,9 +28,23 @@ #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include +#include +#include //======================================================================= @@ -56,6 +70,7 @@ GEOMAlgo_Extractor::~GEOMAlgo_Extractor() void GEOMAlgo_Extractor::SetShape(const TopoDS_Shape &theShape) { myShape = theShape; + myMapShapeAnc.Clear(); clear(); } @@ -90,6 +105,37 @@ void GEOMAlgo_Extractor::Perform() myResult = myShape; return; } + + // Mark sub-shapes as removed and modified. + markShapes(); + + // Process Edges. + processShapes(TopAbs_EDGE); + + // Process Wires. + processShapes(TopAbs_WIRE); + + // Process Faces. + processShapes(TopAbs_FACE); + + // Process Shells. + processShapes(TopAbs_SHELL); + + // Process Solids. + processShapes(TopAbs_SOLID); + + // Process Comp-Solids. + processShapes(TopAbs_COMPSOLID); + + // Process Compounds. + processShapes(TopAbs_COMPOUND); + + // Make the result. + myResult = makeResult(myShape); + + TopTools_MapOfShape aMapFence; + + makeHistory(myShape, aMapFence); } //======================================================================= @@ -113,6 +159,9 @@ void GEOMAlgo_Extractor::clear() myRemoved.Clear(); myModified.Clear(); myNew.Clear(); + myMapRemoved.Clear(); + myMapModified.Clear(); + myMapNewShapeAnc.Clear(); } //======================================================================= @@ -133,15 +182,1233 @@ void GEOMAlgo_Extractor::checkData() TopTools_ListIteratorOfListOfShape anIter(mySubShapes); TopTools_IndexedMapOfShape anIndices; + TopTools_MapOfShape aMapFence; TopExp::MapShapes(myShape, anIndices); + while (anIter.More()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aMapFence.Add(aSubShape)) { + // Check if it is a sub-shape of the given shape. + if (!anIndices.Contains(aSubShape)) { + myErrorStatus = 11; + return; + } + + // Check if it is a main shape. + if (aSubShape.IsSame(myShape)) { + myErrorStatus = 12; + return; + } + + anIter.Next(); + } else { + // Remove duplicated index. + mySubShapes.Remove(anIter); + } + } + + if (myMapShapeAnc.IsEmpty()) { + // Fill the map of shapes - ancestors. + makeMapShapeAncestors(myShape); + } + + // Check if there are seam or degenerated edges on faces. + for (anIter.Initialize(mySubShapes); anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aSubShape.ShapeType() == TopAbs_EDGE) { + // Get the list of ancestor wires. + TopTools_ListOfShape anAncWires; + TopTools_ListIteratorOfListOfShape anAncIt; + + if (myMapShapeAnc.IsBound(aSubShape)) { + anAncIt.Initialize(myMapShapeAnc.Find(aSubShape)); + + for (; anAncIt.More(); anAncIt.Next()) { + const TopoDS_Shape &anAncShape = anAncIt.Value(); + + if (anAncShape.ShapeType() == TopAbs_WIRE) { + anAncWires.Append(anAncShape); + } + } + } + + if (!anAncWires.IsEmpty()) { + // Check the ancestor faces. + Standard_Boolean hasFaces = Standard_False; + TopoDS_Edge anEdge = TopoDS::Edge(aSubShape); + + for (anAncIt.Initialize(anAncWires); anAncIt.More(); anAncIt.Next()) { + const TopoDS_Shape &anAncShape = anAncIt.Value(); + + if (anAncShape.ShapeType() == TopAbs_FACE) { + TopoDS_Face aFace = TopoDS::Face(anAncShape); + + if (BRepTools::IsReallyClosed(anEdge, aFace)) { + // Deletion of face's seam edge is not allowed + myErrorStatus = 13; + return; + } + + hasFaces = Standard_True; + } + } + + if (hasFaces && BRep_Tool::Degenerated(anEdge)) { + myErrorStatus = 14; + return; + } + } + } + } +} + +//======================================================================= +//function : makeMapShapeAncestors +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::makeMapShapeAncestors(const TopoDS_Shape &theShape) +{ + if (theShape.ShapeType() == TopAbs_VERTEX) { + // Vertex is the lowest type. It has no ancestors. + return; + } + + TopoDS_Iterator anIter(theShape); + TopTools_MapOfShape aMapFence; + for (; anIter.More(); anIter.Next()) { const TopoDS_Shape &aSubShape = anIter.Value(); - if (!anIndices.Contains(aSubShape)) { - myErrorStatus = 11; - return; + if (aMapFence.Add(aSubShape)) { + // Add theShape as an ancestor shape. + if (!myMapShapeAnc.IsBound(aSubShape)) { + myMapShapeAnc.Bind(aSubShape, TopTools_ListOfShape()); + } + + myMapShapeAnc.ChangeFind(aSubShape).Append(theShape); + + // Recursively call this method for a sub-shape. + makeMapShapeAncestors(aSubShape); + } + } +} + +//======================================================================= +//function : markShapes +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::markShapes() +{ + TopTools_ListIteratorOfListOfShape anIter(mySubShapes); + + // Mark sub-shapes as removed. + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + markRemoved(aSubShape); + } + + // Mark undestors of sub-shapes as modified. + for (anIter.Initialize(mySubShapes); anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + markAncestorsModified(aSubShape); + } +} + +//======================================================================= +//function : markRemoved +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::markRemoved(const TopoDS_Shape &theShape) +{ + if (myMapRemoved.Add(theShape)) { + // Check sub-shapes. + TopoDS_Iterator anIter(theShape); + TopTools_MapOfShape aMapFence; + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aMapFence.Add(aSubShape)) { + TopTools_ListIteratorOfListOfShape anAncIt + (myMapShapeAnc.Find(aSubShape)); + Standard_Boolean isToRm = Standard_True; + + for (; anAncIt.More(); anAncIt.Next()) { + const TopoDS_Shape &anAncShape = anAncIt.Value(); + + if (!myMapRemoved.Contains(anAncShape)) { + isToRm = Standard_False; + break; + } + } + + if (isToRm) { + // Mark sub-shape as removed. + markRemoved(aSubShape); + } + } + } + } +} + +//======================================================================= +//function : markAncestorsModified +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::markAncestorsModified(const TopoDS_Shape &theShape) +{ + if (myMapShapeAnc.IsBound(theShape)) { + TopTools_ListIteratorOfListOfShape anAncIt(myMapShapeAnc.Find(theShape)); + + for (; anAncIt.More(); anAncIt.Next()) { + const TopoDS_Shape &anAncShape = anAncIt.Value(); + + if (!myMapRemoved.Contains(anAncShape) && + !myMapModified.IsBound(anAncShape)) { + // Mark anAncShape as modified. + myMapModified.Bind(anAncShape, TopTools_ListOfShape()); + + // Mark its ancestors as modified. + markAncestorsModified(anAncShape); + } + } + } +} + +//======================================================================= +//function : processShapes +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processShapes(const TopAbs_ShapeEnum &theType) +{ + TopExp_Explorer anExp(myShape, theType); + TopTools_MapOfShape aMapFence; + + for (; anExp.More(); anExp.Next()) { + TopoDS_Shape aShape = anExp.Current(); // Copy + + if (aMapFence.Add(aShape)) { + if (myMapRemoved.Contains(aShape) || + !myMapModified.IsBound(aShape)) { + // Skip removed or not modified shape. + continue; + } + + aShape.Orientation(TopAbs_FORWARD); + + switch(theType) { + case TopAbs_EDGE: + processEdge(aShape); + break; + case TopAbs_WIRE: + processWire(aShape); + break; + case TopAbs_FACE: + case TopAbs_SOLID: + processFOrSo(aShape); + break; + case TopAbs_SHELL: + case TopAbs_COMPSOLID: + processShOrCS(aShape); + break; + case TopAbs_COMPOUND: + processCompound(aShape); + break; + default: + break; + } + } + } + + if (theType == TopAbs_FACE || theType == TopAbs_SOLID) { + // Clear duplicated edges from the faces and faces from solids + removeBoundsOnFOrSo(theType); + } +} + +//======================================================================= +//function : processEdge +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processEdge(const TopoDS_Shape &theEdge) +{ + TopoDS_Iterator anIter(theEdge); + TopTools_MapOfShape aMapFence; + TopTools_ListOfShape aVtxList; + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aShapeVertex = anIter.Value(); + + if (aMapFence.Add(aShapeVertex)) { + if (myMapRemoved.Contains(aShapeVertex)) { + // This vertex is removed. + const TopAbs_Orientation anOri = aShapeVertex.Orientation(); + + if (anOri == TopAbs_FORWARD || anOri == TopAbs_REVERSED) { + // This edge will disappear from the result. + return; + } + } else { + // This vertex is not removed. + aVtxList.Append(aShapeVertex); + } + } + } + + TopoDS_Shape aNewEdge = makeShape(theEdge, aVtxList); + + myMapModified.ChangeFind(theEdge).Append(aNewEdge); +} + +//======================================================================= +//function : processWire +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processWire(const TopoDS_Shape &theWire) +{ + // Get parent face for the wire. + TopoDS_Face aFace; + + if (myMapShapeAnc.IsBound(theWire)) { + TopTools_ListIteratorOfListOfShape anIter(myMapShapeAnc.Find(theWire)); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aParent = anIter.Value(); + + if (aParent.ShapeType() == TopAbs_FACE) { + aFace = TopoDS::Face(aParent.Oriented(TopAbs_FORWARD)); + break; + } + } + } + + TopoDS_Wire aWire = TopoDS::Wire(theWire); + BRepTools_WireExplorer anExp(aWire, aFace); + NCollection_List aListListEdges; + TopTools_ListOfShape aListEdges; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Edge &anEdge = anExp.Current(); + + if (myMapRemoved.Contains(anEdge)) { + // This edge is removed. + if (!aListEdges.IsEmpty()) { + aListListEdges.Append(aListEdges); + aListEdges.Clear(); + } + } else if (myMapModified.IsBound(anEdge)) { + // This edge is modified. + TopTools_ListOfShape aModifEdges; + + getModified(anEdge, aModifEdges); + + if (aModifEdges.IsEmpty()) { + // This edge is not created. + if (!aListEdges.IsEmpty()) { + aListListEdges.Append(aListEdges); + aListEdges.Clear(); + } + } else { + const TopoDS_Shape aModifEdge = oriented(aModifEdges.First(), anEdge); + + aListEdges.Append(aModifEdge); + } + } else { + // Get an edge as it is. + aListEdges.Append(anEdge); + } + } + + if (!aListEdges.IsEmpty()) { + aListListEdges.Append(aListEdges); + } + + if (!aListListEdges.IsEmpty()) { + TopTools_ListOfShape aListWires; + + makeWires(theWire, aListListEdges, aListWires); + myMapModified.ChangeFind(theWire) = aListWires; + } +} + +//======================================================================= +//function : processFOrSo +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processFOrSo(const TopoDS_Shape &theFOrSo) +{ + Standard_Boolean isToCreate = Standard_True; + TopTools_ListOfShape aClosedSubShapes; + TopTools_ListOfShape aNewShapes; + TopoDS_Shape anOuterSubShape; + TopAbs_ShapeEnum aShapeType; + TopAbs_ShapeEnum aSubShapeType; + + if (theFOrSo.ShapeType() == TopAbs_FACE) { + aShapeType = TopAbs_FACE; + aSubShapeType = TopAbs_WIRE; + anOuterSubShape = BRepTools::OuterWire(TopoDS::Face(theFOrSo)); + } else { + aShapeType = TopAbs_SOLID; + aSubShapeType = TopAbs_SHELL; + anOuterSubShape = BRepClass3d::OuterShell(TopoDS::Solid(theFOrSo)); + } + + // Process an outer sub-shape. + if (myMapRemoved.Contains(anOuterSubShape)) { + isToCreate = Standard_False; + } else if (myMapModified.IsBound(anOuterSubShape)) { + TopTools_ListOfShape aModifSubShapes; + + getModified(anOuterSubShape, aModifSubShapes); + + // Check if there is a closed direct sub-shape. + TopTools_ListIteratorOfListOfShape anIter(aModifSubShapes); + TopoDS_Shape aClosedSubShape; + + for (isToCreate = Standard_False; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aSubShape.ShapeType() == aSubShapeType && aSubShape.Closed()) { + if (isToCreate) { + // There is another closed sub-shape. NEVERREACHED. + // No need to create a new shape. + isToCreate = Standard_False; + break; + } else { + // Remember the closed sub-shape. + isToCreate = Standard_True; + aClosedSubShape = aSubShape; + } + } + } + + if (isToCreate) { + // Add a closed sub-shape. + const TopoDS_Shape aNewSubShape = + oriented(aClosedSubShape, anOuterSubShape); + + aClosedSubShapes.Append(aNewSubShape); + } + + // Copy shapes to the list of other shapes. + for (anIter.Initialize(aModifSubShapes); anIter.More(); anIter.Next()) { + const TopoDS_Shape aNewShape = oriented(anIter.Value(), anOuterSubShape); + + if (!isToCreate || !aNewShape.IsSame(aClosedSubShape)) { + aNewShapes.Append(aNewShape); + } + } + } else { + aClosedSubShapes.Append(anOuterSubShape); + } + + // Treat holes. + TopoDS_Iterator anIter(theFOrSo); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aSubShape.IsSame(anOuterSubShape)) { + // Skip an outer sub-shape. + continue; + } + + if (myMapModified.IsBound(aSubShape)) { + // This is a modified sub-shape. + TopTools_ListOfShape aModifSubShapes; + + getModified(aSubShape, aModifSubShapes); + + TopTools_ListIteratorOfListOfShape anIter(aModifSubShapes); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape aNewShape = oriented(anIter.Value(), aSubShape); + + if (isToCreate) { + if (aNewShape.ShapeType() == aSubShapeType && aNewShape.Closed()) { + // This is a closed sub-shape. + aClosedSubShapes.Append(aNewShape); + } else { + aNewShapes.Append(aNewShape); + } + } else { + aNewShapes.Append(aNewShape); + } + } + } else if (!myMapRemoved.Contains(aSubShape)) { + // The shape is not modified. + if (isToCreate) { + aClosedSubShapes.Append(aSubShape); + } else { + aNewShapes.Append(aSubShape); + } + } + } + + if (isToCreate) { + // Create a new shape. + TopoDS_Shape aNewShape = makeShape(theFOrSo, aClosedSubShapes); + + aNewShapes.Prepend(aNewShape); + } + + if (!aNewShapes.IsEmpty()) { + // Store modified shapes. + myMapModified.ChangeFind(theFOrSo) = aNewShapes; + } +} + +//======================================================================= +//function : processShOrCS +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processShOrCS(const TopoDS_Shape &theShOrCS) +{ + // Treat sub-shapes. + TopoDS_Iterator anIter(theShOrCS); + TopTools_ListOfShape aNewSubShapes; + TopTools_ListOfShape aNewOtherShapes; + TopAbs_ShapeEnum aSubShapeType; + TopAbs_ShapeEnum aSubSubShapeType; + + if (theShOrCS.ShapeType() == TopAbs_SHELL) { + aSubShapeType = TopAbs_FACE; + aSubSubShapeType = TopAbs_EDGE; + } else { // comp-solid + aSubShapeType = TopAbs_SOLID; + aSubSubShapeType = TopAbs_FACE; + } + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (myMapModified.IsBound(aSubShape)) { + TopTools_ListOfShape aModifList; + + getModified(aSubShape, aModifList); + + // Copy shapes to the list of other shapes. + TopTools_ListIteratorOfListOfShape anIter(aModifList); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape aNewShape = oriented(anIter.Value(), aSubShape); + + if (aNewShape.ShapeType() == aSubShapeType) { + aNewSubShapes.Append(aNewShape); + } else { + aNewOtherShapes.Append(aNewShape); + } + } + } else if (!myMapRemoved.Contains(aSubShape)) { + // Shape is neither removed nor modified. Add it as it is. + if (aSubShape.ShapeType() == aSubShapeType) { + aNewSubShapes.Append(aSubShape); + } else { + aNewOtherShapes.Append(aSubShape); + } + } + } + + // Group sub-shapes via bounds + TopTools_ListOfShape aNewShapes; + + groupViaBounds(theShOrCS, aNewSubShapes, aNewShapes); + aNewOtherShapes.Prepend(aNewShapes); + + if (!aNewOtherShapes.IsEmpty()) { + // Store modified shapes. + myMapModified.ChangeFind(theShOrCS) = aNewOtherShapes; + } +} + +//======================================================================= +//function : processCompound +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::processCompound(const TopoDS_Shape &theCompound) +{ + // Treat sub-shapes. + TopoDS_Iterator anIter(theCompound); + TopTools_ListOfShape aNewSubShapes; + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (myMapModified.IsBound(aSubShape)) { + TopTools_ListOfShape aModifList; + + getModified(aSubShape, aModifList); + + // Copy shapes to the list of other shapes. + TopTools_ListIteratorOfListOfShape anIter(aModifList); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape aNewShape = oriented(anIter.Value(), aSubShape); + + aNewSubShapes.Append(aNewShape); + } + } else if (!myMapRemoved.Contains(aSubShape)) { + // Shape is neither removed nor modified. Add it as it is. + aNewSubShapes.Append(aSubShape); + } + } + + if (!aNewSubShapes.IsEmpty()) { + if (aNewSubShapes.Extent() == 1) { + // Avoid creation of new compound for a single sub-shape. + myMapModified.ChangeFind(theCompound).Append(aNewSubShapes.First()); + } else { + TopoDS_Shape aNewShape = makeShape(theCompound, aNewSubShapes); + + // Store modified shapes. + myMapModified.ChangeFind(theCompound).Append(aNewShape); + } + } +} + +//======================================================================= +//function : removeBoundsOnFOrSo +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::removeBoundsOnFOrSo(const TopAbs_ShapeEnum theType) +{ + // Get bounds on faces or solids. + TopExp_Explorer anExp(myShape, theType); + TopTools_MapOfShape aMapFence; + TopAbs_ShapeEnum aBoundType; + TopAbs_ShapeEnum aComplexBndType; + TopTools_IndexedMapOfShape aMapBounds; + + if (theType == TopAbs_FACE) { + aBoundType = TopAbs_EDGE; + aComplexBndType = TopAbs_WIRE; + } else { // solid + aBoundType = TopAbs_FACE; + aComplexBndType = TopAbs_SHELL; + } + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &aShape = anExp.Current(); + + if (aMapFence.Add(aShape)) { + if (myMapRemoved.Contains(aShape)) { + continue; + } + + if (myMapModified.IsBound(aShape)) { + TopTools_ListOfShape aNewShapes; + + getModified(aShape, aNewShapes); + + if (!aNewShapes.IsEmpty()) { + const TopoDS_Shape &aNewShape = aNewShapes.First(); + + if (aNewShape.ShapeType() == theType) { + // Get bounds from the modified shape. + TopExp::MapShapes(aNewShape, aBoundType, aMapBounds); + } + } + } else { + // Get bounds from the original shapes. + TopExp::MapShapes(aShape, aBoundType, aMapBounds); + } + } + } + + // Remove duplicated bounds from the faces or solids + aMapFence.Clear(); + + for (anExp.Init(myShape, theType); anExp.More(); anExp.Next()) { + const TopoDS_Shape &aShape = anExp.Current(); + + if (aMapFence.Add(aShape)) { + if (myMapModified.IsBound(aShape)) { + TopTools_ListOfShape &aNewShapes = + myMapModified.ChangeFind(aShape); + TopTools_ListIteratorOfListOfShape anIter(aNewShapes); + + while (anIter.More()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + Standard_Boolean isToRm = Standard_False; + + if (aSubShape.ShapeType() == aBoundType) { + // edge or face + isToRm = aMapBounds.Contains(aSubShape); + } else if (aSubShape.ShapeType() == aComplexBndType) { + // wire or shell + TopTools_ListOfShape aNewBounds; + Standard_Boolean isModified; + + if (theType == TopAbs_FACE) { + isModified = removeCommonEdges(aSubShape, aMapBounds, aNewBounds); + } else { + isModified = removeCommonFaces(aSubShape, aMapBounds, aNewBounds); + } + + if (isModified) { + myMapModified.Bind(aSubShape, aNewBounds); + aNewShapes.InsertBefore(aNewBounds, anIter); + isToRm = Standard_True; // To remove unmodified bound. + } + } + + if (isToRm) { + aNewShapes.Remove(anIter); + } else { + anIter.Next(); + } + } + } + } + } +} + +//======================================================================= +//function : oriented +//purpose : +//======================================================================= +TopoDS_Shape GEOMAlgo_Extractor::oriented(const TopoDS_Shape &theShape, + const TopoDS_Shape &theContext) +{ + const TopAbs_Orientation aShapeOri = theShape.Orientation(); + const TopAbs_Orientation aContextOri = theContext.Orientation(); + TopoDS_Shape aResult = theShape; + + aResult.Orientation(TopAbs::Compose(aShapeOri, aContextOri)); + + return aResult; +} + +//======================================================================= +//function : makeShape +//purpose : +//======================================================================= +TopoDS_Shape GEOMAlgo_Extractor::makeShape + (const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes) +{ + TopoDS_Shape aResult = getShapeFromSubShapes(theShape, theSubShapes); + + if (aResult.IsNull()) { + // Create a new shape. + BRep_Builder aBuilder; + TopTools_ListIteratorOfListOfShape anIter(theSubShapes); + TopTools_MapOfShape aMapFence; + + aResult = theShape.EmptyCopied(); + aMapFence.Clear(); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + if (aMapFence.Add(aSubShape)) { + aBuilder.Add(aResult, aSubShape); + + // Fill the map of new shape - ancestors. + if (!myMapNewShapeAnc.IsBound(aSubShape)) { + myMapNewShapeAnc.Bind(aSubShape, TopTools_ListOfShape()); + } + + myMapNewShapeAnc.ChangeFind(aSubShape).Append(aResult); + } + } + } + + return aResult; +} + +//======================================================================= +//function : getShapeFromSubShapes +//purpose : +//======================================================================= +TopoDS_Shape GEOMAlgo_Extractor::getShapeFromSubShapes + (const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes) +{ + // Fill the map of sub-shapes. + TopTools_ListIteratorOfListOfShape anIter(theSubShapes); + TopTools_MapOfShape aMapSubShapes; + TopoDS_Shape aFirstSubShape = theSubShapes.First(); + TopoDS_Shape aResult; + + for (; anIter.More(); anIter.Next()) { + aMapSubShapes.Add(anIter.Value()); + } + + // Check if such a shape is already created. + if (!aMapSubShapes.IsEmpty()) { + TopTools_MapIteratorOfMapOfShape aMapIt(aMapSubShapes); + Standard_Boolean isFirst = Standard_True; + TopTools_MapOfShape aMapAncs[2]; + Standard_Integer iCur = 0; + Standard_Integer iPrev = 1; + + for (; aMapIt.More(); aMapIt.Next()) { + const TopoDS_Shape &aSubShape = aMapIt.Key(); + + // Switch iCur and iPrev. + iCur = iCur ? 0 : 1; + iPrev = iPrev ? 0 : 1; + + if (myMapNewShapeAnc.IsBound(aSubShape)) { + TopTools_ListIteratorOfListOfShape + anAncIt(myMapNewShapeAnc.Find(aSubShape)); + + if (isFirst) { + // This is a first loop. Just fill the map of ancestors. + for (; anAncIt.More(); anAncIt.Next()) { + aMapAncs[iCur].Add(anAncIt.Value()); + } + } else { + // Add in aMapAnc[iCur] elements that are only in aMapAnc[iPrev]. + for (aMapAncs[iCur].Clear(); anAncIt.More(); anAncIt.Next()) { + const TopoDS_Shape &anAncestor = anAncIt.Value(); + + if (aMapAncs[iPrev].Contains(anAncestor)) { + aMapAncs[iCur].Add(anAncIt.Value()); + } + } + } + + if (aMapAncs[iCur].IsEmpty()) { + // There is no common shape. It means that + // the result should be a new shape. + aMapAncs[iCur].Clear(); + break; + } + } else { + // This is a new sub-shape. So the result shape is new. + aMapAncs[iCur].Clear(); + break; + } + } + + if (!aMapAncs[iCur].IsEmpty()) { + // Get exactly the same shape. + const TopAbs_ShapeEnum aType = theShape.ShapeType(); + + for (aMapIt.Initialize(aMapAncs[iCur]); aMapIt.More(); aMapIt.Next()) { + const TopoDS_Shape &aShape = aMapIt.Key(); + + if (aShape.ShapeType() == aType) { + // Check sub-shapes. + TopoDS_Iterator aSubShIt(aShape); + TopAbs_Orientation aNewOri = TopAbs_FORWARD; + Standard_Boolean isComposedOri = Standard_False; + + for (; aSubShIt.More(); aSubShIt.Next()) { + const TopoDS_Shape &aSubSh = aSubShIt.Value(); + + if (!aMapSubShapes.Contains(aSubSh)) { + // There are another sub-shapes in the ancestor. + break; + } + + if (!isComposedOri && aSubSh.IsSame(aFirstSubShape)) { + // Compose orientaiton. + isComposedOri = Standard_True; + aNewOri = TopAbs::Compose + (aFirstSubShape.Orientation(), aSubSh.Orientation()); + } + } + + if (!aSubShIt.More()) { + // That is the same shape. Compose the orientation. + aResult = aShape; + aResult.Orientation(aNewOri); + break; + } + } + } + } + } + + return aResult; +} + +//======================================================================= +//function : makeResult +//purpose : +//======================================================================= +TopoDS_Shape GEOMAlgo_Extractor::makeResult(const TopoDS_Shape &theShape) +{ + TopoDS_Shape aResult; + + if (!myMapRemoved.Contains(theShape)) { + if (myMapModified.IsBound(theShape)) { + // The shape is modified. + TopTools_ListOfShape aListModif; + + getModified(theShape, aListModif); + + const Standard_Integer aNbShapes = aListModif.Extent(); + + if (aNbShapes == 1) { + aResult = oriented(aListModif.First(), theShape); + } else if (aNbShapes > 1) { + // Build a result as a compound + TopTools_ListIteratorOfListOfShape anIter(aListModif); + BRep_Builder aBuilder; + TopoDS_Compound aCompound; + TopTools_MapOfShape aMapFence; + + aBuilder.MakeCompound(aCompound); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape aModifShape = oriented(anIter.Value(), theShape); + + if (aMapFence.Add(aModifShape)) { + aBuilder.Add(aCompound, aModifShape); + } + } + + aResult = aCompound; + } + } else { + // The result is not modified shape. + aResult = theShape; + } + } + + return aResult; +} + +//======================================================================= +//function : makeHistory +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::makeHistory(const TopoDS_Shape &theShape, + TopTools_MapOfShape &theMapFence) +{ + if (theMapFence.Add(theShape)) { + Standard_Boolean isKept = Standard_True; + + if (myMapRemoved.Contains(theShape)) { + myRemoved.Append(theShape); + isKept = Standard_False; + } else if (myMapModified.IsBound(theShape)) { + TopTools_ListOfShape aListModif; + + getModified(theShape, aListModif, theShape.ShapeType()); + + Standard_Boolean isModif = !aListModif.IsEmpty(); + const TopAbs_ShapeEnum aType = theShape.ShapeType(); + + if (isModif) { + // Add the new shapes. + TopTools_ListIteratorOfListOfShape anIter(aListModif); + + // Skip the first shape. + for (anIter.Next(); anIter.More(); anIter.Next()) { + myNew.Append(anIter.Value()); + } + } + + if (isModif) { + myModified.Append(theShape); + } else { + myRemoved.Append(theShape); + } + + isKept = Standard_False; + } + + if (!isKept) { + // Collect history for children. + TopoDS_Iterator anIter(theShape); + + for (; anIter.More(); anIter.Next()) { + const TopoDS_Shape &aSubShape = anIter.Value(); + + makeHistory(aSubShape, theMapFence); + } + } + } +} + +//======================================================================= +//function : removeCommonEdges +//purpose : +//======================================================================= +Standard_Boolean GEOMAlgo_Extractor::removeCommonEdges + (const TopoDS_Shape &theWire, + const TopTools_IndexedMapOfShape &theMapEdgesToRm, + TopTools_ListOfShape &theNewWires) +{ + TopExp_Explorer anExp(theWire, TopAbs_EDGE); + NCollection_List aListListEdges; + TopTools_ListOfShape aListEdges; + Standard_Boolean isModified = Standard_False; + TopoDS_Vertex aVtx[2]; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &anEdge = anExp.Current(); + + if (theMapEdgesToRm.Contains(anEdge)) { + // This edge is removed. + TopExp::Vertices(TopoDS::Edge(anEdge), aVtx[0], aVtx[1]); + + // Skip edges that have same first and last vertices. + if (aVtx[0].IsNull() || !aVtx[0].IsSame(aVtx[1])) { + if (!aListEdges.IsEmpty()) { + aListListEdges.Append(aListEdges); + aListEdges.Clear(); + } + } + + isModified = Standard_True; + } else { + aListEdges.Append(anEdge); + } + } + + if (!aListEdges.IsEmpty()) { + aListListEdges.Append(aListEdges); + } + + if (isModified && !aListListEdges.IsEmpty()) { + // Make wires. + makeWires(theWire, aListListEdges, theNewWires); + } + + return isModified; +} + +//======================================================================= +//function : removeCommonFaces +//purpose : +//======================================================================= +Standard_Boolean GEOMAlgo_Extractor::removeCommonFaces + (const TopoDS_Shape &theShell, + const TopTools_IndexedMapOfShape &theMapFacesToRm, + TopTools_ListOfShape &theNewShells) +{ + TopExp_Explorer anExp(theShell, TopAbs_FACE); + TopTools_ListOfShape aListFaces; + Standard_Boolean isModified = Standard_False; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &aFace = anExp.Current(); + + if (theMapFacesToRm.Contains(aFace)) { + isModified = Standard_True; + } else { + aListFaces.Append(aFace); + } + } + + if (isModified && !aListFaces.IsEmpty()) { + // Create new shells. + groupViaBounds(theShell, aListFaces, theNewShells); + } + + return isModified; +} + +//======================================================================= +//function : makeWires +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::makeWires + (const TopoDS_Shape &theWire, + NCollection_List &theListListEdges, + TopTools_ListOfShape &theWires) +{ + if (theListListEdges.Size() > 1) { + // Check if it is possible to merge first and last lists of edges. + TopoDS_Edge anEdgeFirst = TopoDS::Edge(theListListEdges.First().First()); + TopoDS_Edge anEdgeLast = TopoDS::Edge(theListListEdges.Last().Last()); + TopoDS_Vertex aCommonVtx; + + if (TopExp::CommonVertex(anEdgeFirst, anEdgeLast, aCommonVtx)) { + // Merge First and last lists of edges. + theListListEdges.First().Prepend(theListListEdges.Last()); + // Remove the last list. + NCollection_List::Iterator anIter(theListListEdges); + + for (;anIter.More(); anIter.Next()) { + if (anIter.Value().IsEmpty()) { + theListListEdges.Remove(anIter); + break; + } + } + } + } + + // Create wires. + NCollection_List::Iterator anIter(theListListEdges); + + for (;anIter.More(); anIter.Next()) { + const TopTools_ListOfShape &anEdges = anIter.Value(); + TopoDS_Shape aNewWireShape = makeShape(theWire, anEdges); + TopoDS_Wire aNewWire = TopoDS::Wire(aNewWireShape); + TopoDS_Vertex aV[2]; + + TopExp::Vertices(aNewWire, aV[0], aV[1]); + + if (!aV[0].IsNull() && !aV[1].IsNull()) { + aNewWire.Closed(aV[0].IsSame(aV[1])); + } + + theWires.Append(aNewWire); + } +} + +//======================================================================= +//function : groupViaBounds +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::groupViaBounds + (const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes, + TopTools_ListOfShape &theNewShapes) +{ + const Standard_Boolean isShell = theShape.ShapeType() == TopAbs_SHELL; + TopAbs_ShapeEnum aBoundType; + + if (isShell) { + aBoundType = TopAbs_EDGE; + } else { // comp-solid + aBoundType = TopAbs_FACE; + } + + // Group connected sub-shapes. + NCollection_Sequence aGroupedSubShapes; + NCollection_Sequence aBounds; + TopTools_ListIteratorOfListOfShape anIt(theSubShapes); + Standard_Integer i; + + for (; anIt.More(); anIt.Next()) { + // Find a zone a sub-shape is connected to. + const TopoDS_Shape &aSubShape = anIt.Value(); + TColStd_MapOfInteger aMapIndices; + const Standard_Integer aNbZones = aBounds.Size(); + TopExp_Explorer anExp(aSubShape, aBoundType); + Standard_Integer j; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &aSubSubShape = anExp.Current(); + + // Check each zone. + for (i = 1; i <= aNbZones; ++i) { + if (!aMapIndices.Contains(i)) { + if (aBounds.Value(i).Contains(aSubSubShape)) { + // The current sub-shape belongs to this zone. + aMapIndices.Add(i); + break; + } + } + } + } + + if (aMapIndices.IsEmpty()) { + // Create a new zone. + aGroupedSubShapes.Append(TopTools_ListOfShape()); + aBounds.Append(TopTools_MapOfShape()); + aGroupedSubShapes.ChangeLast().Append(aSubShape); + anExp.Init(aSubShape, aBoundType); + + TopTools_MapOfShape &aLastZoneBound = aBounds.ChangeLast(); + + for (; anExp.More(); anExp.Next()) { + aLastZoneBound.Add(anExp.Current()); + } + } else { + // Merge zones. Get the first zone. + for (i = 1; i <= aNbZones; ++i) { + if (aMapIndices.Contains(i)) { + break; + } + } + + // Merge other zones with the first one. + TopTools_ListOfShape &aZoneSubShapes = aGroupedSubShapes.ChangeValue(i); + TopTools_MapOfShape &aZoneBounds = aBounds.ChangeValue(i); + + for (j = i + 1; j <= aNbZones; ++j) { + if (aMapIndices.Contains(j)) { + aZoneSubShapes.Append(aGroupedSubShapes.ChangeValue(j)); + + TopTools_MapIteratorOfMapOfShape aMapIt(aBounds.Value(j)); + + for (; aMapIt.More(); aMapIt.Next()) { + aZoneBounds.Add(aMapIt.Key()); + } + } + } + + // Remove merged zones. + for (j = aNbZones; j > i; --j) { + aGroupedSubShapes.Remove(j); + aBounds.Remove(j); + } + + // Add aSubShape to merged zone. + aZoneSubShapes.Append(aSubShape); + anExp.Init(aSubShape, aBoundType); + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &aSubSubShape = anExp.Current(); + + if (!aZoneBounds.Add(aSubSubShape)) { + aZoneBounds.Remove(aSubSubShape); + } + } + } + } + + // Construct new shapes from sub-shapes. + const Standard_Integer aNbGroups = aGroupedSubShapes.Size(); + TopTools_ListOfShape aNewSubShapes; + + for (i = 1; i <= aNbGroups; ++i) { + const TopTools_ListOfShape &aListSubShapes = aGroupedSubShapes.Value(i); + + if (!isShell && aListSubShapes.Extent() == 1) { + // Avoid creation of comp-solid with a single solid. + aNewSubShapes.Append(aListSubShapes.First()); + } else { + TopoDS_Shape aNewShape = makeShape(theShape, aListSubShapes); + + if (aBounds.Value(i).IsEmpty()) { + // This is a closed shape. + aNewShape.Closed(Standard_True); + } + + theNewShapes.Append(aNewShape); + } + } + + // Append the list of single solids (if it is filled). + theNewShapes.Append(aNewSubShapes); +} + +//======================================================================= +//function : getModified +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::getModified(const TopoDS_Shape &theShape, + TopTools_ListOfShape &theModifShapes, + const TopAbs_ShapeEnum theShapeType) +{ + // This shape is modified. + TopTools_ListIteratorOfListOfShape anIt(myMapModified.Find(theShape)); + + for (; anIt.More(); anIt.Next()) { + const TopoDS_Shape &aSubShape = anIt.Value(); + + if (theShapeType == TopAbs_SHAPE || aSubShape.ShapeType() == theShapeType) { + if (myMapModified.IsBound(aSubShape)) { + getModified(aSubShape, theModifShapes); + } else { + theModifShapes.Append(aSubShape); + } } } } @@ -152,6 +1419,9 @@ void GEOMAlgo_Extractor::checkData() // // 10 -myShape=NULL // 11 -mySubShapes contains not only sub-shapes of myShape. +// 12 -Can't remove the main shape. +// 13 -mySubShapes contains seam edges in context of faces. +// 14 -mySubShapes contains degenerated edges in context of faces. // // myWarningStatus : // diff --git a/src/GEOMAlgo/GEOMAlgo_Extractor.hxx b/src/GEOMAlgo/GEOMAlgo_Extractor.hxx index 2b9696ad1..9e9215334 100644 --- a/src/GEOMAlgo/GEOMAlgo_Extractor.hxx +++ b/src/GEOMAlgo/GEOMAlgo_Extractor.hxx @@ -29,8 +29,13 @@ #include +#include #include +#include #include +#include + +class TopTools_IndexedMapOfShape; /** @@ -124,23 +129,234 @@ public: private: /** - * This method reinitializes the shape. + * \brief This method reinitializes the shape. */ void clear(); /** - * This method checks the input data. + * \brief This method checks the input data. */ void checkData(); + /** + * \brief This method fills the map of shapes and ancestors for the whole + * sub-shapes of theShape. This method is recursively called up to the lowest + * level of sub-shapes i.e. vertices. + * + * \param theShape the shape. + */ + void makeMapShapeAncestors(const TopoDS_Shape &theShape); + + /** + * \brief This method marks shapes to be removed and to be modified. + */ + void markShapes(); + + /** + * \brief This method marks theShape to be removed. If it is required, it + * recursively marks its sub-shapes to be removed. + * + * \param theShape the shape. + */ + void markRemoved(const TopoDS_Shape &theShape); + + /** + * \brief This method marks ancestors of theShape to be modified. It is + * recursively called up to the level of main shape. + * + * \param theShape the shape. + */ + void markAncestorsModified(const TopoDS_Shape &theShape); + + /** + * \brief This method performs computation of modified shapes of + * the provided type. + * + * \param theType the processed shape type. + */ + void processShapes(const TopAbs_ShapeEnum &theType); + + /** + * \brief This method performs computation of a modified edge. + * + * \param theEdge the modified edge (should be forward). + */ + void processEdge(const TopoDS_Shape &theEdge); + + /** + * \brief This method performs computation of a modified wire. + * + * \param theWire the modified wire (should be forward). + */ + void processWire(const TopoDS_Shape &theWire); + + /** + * \brief This method performs computation of a modified face or solid. + * + * \param theFOrSo the modified face or solid (should be forward). + */ + void processFOrSo(const TopoDS_Shape &theFOrSo); + + /** + * \brief This method performs computation of a modified shell or comp-solid. + * + * \param theShOrCS the modified shell or comp-solid (should be forward). + */ + void processShOrCS(const TopoDS_Shape &theShOrCS); + + /** + * \brief This method performs computation of a modified compound. + * + * \param theCompound the modified compound (should be forward). + */ + void processCompound(const TopoDS_Shape &theCompound); + + /** + * \brief This method removes hanging edges (faces) built for faces (solids) + * if they lie on created faces (solids). + * + * \param theType the shape type. Should be either face or solid. + */ + void removeBoundsOnFOrSo(const TopAbs_ShapeEnum theType); + + /** + * \brief Returns theShape with an orientation composed with theContext's + * orientation. + * + * \param theShape the shape to be re-oriented. + * \param theContext the context shape. + */ + TopoDS_Shape oriented(const TopoDS_Shape &theShape, + const TopoDS_Shape &theContext); + + /** + * \brief This method makes a shape as an empty copy of theShape adding + * subshapes to it. + * + * \param theShape the shape to be copied (should be forward). + * \param theSubShapes the sub-shapes (should be oriented correctly). + * \return the modified shape. + */ + TopoDS_Shape makeShape(const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes); + + /** + * \brief This method returns the shape from the list of sub-shapes + * if there is any shape created already with these sub-shapes. + * If there is no such shape, null shape is returned. + * + * \param theShape the shape to be copied (should be forward). + * \param theSubShapes the sub-shapes (should be oriented correctly). + * \return the modified shape (or null if it is not found). + */ + TopoDS_Shape getShapeFromSubShapes(const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes); + + /** + * \brief This method makes the result for the given shape. If it is removed + * the result is a compound of its modified sub-shapes (or a single + * modified sub-shape if it in only one). + * + * \param theShape the shape. + * \return the result. + */ + TopoDS_Shape makeResult(const TopoDS_Shape &theShape); + + /** + * \brief This method fills the lists of shapes myRemoved, myModified and + * myNew with removed, modified and newly created shapes correspondingly. + * This method is called recursively for sub-shapes of the shape. + * + * \param theShape the shape. + * \param theMapFence the map of already treated shapes. + */ + void makeHistory(const TopoDS_Shape &theShape, + TopTools_MapOfShape &theMapFence); + + /** + * \brief This method removes edges that are in theMapEdgesToRm from + * theWire and re-creates one or more wires from the rest edges. theNewWires + * contains the modified wire(s). + * + * \param theWire the input wire. + * \param theMapEdgesToRm the map of edges to be extracted from theWire. + * \param theNewWires is the list of new wires. Output parameter. + * \return Standard_True if theWire is modified; Standard_False otherwise. + */ + Standard_Boolean removeCommonEdges + (const TopoDS_Shape &theWire, + const TopTools_IndexedMapOfShape &theMapEdgesToRm, + TopTools_ListOfShape &theNewWires); + + /** + * \brief This method removes faces that are in theMapFacesToRm from + * theShell and re-creates one or more shells from the rest faces. + * theNewShells contains the modified shell(s). + * + * \param theShell the input shell. + * \param theMapFacesToRm the map of faces to be extracted from theShell. + * \param theNewShells is the list of new shells. Output parameter. + * \return Standard_True if theShell is modified; Standard_False otherwise. + */ + Standard_Boolean removeCommonFaces + (const TopoDS_Shape &theShell, + const TopTools_IndexedMapOfShape &theMapFacesToRm, + TopTools_ListOfShape &theNewShells); + + /** + * \brief This method creates wires from the list of list of edges. + * + * \param theWire the input wire. + * \param theListListEdges the list of list of edges. Can be modified + * on output. + * \param theWires the list of created wires. Output parameter. + */ + void makeWires(const TopoDS_Shape &theWire, + NCollection_List &theListListEdges, + TopTools_ListOfShape &theWires); + + /** + * \brief This method collects the shapes in theShapes via common bounds. + * This method is used to group faces into shells via common edges or + * solids into compsolids via common faces. Collected lists of shapes + * are used to create new shapes from theShape that are returned in + * theNewShapes. theNewShapes is not cleared at first. + * + * \param theShape the original shape. + * \param theSubShapes the list of shapes to be connected. + * \param theNewShapes the list of newly created shapes. Output parameter. + */ + void groupViaBounds(const TopoDS_Shape &theShape, + const TopTools_ListOfShape &theSubShapes, + TopTools_ListOfShape &theNewShapes); + + /** + * \brief This method returns the list of modified shapes obtained + * from theShape. It performs recursive search in myMapModified. + * theModifShapes is not cleared at first. If theShapeType filter is equal + * to TopAbs_SHAPE (default value) all modified shapes will be returned, + * otherwise shapes of particular type will only be returned. + * + * \param theShape the shape examined. + * \param theModifShapes the list of modified shapes. Output parameter. + * \param theShapeType the shape type filter. + */ + void getModified(const TopoDS_Shape &theShape, + TopTools_ListOfShape &theModifShapes, + const TopAbs_ShapeEnum theShapeType = TopAbs_SHAPE); + protected: - TopoDS_Shape myShape; - TopoDS_Shape myResult; - TopTools_ListOfShape mySubShapes; - TopTools_ListOfShape myRemoved; - TopTools_ListOfShape myModified; - TopTools_ListOfShape myNew; + TopoDS_Shape myShape; + TopoDS_Shape myResult; + TopTools_ListOfShape mySubShapes; + TopTools_ListOfShape myRemoved; + TopTools_ListOfShape myModified; + TopTools_ListOfShape myNew; + TopTools_DataMapOfShapeListOfShape myMapShapeAnc; + TopTools_MapOfShape myMapRemoved; + TopTools_DataMapOfShapeListOfShape myMapModified; + TopTools_DataMapOfShapeListOfShape myMapNewShapeAnc; }; diff --git a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx index 71e3c7042..11614e378 100644 --- a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx @@ -841,10 +841,21 @@ Standard_Integer GEOMImpl_ShapeDriver::Execute(TFunction_Logbook& log) const if (!anIDs.IsNull()) { const int anUpperID = anIDs->Upper(); + const int aNbShapes = anIndices.Extent(); for (i = anIDs->Lower(); i <= anUpperID; ++i) { - const Standard_Integer anIndex = anIDs->Value(i); - const TopoDS_Shape &aSubShape = anIndices.FindKey(anIndex); + const Standard_Integer anIndex = anIDs->Value(i); + + if (anIndex < 1 || anIndex > aNbShapes) { + TCollection_AsciiString aMsg(" Invalid index: "); + + aMsg += TCollection_AsciiString(anIndex); + StdFail_NotDone::Raise(aMsg.ToCString()); + return 0; + } + + const TopoDS_Shape &aSubShape = anIndices.FindKey(anIndex); + aListSubShapes.Append(aSubShape); } } diff --git a/src/GEOM_I/GEOM_IShapesOperations_i.cc b/src/GEOM_I/GEOM_IShapesOperations_i.cc index 324401311..c6c30b228 100644 --- a/src/GEOM_I/GEOM_IShapesOperations_i.cc +++ b/src/GEOM_I/GEOM_IShapesOperations_i.cc @@ -2244,6 +2244,7 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeExtraction GEOM::GEOM_Object_var aGEOMObject; //Set a not done flag + theStats = new GEOM::GEOM_IShapesOperations::ExtractionStats; GetOperations()->SetNotDone(); //Get the reference object @@ -2253,7 +2254,12 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeExtraction return aGEOMObject._retn(); } - const int aNbIDs = theSubShapeIDs.length(); + const int aNbIDs = theSubShapeIDs.length(); + + if (aNbIDs == 0) { + return aGEOMObject._retn(); + } + int i; Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, aNbIDs); @@ -2272,11 +2278,9 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeExtraction } // Convert statistics. - GEOM::GEOM_IShapesOperations::ExtractionStats_var aResStats = - new GEOM::GEOM_IShapesOperations::ExtractionStats; - const int aNbStats = aStats.size(); + const int aNbStats = aStats.size(); - aResStats->length(aNbStats); + theStats->length(aNbStats); // fill the local CORBA array with values from lists std::list::const_iterator @@ -2316,11 +2320,8 @@ GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeExtraction aResStat->indices = aResIDList; - aResStats[i] = aResStat; + theStats[i] = aResStat; } - // initialize out-parameter with local array - theStats = aResStats._retn(); - return GetObject(aResult); } diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index 16e9ea4ca..03de44164 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -6657,6 +6657,35 @@ class geomBuilder(object, GEOM._objref_GEOM_Gen): RaiseIfFailed("IsSubShapeBelongsTo", self.ShapesOp) return IsOk + ## Perform extraction of sub-shapes from the main shape. + # + # @param theShape the main shape + # @param theListOfID the list of sub-shape IDs to be extracted from + # the main shape. + # @return New GEOM.GEOM_Object, containing the shape without + # extracted sub-shapes. + # + # @ref tui_multi_transformation "Example" + @ManageTransactions("ShapesOp") + def MakeExtraction(self, theShape, theListOfID, theName=None): + """ + Perform extraction of sub-shapes from the main shape. + + Parameters: + theShape the main shape + theListOfID the list of sub-shape IDs to be extracted from + the main shape. + + Returns + New GEOM.GEOM_Object, containing the shape without + extracted sub-shapes. + """ + # Example: see GEOM_TestAll.py + (anObj, aStat) = self.ShapesOp.MakeExtraction(theShape, theListOfID) + RaiseIfFailed("MakeExtraction", self.ShapesOp) + self._autoPublish(anObj, theName, "Extraction") + return anObj + # end of l4_decompose ## @} diff --git a/src/OperationGUI/OperationGUI_ExtractionDlg.cxx b/src/OperationGUI/OperationGUI_ExtractionDlg.cxx index 6885ff728..47f2e722b 100644 --- a/src/OperationGUI/OperationGUI_ExtractionDlg.cxx +++ b/src/OperationGUI/OperationGUI_ExtractionDlg.cxx @@ -319,6 +319,8 @@ OperationGUI_ExtractionDlg::OperationGUI_ExtractionDlg /***************************************************************/ myHelpFileName = "extract_and_rebuild_page.html"; + resize(525, 600); + /* Initialisation */ Init(); } @@ -1005,7 +1007,7 @@ void OperationGUI_ExtractionDlg::onRebuild() QStringList aStrList; - for (j = 1; j < 8; ++j) { + for (j = 0; j < 8; ++j) { if (aNbShapes[j] >= 1) { const char *aShapeType = aNbShapes[j] == 1 ? SINGLE_SHAPE_TYPE_TR_CODES[j] : PLURAL_SHAPE_TYPE_TR_CODES[j];