Salome HOME
[PYTHON 3] 1st draft
[modules/geom.git] / src / GEOM_PY / structelem / parts.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 ## \defgroup parts parts
23 #  \{ 
24 #  \details
25 #  This module defines the different structural element parts. It is used to
26 #  build the geometric shapes of the structural elements. It should not be used
27 #  directly in the general case. Structural elements should be created by the
28 #  \ref structelem.StructuralElementManager "salome.geom.structelem.StructuralElementManager".
29 #  \}
30
31 """
32 This module defines the different structural element parts. It is used to
33 build the geometric shapes of the structural elements. It should not be used
34 directly in the general case. Structural elements should be created by the
35 class :class:`~salome.geom.structelem.StructuralElementManager`.
36 """
37
38 import math
39
40 import salome
41 import SALOMEDS
42
43 from salome.kernel.logger import Logger
44 from salome.kernel import termcolor
45 logger = Logger("salome.geom.structelem.parts", color = termcolor.RED)
46 from salome.geom.geomtools import getGeompy
47
48 from . import orientation
49
50 # Filling for the beams
51 FULL = "FULL"
52 HOLLOW = "HOLLOW"
53
54 # Minimum dimension for the shapes to extrude
55 MIN_DIM_FOR_EXTRUDED_SHAPE = 2e-4
56 MIN_LENGTH_FOR_EXTRUSION = 1e-4
57 MIN_THICKNESS = 1e-5
58
59 # Colors for the structural elements
60 GREEN = SALOMEDS.Color(0.0, 1.0, 0.0)
61 LIGHT_GREEN = SALOMEDS.Color(0.0, 1.0, 170.0/255.0)
62 BLUE = SALOMEDS.Color(0.0, 0.0, 1.0)
63 LIGHT_BLUE = SALOMEDS.Color(0.0, 0.5, 1.0)
64 RED = SALOMEDS.Color(1.0, 0.0, 0.0)
65 LIGHT_RED = SALOMEDS.Color(1.0, 0.5, 0.5)
66 PURPLE = SALOMEDS.Color(170.0/255.0, 85.0/255.0, 1.0)
67 ORANGE = SALOMEDS.Color(1.0, 170.0/255.0, 0.0)
68
69 ## This exception is raised when an invalid parameter is used to build a
70 #  structural element part.
71 #  \ingroup parts
72 class InvalidParameterError(Exception):
73     """
74     This exception is raised when an invalid parameter is used to build a
75     structural element part.
76     """
77     
78     def __init__(self, groupName, expression, minValue, value):
79         self.groupName = groupName
80         self.expression = expression
81         self.minValue = minValue
82         self.value = value
83         
84     def __str__(self):
85         return "%s < %g (%s = %g in %s)" % (self.expression, self.minValue,
86                                             self.expression, self.value,
87                                             self.groupName)
88
89 ## This class enables the use of sub-shapes in sets or as dictionary keys.
90 #  It implements __eq__ and __hash__ methods so that sub-shapes with the same
91 #  CORBA object \em mainShape and the same \em id are considered equal.
92 #  \ingroup parts
93 class SubShapeID:
94     """
95     This class enables the use of sub-shapes in sets or as dictionary keys.
96     It implements __eq__ and __hash__ methods so that sub-shapes with the same
97     CORBA object `mainShape` and the same `id` are considered equal.
98     """
99
100     def __init__(self, mainShape, id):
101         self._mainShape = mainShape
102         self._id = id
103
104     ## Return the sub-shape (GEOM object). \em geom is a pseudo-geompy object
105     #  used to find the geometrical object.
106     def getObj(self, geom):
107         """
108         Return the sub-shape (GEOM object). `geom` is a pseudo-geompy object
109         used to find the geometrical object.
110         """
111         return geom.GetSubShape(self._mainShape, [self._id])
112     
113     def __eq__(self, other):
114         return self._mainShape._is_equivalent(other._mainShape) and \
115                self._id == other._id
116     
117     def __hash__(self):
118         return self._mainShape._hash(2147483647) ^ self._id
119
120 ## This class is the base class for all structural element parts. It should
121 #  not be instantiated directly (consider it as an "abstract" class).
122 #  \param studyId (integer) the ID of the study in which the part is created.
123 #  \param groupName (string) the name of the underlying geometrical primitive 
124 #  in the study.
125 #  \param groupGeomObj (GEOM object) the underlying geometrical primitive.
126 #  \param parameters (dictionary) parameters defining the structural element (see
127 #  subclasses for details).
128 #  \param name (string) name to use for the created object in the study.
129 #  \ingroup parts
130 class StructuralElementPart:
131     """
132     This class is the base class for all structural element parts. It should
133     not be instantiated directly (consider it as an "abstract" class).
134
135     :type  studyId: integer
136     :param studyId: the ID of the study in which the part is created.
137
138     :type  groupName: string
139     :param groupName: the name of the underlying geometrical primitive in the
140                       study.
141
142     :type  groupGeomObj: GEOM object
143     :param groupGeomObj: the underlying geometrical primitive.
144
145     :type  parameters: dictionary
146     :param parameters: parameters defining the structural element (see
147                        subclasses for details).
148
149     :type  name: string
150     :param name: name to use for the created object in the study.
151
152     """
153     
154     DEFAULT_NAME = "StructElemPart"
155
156     def __init__(self, studyId, groupName, groupGeomObj, parameters,
157                  name = DEFAULT_NAME, color = None):
158         self._parameters = parameters
159         self.groupName = groupName
160         self._groupGeomObj = groupGeomObj
161         self._orientation = None
162         self._paramUserName = {}
163         self.name = name
164         self.geom = getGeompy(studyId)
165         self.baseShapesSet = set()
166         self.isMainShape = (groupGeomObj.GetType() != 37) # See geompyDC.ShapeIdToType for type codes
167         if not self.isMainShape:
168             mainShape = self.geom.GetMainShape(groupGeomObj)
169             listIDs = self.geom.GetObjectIDs(groupGeomObj)
170             if mainShape is not None and listIDs is not None:
171                 for id in listIDs:
172                     self.baseShapesSet.add(SubShapeID(mainShape, id))
173         self.color = color
174         if self.color is None:
175             self.color = self._groupGeomObj.GetColor()
176
177     ## This method finds the value of a parameter in the parameters
178     #  dictionary. The argument is a list because some parameters can have
179     #  several different names.
180     def _getParameter(self, nameList, default = None):
181         """
182         This method finds the value of a parameter in the parameters
183         dictionary. The argument is a list because some parameters can have
184         several different names.
185         """
186         if len(nameList) > 0:
187             paramName = nameList[0]
188         for name in nameList:
189             if name in self._parameters:
190                 self._paramUserName[paramName] = name
191                 return self._parameters[name]
192         return default
193
194     ## This method finds the user name for a parameter.
195     def _getParamUserName(self, paramName):
196         """
197         This method finds the user name for a parameter.
198         """
199         if paramName in self._paramUserName:
200             return self._paramUserName[paramName]
201         else:
202             return paramName
203
204     def __repr__(self):
205         reprdict = self.__dict__.copy()
206         del reprdict["_parameters"]
207         del reprdict["groupName"]
208         del reprdict["_groupGeomObj"]
209         del reprdict["_paramUserName"]
210         del reprdict["name"]
211         del reprdict["geom"]
212         del reprdict["baseShapesSet"]
213         return '%s("%s", %s)' % (self.__class__.__name__, self.groupName,
214                                  reprdict)
215
216     ## Add orientation information to the structural element part. See class
217     #  \ref Orientation1D "salome.geom.structelem.orientation.Orientation1D" 
218     #  for the description of the parameters.
219     def addOrientation(self, orientParams):
220         """
221         Add orientation information to the structural element part. See class
222         :class:`~salome.geom.structelem.orientation.Orientation1D` for the description
223         of the parameters.
224         """
225         self._orientation.addParams(orientParams)
226
227     ## This method checks that some parameters or some expressions involving
228     #  those parameters are greater than a minimum value.
229     def _checkSize(self, value, mindim, expression):
230         """
231         This method checks that some parameters or some expressions involving
232         those parameters are greater than a minimum value.
233         """
234         if value < mindim:
235             raise InvalidParameterError(self.groupName, expression,
236                                         mindim, value)
237
238     ## Build the geometric shapes and the markers corresponding to the
239     #  structural element part in the study \em studyId.
240     def build(self):
241         """
242         Build the geometric shapes and the markers corresponding to the
243         structural element part in the study `studyId`.
244         """
245         shape = self._buildPart()
246         markers = self._buildMarkers()
247         shape.SetColor(self.color)
248         for marker in markers:
249             marker.SetColor(self.color)
250         return (shape, markers)
251
252     ## This abstract method must be implemented in subclasses and should
253     #  create the geometrical shape(s) of the structural element part.
254     def _buildPart(self):
255         """
256         This abstract method must be implemented in subclasses and should
257         create the geometrical shape(s) of the structural element part.
258         """
259         raise NotImplementedError("Method _buildPart not implemented in class"
260                                   " %s (it must be implemented in "
261                                   "StructuralElementPart subclasses)." %
262                                   self.__class__.__name__)
263
264     ## This abstract method must be implemented in subclasses and should
265     #  create the markers defining the orientation of the structural element
266     #  part.
267     def _buildMarkers(self):
268         """
269         This abstract method must be implemented in subclasses and should
270         create the markers defining the orientation of the structural element
271         part.
272         """
273         raise NotImplementedError("Method _buildMarker not implemented in "
274                                   "class %s (it must be implemented in "
275                                   "StructuralElementPart subclasses)." %
276                                   self.__class__.__name__)
277
278     ## Find and return the base sub-shapes in the structural element part.
279     def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
280         """
281         Find and return the base sub-shapes in the structural element part.
282         """
283         if self.isMainShape:
284             return [self._groupGeomObj]
285         subShapes = []
286         for subShapeID in self.baseShapesSet:
287             subShape = subShapeID.getObj(self.geom)
288             length = self.geom.BasicProperties(subShape)[0]
289             if length < minDim:
290                 logger.warning("Length too short (%s - ID %s, length = %g), "
291                                "subshape will not be used in structural "
292                                "element" % (self.groupName, subShapeID._id,
293                                             length))
294             else:
295                 subShapes.append(subShape)
296         return subShapes
297
298 ## This class is an "abstract" class for all 1D structural element parts. It
299 #  should not be instantiated directly. See class StructuralElementPart 
300 #  for the description of the parameters.
301 #  \ingroup parts
302 class Beam(StructuralElementPart):
303     """
304     This class is an "abstract" class for all 1D structural element parts. It
305     should not be instantiated directly. See class
306     :class:`StructuralElementPart` for the description of the parameters.
307     """
308
309     DEFAULT_NAME = "Beam"
310
311     def __init__(self, studyId, groupName, groupGeomObj, parameters,
312                  name = DEFAULT_NAME, color = None):
313         StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
314                                        parameters, name, color)
315         self._orientation = orientation.Orientation1D()
316
317     ## This method checks if a 1D object is "reversed", i.e. if its
318     #  orientation is different than the orientation of the underlying OCC
319     #  object.
320     def _isReversed(self, path):
321         """
322         This method checks if a 1D object is "reversed", i.e. if its
323         orientation is different than the orientation of the underlying OCC
324         object.
325         """
326         length = self.geom.BasicProperties(path)[0]
327         p1 = self.geom.MakeVertexOnCurve(path, 0.0)
328         p2 = self.geom.GetFirstVertex(path)
329         dist = self.geom.MinDistance(p1, p2)
330         return dist > length / 2
331
332     ## Get a vertex and the corresponding tangent on a wire by parameter.
333     #  This method takes into account the "real" orientation of the wire
334     #  (i.e. the orientation of the underlying OCC object).
335     def _getVertexAndTangentOnOrientedWire(self, path, param):
336         """
337         Get a vertex and the corresponding tangent on a wire by parameter.
338         This method takes into account the "real" orientation of the wire
339         (i.e. the orientation of the underlying OCC object).
340         """
341         if self._isReversed(path):
342             vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
343             invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
344             tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
345                                                                invtangent,
346                                                                -1.0)
347             tangent = self.geom.MakeVector(vertex, tanpoint)
348         else:
349             vertex = self.geom.MakeVertexOnCurve(path, param)
350             tangent = self.geom.MakeTangentOnCurve(path, param)
351         return (vertex, tangent)
352
353     ## Create a solid by the extrusion of section \em wire1 to section \em wire2
354     #  along \em path.
355     def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
356         """
357         Create a solid by the extrusion of section `wire1` to section `wire2`
358         along `path`.
359         """
360         face1 = self.geom.MakeFace(wire1, True)
361         face2 = self.geom.MakeFace(wire2, True)
362         shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
363                                                         [point1, point2],
364                                                         path, False, False,
365                                                         False)
366         closedShell = self.geom.MakeShell([face1, face2, shell])
367         solid = self.geom.MakeSolid([closedShell])
368         return solid
369
370     ## Build the structural element part.
371     def _buildPart(self):
372         """
373         Build the structural element part.
374         """
375         # Get all the sub-shapes in the group (normally only edges and wires)
376         paths = self._getSubShapes()
377         listPipes = []
378         withContact = False
379         withCorrection = False
380     
381         for path in paths:
382             # Build the sections (rectangular or circular) at each end of the
383             # beam
384             (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
385                                                                         0.0)
386             (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
387                                                                         1.0)
388             (outerWire1, innerWire1, outerWire2, innerWire2) = \
389                     self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
390
391             # Create the resulting solid
392             outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
393                                                       fPoint, lPoint, path)
394             if self.filling == HOLLOW:
395                 innerSolid = self._makeSolidPipeFromWires(innerWire1,
396                                                           innerWire2, fPoint,
397                                                           lPoint, path)
398                 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
399                 listPipes.append(resultSolid)
400             else:
401                 listPipes.append(outerSolid)
402
403         if len(listPipes) == 0:
404             return None
405         elif len(listPipes) == 1:
406             return listPipes[0]
407         else:
408             return self.geom.MakeCompound(listPipes)
409
410     ## Build the markers defining the orientation of the structural element part.
411     def _buildMarkers(self):
412         """
413         Build the markers defining the orientation of the structural element
414         part.
415         """
416         param = 0.5
417         paths = self._getSubShapes()
418         listMarkers = []
419         for path in paths:
420             (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
421                                                                      param)
422             marker = self._orientation.buildMarker(self.geom, center, vecX)
423             listMarkers.append(marker)
424         return listMarkers
425
426
427 ## This class defines a beam with a circular section. It can be full or
428 #  hollow, and its radius and thickness can vary from one end of the beam to
429 #  the other. The valid parameters for circular beams are:
430 #  - "R1" or "R": radius at the first end of the beam.
431 #  - "R2" or "R": radius at the other end of the beam.
432 #  - "EP1" or "EP" (optional): thickness at the first end of the beam.
433 #    If not specified or equal to 0, the beam is considered full.
434 #  - "EP2" or "EP" (optional): thickness at the other end of the beam.
435 #  If not specified or equal to 0, the beam is considered full.
436 #
437 #  See class StructuralElementPart for the description of the other parameters.
438 #  \ingroup parts
439 class CircularBeam(Beam):
440     """
441     This class defines a beam with a circular section. It can be full or
442     hollow, and its radius and thickness can vary from one end of the beam to
443     the other. The valid parameters for circular beams are:
444
445     * "R1" or "R": radius at the first end of the beam.
446     * "R2" or "R": radius at the other end of the beam.
447     * "EP1" or "EP" (optional): thickness at the first end of the beam.
448       If not specified or equal to 0, the beam is considered full.
449     * "EP2" or "EP" (optional): thickness at the other end of the beam.
450       If not specified or equal to 0, the beam is considered full.
451
452     See class :class:`StructuralElementPart` for the description of the
453     other parameters.
454
455     """
456
457     def __init__(self, studyId, groupName, groupGeomObj, parameters,
458                  name = Beam.DEFAULT_NAME, color = None):
459         if color is None:
460             if "R1" in parameters: # variable section
461                 color = LIGHT_RED
462             else:                       # constant section
463                 color = RED
464
465         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
466                       name, color)
467
468         self.R1 = self._getParameter(["R1", "R"])
469         self.R2 = self._getParameter(["R2", "R"])
470         self.EP1 = self._getParameter(["EP1", "EP"])
471         self.EP2 = self._getParameter(["EP2", "EP"])
472
473         if self.EP1 is None or self.EP2 is None or \
474                                 self.EP1 == 0 or self.EP2 == 0:
475             self.filling = FULL
476         else:
477             self.filling = HOLLOW
478
479         logger.debug(repr(self))
480
481         # Check parameters
482         self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
483                         self._getParamUserName("R1"))
484         self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
485                         self._getParamUserName("R2"))
486         if self.filling == HOLLOW:
487             self._checkSize(self.EP1, MIN_THICKNESS,
488                             self._getParamUserName("EP1"))
489             self._checkSize(self.EP2, MIN_THICKNESS,
490                             self._getParamUserName("EP2"))
491             self._checkSize(self.R1 - self.EP1,
492                             MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
493                             "%s - %s" % (self._getParamUserName("R1"),
494                                          self._getParamUserName("EP1")))
495             self._checkSize(self.R2 - self.EP2,
496                             MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
497                             "%s - %s" % (self._getParamUserName("R2"),
498                                          self._getParamUserName("EP2")))
499
500     ## Create the circular sections used to build the pipe.
501     def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
502         """
503         Create the circular sections used to build the pipe.
504         """
505         outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
506         outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
507         if self.filling == HOLLOW:
508             innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
509                                                 self.R1 - self.EP1)
510             innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
511                                                 self.R2 - self.EP2)
512         else:
513             innerCircle1 = None
514             innerCircle2 = None
515
516         return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
517
518
519 ## This class defines a beam with a rectangular section. It can be full or
520 #  hollow, and its dimensions can vary from one end of the beam to the other.
521 #  The valid parameters for rectangular beams are:
522 #  - "HY1", "HY", "H1" or "H": width at the first end of the beam.
523 #  - "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
524 #  - "HY2", "HY", "H2" or "H": width at the other end of the beam.
525 #  - "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
526 #  - "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
527 #    direction at the first end of the beam. If not specified or equal to 0,
528 #    the beam is considered full.
529 #  - "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
530 #    direction at the first end of the beam. If not specified or equal to 0,
531 #    the beam is considered full.
532 #  - "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
533 #    direction at the other end of the beam. If not specified or equal to 0,
534 #    the beam is considered full.
535 #  - "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
536 #    direction at the other end of the beam. If not specified or equal to 0,
537 #    the beam is considered full.
538 #
539 #   See class StructuralElementPart for the description of the other parameters.
540 #  \ingroup parts
541 class RectangularBeam(Beam):
542     """
543     This class defines a beam with a rectangular section. It can be full or
544     hollow, and its dimensions can vary from one end of the beam to the other.
545     The valid parameters for rectangular beams are:
546
547     * "HY1", "HY", "H1" or "H": width at the first end of the beam.
548     * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
549     * "HY2", "HY", "H2" or "H": width at the other end of the beam.
550     * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
551     * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
552       direction at the first end of the beam. If not specified or equal to 0,
553       the beam is considered full.
554     * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
555       direction at the first end of the beam. If not specified or equal to 0,
556       the beam is considered full.
557     * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
558       direction at the other end of the beam. If not specified or equal to 0,
559       the beam is considered full.
560     * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
561       direction at the other end of the beam. If not specified or equal to 0,
562       the beam is considered full.
563
564     See class :class:`StructuralElementPart` for the description of the
565     other parameters.
566
567     """
568
569     def __init__(self, studyId, groupName, groupGeomObj, parameters,
570                  name = Beam.DEFAULT_NAME, color = None):
571         if color is None:
572             if "HY1" in parameters or "H1" in parameters:
573                 color = LIGHT_BLUE # variable section
574             else:                  # constant section
575                 color = BLUE
576
577         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
578                       name, color)
579
580         self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
581         self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
582         self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
583         self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
584         self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
585         self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
586         self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
587         self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
588
589         if self.EPY1 is None or self.EPZ1 is None or \
590            self.EPY2 is None or self.EPZ2 is None or \
591            self.EPY1 == 0 or self.EPZ1 == 0 or \
592            self.EPY2 == 0 or self.EPZ2 == 0:
593             self.filling = FULL
594         else:
595             self.filling = HOLLOW
596
597         logger.debug(repr(self))
598
599         # Check parameters
600         self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
601                         self._getParamUserName("HY1"))
602         self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
603                         self._getParamUserName("HZ1"))
604         self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
605                         self._getParamUserName("HY2"))
606         self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
607                         self._getParamUserName("HZ2"))
608         if self.filling == HOLLOW:
609             self._checkSize(self.EPY1, MIN_THICKNESS,
610                             self._getParamUserName("EPY1"))
611             self._checkSize(self.EPZ1, MIN_THICKNESS,
612                             self._getParamUserName("EPZ1"))
613             self._checkSize(self.EPY2, MIN_THICKNESS,
614                             self._getParamUserName("EPY2"))
615             self._checkSize(self.EPZ2, MIN_THICKNESS,
616                             self._getParamUserName("EPZ2"))
617             self._checkSize(self.HY1 - 2 * self.EPY1,
618                             MIN_DIM_FOR_EXTRUDED_SHAPE,
619                             "%s - 2 * %s" % (self._getParamUserName("HY1"),
620                                              self._getParamUserName("EPY1")))
621             self._checkSize(self.HZ1 - 2 * self.EPZ1,
622                             MIN_DIM_FOR_EXTRUDED_SHAPE,
623                             "%s - 2 * %s" % (self._getParamUserName("HZ1"),
624                                              self._getParamUserName("EPZ1")))
625             self._checkSize(self.HY2 - 2 * self.EPY2,
626                             MIN_DIM_FOR_EXTRUDED_SHAPE,
627                             "%s - 2 * %s" % (self._getParamUserName("HY2"),
628                                              self._getParamUserName("EPY2")))
629             self._checkSize(self.HZ2 - 2 * self.EPZ2,
630                             MIN_DIM_FOR_EXTRUDED_SHAPE,
631                             "%s - 2 * %s" % (self._getParamUserName("HZ2"),
632                                              self._getParamUserName("EPZ2")))
633
634     ## Create a rectangle in the specified plane.
635     def _makeRectangle(self, HY, HZ, lcs):
636         """
637         Create a rectangle in the specified plane.
638         """
639         halfHY = HY / 2.0
640         halfHZ = HZ / 2.0
641         sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
642         sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
643         sketchStr += "TT %g %g:" % (halfHY, halfHZ)
644         sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
645         logger.debug('Drawing rectangle: "%s"' % sketchStr)
646         sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
647         return sketch
648
649     ## Create one side of the rectangular sections used to build the pipe.
650     def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
651         """
652         Create one side of the rectangular sections used to build the pipe.
653         """
654         (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
655         lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
656         outerRect = self._makeRectangle(HY, HZ, lcs)
657         if self.filling == HOLLOW:
658             innerRect = self._makeRectangle(HY - 2.0 * EPY,
659                                             HZ - 2.0 * EPZ,
660                                             lcs)
661         else:
662             innerRect = None
663         return (outerRect, innerRect)
664
665     ## Create the rectangular sections used to build the pipe.
666     def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
667         """
668         Create the rectangular sections used to build the pipe.
669         """
670         (outerRect1, innerRect1) = \
671             self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
672                                         self.EPY1, self.EPZ1)
673         (outerRect2, innerRect2) = \
674             self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
675                                         self.EPY2, self.EPZ2)
676         return (outerRect1, innerRect1, outerRect2, innerRect2)
677
678
679 ## This method finds the value of a parameter in the parameters
680 #  dictionary. The argument is a list because some parameters can have
681 #  several different names.
682 #  \ingroup parts
683 def getParameterInDict(nameList, parametersDict, default = None):
684     """
685     This method finds the value of a parameter in the parameters
686     dictionary. The argument is a list because some parameters can have
687     several different names.
688     """
689     for name in nameList:
690         if name in parametersDict:
691             return parametersDict[name]
692     return default
693
694 ## This class defines a beam with a generic section. It is represented as a
695 #  full rectangular beam with the following parameters:
696 #  - HY1 = sqrt(12 * IZ1 / A1)
697 #  - HZ1 = sqrt(12 * IY1 / A1)
698 #  - HY2 = sqrt(12 * IZ2 / A2)
699 #  - HZ2 = sqrt(12 * IY2 / A2)
700 #    
701 #  See StructuralElementPart for the description of the other parameters.
702 #  \ingroup parts
703 class GeneralBeam(RectangularBeam):
704     """
705     This class defines a beam with a generic section. It is represented as a
706     full rectangular beam with the following parameters:
707     
708     * HY1 = sqrt(12 * IZ1 / A1)
709     * HZ1 = sqrt(12 * IY1 / A1)
710     * HY2 = sqrt(12 * IZ2 / A2)
711     * HZ2 = sqrt(12 * IY2 / A2)
712     
713     See class :class:`StructuralElementPart` for the description of the other
714     parameters.
715     """
716
717     def __init__(self, studyId, groupName, groupGeomObj, parameters,
718                  name = Beam.DEFAULT_NAME, color = None):
719         self.IY1 = getParameterInDict(["IY1", "IY"], parameters)
720         self.IZ1 = getParameterInDict(["IZ1", "IZ"], parameters)
721         self.IY2 = getParameterInDict(["IY2", "IY"], parameters)
722         self.IZ2 = getParameterInDict(["IZ2", "IZ"], parameters)
723         self.A1 = getParameterInDict(["A1", "A"], parameters)
724         self.A2 = getParameterInDict(["A2", "A"], parameters)
725         parameters["HY1"] = math.sqrt(12 * self.IZ1 / self.A1)
726         parameters["HZ1"] = math.sqrt(12 * self.IY1 / self.A1)
727         parameters["HY2"] = math.sqrt(12 * self.IZ2 / self.A2)
728         parameters["HZ2"] = math.sqrt(12 * self.IY2 / self.A2)
729
730         if color is None:
731             if "IY1" in parameters: # variable section
732                 color = LIGHT_GREEN
733             else:                         # constant section
734                 color = GREEN
735
736         RectangularBeam.__init__(self, studyId, groupName, groupGeomObj, parameters,
737                                  name, color)
738
739 ## This class is an "abstract" class for all 2D structural element parts. It
740 #  should not be instantiated directly. 
741 #  See class StructuralElementPart for the description of the parameters.
742 #  \ingroup parts
743 class StructuralElementPart2D(StructuralElementPart):
744     """
745     This class is an "abstract" class for all 2D structural element parts. It
746     should not be instantiated directly. See class
747     :class:`StructuralElementPart` for the description of the parameters.
748     """
749
750     DEFAULT_NAME = "StructuralElementPart2D"
751
752     def __init__(self, studyId, groupName, groupGeomObj, parameters,
753                  name = DEFAULT_NAME):
754         StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
755                                        parameters, name)
756         self._orientation = orientation.Orientation2D(
757                                         self._getParameter(["angleAlpha"]),
758                                         self._getParameter(["angleBeta"]),
759                                         self._getParameter(["Vecteur"]))
760         self.offset = self._getParameter(["Excentre"], 0.0)
761
762     ## Create a copy of a face at a given offset.
763     def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
764         """
765         Create a copy of a face at a given offset.
766         """
767         if abs(offset) < epsilon:
768             return self.geom.MakeCopy(face)
769         else:
770             offsetObj = self.geom.MakeOffset(face, offset)
771             # We have to explode the resulting object into faces because it is
772             # created as a polyhedron and not as a single face
773             faces = self.geom.SubShapeAll(offsetObj,
774                                           self.geom.ShapeType["FACE"])
775             return faces[0]
776
777     ## Build the markers for the structural element part with a given offset
778     #  from the base face.
779     def _buildMarkersWithOffset(self, offset):
780         """
781         Build the markers for the structural element part with a given offset
782         from the base face.
783         """
784         uParam = 0.5
785         vParam = 0.5
786         listMarkers = []
787         subShapes = self._getSubShapes()
788     
789         for subShape in subShapes:
790             faces = self.geom.SubShapeAll(subShape,
791                                           self.geom.ShapeType["FACE"])
792             for face in faces:
793                 offsetFace = self._makeFaceOffset(face, offset)
794                 # get the center of the face and the normal at the center
795                 center = self.geom.MakeVertexOnSurface(offsetFace,
796                                                        uParam, vParam)
797                 normal = self.geom.GetNormal(offsetFace, center)
798                 marker = self._orientation.buildMarker(self.geom,
799                                                        center, normal)
800                 listMarkers.append(marker)
801
802         return listMarkers
803
804 ## This class defines a shell with a given thickness. It can be shifted from
805 #  the base face. The valid parameters for thick shells are:
806 #  - "Epais": thickness of the shell.
807 #  - "Excentre": offset of the shell from the base face.
808 #  - "angleAlpha": angle used to build the markers (see class
809 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
810 #  - "angleBeta": angle used to build the markers (see class
811 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
812 #  - "Vecteur": vector used instead of the angles to build the markers (see
813 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
814 #
815 #    See class StructuralElementPart for the description of the other parameters.
816 #  \ingroup parts
817 class ThickShell(StructuralElementPart2D):
818     """
819     This class defines a shell with a given thickness. It can be shifted from
820     the base face. The valid parameters for thick shells are:
821
822     * "Epais": thickness of the shell.
823     * "Excentre": offset of the shell from the base face.
824     * "angleAlpha": angle used to build the markers (see class
825       :class:`~salome.geom.structelem.orientation.Orientation2D`)
826     * "angleBeta": angle used to build the markers (see class
827       :class:`~salome.geom.structelem.orientation.Orientation2D`)
828     * "Vecteur": vector used instead of the angles to build the markers (see
829       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
830
831     See class :class:`StructuralElementPart` for the description of the
832     other parameters.
833     """
834
835     DEFAULT_NAME = "ThickShell"
836
837     def __init__(self, studyId, groupName, groupGeomObj, parameters,
838                  name = DEFAULT_NAME):
839         StructuralElementPart2D.__init__(self, studyId, groupName,
840                                          groupGeomObj, parameters, name)
841         self.thickness = self._getParameter(["Epais"])
842         logger.debug(repr(self))
843
844     ## Create the geometrical shapes corresponding to the thick shell.
845     def _buildPart(self):
846         """
847         Create the geometrical shapes corresponding to the thick shell.
848         """
849         subShapes = self._getSubShapes()
850         listSolids = []
851     
852         for subShape in subShapes:
853             faces = self.geom.SubShapeAll(subShape,
854                                           self.geom.ShapeType["FACE"])
855             for face in faces:
856                 shape = self._buildThickShellForFace(face)
857                 listSolids.append(shape)
858
859         if len(listSolids) == 0:
860             return None
861         elif len(listSolids) == 1:
862             return listSolids[0]
863         else:
864             return self.geom.MakeCompound(listSolids)
865
866     ## Create the geometrical shapes corresponding to the thick shell for a
867     #  given face.
868     def _buildThickShellForFace(self, face):
869         """
870         Create the geometrical shapes corresponding to the thick shell for a
871         given face.
872         """
873         epsilon = 1e-6
874         if self.thickness < 2 * epsilon:
875             return self._makeFaceOffset(face, self.offset, epsilon)
876
877         upperOffset = self.offset + self.thickness / 2.0
878         lowerOffset = self.offset - self.thickness / 2.0
879         ruledMode = True
880         modeSolid = False
881
882         upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
883         lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
884         listShapes = [upperFace, lowerFace]
885         upperWires = self.geom.SubShapeAll(upperFace,
886                                            self.geom.ShapeType["WIRE"])
887         lowerWires = self.geom.SubShapeAll(lowerFace,
888                                            self.geom.ShapeType["WIRE"])
889         if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
890             # if the face is a cylinder, we remove the extra side edge
891             upperWires = self._removeCylinderExtraEdge(upperWires)
892             lowerWires = self._removeCylinderExtraEdge(lowerWires)
893         for i in range(len(upperWires)):
894             resShape = self.geom.MakeThruSections([upperWires[i],
895                                                    lowerWires[i]],
896                                                   modeSolid, epsilon,
897                                                   ruledMode)
898             listShapes.append(resShape)
899         resultShell = self.geom.MakeShell(listShapes)
900         resultSolid = self.geom.MakeSolid([resultShell])
901         return resultSolid
902
903     ## Remove the side edge in a cylinder.
904     def _removeCylinderExtraEdge(self, wires):
905         """
906         Remove the side edge in a cylinder.
907         """
908         result = []
909         for wire in wires:
910             edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
911             for edge in edges:
912                 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
913                     result.append(edge)
914         return result
915
916     ## Build the markers defining the orientation of the thick shell.
917     def _buildMarkers(self):
918         """
919         Build the markers defining the orientation of the thick shell.
920         """
921         return self._buildMarkersWithOffset(self.offset +
922                                             self.thickness / 2.0)
923
924 ## This class defines a grid. A grid is represented by a 2D face patterned
925 #  with small lines in the main direction of the grid frame. The valid
926 #  parameters for grids are:
927 #  - "Excentre": offset of the grid from the base face.
928 #  - "angleAlpha": angle used to build the markers (see class
929 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
930 #  - "angleBeta": angle used to build the markers (see class
931 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
932 #  - "Vecteur": vector used instead of the angles to build the markers (see
933 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
934 #  - "origAxeX": X coordinate of the origin of the axis used to determine the
935 #    orientation of the frame in the case of a cylindrical grid.
936 #  - "origAxeY": Y coordinate of the origin of the axis used to determine the
937 #    orientation of the frame in the case of a cylindrical grid.
938 #  - "origAxeZ": Z coordinate of the origin of the axis used to determine the
939 #    orientation of the frame in the case of a cylindrical grid.
940 #  - "axeX": X coordinate of the axis used to determine the orientation of
941 #    the frame in the case of a cylindrical grid.
942 #  - "axeY": Y coordinate of the axis used to determine the orientation of
943 #    the frame in the case of a cylindrical grid.
944 #  - "axeZ": Z coordinate of the axis used to determine the orientation of
945 #    the frame in the case of a cylindrical grid.
946 #
947 #    See class StructuralElementPart for the description of the other parameters.
948 #  \ingroup parts
949 class Grid(StructuralElementPart2D):
950     """
951     This class defines a grid. A grid is represented by a 2D face patterned
952     with small lines in the main direction of the grid frame. The valid
953     parameters for grids are:
954
955     * "Excentre": offset of the grid from the base face.
956     * "angleAlpha": angle used to build the markers (see class
957       :class:`~salome.geom.structelem.orientation.Orientation2D`)
958     * "angleBeta": angle used to build the markers (see class
959       :class:`~salome.geom.structelem.orientation.Orientation2D`)
960     * "Vecteur": vector used instead of the angles to build the markers (see
961       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
962     * "origAxeX": X coordinate of the origin of the axis used to determine the
963       orientation of the frame in the case of a cylindrical grid.
964     * "origAxeY": Y coordinate of the origin of the axis used to determine the
965       orientation of the frame in the case of a cylindrical grid.
966     * "origAxeZ": Z coordinate of the origin of the axis used to determine the
967       orientation of the frame in the case of a cylindrical grid.
968     * "axeX": X coordinate of the axis used to determine the orientation of
969       the frame in the case of a cylindrical grid.
970     * "axeY": Y coordinate of the axis used to determine the orientation of
971       the frame in the case of a cylindrical grid.
972     * "axeZ": Z coordinate of the axis used to determine the orientation of
973       the frame in the case of a cylindrical grid.
974
975     See class :class:`StructuralElementPart` for the description of the
976     other parameters.
977     """
978
979     DEFAULT_NAME = "Grid"
980
981     def __init__(self, studyId, groupName, groupGeomObj, parameters,
982                  name = DEFAULT_NAME):
983         StructuralElementPart2D.__init__(self, studyId, groupName,
984                                          groupGeomObj, parameters, name)
985         self.xr = self._getParameter(["origAxeX"])
986         self.yr = self._getParameter(["origAxeY"])
987         self.zr = self._getParameter(["origAxeZ"])
988         self.vx = self._getParameter(["axeX"])
989         self.vy = self._getParameter(["axeY"])
990         self.vz = self._getParameter(["axeZ"])
991         logger.debug(repr(self))
992
993     ## Create the geometrical shapes representing the grid.
994     def _buildPart(self):
995         """
996         Create the geometrical shapes representing the grid.
997         """
998         subShapes = self._getSubShapes()
999         listGridShapes = []
1000     
1001         for subShape in subShapes:
1002             faces = self.geom.SubShapeAll(subShape,
1003                                           self.geom.ShapeType["FACE"])
1004             for face in faces:
1005                 if self.geom.KindOfShape(face)[0] == \
1006                                         self.geom.kind.CYLINDER2D and \
1007                         self.xr is not None and self.yr is not None and \
1008                         self.zr is not None and self.vx is not None and \
1009                         self.vy is not None and self.vz is not None:
1010                     shape = self._buildGridForCylinderFace(face)
1011                 else:
1012                     shape = self._buildGridForNormalFace(face)
1013                 listGridShapes.append(shape)
1014
1015         if len(listGridShapes) == 0:
1016             return None
1017         elif len(listGridShapes) == 1:
1018             return listGridShapes[0]
1019         else:
1020             return self.geom.MakeCompound(listGridShapes)
1021
1022     ## Create the geometrical shapes representing the grid for a given
1023     #  non-cylindrical face.
1024     def _buildGridForNormalFace(self, face):
1025         """
1026         Create the geometrical shapes representing the grid for a given
1027         non-cylindrical face.
1028         """
1029         baseFace = self._makeFaceOffset(face, self.offset)
1030         gridList = [baseFace]
1031         
1032         # Compute display length for grid elements
1033         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1034         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1035         length = self.geom.MinDistance(p1, p2) / 2.0
1036
1037         for u in range(1, 10):
1038             uParam = u * 0.1
1039             for v in range(1, 10):
1040                 vParam = v * 0.1
1041                 # get tangent plane on surface by parameters
1042                 center = self.geom.MakeVertexOnSurface(baseFace,
1043                                                        uParam, vParam)
1044                 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
1045                                                              vParam, 1.0)
1046                 
1047                 # use the marker to get the orientation of the frame
1048                 normal = self.geom.GetNormal(tangPlane)
1049                 marker = self._orientation.buildMarker(self.geom, center,
1050                                                        normal, False)
1051                 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
1052                 xPoint = self.geom.MakeTranslation(center, Xx * length,
1053                                                    Xy * length, Xz * length)
1054                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1055                 gridList.append(gridLine)
1056         grid = self.geom.MakeCompound(gridList)
1057         return grid
1058
1059     ## Create the geometrical shapes representing the grid for a given
1060     #  cylindrical face.
1061     def _buildGridForCylinderFace(self, face):
1062         """
1063         Create the geometrical shapes representing the grid for a given
1064         cylindrical face.
1065         """
1066         baseFace = self._makeFaceOffset(face, self.offset)
1067         gridList = [baseFace]
1068         
1069         # Compute display length for grid elements
1070         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1071         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1072         length = self.geom.MinDistance(p1, p2) / 2.0
1073         
1074         # Create reference vector V
1075         origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
1076         vPoint = self.geom.MakeTranslation(origPoint,
1077                                            self.vx, self.vy, self.vz)
1078         refVec = self.geom.MakeVector(origPoint, vPoint)
1079
1080         for u in range(10):
1081             uParam = u * 0.1
1082             for v in range(1, 10):
1083                 vParam = v * 0.1
1084                 
1085                 # Compute the local orientation of the frame
1086                 center = self.geom.MakeVertexOnSurface(baseFace,
1087                                                        uParam, vParam)
1088                 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
1089                                                          vPoint, 1.0)
1090                 locOrient = self.geom.GetNormal(locPlaneYZ)
1091                 xPoint = self.geom.MakeTranslationVectorDistance(center,
1092                                                                  locOrient,
1093                                                                  length)
1094                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1095                 gridList.append(gridLine)
1096
1097         grid = self.geom.MakeCompound(gridList)
1098         return grid
1099
1100     ## Create the markers defining the orientation of the grid.
1101     def _buildMarkers(self):
1102         """
1103         Create the markers defining the orientation of the grid.
1104         """
1105         return self._buildMarkersWithOffset(self.offset)
1106
1107 ## Alias for class GeneralBeam.
1108 #  \ingroup parts
1109 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
1110                        name = "POUTRE"):
1111     """
1112     Alias for class :class:`GeneralBeam`.
1113     """
1114     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
1115
1116 ## Alias for class CircularBeam.
1117 #  \ingroup parts
1118 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
1119                      name = "POUTRE"):
1120     """
1121     Alias for class :class:`CircularBeam`.
1122     """
1123     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
1124
1125 ## Alias for class RectangularBeam. 
1126 #  \ingroup parts
1127 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
1128                         name = "POUTRE"):
1129     """
1130     Alias for class :class:`RectangularBeam`.
1131     """
1132     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
1133
1134 ## Alias for class GeneralBeam.  
1135 #  \ingroup parts
1136 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
1137                       name = "BARRE"):
1138     """
1139     Alias for class :class:`GeneralBeam`.
1140     """
1141     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
1142                        color = ORANGE)
1143
1144 ## Alias for class RectangularBeam.      
1145 #  \ingroup parts
1146 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
1147                        name = "BARRE"):
1148     """
1149     Alias for class :class:`RectangularBeam`.
1150     """
1151     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
1152                            color = ORANGE)
1153
1154 ## Alias for class CircularBeam.
1155 #  \ingroup parts
1156 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
1157                     name = "BARRE"):
1158     """
1159     Alias for class :class:`CircularBeam`.
1160     """
1161     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1162                         color = ORANGE)
1163
1164 ## Alias for class CircularBeam.
1165 #  \ingroup parts
1166 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
1167     """
1168     Alias for class :class:`CircularBeam`.
1169     """
1170     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1171                         color = PURPLE)
1172
1173 ## Alias for class ThickShell.
1174 #  \ingroup parts
1175 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
1176     """
1177     Alias for class :class:`ThickShell`.
1178     """
1179     return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
1180
1181 ## Alias for class Grid.
1182 #  \ingroup parts
1183 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
1184     """
1185     Alias for class :class:`Grid`.
1186     """
1187     return Grid(studyId, groupName, groupGeomObj, parameters, name)