CHECK_HTML_GENERATORS
+echo
+echo ---------------------------------------------
+echo testing sphinx
+echo ---------------------------------------------
+echo
+CHECK_SPHINX
+
echo
echo ---------------------------------------------
echo Testing Kernel
echo Configure
if test "${gui_ok}" = "yes"; then
- variables="cc_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok Kernel_ok gui_ok"
+ variables="cc_ok lex_yacc_ok python_ok swig_ok threads_ok OpenGL_ok qt_ok vtk_ok hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok sphinx_ok Kernel_ok gui_ok"
elif test "${SalomeGUI_need}" != "no"; then
variables="cc_ok lex_yacc_ok python_ok swig_ok threads_ok vtk_ok hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok Kernel_ok gui_ok"
else
bin/Makefile \
GEOM_version.h \
doc/Makefile \
+ doc/docutils/Makefile \
doc/salome/Makefile \
doc/salome/gui/Makefile \
doc/salome/gui/GEOM/Makefile \
src/GEOM_I_Superv/Makefile \
src/GEOM_SWIG/Makefile \
src/GEOM_SWIG_WITHIHM/Makefile \
+ src/GEOM_PY/Makefile \
+ src/GEOM_PY/structelem/Makefile \
src/GenerationGUI/Makefile \
src/GroupGUI/Makefile \
src/IGESExport/Makefile \
# $Header$
# source path
#
-SUBDIRS = salome
+SUBDIRS = salome docutils
usr_docs:
(cd salome && $(MAKE) $(AM_MAKEFLAGS) usr_docs)
--- /dev/null
+# -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+# 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.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+
+include $(top_srcdir)/adm_local/unix/make_common_starter.am
+
+pydocdir = $(docdir)/tui/GEOM/docutils
+
+.PHONY : latex
+
+if SPHINX_IS_OK
+
+pydoc_DATA=html/index.html
+html/index.html:$(RSTFILES)
+ make htm
+
+endif
+
+EXTRA_DIST+= html
+
+SPHINXOPTS =
+SOURCEDIR = $(srcdir)
+SPHINXBUILD = sphinx-build
+PAPEROPT_a4 = -D latex_paper_size=a4
+ALLSPHINXOPTS = -d doctrees $(PAPEROPT_a4) $(SPHINXOPTS) $(SOURCEDIR)
+
+SPHINX_PYTHONPATH = $(prefix)/lib/python$(PYTHON_VERSION)/site-packages/salome:$(KERNEL_ROOT_DIR)/bin/salome:$(KERNEL_ROOT_DIR)/lib/python$(PYTHON_VERSION)/site-packages/salome:$(OMNIORB_ROOT)/lib/python$(PYTHON_VERSION)/site-packages
+
+SPHINX_LD_LIBRARY_PATH = $(OMNIORB_ROOT)/lib
+
+htm:
+ mkdir -p html doctrees
+ PYTHONPATH=$(SPHINX_PYTHONPATH):${PYTHONPATH}; \
+ LD_LIBRARY_PATH=$(SPHINX_LD_LIBRARY_PATH):${LD_LIBRARY_PATH}; \
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) html
+ @echo
+ @echo "Build finished. The HTML pages are in html."
+
+latex:
+ mkdir -p latex doctrees
+ PYTHONPATH=$(SPHINX_PYTHONPATH):${PYTHONPATH}; \
+ LD_LIBRARY_PATH=$(SPHINX_LD_LIBRARY_PATH):${LD_LIBRARY_PATH}; \
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) latex
+ @echo
+ @echo "Build finished; the LaTeX files are in latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+html:
+ mkdir -p $@
+
+RSTFILES= \
+ index.rst \
+ overview.rst \
+ docapi.rst
+
+EXTRA_DIST+= $(RSTFILES)
+
+EXTRA_DIST+= \
+ conf.py
+
+install-data-local:
+ $(INSTALL) -d $(pydocdir)
+ if test -d "html"; then b=; else b="$(srcdir)/"; fi; \
+ cp -rf $$b"html"/* $(pydocdir) ; \
+ if test -f $$b"latex"/geompy.pdf; then cp -f $$b"latex"/geompy.pdf $(pydocdir) ; fi;
+
+uninstall-local:
+ chmod -R +w $(pydocdir)
+ rm -rf $(pydocdir)/*
+
+clean-local:
+ -rm -rf html latex doctrees
+ if test -d "html"; then rm -rf html ; fi
--- /dev/null
+# -*- coding: iso-8859-1 -*-
+#
+# yacs documentation build configuration file, created by
+# sphinx-quickstart on Fri Aug 29 09:57:25 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc']
+
+# Uncomment the following line to build the links with Python documentation
+# (you might need to set http_proxy environment variable for this to work)
+#extensions += ['sphinx.ext.intersphinx']
+
+# Intersphinx mapping to add links to modules and objects in the Python
+# standard library documentation
+intersphinx_mapping = {'http://docs.python.org': None}
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'GEOM python packages'
+copyright = '2010 EDF R&D'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '5.1.4'
+# The full version, including alpha/beta/rc tags.
+release = '5.1.4'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+language = 'en'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['.build','ref','images','CVS','.svn']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+#html_theme = 'nature'
+#html_theme = 'agogo'
+#html_theme = 'sphinxdoc'
+#html_theme = 'omadoc'
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = ['themes']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'geompydoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+latex_paper_size = 'a4'
+
+# The font size ('10pt', '11pt' or '12pt').
+latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'geompy.tex', 'Documentation of the GEOM python packages', 'EDF R\&D', 'manual')
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+latex_logo = '../salome/tui/images/head.png'
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = True
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+latex_use_modindex = False
--- /dev/null
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ Documentation of the programming interface (API)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+This section describes the python packages and modules of the
+``salome.geom`` python package. The main part is generated from the
+code documentation included in source python files.
+
+:mod:`salome.geom` -- Package containing the GEOM python utilities
+==================================================================
+
+:mod:`geomtools` -- Tools to access GEOM engine and objects
+-----------------------------------------------------------
+
+.. automodule:: salome.geom.geomtools
+ :members:
+
+:mod:`structelem` -- Structural elements package
+------------------------------------------------
+
+.. automodule:: salome.geom.structelem
+
+.. autoclass:: StructuralElementManager
+ :members:
+
+.. autoclass:: StructuralElement
+ :members:
+
+:mod:`structelem.parts` -- Structural element parts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: salome.geom.structelem.parts
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+:mod:`structelem.orientation` -- Structural element orientation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. automodule:: salome.geom.structelem.orientation
+ :members:
+ :undoc-members:
--- /dev/null
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ Documentation of the GEOM python packages
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Main documentation
+==================
+
+.. toctree::
+ :maxdepth: 3
+
+ overview.rst
+ docapi.rst
+
--- /dev/null
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+General presentation of the GEOM python package
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The GEOM python package essentially contains:
+
+* The visualization of structural elements: a function to create
+ geometrical 3D representations of mechanical models called
+ "structural elements".
+
+Note that these functions either encapsulate the python programming
+interface of GEOM core (the CORBA or SWIG interfaces for example) or
+extend existing utilities as the ``geompy.py`` module.
+
+The functions are distributed in the python package
+``salome.geom``. For example, the usage of the visualization of
+structural elements can be appreciated with this set of instructions:
+
+.. code-block:: python
+
+ from salome.geom.structelem import TEST_StructuralElement
+ TEST_StructuralElement()
+
+This creates the geometrical objects displayed in the study below:
+
+.. image:: /images/salome-geom-structuralelements.png
+ :align: center
+
+The specification of the programming interface of this package is
+detailled in the part :doc:`Documentation of the programming interface
+(API)</docapi>` of this documentation.
+
+.. note::
+ The main package ``salome`` contains other sub-packages that are
+ distributed with the other SALOME modules. For example, the KERNEL
+ module provides the python package ``salome.kernel`` and SMESH the
+ package ``salome.smesh``.
--- /dev/null
+/*!
+
+\page geompypkg_page Programming Interface of GEOM python package
+
+Sorry, but the documentation is not available yet in doxygen format.
+
+Fortunately, a documentation exists in restructured format and then
+can be generated here using sphinx, in the expectative of the doxygen
+version. This documentation is available <a href="../../tui/GEOM/docutils/index.html">
+here</a>.
+
+Here is a sample generated from the doxygen format:
+
+The GEOM python package essentially contains:
+
+<ul>
+ <li>The visualization of structural elements: a function to create
+ geometrical 3D representations of mechanical models called
+ "structural elements".
+</ul>
+
+For details, you should refer to the complete
+<a href="../../tui/GEOM/docutils/index.html"> documentation of the GEOM
+python packages</a> generated with sphinx from rst text files.
+
+Note that these functions either encapsulate the python programming
+interface of GEOM core (the CORBA or SWIG interfaces for example) or
+extend existing utilities as the ``geompy.py`` module.
+
+The functions are distributed in the python package
+``salome.geom``. For example, the usage of the visualization of
+structural elements can be appreciated with this set of instructions:
+
+\code
+
+ from salome.geom.structelem import TEST_StructuralElement
+ TEST_StructuralElement()
+\endcode
+
+This creates the geometrical objects displayed in the study below:
+
+\image html salome-geom-structuralelements.png "Example of Geometry created from structural elements"
+
+*/
Almost all geometry module functionalities are accessible via
\subpage geompy_page "Geometry module Python Interface"
+\n Have a look also at the
+<a href="../../gui/GEOM/geompypkg_page.html"> documentation of the GEOM python packages</a>
+
\image html image3.png "Example of Geometry module usage for engineering tasks"
--- /dev/null
+# Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# 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.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+include $(top_srcdir)/adm_local/unix/make_common_starter.am
+
+SUBDIRS= structelem
+
+salomepypkgdir = $(salomepythondir)/salome/geom
+salomepypkg_PYTHON = \
+ __init__.py \
+ geomtools.py
--- /dev/null
+# -*- coding: iso-8859-1 -*-
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2009 EDF R&D
+#
+# This file is part of PAL_SRC.
+#
+# PAL_SRC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PAL_SRC 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with PAL_SRC; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+"""
+This module provides tools to facilitate the use of geom engine and geom
+objects in Salome.
+"""
+
+import salome
+GEOM = None # GEOM module is loaded only when needed
+
+from salome.kernel.logger import Logger
+from salome.kernel import termcolor
+logger = Logger("salome.geom.geomtools", color = termcolor.RED)
+
+from salome.kernel.studyedit import getActiveStudyId, getStudyEditor
+
+_geompys = {}
+
+def getGeompy(studyId = None):
+ """
+ Return an object behaving exactly like geompy module, except that it is
+ associated with the study `studyId`. If `studyId` is :const:`None`, return
+ a pseudo geompy object for the current study.
+ """
+ # We can't use geompy module because it initializes GEOM with
+ # salome.myStudy, which may not exist. So we use this trick to create
+ # a pseudo geompy module.
+ salome.salome_init()
+ if studyId is None:
+ studyId = getActiveStudyId()
+ if not _geompys.has_key(studyId):
+ import geompyDC
+ _geompys[studyId] = salome.lcc.FindOrLoadComponent("FactoryServer",
+ "GEOM")
+ _geompys[studyId].ShapeType = geompyDC.ShapeType
+ _geompys[studyId].GEOM = geompyDC.GEOM
+ _geompys[studyId].kind = geompyDC.kind
+ _geompys[studyId].info = geompyDC.info
+ _geompys[studyId].PackData = geompyDC.PackData
+ _geompys[studyId].ReadTexture = geompyDC.ReadTexture
+ study = salome.myStudyManager.GetStudyByID(studyId)
+ _geompys[studyId].init_geom(study)
+ return _geompys[studyId]
+
+
+class GeomStudyTools:
+ """
+ This class provides several methods to manipulate geom objects in Salome
+ study. The parameter `studyEditor` defines a
+ :class:`~salome.kernel.studyedit.StudyEditor` object used to access the study. If
+ :const:`None`, the method returns a :class:`~salome.kernel.studyedit.StudyEditor`
+ object on the current study.
+
+ .. attribute:: editor
+
+ This instance attribute contains the underlying
+ :class:`~salome.kernel.studyedit.StudyEditor` object. It can be used to access
+ the study but the attribute itself should not be modified.
+
+ """
+
+ def __init__(self, studyEditor = None):
+ global GEOM
+ if GEOM is None:
+ GEOM = __import__("GEOM")
+ if studyEditor is None:
+ studyEditor = getStudyEditor()
+ self.editor = studyEditor
+
+ def displayShapeByName(self, shapeName, color = None):
+ """
+ Display the geometrical shape whose name in the study is `shapeName`.
+
+ :type shapeName: string
+ :param shapeName: name of the geometrical shape
+
+ :type color: tuple (triplet)
+ :param color: RGB components of the color of the shape
+
+ :return: True if the shape was found, False otherwise
+ """
+ logger.debug("displayShapeByName in PAL: %s with color %s" %
+ (shapeName, color))
+ listSO = self.editor.study.FindObjectByName(shapeName, "GEOM")
+ for sObj in listSO:
+ entry = sObj.GetID()
+ geomObj = self.editor.getOrLoadObject(sObj)
+ if geomObj:
+ shape = geomObj._narrow(GEOM.GEOM_Object)
+ if shape:
+ geomgui = salome.ImportComponentGUI("GEOM")
+ geomgui.createAndDisplayGO(entry)
+ geomgui.setDisplayMode(entry, 1)
+ if color is not None:
+ geomgui.setColor(entry, color[0], color[1], color[2])
+ return True
+ return False
--- /dev/null
+# Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# 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.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+include $(top_srcdir)/adm_local/unix/make_common_starter.am
+
+salomepypkgdir = $(salomepythondir)/salome/geom/structelem
+salomepypkg_PYTHON = \
+ __init__.py \
+ parts.py \
+ orientation.py
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2009 EDF R&D
+#
+# This file is part of PAL_SRC.
+#
+# PAL_SRC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PAL_SRC 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with PAL_SRC; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+"""
+This package is used to create and visualize structural elements. It contains
+three modules:
+
+* This module :mod:`salome.geom.structelem` defines the main classes
+ :class:`StructuralElement` and :class:`StructuralElementManager` that can be
+ directly used to build structural elements.
+* The module :mod:`salome.geom.structelem.parts` defines the classes corresponding to
+ the different parts (beams, grids, etc.) that make up a structural element.
+ It is used to build the geometric shapes in the structural element.
+* The module :mod:`salome.geom.structelem.orientation` defines the classes that are
+ used to compute the orientation of the structural element parts and to build
+ the corresponding markers.
+
+A structural element is a set of geometric shapes (beams, grids, etc.) that
+are built semi-automatically along a set of geometric primitives (edges for
+instance). They are visualized with the same color as their base primitives in
+the geom viewer.
+
+Structural elements are generally created by the
+:class:`StructuralElementManager` class, from a list of commands describing
+the element to create.
+
+Example::
+
+ commandList = [('VisuPoutreGenerale', {'Group_Maille': 'Edge_1'}),
+ ('VisuBarreCercle',
+ {'R': 30, 'Group_Maille': 'Edge_1', 'EP': 15}),
+ ]
+
+ structElemManager = StructuralElementManager()
+ elem = structElemManager.createElement(commandList)
+ elem.display()
+ salome.sg.updateObjBrowser(True)
+
+"""
+
+import types
+
+import salome
+
+from salome.kernel.logger import Logger
+from salome.kernel import termcolor
+logger = Logger("salome.geom.structelem", color = termcolor.RED)
+from salome.kernel.studyedit import getStudyEditor
+
+__all__ = ["parts", "orientation"]
+
+from salome.geom.structelem import parts
+from salome.geom.structelem.parts import InvalidParameterError
+
+class StructuralElementManager:
+ """
+ This class manages the structural elements in the study. It is used to
+ create a new structural element from a list of commands. The parameter
+ `studyId` defines the ID of the study in which the manager will create
+ structural elements. If it is :const:`None` or not specified, it will use
+ the ID of the current study as defined by
+ :func:`salome.kernel.studyedit.getActiveStudyId` function.
+ """
+ def __init__(self, studyId = None):
+ self._studyEditor = getStudyEditor(studyId)
+
+ def createElement(self, commandList):
+ """
+ Create a structural element from the list of commands `commandList`.
+ Each command in this list represent a part of the structural element,
+ that is a specific kind of shape (circular beam, grid, etc.)
+ associated with one or several geometrical primitives. A command must
+ be a tuple. The first element is the structural element part class
+ name or alias name. The second element is a dictionary containing the
+ parameters describing the part. Valid class names are all the classes
+ defined in the module :mod:`~salome.geom.structelem.parts` and inheriting
+ class :class:`~parts.StructuralElementPart`. There are also several
+ aliases for backward compatibility. Here is the complete list:
+
+ * :class:`~parts.GeneralBeam`
+ * :class:`~parts.CircularBeam`
+ * :class:`~parts.RectangularBeam`
+ * :class:`~parts.ThickShell`
+ * :class:`~parts.Grid`
+
+ * :func:`~parts.VisuPoutreGenerale` (alias for
+ :class:`~parts.GeneralBeam`)
+ * :func:`~parts.VisuPoutreCercle` (alias for
+ :class:`~parts.CircularBeam`)
+ * :func:`~parts.VisuPoutreRectangle` (alias for
+ :class:`~parts.RectangularBeam`)
+ * :func:`~parts.VisuBarreGenerale` (alias for
+ :class:`~parts.GeneralBeam`)
+ * :func:`~parts.VisuBarreRectangle` (alias for
+ :class:`~parts.RectangularBeam`)
+ * :func:`~parts.VisuBarreCercle` (alias for
+ :class:`~parts.CircularBeam`)
+ * :func:`~parts.VisuCable` (alias for :class:`~parts.CircularBeam`)
+ * :func:`~parts.VisuCoque` (alias for :class:`~parts.ThickShell`)
+ * :func:`~parts.VisuGrille` (alias for :class:`~parts.Grid`)
+
+ * ``Orientation``: This identifier is used to specify the orientation
+ of one or several 1D structural element parts (i.e. beams). The
+ parameters are described in class
+ :class:`~orientation.Orientation1D`.
+
+ The valid parameters in the dictionary depend on the type of the
+ structural element part, and are detailed in the documentation of
+ the corresponding class. The only parameter that is common to all the
+ classes is "MeshGroups" (that can also be named "Group_Maille"). It
+ defines the name of the geometrical object(s) in the study that will
+ be used as primitives to build the structural element part. This
+ parameter can be either a list of strings or a single string with
+ comma separated names.
+ """
+ logger.debug("StructuralElementManager.createElement: START")
+ logger.debug("Command list: %s" % commandList)
+
+ element = StructuralElement(self._studyEditor.studyId)
+ orientationCmdList = []
+ for command in commandList:
+ (parttype, parameters) = command
+ if parttype == "Orientation":
+ orientationCmdList += [command]
+ elif parttype not in dir(parts):
+ logger.warning('Invalid structural element part name "%s"'
+ ' in command %s, this command will be '
+ 'ignored.' % (parttype, command))
+ else:
+ (meshGroupList, newparams) = self._extractMeshGroups(command)
+ for meshGroup in meshGroupList:
+ # Get the geometrical primitive object
+ groupSObj = self._studyEditor.study.FindObject(meshGroup)
+ groupGeomObj = None
+ if groupSObj is not None:
+ groupGeomObj = \
+ self._studyEditor.getOrLoadObject(groupSObj)
+ if groupGeomObj is None:
+ logger.error("Can't get geom object corresponding to "
+ 'mesh group "%s", structural element '
+ "part %s will not be built." %
+ (groupName, part))
+ continue
+
+ # Create the part
+ try:
+ part = parts.__dict__[parttype](
+ self._studyEditor.studyId, meshGroup,
+ groupGeomObj, newparams)
+ element.addPart(part)
+ except InvalidParameterError, e:
+ logger.error("Invalid parameter error: %s" % e)
+ raise
+ except:
+ logger.exception("Can't create structural element"
+ " part with command %s." %
+ str(command))
+
+ # Orientations are parsed after the parts because they must be
+ # associated with existing parts.
+ for command in orientationCmdList:
+ (parttype, parameters) = command
+ (meshGroupList, orientParams) = self._extractMeshGroups(command)
+ for meshGroup in meshGroupList:
+ element.addOrientation(meshGroup, orientParams)
+
+ element.build()
+ logger.debug("StructuralElementManager.createElement: END")
+ return element
+
+ def _extractMeshGroups(self, command):
+ """
+ This method extracts the names of the mesh groups (i.e. the
+ geometrical objects used to build the structural element part) in the
+ command in parameter. It returns a tuple containing the mesh groups as
+ a list of strings and the other parameters of the command as a new
+ dictionary.
+ """
+ (parttype, parameters) = command
+ newparams = parameters.copy()
+ groupMailleParam = newparams.pop("Group_Maille", None)
+ meshGroupParam = newparams.pop("MeshGroups", None)
+ if groupMailleParam is None and meshGroupParam is None:
+ logger.warning("No mesh group specified in command %s, this "
+ "command will be ignored." % command)
+ return ([], newparams)
+ elif groupMailleParam is not None and meshGroupParam is not None:
+ logger.warning('Both "MeshGroups" and "Group_Maille" specified in'
+ ' command %s, only "MeshGroups" will be used.' %
+ command)
+ elif groupMailleParam is not None and meshGroupParam is None:
+ meshGroupParam = groupMailleParam
+
+ meshGroupList = []
+ if type(meshGroupParam) == types.StringType:
+ meshGroupList = self._getMeshGroupListFromString(meshGroupParam)
+ else:
+ for item in meshGroupParam:
+ meshGroupList += self._getMeshGroupListFromString(item)
+
+ if len(meshGroupList) == 0:
+ logger.warning("Mesh group list is empty in command %s, this "
+ "command will be ignored." % command)
+
+ return (meshGroupList, newparams)
+
+ def _getMeshGroupListFromString(self, meshString):
+ """
+ This method splits the string in parameter to extract comma separated
+ names. Those names are returned as a list of strings.
+ """
+ meshGroupList = []
+ list = meshString.split(",")
+ for item in list:
+ strippedItem = item.strip()
+ if len(strippedItem) > 0:
+ meshGroupList.append(strippedItem)
+ return meshGroupList
+
+
+class StructuralElement:
+ """
+ This class represents a structural element, i.e. a set of geometrical
+ objects built along geometrical primitives. The parameter `studyId`
+ defines the ID of the study that will contain the structural element. If
+ it is :const:`None` or not specified, the constructor will use the ID of
+ the active study as defined by :func:`salome.kernel.studyedit.getActiveStudyId`
+ function. Structural elements are normally created by the class
+ :class:`StructuralElementManager`, so this class should not be
+ instantiated directly in the general case.
+ """
+ _counter = 1
+ _mainFolderTag = 14725
+
+ def __init__(self, studyId = None):
+ # _parts is the dictionary mapping group name to structural element
+ # part. _shapeDict is the dictionary mapping SubShapeID objects to
+ # structural element parts. Both are used to avoid duplicate shapes
+ # in structural elements.
+ self._parts = {}
+ self._shapeDict = {}
+ self._id = StructuralElement._counter
+ StructuralElement._counter += 1
+ self._studyEditor = getStudyEditor(studyId)
+ logger.debug("Creating structural element in study %s" %
+ self._studyEditor.studyId)
+ self._SObject = None
+
+ def _getSObject(self):
+ """
+ Find or create the study object corresponding to the structural
+ element. This object is named "SE_N" where N is a numerical ID.
+ """
+ if self._SObject is None:
+ geomComponent = self._studyEditor.study.FindComponent("GEOM")
+ mainFolder = self._studyEditor.setItemAtTag(geomComponent,
+ StructuralElement._mainFolderTag,
+ name = "Structural Elements")
+ self._SObject = self._studyEditor.findOrCreateItem(mainFolder,
+ name = "SE_" + str(self._id))
+ return self._SObject
+
+ def addPart(self, newpart):
+ """
+ Add a part to the structural element.
+
+ :type newpart: :class:`~parts.StructuralElementPart`
+ :param newpart: the part to add to the structural element.
+
+ """
+ newshapes = newpart.baseShapesSet
+
+ # Check duplicate groups
+ if self._parts.has_key(newpart.groupName):
+ logger.warning('Mesh group "%s" is used several times in the '
+ 'structural element. Only the last definition '
+ 'will be used.' % newpart.groupName)
+ else:
+ # Check duplicate shapes
+ intersect = newshapes.intersection(self._shapeDict.keys())
+ while len(intersect) > 0:
+ shape, = intersect
+ oldpartwithshape = self._shapeDict[shape]
+ oldpartshapes = oldpartwithshape.baseShapesSet
+ intersectwitholdpart = intersect.intersection(oldpartshapes)
+ logger.warning('Some shapes are common to groups "%s" and '
+ '"%s". For those, the parameters defined for '
+ '"%s" will be used.' %
+ (oldpartwithshape.groupName, newpart.groupName,
+ newpart.groupName))
+ oldpartwithshape.baseShapesSet = \
+ oldpartshapes.difference(intersectwitholdpart)
+ intersect = intersect.difference(intersectwitholdpart)
+
+ # Finally add the new part in the structural element
+ self._parts[newpart.groupName] = newpart
+ for shape in newshapes:
+ self._shapeDict[shape] = newpart
+
+ def addOrientation(self, meshGroup, orientParams):
+ """
+ Add orientation information to a part in the structural element. This
+ information will be used to build the corresponding markers.
+
+ :type meshGroup: string
+ :param meshGroup: the name of a geometrical primitive. The orientation
+ information will apply to the structural element
+ part built along this primitive.
+
+ :type orientParams: dictionary
+ :param orientParams: parameters defining the orientation of the
+ structural element part. Those parameters are
+ detailed in class
+ :class:`~orientation.Orientation1D`.
+
+ """
+ if self._parts.has_key(meshGroup):
+ self._parts[meshGroup].addOrientation(orientParams)
+ else:
+ logger.warning('Mesh group "%s" not found in structural element, '
+ 'cannot set orientation.' % meshGroup)
+
+ def build(self):
+ """
+ Build the geometric shapes and the markers corresponding to the
+ different parts of the structural element, and add them to the study.
+ """
+ gg = salome.ImportComponentGUI("GEOM")
+ for part in self._parts.itervalues():
+ # Build the structural element part
+ logger.debug("Building %s" % part)
+ try:
+ (shape, markers) = part.build()
+ if shape is None:
+ logger.error("Part %s has not been built" % part)
+ continue
+ except:
+ logger.exception("Couldn't build part %s" % part)
+ continue
+
+ # Add the new objects to the study
+ IOR = self._studyEditor.study.ConvertObjectToIOR(shape)
+ shapeSObjName = part.name + "_" + part.groupName
+ icon = None
+ if salome.hasDesktop():
+ icon = gg.getShapeTypeIcon(IOR)
+ shapeSObj = self._studyEditor.createItem(self._getSObject(),
+ name = shapeSObjName, IOR = IOR,
+ icon = icon)
+ if markers is not None and len(markers) > 0:
+ i = 1
+ for marker in markers:
+ markerIOR = \
+ self._studyEditor.study.ConvertObjectToIOR(marker)
+ markerSObjName = "Orient_" + shapeSObjName
+ if len(markers) > 1:
+ markerSObjName += "_%d" % i
+ markerSObj = self._studyEditor.createItem(
+ self._getSObject(),
+ name = markerSObjName,
+ IOR = markerIOR,
+ icon = "ICON_OBJBROWSER_LCS")
+ i += 1
+
+ def display(self):
+ """
+ Display the structural element in the geom view.
+ """
+ StructuralElement.showElement(self._SObject)
+
+ @staticmethod
+ def showElement(theSObject):
+ """
+ Display the structural element corresponding to the study object
+ `theSObject`
+ """
+ if theSObject is not None:
+ gg = salome.ImportComponentGUI("GEOM")
+ aStudy = theSObject.GetStudy()
+ editor = getStudyEditor(aStudy._get_StudyId())
+ aIterator = aStudy.NewChildIterator(theSObject)
+ aIterator.Init()
+ while aIterator.More():
+ sobj = aIterator.Value()
+ icon = editor.getIcon(sobj)
+ if icon != "ICON_OBJBROWSER_LCS":
+ entry = aIterator.Value().GetID()
+ gg.createAndDisplayGO(entry)
+ gg.setDisplayMode(entry, 1)
+ aIterator.Next()
+
+
+def TEST_CreateGeometry():
+ import geompy
+ import SALOMEDS
+ geompy.init_geom(salome.myStudy)
+ Box_1 = geompy.MakeBoxDXDYDZ(200, 200, 200)
+ edges = geompy.SubShapeAllSorted(Box_1, geompy.ShapeType["EDGE"])
+ edges[0].SetColor(SALOMEDS.Color(1.0,0.0,0.0))
+ edges[1].SetColor(SALOMEDS.Color(0.0,1.0,0.0))
+ edges[2].SetColor(SALOMEDS.Color(0.0,0.0,1.0))
+ edges[3].SetColor(SALOMEDS.Color(1.0,0.0,1.0))
+ edges[4].SetColor(SALOMEDS.Color(0.0,1.0,1.0))
+ edges[5].SetColor(SALOMEDS.Color(0.5,0.0,0.0))
+ edges[6].SetColor(SALOMEDS.Color(0.0,0.5,0.0))
+ edges[7].SetColor(SALOMEDS.Color(0.0,0.0,0.5))
+ geompy.addToStudy(Box_1, "Box_1")
+ for i in range(len(edges)):
+ geompy.addToStudyInFather(Box_1, edges[i], "Edge_%d" % i)
+ faces = geompy.SubShapeAllSorted(Box_1, geompy.ShapeType["FACE"])
+ faces[3].SetColor(SALOMEDS.Color(1.0,0.5,0.0))
+ faces[4].SetColor(SALOMEDS.Color(0.0,1.0,0.5))
+ for i in range(len(faces)):
+ geompy.addToStudyInFather(Box_1, faces[i], "Face_%d" % i)
+ Cylinder_1 = geompy.MakeCylinderRH(50, 200)
+ geompy.TranslateDXDYDZ(Cylinder_1, 300, 300, 0)
+ cyl_faces = geompy.SubShapeAllSorted(Cylinder_1, geompy.ShapeType["FACE"])
+ geompy.addToStudy(Cylinder_1, "Cylinder_1")
+ for i in range(len(cyl_faces)):
+ geompy.addToStudyInFather(Cylinder_1, cyl_faces[i], "CylFace_%d" % i)
+ Cylinder_2 = geompy.MakeTranslation(Cylinder_1, 100, 100, 0)
+ cyl_faces2 = geompy.SubShapeAllSorted(Cylinder_2,
+ geompy.ShapeType["FACE"])
+ geompy.addToStudy(Cylinder_2, "Cylinder_2")
+ for i in range(len(cyl_faces2)):
+ geompy.addToStudyInFather(Cylinder_2, cyl_faces2[i],
+ "CylFace2_%d" % i)
+
+
+def TEST_StructuralElement():
+ salome.salome_init()
+ TEST_CreateGeometry()
+ liste_commandes = [('Orientation', {'MeshGroups': 'Edge_4',
+ 'VECT_Y': (1.0, 0.0, 1.0)}),
+ ('Orientation', {'MeshGroups': 'Edge_5',
+ 'ANGL_VRIL': 45.0}),
+ ('GeneralBeam', {'MeshGroups': 'Edge_1, Edge_7'}),
+ ('VisuPoutreCercle', {'MeshGroups': ['Edge_6'],
+ 'R1': 30, 'R2': 20}),
+ ('CircularBeam', {'MeshGroups': ['Edge_2', 'Edge_3'],
+ 'R': 40, 'EP': 20}),
+ ('RectangularBeam', {'MeshGroups': 'Edge_4, Edge_5',
+ 'HZ1': 60, 'HY1': 40,
+ 'EPZ1': 15, 'EPY1': 10,
+ 'HZ2': 40, 'HY2': 60,
+ 'EPZ2': 10, 'EPY2': 15}),
+ ('VisuCable', {'MeshGroups': 'Edge_7', 'R': 5}),
+ ('VisuCoque', {'MeshGroups': 'Face_4',
+ 'Epais': 10, 'Excentre': 5,
+ 'angleAlpha': 45, 'angleBeta': 60}),
+ ('VisuCoque', {'MeshGroups': 'CylFace_2', 'Epais': 5}),
+ ('VisuGrille', {'MeshGroups': 'Face_5', 'Excentre': 5,
+ 'angleAlpha': 45, 'angleBeta': 60}),
+ ('VisuGrille', {'MeshGroups': 'CylFace2_2',
+ 'Excentre': 5, 'origAxeX': 400,
+ 'origAxeY': 400, 'origAxeZ': 0,
+ 'axeX': 0, 'axeY': 0, 'axeZ': 100}),
+ ]
+
+ structElemManager = StructuralElementManager()
+ elem = structElemManager.createElement(liste_commandes)
+ if salome.hasDesktop():
+ elem.display()
+ salome.sg.updateObjBrowser(True)
+
+
+# Main function only used to test the module
+if __name__ == "__main__":
+ TEST_StructuralElement()
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2009 EDF R&D
+#
+# This file is part of PAL_SRC.
+#
+# PAL_SRC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PAL_SRC 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with PAL_SRC; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+"""
+This module is used to compute the orientation of the different parts in a
+structural element and to build the corresponding markers (trihedrons).
+"""
+
+import math
+
+from salome.kernel.logger import Logger
+from salome.kernel import termcolor
+logger = Logger("__PAL_GEOM__.structelem.orientation", color = termcolor.RED)
+
+
+class Orientation1D:
+ """
+ This class is used to compute the orientation of 1D elements and to build
+ the corresponding markers.
+ """
+
+ def __init__(self):
+ self.geom = None
+ self._vectorYCoords = None
+ self._angle = 0.0
+
+ def __repr__(self):
+ reprdict = self.__dict__.copy()
+ del reprdict["geom"]
+ return '%s(%s)' % (self.__class__.__name__, reprdict)
+
+ def addParams(self, params):
+ """
+ Add orientation parameters. `params` is a dictionary containing one or
+ several orientation parameters. The valid parameters are:
+
+ * "VECT_Y": Triplet defining the local Y axis (the X axis is the
+ main direction of the 1D element).
+ * "ANGL_VRIL": Angle of rotation along the X axis to define the local
+ coordinate system.
+
+ The parameters can be specified several times. In this case, only the
+ first "VECT_Y" is taken into account, and the values of "ANGL_VRIL"
+ are added to obtain the total rotation angle.
+ """
+ mydict = params.copy()
+ if mydict.has_key("VECT_Y"):
+ newVecCoords = mydict.pop("VECT_Y")
+ if self._vectorYCoords is None:
+ logger.debug("Setting orientation vector Y to %s" %
+ str(newVecCoords))
+ self._vectorYCoords = newVecCoords
+ else:
+ logger.warning('Orientation parameter "VECT_Y" is specified '
+ 'several times for the same mesh group, vector'
+ ' %s will be used' % str(self._vectorYCoords))
+ if mydict.has_key("ANGL_VRIL"):
+ newAngle = mydict.pop("ANGL_VRIL")
+ self._angle += newAngle
+ logger.debug("Adding angle %f to orientation, new angle is %f." %
+ (newAngle, self._angle))
+ if len(mydict) > 0:
+ logger.warning("Invalid orientation parameter(s) (ignored): %s" %
+ str(mydict))
+
+ def _buildDefaultMarker(self, center, vecX):
+ """
+ Create the default marker, that use the main direction of the 1D
+ object as the local X axis and the global Z axis to determine the
+ local Z axis.
+ """
+ xPoint = self.geom.MakeTranslationVector(center, vecX)
+ givenVecZ = self.geom.MakeVectorDXDYDZ(0.0, 0.0, 1.0)
+ angle = self.geom.GetAngleRadians(vecX, givenVecZ)
+ if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
+ logger.warning("Beam X axis is colinear to absolute Z axis. "
+ "Absolute X axis will be used to determine "
+ "local Z axis.")
+ givenVecZ = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
+ zPoint = self.geom.MakeTranslationVector(center, givenVecZ)
+ locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint, xPoint, 1.0)
+ locY = self.geom.GetNormal(locPlaneZX)
+ marker = self.geom.MakeMarkerPntTwoVec(center,vecX,locY)
+ return marker
+
+ def buildMarker(self, geom, center, vecX):
+ """
+ Create a marker with origin `center` and X axis `vecX`. `geom` is the
+ pseudo-geompy object used to build the geometric shapes.
+ """
+ self.geom = geom
+ marker = None
+ if self._vectorYCoords is None:
+ marker = self._buildDefaultMarker(center, vecX)
+ else:
+ xPoint = self.geom.MakeTranslationVector(center, vecX)
+ givenLocY = self.geom.MakeVectorDXDYDZ(self._vectorYCoords[0],
+ self._vectorYCoords[1],
+ self._vectorYCoords[2])
+ angle = self.geom.GetAngleRadians(vecX, givenLocY)
+ if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
+ logger.warning("Vector Y is colinear to the beam X axis, "
+ "using default LCS.")
+ marker = self._buildDefaultMarker(center, vecX)
+ else:
+ yPoint = self.geom.MakeTranslationVector(center, givenLocY)
+ locPlaneXY = self.geom.MakePlaneThreePnt(center, xPoint,
+ yPoint, 1.0)
+ locZ = self.geom.GetNormal(locPlaneXY)
+ zPoint = self.geom.MakeTranslationVector(center, locZ)
+ locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint,
+ xPoint, 1.0)
+ locY = self.geom.GetNormal(locPlaneZX)
+ marker = self.geom.MakeMarkerPntTwoVec(center,vecX,locY)
+
+ if self._angle != 0.0:
+ angleRad = math.radians(self._angle)
+ marker = self.geom.Rotate(marker, vecX, angleRad)
+
+ return marker
+
+
+class Orientation2D:
+ """
+ This class is used to compute the orientation of 2D elements and to build
+ the corresponding markers. Angles `alpha` and `beta` are used to determine
+ the local coordinate system for the 2D element. If `vect` is not
+ :const:`None`, it is used instead of `alpha` and `beta`.
+ """
+
+ def __init__(self, alpha, beta, vect):
+ self.geom = None
+ self._alpha = alpha
+ self._beta = beta
+ self._vect = vect
+
+ def __repr__(self):
+ reprdict = self.__dict__.copy()
+ del reprdict["geom"]
+ return '%s(%s)' % (self.__class__.__name__, reprdict)
+
+ def _buildDefaultMarker(self, center, normal, warnings = True):
+ """
+ Create the default marker, that use the normal vector of the 2D object
+ as the local Z axis and the global X axis to determine the local X
+ axis. `warnings` can be used to enable or disable the logging of
+ warning messages.
+ """
+ marker = None
+ globalVecX = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
+ angle = self.geom.GetAngleRadians(normal, globalVecX)
+ if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
+ if warnings:
+ logger.warning("Face normal is colinear to absolute X axis. "
+ "Absolute Y axis will be used to determine "
+ "local X axis.")
+ globalVecY = self.geom.MakeVectorDXDYDZ(0.0, 1.0, 0.0)
+ marker = self._buildMarkerRefVecX(center, normal, globalVecY)
+ else:
+ marker = self._buildMarkerRefVecX(center, normal, globalVecX)
+ return marker
+
+ def _buildMarkerRefVecX(self, center, normal, refVecX):
+ """
+ Create a marker using `normal` as Z axis and `refVecX` to determine
+ the X axis.
+ """
+ xPoint = self.geom.MakeTranslationVector(center, refVecX)
+ zPoint = self.geom.MakeTranslationVector(center, normal)
+ locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint, xPoint, 1.0)
+ locY = self.geom.GetNormal(locPlaneZX)
+ yPoint = self.geom.MakeTranslationVector(center, locY)
+ locPlaneYZ = self.geom.MakePlaneThreePnt(center, yPoint, zPoint, 1.0)
+ locX = self.geom.GetNormal(locPlaneYZ)
+ marker = self.geom.MakeMarkerPntTwoVec(center, locX, locY)
+ return marker
+
+ def buildMarker(self, geom, center, normal, warnings = True):
+ """
+ Create a marker with origin `center` and `normal` as Z axis. The other
+ axes are computed using the parameters alpha and beta of the
+ Orientation2D instance. `geom` is the pseudo-geompy object used to
+ build the geometric shapes. `warnings` can be used to enable or
+ disable the logging of warning messages.
+ """
+ self.geom = geom
+ marker = None
+ refVecX = None
+ if self._vect is not None:
+ # Using vector parameter
+ if abs(self._vect[0]) <= 1e-7 and abs(self._vect[1]) <= 1e-7 and \
+ abs(self._vect[2]) <= 1e-7:
+ if warnings:
+ logger.warning("Vector too small: %s, using default LCS" %
+ self._vect)
+ else:
+ refVecX = self.geom.MakeVectorDXDYDZ(self._vect[0],
+ self._vect[1],
+ self._vect[2])
+ elif self._alpha is not None and self._beta is not None:
+ # Using alpha and beta angles
+ alphaRad = math.radians(self._alpha)
+ betaRad = math.radians(self._beta)
+ if abs(alphaRad) <= 1e-7 and abs(betaRad) <= 1e-7:
+ if warnings:
+ logger.warning("Angles too small: (%g, %g), using "
+ "default LCS" % (self._alpha, self._beta))
+ else:
+ # rotate global CS with angles alpha and beta
+ refVecX = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
+ refVecY = self.geom.MakeVectorDXDYDZ(0.0, 1.0, 0.0)
+ globalVecZ = self.geom.MakeVectorDXDYDZ(0.0, 0.0, 1.0)
+ if abs(alphaRad) > 1e-7:
+ refVecX = self.geom.Rotate(refVecX, globalVecZ, alphaRad)
+ refVecY = self.geom.Rotate(refVecY, globalVecZ, alphaRad)
+ if abs(betaRad) > 1e-7:
+ refVecX = self.geom.Rotate(refVecX, refVecY, betaRad)
+
+ if refVecX is not None:
+ # build local coordinate system
+ angle = self.geom.GetAngleRadians(normal, refVecX)
+ if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
+ if warnings:
+ logger.warning("Face normal is colinear to the reference "
+ "X axis, using default LCS.")
+ else:
+ marker = self._buildMarkerRefVecX(center, normal, refVecX)
+
+ if marker is None:
+ marker = self._buildDefaultMarker(center, normal, warnings)
+
+ return marker
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007-2009 EDF R&D
+#
+# This file is part of PAL_SRC.
+#
+# PAL_SRC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# PAL_SRC 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with PAL_SRC; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+"""
+This module defines the different structural element parts. It is used to
+build the geometric shapes of the structural elements. It should not be used
+directly in the general case. Structural elements should be created by the
+class :class:`~salome.geom.structelem.StructuralElementManager`.
+"""
+
+import salome
+
+from salome.kernel.logger import Logger
+from salome.kernel import termcolor
+logger = Logger("salome.geom.structelem.parts", color = termcolor.RED)
+from salome.geom.geomtools import getGeompy
+
+import orientation
+
+# Filling for the beams
+FULL = "FULL"
+HOLLOW = "HOLLOW"
+
+# Minimum dimension for the shapes to extrude
+MIN_DIM_FOR_EXTRUDED_SHAPE = 2e-4
+MIN_LENGTH_FOR_EXTRUSION = 1e-4
+MIN_THICKNESS = 1e-5
+
+
+class InvalidParameterError(Exception):
+ """
+ This exception is raised when an invalid parameter is used to build a
+ structural element part.
+ """
+
+ def __init__(self, groupName, expression, minValue, value):
+ self.groupName = groupName
+ self.expression = expression
+ self.minValue = minValue
+ self.value = value
+
+ def __str__(self):
+ return "%s < %g (%s = %g in %s)" % (self.expression, self.minValue,
+ self.expression, self.value,
+ self.groupName)
+
+
+class SubShapeID:
+ """
+ This class enables the use of subshapes in sets or as dictionary keys.
+ It implements __eq__ and __hash__ methods so that subshapes with the same
+ CORBA object `mainShape` and the same `id` are considered equal.
+ """
+
+ def __init__(self, mainShape, id):
+ self._mainShape = mainShape
+ self._id = id
+
+ def getObj(self, geom):
+ """
+ Return the subshape (GEOM object). `geom` is a pseudo-geompy object
+ used to find the geometrical object.
+ """
+ return geom.GetSubShape(self._mainShape, [self._id])
+
+ def __eq__(self, other):
+ return self._mainShape._is_equivalent(other._mainShape) and \
+ self._id == other._id
+
+ def __hash__(self):
+ return self._mainShape._hash(2147483647) ^ self._id
+
+
+class StructuralElementPart:
+ """
+ This class is the base class for all structural element parts. It should
+ not be instantiated directly (consider it as an "abstract" class).
+
+ :type studyId: integer
+ :param studyId: the ID of the study in which the part is created.
+
+ :type groupName: string
+ :param groupName: the name of the underlying geometrical primitive in the
+ study.
+
+ :type groupGeomObj: GEOM object
+ :param groupGeomObj: the underlying geometrical primitive.
+
+ :type parameters: dictionary
+ :param parameters: parameters defining the structural element (see
+ subclasses for details).
+
+ :type name: string
+ :param name: name to use for the created object in the study.
+
+ """
+
+ DEFAULT_NAME = "StructElemPart"
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = DEFAULT_NAME):
+ self._parameters = parameters
+ self.groupName = groupName
+ self._groupGeomObj = groupGeomObj
+ self._orientation = None
+ self._paramUserName = {}
+ self.name = name
+ self.geom = getGeompy(studyId)
+ self.baseShapesSet = set()
+ mainShape = self.geom.GetMainShape(groupGeomObj)
+ listIDs = self.geom.GetObjectIDs(groupGeomObj)
+ if mainShape is not None and listIDs is not None:
+ for id in listIDs:
+ self.baseShapesSet.add(SubShapeID(mainShape, id))
+
+ def _getParameter(self, nameList, default = None):
+ """
+ This method finds the value of a parameter in the parameters
+ dictionary. The argument is a list because some parameters can have
+ several different names.
+ """
+ if len(nameList) > 0:
+ paramName = nameList[0]
+ for name in nameList:
+ if self._parameters.has_key(name):
+ self._paramUserName[paramName] = name
+ return self._parameters[name]
+ return default
+
+ def _getParamUserName(self, paramName):
+ """
+ This method finds the user name for a parameter.
+ """
+ if self._paramUserName.has_key(paramName):
+ return self._paramUserName[paramName]
+ else:
+ return paramName
+
+ def __repr__(self):
+ reprdict = self.__dict__.copy()
+ del reprdict["_parameters"]
+ del reprdict["groupName"]
+ del reprdict["_groupGeomObj"]
+ del reprdict["_paramUserName"]
+ del reprdict["name"]
+ del reprdict["geom"]
+ del reprdict["baseShapesSet"]
+ return '%s("%s", %s)' % (self.__class__.__name__, self.groupName,
+ reprdict)
+
+ def addOrientation(self, orientParams):
+ """
+ Add orientation information to the structural element part. See class
+ :class:`~salome.geom.structelem.orientation.Orientation1D` for the description
+ of the parameters.
+ """
+ self._orientation.addParams(orientParams)
+
+ def _checkSize(self, value, mindim, expression):
+ """
+ This method checks that some parameters or some expressions involving
+ those parameters are greater than a minimum value.
+ """
+ if value < mindim:
+ raise InvalidParameterError(self.groupName, expression,
+ mindim, value)
+
+ def build(self):
+ """
+ Build the geometric shapes and the markers corresponding to the
+ structural element part in the study `studyId`.
+ """
+ shape = self._buildPart()
+ markers = self._buildMarkers()
+ shape.SetColor(self._groupGeomObj.GetColor())
+ for marker in markers:
+ marker.SetColor(self._groupGeomObj.GetColor())
+ return (shape, markers)
+
+ def _buildPart(self):
+ """
+ This abstract method must be implemented in subclasses and should
+ create the geometrical shape(s) of the structural element part.
+ """
+ raise NotImplementedError("Method _buildPart not implemented in class"
+ " %s (it must be implemented in "
+ "StructuralElementPart subclasses)." %
+ self.__class__.__name__)
+
+ def _buildMarkers(self):
+ """
+ This abstract method must be implemented in subclasses and should
+ create the markers defining the orientation of the structural element
+ part.
+ """
+ raise NotImplementedError("Method _buildMarker not implemented in "
+ "class %s (it must be implemented in "
+ "StructuralElementPart subclasses)." %
+ self.__class__.__name__)
+
+ def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
+ """
+ Find and return the base subshapes in the structural element part.
+ """
+ subShapes = []
+ for subShapeID in self.baseShapesSet:
+ subShape = subShapeID.getObj(self.geom)
+ length = self.geom.BasicProperties(subShape)[0]
+ if length < minDim:
+ logger.warning("Length too short (%s - ID %s, length = %g), "
+ "subshape will not be used in structural "
+ "element" % (self.groupName, subShapeID._id,
+ length))
+ else:
+ subShapes.append(subShape)
+ return subShapes
+
+
+class Beam(StructuralElementPart):
+ """
+ This class is an "abstract" class for all 1D structural element parts. It
+ should not be instantiated directly. See class
+ :class:`StructuralElementPart` for the description of the parameters.
+ """
+
+ DEFAULT_NAME = "Beam"
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = DEFAULT_NAME):
+ StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
+ parameters, name)
+ self._orientation = orientation.Orientation1D()
+
+ def _isReversed(self, path):
+ """
+ This method checks if a 1D object is "reversed", i.e. if its
+ orientation is different than the orientation of the underlying OCC
+ object.
+ """
+ fParam = 0.
+ lParam = 1.
+ fPoint = self.geom.MakeVertexOnCurve(path, fParam)
+ lPoint = self.geom.MakeVertexOnCurve(path, lParam)
+
+ fNormal = self.geom.MakeTangentOnCurve(path, fParam)
+ lNormal = self.geom.MakeTangentOnCurve(path, lParam)
+
+ fCircle = self.geom.MakeCircle(fPoint, fNormal, 10)
+ lCircle = self.geom.MakeCircle(lPoint, lNormal, 10)
+
+ try:
+ pipe = self.geom.MakePipeWithDifferentSections([fCircle, lCircle],
+ [fPoint, lPoint],
+ path, False, False)
+ except RuntimeError, e:
+ # This dirty trick is needed if the wire is not oriented in the
+ # direction corresponding to parameters 0.0 -> 1.0. In this case,
+ # we catch the error and invert the ends of the wire. This trick
+ # will be removed when the function giving the orientation of an
+ # edge will be added in geompy (see issue 1144 in PAL bugtracker).
+ if (str(e) == "MakePipeWithDifferentSections : First location "
+ "shapes is not coincided with first vertex of "
+ "aWirePath"):
+ return True
+ else:
+ raise
+ return False
+
+ def _getVertexAndTangentOnOrientedWire(self, path, param):
+ """
+ Get a vertex and the corresponding tangent on a wire by parameter.
+ This method takes into account the "real" orientation of the wire
+ (i.e. the orientation of the underlying OCC object).
+ """
+ if self._isReversed(path):
+ vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
+ invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
+ tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
+ invtangent,
+ -1.0)
+ tangent = self.geom.MakeVector(vertex, tanpoint)
+ else:
+ vertex = self.geom.MakeVertexOnCurve(path, param)
+ tangent = self.geom.MakeTangentOnCurve(path, param)
+ return (vertex, tangent)
+
+ def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
+ """
+ Create a solid by the extrusion of section `wire1` to section `wire2`
+ along `path`.
+ """
+ face1 = self.geom.MakeFace(wire1, True)
+ face2 = self.geom.MakeFace(wire2, True)
+ shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
+ [point1, point2],
+ path, False, False)
+ closedShell = self.geom.MakeShell([face1, face2, shell])
+ solid = self.geom.MakeSolid([closedShell])
+ return solid
+
+ def _buildPart(self):
+ """
+ Build the structural element part.
+ """
+ # Get all the subshapes in the group (normally only edges and wires)
+ paths = self._getSubShapes()
+ listPipes = []
+ withContact = False
+ withCorrection = False
+
+ for path in paths:
+ # Build the sections (rectangular or circular) at each end of the
+ # beam
+ (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
+ 0.0)
+ (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
+ 1.0)
+ (outerWire1, innerWire1, outerWire2, innerWire2) = \
+ self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
+
+ # Create the resulting solid
+ outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
+ fPoint, lPoint, path)
+ if self.filling == HOLLOW:
+ innerSolid = self._makeSolidPipeFromWires(innerWire1,
+ innerWire2, fPoint,
+ lPoint, path)
+ resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
+ listPipes.append(resultSolid)
+ else:
+ listPipes.append(outerSolid)
+
+ if len(listPipes) == 0:
+ return None
+ elif len(listPipes) == 1:
+ return listPipes[0]
+ else:
+ return self.geom.MakeCompound(listPipes)
+
+ def _buildMarkers(self):
+ """
+ Build the markers defining the orientation of the structural element
+ part.
+ """
+ param = 0.5
+ paths = self._getSubShapes()
+ listMarkers = []
+ for path in paths:
+ (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
+ param)
+ marker = self._orientation.buildMarker(self.geom, center, vecX)
+ listMarkers.append(marker)
+ return listMarkers
+
+
+class GeneralBeam(Beam):
+ """
+ This class defines a beam with a generic section. It is represented only
+ as the underlying wire. See class :class:`StructuralElementPart` for the
+ description of the parameters.
+ """
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = Beam.DEFAULT_NAME):
+ Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
+ name)
+ logger.debug(repr(self))
+
+ def _buildPart(self):
+ """
+ Create a copy of the underlying wire.
+ """
+ edges = self._getSubShapes(1e-7)
+ wire = None
+ if len(edges) > 0:
+ wire = self.geom.MakeWire(edges)
+ return wire
+
+
+class CircularBeam(Beam):
+ """
+ This class defines a beam with a circular section. It can be full or
+ hollow, and its radius and thickness can vary from one end of the beam to
+ the other. The valid parameters for circular beams are:
+
+ * "R1" or "R": radius at the first end of the beam.
+ * "R2" or "R": radius at the other end of the beam.
+ * "EP1" or "EP" (optional): thickness at the first end of the beam.
+ If not specified or equal to 0, the beam is considered full.
+ * "EP2" or "EP" (optional): thickness at the other end of the beam.
+ If not specified or equal to 0, the beam is considered full.
+
+ See class :class:`StructuralElementPart` for the description of the
+ other parameters.
+
+ """
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = Beam.DEFAULT_NAME):
+ Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
+ name)
+
+ self.R1 = self._getParameter(["R1", "R"])
+ self.R2 = self._getParameter(["R2", "R"])
+ self.EP1 = self._getParameter(["EP1", "EP"])
+ self.EP2 = self._getParameter(["EP2", "EP"])
+
+ if self.EP1 is None or self.EP2 is None or \
+ self.EP1 == 0 or self.EP2 == 0:
+ self.filling = FULL
+ else:
+ self.filling = HOLLOW
+
+ logger.debug(repr(self))
+
+ # Check parameters
+ self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
+ self._getParamUserName("R1"))
+ self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
+ self._getParamUserName("R2"))
+ if self.filling == HOLLOW:
+ self._checkSize(self.EP1, MIN_THICKNESS,
+ self._getParamUserName("EP1"))
+ self._checkSize(self.EP2, MIN_THICKNESS,
+ self._getParamUserName("EP2"))
+ self._checkSize(self.R1 - self.EP1,
+ MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
+ "%s - %s" % (self._getParamUserName("R1"),
+ self._getParamUserName("EP1")))
+ self._checkSize(self.R2 - self.EP2,
+ MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
+ "%s - %s" % (self._getParamUserName("R2"),
+ self._getParamUserName("EP2")))
+
+ def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
+ """
+ Create the circular sections used to build the pipe.
+ """
+ outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
+ outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
+ if self.filling == HOLLOW:
+ innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
+ self.R1 - self.EP1)
+ innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
+ self.R2 - self.EP2)
+ else:
+ innerCircle1 = None
+ innerCircle2 = None
+
+ return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
+
+
+class RectangularBeam(Beam):
+ """
+ This class defines a beam with a rectangular section. It can be full or
+ hollow, and its dimensions can vary from one end of the beam to the other.
+ The valid parameters for rectangular beams are:
+
+ * "HY1", "HY", "H1" or "H": width at the first end of the beam.
+ * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
+ * "HY2", "HY", "H2" or "H": width at the other end of the beam.
+ * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
+ * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
+ direction at the first end of the beam. If not specified or equal to 0,
+ the beam is considered full.
+ * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
+ direction at the first end of the beam. If not specified or equal to 0,
+ the beam is considered full.
+ * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
+ direction at the other end of the beam. If not specified or equal to 0,
+ the beam is considered full.
+ * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
+ direction at the other end of the beam. If not specified or equal to 0,
+ the beam is considered full.
+
+ See class :class:`StructuralElementPart` for the description of the
+ other parameters.
+
+ """
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = Beam.DEFAULT_NAME):
+ Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
+ name)
+
+ self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
+ self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
+ self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
+ self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
+ self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
+ self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
+ self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
+ self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
+
+ if self.EPY1 is None or self.EPZ1 is None or \
+ self.EPY2 is None or self.EPZ2 is None or \
+ self.EPY1 == 0 or self.EPZ1 == 0 or \
+ self.EPY2 == 0 or self.EPZ2 == 0:
+ self.filling = FULL
+ else:
+ self.filling = HOLLOW
+
+ logger.debug(repr(self))
+
+ # Check parameters
+ self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
+ self._getParamUserName("HY1"))
+ self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
+ self._getParamUserName("HZ1"))
+ self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
+ self._getParamUserName("HY2"))
+ self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
+ self._getParamUserName("HZ2"))
+ if self.filling == HOLLOW:
+ self._checkSize(self.EPY1, MIN_THICKNESS,
+ self._getParamUserName("EPY1"))
+ self._checkSize(self.EPZ1, MIN_THICKNESS,
+ self._getParamUserName("EPZ1"))
+ self._checkSize(self.EPY2, MIN_THICKNESS,
+ self._getParamUserName("EPY2"))
+ self._checkSize(self.EPZ2, MIN_THICKNESS,
+ self._getParamUserName("EPZ2"))
+ self._checkSize(self.HY1 - 2 * self.EPY1,
+ MIN_DIM_FOR_EXTRUDED_SHAPE,
+ "%s - 2 * %s" % (self._getParamUserName("HY1"),
+ self._getParamUserName("EPY1")))
+ self._checkSize(self.HZ1 - 2 * self.EPZ1,
+ MIN_DIM_FOR_EXTRUDED_SHAPE,
+ "%s - 2 * %s" % (self._getParamUserName("HZ1"),
+ self._getParamUserName("EPZ1")))
+ self._checkSize(self.HY2 - 2 * self.EPY2,
+ MIN_DIM_FOR_EXTRUDED_SHAPE,
+ "%s - 2 * %s" % (self._getParamUserName("HY2"),
+ self._getParamUserName("EPY2")))
+ self._checkSize(self.HZ2 - 2 * self.EPZ2,
+ MIN_DIM_FOR_EXTRUDED_SHAPE,
+ "%s - 2 * %s" % (self._getParamUserName("HZ2"),
+ self._getParamUserName("EPZ2")))
+
+ def _makeRectangle(self, HY, HZ, planeSect):
+ """
+ Create a rectangle in the specified plane.
+ """
+ halfHY = HY / 2.0
+ halfHZ = HZ / 2.0
+ sketchStr = "Sketcher:F %g" % (-halfHZ) + " %g" % (-halfHY) + ":"
+ sketchStr += "TT %g" % (halfHZ) + " %g" % (-halfHY) + ":"
+ sketchStr += "TT %g" % (halfHZ) + " %g" % (halfHY) + ":"
+ sketchStr += "TT %g" % (-halfHZ) + " %g" % (halfHY) + ":WW"
+ logger.debug('Drawing rectangle: "%s"' % sketchStr)
+ sketch = self.geom.MakeSketcherOnPlane(sketchStr, planeSect)
+ return sketch
+
+ def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
+ """
+ Create the rectangular sections used to build the pipe.
+ """
+ planeSect1 = self.geom.MakePlane(fPoint, fNormal, 1.0)
+ outerRect1 = self._makeRectangle(self.HY1, self.HZ1, planeSect1)
+ planeSect2 = self.geom.MakePlane(lPoint, lNormal, 1.0)
+ outerRect2 = self._makeRectangle(self.HY2, self.HZ2, planeSect2)
+ if self.filling == HOLLOW:
+ innerRect1 = self._makeRectangle(self.HY1 - 2 * self.EPY1,
+ self.HZ1 - 2 * self.EPZ1,
+ planeSect1)
+ innerRect2 = self._makeRectangle(self.HY2 - 2 * self.EPY2,
+ self.HZ2 - 2 * self.EPZ2,
+ planeSect2)
+ else:
+ innerRect1 = None
+ innerRect2 = None
+
+ return (outerRect1, innerRect1, outerRect2, innerRect2)
+
+
+class StructuralElementPart2D(StructuralElementPart):
+ """
+ This class is an "abstract" class for all 2D structural element parts. It
+ should not be instantiated directly. See class
+ :class:`StructuralElementPart` for the description of the parameters.
+ """
+
+ DEFAULT_NAME = "StructuralElementPart2D"
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = DEFAULT_NAME):
+ StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
+ parameters, name)
+ self._orientation = orientation.Orientation2D(
+ self._getParameter(["angleAlpha"]),
+ self._getParameter(["angleBeta"]),
+ self._getParameter(["Vecteur"]))
+ self.offset = self._getParameter(["Excentre"], 0.0)
+
+ def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
+ """
+ Create a copy of a face at a given offset.
+ """
+ if abs(offset) < epsilon:
+ return self.geom.MakeCopy(face)
+ else:
+ offsetObj = self.geom.MakeOffset(face, offset)
+ # We have to explode the resulting object into faces because it is
+ # created as a polyhedron and not as a single face
+ faces = self.geom.SubShapeAll(offsetObj,
+ self.geom.ShapeType["FACE"])
+ return faces[0]
+
+ def _buildMarkersWithOffset(self, offset):
+ """
+ Build the markers for the structural element part with a given offset
+ from the base face.
+ """
+ uParam = 0.5
+ vParam = 0.5
+ listMarkers = []
+ subShapes = self._getSubShapes()
+
+ for subShape in subShapes:
+ faces = self.geom.SubShapeAll(subShape,
+ self.geom.ShapeType["FACE"])
+ for face in faces:
+ offsetFace = self._makeFaceOffset(face, offset)
+ # get tangent plane on surface by parameters
+ center = self.geom.MakeVertexOnSurface(offsetFace,
+ uParam, vParam)
+ tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
+ uParam, vParam,
+ 1.0)
+ normal = self.geom.GetNormal(tangPlane)
+ marker = self._orientation.buildMarker(self.geom,
+ center, normal)
+ listMarkers.append(marker)
+
+ return listMarkers
+
+
+class ThickShell(StructuralElementPart2D):
+ """
+ This class defines a shell with a given thickness. It can be shifted from
+ the base face. The valid parameters for thick shells are:
+
+ * "Epais": thickness of the shell.
+ * "Excentre": offset of the shell from the base face.
+ * "angleAlpha": angle used to build the markers (see class
+ :class:`~salome.geom.structelem.orientation.Orientation2D`)
+ * "angleBeta": angle used to build the markers (see class
+ :class:`~salome.geom.structelem.orientation.Orientation2D`)
+ * "Vecteur": vector used instead of the angles to build the markers (see
+ class :class:`~salome.geom.structelem.orientation.Orientation2D`)
+
+ See class :class:`StructuralElementPart` for the description of the
+ other parameters.
+ """
+
+ DEFAULT_NAME = "ThickShell"
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = DEFAULT_NAME):
+ StructuralElementPart2D.__init__(self, studyId, groupName,
+ groupGeomObj, parameters, name)
+ self.thickness = self._getParameter(["Epais"])
+ logger.debug(repr(self))
+
+ def _buildPart(self):
+ """
+ Create the geometrical shapes corresponding to the thick shell.
+ """
+ subShapes = self._getSubShapes()
+ listSolids = []
+
+ for subShape in subShapes:
+ faces = self.geom.SubShapeAll(subShape,
+ self.geom.ShapeType["FACE"])
+ for face in faces:
+ shape = self._buildThickShellForFace(face)
+ listSolids.append(shape)
+
+ if len(listSolids) == 0:
+ return None
+ elif len(listSolids) == 1:
+ return listSolids[0]
+ else:
+ return self.geom.MakeCompound(listSolids)
+
+ def _buildThickShellForFace(self, face):
+ """
+ Create the geometrical shapes corresponding to the thick shell for a
+ given face.
+ """
+ epsilon = 1e-6
+ if self.thickness < 2 * epsilon:
+ return self._makeFaceOffset(face, self.offset, epsilon)
+
+ upperOffset = self.offset + self.thickness / 2.0
+ lowerOffset = self.offset - self.thickness / 2.0
+ ruledMode = True
+ modeSolid = False
+
+ upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
+ lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
+ listShapes = [upperFace, lowerFace]
+ upperWires = self.geom.SubShapeAll(upperFace,
+ self.geom.ShapeType["WIRE"])
+ lowerWires = self.geom.SubShapeAll(lowerFace,
+ self.geom.ShapeType["WIRE"])
+ if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
+ # if the face is a cylinder, we remove the extra side edge
+ upperWires = self._removeCylinderExtraEdge(upperWires)
+ lowerWires = self._removeCylinderExtraEdge(lowerWires)
+ for i in range(len(upperWires)):
+ resShape = self.geom.MakeThruSections([upperWires[i],
+ lowerWires[i]],
+ modeSolid, epsilon,
+ ruledMode)
+ listShapes.append(resShape)
+ resultShell = self.geom.MakeShell(listShapes)
+ resultSolid = self.geom.MakeSolid([resultShell])
+ return resultSolid
+
+ def _removeCylinderExtraEdge(self, wires):
+ """
+ Remove the side edge in a cylinder.
+ """
+ result = []
+ for wire in wires:
+ edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
+ for edge in edges:
+ if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
+ result.append(edge)
+ return result
+
+ def _buildMarkers(self):
+ """
+ Build the markers defining the orientation of the thick shell.
+ """
+ return self._buildMarkersWithOffset(self.offset +
+ self.thickness / 2.0)
+
+
+class Grid(StructuralElementPart2D):
+ """
+ This class defines a grid. A grid is represented by a 2D face patterned
+ with small lines in the main direction of the grid frame. The valid
+ parameters for grids are:
+
+ * "Excentre": offset of the grid from the base face.
+ * "angleAlpha": angle used to build the markers (see class
+ :class:`~salome.geom.structelem.orientation.Orientation2D`)
+ * "angleBeta": angle used to build the markers (see class
+ :class:`~salome.geom.structelem.orientation.Orientation2D`)
+ * "Vecteur": vector used instead of the angles to build the markers (see
+ class :class:`~salome.geom.structelem.orientation.Orientation2D`)
+ * "origAxeX": X coordinate of the origin of the axis used to determine the
+ orientation of the frame in the case of a cylindrical grid.
+ * "origAxeY": Y coordinate of the origin of the axis used to determine the
+ orientation of the frame in the case of a cylindrical grid.
+ * "origAxeZ": Z coordinate of the origin of the axis used to determine the
+ orientation of the frame in the case of a cylindrical grid.
+ * "axeX": X coordinate of the axis used to determine the orientation of
+ the frame in the case of a cylindrical grid.
+ * "axeY": Y coordinate of the axis used to determine the orientation of
+ the frame in the case of a cylindrical grid.
+ * "axeZ": Z coordinate of the axis used to determine the orientation of
+ the frame in the case of a cylindrical grid.
+
+ See class :class:`StructuralElementPart` for the description of the
+ other parameters.
+ """
+
+ DEFAULT_NAME = "Grid"
+
+ def __init__(self, studyId, groupName, groupGeomObj, parameters,
+ name = DEFAULT_NAME):
+ StructuralElementPart2D.__init__(self, studyId, groupName,
+ groupGeomObj, parameters, name)
+ self.xr = self._getParameter(["origAxeX"])
+ self.yr = self._getParameter(["origAxeY"])
+ self.zr = self._getParameter(["origAxeZ"])
+ self.vx = self._getParameter(["axeX"])
+ self.vy = self._getParameter(["axeY"])
+ self.vz = self._getParameter(["axeZ"])
+ logger.debug(repr(self))
+
+ def _buildPart(self):
+ """
+ Create the geometrical shapes representing the grid.
+ """
+ subShapes = self._getSubShapes()
+ listGridShapes = []
+
+ for subShape in subShapes:
+ faces = self.geom.SubShapeAll(subShape,
+ self.geom.ShapeType["FACE"])
+ for face in faces:
+ if self.geom.KindOfShape(face)[0] == \
+ self.geom.kind.CYLINDER2D and \
+ self.xr is not None and self.yr is not None and \
+ self.zr is not None and self.vx is not None and \
+ self.vy is not None and self.vz is not None:
+ shape = self._buildGridForCylinderFace(face)
+ else:
+ shape = self._buildGridForNormalFace(face)
+ listGridShapes.append(shape)
+
+ if len(listGridShapes) == 0:
+ return None
+ elif len(listGridShapes) == 1:
+ return listGridShapes[0]
+ else:
+ return self.geom.MakeCompound(listGridShapes)
+
+ def _buildGridForNormalFace(self, face):
+ """
+ Create the geometrical shapes representing the grid for a given
+ non-cylindrical face.
+ """
+ baseFace = self._makeFaceOffset(face, self.offset)
+ gridList = [baseFace]
+
+ # Compute display length for grid elements
+ p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
+ p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
+ length = self.geom.MinDistance(p1, p2) / 2.0
+
+ for u in range(1, 10):
+ uParam = u * 0.1
+ for v in range(1, 10):
+ vParam = v * 0.1
+ # get tangent plane on surface by parameters
+ center = self.geom.MakeVertexOnSurface(baseFace,
+ uParam, vParam)
+ tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
+ vParam, 1.0)
+
+ # use the marker to get the orientation of the frame
+ normal = self.geom.GetNormal(tangPlane)
+ marker = self._orientation.buildMarker(self.geom, center,
+ normal, False)
+ [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
+ xPoint = self.geom.MakeTranslation(center, Xx * length,
+ Xy * length, Xz * length)
+ gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
+ gridList.append(gridLine)
+ grid = self.geom.MakeCompound(gridList)
+ return grid
+
+ def _buildGridForCylinderFace(self, face):
+ """
+ Create the geometrical shapes representing the grid for a given
+ cylindrical face.
+ """
+ baseFace = self._makeFaceOffset(face, self.offset)
+ gridList = [baseFace]
+
+ # Compute display length for grid elements
+ p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
+ p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
+ length = self.geom.MinDistance(p1, p2) / 2.0
+
+ # Create reference vector V
+ origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
+ vPoint = self.geom.MakeTranslation(origPoint,
+ self.vx, self.vy, self.vz)
+ refVec = self.geom.MakeVector(origPoint, vPoint)
+
+ for u in range(10):
+ uParam = u * 0.1
+ for v in range(1, 10):
+ vParam = v * 0.1
+
+ # Compute the local orientation of the frame
+ center = self.geom.MakeVertexOnSurface(baseFace,
+ uParam, vParam)
+ locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
+ vPoint, 1.0)
+ locOrient = self.geom.GetNormal(locPlaneYZ)
+ xPoint = self.geom.MakeTranslationVectorDistance(center,
+ locOrient,
+ length)
+ gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
+ gridList.append(gridLine)
+
+ grid = self.geom.MakeCompound(gridList)
+ return grid
+
+ def _buildMarkers(self):
+ """
+ Create the markers defining the orientation of the grid.
+ """
+ return self._buildMarkersWithOffset(self.offset)
+
+
+def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
+ name = "POUTRE"):
+ """
+ Alias for class :class:`GeneralBeam`.
+ """
+ return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
+ name = "POUTRE"):
+ """
+ Alias for class :class:`CircularBeam`.
+ """
+ return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
+ name = "POUTRE"):
+ """
+ Alias for class :class:`RectangularBeam`.
+ """
+ return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
+ name = "BARRE"):
+ """
+ Alias for class :class:`GeneralBeam`.
+ """
+ return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
+ name = "BARRE"):
+ """
+ Alias for class :class:`RectangularBeam`.
+ """
+ return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
+ name = "BARRE"):
+ """
+ Alias for class :class:`CircularBeam`.
+ """
+ return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
+ """
+ Alias for class :class:`CircularBeam`.
+ """
+ return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
+ """
+ Alias for class :class:`ThickShell`.
+ """
+ return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
+
+def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
+ """
+ Alias for class :class:`Grid`.
+ """
+ return Grid(studyId, groupName, groupGeomObj, parameters, name)
SUBDIRS = ARCHIMEDE NMTDS NMTTools GEOMAlgo SKETCHER OCC2VTK GEOM \
BREPExport BREPImport IGESExport IGESImport STEPExport \
STEPImport STLExport VTKExport ShHealOper GEOMImpl GEOM_I \
- GEOMClient GEOM_I_Superv GEOM_SWIG
+ GEOMClient GEOM_I_Superv GEOM_SWIG GEOM_PY
if GEOM_ENABLE_GUI
SUBDIRS += OBJECT DlgRef GEOMFiltersSelection GEOMGUI GEOMBase GEOMToolsGUI \
GEOMToolsGUI DisplayGUI BasicGUI PrimitiveGUI GenerationGUI \
EntityGUI BuildGUI BooleanGUI TransformationGUI OperationGUI \
RepairGUI MeasureGUI GroupGUI BlocksGUI AdvancedGUI \
- GEOM_SWIG_WITHIHM
+ GEOM_SWIG_WITHIHM GEOM_PY