]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #2564: CEA 2018-1 SMASH
authordbv <dbv@opencascade.com>
Sat, 11 Aug 2018 16:18:10 +0000 (19:18 +0300)
committerdbv <dbv@opencascade.com>
Sat, 11 Aug 2018 16:18:46 +0000 (19:18 +0300)
Added possibility to select planar faces in Boolean Smash feature.

src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.h
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/Test/TestBooleanSmash_Face_Face.py [new file with mode: 0644]
src/FeaturesPlugin/boolean_smash_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml

index e111b5906c52df782dd35f5a6ad26fe9f3b3d7a3..f2667acbee8c83166d18b56356179345d27326fb 100644 (file)
@@ -69,6 +69,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_Translation.cpp
     FeaturesPlugin_Boolean.cpp
     FeaturesPlugin_BooleanCut.cpp
+    FeaturesPlugin_BooleanSmash.cpp
     FeaturesPlugin_Intersection.cpp
     FeaturesPlugin_Partition.cpp
     FeaturesPlugin_Pipe.cpp
@@ -105,6 +106,7 @@ SET(XML_RESOURCES
   rotation_widget.xml
   translation_widget.xml
   boolean_widget.xml
+  boolean_smash_widget.xml
   recover_widget.xml
   partition_widget.xml
   placement_widget.xml
@@ -292,4 +294,5 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestBooleanCut_Wire_Face.py
                TestBooleanCut_Wire_Wire.py
                TestBooleanCut_WireCompound_WireCompound.py
+               TestBooleanSmash_Face_Face.py
 )
