Salome HOME
macro tuyauterie gni/tuyauterie_integ_2
authorGérald NICOLAS <gerald.nicolas@edf.fr>
Tue, 15 Jun 2021 09:16:43 +0000 (11:16 +0200)
committerAnthony Geay <anthony.geay@edf.fr>
Thu, 16 Sep 2021 05:44:23 +0000 (07:44 +0200)
41 files changed:
src/PythonAddons/CMakeLists.txt
src/PythonAddons/PythonAddons_msg_en.ts
src/PythonAddons/PythonAddons_msg_fr.ts [new file with mode: 0644]
src/PythonAddons/Test/TestRectangle.py [changed mode: 0644->0755]
src/PythonAddons/Test/TestRectangleCentered.py [changed mode: 0644->0755]
src/PythonAddons/Test/TestcompoundVertices.py [changed mode: 0644->0755]
src/PythonAddons/Test/TestimportParameters.py [changed mode: 0644->0755]
src/PythonAddons/Test/TestpipeNetwork_2par2.py [new file with mode: 0755]
src/PythonAddons/Test/TestpipeNetwork_parligne.py [new file with mode: 0755]
src/PythonAddons/__init__.py [changed mode: 0644->0755]
src/PythonAddons/addons_Features.py [changed mode: 0644->0755]
src/PythonAddons/addons_Features.xml.in
src/PythonAddons/doc/addons_Features.rst
src/PythonAddons/doc/examples/pipeNetwork.py [new file with mode: 0755]
src/PythonAddons/doc/examples/pipeNetwork_ligne.txt [new symlink]
src/PythonAddons/doc/examples/rectangle/feature.py [changed mode: 0644->0755]
src/PythonAddons/doc/images/compound.png [changed from file to symlink]
src/PythonAddons/doc/images/importParameters.png [changed from file to symlink]
src/PythonAddons/doc/images/pipeNetwork.png [new symlink]
src/PythonAddons/doc/images/pipeNetworkExemple.png [new file with mode: 0644]
src/PythonAddons/doc/images/pipeNetworkPanel.png [new file with mode: 0644]
src/PythonAddons/doc/images/pipeNetworkPanelHexa.png [new file with mode: 0644]
src/PythonAddons/doc/pipeNetworkFeature.rst [new file with mode: 0644]
src/PythonAddons/macros/__init__.py [changed mode: 0644->0755]
src/PythonAddons/macros/compoundVertices/__init__.py [changed mode: 0644->0755]
src/PythonAddons/macros/compoundVertices/feature.py [changed mode: 0644->0755]
src/PythonAddons/macros/compoundVertices/icons/compound.png [new file with mode: 0644]
src/PythonAddons/macros/compoundVertices/icons/import.png [deleted file]
src/PythonAddons/macros/compoundVertices/widget.xml
src/PythonAddons/macros/importParameters/__init__.py [changed mode: 0644->0755]
src/PythonAddons/macros/importParameters/feature.py [changed mode: 0644->0755]
src/PythonAddons/macros/importParameters/widget.xml
src/PythonAddons/macros/pipeNetwork/__init__.py [new file with mode: 0755]
src/PythonAddons/macros/pipeNetwork/feature.py [new file with mode: 0755]
src/PythonAddons/macros/pipeNetwork/icons/pipeNetwork.png [new file with mode: 0644]
src/PythonAddons/macros/pipeNetwork/pipeNetwork_2par2.txt [new file with mode: 0644]
src/PythonAddons/macros/pipeNetwork/pipeNetwork_ligne.txt [new file with mode: 0644]
src/PythonAddons/macros/pipeNetwork/widget.xml [new file with mode: 0644]
src/PythonAddons/macros/rectangle/__init__.py [changed mode: 0644->0755]
src/PythonAddons/macros/rectangle/feature.py [changed mode: 0644->0755]
src/PythonAddons/tests.set

index 289f365e7c9dfc1d90bdd0dcd97d047d7b7c901b..07d9bbd5eb37cd0008d6ff776487b5232be2f436 100644 (file)
@@ -19,6 +19,7 @@
 
 SET(TEXT_RESOURCES
        PythonAddons_msg_en.ts
+       PythonAddons_msg_fr.ts
 )
 
 # configuration
@@ -42,6 +43,7 @@ INSTALL(DIRECTORY macros DESTINATION ${SHAPER_INSTALL_ADDONS})
 INSTALL(DIRECTORY macros/rectangle/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons)
 INSTALL(DIRECTORY macros/compoundVertices/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons)
 INSTALL(DIRECTORY macros/importParameters/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons)
+INSTALL(DIRECTORY macros/pipeNetwork/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons)
 INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
 
 INCLUDE(UnitTest)
@@ -53,16 +55,16 @@ ADD_UNIT_TESTS(${TEST_NAMES})
 if(${HAVE_SALOME})
   enable_testing()
   set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/PythonAddons")
-  
+
   install(FILES CTestTestfileInstall.cmake
   DESTINATION ${TEST_INSTALL_DIRECTORY}
   RENAME CTestTestfile.cmake)
   install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY})
-  
+
   set(TMP_TESTS_NAMES)
   foreach(tfile ${TEST_NAMES})
     list(APPEND TMP_TESTS_NAMES "Test/${tfile}")
   endforeach(tfile ${TEST_NAMES})
-  
+
   install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY})
 endif(${HAVE_SALOME})
index 305ed4131767bf8eecf7e9502b42a027cc6122ac..2c39004e3e9230bc4f6a236f63cb970c6f9338d5 100644 (file)
@@ -1,4 +1,101 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TS>
 <TS version="2.0" language="en_US">
+
+  <!-- compoundVertices -->
+  <context>
+    <name>compoundVertices</name>
+    <message>
+      <source>Points set</source>
+      <translation>Import points</translation>
+    </message>
+    <message>
+      <source>Import a set of construction points</source>
+      <translation>Import a set of construction points</translation>
+    </message>
+  </context>
+  <context>
+    <name>compoundVertices:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Import txt file (X Y Z)</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Select the file of the points,
+      defined by their coordinates X Y Z</translation>
+    </message>
+  </context>
+  <context>
+    <name>compoundVertices:separator</name>
+    <message>
+      <source>Separator (optional):</source>
+      <translation>Separator (optional):</translation>
+    </message>
+    <message>
+      <source>"Select separator"</source>
+      <translation>Select a separator; the default value is white spaces.</translation>
+    </message>
+  </context>
+
+  <!-- importParameters -->
+  <context>
+    <name>importParameters</name>
+    <message>
+      <source>Import Parameters</source>
+      <translation>Import parameters</translation>
+    </message>
+    <message>
+      <source>Import a set of parameters</source>
+      <translation>Import a set of parameters</translation>
+    </message>
+  </context>
+  <context>
+    <name>importParameters:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Import file</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Select the file of the parameters,
+      defined by couples: name, value</translation>
+    </message>
+  </context>
+
+  <!-- pipeNetwork -->
+  <context>
+    <name>pipeNetwork</name>
+    <message>
+      <source>Pipe Network</source>
+      <translation>Pipe network</translation>
+    </message>
+    <message>
+      <source>Create</source>
+      <translation>Create a network of pipes</translation>
+    </message>
+  </context>
+  <context>
+    <name>pipeNetwork:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Text file of the network</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Select the text file of the network</translation>
+    </message>
+  </context>
+  <context>
+    <name>pipeNetwork:blocking</name>
+    <message>
+      <source>Hexa</source>
+      <translation>Mesh with hexadra</translation>
+    </message>
+    <message>
+      <source>Partition</source>
+      <translation>Partition of the CAD to mesh with hexadra</translation>
+    </message>
+  </context>
+
 </TS>
