]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Add new feature AddNode for OPERA
authorNicolas RECHATIN <nicolas.rechatin@cea.fr>
Thu, 5 Aug 2021 10:26:08 +0000 (12:26 +0200)
committerNicolas Rechatin <nicolas.rechatin@cea.fr>
Mon, 20 Sep 2021 15:04:59 +0000 (17:04 +0200)
27 files changed:
src/OperaAPI/CMakeLists.txt
src/OperaAPI/OperaAPI.i
src/OperaAPI/OperaAPI_AddNode.cpp [new file with mode: 0644]
src/OperaAPI/OperaAPI_AddNode.h [new file with mode: 0644]
src/OperaAPI/OperaAPI_swig.h
src/OperaPlugin/CMakeLists.txt
src/OperaPlugin/OperaPlugin_AddNode.cpp [new file with mode: 0644]
src/OperaPlugin/OperaPlugin_AddNode.h [new file with mode: 0644]
src/OperaPlugin/OperaPlugin_Plugin.cpp
src/OperaPlugin/OperaPlugin_Tools.cpp [new file with mode: 0644]
src/OperaPlugin/OperaPlugin_Tools.h [new file with mode: 0644]
src/OperaPlugin/OperaPlugin_Volume.cpp
src/OperaPlugin/OperaPlugin_msg_fr.ts
src/OperaPlugin/Test/TestAddNode.py [new file with mode: 0644]
src/OperaPlugin/addnode_widget.xml [new file with mode: 0644]
src/OperaPlugin/doc/OperaPlugin.rst
src/OperaPlugin/doc/TUI_addnode.rst [new file with mode: 0644]
src/OperaPlugin/doc/addnodeFeature.rst [new file with mode: 0644]
src/OperaPlugin/doc/examples/addnode.py [new file with mode: 0644]
src/OperaPlugin/doc/images/AddNode.png [new file with mode: 0644]
src/OperaPlugin/doc/images/AddNode1.png [new file with mode: 0644]
src/OperaPlugin/doc/images/AddNode_button.png [new file with mode: 0644]
src/OperaPlugin/doc/volumeFeature.rst
src/OperaPlugin/icons/AddNode.png [new file with mode: 0644]
src/OperaPlugin/plugin-Opera.xml
src/OperaPlugin/tests.set
src/PythonAPI/model/opera/__init__.py