diff --git a/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp b/src/FeaturesPlugin/FeaturesPlugin_BooleanSmash.cpp
new file mode 100644 (file)
index 0000000..ebc6549
--- /dev/null
@@ -0,0 +1,306 @@
+// Copyright (C) 2014-2017  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "FeaturesPlugin_BooleanSmash.h"
+
+#include <ModelAPI_ResultCompSolid.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_PaveFiller.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_ShapeIterator.h>
+
+//==================================================================================================
+FeaturesPlugin_BooleanSmash::FeaturesPlugin_BooleanSmash()
+: FeaturesPlugin_Boolean(FeaturesPlugin_Boolean::BOOL_SMASH)
+{
+}
+
+//==================================================================================================
+void FeaturesPlugin_BooleanSmash::initAttributes()
+{
+  data()->addAttribute(OBJECT_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(TOOL_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+//==================================================================================================
+void FeaturesPlugin_BooleanSmash::execute()
+{
+  ListOfShape anObjects, aTools;
+  std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape> aCompSolidsObjects;
+
+  // Getting objects.
+  AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECT_LIST_ID());
+  for(int anObjectsIndex = 0; anObjectsIndex < anObjectsSelList->size(); anObjectsIndex++) {
+    AttributeSelectionPtr anObjectAttr = anObjectsSelList->value(anObjectsIndex);
+    std::shared_ptr<GeomAPI_Shape> anObject = anObjectAttr->value();
+    if(!anObject.get()) {
+      return;
+    }
+    ResultPtr aContext = anObjectAttr->context();
+    ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
+    if (aResCompSolidPtr.get())
+    {
+      std::shared_ptr<GeomAPI_Shape> aContextShape = aResCompSolidPtr->shape();
+
+      std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
+        anIt = aCompSolidsObjects.begin();
+      for (; anIt != aCompSolidsObjects.end(); anIt++) {
+        if (anIt->first->isEqual(aContextShape)) {
+          aCompSolidsObjects[anIt->first].push_back(anObject);
+          break;
+        }
+      }
+      if (anIt == aCompSolidsObjects.end()) {
+        aCompSolidsObjects[aContextShape].push_back(anObject);
+      }
+
+    } else {
+      anObjects.push_back(anObject);
+    }
+  }
+
+  // Getting tools.
+  AttributeSelectionListPtr aToolsSelList = selectionList(TOOL_LIST_ID());
+  for(int aToolsIndex = 0; aToolsIndex < aToolsSelList->size(); aToolsIndex++) {
+    AttributeSelectionPtr aToolAttr = aToolsSelList->value(aToolsIndex);
+    GeomShapePtr aTool = aToolAttr->value();
+    if(!aTool.get()) {
+      return;
+    }
+    aTools.push_back(aTool);
+  }
+
+  int aResultIndex = 0;
+
+  if((anObjects.empty() && aCompSolidsObjects.empty())
+     || aTools.empty()) {
+    std::string aFeatureError = "Error: Not enough objects for boolean operation.";
+    setError(aFeatureError);
+    return;
+  }
+
+  // List of original shapes for naming.
+  ListOfShape anOriginalShapes;
+  anOriginalShapes.insert(anOriginalShapes.end(), anObjects.begin(), anObjects.end());
+  anOriginalShapes.insert(anOriginalShapes.end(), aTools.begin(), aTools.end());
+
+  // Collecting all shapes which will be smashed.
+  ListOfShape aShapesToSmash;
+  aShapesToSmash.insert(aShapesToSmash.end(), anObjects.begin(), anObjects.end());
+
+  // Collecting solids from compsolids which will not be modified in
+  // boolean operation and will be added to result.
+  ListOfShape aShapesToAdd;
+  for (std::map<std::shared_ptr<GeomAPI_Shape>, ListOfShape>::iterator
+       anIt = aCompSolidsObjects.begin();
+       anIt != aCompSolidsObjects.end();
+       ++anIt)
+  {
+    std::shared_ptr<GeomAPI_Shape> aCompSolid = anIt->first;
+    ListOfShape& aUsedInOperationSolids = anIt->second;
+    anOriginalShapes.push_back(aCompSolid);
+    aShapesToSmash.insert(aShapesToSmash.end(),
+                          aUsedInOperationSolids.begin(),
+                          aUsedInOperationSolids.end());
+
+    // Collect solids from compsolid which will not be modified in boolean operation.
+    for (GeomAPI_ShapeExplorer anExp(aCompSolid, GeomAPI_Shape::SOLID);
+         anExp.more();
+         anExp.next())
+    {
+      std::shared_ptr<GeomAPI_Shape> aSolidInCompSolid = anExp.current();
+      ListOfShape::iterator anIt = aUsedInOperationSolids.begin();
+      for (; anIt != aUsedInOperationSolids.end(); anIt++) {
+        if (aSolidInCompSolid->isEqual(*anIt)) {
+          break;
+        }
+      }
+      if (anIt == aUsedInOperationSolids.end()) {
+        aShapesToAdd.push_back(aSolidInCompSolid);
+      }
+    }
+  }
+
+  GeomAlgoAPI_MakeShapeList aMakeShapeList;
+  GeomAPI_DataMapOfShapeShape aMapOfShapes;
+  if (!aShapesToAdd.empty()) {
+    // Cut objects with not used solids.
+    std::shared_ptr<GeomAlgoAPI_Boolean> anObjectsCutAlgo(
+      new GeomAlgoAPI_Boolean(aShapesToSmash,
+                              aShapesToAdd,
+                              GeomAlgoAPI_Boolean::BOOL_CUT));
+
+    if (GeomAlgoAPI_ShapeTools::volume(anObjectsCutAlgo->shape()) > 1.e-27) {
+      aShapesToSmash.clear();
+      aShapesToSmash.push_back(anObjectsCutAlgo->shape());
+      aMakeShapeList.appendAlgo(anObjectsCutAlgo);
+      aMapOfShapes.merge(anObjectsCutAlgo->mapOfSubShapes());
+    }
+
+    // Cut tools with not used solids.
+    std::shared_ptr<GeomAlgoAPI_Boolean> aToolsCutAlgo(
+      new GeomAlgoAPI_Boolean(aTools,
+                              aShapesToAdd,
+                              GeomAlgoAPI_Boolean::BOOL_CUT));
+
+    if (GeomAlgoAPI_ShapeTools::volume(aToolsCutAlgo->shape()) > 1.e-27) {
+      aTools.clear();
+      aTools.push_back(aToolsCutAlgo->shape());
+      aMakeShapeList.appendAlgo(aToolsCutAlgo);
+      aMapOfShapes.merge(aToolsCutAlgo->mapOfSubShapes());
+    }
+  }
+
+  // Cut objects with tools.
+  std::shared_ptr<GeomAlgoAPI_Boolean> aBoolAlgo(
+    new GeomAlgoAPI_Boolean(aShapesToSmash,
+                            aTools,
+                            GeomAlgoAPI_Boolean::BOOL_CUT));
+
+  // Checking that the algorithm worked properly.
+  if (!aBoolAlgo->isDone()) {
+    static const std::string aFeatureError = "Error: Boolean algorithm failed.";
+    setError(aFeatureError);
+    return;
+  }
+  if (aBoolAlgo->shape()->isNull()) {
+    static const std::string aShapeError = "Error: Resulting shape is Null.";
+    setError(aShapeError);
+    return;
+  }
+  if (!aBoolAlgo->isValid()) {
+    std::string aFeatureError = "Error: Resulting shape is not valid.";
+    setError(aFeatureError);
+    return;
+  }
+  aMakeShapeList.appendAlgo(aBoolAlgo);
+  aMapOfShapes.merge(aBoolAlgo->mapOfSubShapes());
+
+  // Put all (cut result, tools and not used solids) to PaveFiller.
+  aShapesToAdd.push_back(aBoolAlgo->shape());
+  aShapesToAdd.insert(aShapesToAdd.end(), aTools.begin(), aTools.end());
+
+  std::shared_ptr<GeomAlgoAPI_PaveFiller> aFillerAlgo(
+    new GeomAlgoAPI_PaveFiller(aShapesToAdd, true));
+  if (!aFillerAlgo->isDone()) {
+    std::string aFeatureError = "Error: PaveFiller algorithm failed.";
+    setError(aFeatureError);
+    return;
+  }
+  if (aFillerAlgo->shape()->isNull()) {
+    static const std::string aShapeError = "Error: Resulting shape is Null.";
+    setError(aShapeError);
+    return;
+  }
+  if (!aFillerAlgo->isValid()) {
+    std::string aFeatureError = "Error: Resulting shape is not valid.";
+    setError(aFeatureError);
+    return;
+  }
+
+  std::shared_ptr<GeomAPI_Shape> aShape = aFillerAlgo->shape();
+  aMakeShapeList.appendAlgo(aFillerAlgo);
+  aMapOfShapes.merge(aFillerAlgo->mapOfSubShapes());
+
+  std::shared_ptr<GeomAPI_Shape> aFrontShape = anOriginalShapes.front();
+  anOriginalShapes.pop_front();
+  std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
+  loadNamingDS(aResultBody,
+               aFrontShape,
+               anOriginalShapes,
+               aShape,
+               aMakeShapeList,
+               aMapOfShapes);
+
+  setResult(aResultBody, aResultIndex);
+  aResultIndex++;
+
+  // remove the rest results if there were produced in the previous pass
+  removeResults(aResultIndex);
+}
+
+//==================================================================================================
+void FeaturesPlugin_BooleanSmash::loadNamingDS(ResultBodyPtr theResultBody,
+                                             const GeomShapePtr theBaseShape,
+                                             const ListOfShape& theTools,
+                                             const GeomShapePtr theResultShape,
+                                             GeomAlgoAPI_MakeShape& theMakeShape,
+                                             GeomAPI_DataMapOfShapeShape& theMapOfShapes)
+{
+  //load result
+  if(theBaseShape->isEqual(theResultShape)) {
+    theResultBody->store(theResultShape, false);
+  } else {
+    const int aModifyVTag = 1;
+    const int aModifyETag = 2;
+    const int aModifyFTag = 3;
+    const int aDeletedTag = 4;
+    /// sub solids will be placed at labels 5, 6, etc. if result is compound of solids
+    const int aSubsolidsTag = 5;
+
+    theResultBody->storeModified(theBaseShape, theResultShape, aSubsolidsTag);
+
+    const std::string aModVName = "Modified_Vertex";
+    const std::string aModEName = "Modified_Edge";
+    const std::string aModFName = "Modified_Face";
+
+    theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::VERTEX,
+                                               aModifyVTag, aModVName, theMapOfShapes, false,
+                                               true, true);
+    theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::EDGE,
+                                               aModifyETag, aModEName, theMapOfShapes, false,
+                                               true, true);
+    theResultBody->loadAndOrientModifiedShapes(&theMakeShape, theBaseShape, GeomAPI_Shape::FACE,
+                                               aModifyFTag, aModFName, theMapOfShapes, false,
+                                               true, true);
+
+    theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
+                                     GeomAPI_Shape::VERTEX, aDeletedTag);
+    theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
+                                     GeomAPI_Shape::EDGE, aDeletedTag);
+    theResultBody->loadDeletedShapes(&theMakeShape, theBaseShape,
+                                     GeomAPI_Shape::FACE, aDeletedTag);
+
+    for (ListOfShape::const_iterator anIter = theTools.begin(); anIter != theTools.end(); anIter++)
+    {
+      theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::VERTEX,
+                                                 aModifyVTag, aModVName, theMapOfShapes, false,
+                                                 true, true);
+
+      theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::EDGE,
+                                                 aModifyETag, aModEName, theMapOfShapes, false,
+                                                 true, true);
+
+      theResultBody->loadAndOrientModifiedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE,
+                                                 aModifyFTag, aModFName, theMapOfShapes, false,
+                                                 true, true);
+
+      theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::VERTEX, aDeletedTag);
+      theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::EDGE, aDeletedTag);
+      theResultBody->loadDeletedShapes(&theMakeShape, *anIter, GeomAPI_Shape::FACE, aDeletedTag);
+    }
+  }
+}
index 86809f9eb065ba1a18033ed91f23b93e4e63bb0f..0238d271292a3f754c2af746dfa77d488e1e0191 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "FeaturesPlugin_Boolean.h"
 
