diff --git a/doc/salome/gui/GEOM/CMakeLists.txt b/doc/salome/gui/GEOM/CMakeLists.txt index f7877081b..b765fe7ae 100644 --- a/doc/salome/gui/GEOM/CMakeLists.txt +++ b/doc/salome/gui/GEOM/CMakeLists.txt @@ -66,6 +66,7 @@ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/GEOM DESTINATION ${SALOME_INSTALL_ INSTALL(FILES images/head.png DESTINATION ${SALOME_INSTALL_DOC}/gui/GEOM) INSTALL(FILES images/head.png DESTINATION ${SALOME_INSTALL_DOC}/gui/GEOM/geompy_doc) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/static/SALOME_BOA_PA.pdf DESTINATION ${SALOME_INSTALL_DOC}/gui/GEOM) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/static/ExtractAndRebuild.pdf DESTINATION ${SALOME_INSTALL_DOC}/gui/GEOM) INSTALL(FILES input/geompy_migration.doc input/tui_auto_completion_documentation.doc input/tui_execution_distribution.doc DESTINATION ${SALOME_INSTALL_DOC}/gui/GEOM/input) FILE(GLOB tag_files ${CMAKE_CURRENT_BINARY_DIR}/*.tag) diff --git a/doc/salome/gui/GEOM/images/extract_init.png b/doc/salome/gui/GEOM/images/extract_init.png new file mode 100644 index 000000000..d60855104 Binary files /dev/null and b/doc/salome/gui/GEOM/images/extract_init.png differ diff --git a/doc/salome/gui/GEOM/images/extract_rebuild.png b/doc/salome/gui/GEOM/images/extract_rebuild.png new file mode 100644 index 000000000..f553d263d Binary files /dev/null and b/doc/salome/gui/GEOM/images/extract_rebuild.png differ diff --git a/doc/salome/gui/GEOM/images/extract_result.png b/doc/salome/gui/GEOM/images/extract_result.png new file mode 100644 index 000000000..4148d0d97 Binary files /dev/null and b/doc/salome/gui/GEOM/images/extract_result.png differ diff --git a/doc/salome/gui/GEOM/input/extract_and_rebuild.doc b/doc/salome/gui/GEOM/input/extract_and_rebuild.doc new file mode 100644 index 000000000..88a90da3d --- /dev/null +++ b/doc/salome/gui/GEOM/input/extract_and_rebuild.doc @@ -0,0 +1,82 @@ +/*! + +\page extract_and_rebuild_page Extract and Rebuild + + +This operation allows extraction of sub-shapes from a given +shape. + +To use this operation, select in the Main Menu Operations -> Extract and Rebuild. +The following dialog box appears: + +\image html extract_rebuild.png "Extract and Rebuild Dialog" + +In this dialog: + + +TUI Command: geompy.MakeExtraction(theShape, theListOfID), +
where \em theShape is the main shape, \em theListOfID is a list of +sub-shape IDs to be extracted. + +Our TUI Scripts provide you with useful example of the use of +\ref swig_MakeExtraction "Extract and Rebuild" functionality. + +More details + +If a sub-shape is extracted, all its ancestors should be modified. An ancestors +of extracted sub-shapes can be either: +- created anew without extracted sub-shapes, or +- extracted if it is not possible to create a valid shape without extracted +sub-shape. + +E.g. it is necessary to extract the vertex from the box: + +\image html extract_init.png "Extraction of the vertex from the box" + +In this case 3 ancestor edges are removed as they can't be valid without +this vertex. 3 faces that contain these edges are also removed. It is because +the wires without edges are not closed and it is not possible to create +a valid face on not closed wire. These wires should contain two remaining +edges, but they are removed as they are the part of the remaining shell. +So these wires become empty that means that they should be removed as well. + +The shell is replaced by another one that contains 3 not modified faces. As +It is not possible to construct a valid solid from not closed shell the solid +is removed. So the result of the extraction is a shell that contains 3 faces: + +\image html extract_result.png "Result shape" + +Please, refer to this document for a detailed +description of Extract and Rebuild operation. + +*/ diff --git a/doc/salome/gui/GEOM/input/related_docs.doc b/doc/salome/gui/GEOM/input/related_docs.doc index fea4ba010..2f210676c 100644 --- a/doc/salome/gui/GEOM/input/related_docs.doc +++ b/doc/salome/gui/GEOM/input/related_docs.doc @@ -7,4 +7,6 @@ that can be useful for reading. General Fuse Algorithm, Partition Algorithm, Boolean Operations Algorithm. Backgrounds. +Extract and Rebuild algorithm specification. + */ diff --git a/doc/salome/gui/GEOM/input/transforming_geom_objs.doc b/doc/salome/gui/GEOM/input/transforming_geom_objs.doc index 8ded8676a..3a1307360 100644 --- a/doc/salome/gui/GEOM/input/transforming_geom_objs.doc +++ b/doc/salome/gui/GEOM/input/transforming_geom_objs.doc @@ -27,6 +27,8 @@ special case of \b Explode operation. special case of \b Explode operation.
  • \subpage transfer_data_page "Transfer Data" operation, which copies non-topological data from one shape to another.
  • +
  • \subpage extract_and_rebuild_page "Extract and Rebuild" operation, which +extracts sub-shapes from the main shape.
  • \subpage restore_presentation_parameters_page "Restore presentation parameters". diff --git a/doc/salome/gui/GEOM/input/tui_test_all.doc b/doc/salome/gui/GEOM/input/tui_test_all.doc index 5ed1334a0..7c2ddd136 100644 --- a/doc/salome/gui/GEOM/input/tui_test_all.doc +++ b/doc/salome/gui/GEOM/input/tui_test_all.doc @@ -105,6 +105,9 @@ \until geompy.GetSubShapeEdgeSorted(Sketcher3d_2, p3, "OrderedEdges") \anchor swig_GetSubShapesWithTolerance +\until geompy.GetSubShapesWithTolerance(Box, GEOM.FACE, GEOM.CC_LE, 1.e-7, "le") + +\anchor swig_MakeExtraction \until print "DONE" */ diff --git a/doc/salome/gui/GEOM/static/ExtractAndRebuild.pdf b/doc/salome/gui/GEOM/static/ExtractAndRebuild.pdf new file mode 100644 index 000000000..36e411057 Binary files /dev/null and b/doc/salome/gui/GEOM/static/ExtractAndRebuild.pdf differ diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index be4adbbd0..777f3bcc3 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -2782,6 +2782,43 @@ module GEOM in comparison_condition theCondition, in double theTolerance); + /** + * This enumeration represents an extraction statistics type. It is used in + * the interface GEOM_IShapesOperations::MakeExtraction. + */ + enum ExtractionStatType + { + EST_Removed, ///< Removed sub-shapes + EST_Modified, ///< Modified sub-shapes + EST_Added ///< Newly created sub-shapes + }; + + /*! + * This structure defines a format of extraction statistics. It is used in + * the interface GEOM_IShapesOperations::MakeExtraction. + */ + struct ExtractionStat + { + ExtractionStatType type; ///< Type of extraction statistics. + ListOfLong indices; ///< Shape indices touched by this type of modification. + }; + + typedef sequence ExtractionStats; + + /*! + * \brief Return the shape that is constructed from theShape without + * extracted sub-shapes from the input list. + * + * \param theShape the original shape. + * \param theSubShapeIDs the list of sub-shape IDs to be extracted from + * the original shape. + * \param theStats the operation statistics. Output parameter. + * \return the shape without extracted sub-shapes. + */ + GEOM_Object MakeExtraction(in GEOM_Object theShape, + in ListOfLong theSubShapeIDs, + out ExtractionStats theStats); + }; // # GEOM_IBlocksOperations: diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index b08b1d5b9..ed5809964 100755 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -94,6 +94,7 @@ SET( _res_files edgeextension.png erase.png eraseall.png + extract.png extruded_boss.png extruded_cut.png facetosurface.png diff --git a/resources/extract.png b/resources/extract.png new file mode 100644 index 000000000..cdbe85a83 Binary files /dev/null and b/resources/extract.png differ diff --git a/src/GEOMAlgo/CMakeLists.txt b/src/GEOMAlgo/CMakeLists.txt index d2b6024ab..38126e94b 100755 --- a/src/GEOMAlgo/CMakeLists.txt +++ b/src/GEOMAlgo/CMakeLists.txt @@ -59,6 +59,7 @@ SET(GEOMAlgo_HEADERS GEOMAlgo_DataMapOfPassKeyInteger.hxx GEOMAlgo_DataMapOfShapeMapOfShape.hxx GEOMAlgo_DataMapOfShapePnt.hxx + GEOMAlgo_Extractor.hxx GEOMAlgo_FinderShapeOn.hxx GEOMAlgo_FinderShapeOn1.hxx GEOMAlgo_FinderShapeOn2.hxx @@ -123,6 +124,7 @@ SET(GEOMAlgo_SOURCES GEOMAlgo_ClsfSurf.cxx GEOMAlgo_CoupleOfShapes.cxx GEOMAlgo_FinderShapeOn2.cxx + GEOMAlgo_Extractor.cxx GEOMAlgo_GetInPlace.cxx GEOMAlgo_GetInPlace_1.cxx GEOMAlgo_GetInPlace_2.cxx diff --git a/src/GEOMAlgo/GEOMAlgo_Extractor.cxx b/src/GEOMAlgo/GEOMAlgo_Extractor.cxx new file mode 100644 index 000000000..bdbadab69 --- /dev/null +++ b/src/GEOMAlgo/GEOMAlgo_Extractor.cxx @@ -0,0 +1,1429 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File: GEOMAlgo_Extractor.cxx +// Created: +// Author: Sergey KHROMOV +// + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//======================================================================= +//function : GEOMAlgo_Extractor +//purpose : +//======================================================================= +GEOMAlgo_Extractor::GEOMAlgo_Extractor() +{ +} + +//======================================================================= +//function : ~GEOMAlgo_Extractor +//purpose : +//======================================================================= +GEOMAlgo_Extractor::~GEOMAlgo_Extractor() +{ +} + +//======================================================================= +//function : SetShape +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::SetShape(const TopoDS_Shape &theShape) +{ + myShape = theShape; + myMapShapeAnc.Clear(); + clear(); +} + +//======================================================================= +//function : SetShapesToRemove +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::SetShapesToRemove + (const TopTools_ListOfShape &theSubShapes) +{ + mySubShapes.Assign(theSubShapes); + clear(); +} + +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::Perform() +{ + clear(); + myErrorStatus = 0; + // + checkData(); + + if(myErrorStatus) { + return; + } + + if (myWarningStatus == 10) { + // The result is the same shape. Nothing is modified. + 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); +} + +//======================================================================= +//function : GetResult +//purpose : +//======================================================================= +const TopoDS_Shape &GEOMAlgo_Extractor::GetResult() const +{ + return myResult; +} + +//======================================================================= +//function : clear +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::clear() +{ + myErrorStatus = 1; + myWarningStatus = 0; + myResult.Nullify(); + myRemoved.Clear(); + myModified.Clear(); + myNew.Clear(); + myMapRemoved.Clear(); + myMapModified.Clear(); + myMapNewShapeAnc.Clear(); +} + +//======================================================================= +//function : checkData +//purpose : +//======================================================================= +void GEOMAlgo_Extractor::checkData() +{ + if (myShape.IsNull()) { + myErrorStatus = 10; + return; + } + + if (mySubShapes.IsEmpty()) { + myWarningStatus = 10; + return; + } + + 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 (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); + } + } + } +} + + +// +// myErrorStatus : +// +// 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 : +// +// 10 -mySubShapes is empty +// diff --git a/src/GEOMAlgo/GEOMAlgo_Extractor.hxx b/src/GEOMAlgo/GEOMAlgo_Extractor.hxx new file mode 100644 index 000000000..9e9215334 --- /dev/null +++ b/src/GEOMAlgo/GEOMAlgo_Extractor.hxx @@ -0,0 +1,363 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +// File: GEOMAlgo_Extractor.hxx +// Author: Sergey KHROMOV + +#ifndef _GEOMAlgo_Extractor_HeaderFile +#define _GEOMAlgo_Extractor_HeaderFile + + +#include + +#include +#include +#include +#include +#include + +class TopTools_IndexedMapOfShape; + + +/** + * \brief This class encapsulates an algorithm of extraction of sub-shapes + * from the main shape. + */ +class GEOMAlgo_Extractor : public GEOMAlgo_Algo +{ +public: + + /** + * \brief Empty constructor. + */ + Standard_EXPORT GEOMAlgo_Extractor(); + + /** + * \brief Virtual destructor. + */ + Standard_EXPORT virtual ~GEOMAlgo_Extractor(); + + /** + * \brief This method sets the main shape. + * + * \param theShape the main shape. + */ + Standard_EXPORT void SetShape(const TopoDS_Shape &theShape); + + /** + * \brief This method returns the main shape. + * + * \return the main shape. + */ + const TopoDS_Shape &GetShape() const + { return myShape; } + + /** + * \brief This method sets the list of sub-shapes to be removed + * from the main shape. + * + * \param theSubShapes the sub-shapes to be removed. + */ + Standard_EXPORT void SetShapesToRemove + (const TopTools_ListOfShape &theSubShapes); + + /** + * \brief This method returns the list of sub-shapes to be removed + * from the main shape. + * + * \return the list of sub-shapes to be removed. + */ + const TopTools_ListOfShape &GetShapesToRemove() const + { return mySubShapes; } + + /** + * This method performs computation of the extracted shape. + */ + Standard_EXPORT virtual void Perform(); + + /** + * This method returns the result of the algorithm. + * + * \return the result of the operation. + */ + Standard_EXPORT const TopoDS_Shape &GetResult() const; + + /** + * \brief This method returns the sub-shapes removed from the main shape. + * + * \return the list of removed sub-shapes. + */ + const TopTools_ListOfShape &GetRemoved() const + { return myRemoved; } + + /** + * \brief This method returns the sub-shapes modified in the main shape. + * + * \return the list of modified sub-shapes. + */ + const TopTools_ListOfShape &GetModified() const + { return myModified; } + + /** + * \brief This method returns the newly created sub-shapes in the result + * shape. + * + * \return the list of new sub-shapes in result. + */ + const TopTools_ListOfShape &GetNew() const + { return myNew; } + +private: + + /** + * \brief This method reinitializes the shape. + */ + void clear(); + + /** + * \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; + TopTools_DataMapOfShapeListOfShape myMapShapeAnc; + TopTools_MapOfShape myMapRemoved; + TopTools_DataMapOfShapeListOfShape myMapModified; + TopTools_DataMapOfShapeListOfShape myMapNewShapeAnc; + +}; + +#endif diff --git a/src/GEOMGUI/GEOM_images.ts b/src/GEOMGUI/GEOM_images.ts index cfcccd313..5ec53885f 100644 --- a/src/GEOMGUI/GEOM_images.ts +++ b/src/GEOMGUI/GEOM_images.ts @@ -1387,6 +1387,10 @@ ICO_TRANSFER_DATA transfer_data.png + + ICO_EXTRACTION + extract.png + ICO_IMPORT_SHAPE import.png @@ -1407,6 +1411,10 @@ ICON_DLG_TRANSFER_DATA transfer_data.png + + ICON_DLG_EXTRACTION + extract.png + ICON_DLG_SCALE_ALONG_AXES scale_along_axes.png diff --git a/src/GEOMGUI/GEOM_msg_en.ts b/src/GEOMGUI/GEOM_msg_en.ts index 7aef53a75..efb543e09 100644 --- a/src/GEOMGUI/GEOM_msg_en.ts +++ b/src/GEOMGUI/GEOM_msg_en.ts @@ -471,6 +471,10 @@ Please, select face, shell or solid and try again GEOM_COMPOUNDSOLID CompSolid + + GEOM_COMPSOLIDS + CompSolids + GEOM_COMPOUND_TITLE Create A Compound @@ -607,6 +611,10 @@ Please, select face, shell or solid and try again GEOM_EDGE Edge + + GEOM_EDGES + Edges + GEOM_EDGE_TITLE Create An Edge @@ -2024,6 +2032,10 @@ Please, select face, shell or solid and try again GEOM_SOLID Solid + + GEOM_SOLIDS + Solids + GEOM_SOLID_TITLE Solid Construction @@ -5236,6 +5248,18 @@ Please, select face, shell or solid and try again STB_TRANSFER_DATA Transfer Data + + TOP_EXTRACTION + Extract and Rebuild + + + MEN_EXTRACTION + Extract and Rebuild + + + STB_EXTRACTION + Extract and Rebuild + TOP_EXTENSION Extend Edge or Face @@ -7629,4 +7653,55 @@ Do you want to create new material? Rotation angle + + OperationGUI_ExtractionDlg + + GEOM_EXTRACT_TITLE + Extract and Rebuild + + + GEOM_EXTRACT_TYPE + Extraction type + + + GEOM_EXTRACT_INPUT_PARAMS + Input parameters + + + GEOM_EXTRACT_STATISTICS + Statistics + + + GEOM_EXTRACT_SUB_SHAPE_TYPE + Sub-shape type + + + GEOM_EXTRACT_FILTERED_SHAPES + Filtered shapes + + + GEOM_EXTRACT_SHAPES_TO_EXTRACT + Shapes to extract + + + GEOM_EXTRACT_REBUILD + Rebuild + + + GEOM_EXTRACT_REMOVED + Removed + + + GEOM_EXTRACT_MODIFIED + Modified + + + GEOM_EXTRACT_ADDED + Added + + + GEOM_EXTRACT_NAME + Extraction + + diff --git a/src/GEOMGUI/GEOM_msg_fr.ts b/src/GEOMGUI/GEOM_msg_fr.ts index a7111b94c..7db35f809 100644 --- a/src/GEOMGUI/GEOM_msg_fr.ts +++ b/src/GEOMGUI/GEOM_msg_fr.ts @@ -471,6 +471,10 @@ Choisissez une face, une coque ou un solide et essayez de nouveau GEOM_COMPOUNDSOLID Assemblage solide + + GEOM_COMPSOLIDS + CompSolids + GEOM_COMPOUND_TITLE Créer un assemblage @@ -607,6 +611,10 @@ Choisissez une face, une coque ou un solide et essayez de nouveau GEOM_EDGE Arête + + GEOM_EDGES + Edges + GEOM_EDGE_TITLE Créer une arête @@ -2016,6 +2024,10 @@ Choisissez une face, une coque ou un solide et essayez de nouveau GEOM_SOLID Solide + + GEOM_SOLIDS + Solids + GEOM_SOLID_TITLE Construction d'un solide @@ -5228,6 +5240,18 @@ Choisissez une face, une coque ou un solide et essayez de nouveau STB_TRANSFER_DATA Transfert de données + + TOP_EXTRACTION + Extract and Rebuild + + + MEN_EXTRACTION + Extract and Rebuild + + + STB_EXTRACTION + Extract and Rebuild + TOP_EXTENSION Extend Edge or Face @@ -7605,4 +7629,55 @@ Voulez-vous en créer un nouveau ? Longueur de l'angle + + OperationGUI_ExtractionDlg + + GEOM_EXTRACT_TITLE + Extract and Rebuild + + + GEOM_EXTRACT_TYPE + Extraction type + + + GEOM_EXTRACT_INPUT_PARAMS + Input parameters + + + GEOM_EXTRACT_STATISTICS + Statistics + + + GEOM_EXTRACT_SUB_SHAPE_TYPE + Sub-shape type + + + GEOM_EXTRACT_FILTERED_SHAPES + Filtered shapes + + + GEOM_EXTRACT_SHAPES_TO_EXTRACT + Shapes to extract + + + GEOM_EXTRACT_REBUILD + Rebuild + + + GEOM_EXTRACT_REMOVED + Removed + + + GEOM_EXTRACT_MODIFIED + Modified + + + GEOM_EXTRACT_ADDED + Added + + + GEOM_EXTRACT_NAME + Extraction + + diff --git a/src/GEOMGUI/GEOM_msg_ja.ts b/src/GEOMGUI/GEOM_msg_ja.ts index 0e42dfe3d..667818994 100644 --- a/src/GEOMGUI/GEOM_msg_ja.ts +++ b/src/GEOMGUI/GEOM_msg_ja.ts @@ -467,6 +467,10 @@ GEOM_COMPOUNDSOLID 固体のアセンブリ + + GEOM_COMPSOLIDS + CompSolids + GEOM_COMPOUND_TITLE コンパウンドの作成 @@ -603,6 +607,10 @@ GEOM_EDGE Edge + + GEOM_EDGES + Edges + GEOM_EDGE_TITLE エッジを作成 @@ -2019,6 +2027,10 @@ GEOM_SOLID ソリッド + + GEOM_SOLIDS + Solids + GEOM_SOLID_TITLE ソリッドの構築 @@ -5231,6 +5243,18 @@ STB_TRANSFER_DATA データ転送 + + TOP_EXTRACTION + Extract and Rebuild + + + MEN_EXTRACTION + Extract and Rebuild + + + STB_EXTRACTION + Extract and Rebuild + TOP_EXTENSION エッジまたは面の拡張 @@ -7598,4 +7622,55 @@ 回転角度 + + OperationGUI_ExtractionDlg + + GEOM_EXTRACT_TITLE + Extract and Rebuild + + + GEOM_EXTRACT_TYPE + Extraction type + + + GEOM_EXTRACT_INPUT_PARAMS + Input parameters + + + GEOM_EXTRACT_STATISTICS + Statistics + + + GEOM_EXTRACT_SUB_SHAPE_TYPE + Sub-shape type + + + GEOM_EXTRACT_FILTERED_SHAPES + Filtered shapes + + + GEOM_EXTRACT_SHAPES_TO_EXTRACT + Shapes to extract + + + GEOM_EXTRACT_REBUILD + Rebuild + + + GEOM_EXTRACT_REMOVED + Removed + + + GEOM_EXTRACT_MODIFIED + Modified + + + GEOM_EXTRACT_ADDED + Added + + + GEOM_EXTRACT_NAME + Extraction + + diff --git a/src/GEOMGUI/GeometryGUI.cxx b/src/GEOMGUI/GeometryGUI.cxx index 0d3f733a6..47aeffbf8 100644 --- a/src/GEOMGUI/GeometryGUI.cxx +++ b/src/GEOMGUI/GeometryGUI.cxx @@ -623,6 +623,7 @@ void GeometryGUI::OnGUIEvent( int id, const QVariant& theParam ) case GEOMOp::OpExtrudedBoss: // MENU OPERATION - EXTRUDED BOSS case GEOMOp::OpExtrudedCut: // MENU OPERATION - EXTRUDED CUT case GEOMOp::OpTransferData: // MENU OPERATION - TRANSFER DATA + case GEOMOp::OpExtraction: // MENU OPERATION - EXTRACT AND REBUILD libName = "OperationGUI"; break; case GEOMOp::OpSewing: // MENU REPAIR - SEWING @@ -1005,6 +1006,7 @@ void GeometryGUI::initialize( CAM_Application* app ) createGeomAction( GEOMOp::OpShapesOnShape, "GET_SHAPES_ON_SHAPE" ); createGeomAction( GEOMOp::OpSharedShapes, "GET_SHARED_SHAPES" ); createGeomAction( GEOMOp::OpTransferData, "TRANSFER_DATA" ); + createGeomAction( GEOMOp::OpExtraction, "EXTRACTION" ); createGeomAction( GEOMOp::OpExtrudedCut, "EXTRUDED_CUT" ); createGeomAction( GEOMOp::OpExtrudedBoss, "EXTRUDED_BOSS" ); createGeomAction( GEOMOp::OpFillet1d, "FILLET_1D" ); @@ -1262,6 +1264,7 @@ void GeometryGUI::initialize( CAM_Application* app ) createMenu( GEOMOp::OpShapesOnShape, operId, -1 ); createMenu( GEOMOp::OpSharedShapes, operId, -1 ); createMenu( GEOMOp::OpTransferData, operId, -1 ); + createMenu( GEOMOp::OpExtraction, operId, -1 ); createMenu( separator(), operId, -1 ); @@ -1438,6 +1441,7 @@ void GeometryGUI::initialize( CAM_Application* app ) createTool( GEOMOp::OpShapesOnShape, operTbId ); createTool( GEOMOp::OpSharedShapes, operTbId ); createTool( GEOMOp::OpTransferData, operTbId ); + createTool( GEOMOp::OpExtraction, operTbId ); int featTbId = createTool( tr( "TOOL_FEATURES" ), QString( "GEOMModification" ) ); createTool( GEOMOp::OpFillet1d, featTbId ); diff --git a/src/GEOMGUI/GeometryGUI_Operations.h b/src/GEOMGUI/GeometryGUI_Operations.h index 480b7d2fd..a80c3d093 100644 --- a/src/GEOMGUI/GeometryGUI_Operations.h +++ b/src/GEOMGUI/GeometryGUI_Operations.h @@ -166,6 +166,7 @@ namespace GEOMOp { OpExtrudedBoss = 3709, // MENU OPERATION - ETRUDED BOSS OpExtrudedCut = 3710, // MENU OPERATION - ETRUDED CUT OpTransferData = 3711, // MENU OPERATION - TRANSFER DATA + OpExtraction = 3712, // MENU OPERATION - EXTRACT AND REBUILD // RepairGUI -------------------//-------------------------------- OpSewing = 4000, // MENU REPAIR - SEWING OpSuppressFaces = 4001, // MENU REPAIR - SUPPRESS FACES diff --git a/src/GEOMImpl/CMakeLists.txt b/src/GEOMImpl/CMakeLists.txt index 5c59b2e72..9bdce7d48 100755 --- a/src/GEOMImpl/CMakeLists.txt +++ b/src/GEOMImpl/CMakeLists.txt @@ -79,6 +79,7 @@ SET(GEOMImpl_HEADERS GEOMImpl_ICircle.hxx GEOMImpl_ISpline.hxx GEOMImpl_IEllipse.hxx + GEOMImpl_IExtract.hxx GEOMImpl_IFillet.hxx GEOMImpl_IFillet1d.hxx GEOMImpl_IFillet2d.hxx diff --git a/src/GEOMImpl/GEOMImpl_IExtract.hxx b/src/GEOMImpl/GEOMImpl_IExtract.hxx new file mode 100644 index 000000000..35a2799e4 --- /dev/null +++ b/src/GEOMImpl/GEOMImpl_IExtract.hxx @@ -0,0 +1,73 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +//NOTE: This is an intreface to a function for the Offset creation. +// +#include "GEOM_Function.hxx" +#include + +#define EXTRACT_SHAPE 1 +#define EXTRACT_IDS 2 +#define EXTRACT_REMOVED_IDS 3 +#define EXTRACT_MODIFIED_IDS 4 +#define EXTRACT_ADDED_IDS 5 + +class GEOMImpl_IExtract +{ + public: + + GEOMImpl_IExtract(Handle(GEOM_Function) theFunction): _func(theFunction) {} + + void SetShape(Handle(GEOM_Function) theShape) + { _func->SetReference(EXTRACT_SHAPE, theShape); } + + Handle(GEOM_Function) GetShape() + { return _func->GetReference(EXTRACT_SHAPE); } + + void SetSubShapeIDs(const Handle(TColStd_HArray1OfInteger)& theSubShapeIDs) + { _func->SetIntegerArray(EXTRACT_IDS, theSubShapeIDs); } + + Handle(TColStd_HArray1OfInteger) GetSubShapeIDs() + { return _func->GetIntegerArray(EXTRACT_IDS); } + + void SetRemovedIDs(const Handle(TColStd_HArray1OfInteger)& theRemovedIDs) + { _func->SetIntegerArray(EXTRACT_REMOVED_IDS, theRemovedIDs); } + + Handle(TColStd_HArray1OfInteger) GetRemovedIDs() + { return _func->GetIntegerArray(EXTRACT_REMOVED_IDS); } + + void SetModifiedIDs(const Handle(TColStd_HArray1OfInteger)& theModifiedIDs) + { _func->SetIntegerArray(EXTRACT_MODIFIED_IDS, theModifiedIDs); } + + Handle(TColStd_HArray1OfInteger) GetModifiedIDs() + { return _func->GetIntegerArray(EXTRACT_MODIFIED_IDS); } + + void SetAddedIDs(const Handle(TColStd_HArray1OfInteger)& theAddedIDs) + { _func->SetIntegerArray(EXTRACT_ADDED_IDS, theAddedIDs); } + + Handle(TColStd_HArray1OfInteger) GetAddedIDs() + { return _func->GetIntegerArray(EXTRACT_ADDED_IDS); } + + private: + + Handle(GEOM_Function) _func; +}; diff --git a/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx b/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx index 65716670c..c02c13f4d 100644 --- a/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IShapesOperations.cxx @@ -36,6 +36,7 @@ #include "GEOMImpl_GlueDriver.hxx" #include "GEOMImpl_FillingDriver.hxx" +#include "GEOMImpl_IExtract.hxx" #include "GEOMImpl_IVector.hxx" #include "GEOMImpl_IShapes.hxx" #include "GEOMImpl_IShapeExtend.hxx" @@ -3163,6 +3164,107 @@ Handle(TColStd_HSequenceOfTransient) return aSeq; } +//============================================================================= +/*! + * MakeExtraction + */ +//============================================================================= +Handle(GEOM_Object) GEOMImpl_IShapesOperations::MakeExtraction + (const Handle(GEOM_Object) &theShape, + const Handle(TColStd_HArray1OfInteger) &theSubShapeIDs, + std::list &theStats) +{ + SetErrorCode(KO); + + if (theShape.IsNull()) { + return NULL; + } + + //Add a new Result object + Handle(GEOM_Object) aResult = + GetEngine()->AddObject(GetDocID(), GEOM_EXTRACTION); + + //Add a new Extraction function + Handle(GEOM_Function) aFunction = + aResult->AddFunction(GEOMImpl_ShapeDriver::GetID(), EXTRACTION); + + //Check if the function is set correctly + if (aFunction->GetDriverGUID() != GEOMImpl_ShapeDriver::GetID()) { + return NULL; + } + + Handle(GEOM_Function) aShape = theShape->GetLastFunction(); + + if (aShape.IsNull()) { + return NULL; + } + + GEOMImpl_IExtract aCI (aFunction); + + aCI.SetShape(aShape); + aCI.SetSubShapeIDs(theSubShapeIDs); + + //Compute the Edge value + try { + OCC_CATCH_SIGNALS; + if (!GetSolver()->ComputeFunction(aFunction)) { + SetErrorCode("Shape driver failed"); + + return NULL; + } + } + catch (Standard_Failure) { + Handle(Standard_Failure) aFail = Standard_Failure::Caught(); + SetErrorCode(aFail->GetMessageString()); + + return NULL; + } + + // Fill in statistics. + theStats.clear(); + + Handle(TColStd_HArray1OfInteger) aStatIDsArray[3] = + { aCI.GetRemovedIDs(), aCI.GetModifiedIDs(), aCI.GetAddedIDs() }; + int i; + int j; + + for (j = 0; j < 3; ++j) { + if (!aStatIDsArray[j].IsNull()) { + const int anUpperID = aStatIDsArray[j]->Upper(); + ExtractionStat aStat; + + for (i = aStatIDsArray[j]->Lower(); i <= anUpperID; ++i) { + aStat.indices.push_back(aStatIDsArray[j]->Value(i)); + } + + aStat.type = (ExtractionStatType) j; + theStats.push_back(aStat); + } + } + + //Make a Python command + GEOM::TPythonDump pd(aFunction); + + pd << aResult << " = geompy.MakeExtraction(" << theShape << ", ["; + + if (!theSubShapeIDs.IsNull()) { + const int aNbIDs = theSubShapeIDs->Upper(); + + for (i = theSubShapeIDs->Lower(); i < aNbIDs; ++i) { + pd << theSubShapeIDs->Value(i) << ", "; + } + + // Dump the last value without a comma. + pd << theSubShapeIDs->Value(i); + } + + pd << "])"; + + SetErrorCode(OK); + + return aResult; +} + //======================================================================= //function : getShapesOnSurfaceIDs /*! diff --git a/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx b/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx index d8e4f9fb2..38b375059 100644 --- a/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IShapesOperations.hxx @@ -59,6 +59,25 @@ class GEOMImpl_IShapesOperations : public GEOM_IOperations All = Groups | Fields | SubShapes, }; + /** + * This enumeration represents an extraction statistics type. + */ + enum ExtractionStatType + { + EST_Removed, ///< Removed sub-shapes + EST_Modified, ///< Modified sub-shapes + EST_Added ///< Newly created sub-shapes + }; + + /*! + * This structure defines a format of extraction statistics. + */ + struct ExtractionStat + { + ExtractionStatType type; ///< Type of extraction statistics. + std::list indices; ///< Shape indices touched by this type of modification. + }; + Standard_EXPORT GEOMImpl_IShapesOperations(GEOM_Engine* theEngine, int theDocID); Standard_EXPORT ~GEOMImpl_IShapesOperations(); @@ -470,6 +489,21 @@ class GEOMImpl_IShapesOperations : public GEOM_IOperations const GEOMUtils::ComparisonCondition theCondition, const Standard_Real theTolerance); + /*! + * \brief Return the shape that is constructed from theShape without + * extracted sub-shapes from the input list. + * + * \param theShape the original shape. + * \param theSubShapeIDs the list of sub-shape IDs to be extracted from + * the original shape. + * \param theStats the operation statistics. Output parameter. + * \return the shape without extracted sub-shapes. + */ + Handle(GEOM_Object) MakeExtraction + (const Handle(GEOM_Object) &theShape, + const Handle(TColStd_HArray1OfInteger) &theSubShapeIDs, + std::list &theStats); + private: Handle(GEOM_Object) MakeShape (std::list theShapes, const Standard_Integer theObjectType, diff --git a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx index 46bcd193e..471fd679b 100644 --- a/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx +++ b/src/GEOMImpl/GEOMImpl_ShapeDriver.cxx @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include // OCCT Includes #include @@ -109,6 +111,39 @@ #include +/** + * \brief This static function converts the list of shapes into an array + * of their IDs. If the input list is empty, null handle will be returned. + * this method doesn't check if a shape presents in theIndices map. + * + * \param theListOfShapes the list of shapes. + * \param theIndices the indexed map of shapes. + * \return the array of shape IDs. + */ +static Handle(TColStd_HArray1OfInteger) GetShapeIDs + (const TopTools_ListOfShape &theListOfShapes, + const TopTools_IndexedMapOfShape &theIndices) +{ + Handle(TColStd_HArray1OfInteger) aResult; + + if (!theListOfShapes.IsEmpty()) { + const Standard_Integer aNbShapes = theListOfShapes.Extent(); + TopTools_ListIteratorOfListOfShape anIter(theListOfShapes); + Standard_Integer i; + + aResult = new TColStd_HArray1OfInteger(1, aNbShapes); + + for (i = 1; anIter.More(); anIter.Next(), ++i) { + const TopoDS_Shape &aShape = anIter.Value(); + const Standard_Integer anIndex = theIndices.FindIndex(aShape); + + aResult->SetValue(i, anIndex); + } + } + + return aResult; +} + namespace { // check that compound includes only shapes of expected type @@ -918,6 +953,97 @@ Standard_Integer GEOMImpl_ShapeDriver::Execute(TFunction_Logbook& log) const } } } + } else if (aType == EXTRACTION) { + allowCompound = true; + + GEOMImpl_IExtract aCI(aFunction); + Handle(GEOM_Function) aRefShape = aCI.GetShape(); + TopoDS_Shape aShapeBase = aRefShape->GetValue(); + + if (aShapeBase.IsNull()) { + Standard_NullObject::Raise("Argument Shape is null"); + return 0; + } + + Handle(TColStd_HArray1OfInteger) anIDs = aCI.GetSubShapeIDs(); + TopTools_ListOfShape aListSubShapes; + TopTools_IndexedMapOfShape anIndices; + int i; + + TopExp::MapShapes(aShapeBase, anIndices); + + 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); + + 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); + } + } + + // Compute extraction. + GEOMAlgo_Extractor anExtractor; + + anExtractor.SetShape(aShapeBase); + anExtractor.SetShapesToRemove(aListSubShapes); + + anExtractor.Perform(); + + // Interprete results + Standard_Integer iErr = anExtractor.ErrorStatus(); + + // The detailed description of error codes is in GEOMAlgo_Extractor.cxx + if (iErr) { + TCollection_AsciiString aMsg(" iErr : "); + + aMsg += TCollection_AsciiString(iErr); + StdFail_NotDone::Raise(aMsg.ToCString()); + return 0; + } + + aShape = anExtractor.GetResult(); + + // Get statistics. + const TopTools_ListOfShape &aRemoved = anExtractor.GetRemoved(); + const TopTools_ListOfShape &aModified = anExtractor.GetModified(); + const TopTools_ListOfShape &aNew = anExtractor.GetNew(); + Handle(TColStd_HArray1OfInteger) aRemovedIDs = + GetShapeIDs(aRemoved, anIndices); + Handle(TColStd_HArray1OfInteger) aModifiedIDs = + GetShapeIDs(aModified, anIndices); + Handle(TColStd_HArray1OfInteger) aNewIDs; + + if (!aShape.IsNull()) { + // Get newly created sub-shapes + TopTools_IndexedMapOfShape aNewIndices; + + TopExp::MapShapes(aShape, aNewIndices); + aNewIDs = GetShapeIDs(aNew, aNewIndices); + } + + if (!aRemovedIDs.IsNull()) { + aCI.SetRemovedIDs(aRemovedIDs); + } + + if (!aModifiedIDs.IsNull()) { + aCI.SetModifiedIDs(aModifiedIDs); + } + + if (!aNewIDs.IsNull()) { + aCI.SetAddedIDs(aNewIDs); + } } else { } @@ -1880,6 +2006,15 @@ GetCreationInformation(std::string& theOperationName, AddParam(theParams, "Face", aSE.GetShape()); break; } + case EXTRACTION: + { + GEOMImpl_IExtract aCI (function); + + theOperationName = "EXTRACTION"; + AddParam(theParams, "Main Shape", aCI.GetShape()); + AddParam(theParams, "Sub-shape IDs", aCI.GetSubShapeIDs()); + break; + } default: return false; } diff --git a/src/GEOMImpl/GEOMImpl_Types.hxx b/src/GEOMImpl/GEOMImpl_Types.hxx index 393b4303c..2e58443ac 100644 --- a/src/GEOMImpl/GEOMImpl_Types.hxx +++ b/src/GEOMImpl/GEOMImpl_Types.hxx @@ -119,6 +119,8 @@ #define GEOM_TRANSFER_DATA 57 +#define GEOM_EXTRACTION 58 + //GEOM_Function types #define COPY_WITH_REF 1 @@ -316,6 +318,7 @@ #define FACE_UV 17 #define SURFACE_FROM_FACE 18 #define SOLID_FACES 19 +#define EXTRACTION 20 #define ARCHIMEDE_TYPE 1 diff --git a/src/GEOM_I/GEOM_IShapesOperations_i.cc b/src/GEOM_I/GEOM_IShapesOperations_i.cc index 7561d9a16..c6c30b228 100644 --- a/src/GEOM_I/GEOM_IShapesOperations_i.cc +++ b/src/GEOM_I/GEOM_IShapesOperations_i.cc @@ -2230,3 +2230,98 @@ GEOM::ListOfGO* GEOM_IShapesOperations_i::GetSubShapesWithTolerance return aSeq._retn(); } + +//============================================================================= +/*! + * MakeExtraction + */ +//============================================================================= +GEOM::GEOM_Object_ptr GEOM_IShapesOperations_i::MakeExtraction + (GEOM::GEOM_Object_ptr theShape, + const GEOM::ListOfLong &theSubShapeIDs, + GEOM::GEOM_IShapesOperations::ExtractionStats_out theStats) +{ + GEOM::GEOM_Object_var aGEOMObject; + + //Set a not done flag + theStats = new GEOM::GEOM_IShapesOperations::ExtractionStats; + GetOperations()->SetNotDone(); + + //Get the reference object + Handle(GEOM_Object) aShape = GetObjectImpl(theShape); + + if (aShape.IsNull()) { + return aGEOMObject._retn(); + } + + const int aNbIDs = theSubShapeIDs.length(); + + if (aNbIDs == 0) { + return aGEOMObject._retn(); + } + + int i; + Handle(TColStd_HArray1OfInteger) anArray = + new TColStd_HArray1OfInteger (1, aNbIDs); + + for (i = 0; i < aNbIDs; i++) { + anArray->SetValue(i + 1, theSubShapeIDs[i]); + } + + //Get Shapes in place of aShapeWhat + std::list aStats; + Handle(GEOM_Object) aResult = + GetOperations()->MakeExtraction(aShape, anArray, aStats); + + if (!GetOperations()->IsDone() || aResult.IsNull()) { + return aGEOMObject._retn(); + } + + // Convert statistics. + const int aNbStats = aStats.size(); + + theStats->length(aNbStats); + + // fill the local CORBA array with values from lists + std::list::const_iterator + anIt = aStats.begin(); + + for (i = 0; anIt != aStats.end(); i++, anIt++) { + GEOM::GEOM_IShapesOperations::ExtractionStat_var aResStat = + new GEOM::GEOM_IShapesOperations::ExtractionStat; + + // Copy type + switch (anIt->type) { + case GEOMImpl_IShapesOperations::EST_Removed: + aResStat->type = GEOM::GEOM_IShapesOperations::EST_Removed; + break; + case GEOMImpl_IShapesOperations::EST_Modified: + aResStat->type = GEOM::GEOM_IShapesOperations::EST_Modified; + break; + case GEOMImpl_IShapesOperations::EST_Added: + aResStat->type = GEOM::GEOM_IShapesOperations::EST_Added; + break; + default: + break; + } + + // Copy the list of IDs + std::list aIDList = anIt->indices; + GEOM::ListOfLong_var aResIDList = new GEOM::ListOfLong; + + aResIDList->length(aIDList.size()); + + std::list::iterator anIDIt = aIDList.begin(); + int j = 0; + + for (; anIDIt != aIDList.end(); j++, anIDIt++) { + aResIDList[j] = *anIDIt; + } + + aResStat->indices = aResIDList; + + theStats[i] = aResStat; + } + + return GetObject(aResult); +} diff --git a/src/GEOM_I/GEOM_IShapesOperations_i.hh b/src/GEOM_I/GEOM_IShapesOperations_i.hh index 0f36a38c3..ff9e417f0 100644 --- a/src/GEOM_I/GEOM_IShapesOperations_i.hh +++ b/src/GEOM_I/GEOM_IShapesOperations_i.hh @@ -306,6 +306,11 @@ class GEOM_I_EXPORT GEOM_IShapesOperations_i : GEOM::comparison_condition theCondition, CORBA::Double theTolerance); + GEOM::GEOM_Object_ptr MakeExtraction + (GEOM::GEOM_Object_ptr theShape, + const GEOM::ListOfLong &theSubShapeIDs, + GEOM::GEOM_IShapesOperations::ExtractionStats_out theStats); + ::GEOMImpl_IShapesOperations* GetOperations() { return (::GEOMImpl_IShapesOperations*)GetImpl(); } }; diff --git a/src/GEOM_SWIG/GEOM_TestAll.py b/src/GEOM_SWIG/GEOM_TestAll.py index ea862293f..a500a67d4 100644 --- a/src/GEOM_SWIG/GEOM_TestAll.py +++ b/src/GEOM_SWIG/GEOM_TestAll.py @@ -590,5 +590,10 @@ def TestAll (geompy, math): geompy.GetSubShapesWithTolerance(Box, GEOM.FACE, GEOM.CC_LT, 2.e-7, "lt") geompy.GetSubShapesWithTolerance(Box, GEOM.FACE, GEOM.CC_LE, 1.e-7, "le") + # MakeExtraction + geompy.MakeExtraction(Box, [13], "Ext_no_face") + geompy.MakeExtraction(Box, [18], "Ext_no_edge") + geompy.MakeExtraction(Box, [16], "Ext_no_vertex") + print "DONE" diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index 379105b72..5b74cabdd 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -6661,6 +6661,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 swig_MakeExtraction "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/CMakeLists.txt b/src/OperationGUI/CMakeLists.txt index 2ff65aed2..7f949c31c 100755 --- a/src/OperationGUI/CMakeLists.txt +++ b/src/OperationGUI/CMakeLists.txt @@ -73,6 +73,7 @@ SET(OperationGUI_HEADERS OperationGUI_ChamferDlg.h OperationGUI_GetShapesOnShapeDlg.h OperationGUI_GetSharedShapesDlg.h + OperationGUI_ExtractionDlg.h OperationGUI_ExtrudedFeatureDlg.h OperationGUI_ClippingDlg.h OperationGUI_TransferDataDlg.h @@ -87,6 +88,7 @@ SET(_moc_HEADERS OperationGUI_ChamferDlg.h OperationGUI_GetShapesOnShapeDlg.h OperationGUI_GetSharedShapesDlg.h + OperationGUI_ExtractionDlg.h OperationGUI_ExtrudedFeatureDlg.h OperationGUI_ClippingDlg.h OperationGUI_TransferDataDlg.h @@ -109,6 +111,7 @@ SET(OperationGUI_SOURCES OperationGUI_FilletDlg.cxx OperationGUI_Fillet1d2dDlg.cxx OperationGUI_ChamferDlg.cxx + OperationGUI_ExtractionDlg.cxx OperationGUI_ExtrudedFeatureDlg.cxx OperationGUI_ClippingDlg.cxx OperationGUI_TransferDataDlg.cxx diff --git a/src/OperationGUI/OperationGUI.cxx b/src/OperationGUI/OperationGUI.cxx index 3288921ab..96e5fc57a 100644 --- a/src/OperationGUI/OperationGUI.cxx +++ b/src/OperationGUI/OperationGUI.cxx @@ -40,6 +40,7 @@ #include "OperationGUI_GetSharedShapesDlg.h" #include "OperationGUI_ExtrudedFeatureDlg.h" // Methods EXTRUDED BOSS / CUT #include "OperationGUI_TransferDataDlg.h" +#include "OperationGUI_ExtractionDlg.h" //======================================================================= // function : OperationGUI() @@ -83,6 +84,7 @@ bool OperationGUI::OnGUIEvent (int theCommandID, SUIT_Desktop* parent) case GEOMOp::OpFillet1d: (new OperationGUI_Fillet1d2dDlg (getGeometryGUI(), parent, true))->show(); break; case GEOMOp::OpFillet2d: (new OperationGUI_Fillet1d2dDlg (getGeometryGUI(), parent, false))->show(); break; case GEOMOp::OpTransferData: (new OperationGUI_TransferDataDlg (getGeometryGUI(), parent))->show(); break; + case GEOMOp::OpExtraction: (new OperationGUI_ExtractionDlg (getGeometryGUI(), parent))->show(); break; default: app->putInfo(tr("GEOM_PRP_COMMAND").arg(theCommandID)); } diff --git a/src/OperationGUI/OperationGUI_ExtractionDlg.cxx b/src/OperationGUI/OperationGUI_ExtractionDlg.cxx new file mode 100644 index 000000000..47f2e722b --- /dev/null +++ b/src/OperationGUI/OperationGUI_ExtractionDlg.cxx @@ -0,0 +1,1324 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "OperationGUI_ExtractionDlg.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if QT_VERSION >= 0x050300 + #include +#else + /** + * This class is named as QT class as it is introduced since Qt 5.3. + * It should not be compiled when Salome is ported on Qt 5.3. + */ + class QSignalBlocker + { + public: + QSignalBlocker(QObject *object) + : myObject (object), + myIsBlocked (object && object->signalsBlocked()) { + if (myObject) { + myObject->blockSignals(true); + } + } + + ~QSignalBlocker() { + if (myObject) { + myObject->blockSignals(myIsBlocked); + } + } + + private: + QObject *myObject; ///< Blocked object. + bool myIsBlocked; ///< Initial blocked state. + }; +#endif + + +#define ID_ROLE Qt::DisplayRole +#define TYPE_ROLE Qt::UserRole + +static const char* const TMP_STR = "TEMP"; + +static const char* const SINGLE_SHAPE_TYPE_TR_CODES [] = { + "GEOM_COMPOUND", + "GEOM_COMPOUNDSOLID", + "GEOM_SOLID", + "GEOM_SHELL", + "GEOM_FACE", + "GEOM_WIRE", + "GEOM_EDGE", + "GEOM_VERTEX" +}; + +static const char* const PLURAL_SHAPE_TYPE_TR_CODES [] = { + "GEOM_COMPOUND", // Not used + "GEOM_COMPSOLIDS", + "GEOM_SOLIDS", + "GEOM_SHELLS", + "GEOM_FACES", + "GEOM_WIREZ", + "GEOM_EDGES", + "GEOM_VERTEXES" +}; + + +/** + * This static function creates a new list widget item with given ID and + * returns it. + * + * \param theID the item ID. + * \param theListWidget the list widget. + * \return the created list widget item. + */ +static QListWidgetItem *addNewItem(const int theID, + QListWidget *theListWidget) +{ + QListWidgetItem *aResult = new QListWidgetItem; + + aResult->setData(ID_ROLE, theID); + theListWidget->addItem(aResult); + + return aResult; +} + +/** + * This static function creates a new tree widget item as a child of the input + * one with given ID and returns it. + * + * \param theID the item ID. + * \param theParentItem the parent item. + * \return the created tree widget item. + */ +static QTreeWidgetItem *addChildItem(const int theID, + QTreeWidgetItem *theParentItem) +{ + QTreeWidgetItem *aResult = new QTreeWidgetItem; + + aResult->setData(0, ID_ROLE, theID); + theParentItem->addChild(aResult); + + return aResult; +} + +/** + * This static function returns the maximal shape type of sub-shapes stored in + * the input compound. If it is not a compound, it returns TopAbs_SHAPE. + * + * \param theCompound the compound. + * \return the maximal shape type of sub-shapes stored in the input compound. + */ +static TopAbs_ShapeEnum GetMaxShapeTypeInComp(const TopoDS_Shape &theCompound) +{ + TopAbs_ShapeEnum aResult = TopAbs_SHAPE; + + if (theCompound.IsNull() || theCompound.ShapeType() != TopAbs_COMPOUND) { + return aResult; + } + + TopoDS_Iterator anIt(theCompound, Standard_False, Standard_False); + + for (; anIt.More(); anIt.Next()) { + const TopoDS_Shape &aSubShape = anIt.Value(); + + if (aSubShape.IsNull()) { + continue; + } + + // Get the sub-shape type. + TopAbs_ShapeEnum aSubType = aSubShape.ShapeType(); + + if (aSubType == TopAbs_COMPOUND) { + aSubType = GetMaxShapeTypeInComp(aSubShape); + } + + if (aSubType == TopAbs_SHAPE) { + continue; + } + + if (aResult == TopAbs_SHAPE) { + // This is an initialization. + aResult = aSubType; + } else if (aResult > aSubType) { + aResult = aSubType; + } + } + + return aResult; +} + +//================================================================================= +// class : OperationGUI_ExtractionDlg() +// purpose : +//================================================================================= +OperationGUI_ExtractionDlg::OperationGUI_ExtractionDlg + (GeometryGUI* GUI, QWidget* parent) + : GEOMBase_Skeleton (GUI, parent, false), + mySelBtn (0), + myMainShapeEdit (0), + mySubShTypeCompo (0), + myFilteredList (0), + myExtractedTree (0), + myRemovedList (0), + myModifiedList (0), + myAddedList (0), + myRebuildBtn (0), + myIsHiddenMain (false) +{ + QPixmap image0(SUIT_Session::session()->resourceMgr()->loadPixmap( + "GEOM", tr("ICON_DLG_EXTRACTION"))); + QPixmap image1(SUIT_Session::session()->resourceMgr()->loadPixmap( + "GEOM", tr("ICON_SELECT"))); + + setWindowTitle(tr("GEOM_EXTRACT_TITLE")); + + /***************************************************************/ + + mainFrame()->GroupConstructors->setTitle(tr("GEOM_EXTRACT_TYPE")); + mainFrame()->RadioButton1->setIcon( image0 ); + mainFrame()->RadioButton2->setAttribute(Qt::WA_DeleteOnClose); + mainFrame()->RadioButton2->close(); + mainFrame()->RadioButton3->setAttribute(Qt::WA_DeleteOnClose); + mainFrame()->RadioButton3->close(); + + // Create an input group. + QGroupBox *anInputGrp = new QGroupBox(tr("GEOM_EXTRACT_INPUT_PARAMS"), centralWidget()); + QGridLayout *anInputLayout = new QGridLayout(anInputGrp); + QHBoxLayout *aShapeLayout = new QHBoxLayout(anInputGrp); + QVBoxLayout *aViewBtnsLayout = new QVBoxLayout(anInputGrp); + QVBoxLayout *aMoveBtnsLayout = new QVBoxLayout(anInputGrp); + QLabel *aMainObjLbl = new QLabel(tr("GEOM_MAIN_OBJECT"), anInputGrp); + QLabel *aSubShTypeLbl = new QLabel(tr("GEOM_EXTRACT_SUB_SHAPE_TYPE"), anInputGrp); + QLabel *aFilteredLbl = new QLabel(tr("GEOM_EXTRACT_FILTERED_SHAPES"), anInputGrp); + QLabel *anExtractedLbl = new QLabel(tr("GEOM_EXTRACT_SHAPES_TO_EXTRACT"), anInputGrp); + QPushButton *aShowOnlySelBtn = new QPushButton(tr("SHOW_ONLY_SELECTED"), anInputGrp); + QPushButton *aHideSelBtn = new QPushButton(tr("HIDE_SELECTED"), anInputGrp); + QPushButton *aShowAllBtn = new QPushButton(tr("SHOW_ALL_SUB_SHAPES"), anInputGrp); + QPushButton *anAddBtn = new QPushButton(">>", anInputGrp); + QPushButton *aRemoveBtn = new QPushButton("<<", anInputGrp); + + myRebuildBtn = new QPushButton(tr("GEOM_EXTRACT_REBUILD"), anInputGrp); + mySelBtn = new QPushButton(anInputGrp); + myMainShapeEdit = new QLineEdit(anInputGrp); + mySubShTypeCompo = new QComboBox(anInputGrp); + myFilteredList = new QListWidget(anInputGrp); + myExtractedTree = new QTreeWidget(anInputGrp); + mySelBtn->setIcon(image1); + myMainShapeEdit->setReadOnly(true); + + aShapeLayout->addWidget(mySelBtn); + aShapeLayout->addWidget(myMainShapeEdit); + + aViewBtnsLayout->addStretch(); + aViewBtnsLayout->addWidget(aShowOnlySelBtn); + aViewBtnsLayout->addWidget(aHideSelBtn); + aViewBtnsLayout->addWidget(aShowAllBtn); + aViewBtnsLayout->addStretch(); + + aMoveBtnsLayout->addStretch(); + aMoveBtnsLayout->addWidget(anAddBtn); + aMoveBtnsLayout->addWidget(aRemoveBtn); + aMoveBtnsLayout->addStretch(); + + anInputLayout->setSpacing(6); + anInputLayout->setContentsMargins(9, 9, 9, 9); + anInputLayout->addWidget(aMainObjLbl, 0, 0); + anInputLayout->addLayout(aShapeLayout, 0, 1, 1, 3); + anInputLayout->addWidget(aSubShTypeLbl, 1, 0); + anInputLayout->addWidget(mySubShTypeCompo, 1, 1, 1, 3); + anInputLayout->addWidget(aFilteredLbl, 2, 1); + anInputLayout->addWidget(anExtractedLbl, 2, 3); + anInputLayout->addLayout(aViewBtnsLayout, 3, 0); + anInputLayout->addWidget(myFilteredList, 3, 1); + anInputLayout->addLayout(aMoveBtnsLayout, 3, 2); + anInputLayout->addWidget(myExtractedTree, 3, 3); + anInputLayout->addWidget(myRebuildBtn, 4, 0, 1, 4); + + // Create a statistics group. + QGroupBox *aStatGrp = new QGroupBox(tr("GEOM_EXTRACT_STATISTICS"), centralWidget()); + QGridLayout *aStatLayout = new QGridLayout(aStatGrp); + QLabel *aRemovedLbl = new QLabel(tr("GEOM_EXTRACT_REMOVED"), aStatGrp); + QLabel *aModifiedLbl = new QLabel(tr("GEOM_EXTRACT_MODIFIED"), aStatGrp); + QLabel *anAddedLbl = new QLabel(tr("GEOM_EXTRACT_ADDED"), aStatGrp); + + myRemovedList = new QListWidget(aStatGrp); + myModifiedList = new QListWidget(aStatGrp); + myAddedList = new QListWidget(aStatGrp); + + aStatLayout->setSpacing(6); + aStatLayout->setContentsMargins(9, 9, 9, 9); + aStatLayout->addWidget(aRemovedLbl, 0, 0); + aStatLayout->addWidget(aModifiedLbl, 0, 1); + aStatLayout->addWidget(anAddedLbl, 0, 2); + aStatLayout->addWidget(myRemovedList, 1, 0); + aStatLayout->addWidget(myModifiedList, 1, 1); + aStatLayout->addWidget(myAddedList, 1, 2); + + // Create a main layout. + QVBoxLayout* aLayout = new QVBoxLayout(centralWidget()); + + aLayout->setMargin(0); + aLayout->setSpacing(6); + aLayout->addWidget(anInputGrp); + aLayout->addWidget(aStatGrp); + + // signals and slots connections + connect(anAddBtn, SIGNAL(clicked()), this, SLOT(onAddExtracted())); + connect(aRemoveBtn, SIGNAL(clicked()), this, SLOT(onRemoveExtracted())); + connect(aShowOnlySelBtn, SIGNAL(clicked()), this, SLOT(showOnlySelected())); + connect(aHideSelBtn, SIGNAL(clicked()), this, SLOT(hideSelected())); + connect(aShowAllBtn, SIGNAL(clicked()), this, SLOT(showAllSelected())); + + /***************************************************************/ + myHelpFileName = "extract_and_rebuild_page.html"; + + resize(525, 600); + + /* Initialisation */ + Init(); +} + +//================================================================================= +// function : ~OperationGUI_ExtractionDlg() +// purpose : Destroys the object and frees any allocated resources +//================================================================================= +OperationGUI_ExtractionDlg::~OperationGUI_ExtractionDlg() +{ + restoreViewer(); +} + +//================================================================================= +// function : Init() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::Init() +{ + mySelBtn->setCheckable(true); + mySelBtn->setChecked(true); + myFilteredList->setSelectionMode(QAbstractItemView::ExtendedSelection); + myFilteredList->setSortingEnabled(true); + myExtractedTree->setHeaderHidden(true); + myExtractedTree->setSelectionMode(QAbstractItemView::ExtendedSelection); + myExtractedTree->setColumnCount(1); + myRebuildBtn->setEnabled(false); + myRemovedList->setSelectionMode(QAbstractItemView::NoSelection); + myModifiedList->setSelectionMode(QAbstractItemView::NoSelection); + myAddedList->setSelectionMode(QAbstractItemView::NoSelection); + + // Fill in the extracted tree with initial elements. + myTopItems[0] = 0; // No need to create a item for compound. + + int i; + + for (i = 1; i < 8; i++) { + myTopItems[i] = new QTreeWidgetItem; + myTopItems[i]->setText(0, tr(PLURAL_SHAPE_TYPE_TR_CODES[i])); + myTopItems[i]->setData(0, TYPE_ROLE, i); + + myExtractedTree->addTopLevelItem(myTopItems[i]); + myTopItems[i]->setHidden(true); + } + + // signals and slots connections + connect(mySelBtn, SIGNAL(clicked()), this, SLOT(SetEditCurrentArgument())); + connect(buttonOk(), SIGNAL(clicked()), this, SLOT(ClickOnOk())); + connect(buttonApply(), SIGNAL(clicked()), this, SLOT(ClickOnApply())); + connect(mySubShTypeCompo, SIGNAL(currentIndexChanged(int)), + this, SLOT(onShapeTypeChanged())); + connect(myRebuildBtn, SIGNAL(clicked()), this, SLOT(onRebuild())); + connect(myGeomGUI->getApp()->selectionMgr(), SIGNAL(currentSelectionChanged()), + this, SLOT(SelectionIntoArgument())); + connect(myFilteredList, SIGNAL(itemSelectionChanged()), + this, SLOT(onListSelectionChanged())); + connect(myExtractedTree, SIGNAL(itemSelectionChanged()), + this, SLOT(onListSelectionChanged())); + + initName(tr("GEOM_EXTRACT_NAME")); + + activateSelection(); + SelectionIntoArgument(); +} + +//================================================================================= +// function : updateSubShTypeCompo() +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::updateSubShTypeCompo() +{ + bool isValid = true; + int anIStart = TopAbs_COMPOUND; + const int anIEnd = TopAbs_VERTEX; + TopoDS_Shape aShape; + + if (GEOMBase::GetShape(myObj, aShape)) { + const TopAbs_ShapeEnum aType = aShape.ShapeType(); + + if (aType == TopAbs_COMPOUND) { + anIStart = GetMaxShapeTypeInComp(aShape); + isValid = anIStart != TopAbs_SHAPE; + } else { + anIStart = aType + 1; + } + } + + QSignalBlocker aBlocker(mySubShTypeCompo); + mySubShTypeCompo->clear(); + + if (isValid) { + int i; + + for (i = anIStart; i <= anIEnd; i++) { + mySubShTypeCompo->addItem(tr(SINGLE_SHAPE_TYPE_TR_CODES[i]), i); + } + + updateFilteredList(); + } + + return isValid; +} + +//================================================================================= +// function : updateFilteredList() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::updateFilteredList() +{ + TopoDS_Shape aShape; + QSignalBlocker aBlocker(myFilteredList); + + myFilteredList->clear(); + + if (GEOMBase::GetShape(myObj, aShape)) { + const TopAbs_ShapeEnum aType = (TopAbs_ShapeEnum) + mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt(); + TopExp_Explorer anExp(aShape, aType); + + if (anExp.More()) { + TopTools_MapOfShape aMapFence; + + for (; anExp.More(); anExp.Next()) { + const TopoDS_Shape &aSubShape = anExp.Current(); + + if (!aSubShape.IsNull() && aMapFence.Add(aSubShape)) { + int anIndex = myIndices.FindIndex(aSubShape); + + if (!myMapExtractedIDs.Contains(anIndex)) { + addNewItem(anIndex, myFilteredList); + } + } + } + } + } +} + +//================================================================================= +// function : resetBuildData() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::resetBuildData(const bool isEnableBuild) +{ + // Clear result data. + myRemovedList->clear(); + myModifiedList->clear(); + myAddedList->clear(); + myRebuildBtn->setEnabled(isEnableBuild); +} + +//================================================================================= +// function : isEmptyExtracted() +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::isEmptyExtracted() +{ + bool isEmpty = true; + int i; + + // Check if there are sub-shapes to be extracted. + for (i = 1; i < 8; i++) { + if (!myTopItems[i]->isHidden()) { + isEmpty = false; + + break; + } + } + + return isEmpty; +} + +//================================================================================= +// function : selectMainShape +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::selectMainShape() +{ + LightApp_SelectionMgr *aSelMgr = myGeomGUI->getApp()->selectionMgr(); + SALOME_ListIO aSelList; + + aSelMgr->selectedObjects(aSelList); + + if (aSelList.Extent() == 1) { + GEOM::GEOM_Object_var aSelObject = + GEOMBase::ConvertIOinGEOMObject(aSelList.First()); + TopoDS_Shape aSelShape; + + if (GEOMBase::GetShape(aSelObject, aSelShape)) { + const TopAbs_ShapeEnum aType = aSelShape.ShapeType(); + + // Skip verices. + if (aType != TopAbs_VERTEX) { + myObj = aSelObject; + + // Initialize map of indices. Note that myIndices should be empty. + TopExp::MapShapes(aSelShape, myIndices); + } + } + } + + if (!updateSubShTypeCompo()) { + // Invalid selected object. + myObj = GEOM::GEOM_Object::_nil(); + } + + if (!CORBA::is_nil(myObj)) { + mySelBtn->setChecked(false); + myMainShapeEdit->setEnabled(false); + myMainShapeEdit->setText(GEOMBase::GetName(myObj)); + + // Hide the main object from the viewer. + SALOME_View* aView = GEOM_Displayer::GetActiveView(); + + if (aView) { + CORBA::String_var aMainEntry = myObj->GetStudyEntry(); + Handle(SALOME_InteractiveObject) anIO = createIO(aMainEntry.in()); + + if (aView->isVisible(anIO)) { + GEOM_Displayer *aDisplayer = getDisplayer(); + + aDisplayer->Erase(myObj, false, true); + myIsHiddenMain = true; + } + } + } +} + +//================================================================================= +// function : selectSubShapes +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::selectSubShapes() +{ + QSignalBlocker aBlocker(myFilteredList); + + // Clear current selection. + myFilteredList->clearSelection(); + + LightApp_SelectionMgr *aSelMgr = myGeomGUI->getApp()->selectionMgr(); + SALOME_ListIO aSelList; + const int aCurType = + mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt(); + + aSelMgr->selectedObjects(aSelList); + + // try to find out and process the global selection + // (of not published objects and of published sub-shapes) + SALOME_ListIteratorOfListIO anIter(aSelList); + + for (; anIter.More(); anIter.Next()) { + Handle(SALOME_InteractiveObject) anIObj = anIter.Value(); + QString anEntry = anIObj->getEntry(); + QStringList aParts = anEntry.split("_"); + int aSubShapeId = -1; + + if (!aParts.isEmpty()) { + if (aParts.first() == TMP_STR) { + bool isOk = false; + const int anIndex = aParts.last().toInt(&isOk); + + if (isOk && anIndex > 0) { + // This is a sub-shape. + aSubShapeId = anIndex; + } + } + } + + if (aSubShapeId < 0) { + // This is a published shape. + GEOM::GEOM_Object_var aSelObject = + GEOMBase::ConvertIOinGEOMObject(anIObj); + TopoDS_Shape aSelShape; + + if (GEOMBase::GetShape(aSelObject, aSelShape)) { + + if (aSelShape.ShapeType() == aCurType) { + const int anIndex = myIndices.FindIndex(aSelShape); + + if (anIndex > 0) { + // This is a sub-shape. Select it in the filtered list. + aSubShapeId = anIndex; + } + } + } + } + + // Select a list widget item by Id. + if (aSubShapeId > 0) { + QString anIdText = QString("%1").arg(aSubShapeId); + QList aFound = + myFilteredList->findItems(anIdText, Qt::MatchExactly); + + foreach (QListWidgetItem *anItem, aFound) { + anItem->setSelected(true); + } + } + } +} + +//================================================================================= +// function : ClickOnOk() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::ClickOnOk() +{ + if (ClickOnApply()) { + ClickOnCancel(); + } +} + +//================================================================================= +// function : ClickOnApply() +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::ClickOnApply() +{ + if (!onAccept()) { + return false; + } + + initName(); + + return true; +} + +//================================================================================= +// function : onShapeTypeChanged +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::onShapeTypeChanged() +{ + updateFilteredList(); + eraseAll(); +} + +//================================================================================= +// function : onAddExtracted +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::onAddExtracted() +{ + QList aListSelected = myFilteredList->selectedItems(); + + if (aListSelected.empty()) { + return; + } + + const int aShapeType = + mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt(); + bool isTreeUpdated = false; + + foreach (QListWidgetItem *anItem, aListSelected) { + const int anIndex = anItem->data(ID_ROLE).toInt(); + + if (myMapExtractedIDs.Add(anIndex)) { + addChildItem(anIndex, myTopItems[aShapeType]); + isTreeUpdated = true; + } + + // Remove anItem from the list. + myFilteredList->removeItemWidget(anItem); + delete anItem; + } + + if (isTreeUpdated) { + myTopItems[aShapeType]->sortChildren(0, Qt::AscendingOrder); + + // Reset build data + resetBuildData(true); + } + + myFilteredList->clearSelection(); + myTopItems[aShapeType]->setHidden(false); +} + +//================================================================================= +// function : onRemoveExtracted +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::onRemoveExtracted() +{ + QList aListSelected = myExtractedTree->selectedItems(); + + if (aListSelected.empty()) { + return; + } + + const int aShapeType = + mySubShTypeCompo->itemData(mySubShTypeCompo->currentIndex()).toInt(); + QSet aSetFence; + bool isTreeUpdated = false; + + foreach (QTreeWidgetItem *anItem, aListSelected) { + if (!aSetFence.contains(anItem)) { + aSetFence.insert(anItem); + + QTreeWidgetItem *aParent = anItem->parent(); + + if (aParent) { + const int anIndex = anItem->data(0, ID_ROLE).toInt(); + // This is a ID item. Remove the ID from myMapExtractedIDs. + if (myMapExtractedIDs.Remove(anIndex)) { + // The item is not removed yet. Get parent index. + const int aParentIndex = aParent->data(0, TYPE_ROLE).toInt(); + + if (aShapeType == aParentIndex) { + // Create an item in the filtered list. + addNewItem(anIndex, myFilteredList); + } + + aParent->removeChild(anItem); + delete anItem; + isTreeUpdated = true; + + // Hilde an empty parent item. + if (aParent->childCount() == 0) { + aParent->setHidden(true); + } + } + } else { + // This is a top level item. Remove all its children. + QList aChildItems = anItem->takeChildren(); + const int anIndex = anItem->data(0, TYPE_ROLE).toInt(); + + // Remove IDs from myMapExtractedIDs. + foreach (QTreeWidgetItem *aChild, aChildItems) { + if (!aSetFence.contains(aChild)) { + aSetFence.insert(aChild); + + const int aChildIndex = aChild->data(0, ID_ROLE).toInt(); + + if (myMapExtractedIDs.Remove(aChildIndex)) { + if (aShapeType == anIndex) { + // Create items in the filtered list. + addNewItem(aChildIndex, myFilteredList); + } + + delete aChild; + isTreeUpdated = true; + } + } + } + + // Hilde an empty item. + anItem->setHidden(true); + } + } + } + + myExtractedTree->clearSelection(); + + if (isTreeUpdated) { + // Reset build data + const bool isEnableRebuild = !isEmptyExtracted(); + + resetBuildData(isEnableRebuild); + } +} + +//================================================================================= +// function : onListSelectionChanged +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::onListSelectionChanged() +{ + SALOME_ListIO anIOList; + QList aListSel = myFilteredList->selectedItems(); + QList aTreeSel = myExtractedTree->selectedItems(); + + // Collect selected items from myFilteredList + foreach (QListWidgetItem *anItem, aListSel) { + const int anIndex = anItem->data(ID_ROLE).toInt(); + + if (myMapDisplayedIDs.Contains(anIndex)) { + // Collect only displayed sub-shapes for selection in the viewer. + QString anEntry = getSubShapeEntry(anIndex); + Handle(SALOME_InteractiveObject) anIO = + createIO(anEntry.toLatin1().data()); + + anIOList.Append(anIO); + } + } + + // Collect selected items from myExtractedTree + foreach (QTreeWidgetItem *anItem, aTreeSel) { + if (anItem->parent()) { + // This is a ID item. + const int anIndex = anItem->data(0, ID_ROLE).toInt(); + + if (myMapDisplayedIDs.Contains(anIndex)) { + // Collect only displayed sub-shapes for selection in the viewer. + QString anEntry = getSubShapeEntry(anIndex); + Handle(SALOME_InteractiveObject) anIO = + createIO(anEntry.toLatin1().data()); + + anIOList.Append(anIO); + } + } + } + + // Select object in viewer. + LightApp_SelectionMgr *aSelMgr = myGeomGUI->getApp()->selectionMgr(); + + aSelMgr->setSelectedObjects(anIOList); +} + +//================================================================================= +// function : showOnlySelected +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::showOnlySelected() +{ + TColStd_MapOfInteger aMapIDsSelected; + TColStd_MapOfInteger aMapIDsToDisplay; + const int aNbItems = myFilteredList->count(); + int i; + QSet aSelEntry; + + // Get sub-shape IDs to be displayed. + for (i = 0; i < aNbItems; ++i) { + QListWidgetItem *anItem = myFilteredList->item(i); + const int anIndex = anItem->data(ID_ROLE).toInt(); + + if (anItem->isSelected()) { + aMapIDsSelected.Add(anIndex); + aSelEntry.insert(getSubShapeEntry(anIndex)); + + if (!myMapDisplayedIDs.Contains(anIndex)) { + aMapIDsToDisplay.Add(anIndex); + } + } + } + + // Get sub-shape IDs to be erased. + TColStd_MapOfInteger aMapIDsToHide; + TColStd_MapIteratorOfMapOfInteger anIter(myMapDisplayedIDs); + + for (; anIter.More(); anIter.Next()) { + const int anIndex = anIter.Key(); + + if (!aMapIDsSelected.Contains(anIndex)) { + aMapIDsToHide.Add(anIndex); + } + } + + // Display sub-shapes. + for (anIter.Initialize(aMapIDsToDisplay); anIter.More(); anIter.Next()) { + displaySubShape(anIter.Key()); + } + + // Hide sub-shapes. + for (anIter.Initialize(aMapIDsToHide); anIter.More(); anIter.Next()) { + eraseSubShape(anIter.Key()); + } + + // Hide all objects except already displayed sub-shapes. + SALOME_ListIO aDisplayed; + SALOME_View *aView = GEOM_Displayer::GetActiveView(); + + if (aView) { + aView->GetVisible(aDisplayed); + } + + SALOME_ListIteratorOfListIO aDispIt(aDisplayed); + GEOM_Displayer *aDisplayer = getDisplayer(); + + for (; aDispIt.More(); aDispIt.Next()) { + Handle(SALOME_InteractiveObject) anIO = aDispIt.Value(); + + if (!aSelEntry.contains(anIO->getEntry())) { + aDisplayer->Erase(anIO, false, false); + } + } + + onListSelectionChanged(); + aDisplayer->UpdateViewer(); +} + +//================================================================================= +// function : hideSelected +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::hideSelected() +{ + QList aListSelected = myFilteredList->selectedItems(); + + foreach (QListWidgetItem *anItem, aListSelected) { + const int anIndex = anItem->data(ID_ROLE).toInt(); + + eraseSubShape(anIndex); + } + + getDisplayer()->UpdateViewer(); +} + +//================================================================================= +// function : showAllSelected +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::showAllSelected() +{ + const int aNbItems = myFilteredList->count(); + int i; + + for (i = 0; i < aNbItems; ++i) { + QListWidgetItem *anItem = myFilteredList->item(i); + const int anIndex = anItem->data(ID_ROLE).toInt(); + + displaySubShape(anIndex); + } + + onListSelectionChanged(); + getDisplayer()->UpdateViewer(); +} + +//================================================================================= +// function : onRebuild +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::onRebuild() +{ + GEOM::GEOM_Object_var aResShape; + GEOM::GEOM_IShapesOperations::ExtractionStats aStats; + + if (!getResult(aResShape.out(), aStats)) { + resetBuildData(false); + return; + } + + TopoDS_Shape anOldShape; + TopoDS_Shape aNewShape; + TopTools_IndexedMapOfShape aNewIndices; + + if (!GEOMBase::GetShape(aResShape, aNewShape)) { + resetBuildData(false); + return; + } + + TopExp::MapShapes(aNewShape, aNewIndices); + + const int aNbStat = aStats.length(); + int i; + + for (i = 0; i < aNbStat; ++i) { + // Compute number of sub-shapes of each type. + const int aNbSubShapes = aStats[i].indices.length(); + int aNbShapes [] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int j; + + TopTools_IndexedMapOfShape *aMapShapes = + (aStats[i].type == GEOM::GEOM_IShapesOperations::EST_Added) ? + &aNewIndices : &myIndices; + + for (j = 0; j < aNbSubShapes; ++j) { + const int anIndex = aStats[i].indices[j]; + + if (anIndex < 1 || anIndex > aMapShapes->Extent()) { + resetBuildData(false); + return; + } + + const TopoDS_Shape &aSubShape = aMapShapes->FindKey(anIndex); + + aNbShapes[aSubShape.ShapeType()]++; + } + + // Fill the statistics. + QListWidget *aListWidget = 0; + + switch (aStats[i].type) { + case GEOM::GEOM_IShapesOperations::EST_Removed: + aListWidget = myRemovedList; + break; + case GEOM::GEOM_IShapesOperations::EST_Modified: + aListWidget = myModifiedList; + break; + case GEOM::GEOM_IShapesOperations::EST_Added: + aListWidget = myAddedList; + break; + default: + resetBuildData(false); + return; + } + + QStringList aStrList; + + 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]; + + aStrList.append(QString("%1 %2").arg(aNbShapes[j]).arg(tr(aShapeType))); + } + } + + aListWidget->addItems(aStrList); + } + + myRebuildBtn->setEnabled(false); +} + +//================================================================================= +// function : SelectionIntoArgument +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::SelectionIntoArgument() +{ + if (myMainShapeEdit->isEnabled()) { + // Selection of main object + selectMainShape(); + } else { + // Selection of filtered shapes + selectSubShapes(); + } +} + +//================================================================================= +// function : SetEditCurrentArgument +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::SetEditCurrentArgument() +{ + QSignalBlocker aBlockerList(myFilteredList); + QSignalBlocker aBlockerTree(myExtractedTree); + + restoreViewer(); + myObj = GEOM::GEOM_Object::_nil(); + myMainShapeEdit->setEnabled(true); + myMainShapeEdit->setText(""); + myMainShapeEdit->setFocus(); + + updateSubShTypeCompo(); + + myFilteredList->clear(); + myRemovedList->clear(); + myModifiedList->clear(); + myAddedList->clear(); + myIndices.Clear(); + + // Clear myExtractedTree. + int i; + + for (i = 1; i < 8; i++) { + QList aListItems = myTopItems[i]->takeChildren(); + + foreach (QTreeWidgetItem *anItem, aListItems) { + delete anItem; + } + + myTopItems[i]->setHidden(true); + } + + myExtractedTree->clearSelection(); + + myMapExtractedIDs.Clear(); + + // Update viewer + eraseAll(); +} + +//================================================================================= +// function : ActivateThisDialog() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::ActivateThisDialog() +{ + GEOMBase_Skeleton::ActivateThisDialog(); + + LightApp_SelectionMgr* aSel = myGeomGUI->getApp()->selectionMgr(); + + if (aSel) { + connect(aSel, SIGNAL(currentSelectionChanged()), + this, SLOT(SelectionIntoArgument())); + } + + activateSelection(); +} + +//================================================================================= +// function : activateSelection +// purpose : activate selection of all shapes +//================================================================================= +void OperationGUI_ExtractionDlg::activateSelection() +{ + globalSelection(GEOM_ALLSHAPES); +} + +//================================================================================= +// function : enterEvent() +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::enterEvent(QEvent *) +{ + if (!mainFrame()->GroupConstructors->isEnabled()) { + ActivateThisDialog(); + } +} + +//================================================================================= +// function : getResult +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::getResult + (GEOM::GEOM_Object_ptr &theResult, + GEOM::GEOM_IShapesOperations::ExtractionStats &theStats) +{ + if (myObj->_is_nil()) { + return false; + } + + // Get IDs of extracted shapes. + int i; + int aNbShapes = 0; + + for (i = 1; i < 8; i++) { + aNbShapes += myTopItems[i]->childCount(); + } + + if (aNbShapes == 0) { + return false; + } + + GEOM::ListOfLong_var aSubShapeIDs = new GEOM::ListOfLong; + int j; + int jCur; + + aSubShapeIDs->length(aNbShapes); + + for (jCur = 0, i = 1; i < 8; ++i) { + aNbShapes = myTopItems[i]->childCount(); + + for (j = 0; j < aNbShapes; ++j, ++jCur) { + aSubShapeIDs[jCur] = myTopItems[i]->child(j)->data(0, ID_ROLE).toInt(); + } + } + + GEOM::GEOM_IShapesOperations_var anOper = + GEOM::GEOM_IShapesOperations::_narrow(getOperation()); + + try { + GEOM::GEOM_Object_var anObj; + GEOM::GEOM_IShapesOperations::ExtractionStats_var aStats; + + anObj = anOper->MakeExtraction(myObj, aSubShapeIDs, aStats); + + if (anOper->IsDone() && aStats->length() > 0) { + theStats = aStats; + } + + if (!CORBA::is_nil(anObj)) { + theResult = anObj._retn(); + } + } + catch (const SALOME::SALOME_Exception& e) { + SalomeApp_Tools::QtCatchCorbaException(e); + return false; + } + + return anOper->IsDone(); +} + +//================================================================================= +// function : isValid +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::isValid(QString &) +{ + bool isOk = !myObj->_is_nil() && !isEmptyExtracted(); + + return isOk; +} + +//================================================================================= +// function : createOperation +// purpose : +//================================================================================= +GEOM::GEOM_IOperations_ptr OperationGUI_ExtractionDlg::createOperation() +{ + return getGeomEngine()->GetIShapesOperations(getStudyId()); +} + +//================================================================================= +// function : execute +// purpose : +//================================================================================= +bool OperationGUI_ExtractionDlg::execute(ObjectList &objects) +{ + GEOM::GEOM_Object_var aResShape; + GEOM::GEOM_IShapesOperations::ExtractionStats aStats; + + if (!getResult(aResShape.out(), aStats)) { + return false; + } + + if (!aResShape->_is_nil()) { + objects.push_back(aResShape._retn()); + } + + return true; +} + +//================================================================================= +// function : getSubShapeEntry +// purpose : +//================================================================================= +QString OperationGUI_ExtractionDlg::getSubShapeEntry(const int theId) +{ + CORBA::String_var aMainEntry = myObj->GetStudyEntry(); + QString anEntry = QString("%1_").arg(TMP_STR) + + aMainEntry.in() + QString("_%1").arg(theId); + + return anEntry; +} + +//================================================================================= +// function : createIO +// purpose : +//================================================================================= +Handle_SALOME_InteractiveObject OperationGUI_ExtractionDlg::createIO + (const char *theEntry) +{ + Handle(SALOME_InteractiveObject) anIO = new SALOME_InteractiveObject + (theEntry, "GEOM", "TEMP_IO"); + + return anIO; +} + +//================================================================================= +// function : displaySubShape +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::displaySubShape(const int theId) +{ + if (theId < 1 || theId > myIndices.Extent()) { + return; + } + + // Create a presentation + const TopoDS_Shape &aSubShape = myIndices.FindKey(theId); + QString anEntry = getSubShapeEntry(theId); + SALOME_View *aView = GEOM_Displayer::GetActiveView(); + GEOM_Displayer *aDisplayer = getDisplayer(); + SALOME_Prs *aPrs = aDisplayer->buildSubshapePresentation + (aSubShape, anEntry, aView); + + if (aPrs) { + if (aView) { + aView->Display(aDisplayer, aPrs); + } + + delete aPrs; + + myMapDisplayedIDs.Add(theId); + } +} + +//================================================================================= +// function : eraseSubShape +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::eraseSubShape(const int theId) +{ + QString anEntry = getSubShapeEntry(theId); + Handle(SALOME_InteractiveObject) anIO = + createIO(anEntry.toLatin1().data()); + + getDisplayer()->Erase(anIO, false, false); + myMapDisplayedIDs.Remove(theId); +} + +//================================================================================= +// function : eraseAll +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::eraseAll() +{ + TColStd_MapIteratorOfMapOfInteger anIter(myMapDisplayedIDs); + + for (; anIter.More(); anIter.Next()) { + eraseSubShape(anIter.Key()); + } + + myMapDisplayedIDs.Clear(); + getDisplayer()->UpdateViewer(); +} + +//================================================================================= +// function : restoreViewer +// purpose : +//================================================================================= +void OperationGUI_ExtractionDlg::restoreViewer() +{ + if (!CORBA::is_nil(myObj)) { + if (myIsHiddenMain) { + getDisplayer()->Display(myObj, false); + myIsHiddenMain = false; + } + + eraseAll(); + } +} diff --git a/src/OperationGUI/OperationGUI_ExtractionDlg.h b/src/OperationGUI/OperationGUI_ExtractionDlg.h new file mode 100644 index 000000000..f10592aa5 --- /dev/null +++ b/src/OperationGUI/OperationGUI_ExtractionDlg.h @@ -0,0 +1,115 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OPERATIONGUI_EXTRACTIONDLG_H +#define OPERATIONGUI_EXTRACTIONDLG_H + +#include + +#include +#include + +class QComboBox; +class QListWidget; +class QTreeWidget; +class QTreeWidgetItem; + + +//================================================================================= +// class : OperationGUI_ExtractionDlg +// purpose : +//================================================================================= +class OperationGUI_ExtractionDlg : public GEOMBase_Skeleton +{ + + Q_OBJECT + +public: + + OperationGUI_ExtractionDlg( GeometryGUI*, QWidget* ); + ~OperationGUI_ExtractionDlg(); + +protected: + + // redefined from GEOMBase_Helper and MeasureGUI_Skeleton + virtual GEOM::GEOM_IOperations_ptr createOperation(); + virtual bool execute(ObjectList &); + virtual void activateSelection(); + virtual bool isValid( QString& ); + +private slots: + + void SelectionIntoArgument(); + void ClickOnOk(); + bool ClickOnApply(); + void onShapeTypeChanged(); + void onAddExtracted(); + void onRemoveExtracted(); + void onListSelectionChanged(); + void showOnlySelected(); + void hideSelected(); + void showAllSelected(); + void onRebuild(); + void ActivateThisDialog(); + void SetEditCurrentArgument(); + +private: + + void Init(); + bool updateSubShTypeCompo(); + void updateFilteredList(); + void resetBuildData(const bool isEnableBuild); + bool isEmptyExtracted(); + void selectMainShape(); + void selectSubShapes(); + void enterEvent(QEvent *); + bool getResult + (GEOM::GEOM_Object_ptr &theResult, + GEOM::GEOM_IShapesOperations::ExtractionStats &theStats); + QString getSubShapeEntry(const int theId); + Handle_SALOME_InteractiveObject createIO(const char *theEntry); + void displaySubShape(const int theId); + void eraseSubShape(const int theId); + void eraseAll(); + void restoreViewer(); + +private: + + GEOM::GEOM_Object_var myObj; + QPushButton *mySelBtn; + QLineEdit *myMainShapeEdit; + QComboBox *mySubShTypeCompo; + QListWidget *myFilteredList; + QTreeWidget *myExtractedTree; + QListWidget *myRemovedList; + QListWidget *myModifiedList; + QListWidget *myAddedList; + QTreeWidgetItem *myTopItems[8]; + QPushButton *myRebuildBtn; + TColStd_MapOfInteger myMapExtractedIDs; + bool myIsHiddenMain; + TColStd_MapOfInteger myMapDisplayedIDs; + TopTools_IndexedMapOfShape myIndices; + +}; + +#endif // OPERATIONGUI_EXTRACTIONDLG_H