diff --git a/src/PythonAddons/PythonAddons_msg_fr.ts b/src/PythonAddons/PythonAddons_msg_fr.ts
new file mode 100644 (file)
index 0000000..01cebfc
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+
+  <!-- compoundVertices -->
+  <context>
+    <name>compoundVertices</name>
+    <message>
+      <source>Points set</source>
+      <translation>Importer des points</translation>
+    </message>
+    <message>
+      <source>Import a set of construction points</source>
+      <translation>Importer un ensemble de points de construction</translation>
+    </message>
+  </context>
+  <context>
+    <name>compoundVertices:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Fichier des points à importer (X Y Z)</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Choisir le fichier contenant les points à importer,
+      définis par leurs coordonnées X Y Z</translation>
+    </message>
+  </context>
+  <context>
+    <name>compoundVertices:separator</name>
+    <message>
+      <source>Separator (optional):</source>
+      <translation>Séparateur (optionnel) :</translation>
+    </message>
+    <message>
+      <source>"Select separator"</source>
+      <translation>Choisir éventuellement un séparateur ; par défaut ce sont des blancs.</translation>
+    </message>
+  </context>
+
+  <!-- importParameters -->
+  <context>
+    <name>importParameters</name>
+    <message>
+      <source>Import Parameters</source>
+      <translation>Importer des paramètres</translation>
+    </message>
+    <message>
+      <source>Import a set of parameters</source>
+      <translation>Importer un ensemble de paramètres</translation>
+    </message>
+  </context>
+  <context>
+    <name>importParameters:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Fichier des paramètres à importer</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Choisir le fichier contenant les paramètres à importer,
+      définis par les paires : nom, valeur</translation>
+    </message>
+  </context>
+
+  <!-- pipeNetwork -->
+  <context>
+    <name>pipeNetwork</name>
+    <message>
+      <source>Pipe Network</source>
+      <translation>Réseau de tuyaux</translation>
+    </message>
+    <message>
+      <source>Create</source>
+      <translation>Créer un réseau de tuyaux</translation>
+    </message>
+  </context>
+  <context>
+    <name>pipeNetwork:file_path</name>
+    <message>
+      <source>Import file</source>
+      <translation>Fichier texte de la description du réseau</translation>
+    </message>
+    <message>
+      <source>Select file</source>
+      <translation>Choisir le fichier texte de la description du réseau</translation>
+    </message>
+  </context>
+  <context>
+    <name>pipeNetwork:blocking</name>
+    <message>
+      <source>Hexa</source>
+      <translation>Pour mailler en hexaèdres</translation>
+    </message>
+    <message>
+      <source>Partition</source>
+      <translation>Partitionner la CAO pour mailler en hexaèdres</translation>
+    </message>
+  </context>
+
+</TS>
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/src/PythonAddons/Test/TestpipeNetwork_2par2.py b/src/PythonAddons/Test/TestpipeNetwork_2par2.py
new file mode 100755 (executable)
index 0000000..40fad6c
--- /dev/null
@@ -0,0 +1,51 @@
+# 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
+#
+"""Test de la création du réseau de tuyaux - Description des lignes par paquets de 2 noeuds"""
+
+__revision__ = "V02.01"
+
+import os
+
+from ModelAPI import *
+
+aSession = ModelAPI_Session.get()
+
+def getFilePath(fileName):
+    """Le fichier décrivant le réseau"""
+    path = os.path.join(os.getenv("SHAPER_ROOT_DIR"), "bin", "salome", "macros", "pipeNetwork")
+    return os.path.join(path, fileName)
+
+theFile = getFilePath("pipeNetwork_2par2.txt")
+
+aSession.startOperation("Create part for pipe network")
+aPartFeature = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+aPart = aSession.activeDocument()
+
+aSession.startOperation("Import file")
+aFeatureKind = "pipeNetwork"
+anImportFeature = aPart.addFeature(aFeatureKind)
+aFieldName = "file_path"
+aFile = anImportFeature.string(aFieldName)
+aFile.setValue(theFile)
+aSession.finishOperation()
+
+assert(aPart.size("Construction") == 42), "Right number of construction: {}".format(aPart.size("Construction"))
+
+assert(aPart.size("Folders") == 1), "Right number of folders: {}".format(aPart.size("Folders"))
diff --git a/src/PythonAddons/Test/TestpipeNetwork_parligne.py b/src/PythonAddons/Test/TestpipeNetwork_parligne.py
new file mode 100755 (executable)
index 0000000..f0f0d46
--- /dev/null
@@ -0,0 +1,51 @@
+# 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
+#
+"""Test de la création du réseau de tuyaux - Description par ligne entière"""
+
+__revision__ = "V01.04"
+
+import os
+
+from ModelAPI import *
+
+aSession = ModelAPI_Session.get()
+
+def getFilePath(fileName):
+    """Le fichier décrivant le réseau"""
+    path = os.path.join(os.getenv("SHAPER_ROOT_DIR"), "bin", "salome", "macros", "pipeNetwork")
+    return os.path.join(path, fileName)
+
+theFile = getFilePath("pipeNetwork_ligne.txt")
+
+aSession.startOperation("Create part for pipe network")
+aPartFeature = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+aPart = aSession.activeDocument()
+
+aSession.startOperation("Import file")
+aFeatureKind = "pipeNetwork"
+anImportFeature = aPart.addFeature(aFeatureKind)
+aFieldName = "file_path"
+aFile = anImportFeature.string(aFieldName)
+aFile.setValue(theFile)
+aSession.finishOperation()
+
+assert(aPart.size("Construction") == 46), "Right number of construction: {}".format(aPart.size("Construction"))
+
+assert(aPart.size("Folders") == 1), "Right number of folders: {}".format(aPart.size("Folders"))
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 64fbca8..4cef6a7
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-"""Registration of all user-defined Python features
-"""
+"""Registration of all user-defined Python features"""
 
 import ModelAPI
 from macros.rectangle.feature import SketchPlugin_Rectangle
 from macros.compoundVertices.feature import compoundVertices
 from macros.importParameters.feature import importParameters
+from macros.pipeNetwork.feature import pipeNetwork
 
 
 class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin):
@@ -49,6 +49,8 @@ class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin):
             aFeature = compoundVertices().__disown__()
         elif theFeatureID == importParameters.ID():
             aFeature = importParameters().__disown__()
+        elif theFeatureID == pipeNetwork.ID():
+            aFeature = pipeNetwork().__disown__()
         else:
             raise Exception("No such feature %s" % theFeatureID)
 
index 3f3b7666d7f1b41f33820f09202eaf5ddc8597c1..a164800b9b24c75bca3988509c7852a21c43b203 100644 (file)
@@ -2,4 +2,5 @@
   <source path="@ADDONS_FOLDER_PATH@/macros/rectangle/widget.xml"/>
   <source path="@ADDONS_FOLDER_PATH@/macros/compoundVertices/widget.xml"/>
   <source path="@ADDONS_FOLDER_PATH@/macros/importParameters/widget.xml"/>
+  <source path="@ADDONS_FOLDER_PATH@/macros/pipeNetwork/widget.xml"/>
 </plugin>
index 1db6329d641b948d2c99f16223f01903ea839a8c..aa463c383edde1b2c1c192be270e3dcd711b2cc0 100644 (file)
@@ -10,7 +10,7 @@ A feature description includes 4 files:
 
 - widget.xml with a description of the property panel,
 -  __init__.py,
-- feature.py with python commands, 
+- feature.py with python commands,
 - icon.png with image of button in the toolbar (the file is located at sub-folder /icons).
 
 Some examples of already created custom features are:
@@ -22,3 +22,4 @@ Some examples of already created custom features are:
    rectangleFeature.rst
    compoundVerticesFeature.rst
    importParametersFeature.rst
