Salome HOME
Merge branch 'fbt/add_header_for_mpi_compilation'
[modules/geom.git] / src / GEOM_PY / structelem / parts.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2015  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 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 self._parameters.has_key(name):
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 self._paramUserName.has_key(paramName):
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         closedShell = self.geom.MakeShell([face1, face2, shell])
366         solid = self.geom.MakeSolid([closedShell])
367         return solid
368
369     ## Build the structural element part.
370     def _buildPart(self):
371         """
372         Build the structural element part.
373         """
374         # Get all the sub-shapes in the group (normally only edges and wires)
375         paths = self._getSubShapes()
376         listPipes = []
377         withContact = False
378         withCorrection = False
379     
380         for path in paths:
381             # Build the sections (rectangular or circular) at each end of the
382             # beam
383             (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
384                                                                         0.0)
385             (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
386                                                                         1.0)
387             (outerWire1, innerWire1, outerWire2, innerWire2) = \
388                     self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
389
390             # Create the resulting solid
391             outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
392                                                       fPoint, lPoint, path)
393             if self.filling == HOLLOW:
394                 innerSolid = self._makeSolidPipeFromWires(innerWire1,
395                                                           innerWire2, fPoint,
396                                                           lPoint, path)
397                 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
398                 listPipes.append(resultSolid)
399             else:
400                 listPipes.append(outerSolid)
401
402         if len(listPipes) == 0:
403             return None
404         elif len(listPipes) == 1:
405             return listPipes[0]
406         else:
407             return self.geom.MakeCompound(listPipes)
408
409     ## Build the markers defining the orientation of the structural element part.
410     def _buildMarkers(self):
411         """
412         Build the markers defining the orientation of the structural element
413         part.
414         """
415         param = 0.5
416         paths = self._getSubShapes()
417         listMarkers = []
418         for path in paths:
419             (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
420                                                                      param)
421             marker = self._orientation.buildMarker(self.geom, center, vecX)
422             listMarkers.append(marker)
423         return listMarkers
424
425
426 ## This class defines a beam with a circular section. It can be full or
427 #  hollow, and its radius and thickness can vary from one end of the beam to
428 #  the other. The valid parameters for circular beams are:
429 #  - "R1" or "R": radius at the first end of the beam.
430 #  - "R2" or "R": radius at the other end of the beam.
431 #  - "EP1" or "EP" (optional): thickness at the first end of the beam.
432 #    If not specified or equal to 0, the beam is considered full.
433 #  - "EP2" or "EP" (optional): thickness at the other end of the beam.
434 #  If not specified or equal to 0, the beam is considered full.
435 #
436 #  See class StructuralElementPart for the description of the other parameters.
437 #  \ingroup parts
438 class CircularBeam(Beam):
439     """
440     This class defines a beam with a circular section. It can be full or
441     hollow, and its radius and thickness can vary from one end of the beam to
442     the other. The valid parameters for circular beams are:
443
444     * "R1" or "R": radius at the first end of the beam.
445     * "R2" or "R": radius at the other end of the beam.
446     * "EP1" or "EP" (optional): thickness at the first end of the beam.
447       If not specified or equal to 0, the beam is considered full.
448     * "EP2" or "EP" (optional): thickness at the other end of the beam.
449       If not specified or equal to 0, the beam is considered full.
450
451     See class :class:`StructuralElementPart` for the description of the
452     other parameters.
453
454     """
455
456     def __init__(self, studyId, groupName, groupGeomObj, parameters,
457                  name = Beam.DEFAULT_NAME, color = None):
458         if color is None:
459             if parameters.has_key("R1"): # variable section
460                 color = LIGHT_RED
461             else:                       # constant section
462                 color = RED
463
464         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
465                       name, color)
466
467         self.R1 = self._getParameter(["R1", "R"])
468         self.R2 = self._getParameter(["R2", "R"])
469         self.EP1 = self._getParameter(["EP1", "EP"])
470         self.EP2 = self._getParameter(["EP2", "EP"])
471
472         if self.EP1 is None or self.EP2 is None or \
473                                 self.EP1 == 0 or self.EP2 == 0:
474             self.filling = FULL
475         else:
476             self.filling = HOLLOW
477
478         logger.debug(repr(self))
479
480         # Check parameters
481         self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
482                         self._getParamUserName("R1"))
483         self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
484                         self._getParamUserName("R2"))
485         if self.filling == HOLLOW:
486             self._checkSize(self.EP1, MIN_THICKNESS,
487                             self._getParamUserName("EP1"))
488             self._checkSize(self.EP2, MIN_THICKNESS,
489                             self._getParamUserName("EP2"))
490             self._checkSize(self.R1 - self.EP1,
491                             MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
492                             "%s - %s" % (self._getParamUserName("R1"),
493                                          self._getParamUserName("EP1")))
494             self._checkSize(self.R2 - self.EP2,
495                             MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
496                             "%s - %s" % (self._getParamUserName("R2"),
497                                          self._getParamUserName("EP2")))
498
499     ## Create the circular sections used to build the pipe.
500     def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
501         """
502         Create the circular sections used to build the pipe.
503         """
504         outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
505         outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
506         if self.filling == HOLLOW:
507             innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
508                                                 self.R1 - self.EP1)
509             innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
510                                                 self.R2 - self.EP2)
511         else:
512             innerCircle1 = None
513             innerCircle2 = None
514
515         return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
516
517
518 ## This class defines a beam with a rectangular section. It can be full or
519 #  hollow, and its dimensions can vary from one end of the beam to the other.
520 #  The valid parameters for rectangular beams are:
521 #  - "HY1", "HY", "H1" or "H": width at the first end of the beam.
522 #  - "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
523 #  - "HY2", "HY", "H2" or "H": width at the other end of the beam.
524 #  - "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
525 #  - "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
526 #    direction at the first end of the beam. If not specified or equal to 0,
527 #    the beam is considered full.
528 #  - "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
529 #    direction at the first end of the beam. If not specified or equal to 0,
530 #    the beam is considered full.
531 #  - "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
532 #    direction at the other end of the beam. If not specified or equal to 0,
533 #    the beam is considered full.
534 #  - "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
535 #    direction at the other end of the beam. If not specified or equal to 0,
536 #    the beam is considered full.
537 #
538 #   See class StructuralElementPart for the description of the other parameters.
539 #  \ingroup parts
540 class RectangularBeam(Beam):
541     """
542     This class defines a beam with a rectangular section. It can be full or
543     hollow, and its dimensions can vary from one end of the beam to the other.
544     The valid parameters for rectangular beams are:
545
546     * "HY1", "HY", "H1" or "H": width at the first end of the beam.
547     * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
548     * "HY2", "HY", "H2" or "H": width at the other end of the beam.
549     * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
550     * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
551       direction at the first end of the beam. If not specified or equal to 0,
552       the beam is considered full.
553     * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
554       direction at the first end of the beam. If not specified or equal to 0,
555       the beam is considered full.
556     * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
557       direction at the other end of the beam. If not specified or equal to 0,
558       the beam is considered full.
559     * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
560       direction at the other end of the beam. If not specified or equal to 0,
561       the beam is considered full.
562
563     See class :class:`StructuralElementPart` for the description of the
564     other parameters.
565
566     """
567
568     def __init__(self, studyId, groupName, groupGeomObj, parameters,
569                  name = Beam.DEFAULT_NAME, color = None):
570         if color is None:
571             if parameters.has_key("HY1") or parameters.has_key("H1"):
572                 color = LIGHT_BLUE # variable section
573             else:                  # constant section
574                 color = BLUE
575
576         Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
577                       name, color)
578
579         self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
580         self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
581         self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
582         self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
583         self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
584         self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
585         self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
586         self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
587
588         if self.EPY1 is None or self.EPZ1 is None or \
589            self.EPY2 is None or self.EPZ2 is None or \
590            self.EPY1 == 0 or self.EPZ1 == 0 or \
591            self.EPY2 == 0 or self.EPZ2 == 0:
592             self.filling = FULL
593         else:
594             self.filling = HOLLOW
595
596         logger.debug(repr(self))
597
598         # Check parameters
599         self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
600                         self._getParamUserName("HY1"))
601         self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
602                         self._getParamUserName("HZ1"))
603         self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
604                         self._getParamUserName("HY2"))
605         self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
606                         self._getParamUserName("HZ2"))
607         if self.filling == HOLLOW:
608             self._checkSize(self.EPY1, MIN_THICKNESS,
609                             self._getParamUserName("EPY1"))
610             self._checkSize(self.EPZ1, MIN_THICKNESS,
611                             self._getParamUserName("EPZ1"))
612             self._checkSize(self.EPY2, MIN_THICKNESS,
613                             self._getParamUserName("EPY2"))
614             self._checkSize(self.EPZ2, MIN_THICKNESS,
615                             self._getParamUserName("EPZ2"))
616             self._checkSize(self.HY1 - 2 * self.EPY1,
617                             MIN_DIM_FOR_EXTRUDED_SHAPE,
618                             "%s - 2 * %s" % (self._getParamUserName("HY1"),
619                                              self._getParamUserName("EPY1")))
620             self._checkSize(self.HZ1 - 2 * self.EPZ1,
621                             MIN_DIM_FOR_EXTRUDED_SHAPE,
622                             "%s - 2 * %s" % (self._getParamUserName("HZ1"),
623                                              self._getParamUserName("EPZ1")))
624             self._checkSize(self.HY2 - 2 * self.EPY2,
625                             MIN_DIM_FOR_EXTRUDED_SHAPE,
626                             "%s - 2 * %s" % (self._getParamUserName("HY2"),
627                                              self._getParamUserName("EPY2")))
628             self._checkSize(self.HZ2 - 2 * self.EPZ2,
629                             MIN_DIM_FOR_EXTRUDED_SHAPE,
630                             "%s - 2 * %s" % (self._getParamUserName("HZ2"),
631                                              self._getParamUserName("EPZ2")))
632
633     ## Create a rectangle in the specified plane.
634     def _makeRectangle(self, HY, HZ, lcs):
635         """
636         Create a rectangle in the specified plane.
637         """
638         halfHY = HY / 2.0
639         halfHZ = HZ / 2.0
640         sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
641         sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
642         sketchStr += "TT %g %g:" % (halfHY, halfHZ)
643         sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
644         logger.debug('Drawing rectangle: "%s"' % sketchStr)
645         sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
646         return sketch
647
648     ## Create one side of the rectangular sections used to build the pipe.
649     def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
650         """
651         Create one side of the rectangular sections used to build the pipe.
652         """
653         (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
654         lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
655         outerRect = self._makeRectangle(HY, HZ, lcs)
656         if self.filling == HOLLOW:
657             innerRect = self._makeRectangle(HY - 2.0 * EPY,
658                                             HZ - 2.0 * EPZ,
659                                             lcs)
660         else:
661             innerRect = None
662         return (outerRect, innerRect)
663
664     ## Create the rectangular sections used to build the pipe.
665     def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
666         """
667         Create the rectangular sections used to build the pipe.
668         """
669         (outerRect1, innerRect1) = \
670             self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
671                                         self.EPY1, self.EPZ1)
672         (outerRect2, innerRect2) = \
673             self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
674                                         self.EPY2, self.EPZ2)
675         return (outerRect1, innerRect1, outerRect2, innerRect2)
676
677
678 ## This method finds the value of a parameter in the parameters
679 #  dictionary. The argument is a list because some parameters can have
680 #  several different names.
681 #  \ingroup parts
682 def getParameterInDict(nameList, parametersDict, default = None):
683     """
684     This method finds the value of a parameter in the parameters
685     dictionary. The argument is a list because some parameters can have
686     several different names.
687     """
688     for name in nameList:
689         if parametersDict.has_key(name):
690             return parametersDict[name]
691     return default
692
693 ## This class defines a beam with a generic section. It is represented as a
694 #  full rectangular beam with the following parameters:
695 #  - HY1 = sqrt(12 * IZ1 / A1)
696 #  - HZ1 = sqrt(12 * IY1 / A1)
697 #  - HY2 = sqrt(12 * IZ2 / A2)
698 #  - HZ2 = sqrt(12 * IY2 / A2)
699 #    
700 #  See StructuralElementPart for the description of the other parameters.
701 #  \ingroup parts
702 class GeneralBeam(RectangularBeam):
703     """
704     This class defines a beam with a generic section. It is represented as a
705     full rectangular beam with the following parameters:
706     
707     * HY1 = sqrt(12 * IZ1 / A1)
708     * HZ1 = sqrt(12 * IY1 / A1)
709     * HY2 = sqrt(12 * IZ2 / A2)
710     * HZ2 = sqrt(12 * IY2 / A2)
711     
712     See class :class:`StructuralElementPart` for the description of the other
713     parameters.
714     """
715
716     def __init__(self, studyId, groupName, groupGeomObj, parameters,
717                  name = Beam.DEFAULT_NAME, color = None):
718         self.IY1 = getParameterInDict(["IY1", "IY"], parameters)
719         self.IZ1 = getParameterInDict(["IZ1", "IZ"], parameters)
720         self.IY2 = getParameterInDict(["IY2", "IY"], parameters)
721         self.IZ2 = getParameterInDict(["IZ2", "IZ"], parameters)
722         self.A1 = getParameterInDict(["A1", "A"], parameters)
723         self.A2 = getParameterInDict(["A2", "A"], parameters)
724         parameters["HY1"] = math.sqrt(12 * self.IZ1 / self.A1)
725         parameters["HZ1"] = math.sqrt(12 * self.IY1 / self.A1)
726         parameters["HY2"] = math.sqrt(12 * self.IZ2 / self.A2)
727         parameters["HZ2"] = math.sqrt(12 * self.IY2 / self.A2)
728
729         if color is None:
730             if parameters.has_key("IY1"): # variable section
731                 color = LIGHT_GREEN
732             else:                         # constant section
733                 color = GREEN
734
735         RectangularBeam.__init__(self, studyId, groupName, groupGeomObj, parameters,
736                                  name, color)
737
738 ## This class is an "abstract" class for all 2D structural element parts. It
739 #  should not be instantiated directly. 
740 #  See class StructuralElementPart for the description of the parameters.
741 #  \ingroup parts
742 class StructuralElementPart2D(StructuralElementPart):
743     """
744     This class is an "abstract" class for all 2D structural element parts. It
745     should not be instantiated directly. See class
746     :class:`StructuralElementPart` for the description of the parameters.
747     """
748
749     DEFAULT_NAME = "StructuralElementPart2D"
750
751     def __init__(self, studyId, groupName, groupGeomObj, parameters,
752                  name = DEFAULT_NAME):
753         StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
754                                        parameters, name)
755         self._orientation = orientation.Orientation2D(
756                                         self._getParameter(["angleAlpha"]),
757                                         self._getParameter(["angleBeta"]),
758                                         self._getParameter(["Vecteur"]))
759         self.offset = self._getParameter(["Excentre"], 0.0)
760
761     ## Create a copy of a face at a given offset.
762     def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
763         """
764         Create a copy of a face at a given offset.
765         """
766         if abs(offset) < epsilon:
767             return self.geom.MakeCopy(face)
768         else:
769             offsetObj = self.geom.MakeOffset(face, offset)
770             # We have to explode the resulting object into faces because it is
771             # created as a polyhedron and not as a single face
772             faces = self.geom.SubShapeAll(offsetObj,
773                                           self.geom.ShapeType["FACE"])
774             return faces[0]
775
776     ## Build the markers for the structural element part with a given offset
777     #  from the base face.
778     def _buildMarkersWithOffset(self, offset):
779         """
780         Build the markers for the structural element part with a given offset
781         from the base face.
782         """
783         uParam = 0.5
784         vParam = 0.5
785         listMarkers = []
786         subShapes = self._getSubShapes()
787     
788         for subShape in subShapes:
789             faces = self.geom.SubShapeAll(subShape,
790                                           self.geom.ShapeType["FACE"])
791             for face in faces:
792                 offsetFace = self._makeFaceOffset(face, offset)
793                 # get tangent plane on surface by parameters
794                 center = self.geom.MakeVertexOnSurface(offsetFace,
795                                                        uParam, vParam)
796                 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
797                                                              uParam, vParam,
798                                                              1.0)
799                 normal = self.geom.GetNormal(tangPlane)
800                 marker = self._orientation.buildMarker(self.geom,
801                                                        center, normal)
802                 listMarkers.append(marker)
803
804         return listMarkers
805
806 ## This class defines a shell with a given thickness. It can be shifted from
807 #  the base face. The valid parameters for thick shells are:
808 #  - "Epais": thickness of the shell.
809 #  - "Excentre": offset of the shell from the base face.
810 #  - "angleAlpha": angle used to build the markers (see class
811 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
812 #  - "angleBeta": angle used to build the markers (see class
813 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
814 #  - "Vecteur": vector used instead of the angles to build the markers (see
815 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
816 #
817 #    See class StructuralElementPart for the description of the other parameters.
818 #  \ingroup parts
819 class ThickShell(StructuralElementPart2D):
820     """
821     This class defines a shell with a given thickness. It can be shifted from
822     the base face. The valid parameters for thick shells are:
823
824     * "Epais": thickness of the shell.
825     * "Excentre": offset of the shell from the base face.
826     * "angleAlpha": angle used to build the markers (see class
827       :class:`~salome.geom.structelem.orientation.Orientation2D`)
828     * "angleBeta": angle used to build the markers (see class
829       :class:`~salome.geom.structelem.orientation.Orientation2D`)
830     * "Vecteur": vector used instead of the angles to build the markers (see
831       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
832
833     See class :class:`StructuralElementPart` for the description of the
834     other parameters.
835     """
836
837     DEFAULT_NAME = "ThickShell"
838
839     def __init__(self, studyId, groupName, groupGeomObj, parameters,
840                  name = DEFAULT_NAME):
841         StructuralElementPart2D.__init__(self, studyId, groupName,
842                                          groupGeomObj, parameters, name)
843         self.thickness = self._getParameter(["Epais"])
844         logger.debug(repr(self))
845
846     ## Create the geometrical shapes corresponding to the thick shell.
847     def _buildPart(self):
848         """
849         Create the geometrical shapes corresponding to the thick shell.
850         """
851         subShapes = self._getSubShapes()
852         listSolids = []
853     
854         for subShape in subShapes:
855             faces = self.geom.SubShapeAll(subShape,
856                                           self.geom.ShapeType["FACE"])
857             for face in faces:
858                 shape = self._buildThickShellForFace(face)
859                 listSolids.append(shape)
860
861         if len(listSolids) == 0:
862             return None
863         elif len(listSolids) == 1:
864             return listSolids[0]
865         else:
866             return self.geom.MakeCompound(listSolids)
867
868     ## Create the geometrical shapes corresponding to the thick shell for a
869     #  given face.
870     def _buildThickShellForFace(self, face):
871         """
872         Create the geometrical shapes corresponding to the thick shell for a
873         given face.
874         """
875         epsilon = 1e-6
876         if self.thickness < 2 * epsilon:
877             return self._makeFaceOffset(face, self.offset, epsilon)
878
879         upperOffset = self.offset + self.thickness / 2.0
880         lowerOffset = self.offset - self.thickness / 2.0
881         ruledMode = True
882         modeSolid = False
883
884         upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
885         lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
886         listShapes = [upperFace, lowerFace]
887         upperWires = self.geom.SubShapeAll(upperFace,
888                                            self.geom.ShapeType["WIRE"])
889         lowerWires = self.geom.SubShapeAll(lowerFace,
890                                            self.geom.ShapeType["WIRE"])
891         if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
892             # if the face is a cylinder, we remove the extra side edge
893             upperWires = self._removeCylinderExtraEdge(upperWires)
894             lowerWires = self._removeCylinderExtraEdge(lowerWires)
895         for i in range(len(upperWires)):
896             resShape = self.geom.MakeThruSections([upperWires[i],
897                                                    lowerWires[i]],
898                                                   modeSolid, epsilon,
899                                                   ruledMode)
900             listShapes.append(resShape)
901         resultShell = self.geom.MakeShell(listShapes)
902         resultSolid = self.geom.MakeSolid([resultShell])
903         return resultSolid
904
905     ## Remove the side edge in a cylinder.
906     def _removeCylinderExtraEdge(self, wires):
907         """
908         Remove the side edge in a cylinder.
909         """
910         result = []
911         for wire in wires:
912             edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
913             for edge in edges:
914                 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
915                     result.append(edge)
916         return result
917
918     ## Build the markers defining the orientation of the thick shell.
919     def _buildMarkers(self):
920         """
921         Build the markers defining the orientation of the thick shell.
922         """
923         return self._buildMarkersWithOffset(self.offset +
924                                             self.thickness / 2.0)
925
926 ## This class defines a grid. A grid is represented by a 2D face patterned
927 #  with small lines in the main direction of the grid frame. The valid
928 #  parameters for grids are:
929 #  - "Excentre": offset of the grid from the base face.
930 #  - "angleAlpha": angle used to build the markers (see class
931 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
932 #  - "angleBeta": angle used to build the markers (see class
933 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
934 #  - "Vecteur": vector used instead of the angles to build the markers (see
935 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
936 #  - "origAxeX": X coordinate of the origin of the axis used to determine the
937 #    orientation of the frame in the case of a cylindrical grid.
938 #  - "origAxeY": Y coordinate of the origin of the axis used to determine the
939 #    orientation of the frame in the case of a cylindrical grid.
940 #  - "origAxeZ": Z coordinate of the origin of the axis used to determine the
941 #    orientation of the frame in the case of a cylindrical grid.
942 #  - "axeX": X coordinate of the axis used to determine the orientation of
943 #    the frame in the case of a cylindrical grid.
944 #  - "axeY": Y coordinate of the axis used to determine the orientation of
945 #    the frame in the case of a cylindrical grid.
946 #  - "axeZ": Z coordinate of the axis used to determine the orientation of
947 #    the frame in the case of a cylindrical grid.
948 #
949 #    See class StructuralElementPart for the description of the other parameters.
950 #  \ingroup parts
951 class Grid(StructuralElementPart2D):
952     """
953     This class defines a grid. A grid is represented by a 2D face patterned
954     with small lines in the main direction of the grid frame. The valid
955     parameters for grids are:
956
957     * "Excentre": offset of the grid from the base face.
958     * "angleAlpha": angle used to build the markers (see class
959       :class:`~salome.geom.structelem.orientation.Orientation2D`)
960     * "angleBeta": angle used to build the markers (see class
961       :class:`~salome.geom.structelem.orientation.Orientation2D`)
962     * "Vecteur": vector used instead of the angles to build the markers (see
963       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
964     * "origAxeX": X coordinate of the origin of the axis used to determine the
965       orientation of the frame in the case of a cylindrical grid.
966     * "origAxeY": Y coordinate of the origin of the axis used to determine the
967       orientation of the frame in the case of a cylindrical grid.
968     * "origAxeZ": Z coordinate of the origin of the axis used to determine the
969       orientation of the frame in the case of a cylindrical grid.
970     * "axeX": X coordinate of the axis used to determine the orientation of
971       the frame in the case of a cylindrical grid.
972     * "axeY": Y coordinate of the axis used to determine the orientation of
973       the frame in the case of a cylindrical grid.
974     * "axeZ": Z coordinate of the axis used to determine the orientation of
975       the frame in the case of a cylindrical grid.
976
977     See class :class:`StructuralElementPart` for the description of the
978     other parameters.
979     """
980
981     DEFAULT_NAME = "Grid"
982
983     def __init__(self, studyId, groupName, groupGeomObj, parameters,
984                  name = DEFAULT_NAME):
985         StructuralElementPart2D.__init__(self, studyId, groupName,
986                                          groupGeomObj, parameters, name)
987         self.xr = self._getParameter(["origAxeX"])
988         self.yr = self._getParameter(["origAxeY"])
989         self.zr = self._getParameter(["origAxeZ"])
990         self.vx = self._getParameter(["axeX"])
991         self.vy = self._getParameter(["axeY"])
992         self.vz = self._getParameter(["axeZ"])
993         logger.debug(repr(self))
994
995     ## Create the geometrical shapes representing the grid.
996     def _buildPart(self):
997         """
998         Create the geometrical shapes representing the grid.
999         """
1000         subShapes = self._getSubShapes()
1001         listGridShapes = []
1002     
1003         for subShape in subShapes:
1004             faces = self.geom.SubShapeAll(subShape,
1005                                           self.geom.ShapeType["FACE"])
1006             for face in faces:
1007                 if self.geom.KindOfShape(face)[0] == \
1008                                         self.geom.kind.CYLINDER2D and \
1009                         self.xr is not None and self.yr is not None and \
1010                         self.zr is not None and self.vx is not None and \
1011                         self.vy is not None and self.vz is not None:
1012                     shape = self._buildGridForCylinderFace(face)
1013                 else:
1014                     shape = self._buildGridForNormalFace(face)
1015                 listGridShapes.append(shape)
1016
1017         if len(listGridShapes) == 0:
1018             return None
1019         elif len(listGridShapes) == 1:
1020             return listGridShapes[0]
1021         else:
1022             return self.geom.MakeCompound(listGridShapes)
1023
1024     ## Create the geometrical shapes representing the grid for a given
1025     #  non-cylindrical face.
1026     def _buildGridForNormalFace(self, face):
1027         """
1028         Create the geometrical shapes representing the grid for a given
1029         non-cylindrical face.
1030         """
1031         baseFace = self._makeFaceOffset(face, self.offset)
1032         gridList = [baseFace]
1033         
1034         # Compute display length for grid elements
1035         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1036         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1037         length = self.geom.MinDistance(p1, p2) / 2.0
1038
1039         for u in range(1, 10):
1040             uParam = u * 0.1
1041             for v in range(1, 10):
1042                 vParam = v * 0.1
1043                 # get tangent plane on surface by parameters
1044                 center = self.geom.MakeVertexOnSurface(baseFace,
1045                                                        uParam, vParam)
1046                 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
1047                                                              vParam, 1.0)
1048                 
1049                 # use the marker to get the orientation of the frame
1050                 normal = self.geom.GetNormal(tangPlane)
1051                 marker = self._orientation.buildMarker(self.geom, center,
1052                                                        normal, False)
1053                 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
1054                 xPoint = self.geom.MakeTranslation(center, Xx * length,
1055                                                    Xy * length, Xz * length)
1056                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1057                 gridList.append(gridLine)
1058         grid = self.geom.MakeCompound(gridList)
1059         return grid
1060
1061     ## Create the geometrical shapes representing the grid for a given
1062     #  cylindrical face.
1063     def _buildGridForCylinderFace(self, face):
1064         """
1065         Create the geometrical shapes representing the grid for a given
1066         cylindrical face.
1067         """
1068         baseFace = self._makeFaceOffset(face, self.offset)
1069         gridList = [baseFace]
1070         
1071         # Compute display length for grid elements
1072         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1073         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1074         length = self.geom.MinDistance(p1, p2) / 2.0
1075         
1076         # Create reference vector V
1077         origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
1078         vPoint = self.geom.MakeTranslation(origPoint,
1079                                            self.vx, self.vy, self.vz)
1080         refVec = self.geom.MakeVector(origPoint, vPoint)
1081
1082         for u in range(10):
1083             uParam = u * 0.1
1084             for v in range(1, 10):
1085                 vParam = v * 0.1
1086                 
1087                 # Compute the local orientation of the frame
1088                 center = self.geom.MakeVertexOnSurface(baseFace,
1089                                                        uParam, vParam)
1090                 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
1091                                                          vPoint, 1.0)
1092                 locOrient = self.geom.GetNormal(locPlaneYZ)
1093                 xPoint = self.geom.MakeTranslationVectorDistance(center,
1094                                                                  locOrient,
1095                                                                  length)
1096                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1097                 gridList.append(gridLine)
1098
1099         grid = self.geom.MakeCompound(gridList)
1100         return grid
1101
1102     ## Create the markers defining the orientation of the grid.
1103     def _buildMarkers(self):
1104         """
1105         Create the markers defining the orientation of the grid.
1106         """
1107         return self._buildMarkersWithOffset(self.offset)
1108
1109 ## Alias for class GeneralBeam.
1110 #  \ingroup parts
1111 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
1112                        name = "POUTRE"):
1113     """
1114     Alias for class :class:`GeneralBeam`.
1115     """
1116     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
1117
1118 ## Alias for class CircularBeam.
1119 #  \ingroup parts
1120 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
1121                      name = "POUTRE"):
1122     """
1123     Alias for class :class:`CircularBeam`.
1124     """
1125     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
1126
1127 ## Alias for class RectangularBeam. 
1128 #  \ingroup parts
1129 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
1130                         name = "POUTRE"):
1131     """
1132     Alias for class :class:`RectangularBeam`.
1133     """
1134     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
1135
1136 ## Alias for class GeneralBeam.  
1137 #  \ingroup parts
1138 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
1139                       name = "BARRE"):
1140     """
1141     Alias for class :class:`GeneralBeam`.
1142     """
1143     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
1144                        color = ORANGE)
1145
1146 ## Alias for class RectangularBeam.      
1147 #  \ingroup parts
1148 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
1149                        name = "BARRE"):
1150     """
1151     Alias for class :class:`RectangularBeam`.
1152     """
1153     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
1154                            color = ORANGE)
1155
1156 ## Alias for class CircularBeam.
1157 #  \ingroup parts
1158 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
1159                     name = "BARRE"):
1160     """
1161     Alias for class :class:`CircularBeam`.
1162     """
1163     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1164                         color = ORANGE)
1165
1166 ## Alias for class CircularBeam.
1167 #  \ingroup parts
1168 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
1169     """
1170     Alias for class :class:`CircularBeam`.
1171     """
1172     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1173                         color = PURPLE)
1174
1175 ## Alias for class ThickShell.
1176 #  \ingroup parts
1177 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
1178     """
1179     Alias for class :class:`ThickShell`.
1180     """
1181     return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
1182
1183 ## Alias for class Grid.
1184 #  \ingroup parts
1185 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
1186     """
1187     Alias for class :class:`Grid`.
1188     """
1189     return Grid(studyId, groupName, groupGeomObj, parameters, name)