Adding salome.geom python package

This commit is contained in:
boulant 2010-07-29 09:38:04 +00:00
parent 4dfe2cd0b6
commit ba2b4f7d08
15 changed files with 2269 additions and 6 deletions

View File

@ -316,6 +316,13 @@ echo
CHECK_HTML_GENERATORS
echo
echo ---------------------------------------------
echo testing sphinx
echo ---------------------------------------------
echo
CHECK_SPHINX
echo
echo ---------------------------------------------
echo Testing Kernel
@ -333,11 +340,11 @@ echo
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 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 hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok sphinx_ok Kernel_ok gui_ok"
else
variables="cc_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok Kernel_ok"
variables="cc_ok lex_yacc_ok python_ok swig_ok threads_ok hdf5_ok omniORB_ok boost_ok occ_ok doxygen_ok graphviz_ok sphinx_ok Kernel_ok"
fi
for var in $variables
@ -381,6 +388,7 @@ AC_OUTPUT([ \
bin/Makefile \
GEOM_version.h \
doc/Makefile \
doc/docutils/Makefile \
doc/salome/Makefile \
doc/salome/gui/Makefile \
doc/salome/gui/GEOM/Makefile \
@ -415,6 +423,8 @@ AC_OUTPUT([ \
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 \

View File

@ -24,7 +24,7 @@
# $Header$
# source path
#
SUBDIRS = salome
SUBDIRS = salome docutils
usr_docs:
(cd salome && $(MAKE) $(AM_MAKEFLAGS) usr_docs)

92
doc/docutils/Makefile.am Normal file
View File

@ -0,0 +1,92 @@
# -*- 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)/docutils/GEOM
.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

200
doc/docutils/conf.py Normal file
View File

@ -0,0 +1,200 @@
# -*- 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

43
doc/docutils/docapi.rst Normal file
View File

@ -0,0 +1,43 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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:

14
doc/docutils/index.rst Normal file
View File

@ -0,0 +1,14 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Documentation of the GEOM python packages
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Main documentation
==================
.. toctree::
:maxdepth: 3
overview.rst
docapi.rst

31
doc/docutils/overview.rst Normal file
View File

@ -0,0 +1,31 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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:
>>> from salome.geom.structelem import TEST_StructuralElement
>>> TEST_StructuralElement()
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``.

27
src/GEOM_PY/Makefile.am Normal file
View File

@ -0,0 +1,27 @@
# 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

1
src/GEOM_PY/__init__.py Normal file
View File

@ -0,0 +1 @@
# -*- coding: iso-8859-1 -*-

115
src/GEOM_PY/geomtools.py Normal file
View File

@ -0,0 +1,115 @@
# -*- 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

View File

@ -0,0 +1,26 @@
# 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

View File

@ -0,0 +1,486 @@
# -*- 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()

View File

@ -0,0 +1,249 @@
# -*- 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

View File

@ -0,0 +1,969 @@
# -*- 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)

View File

@ -24,7 +24,7 @@
SUBDIRS = ARCHIMEDE NMTDS NMTTools GEOMAlgo SKETCHER GEOM BREPExport \
BREPImport IGESExport IGESImport STEPExport STEPImport \
STLExport ShHealOper GEOMImpl GEOM_I GEOMClient GEOM_I_Superv \
GEOM_SWIG
GEOM_SWIG GEOM_PY
if GEOM_ENABLE_GUI
SUBDIRS += OBJECT DlgRef GEOMFiltersSelection GEOMGUI GEOMBase GEOMToolsGUI \
@ -39,4 +39,4 @@ DIST_SUBDIRS = ARCHIMEDE NMTDS NMTTools GEOMAlgo SKETCHER GEOM BREPExport \
OBJECT DlgRef GEOMFiltersSelection GEOMGUI GEOMBase GEOMToolsGUI \
DisplayGUI BasicGUI PrimitiveGUI GenerationGUI EntityGUI \
BuildGUI BooleanGUI TransformationGUI OperationGUI RepairGUI \
MeasureGUI GroupGUI BlocksGUI AdvancedGUI GEOM_SWIG_WITHIHM
MeasureGUI GroupGUI BlocksGUI AdvancedGUI GEOM_SWIG_WITHIHM GEOM_PY