+   pipeNetworkFeature.rst
diff --git a/src/PythonAddons/doc/examples/pipeNetwork.py b/src/PythonAddons/doc/examples/pipeNetwork.py
new file mode 100755 (executable)
index 0000000..beee738
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""Exemple de création d'un objet SHAPER tuyauterie à partir d'une description dans un fichier txte
+
+Copyright 2021 EDF
+"""
+
+__revision__ = "V02.01"
+
+#=================================================================================
+# theFile = fichier texte de la description du réseau
+theFile = "/home/D68518/pipeNetwork_ligne.txt"
+#=================================================================================
+
+import salome
+salome.standalone()
+salome.salome_init()
+
+from ModelAPI import *
+
+aSession = ModelAPI_Session.get()
+
+# Création de la part pour accueillir le réseau
+aSession.startOperation("Create part for pipe network")
+aPartFeature = aSession.moduleDocument().addFeature("Part")
+aSession.finishOperation()
+aPart = aSession.activeDocument()
+
+# Importation et traitement du fichier
+aSession.startOperation("Import file")
+aFeatureKind = "pipeNetwork"
+anImportFeature = aPart.addFeature(aFeatureKind)
+aFieldName = "file_path"
+aFile = anImportFeature.string(aFieldName)
+aFile.setValue(theFile)
+aSession.finishOperation()
+
+if salome.sg.hasDesktop():
+  salome.sg.updateObjBrowser()
diff --git a/src/PythonAddons/doc/examples/pipeNetwork_ligne.txt b/src/PythonAddons/doc/examples/pipeNetwork_ligne.txt
new file mode 120000 (symlink)
index 0000000..73d64f4
--- /dev/null
@@ -0,0 +1 @@
+../../macros/pipeNetwork/pipeNetwork_ligne.txt
\ No newline at end of file
deleted file mode 100644 (file)
index 5e119b39a983359f202624c1e9c2a1878ca5df56..0000000000000000000000000000000000000000
Binary files a/src/PythonAddons/doc/images/compound.png and /dev/null differ
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..fe75a84da079b96758277102f438563d7f809362
--- /dev/null
@@ -0,0 +1 @@
+../../macros/compoundVertices/icons/compound.png
\ No newline at end of file
deleted file mode 100644 (file)
index 3b382b91c46c96f98cb71d0591892129fc2fb908..0000000000000000000000000000000000000000
Binary files a/src/PythonAddons/doc/images/importParameters.png and /dev/null differ
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..c5167fbcc0a456e2b6c2c361597802042c9c0f26
--- /dev/null
@@ -0,0 +1 @@
+../../macros/importParameters/icons/parameters.png
\ No newline at end of file
diff --git a/src/PythonAddons/doc/images/pipeNetwork.png b/src/PythonAddons/doc/images/pipeNetwork.png
new file mode 120000 (symlink)
index 0000000..6e1cab8
--- /dev/null
@@ -0,0 +1 @@
+../../macros/pipeNetwork/icons/pipeNetwork.png
\ No newline at end of file
diff --git a/src/PythonAddons/doc/images/pipeNetworkExemple.png b/src/PythonAddons/doc/images/pipeNetworkExemple.png
new file mode 100644 (file)
index 0000000..ab9e719
Binary files /dev/null and b/src/PythonAddons/doc/images/pipeNetworkExemple.png differ
diff --git a/src/PythonAddons/doc/images/pipeNetworkPanel.png b/src/PythonAddons/doc/images/pipeNetworkPanel.png
new file mode 100644 (file)
index 0000000..d80ec02
Binary files /dev/null and b/src/PythonAddons/doc/images/pipeNetworkPanel.png differ
diff --git a/src/PythonAddons/doc/images/pipeNetworkPanelHexa.png b/src/PythonAddons/doc/images/pipeNetworkPanelHexa.png
new file mode 100644 (file)
index 0000000..798b3fc
Binary files /dev/null and b/src/PythonAddons/doc/images/pipeNetworkPanelHexa.png differ
diff --git a/src/PythonAddons/doc/pipeNetworkFeature.rst b/src/PythonAddons/doc/pipeNetworkFeature.rst
new file mode 100644 (file)
index 0000000..02a4459
--- /dev/null
@@ -0,0 +1,105 @@
+.. _pipeNetwork:
+.. |pipeNetwork.icon|    image:: images/pipeNetwork.png
+
+Réseau de tuyaux
+================
+
+Cette macro crée les objets SHAPER correspondant à un réseau de tuyauteries décrit dans un fichier texte.
+
+Pour créer l'objet de la tuyauterie :
+
+#. Choisir dans le menu principal *Macros - > Réseau de tuyaux* ou
+#. Cliquer le bouton |pipeNetwork.icon| **Réseau de tuyaux** dans la barre des macros.
+
+Le menu suivant apparaît :
+
+.. figure:: images/pipeNetworkPanel.png
+   :align: center
+   :alt: Menu de création du réseau
+
+   Menu de création du réseau de tuyaux
+
+On doit fournir le fichier de type texte qui contient le réseau. Sa syntaxe est décrite plus bas.
+
+Syntaxe du fichier de données
+"""""""""""""""""""""""""""""
+
+Règles générales
+----------------
+
+- Chaque ligne commençant par # est ignorée
+- Une information par ligne
+- Sur une ligne, les données sont séparés par des blancs
+- Les données sont regroupées en 3 sections : les noeuds, la connectivité, les raccordements
+- Une section débute par **mot-clé section**
+
+Les noeuds
+----------
+
+- Repérage avec **nodes section**
+
+- Pour un noeud dont on donne les coordonnées en absolu :
+
+``Identifiant du noeud, le signe -, les 3 coordonnées``
+
+- Pour un noeud défini par rapport à un autre :
+
+``Identifiant du noeud, identifiant du noeud de départ, les 3 coordonnées de la translation``
+
+La connectivité
+---------------
+
+- Repérage avec **connectivity section**
+- Choix de la méthode de description avec **method=par_ligne** ou **method=2par2**
+
+- Pour la méthode en ligne :
+
+Chaque ligne est décrite par la suite de ses noeuds repérés par leurs identifiants :
+
+``Identifiant du noeud n°1, identifiant du noeud n°2, ..., identifiant du dernier noeud``
+
+- Pour la méthode 2 par 2 :
+
+Chaque tronçon est décrit par les 2 noeuds repérés par leurs identifiants :
+
+``Identifiant du noeud n°1 , identifiant du noeud n°2``
+
+Le raccordement entre tuyaux
+----------------------------
+
+- Repérage avec **fillets section**
+- Pour chaque noeud à la jonction de 2 tuyaux :
+
+Si la jonction est directe : ``Identifiant du noeud, angular_connection``
+
+Si la jonction est courbe : ``Identifiant du noeud, radius=xxx`` où xxx est le rayon de courbure.
+
+.. note::
+  Par défaut, la jonction entre deux tuyaux est directe, sans rayon de courbure. On peut donc se passer de l'information ``angular_connection``. Si toutes les jonctions sont directes, on peut se passer totalement de la rubrique **fillets section**.
+
+.. note::
+  Une jonction avec un rayon de courbure ne peut avoir lieu que sur un noeud auquel aboutit exactement 2 tuyaux. L'arc de cercle est tracé dans le plan formé par les deux tuyaux. Les deux tuyaux ne doivent donc pas être colinéaires.
+
+Exemple
+-------
+.. literalinclude:: examples/pipeNetwork_ligne.txt
+    :linenos:
+    :language: text
+
+.. figure:: images/pipeNetworkExemple.png
+   :align: center
+   :alt: Exemple de réseau
+
+   Exemple de réseau
+
+:download:`Téléchargement des données de cet exemple<examples/pipeNetwork_ligne.txt>`
+
+Le pilotage en TUI se fait ainsi :
+
+.. literalinclude:: examples/pipeNetwork.py
+    :linenos:
+    :language: python
+
+:download:`Téléchargement du pilotage en TUI<examples/pipeNetwork.py>`
+
+
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/src/PythonAddons/macros/compoundVertices/icons/compound.png b/src/PythonAddons/macros/compoundVertices/icons/compound.png
new file mode 100644 (file)
index 0000000..5e119b3
Binary files /dev/null and b/src/PythonAddons/macros/compoundVertices/icons/compound.png differ
diff --git a/src/PythonAddons/macros/compoundVertices/icons/import.png b/src/PythonAddons/macros/compoundVertices/icons/import.png
deleted file mode 100644 (file)
index 5e119b3..0000000
Binary files a/src/PythonAddons/macros/compoundVertices/icons/import.png and /dev/null differ
index c33e845dd1f9511d3560bbb6a32ca6207dceb280..8d15c8a3917dc1cae26afb7a11ca7370f6d0440b 100644 (file)
@@ -5,11 +5,11 @@
         id="compoundVertices"
         title="Points set"
         tooltip="Import a set of construction points"
