]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Implement filter "F7: Opposite to an edge"
authorazv <azv@opencascade.com>
Fri, 28 Jun 2019 09:48:40 +0000 (12:48 +0300)
committerazv <azv@opencascade.com>
Fri, 28 Jun 2019 09:48:40 +0000 (12:48 +0300)
src/FiltersPlugin/CMakeLists.txt
src/FiltersPlugin/FiltersPlugin_OppositeToEdge.cpp [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_OppositeToEdge.h [new file with mode: 0644]
src/FiltersPlugin/FiltersPlugin_Plugin.cpp
src/FiltersPlugin/Test/TestFilter_OppositeToEdge.py [new file with mode: 0644]

index 8f6941ee711cba046f97f7a7bc57e8993ad8e95f..121dc0ff3e33c69451268508954cf71b3cc859fa 100644 (file)
@@ -31,6 +31,7 @@ SET(PROJECT_HEADERS
     FiltersPlugin_OnLine.h
     FiltersPlugin_OnGeometry.h
     FiltersPlugin_OnPlaneSide.h
+    FiltersPlugin_OppositeToEdge.h
 )
 
 SET(PROJECT_SOURCES
@@ -43,6 +44,7 @@ SET(PROJECT_SOURCES
     FiltersPlugin_OnLine.cpp
     FiltersPlugin_OnGeometry.cpp
     FiltersPlugin_OnPlaneSide.cpp
+    FiltersPlugin_OppositeToEdge.cpp
 )
 
 SET(PROJECT_LIBRARIES
@@ -81,6 +83,7 @@ ADD_UNIT_TESTS(
   TestFilter_OnGeometry_Face.py
   TestFilter_OnPlaneSide_Face.py
   TestFilter_OnPlaneSide_Plane.py
+  TestFilter_OppositeToEdge.py
   TestFilter_HorizontalFaces.py
   TestFilter_VerticalFaces.py
 )
diff --git a/src/FiltersPlugin/FiltersPlugin_OppositeToEdge.cpp b/src/FiltersPlugin/FiltersPlugin_OppositeToEdge.cpp
new file mode 100644 (file)
index 0000000..35d1a42
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// 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 "FiltersPlugin_OppositeToEdge.h"
+
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeExplorer.h>
+
+#include <map>
+
+typedef std::map<GeomShapePtr, SetOfShapes, GeomAPI_Shape::Comparator> MapShapeAndAncestors;
+
+static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap)
+{
+  GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE);
+  for (; aFExp.more(); aFExp.next()) {
+    GeomShapePtr aFace = aFExp.current();
+    GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE);
+    for (; aEExp.more(); aEExp.next())
+      theMap[aEExp.current()].insert(aFace);
+  }
+}
+
+// Return edge in the quadratic face opposite to the given one.
+// If the face is not quadratic, returns empty shape.
+static GeomShapePtr oppositeEdgeInQuadFace(const GeomShapePtr theEdge,
+                                           const GeomShapePtr theFace)
+{
+  static int THE_QUAD = 4;
+
+  int aNbEdges = 0;
+  int anOriginalEdgeIndex = -THE_QUAD;
+  GeomShapePtr anOppositeEdge;
+  GeomAPI_ShapeExplorer anExp(theFace, GeomAPI_Shape::EDGE);
+  while (anExp.more()) {
+    if (anExp.current()->isSame(theEdge))
+      anOriginalEdgeIndex = aNbEdges;
+    else if (aNbEdges == anOriginalEdgeIndex + THE_QUAD / 2) {
+      anOppositeEdge = anExp.current();
+      if (aNbEdges >= THE_QUAD)
+        break;
+    }
+
+    ++aNbEdges;
+    anExp.next();
+    if (!anExp.more()) {
+      if (aNbEdges != THE_QUAD) {
+        // not quad face
+        anOppositeEdge = GeomShapePtr();
+        break;
+      }
+      if (!anOppositeEdge)
+        anExp.reinit();
+    }
+  }
+  return anOppositeEdge;
+}
+
+// Find all opposite edges for the given.
+static void cacheOppositeEdge(const GeomShapePtr theEdge,
+                              const MapShapeAndAncestors& theEdgeToFaces,
+                              SetOfShapes& theCache)
+{
+  MapShapeAndAncestors::const_iterator aFound = theEdgeToFaces.find(theEdge);
+  if (aFound == theEdgeToFaces.end())
+    return;
+
+  for (SetOfShapes::const_iterator aFIt = aFound->second.begin();
+       aFIt != aFound->second.end(); ++aFIt) {
+    GeomShapePtr anOpposite = oppositeEdgeInQuadFace(theEdge, *aFIt);
+    if (anOpposite && theCache.find(anOpposite) == theCache.end()) {
+      theCache.insert(anOpposite);
+      cacheOppositeEdge(anOpposite, theEdgeToFaces, theCache);
+    }
+  }
+}
+
+static void cacheOppositeEdges(const GeomShapePtr theTopLevelShape,
+                               const GeomShapePtr theEdge,
+                               SetOfShapes& theCache)
+{
+  if (!theTopLevelShape || !theEdge)
+    return;
+
+  MapShapeAndAncestors anEdgesToFaces;
+  mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces);
+
+  // keep the original edge
+  theCache.insert(theEdge);
+  // cache opposite edges
+  cacheOppositeEdge(theEdge, anEdgesToFaces, theCache);
+}
+
+
+bool FiltersPlugin_OppositeToEdge::isSupported(GeomAPI_Shape::ShapeType theType) const
+{
+  return theType == GeomAPI_Shape::EDGE;
+}
+
+bool FiltersPlugin_OppositeToEdge::isOk(const GeomShapePtr& theShape,
+                                        const ModelAPI_FiltersArgs& theArgs) const
+{
+  AttributePtr aAttr = theArgs.argument("OppositeToEdge");
+  AttributeSelectionPtr aList = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aAttr);
+  if (!aList.get())
+    return false;
+  GeomShapePtr anEdge = aList->value();
+  if (!myOriginalEdge || !myOriginalEdge->isSame(anEdge)) {
+    // new edge is selected, need to update the cache
+    const_cast<FiltersPlugin_OppositeToEdge*>(this)->myOriginalEdge = anEdge;
+    const_cast<FiltersPlugin_OppositeToEdge*>(this)->myCachedShapes.clear();
+  }
+
+  if (myCachedShapes.empty()) {
+    ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(aList->context(), true);
+    if (!aBaseResult.get())
+      return false;
+
+    cacheOppositeEdges(aBaseResult->shape(), anEdge,
+        const_cast<FiltersPlugin_OppositeToEdge*>(this)->myCachedShapes);
+  }
+
+  return myCachedShapes.find(theShape) != myCachedShapes.end();
+}
+
+static std::string XMLRepresentation =
+"<filter id = \"OppositeToEdge\">"
+" <shape_selector id=\"OppositeToEdge__OppositeToEdge\""
+"   label=\"Edge:\""
+"   tooltip=\"Select edge.\""
+"   shape_types=\"edges\">"
+"   <validator id=\"GeomValidators_ShapeType\" parameters=\"line\"/>"
+" </shape_selector>"
+"</filter>";
+
+
+std::string FiltersPlugin_OppositeToEdge::xmlRepresentation() const
+{
+  return XMLRepresentation;
+}
+
+void FiltersPlugin_OppositeToEdge::initAttributes(ModelAPI_FiltersArgs& theArguments)
+{
+  theArguments.initAttribute("OppositeToEdge", ModelAPI_AttributeSelection::typeId());
+}
diff --git a/src/FiltersPlugin/FiltersPlugin_OppositeToEdge.h b/src/FiltersPlugin/FiltersPlugin_OppositeToEdge.h
new file mode 100644 (file)
index 0000000..9db4458
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+//
+// 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 FILTERSPLUGIN_OPPOSITETOEDGE_H_
+#define FILTERSPLUGIN_OPPOSITETOEDGE_H_
+
+#include "FiltersPlugin.h"
+
+#include <GeomAPI_Shape.h>
+#include <ModelAPI_Filter.h>
+
+#include <set>
+
+typedef std::set<GeomShapePtr, GeomAPI_Shape::Comparator> SetOfShapes;
+
+/**\class FiltersPlugin_OppositeToEdge
+* \ingroup DataModel
+* \brief Filter for edges of quadrangular faces opposite to the selected edge
+*/
+class FiltersPlugin_OppositeToEdge : public ModelAPI_Filter
+{
+public:
+  FiltersPlugin_OppositeToEdge() : ModelAPI_Filter() {}
+
+  virtual const std::string& name() const {
+    static const std::string kName("Opposite to an edge");
+    return kName;
+  }
+
+  /// Returns true for any type because it supports all selection types
+  virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override;
+
+  /// This method should contain the filter logic. It returns true if the given shape
+  /// is accepted by the filter.
+  /// \param theShape the given shape
+  virtual bool isOk(const GeomShapePtr& theShape,
+                    const ModelAPI_FiltersArgs& theArgs) const override;
+
+  /// Returns XML string which represents GUI of the filter
+  virtual std::string xmlRepresentation() const override;
+
+  /// Initializes arguments of a filter.
+  virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override;
+
+private:
+  /// Original edge selected for filtering
+  GeomShapePtr myOriginalEdge;
+  /// Shapes applicable for the filter
+  SetOfShapes myCachedShapes;
+};
+
+#endif
\ No newline at end of file
index 67a8c8fce8c8612baa85499fe51be02817a11b84..956e8477db7b5360813f0bd67fbb9cab3eff6dfd 100644 (file)
@@ -26,6 +26,7 @@
 #include "FiltersPlugin_OnLine.h"
 #include "FiltersPlugin_OnGeometry.h"
 #include "FiltersPlugin_OnPlaneSide.h"