index a9da8f18117f4f4f129143e05046e23d8e1e6e2f..192634bd9499106eef3ad810b5c6aea2937bbecc 100644 (file)
@@ -22,10 +22,12 @@ INCLUDE(Common)
 SET(PROJECT_HEADERS
   OperaAPI.h
   OperaAPI_Volume.h
+  OperaAPI_AddNode.h
 )
 
 SET(PROJECT_SOURCES
   OperaAPI_Volume.cpp
+  OperaAPI_AddNode.cpp
 )
 
 SET(PROJECT_LIBRARIES
index 6bbadc5250aa4705b23c4d48bbf4b3e05705ee48..57223e944fcc8eb69f6f70f38eeaf8a427fe3df1 100644 (file)
@@ -39,6 +39,8 @@
 
 // shared pointers
 %shared_ptr(OperaAPI_Volume)
+%shared_ptr(OperaAPI_AddNode)
 
 // all supported interfaces
 %include "OperaAPI_Volume.h"
+%include "OperaAPI_AddNode.h"
diff --git a/src/OperaAPI/OperaAPI_AddNode.cpp b/src/OperaAPI/OperaAPI_AddNode.cpp
new file mode 100644 (file)
index 0000000..2978580
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright (C) 2014-2021  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 "OperaAPI_AddNode.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+//==================================================================================================
+OperaAPI_AddNode::OperaAPI_AddNode(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+: ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+
+//==================================================================================================
+OperaAPI_AddNode::OperaAPI_AddNode(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                   const ModelHighAPI_Selection& theMainObject,
+                                   const std::list<ModelHighAPI_Selection>& theToolsList)
+                                                                  : ModelHighAPI_Interface(theFeature)
+{
+  if(initialize()) {
+    fillAttribute(theMainObject, mainObject());
+    setToolsList(theToolsList);
+  }
+}
+
+//==================================================================================================
+OperaAPI_AddNode::~OperaAPI_AddNode()
+{
+}
+
+//==================================================================================================
+void OperaAPI_AddNode::setMainObject(const ModelHighAPI_Selection& theMainObject)
+{
+  fillAttribute(theMainObject, mainObject());
+  execute();
+}
+
+//==================================================================================================
+void OperaAPI_AddNode::setToolsList(const std::list<ModelHighAPI_Selection>& theToolsList)
+{
+  fillAttribute(theToolsList, toolsList());
+  execute();
+}
+
+//==================================================================================================
+void OperaAPI_AddNode::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  const std::string& aDocName = theDumper.name(aBase->document());
+
+  AttributeSelectionPtr anAttrObject = aBase->selection(OperaPlugin_AddNode::MAIN_OBJECT_ID());
+  theDumper << aBase << " = model.addAddNode(" << aDocName << ", " << anAttrObject << ", ";
+
+  AttributeSelectionListPtr anAttrList =
+    aBase->selectionList(OperaPlugin_AddNode::TOOLS_LIST_ID());
+  theDumper << anAttrList << ")" << std::endl;
+}
+
+//==================================================================================================
+AddNodePtr addAddNode(const std::shared_ptr<ModelAPI_Document>& thePart,
+                      const ModelHighAPI_Selection& theMainObject,
+                      const std::list<ModelHighAPI_Selection>& theToolsList)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(OperaAPI_AddNode::ID());
+  return AddNodePtr(new OperaAPI_AddNode(aFeature, theMainObject, theToolsList));
+}
diff --git a/src/OperaAPI/OperaAPI_AddNode.h b/src/OperaAPI/OperaAPI_AddNode.h
new file mode 100644 (file)
index 0000000..2886216
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright (C) 2014-2021  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 OPERAAPI_ADDNODE_H_
+#define OPERAAPI_ADDNODE_H_
+
+#include "OperaAPI.h"
+#include <OperaPlugin_AddNode.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Selection;
+
+/// \class OperaAPI_AddNode
+/// \ingroup CPPHighAPI
+/// \brief Interface for AddNode feature.
+class OperaAPI_AddNode: public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  OPERAAPI_EXPORT
+  explicit OperaAPI_AddNode(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with values.
+  OPERAAPI_EXPORT
+  explicit OperaAPI_AddNode(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                            const ModelHighAPI_Selection& theMainObject,
+                            const std::list<ModelHighAPI_Selection>& theToolsList);
+
+  /// Destructor.
+  OPERAAPI_EXPORT
+  virtual ~OperaAPI_AddNode();
+
+  INTERFACE_2(OperaPlugin_AddNode::ID(),
+              mainObject, OperaPlugin_AddNode::MAIN_OBJECT_ID(),
+              ModelAPI_AttributeSelection, /** Main Object */,
+              toolsList, OperaPlugin_AddNode::TOOLS_LIST_ID(),
+              ModelAPI_AttributeSelectionList, /** Tools list*/)
+
+  /// Set main object
+  OPERAAPI_EXPORT
+  void setMainObject(const ModelHighAPI_Selection& theMainObject);
+
+  /// Set tools list
+  OPERAAPI_EXPORT
+  void setToolsList(const std::list<ModelHighAPI_Selection>& theToolsList);
+
+  /// Dump wrapped feature
+  OPERAAPI_EXPORT
+  virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+};
+
+/// Pointer AddNode feature
+typedef std::shared_ptr<OperaAPI_AddNode> AddNodePtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Volume feature.
+OPERAAPI_EXPORT
+AddNodePtr addAddNode(const std::shared_ptr<ModelAPI_Document>& thePart,
+                      const ModelHighAPI_Selection& theMainObject,
+                      const std::list<ModelHighAPI_Selection>& theToolsList);
+
+#endif // OPERAAPI_ADDNODE_H_
index eaa088dc9cccce96e2e13d36f6c4d08b026b89fc..661e51618f795b5a7a8fa05390875eeefab5acf4 100644 (file)
@@ -24,5 +24,6 @@
 
   #include "OperaAPI.h"
   #include "OperaAPI_Volume.h"
+  #include "OperaAPI_AddNode.h"
 
 #endif // OPERAAPI_SWIG_H_