+#include <ModelAPI_ResultBody.h>
+
 /// \class FeaturesPlugin_BooleanSmash
 /// \ingroup Plugins
 /// \brief Feature for applying of Boolean Smash operation.
@@ -44,10 +46,40 @@ public:
     return MY_KIND;
   }
 
+  /// Attribute name of main objects.
+  inline static const std::string& OBJECT_LIST_ID()
+  {
+    static const std::string MY_OBJECT_LIST_ID("main_objects");
+    return MY_OBJECT_LIST_ID;
+  }
+
+  /// Attribute name of tool objects.
+  inline static const std::string& TOOL_LIST_ID()
+  {
+    static const std::string MY_TOOL_LIST_ID("tool_objects");
+    return MY_TOOL_LIST_ID;
+  }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Creates a new part document if needed.
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
 public:
 
-    /// Use plugin manager for features creation.
-  FeaturesPlugin_BooleanSmash(): FeaturesPlugin_Boolean(BOOL_SMASH) {};
+  /// Use plugin manager for features creation.
+  FeaturesPlugin_BooleanSmash();
+
+private:
+
+  /// Load Naming data structure of the feature to the document
+  void loadNamingDS(ResultBodyPtr theResultBody,
+                    const GeomShapePtr theBaseShape,
+                    const ListOfShape& theTools,
+                    const GeomShapePtr theResultShape,
+                    GeomAlgoAPI_MakeShape& theMakeShape,
+                    GeomAPI_DataMapOfShapeShape& theMapOfShapes);
 
 };
 
