From: Gérald NICOLAS Date: Tue, 15 Jun 2021 09:16:43 +0000 (+0200) Subject: macro tuyauterie X-Git-Tag: V9_8_0a1~17 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2Fgni%2Ftuyauterie_integ_2;p=modules%2Fshaper.git macro tuyauterie --- diff --git a/src/PythonAddons/CMakeLists.txt b/src/PythonAddons/CMakeLists.txt index 289f365e7..07d9bbd5e 100644 --- a/src/PythonAddons/CMakeLists.txt +++ b/src/PythonAddons/CMakeLists.txt @@ -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}) diff --git a/src/PythonAddons/PythonAddons_msg_en.ts b/src/PythonAddons/PythonAddons_msg_en.ts index 305ed4131..2c39004e3 100644 --- a/src/PythonAddons/PythonAddons_msg_en.ts +++ b/src/PythonAddons/PythonAddons_msg_en.ts @@ -1,4 +1,101 @@ + + + + compoundVertices + + Points set + Import points + + + Import a set of construction points + Import a set of construction points + + + + compoundVertices:file_path + + Import file + Import txt file (X Y Z) + + + Select file + Select the file of the points, + defined by their coordinates X Y Z + + + + compoundVertices:separator + + Separator (optional): + Separator (optional): + + + "Select separator" + Select a separator; the default value is white spaces. + + + + + + importParameters + + Import Parameters + Import parameters + + + Import a set of parameters + Import a set of parameters + + + + importParameters:file_path + + Import file + Import file + + + Select file + Select the file of the parameters, + defined by couples: name, value + + + + + + pipeNetwork + + Pipe Network + Pipe network + + + Create + Create a network of pipes + + + + pipeNetwork:file_path + + Import file + Text file of the network + + + Select file + Select the text file of the network + + + + pipeNetwork:blocking + + Hexa + Mesh with hexadra + + + Partition + Partition of the CAD to mesh with hexadra + + + diff --git a/src/PythonAddons/PythonAddons_msg_fr.ts b/src/PythonAddons/PythonAddons_msg_fr.ts new file mode 100644 index 000000000..01cebfc99 --- /dev/null +++ b/src/PythonAddons/PythonAddons_msg_fr.ts @@ -0,0 +1,101 @@ + + + + + + + compoundVertices + + Points set + Importer des points + + + Import a set of construction points + Importer un ensemble de points de construction + + + + compoundVertices:file_path + + Import file + Fichier des points à importer (X Y Z) + + + Select file + Choisir le fichier contenant les points à importer, + définis par leurs coordonnées X Y Z + + + + compoundVertices:separator + + Separator (optional): + Séparateur (optionnel) : + + + "Select separator" + Choisir éventuellement un séparateur ; par défaut ce sont des blancs. + + + + + + importParameters + + Import Parameters + Importer des paramètres + + + Import a set of parameters + Importer un ensemble de paramètres + + + + importParameters:file_path + + Import file + Fichier des paramètres à importer + + + Select file + Choisir le fichier contenant les paramètres à importer, + définis par les paires : nom, valeur + + + + + + pipeNetwork + + Pipe Network + Réseau de tuyaux + + + Create + Créer un réseau de tuyaux + + + + pipeNetwork:file_path + + Import file + Fichier texte de la description du réseau + + + Select file + Choisir le fichier texte de la description du réseau + + + + pipeNetwork:blocking + + Hexa + Pour mailler en hexaèdres + + + Partition + Partitionner la CAO pour mailler en hexaèdres + + + + diff --git a/src/PythonAddons/Test/TestRectangle.py b/src/PythonAddons/Test/TestRectangle.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/Test/TestRectangleCentered.py b/src/PythonAddons/Test/TestRectangleCentered.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/Test/TestcompoundVertices.py b/src/PythonAddons/Test/TestcompoundVertices.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/Test/TestimportParameters.py b/src/PythonAddons/Test/TestimportParameters.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/Test/TestpipeNetwork_2par2.py b/src/PythonAddons/Test/TestpipeNetwork_2par2.py new file mode 100755 index 000000000..40fad6c33 --- /dev/null +++ b/src/PythonAddons/Test/TestpipeNetwork_2par2.py @@ -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 index 000000000..f0f0d46ca --- /dev/null +++ b/src/PythonAddons/Test/TestpipeNetwork_parligne.py @@ -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")) diff --git a/src/PythonAddons/__init__.py b/src/PythonAddons/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/addons_Features.py b/src/PythonAddons/addons_Features.py old mode 100644 new mode 100755 index 64fbca848..4cef6a72b --- a/src/PythonAddons/addons_Features.py +++ b/src/PythonAddons/addons_Features.py @@ -17,13 +17,13 @@ # 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) diff --git a/src/PythonAddons/addons_Features.xml.in b/src/PythonAddons/addons_Features.xml.in index 3f3b7666d..a164800b9 100644 --- a/src/PythonAddons/addons_Features.xml.in +++ b/src/PythonAddons/addons_Features.xml.in @@ -2,4 +2,5 @@ + diff --git a/src/PythonAddons/doc/addons_Features.rst b/src/PythonAddons/doc/addons_Features.rst index 1db6329d6..aa463c383 100644 --- a/src/PythonAddons/doc/addons_Features.rst +++ b/src/PythonAddons/doc/addons_Features.rst @@ -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 index 000000000..beee7386d --- /dev/null +++ b/src/PythonAddons/doc/examples/pipeNetwork.py @@ -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 index 000000000..73d64f4b0 --- /dev/null +++ b/src/PythonAddons/doc/examples/pipeNetwork_ligne.txt @@ -0,0 +1 @@ +../../macros/pipeNetwork/pipeNetwork_ligne.txt \ No newline at end of file diff --git a/src/PythonAddons/doc/examples/rectangle/feature.py b/src/PythonAddons/doc/examples/rectangle/feature.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/doc/images/compound.png b/src/PythonAddons/doc/images/compound.png deleted file mode 100644 index 5e119b39a..000000000 Binary files a/src/PythonAddons/doc/images/compound.png and /dev/null differ diff --git a/src/PythonAddons/doc/images/compound.png b/src/PythonAddons/doc/images/compound.png new file mode 120000 index 000000000..fe75a84da --- /dev/null +++ b/src/PythonAddons/doc/images/compound.png @@ -0,0 +1 @@ +../../macros/compoundVertices/icons/compound.png \ No newline at end of file diff --git a/src/PythonAddons/doc/images/importParameters.png b/src/PythonAddons/doc/images/importParameters.png deleted file mode 100644 index 3b382b91c..000000000 Binary files a/src/PythonAddons/doc/images/importParameters.png and /dev/null differ diff --git a/src/PythonAddons/doc/images/importParameters.png b/src/PythonAddons/doc/images/importParameters.png new file mode 120000 index 000000000..c5167fbcc --- /dev/null +++ b/src/PythonAddons/doc/images/importParameters.png @@ -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 index 000000000..6e1cab8e7 --- /dev/null +++ b/src/PythonAddons/doc/images/pipeNetwork.png @@ -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 index 000000000..ab9e71980 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 index 000000000..d80ec0209 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 index 000000000..798b3fc4a 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 index 000000000..02a44595b --- /dev/null +++ b/src/PythonAddons/doc/pipeNetworkFeature.rst @@ -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` + +Le pilotage en TUI se fait ainsi : + +.. literalinclude:: examples/pipeNetwork.py + :linenos: + :language: python + +:download:`Téléchargement du pilotage en TUI` + + diff --git a/src/PythonAddons/macros/__init__.py b/src/PythonAddons/macros/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/compoundVertices/__init__.py b/src/PythonAddons/macros/compoundVertices/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/compoundVertices/feature.py b/src/PythonAddons/macros/compoundVertices/feature.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/compoundVertices/icons/compound.png b/src/PythonAddons/macros/compoundVertices/icons/compound.png new file mode 100644 index 000000000..5e119b39a 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 index 5e119b39a..000000000 Binary files a/src/PythonAddons/macros/compoundVertices/icons/import.png and /dev/null differ diff --git a/src/PythonAddons/macros/compoundVertices/widget.xml b/src/PythonAddons/macros/compoundVertices/widget.xml index c33e845dd..8d15c8a39 100644 --- a/src/PythonAddons/macros/compoundVertices/widget.xml +++ b/src/PythonAddons/macros/compoundVertices/widget.xml @@ -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"> - + - + diff --git a/src/PythonAddons/macros/importParameters/__init__.py b/src/PythonAddons/macros/importParameters/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/importParameters/feature.py b/src/PythonAddons/macros/importParameters/feature.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/importParameters/widget.xml b/src/PythonAddons/macros/importParameters/widget.xml index 37e0208d7..6d4954165 100644 --- a/src/PythonAddons/macros/importParameters/widget.xml +++ b/src/PythonAddons/macros/importParameters/widget.xml @@ -2,11 +2,11 @@ - + diff --git a/src/PythonAddons/macros/pipeNetwork/__init__.py b/src/PythonAddons/macros/pipeNetwork/__init__.py new file mode 100755 index 000000000..2614b9cee --- /dev/null +++ b/src/PythonAddons/macros/pipeNetwork/__init__.py @@ -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 index 000000000..a22632084 --- /dev/null +++ b/src/PythonAddons/macros/pipeNetwork/feature.py @@ -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 index 000000000..7b265be40 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 index 000000000..4a12d624e --- /dev/null +++ b/src/PythonAddons/macros/pipeNetwork/pipeNetwork_2par2.txt @@ -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 index 000000000..2b41ca6ef --- /dev/null +++ b/src/PythonAddons/macros/pipeNetwork/pipeNetwork_ligne.txt @@ -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 index 000000000..d19245231 --- /dev/null +++ b/src/PythonAddons/macros/pipeNetwork/widget.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/src/PythonAddons/macros/rectangle/__init__.py b/src/PythonAddons/macros/rectangle/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/rectangle/feature.py b/src/PythonAddons/macros/rectangle/feature.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/tests.set b/src/PythonAddons/tests.set index a71c23337..674262962 100644 --- a/src/PythonAddons/tests.set +++ b/src/PythonAddons/tests.set @@ -22,4 +22,6 @@ SET(TEST_NAMES TestRectangleCentered.py TestcompoundVertices.py TestimportParameters.py + TestpipeNetwork_2par2.py + TestpipeNetwork_parligne.py )