-        icon="icons/Addons/import.png"
+        icon="icons/Addons/compound.png"
         helpfile="compoundVerticesFeature.html">
-        <file_selector id="file_path" title="Import txt file (X Y Z)" path="">
+        <file_selector id="file_path" title="Import file" tooltip="Select file" path="">
         </file_selector>
-        <stringvalue id="separator"  label="Separator (optional): ">
+        <stringvalue id="separator" label="Separator (optional):" tooltip="Select separator">
         </stringvalue>
       </feature>
     </group>
index 37e0208d7219019bc65ea5d064b2eb1c7c3ece20..6d495416595f109844f76f98c4d16d28f6d5eb5d 100644 (file)
@@ -2,11 +2,11 @@
   <workbench id="Macros" document="Part">
     <group id="Samples">
       <feature id="importParameters"
-        title="List of Parameters"
+        title="Import Parameters"
         tooltip="Import a set of parameters"
         icon="icons/Addons/parameters.png"
         helpfile="importParametersFeature.html">
-        <file_selector id="file_path" title="Import file" path="">
+        <file_selector id="file_path" title="Import file" tooltip="Select file" path="">
         </file_selector>
       </feature>
     </group>
diff --git a/src/PythonAddons/macros/pipeNetwork/__init__.py b/src/PythonAddons/macros/pipeNetwork/__init__.py
new file mode 100755 (executable)
index 0000000..2614b9c
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (C) 2016-2020  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
+#
+
diff --git a/src/PythonAddons/macros/pipeNetwork/feature.py b/src/PythonAddons/macros/pipeNetwork/feature.py
new file mode 100755 (executable)
index 0000000..a226320
--- /dev/null
@@ -0,0 +1,817 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2016-2020  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
+#
+
+"""pipeNetwork Feature
+Author: Nathalie GORE - Gérald NICOLAS
+Remarque : la fonction de partitionnement pour un futur maillage en hexa est désactivée.
+"""
+
+__revision__ = "V02.17"
+
+from salome.shaper import model
+import ModelAPI
+from GeomAPI import *
+
+import numpy as np
+
+# Si erreur :
+
+def raiseException(texte):
+    """En cas d'erreur"""
+    print (texte)
+
+def printverbose (texte, nb=0, verbose=False):
+    """Impression controlée"""
+    if verbose:
+        if nb:
+            texte_a = ""
+            for _ in range(nb):
+                texte_a += "="
+            print (texte_a)
+        print (texte)
+
+class pipeNetwork(model.Feature):
+    """Creation of a network of pipes"""
+    lfeatures = list()
+    ledges = list()
+    folder = None
+    isHexa = False
+    twopartwo = "2par2"
+    parligne = "par_ligne"
+    radius = 0.5
+    infoPoints = dict()
+    connectivities = dict()
+
+    _verbose = False
+    _verbose_max = False
+
+# Feature initializations
+
+    def __init__(self):
+        """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
+        model.Feature.__init__(self)
+
+    @staticmethod
+    def ID():
+        """Return Id of the Feature."""
+        return "pipeNetwork"
+
+    @staticmethod
+    def FILE_ID():
+        """Returns ID of the file select parameter."""
+        return "file_path"
+
+    #@staticmethod
+    #def HEXAS_ID():
+        #"""Returns ID of the radius parameter."""
+        #return "blocking"
+
+    def getKind(self):
+        """Override Feature.getKind()"""
+        return pipeNetwork.ID()
+
+
+#====================================================================================
+# Initialization of the dialog panel
+
+    def initAttributes(self):
+        """Override Feature.initAttributes()"""
+        # Creating the input argument of the feature
+        self.data().addAttribute(self.FILE_ID(), ModelAPI.ModelAPI_AttributeString_typeId())
+        #self.data().addAttribute(self.HEXAS_ID(), ModelAPI.ModelAPI_AttributeBoolean_typeId())
+
+#====================================================================================
+# Retrieve parent pipe
+
+    def decodingCode(self, code):
+        """decodingCode"""
+        splitCode = code.split(".")
+        if len(splitCode) <= 1:
+            previousCode = ""
+        else:
+            previousCode = code[:len(code)-len(splitCode[-1])-1]
+        return previousCode
+
+#====================================================================================
+
+    def readNodeInfo(self, line):
+        """Lecture des noeuds
+
+La ligne à décoder est formée des informations :
+. l'identifiant du noeud
+. si les coordonnées sont données en absolu : "-" suivi des 3 coordonnées
+. si les coordonnées sont données en relatif : l'identifiant du noeud de départ, suivi des 3 coordonnées de la translation
+Par défaut, on supposera que la connection est angulaire et que ce n'est pas une extrémité.
+        """
+        #print(line)
+        texte = line
+        splitLine = line.split()
+        if ( len(splitLine) != 5 ):
+            diagno = 1
+        elif splitLine[0] in self.infoPoints:
+            texte += "\nThis node was already declared."
+            diagno = 2
+        elif ( splitLine[1] not in self.infoPoints ) and ( splitLine[1] != "-" ):
+            texte += "\nThe starting point was not seen before."
+            diagno = 3
+        else:
+            diagno = 0
+            self.infoPoints[splitLine[0]] = dict()
+            self.infoPoints[splitLine[0]]["Ref"] = splitLine[1]
+            if splitLine[1] == "-":
+                self.infoPoints[splitLine[0]]["X"] = float(splitLine[2])
+                self.infoPoints[splitLine[0]]["Y"] = float(splitLine[3])
+                self.infoPoints[splitLine[0]]["Z"] = float(splitLine[4])
+            else :
+                self.infoPoints[splitLine[0]]["X"] = self.infoPoints[splitLine[1]]["X"] + float(splitLine[2])
+                self.infoPoints[splitLine[0]]["Y"] = self.infoPoints[splitLine[1]]["Y"] + float(splitLine[3])
+                self.infoPoints[splitLine[0]]["Z"] = self.infoPoints[splitLine[1]]["Z"] + float(splitLine[4])
+            printverbose ("Enregistrement du point ({},{},{})".format(self.infoPoints[splitLine[0]]["X"],self.infoPoints[splitLine[0]]["Y"],self.infoPoints[splitLine[0]]["Z"]), verbose=self._verbose)
+            self.infoPoints[splitLine[0]]["Fillet"] = "angular_connection"
+            self.infoPoints[splitLine[0]]["isEnd"] = False
+        #print ("Retour de readNodeInfo = {}".format(diagno))
+        return diagno, texte
+
+#====================================================================================
+
+    def readConnectivity(self, line, method):
+        """Lecture des connectivités
+
+La ligne à décoder est formée des informations :
+. si la méthode est par ligne : la liste des identifiants des noeuds formant le trajet
+. si la méthode est 2 par 2 : chaque tronçon est décrit par les identifiants des 2 noeuds
+Par défaut, on supposera que la méthode est par ligne.
+        """
+        splitLine = line.split()
+        printverbose ("Enregistrement du tronçon : {}".format(splitLine),verbose=self._verbose)
+        diagno = 0
+        if ( method == self.twopartwo ):
+            if self.connectivities:
+                # Recherche si le tronçon existe déjà ou s'il est nouveau
+                existe = False
+                for key, val in self.connectivities.items():
+                    #print(key, " ******* {}".format(val))
+                    if val['chainage'][-1] == splitLine[0]:
+                        # Le tronçon existe
+                        val['chainage'].append(splitLine[1])
+                        #print("On complète le tronçon")
+                        existe = True
+                        break
+                # Le tronçon n'existe pas
+                if not existe:
+                    #print("On démarre un nouveau tronçon - Cas 2")
+                    self.newConnectivity(splitLine[0], splitLine)
+            else :
+                #print("On démarre un nouveau tronçon - Cas 1")
+                self.newConnectivity(splitLine[0], splitLine)
+        else :
+            self.newConnectivity(splitLine[0], splitLine)
+        #print ("Retour de readConnectivity = {}".format(diagno))
+
+        return diagno
+
+#====================================================================================
+
+    def correctConnectivity(self):
+        """Correction des connectivités pour tenir compte de points alignés
+
+Si 3 points sont alignés sur une ligne et qu'aucune ligne ne part du point central,
+il faut scinder la ligne au niveau de ce point pour traiter correctement la suite : on se mettrait
+à créer un plan avec ces 3 points alignés et tout s'effondre ensuite.
+        """
+        while True:
+            # On explore toutes les lignes et on cherche un cas où sur une ligne 3 points consécutifs sont alignés
+            for _, value in self.connectivities.items():
+                # Sur cette ligne, a-t-on 3 points consécutifs alignés ?
+                modif = self.correctConnectivity_a(value["chainage"])
+                # Si on a modifié la description des connectivités, on recommence l'analyse
+                if modif:
+                    break
+            # Si plus rien n'a été modifié, c'est fini
+            if not modif:
+                break
+
+    def correctConnectivity_a(self, l_noeuds):
+        """On explore toutes les lignes et on cherche un cas où sur une ligne 3 points consécutifs sont alignés
+
+Entrées :
+  :l_noeuds: liste des noeuds de la ligne
+
+Sorties :
+  :modif: on a modifié ou non la description des lignes
+        """
+        modif = False
+        nb_points = len(l_noeuds)
+        printverbose ("Analyse de {}".format(l_noeuds), verbose=self._verbose_max)
+        #print ("nb_points = {}".format(nb_points))
+
+        indice = 0
+        nb_test = nb_points - 2
+        for iaux in range(nb_test):
+            # Calcul de l'angle entre les 3 points de la séquence
+            vect = list()
+            #print ("({},{},{}".format(l_noeuds[iaux],l_noeuds[iaux+1],l_noeuds[iaux+2]))
+            for jaux in range(3):
+                coox = self.infoPoints[l_noeuds[iaux+jaux]]["X"]
+                cooy = self.infoPoints[l_noeuds[iaux+jaux]]["Y"]
+                cooz = self.infoPoints[l_noeuds[iaux+jaux]]["Z"]
+                vect.append(np.array((coox,cooy,cooz),np.float))
+            cosinus = np.dot(vect[1]-vect[0],vect[1]-vect[2])/(np.linalg.norm(vect[1]-vect[0])* np.linalg.norm(vect[1]-vect[2]))
+            #print ("cosinus = {}".format(cosinus))
+            # Si l'angle est plat, c'est que les 3 points sont alignés : on arrête... sauf si ce point est un départ d'une autre !
+            if ( (1.-np.abs(cosinus)) < 1.e-4 ):
+                indice = iaux+1
+                if l_noeuds[indice] not in self.connectivities:
+                    break
+                else:
+                    indice = 0
+        # Si un angle plat a été trouvé, on scinde la ligne
+        if indice:
+            #print ("id_noeud_debut = {}, {}".format(l_noeuds[0], l_noeuds[:indice+1]))
+            #print ("id_noeud_new   = {}, {}".format(l_noeuds[indice], l_noeuds[indice:]))
+            self.newConnectivity(l_noeuds[0], l_noeuds[:indice+1])
+            self.newConnectivity(l_noeuds[indice], l_noeuds[indice:])
+            modif = True
+
+        return modif
+
+#====================================================================================
+
+    def newConnectivity(self, key, value):
+        """newConnectivity"""
+        self.connectivities[key] = dict()
+        self.connectivities[key]['chainage'] = value
+
+#====================================================================================
+
+    def readFillet(self, line):
+        """Décodage des caractéristiques de la connection entre deux tuyaux
+
+La ligne est formée de deux informations :
+. l'identifiant du noeud
+. la caractérisation de la connection : "angular_connection" ou "radius=xxx"
+        """
+        splitLine = line.split()
+        if len(splitLine) != 2:
+            print(line)
+            diagno = 1
+        elif not splitLine[0] in self.infoPoints:
+            print(line)
+            diagno = 2
+        elif splitLine[1] == "angular_connection":
+            self.infoPoints[splitLine[0]]["Fillet"] = "angular_connection"
+            diagno = 0
+        elif splitLine[1][:7] == "radius=":
+            self.infoPoints[splitLine[0]]["Fillet"] = "radius"
+            self.infoPoints[splitLine[0]]["Radius"] = float(splitLine[1][7:])
+            diagno = 0
+        else:
+            print(line)
+            diagno = 3
+        #print ("Retour de readFillet = {}".format(diagno))
+        return diagno
+
+#====================================================================================
+
+    def retrieveSubshapesforWire(self, copy, key, ind):
+        """retrieveSubshapesforWire"""
+        exp = GeomAPI_ShapeExplorer(copy.defaultResult().shape(), GeomAPI_Shape.EDGE)
+
+        end = False
+        subshapesForWire = list()
+        currentInd = 0
+        isPipe = True
+        #print("Current chainage : {}".format(self.connectivities[key]['chainage'][ind:]))
+        #print("Indice de démarrage = {}".format(ind))
+
+        while exp.more() and not end :
+            #print("Analyse Edge n°", currentInd)
+            #print(" => ", self.connectivities[key]['chainage'][currentInd], " - ", self.connectivities[key]['chainage'][currentInd+1])
+            #print(" ==> ", self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"], " - ", self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isAngular"])
+            cur = exp.current().edge()
+            if currentInd < ind:
+                #print("Edge non prise en compte")
+                #print("test si fillet : ", currentInd+1, ind, self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"])
+                if currentInd+1 <= ind and self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"] == "radius" and not self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"]:
+                    #print("Fillet à ne pas prendre en compte")
+                    exp.next()
+                    cur = exp.current().edge()
+            else :
+                subshapesForWire.append(model.selection(copy.defaultResult(), cur))
+                #print("Mode normal - Nb segments dans le wire : {}".format(len(subshapesForWire)))
+                # Cas du fillet : on récupère l'edge suivante
+                if self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"] or self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isAngular"]:
+                    end = True
+                    #print("Nb segments dans le wire : {}".format(len(subshapesForWire)))
+                    if ( len(subshapesForWire) == 1 ):
+                        #print("Coude droit en cours")
+                        currentInd += 1
+                        isPipe = False
+                    else :
+                        #print("Coude droit à venir")
+                        subshapesForWire = subshapesForWire[:-1]
+                elif self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["Fillet"] == "radius":
+                    #print("Ajout edge start Fillet")
+                    exp.next()
+                    cur = exp.current().edge()
+                    subshapesForWire.append(model.selection(copy.defaultResult(), cur))
+                    #currentInd = currentInd+1
+                    #print("Mode Fillet - Nb segments dans le wire : {}".format(len(subshapesForWire)))
+                elif self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"] == "radius":
+                    #print("Ajout edge end Fillet")
+                    exp.next()
+                    cur = exp.current().edge()
+                    subshapesForWire.append(model.selection(copy.defaultResult(), cur))
+                    #print("Mode Fillet - Nb segments dans le wire : {}".format(len(subshapesForWire)))
+                else :
+                    if self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isEnd"]:
+                        #print("Fin détecte")
+                        currentInd = currentInd+1
+                        end = True
+                    #else :
+                        #print("Branchement")
+            if not end:
+                currentInd = currentInd+1
+            exp.next()
+            #print("End = {} {}".format(end,self.connectivities[key]['chainage'][currentInd]))
+
+        return subshapesForWire, currentInd, isPipe, self.connectivities[key]['chainage'][currentInd]
+
+#====================================================================================
+
+    def retrieveLastElement(self, obj, typeOfElement):
+        """retrieveLastElement"""
+        exp = GeomAPI_ShapeExplorer(obj.defaultResult().shape(), typeOfElement)
+        while exp.more():
+            cur = None
+            if typeOfElement == GeomAPI_Shape.VERTEX :
+                cur = exp.current().vertex()
+            elif typeOfElement == GeomAPI_Shape.EDGE :
+                cur = exp.current().edge()
+            elif typeOfElement == GeomAPI_Shape.FACE :
+                cur = exp.current().face()
+            elif typeOfElement == GeomAPI_Shape.SOLID :
+                cur = exp.current().solid()
+            if cur is not None:
+                exp.next()
+                cur = model.selection(obj.defaultResult(), cur)
+        return cur
+
+#====================================================================================
+
+    def retrieveFirstElement(self, obj, typeOfElement):
+        """retrieveFirstElement"""
+        exp = GeomAPI_ShapeExplorer(obj.defaultResult().shape(), typeOfElement)
+        cur = None
+        if typeOfElement == GeomAPI_Shape.VERTEX :
+            cur = exp.current().vertex()
+        elif typeOfElement == GeomAPI_Shape.EDGE :
+            cur = exp.current().edge()
+        elif typeOfElement == GeomAPI_Shape.FACE :
+            cur = exp.current().face()
+        elif typeOfElement == GeomAPI_Shape.SOLID :
+            cur = exp.current().solid()
+        if cur is not None:
+            exp.next()
+            cur = model.selection(obj.defaultResult(), cur)
+        return cur
+
+#====================================================================================
+
+    def createPipe(self, part, connectivityInfos):
+        """createPipe"""
+        lPipes = list()
+        startFace = None
+        fuse = None
+        for ind in range(len(connectivityInfos['paths'])):
+            printverbose ("Step = {}".format(ind), 80, verbose=self._verbose_max)
+            if ind == 0:
+                startFace = connectivityInfos['sketch']
+            if connectivityInfos['isPipe'][ind] :
+                pipe = model.addPipe(part, [startFace], connectivityInfos['paths'][ind].result())
+            else :
+                # recherche du plan
+                if self.infoPoints[connectivityInfos['ends'][ind]]['isAngular']:
+                    pipe = model.addExtrusion(part, [startFace], model.selection(), self.infoPoints[connectivityInfos['ends'][ind]]['plane'], 0, model.selection(), 0, "Faces|Wires")
+                else :
+                    # le plan cible n'existe pas
+                    edge = model.addAxis(part, self.infoPoints[connectivityInfos['starts'][ind]]['point'], self.infoPoints[connectivityInfos['ends'][ind]]['point'])
+                    edge.execute(True)
+                    self.lfeatures.append(edge)# self.retrieveFirstElement(connectivityInfos['paths'][ind], GeomAPI_Shape.EDGE)
+                    self.ledges.append(edge)
+                    point = self.retrieveLastElement(connectivityInfos['paths'][ind], GeomAPI_Shape.VERTEX)
+                    plane = model.addPlane(part, edge.result(), point, True)
+                    plane.execute(True)
+                    self.lfeatures.append(plane)
+                    pipe = model.addExtrusion(part, [startFace], edge.result(), plane.result(), 0, model.selection(), 0, "Faces|Wires")
+            pipe.execute(True)
+            self.lfeatures.append(pipe)
+            lPipes.append(pipe.result())
+            if ( ind < len(connectivityInfos['paths'])-1 ):
+                copy = model.addCopy(part, [model.selection(pipe.defaultResult())], 1)
+                copy.execute(True)
+                self.lfeatures.append(copy)
+                startFace = self.retrieveLastElement(copy, GeomAPI_Shape.FACE)
+
+        if len(lPipes) > 1 :
+            fuse = model.addFuse(part, lPipes, False)
+            fuse.execute(True)
+            self.lfeatures.append(fuse)
+        else :
+            return pipe
+        return fuse
+
+#==========================================================
+
+#==========================================================
+# Création des différents éléments
+    def createPoints(self, part):
+        """Création des points
+
+Le point est créé en tant qu'objet de construction avec ses coordonnées.
+Il est nommé conformément au texte donné dans le fichier de données. Cela n'a qu'un intérêt graphique mais agréable en débogage.
+"""
+        print("========================= Création des noeuds ============================")
+        for key, value in self.infoPoints.items():
+            printverbose ("Noeud : '{}'".format(key), verbose=self._verbose)
+            point = model.addPoint(part, value['X'], value['Y'], value['Z'])
+            point.execute(True)
+            point.setName(key)
+            point.result().setName(key)
+            self.lfeatures.append(point)
+            value["point"] = point.result()
+
+    def createPolylines(self, part):
+        """Création des polylines
+
+La polyligne est créée en tant que résultat en enchaînant ses points.
+Elle est nommée conformément aux 1er et dernier noeud. Cela n'a qu'un intérêt graphique mais agréable en débogage.
+"""
+        print("========================= Création des polylines =========================")
+        for key, value in self.connectivities.items():
+            printverbose ("Ligne : {}".format(value['chainage']), verbose=self._verbose)
+            lPoints = list()
+            for id_noeud in value['chainage']:
+                lPoints.append(self.infoPoints[id_noeud]["point"])
+                id_noeud_fin = id_noeud
+            polyline = model.addPolyline3D(part, lPoints, False)
+            polyline.execute(True)
+            nom = "L_{}_{}".format(key,id_noeud_fin)
+            polyline.setName(nom)
+            polyline.result().setName(nom)
+            self.lfeatures.append(polyline)
+            value["polyline"] = polyline
+
+    def createFillets(self, part):
+        """Création des fillets
+
+Le fillet est créé en tant que résultat.
+Il est nommé conformément au noeud d'application. Cela n'a qu'un intérêt graphique mais agréable en débogage.
+"""
+        print("========================= Création des fillets ===========================")
+        for key, value in self.connectivities.items():
+            printverbose ("Examen de la ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
+            # recherche des noeuds fillets
+            value["fillet"] = value["polyline"]
+            for id_noeud in value['chainage']:
+                if self.infoPoints[id_noeud]["Fillet"] == "radius" :
+                    printverbose ("\tFillet sur le noeud '{}'".format(id_noeud), verbose=self._verbose)
+                    fillet1D = model.addFillet(part, [model.selection("VERTEX", (self.infoPoints[id_noeud]["X"],self.infoPoints[id_noeud]["Y"],self.infoPoints[id_noeud]["Z"]))], self.infoPoints[id_noeud]["Radius"])
+                    fillet1D.execute(True)
+                    nom = "F_{}".format(id_noeud)
+                    fillet1D.setName(nom)
+                    fillet1D.result().setName(nom)
+                    self.lfeatures.append(fillet1D)
+                    value["fillet"] = fillet1D
+
+#==========================================================
+
+    def searchRightConnections(self, part):
+        """Recherche des coudes droits"""
+        print("========================= Recherche des coudes droits ====================")
+        for key, value in self.connectivities.items():
+            printverbose ("Examen de la ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
+            # recherche des noeuds fillets
+            for ind, id_noeud in enumerate(value['chainage']):
+                printverbose ("\tNoeud '{}' : {}".format(id_noeud,self.infoPoints[id_noeud]["Fillet"]), verbose=self._verbose)
+                if ( ( ind == 0 ) or ( ind == len(value['chainage'])-1 ) ):
+                    self.infoPoints[id_noeud]["isAngular"] = False
+                else :
+                    if self.infoPoints[id_noeud]["Fillet"] == "radius" :
+                        self.infoPoints[id_noeud]["isAngular"] = False
+                    else :
+                        if id_noeud in self.connectivities:
+                            self.infoPoints[id_noeud]["isAngular"] = False
+                        else :
+                            self.infoPoints[id_noeud]["isAngular"] = True
+                            # Axe d'extrusion
+                            #print(ind-1, ind, ind+1)
+                            printverbose ("\t\tCréation du plan passant par les points : ('{}','{}','{}')".format(value["chainage"][ind-1], id_noeud, value["chainage"][ind+1]), verbose=self._verbose)
+                            #print(self.infoPoints[value["chainage"][ind-1]]["point"])
+
+                            tmpPlane = model.addPlane(part, self.infoPoints[value["chainage"][ind-1]]["point"], self.infoPoints[id_noeud]["point"], self.infoPoints[value["chainage"][ind+1]]["point"])
+                            tmpPlane.execute(True)
+                            self.lfeatures.append(tmpPlane)
+                            axis =  model.addAxis(part, tmpPlane.result(), self.infoPoints[id_noeud]["point"])
+                            axis.execute(True)
+                            self.lfeatures.append(axis)
+                            self.infoPoints[id_noeud]["axis"] = axis.result()
+
+                            # Edge à extruder
+                            tmpEdge = model.addEdge(part, self.infoPoints[id_noeud]["point"], self.infoPoints[value["chainage"][ind+1]]["point"])
+                            tmpEdge.execute(True)
+                            self.lfeatures.append(tmpEdge)
+                            length = model.measureDistance(part, self.infoPoints[value["chainage"][ind-1]]["point"], self.infoPoints[id_noeud]["point"])
+                            point =  model.addPoint(part, tmpEdge.result(), length, False, False)
+                            point.execute(True)
+                            self.lfeatures.append(point)
+                            baseEdge = model.addEdge(part, self.infoPoints[value["chainage"][ind-1]]["point"], point.result())
+                            baseEdge.execute(True)
+                            self.lfeatures.append(baseEdge)
+                            middlePoint = model.addPoint(part, baseEdge.result(), 0.5, True, False)
+                            middlePoint.execute(True)
+                            self.lfeatures.append(middlePoint)
+                            Edge = model.addEdge(part, self.infoPoints[id_noeud]["point"], middlePoint.result())
+                            Edge.execute(True)
+                            self.lfeatures.append(Edge)
+                            self.ledges.append(Edge)
+
+                            # Extrusion
+                            plane = model.addExtrusion(part, [Edge.result()], axis.result(), 10, 0)
+                            plane.execute(True)
+                            self.lfeatures.append(plane)
+                            self.infoPoints[id_noeud]["plane"] = plane.result()
+
+    def createPaths(self, part):
+        """Création des paths pour le pipeNetwork"""
+        print("========================= Création des paths =============================")
+        for key, value in self.connectivities.items():
+            printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
+            # recherche des noeuds fillets
+            value["paths"] = list()
+            value["isPipe"] = list()
+            value["starts"] = list()
+            value["ends"] = list()
+            ind = 0
+            copy = value['fillet']
+            while ind < len(value['chainage'])-1:
+                value["starts"].append(self.connectivities[key]['chainage'][ind])
+                objectsForPath, ind, isPipe, end_noeud = self.retrieveSubshapesforWire(copy, key, ind)
+                if self._verbose_max:
+                    print("************************* ind = {}".format(ind))
+                    print("************************* objectsForPath = {}".format(objectsForPath))
+                path = model.addWire(part, objectsForPath, False)
+                path.execute(True)
+                self.lfeatures.append(path)
+                value["paths"].append(path)
+                value["isPipe"].append(isPipe)
+                value["ends"].append(end_noeud)
+                if ind < len(value['chainage'])-1:
+                    copy = model.addCopy(part, [model.selection(copy.defaultResult())], 1)
+                    copy.execute(True)
+                    self.lfeatures.append(copy)
+
+    def createSketches(self, part):
+        """Création des sketchs"""
+        print("========================= Création des sketchs =========================")
+        for key, value in self.connectivities.items():
+            printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
+            # Creating sketch
+            edge = model.addEdge(part, self.infoPoints[value["chainage"][0]]["point"], self.infoPoints[value["chainage"][1]]["point"])
+            edge.execute(True)
+            self.lfeatures.append(edge)
+            plane = model.addPlane(part, edge.result(), self.infoPoints[value["chainage"][0]]["point"], True)
+            plane.execute(True)
+            self.lfeatures.append(plane)
+            sketch = model.addSketch(part, plane.result())
+            sketch.execute(True)
+            self.lfeatures.append(sketch)
+            SketchProjection = sketch.addProjection(self.infoPoints[value["chainage"][0]]["point"], False)
+            SketchProjection.execute(True)
+            SketchPoint = SketchProjection.createdFeature()
+            SketchPoint.execute(True)
+            SketchCircle = sketch.addCircle(0,0,self.radius)
+            SketchCircle.execute(True)
+            sketch.setCoincident(SketchPoint.result(), SketchCircle.center())
+            sketch.setRadius(SketchCircle.results()[1], self.radius)
+            sketch.execute(True)
+            model.do()
+            value["sketch"] = sketch.result()
+
+    def createPipes(self, part, nameRes):
+        """Création des pipes"""
+        print("========================= Création des pipes =========================")
+        for key, value in self.connectivities.items():
+            printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
+            pipe = self.createPipe(part, value)
+            value["pipe"] = pipe.result()
+
+        # Fusion des pipes
+        print("========================= Fusion des pipes =========================")
+        lPipes = list()
+        for key, value in self.connectivities.items():
+            lPipes.append(value["pipe"])
+        if len(lPipes) > 1 :
+            fuse = model.addFuse(part, lPipes, False)
+            fuse.execute(True)
+            fuse.setName(nameRes)
+            fuse.result().setName(nameRes)
+        else:
+            lPipes[0].setName(nameRes)
+
+#==========================================================
+
+    def print_info (self, verbose, comment=""):
+        """Impression si verbose est valide. Avec un comentaire introductif éventuellement."""
+        if verbose:
+            texte = "\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
+            texte += "\nRécapitulatif"
+            if comment:
+                texte += " {}".format(comment)
+            texte += "\ninfos points ="
+            for key, value in self.infoPoints.items():
+                texte += "\n{} : {}".format(key, value)
+            texte += "\nconnectivities ="
+            for key, value in self.connectivities.items():
+                texte += "\n{} : {}".format(key, value)
+            texte += "\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
+            print(texte+"\n")
+
+#==========================================================
+
+# Execution of the Import
+
+    def execute(self):
+        """F.execute() -- execute the Feature"""
+        # Retrieving the user input
+        apath    = self.string(self.FILE_ID())
+
+        filepath = apath.value()
+        if filepath != "" :
+
+            # A. Initialisation
+            part = model.activeDocument()
+
+            if self.lfeatures :
+                for feature in self.lfeatures:
+                    part.removeFeature(feature.feature())
+                self.lfeatures = list()
+                model.removeFolder(self.folder)
+
+            self.infoPoints = dict()
+            self.connectivities = dict()
+
+            from os.path import basename
+            filename = basename(filepath)
+            if ( "." in filename ):
+                laux= filename.split(".")
+                nameRes = laux[0]
+                for saux in laux[1:-1]:
+                    nameRes+="."+saux
+            else:
+                nameRes = filename
+
+            # Creating the construction points in the current document
+
+            # B. Traitement du fichier
+            print ("\n=============== Traitement du fichier {}".format(filepath))
+            error = 0
+            while True:
+
+                # B.1. Lecture du fichier
+                with open(filepath) as afile:
+                    summary = 0
+                    method = self.parligne
+                    for line in afile:
+                        printverbose  (line[:-1], verbose=self._verbose_max)
+
+                        # B.1.1. Repérages
+                        if line == "\n":
+                            printverbose ("========================= Saut de ligne =========================", verbose=self._verbose_max)
+                            continue
+                        if line[0] == "#" or line[:3] == "...":
+                            continue
+                        if summary == 0 and line[:-1] == "nodes section" :
+                            printverbose ("========================= Lecture des coordonnées ==============================", 80, verbose=self._verbose)
+                            summary = 1
+                            continue
+                        if summary == 1 and line[:-1] == "connectivity section" :
+                            printverbose ("========================= Lecture de la connectivité ===========================", 80, verbose=self._verbose)
+                            summary = 2
+                            continue
+                        if summary == 2 and line[:6] == "method" :
+                            printverbose ("===================== summary == 2 method =========================", verbose=self._verbose_max)
+                            method = line[7:-1]
+                            printverbose ("Méthode : '{}'".format(method), verbose=self._verbose)
+                            if method not in (self.twopartwo, self.parligne):
+                                raiseException("Problem with type of connectivity")
+                            continue
+                        if summary == 2 and line[:-1] == "fillets section" :
+                            printverbose ("========================= Lecture des fillets =========================", 80, verbose=self._verbose)
+                            summary = 3
+                            continue
+
+                        # B.1.2. Enregistrement des données
+                        if summary == 1:
+                            printverbose ("===================== summary == 1 =========================", 80, verbose=self._verbose_max)
+                            diagno, texte = self.readNodeInfo(line[:-1])
+                            if diagno:
+                                raiseException("{}\nProblem with description of nodes.".format(texte))
+                            continue
+                        if summary == 2:
+                            printverbose ("===================== summary == 2 =========================", 80, verbose=self._verbose_max)
+                            diagno = self.readConnectivity(line[:-1],method)
+                            if diagno:
+                                raiseException("Problem with description of connectivities")
+                            continue
+                        if summary == 3:
+                            printverbose ("===================== summary == 3 =========================", 80, verbose=self._verbose_max)
+                            diagno = self.readFillet(line[:-1])
+                            if diagno:
+                                raiseException("Problem with description of fillets")
+                            continue
+
+                        printverbose ("===================== Rien =========================", 80, verbose=self._verbose_max)
+                        if diagno:
+                            error = diagno
+                            break
+
+                if error:
+                    break
+
+
+                # B.2. Gestion des points alignés
+                self.print_info (self._verbose_max, "avant gestion des points alignés")
+
+                self.correctConnectivity ()
+
+                # B.3. Signalement de la fin d'une chaine
+                for _, value in self.connectivities.items():
+                    self.infoPoints[value['chainage'][-1]]["isEnd"] = True
+
+                self.print_info (self._verbose_max, "avant les création de points, etc.")
+
+                # B.4. Creation des points
+                self.createPoints(part)
+
+                # B.5. Creation des polylines
+                self.createPolylines(part)
+
+                # B.6. Creation des fillets
+                self.createFillets(part)
+
+                # B.7. Recherche des coudes droits
+                self.searchRightConnections(part)
+
+                # B.8. Création des paths pour le pipeNetwork
+                self.createPaths(part)
+
+                # B.9. Création des sketchs pour le pipeNetwork
+                self.createSketches(part)
+
+                self.print_info (self._verbose_max, "après la création des sketchs")
+
+                # B.10. Création des pipes
+                self.createPipes(part, nameRes)
+
+                # B.11. Dossier pour les opérations internes
+                print("========================= Mise en dossier =========================")
+                self.folder = model.addFolder(part, self.lfeatures[0], self.lfeatures[-1])
+                self.folder.setName("{}_inter".format(nameRes))
+
+                # B.12. Ménage des résultats inutiles
+                print("========================= Ménage des résultats inutiles ==================")
+                laux = list()
+                for iaux in range(len(self.ledges)):
+                    laux.append(model.selection("EDGE", "Edge_{}_1".format(iaux)))
+                _ = model.addRemoveResults(part, laux)
+
+                break
+
+            return
+
+    def isMacro(self):
+        """Override Feature.initAttributes().
+        F.isMacro() -> True
+
+        pipeNetwork feature is macro: removes itself on the creation transaction
+        finish.
+        """
+        return False
diff --git a/src/PythonAddons/macros/pipeNetwork/icons/pipeNetwork.png b/src/PythonAddons/macros/pipeNetwork/icons/pipeNetwork.png
new file mode 100644 (file)
index 0000000..7b265be
Binary files /dev/null and b/src/PythonAddons/macros/pipeNetwork/icons/pipeNetwork.png differ
diff --git a/src/PythonAddons/macros/pipeNetwork/pipeNetwork_2par2.txt b/src/PythonAddons/macros/pipeNetwork/pipeNetwork_2par2.txt
new file mode 100644 (file)
index 0000000..4a12d62
--- /dev/null
@@ -0,0 +1,43 @@
+# Positions des noeuds :
+nodes section
+# Le tuyau principal
+id_noeud1 - 0 0 0
+id_noeud2 - 10 -10 0
+id_noeud3 - 15 -15 0
+id_noeud4 - 20 -20 0
+id_noeud5 - 21 -21 10
+id_noeud6 - 30 -21 10
+id_noeud7 - 30 -10 10
+id_noeud8 - 30 -5 10
+id_noeud9 - 30 0 10
+# Les deux piquages
+id_noeudA id_noeud2 -5 -5 10
+id_noeudB id_noeudA 0 5 10
+id_noeudC - 30 -10 20
+id_noeudD id_noeudC 5 5 5
+id_noeudE id_noeudD 5 5 5
+
+# Connectivité :
+connectivity section
+# Choix entre 2 méthodes=soit 2par2 soit par_ligne
+method=2par2
+id_noeud1 id_noeud2
+id_noeud2 id_noeud3
+id_noeud3 id_noeud4
+id_noeud4 id_noeud5
+id_noeud5 id_noeud6
+id_noeud6 id_noeud7
+id_noeud7 id_noeud8
+id_noeud8 id_noeud9
+id_noeudA id_noeud2
+id_noeudB id_noeudA
+id_noeud7 id_noeudC
+id_noeudC id_noeudD
+id_noeudD id_noeudE
+
+# Congés de raccordement :
+fillets section
+id_noeud2 angular_connection
+id_noeud4 radius=1
+id_noeud5 angular_connection
+id_noeud6 radius=2
diff --git a/src/PythonAddons/macros/pipeNetwork/pipeNetwork_ligne.txt b/src/PythonAddons/macros/pipeNetwork/pipeNetwork_ligne.txt
new file mode 100644 (file)
index 0000000..2b41ca6
--- /dev/null
@@ -0,0 +1,33 @@
+# Positions des noeuds :
+nodes section
+# Le tuyau principal
+id_noeud1 - 0 0 0
+id_noeud2 - 10 -10 0
+id_noeud3 - 15 -15 0
+id_noeud4 - 20 -20 0
+id_noeud5 - 21 -21 10
+id_noeud6 - 30 -21 10
+id_noeud7 - 30 -10 10
+id_noeud8 - 30 -5 10
+id_noeud9 - 30 0 10
+# Les deux piquages
+id_noeudA id_noeud2 -5 -5 10
+id_noeudB id_noeudA 0 5 10
+id_noeudC - 30 -10 20
+id_noeudD id_noeudC 5 5 5
+id_noeudE id_noeudD 5 5 5
+
+# Connectivité :
+connectivity section
+# Choix entre 2 méthodes=soit 2par2 soit par_ligne
+method=par_ligne
+id_noeud1 id_noeud2 id_noeud3 id_noeud4 id_noeud5 id_noeud6 id_noeud7 id_noeud8 id_noeud9
+id_noeudB id_noeudA id_noeud2
+id_noeud7 id_noeudC id_noeudD id_noeudE
+
+# Congés de raccordement :
+fillets section
+id_noeud2 angular_connection
+id_noeud4 radius=1
+id_noeud5 angular_connection
+id_noeud6 radius=2
diff --git a/src/PythonAddons/macros/pipeNetwork/widget.xml b/src/PythonAddons/macros/pipeNetwork/widget.xml
new file mode 100644 (file)
index 0000000..d192452
--- /dev/null
@@ -0,0 +1,20 @@
+<source>
+  <workbench id="Macros" document="Part">
+    <group id="Samples">
+      <feature
+        id="pipeNetwork"
+        title="Pipe Network"
+        tooltip="Create"
+        icon="icons/Addons/pipeNetwork.png"
+        helpfile="pipeNetworkFeature.html">
+<!--        <boolvalue id="blocking"
+                   label="Hexa"
+                   default="false"
+                   tooltip="Partition"
+                   obligatory="0"/>-->
+        <file_selector id="file_path" title="Import file" path="">
+        </file_selector>
+      </feature>
+    </group>
+  </workbench>
+</source>
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index a71c233376167b1a215b8cb37e15261b4afdea32..674262962d725d7c830bcd9bb37c97ec3a0203a9 100644 (file)
@@ -22,4 +22,6 @@ SET(TEST_NAMES
   TestRectangleCentered.py
   TestcompoundVertices.py
   TestimportParameters.py
+  TestpipeNetwork_2par2.py
+  TestpipeNetwork_parligne.py
 )