index a1f7fd6002df40552a1e1df478d468f9b99bc432..92f3460c8caad5b64941d9c24c843f64fbf1cba1 100644 (file)
 SET(PROJECT_HEADERS
     OperaPlugin.h
     OperaPlugin_Plugin.h
+    OperaPlugin_Tools.h
     OperaPlugin_Volume.h
+    OperaPlugin_AddNode.h
 )
 
 SET(PROJECT_SOURCES
     OperaPlugin_Plugin.cpp
+    OperaPlugin_Tools.cpp
     OperaPlugin_Volume.cpp
-
+    OperaPlugin_AddNode.cpp
 )
 
 SET(XML_RESOURCES
   plugin-Opera.xml
   volume_widget.xml
+  addnode_widget.xml
 )
 
 SET(TEXT_RESOURCES
diff --git a/src/OperaPlugin/OperaPlugin_AddNode.cpp b/src/OperaPlugin/OperaPlugin_AddNode.cpp
new file mode 100644 (file)
index 0000000..9c67576
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright (C) 2014-2021  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 "OperaPlugin_AddNode.h"
+
+#include <ModelAPI_Feature.h>
+
+//=================================================================================================
+OperaPlugin_AddNode::OperaPlugin_AddNode() // Nothing to do during instantiation
+{
+}
+
+//=================================================================================================
+void OperaPlugin_AddNode::initAttributes()
+{
+  data()->addAttribute(MAIN_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(TOOLS_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+}
+
+//=================================================================================================
+bool toolsIntersect(ListOfShape& theToolsList){
+
+  for(auto it = theToolsList.begin(); it != theToolsList.end(); it++)
+    for(auto jt = theToolsList.begin(); jt != theToolsList.end(); jt++)
+    {
+      GeomShapePtr first = *it;
+      GeomShapePtr second = *jt;
+      if (!(first == second))
+        if (first->isIntersect(second))
+          return true;
+    }
+  return false;
+}
+
+//=================================================================================================
+void OperaPlugin_AddNode::performAlgo(const GeomAlgoAPI_Tools::BOPType theBooleanType,
+                                      const GeomShapePtr& theObject,
+                                      const ListOfShape& theTools,
+                                      const ListOfShape& thePlanes,
+                                      int& theResultIndex)
+{
+  //Perform algorithm
+  ListOfShape aListWithObject;
+  aListWithObject.push_back(theObject);
+  std::shared_ptr<GeomAlgoAPI_MakeShapeList> aMakeShapeList(new GeomAlgoAPI_MakeShapeList());
+  std::shared_ptr<GeomAlgoAPI_MakeShape> aBoolAlgo;
+  GeomShapePtr aResShape;
+  aBoolAlgo.reset(new GeomAlgoAPI_Boolean(aListWithObject,
+                                          theTools,
+                                          theBooleanType));
+  //Check for error
+  std::string anError;
+  if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aBoolAlgo, getKind(), anError))
+    return setError(anError);
+
+  //Naming
+  handleNaming(aResShape, aBoolAlgo, aMakeShapeList, theTools);
+}
+
+//=================================================================================================
+void OperaPlugin_AddNode::handleNaming(GeomShapePtr theResShape,
+                                       GeomMakeShapePtr theBoolAlgo,
+                                       std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList,
+                                       const ListOfShape& theTools)
+{
+  //Get result shape
+  int anIndexToRemove = 0;
+  theResShape = theBoolAlgo->shape();
+  theMakeShapeList->appendAlgo(theBoolAlgo);
+  ListOfShape aTestList = theTools;
+  aTestList.push_front(theResShape);
+
+  //Build result compund
+  GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aTestList);
+  if (aCompound) {
+    ResultBodyPtr aResultBody = document()->createBody(data(), anIndexToRemove++);
+    aResultBody->storeModified(aTestList, aCompound, theBoolAlgo);
+    aResultBody->loadModifiedShapes(theMakeShapeList, aCompound, GeomAPI_Shape::VERTEX);
+    aResultBody->loadModifiedShapes(theMakeShapeList, aCompound, GeomAPI_Shape::EDGE);
+    aResultBody->loadModifiedShapes(theMakeShapeList, aCompound, GeomAPI_Shape::FACE);
+    setResult(aResultBody);
+  }
+}
+
+//=================================================================================================
+void OperaPlugin_AddNode::execute()
+{
+  int aResultIndex = 0;
+  ListOfShape aPlanes, aToolList;
+
+  //Get Selection and Shapes
+  AttributeSelectionPtr aMainObjectAttr = selection(MAIN_OBJECT_ID());
+  AttributeSelectionListPtr aToolsAttrList = selectionList(TOOLS_LIST_ID());
+
+  // Get Shapes from selection and test intersection with Main Object
+  GeomShapePtr aMainObjectShape = shapeOfSelection(aMainObjectAttr);
+  for (int anObjectsIndex = 0; anObjectsIndex < aToolsAttrList->size(); anObjectsIndex++){
+    GeomShapePtr currentToolShape = shapeOfSelection(aToolsAttrList->value(anObjectsIndex));
+    if (!aMainObjectShape->isIntersect(currentToolShape) || aMainObjectShape->intersect(currentToolShape))
+      return setError("Error: All tools must be fully inside the main object");
+    aToolList.push_back(currentToolShape);
+  }
+
+  // Check tools intersections
+  if (toolsIntersect(aToolList))
+    return setError("Error: Tools must not intersect each others");
+
+  //Check for error then clean part results
+  if(aMainObjectShape == nullptr )
+    return setError("Error: cannot perform an AddNode with no main object.");
+  if(aToolList.empty())
+    return setError("Error: Tools list cannot be empty.");
+  aMainObjectAttr->context()->setDisabled(aMainObjectAttr->context(), true); // To avoid activation of the Part result
+
+  //Perform Algorithm
+  performAlgo(GeomAlgoAPI_Tools::BOOL_CUT,
+              shapeOfSelection(aMainObjectAttr), aToolList, aPlanes,
+              aResultIndex);
+}
diff --git a/src/OperaPlugin/OperaPlugin_AddNode.h b/src/OperaPlugin/OperaPlugin_AddNode.h
new file mode 100644 (file)
index 0000000..0a41de4
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright (C) 2014-2021  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 OperaPlugin_AddNode_H_
+#define OperaPlugin_AddNode_H_
+
+#include <OperaPlugin.h>
+#include <OperaPlugin_Tools.h>
+
+#include "GeomAPI_ShapeHierarchy.h"
+#include "GeomAPI_ShapeIterator.h"
+
+#include <GeomAlgoAPI_Boolean.h>
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_ShapeBuilder.h>
+#include "GeomAlgoAPI_Tools.h"
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_Tools.h>
+
+/**\class OperaPlugin_AddNode
+ * \ingroup Plugins
+ * \brief Feature for creation of a Node using solids.
+ *
+ * Node creates Node object - This Node takes selected solids shape
+ * and transform the result to a Node with a medium for OPERA.
+ */
+class OperaPlugin_AddNode : public ModelAPI_Feature
+{
+  public:
+    /// Node kind
+    inline static const std::string& ID()
+    {
+      static const std::string MY_NODE_ID("AddNode");
+      return MY_NODE_ID;
+    }
+    /// Attribute name of main object.
+    inline static const std::string& MAIN_OBJECT_ID()
+    {
+      static const std::string MY_MAIN_OBJECT_ID("main_object");
+      return MY_MAIN_OBJECT_ID;
+    }
+    /// Attribute name of selected tools list
+    inline static const std::string& TOOLS_LIST_ID()
+    {
+      static const std::string MY_TOOLS_LIST_ID("tools_list");
+      return MY_TOOLS_LIST_ID;
+    }
+
+    /// Perform boolean alogrithm according to AddNode cases
+    void performAlgo(const GeomAlgoAPI_Tools::BOPType theBooleanType,
+                     const GeomShapePtr& theObject,
+                     const ListOfShape& theTools,
+                     const ListOfShape& thePlanes,
+                     int& theResultIndex);
+
+    /// Creates naming for AddNode results
+    void OperaPlugin_AddNode::handleNaming(GeomShapePtr theResShape,
+                                           GeomMakeShapePtr theBoolAlgo,
+                                          std::shared_ptr<GeomAlgoAPI_MakeShapeList> theMakeShapeList,
+                                          const ListOfShape& theTools);
+
+    /// Creates a new part document if needed
+    OPERAPLUGIN_EXPORT virtual void execute();
+
+    /// Request for initialization of data model of the feature: adding all attributes
+    OPERAPLUGIN_EXPORT virtual void initAttributes();
+
+    /// Returns the kind of a feature
+    OPERAPLUGIN_EXPORT virtual const std::string& getKind()
+    {
+      static std::string MY_KIND = OperaPlugin_AddNode::ID();
+      return MY_KIND;
+    }
+
+    /// Use plugin manager for features creation
+    OperaPlugin_AddNode();
+};
+
+#endif
index 894925751c8bcf529ff952bc4bfb5bcde0ddcd9b..34e927644cb30b6e9ae6b30ee47e064e61545b24 100644 (file)
 
 #include <OperaPlugin_Plugin.h>
 #include <OperaPlugin_Volume.h>