+#include "FiltersPlugin_OppositeToEdge.h"
 
 #include <ModelAPI_Session.h>
 #include <ModelAPI_FiltersFactory.h>
@@ -45,6 +46,7 @@ FiltersPlugin_Plugin::FiltersPlugin_Plugin()
   aFactory->registerFilter("OnLine", new FiltersPlugin_OnLine);
   aFactory->registerFilter("OnGeometry", new FiltersPlugin_OnGeometry);
   aFactory->registerFilter("OnPlaneSide", new FiltersPlugin_OnPlaneSide);
+  aFactory->registerFilter("OppositeToEdge", new FiltersPlugin_OppositeToEdge);
 
   ModelAPI_Session::get()->registerPlugin(this);
 }
diff --git a/src/FiltersPlugin/Test/TestFilter_OppositeToEdge.py b/src/FiltersPlugin/Test/TestFilter_OppositeToEdge.py
new file mode 100644 (file)
index 0000000..8233491
--- /dev/null
@@ -0,0 +1,146 @@
+# Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+#
+# 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
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 100, 100, 100)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], -50, -50, -50)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOY"), model.selection("EDGE", "PartSet/OX"), 30)
+Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 30)
+Plane_6 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/XOZ"), model.selection("EDGE", "PartSet/OZ"), 30)
+Partition_1_objects = [model.selection("SOLID", "Translation_1_1"), model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2"), model.selection("FACE", "Plane_3")]
+Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects, 20190506)
+Filters = model.filters(Part_1_doc, [model.addFilter(name = "OppositeToEdge", args = [model.selection("EDGE", "Partition_1_1_7/Generated_Edge&Plane_2/Plane_2&Plane_1/Plane_1")])])
+model.end()
+
+from GeomAPI import *
+
+Reference = {}
+# Faces are not applicable
+ResultBox_1 = Partition_1.result().resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.FACE)
+while exp.more():
+  Reference[model.selection(ResultBox_1, exp.current())] = False
+  exp.next()
+# Vertices are not applicable too
+exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.VERTEX)
+while exp.more():
+  Reference[model.selection(ResultBox_1, exp.current())] = False
+  exp.next()
+
+# Edges of the partitioned box.
+# Note: the expected values have to be updated if ShapeExplorer will return another order of sub-shapes.
+
+# sub-result 0
+SubResult = Partition_1.result().subResult(0).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+
+# sub-result 1
+SubResult = Partition_1.result().subResult(1).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+
+# sub-result 2
+SubResult = Partition_1.result().subResult(2).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(SubResult, exp.current())] = False
+  exp.next()
+
+# sub-result 3
+SubResult = Partition_1.result().subResult(3).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(SubResult, exp.current())] = False
+  exp.next()
+
+# sub-result 4
+SubResult = Partition_1.result().subResult(4).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+
+# sub-result 5
+SubResult = Partition_1.result().subResult(5).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(SubResult, exp.current())] = False
+  exp.next()
+
+# sub-result 6
+SubResult = Partition_1.result().subResult(6).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+Reference[model.selection(SubResult, exp.current())] = False; exp.next()
+Reference[model.selection(SubResult, exp.current())] = True;  exp.next()
+
+# sub-result 7
+SubResult = Partition_1.result().subResult(7).resultSubShapePair()[0]
+exp = GeomAPI_ShapeExplorer(SubResult.shape(), GeomAPI_Shape.EDGE)
+while exp.more():
+  Reference[model.selection(SubResult, exp.current())] = False
+  exp.next()
+
+model.checkFilter(Part_1_doc, model, Filters, Reference)