index 33f256c1ff88549e3098f90fc87f3fcea7159a76..9d61541af75801ba06f00ae212093439c9d8ec83 100644 (file)
@@ -96,6 +96,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorCircular);
   aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanArguments",
                               new FeaturesPlugin_ValidatorBooleanArguments);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorBooleanSmashSelection",
+                              new FeaturesPlugin_ValidatorBooleanSmashSelection);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
index 97c82b52446f1311a00017c80d356b6d3558b4dd..cfe4ed74377143f4d242a7b07314ce564b15c857 100644 (file)
@@ -21,6 +21,7 @@
 #include "FeaturesPlugin_Validators.h"
 
 #include "FeaturesPlugin_Boolean.h"
+#include "FeaturesPlugin_BooleanSmash.h"
 #include "FeaturesPlugin_Union.h"
 
 #include <Events_InfoMessage.h>
@@ -44,6 +45,7 @@
 #include <GeomAPI_DataMapOfShapeShape.h>
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_PlanarEdges.h>
+#include <GeomAPI_Pln.h>
 #include <GeomAPI_ShapeExplorer.h>
 #include <GeomAPI_ShapeIterator.h>
 
@@ -1153,3 +1155,137 @@ bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFe
 
   return false;
 }
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
+  const AttributePtr& theAttribute,
+  const std::list<std::string>& theArguments,
+  Events_InfoMessage& theError) const
+{
+  std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
+    std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
+
+  AttributeSelectionListPtr anAttrSelectionList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!aFeature.get() || !anAttrSelectionList.get()) {
+    theError =
+      "Error: Validator used in wrong feature or attribute";
+    return false;
+  }
+
+  AttributeSelectionListPtr anOtherAttrSelectionList;
+  if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
+    anOtherAttrSelectionList =
+      aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
+  } else {
+    anOtherAttrSelectionList =
+      aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
+  }
+
+  GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
+  GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
+  GeomPlanePtr aFacesPln;
+
+  for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
+    ResultPtr aContext = anAttrSelection->context();
+    std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
+    GeomShapePtr aContextShape = aContext->shape();
+    if (!aShape.get()) {
+      aShape = aContextShape;
+    }
+
+    if (aShape->isSolid() || aShape->isCompSolid()) {
+      aSelectedShapesType = GeomAPI_Shape::SOLID;
+      ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
+      if (aResCompSolidPtr.get()) {
+        GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
+        aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
+      }
+    } else {
+      aSelectedShapesType = GeomAPI_Shape::FACE;
+      GeomAPI_Face aFace(aShape);
+      aFacesPln = aFace.getPlane();
+      break;
+    }
+  }
+
+  for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
+    if (!anAttrSelection.get()) {
+      theError = "Error: Empty attribute selection.";
+      return false;
+    }
+    ResultPtr aContext = anAttrSelection->context();
+    if (!aContext.get()) {
+      theError = "Error: Empty selection context.";
+      return false;
+    }
+    ResultConstructionPtr aResultConstruction =
+      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
+    if (aResultConstruction.get()) {
+      theError = "Error: Result construction not allowed for selection.";
+      return false;
+    }
+    std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
+    GeomShapePtr aContextShape = aContext->shape();
+    if (!aShape.get()) {
+      aShape = aContextShape;
+    }
+    if (!aShape.get()) {
+      theError = "Error: Empty shape.";
+      return false;
+    }
+    if (!aShape->isEqual(aContextShape)) {
+      theError = "Error: Local selection not allowed.";
+      return false;
+    }
+
+    if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
+      // Other list is empty.
+      if (aShape->isSolid() || aShape->isCompSolid()) {
+        aSelectedShapesType = GeomAPI_Shape::SOLID;
+      } else {
+        aSelectedShapesType = GeomAPI_Shape::FACE;
+        GeomAPI_Face aFace(aShape);
+        aFacesPln = aFace.getPlane();
+
+        if (!aFacesPln.get()) {
+          theError = "Error: Only planar faces allowed.";
+          return false;
+        }
+      }
+
+      continue;
+    } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
+      if (!aShape->isSolid() && !aShape->isCompSolid()) {
+        theError = "Error: Selected shapes should have the same type.";
+        return false;
+      }
+
+      ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
+      if (aResCompSolidPtr.get()) {
+        GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
+        if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
+          theError = "Error: Solids from compsolid in other list not allowed.";
+          return false;
+        }
+      }
+    } else {
+      GeomAPI_Face aFace(aShape);
+      GeomPlanePtr aPln = aFace.getPlane();
+
+      if (!aPln.get()) {
+        theError = "Error: Only planar faces allowed.";
+        return false;
+      }
+
+      if (!aFacesPln->isCoincident(aPln)) {
+        theError = "Error: Only coincident faces allowed.";
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
index c75ad9737149c250af28b9685118f34ecf7e8e0f..ca731ef0e7de141a8a9d8c88f2bb5e732dc0041d 100644 (file)
@@ -288,4 +288,19 @@ public:
   virtual bool isNotObligatory(std::string theFeature, std::string theAttribute);
 };
 
+/// \class FeaturesPlugin_ValidatorBooleanSmashSelection
+/// \ingroup Validators
+/// \brief Verifies the selected object for boolean smash feature
+class FeaturesPlugin_ValidatorBooleanSmashSelection: public ModelAPI_AttributeValidator
+{
+public:
+  //! \return True if the attribute is valid.
+  //! \param[in] theAttribute the checked attribute.
+  //! \param[in] theArguments arguments of the attribute.
+  //! \param[out] theError error message.
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 #endif
diff --git a/src/FeaturesPlugin/Test/TestBooleanSmash_Face_Face.py b/src/FeaturesPlugin/Test/TestBooleanSmash_Face_Face.py
new file mode 100644 (file)
index 0000000..5ac6d47
--- /dev/null
@@ -0,0 +1,52 @@
+## Copyright (C) 2014-2017  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<mailto: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()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(-31.7032590051458, 14.72555746140652, 29.35516607310447)
+SketchCircle_1.result().setColor(225, 0, 0)
+SketchCircle_1.results()[1].setColor(225, 0, 0)
+model.do()
+Sketch_2 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_2 = Sketch_2.addCircle(12.30017152658664, 14.37907375643225, 29.61574408620473)
+SketchCircle_2.result().setColor(225, 0, 0)
+SketchCircle_2.results()[1].setColor(225, 0, 0)
+model.do()
+Face_1 = model.addFace(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f"), model.selection("FACE", "Sketch_2/Face-SketchCircle_2_2f")])
+Smash_1 = model.addSmash(Part_1_doc, [model.selection("FACE", "Face_1_1")], [model.selection("FACE", "Face_1_2")])
+model.testHaveNamingSubshapes(Smash_1, model, Part_1_doc)
+model.do()
+model.end()
+
+from GeomAPI import  GeomAPI_Shape
+
+model.testNbResults(Smash_1, 1)
+model.testNbSubResults(Smash_1, [2])
+model.testNbSubShapes(Smash_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Smash_1, GeomAPI_Shape.FACE, [2])
+model.testNbSubShapes(Smash_1, GeomAPI_Shape.EDGE, [5])
+model.testNbSubShapes(Smash_1, GeomAPI_Shape.VERTEX, [10])
+
+assert(model.checkPythonDump())
diff --git a/src/FeaturesPlugin/boolean_smash_widget.xml b/src/FeaturesPlugin/boolean_smash_widget.xml
new file mode 100644 (file)
index 0000000..cb755c1
--- /dev/null
@@ -0,0 +1,43 @@
+<!--
+Copyright (C) 2014-2017  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<mailto:webmaster.salome@opencascade.com>
+-->
+
+<source>
+  <multi_selector id="main_objects"
+    label="Main objects"
+    icon=""
+    tooltip="Select objects"
+    type_choice="faces solids compsolids"
+    use_choice="false"
+    concealment="true">
+    <validator id="PartSet_DifferentObjects"/>
+    <validator id="FeaturesPlugin_ValidatorBooleanSmashSelection"/>
+  </multi_selector>
+  <multi_selector id="tool_objects"
+    label="Tool objects"
+    icon=""
+    tooltip="Select tools"
+    type_choice="faces solids compsolids"
+    use_choice="false"
+    concealment="true" >
+    <validator id="PartSet_DifferentObjects"/>
+    <validator id="FeaturesPlugin_ValidatorBooleanSmashSelection"/>
+  </multi_selector>
+</source>
index 4095ed581e74afbebf2242a147f5487fd82e0b27..e5b261cbc98f6dd5924d57ee6ccc12a62d47c994 100644 (file)
@@ -80,7 +80,7 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
       <feature id="Smash" title="Smash" tooltip="Perform boolean smash operation with objects"
                icon="icons/Features/bool_smash.png" helpfile="FeaturesPlugin/smashFeature.html"
                auto_preview="false">
-          <source path="boolean_widget.xml"/>
+          <source path="boolean_smash_widget.xml"/>
       </feature>
       <feature id="Intersection" title="Intersection" tooltip="Intersect objects with tools"
                icon="icons/Features/intersection.png" helpfile="FeaturesPlugin/intersectionFeature.html">