+#include <OperaPlugin_AddNode.h>
 
 #include <ModelAPI_Session.h>
 
-#include <string>
-
 // the only created instance of this plugin
 static OperaPlugin_Plugin* MY_PRIMITIVES_INSTANCE = new OperaPlugin_Plugin();
 
@@ -37,6 +36,8 @@ FeaturePtr OperaPlugin_Plugin::createFeature(std::string theFeatureID)
 {
   if (theFeatureID == OperaPlugin_Volume::ID()) {
     return FeaturePtr(new OperaPlugin_Volume);
+  } else if (theFeatureID == OperaPlugin_AddNode::ID()) {
+    return FeaturePtr(new OperaPlugin_AddNode);
   } else {
     return FeaturePtr();
   }
diff --git a/src/OperaPlugin/OperaPlugin_Tools.cpp b/src/OperaPlugin/OperaPlugin_Tools.cpp
new file mode 100644 (file)
index 0000000..8ca4594
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2014-2021  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 "OperaPlugin_Tools.h"
+
+//=================================================================================================
+GeomShapePtr shapeOfSelection(AttributeSelectionPtr theSel)
+{
+  GeomShapePtr aResult;
+  FeaturePtr aSelFeature = theSel->contextFeature();
+
+  //Get result from selection
+  if (aSelFeature.get()) {
+    if (aSelFeature->results().empty()) // if selected feature has no results, make nothing
+      return aResult;
+    if (aSelFeature->results().size() == 1) { // for one sub-result don't make compound
+      aResult = aSelFeature->firstResult()->shape();
+    }
+  }
+
+  //Get shape from result
+  if (!aResult.get())
+    aResult = theSel->value();
+  if (!aResult.get()) {
+    if (theSel->context().get())
+      aResult = theSel->context()->shape();
+  }
+
+  return aResult;
+}
diff --git a/src/OperaPlugin/OperaPlugin_Tools.h b/src/OperaPlugin/OperaPlugin_Tools.h
new file mode 100644 (file)
index 0000000..ba8b76e
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) 2014-2021  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 OperaPlugin_Tools_H_
+#define OperaPlugin_Tools_H_
+
+#include <GeomAPI_Face.h>
+#include <GeomAPI_Shape.h>
+
+#include <GeomAlgoAPI_MakeShape.h>
+#include <GeomAlgoAPI_MakeShapeCustom.h>
+#include <GeomAlgoAPI_MakeShapeList.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_ResultBody.h>
+
+GeomShapePtr shapeOfSelection(AttributeSelectionPtr theSel);
+
+#endif
index 57393a226d90bb89e5c6ee69e4e4c34988ee4e9d..5a2b69613e67294162c8eec26836020b1b7f7a13 100644 (file)
@@ -33,26 +33,6 @@ OperaPlugin_Volume::OperaPlugin_Volume() // Nothing to do during instantiation
 {
 }
 
-//=================================================================================================
-static GeomShapePtr shapeOfSelection(AttributeSelectionPtr theSel) {
-  GeomShapePtr aResult;
-  FeaturePtr aSelFeature = theSel->contextFeature();
-  if (aSelFeature.get()) {
-    if (aSelFeature->results().empty()) // if selected feature has no results, make nothing
-      return aResult;
-    if (aSelFeature->results().size() == 1) { // for one sub-result don't make compound
-      aResult = aSelFeature->firstResult()->shape();
-    }
-  }
-  if (!aResult.get())
-    aResult = theSel->value();
-  if (!aResult.get()) {
-    if (theSel->context().get())
-      aResult = theSel->context()->shape();
-  }
-  return aResult;
-}
-
 //=================================================================================================
 void OperaPlugin_Volume::initAttributes()
 {
index aca1a88156482398b807c9d6ba0d1129a502a869..88085affe8a44ca6339976bcec5f32f615db98c0 100644 (file)
   </context>
 
   <context>
-    <name>Volume:medium</name>
+    <name>AddNode</name>
+    <message>
+      <source>AddNode</source>
+      <translation>AddNode</translation>
+    </message>
+    <message>
+      <source>Perform OPERA Add Node</source>
+      <translation>Faire un AddNode OPERA</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>AddNode:medium</name>
     <message>
       <source>Medium</source>
       <translation>Milieu</translation>
     </message>
   </context>
 
+
+
+
+
+  <context>
+    <name>AddNode:main_object</name>
+    <message>
+      <source>Main object</source>
+      <translation>Objet Principal</translation>
+    </message>
+    <message>
+      <source>Select a main object</source>
+      <translation>Veuillez séléctioner un objet principal</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Volume:tools_list</name>
+    <message>
+      <source>Tools objects</source>
+      <translation>Outils</translation>
+    </message>
+    <message>
+      <source>Select solid objects as tools</source>
+      <translation>Sélectionnez les outils</translation>
+    </message>
+  </context>
+
+  <context>
+    <name>Volume:main_object</name>
+    <message>
+      <source>Attribute "%1" is not initialized.</source>
+      <translation>Sélectionnez un object principal.</translation>
+    </message>
+  </context>
+  <context>
+    <name>Volume:tools_list</name>
+    <message>
+      <source>Attribute "%2" is not initialized.</source>
+      <translation>Sélectionnez les outils.</translation>
+    </message>
+  </context>
+
 </TS>
diff --git a/src/OperaPlugin/Test/TestAddNode.py b/src/OperaPlugin/Test/TestAddNode.py
new file mode 100644 (file)
index 0000000..ca05738
--- /dev/null
@@ -0,0 +1,101 @@
+# Copyright (C) 2014-2021  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
+#
+
+"""
+      TestAddNode.py
+      Test case of OperaPlugin_AddNode
+"""
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create two box (one inside the other)
+Box_1 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_2 = model.addBox(Part_1_doc, 0, 0, 0, 10, 10, 10)
+
+### Create more boxes for error tests
+Box_3= model.addBox(Part_1_doc, 0, 0, 0, 10, 10, 10)
+Box_4 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_5 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_6 = model.addBox(Part_1_doc, 50, 50, 50, 10, 10, 10)
+Box_7 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_8 = model.addBox(Part_1_doc, 20, 0, 0, 10, 10, 10)
+Box_9 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_10 = model.addBox(Part_1_doc, 0, 0, 0, 10, 10, 10)
+Box_11 = model.addBox(Part_1_doc, 5, 5, 5, 10, 10, 10)
+Box_12 = model.addBox(Part_1_doc, 0, 0, 0, 20, 20, 20)
+Box_13 = model.addBox(Part_1_doc, 0, 0, 0, 10, 10, 10)
+Box_14 = model.addBox(Part_1_doc, 0, 0, 0, 5, 5, 5)
+
+
+### Create a volume from the cylinder and the sphere
+AddNode_1 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_1_1"), [model.selection("SOLID", "Box_2_1")])
+
+#Checks
+from GeomAPI import GeomAPI_Shape
+
+model.testNbResults(AddNode_1, 1)
+model.testNbSubResults(AddNode_1, [2])
+model.testNbSubShapes(AddNode_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(AddNode_1, GeomAPI_Shape.FACE, [18])
+model.testHaveNamingFaces(AddNode_1, model, Part_1_doc)
+
+### Create a AddNode with no main object
+AddNode_2 = model.addAddNode(Part_1_doc, model.selection("SOLID", "None"), [model.selection("SOLID", "Box_3_1")])
+model.testNbResults(AddNode_2, 0)
+assert(AddNode_2.feature().error() == "Attribute \"main_object\" is not initialized.")
+
+### Create a AddNode with no tools
+AddNode_3 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_4_1"), [])
+model.testNbResults(AddNode_3, 0)
+assert(AddNode_3.feature().error() == "Attribute \"tools_list\" is not initialized.")
+
+### Create a AddNode with tools outside the main object
+AddNode_4 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_5_1"), [model.selection("SOLID", "Box_6_1")])
+model.testNbResults(AddNode_4, 0)
+assert(AddNode_4.feature().error() == "Error: All tools must be fully inside the main object")
+
+### Create a AddNode with tools intersecting the main object
+AddNode_5 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_7_1"), [model.selection("SOLID", "Box_8_1")])
+model.testNbResults(AddNode_5, 0)
+assert(AddNode_5.feature().error() == "Error: All tools must be fully inside the main object")
+
+### Create a AddNode with intersecting tools
+AddNode_6 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_9_1"), [model.selection("SOLID", "Box_10_1"), model.selection("SOLID", "Box_11_1")])
+model.testNbResults(AddNode_6, 0)
+assert(AddNode_6.feature().error() == "Error: Tools must not intersect each others")
+
+### Create a AddNode with a tool inside another
+AddNode_7 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_12_1"), [model.selection("SOLID", "Box_13_1"), model.selection("SOLID", "Box_14_1")])
+model.testNbResults(AddNode_7, 0)
+assert(AddNode_7.feature().error() == "Error: Tools must not intersect each others")
+
+
+# TODO : Test with out of bounds tools
+# TODO : Test with intersected tools
+
+#=========================================================================
+# End of test
+#=========================================================================
diff --git a/src/OperaPlugin/addnode_widget.xml b/src/OperaPlugin/addnode_widget.xml
new file mode 100644 (file)
index 0000000..adf237d
--- /dev/null
@@ -0,0 +1,16 @@
+<source>
+  <shape_selector id="main_object"
+                  label="Main object"
+                  tooltip="Select a main object"
+                  shape_types="solids">
+    <validator id="GeomValidators_ShapeType" parameters="solid"/>
+  </shape_selector>
+  <multi_selector id="tools_list"
+                  label="Tools objects"
+                  tooltip="Select solid objects as tools"
+                  shape_types="solids"
+                  concealment="true">
+    <validator id="PartSet_DifferentObjects"/>
+    <validator id="GeomValidators_ShapeType" parameters="solid"/>
+  </multi_selector>
+</source>
index f61f280bdf90485c39c5db0d10508ad37dfdd01c..0e61c3302c1b8ede681c76602ec779ce41f9ecc1 100644 (file)
@@ -11,3 +11,4 @@ The Opera plug-in provides a set of common operations to ROOT geometry. It imple
    :maxdepth: 1
 
    volumeFeature.rst
+   addnodeFeature.rst
diff --git a/src/OperaPlugin/doc/TUI_addnode.rst b/src/OperaPlugin/doc/TUI_addnode.rst
new file mode 100644 (file)
index 0000000..fdd30ce
--- /dev/null
@@ -0,0 +1,11 @@
+
+  .. _tui_create_addnode:
+
+Create Add Node
+=============
+
+.. literalinclude:: examples/addnode.py
+    :linenos:
+    :language: python
+
+:download:`Download this script <examples/addnode.py>`
diff --git a/src/OperaPlugin/doc/addnodeFeature.rst b/src/OperaPlugin/doc/addnodeFeature.rst
new file mode 100644 (file)
index 0000000..1b28e4e
--- /dev/null
@@ -0,0 +1,43 @@
+.. |AddNode_button.icon|    image:: images/AddNode_button.png
+
+AddNode
+------
+
+AddNode feature perform an AddNode operation used in bulding the ROOT geometrical hierarchy.
+
+To create a AddNode in the active part:
+
+#. select in the Main Menu *Opera - > AddNode* item  or
+#. click |AddNode_button.icon| **AddNode** button in the toolbar:
+
+AddNode is created by a solid as main object and a list of solids as tools
+
+.. figure:: images/AddNode.png
+   :align: center
+
+Input fields:
+
+- **MainOject** defines the solid main object;
+- **Tools** defines the list of solid tools
+
+**TUI Command**:
+
+.. py:function::
+    model.addAddNode(Part_doc, model.selection("SOLID", main_object_name), model.selection[("SOLID", ...), ...])
+
+    :param part: The current part object.
+    :param object: A main object solid.
+    :param list: A list of tools solids.
+    :return: Result compound.
+
+Result
+""""""
+
+One compound with the boolean operation result and the tools objects below it, depending on geometry cases
+
+.. figure:: images/AddNode1.png
+   :align: center
+
+   AddNode created
+
+**See Also** a sample TUI Script of :ref:`tui_create_addnode` operation.
diff --git a/src/OperaPlugin/doc/examples/addnode.py b/src/OperaPlugin/doc/examples/addnode.py
new file mode 100644 (file)
index 0000000..8e8aea5
--- /dev/null
@@ -0,0 +1,14 @@
+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, 0, 0, 0, 20, 20, 20)
+Box_2 = model.addBox(Part_1_doc, 0, 0, 0, 10, 10, 10)
+
+AddNode_1 = model.addAddNode(Part_1_doc, model.selection("SOLID", "Box_1_1"), [model.selection("SOLID", "Box_2_1")])
+
+model.do()
+model.end()
diff --git a/src/OperaPlugin/doc/images/AddNode.png b/src/OperaPlugin/doc/images/AddNode.png
new file mode 100644 (file)
index 0000000..64a1755
Binary files /dev/null and b/src/OperaPlugin/doc/images/AddNode.png differ
diff --git a/src/OperaPlugin/doc/images/AddNode1.png b/src/OperaPlugin/doc/images/AddNode1.png
new file mode 100644 (file)
index 0000000..3df2991
Binary files /dev/null and b/src/OperaPlugin/doc/images/AddNode1.png differ
diff --git a/src/OperaPlugin/doc/images/AddNode_button.png b/src/OperaPlugin/doc/images/AddNode_button.png
new file mode 100644 (file)
index 0000000..9265aff
Binary files /dev/null and b/src/OperaPlugin/doc/images/AddNode_button.png differ
index 8ea5c85480358c963e881804d5a4095075afd11c..25e9ead045200d90998a2767f07c3d95582cdb09 100644 (file)
@@ -17,12 +17,12 @@ Volume is created by a value and a list of solids
 
 Input fields:
 
-- **Medium** defines the name of the medium; 
+- **Medium** defines the name of the medium;
 - **Objects** defines the list of solid objects
 
 **TUI Command**:
 
-.. py:function:: 
+.. py:function::
     model.addVolume(Part_doc, medium, model.selection[("SOLID", ...), ...])
 
     :param part: The current part object.
@@ -38,6 +38,6 @@ One solid for each selected solid in the volume list with according medium
 .. figure:: images/Volume1.png
    :align: center
 
-   Volume created  
+   Volume created
 
 **See Also** a sample TUI Script of :ref:`tui_create_volume` operation.
diff --git a/src/OperaPlugin/icons/AddNode.png b/src/OperaPlugin/icons/AddNode.png
new file mode 100644 (file)
index 0000000..457dc0f
Binary files /dev/null and b/src/OperaPlugin/icons/AddNode.png differ
index f16bf394b0218e0cfd07a44f8b4324de15645942..90fc01f3395236044abaa3093c200a26927a7aa6 100644 (file)
@@ -9,6 +9,14 @@
                helpfile="volumeFeature.html">
         <source path="volume_widget.xml"/>
       </feature>
+      <feature id="AddNode"
+               title="AddNode"
+               tooltip="Perform OPERA Add Node"
+               icon="icons/Opera/AddNode.png"
+               auto_preview="true"
+               helpfile="addnodeFeature.html">
+        <source path="addnode_widget.xml"/>
+      </feature>
     </group>
   </workbench>
 </plugin>
index 019d00b2f6438c69a3cd75923337998c026767b3..cd7e55f0d4a96a132f6273f1ae378efe802a9fb7 100644 (file)
@@ -19,4 +19,5 @@
 
 SET(TEST_NAMES
               TestVolume.py
+              TestAddNode.py
 )
index a13965476a47e75489087eb2fa529c0a336b4e2a..a1aa77d1da15c7fc661a5fb8d3e3acea7359577a 100644 (file)
@@ -20,3 +20,4 @@
 """
 
 from OperaAPI import addVolume
+from OperaAPI import addAddNode