Salome HOME
Structural elements: wrong orientation of faces (EDF #8518)
[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 the center of the face and the normal at the center
794                 center = self.geom.MakeVertexOnSurface(offsetFace,
795                                                        uParam, vParam)
796                 normal = self.geom.GetNormal(offsetFace, center)
797                 marker = self._orientation.buildMarker(self.geom,
798                                                        center, normal)
799                 listMarkers.append(marker)
800
801         return listMarkers
802
803 ## This class defines a shell with a given thickness. It can be shifted from
804 #  the base face. The valid parameters for thick shells are:
805 #  - "Epais": thickness of the shell.
806 #  - "Excentre": offset of the shell from the base face.
807 #  - "angleAlpha": angle used to build the markers (see class
808 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
809 #  - "angleBeta": angle used to build the markers (see class
810 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
811 #  - "Vecteur": vector used instead of the angles to build the markers (see
812 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
813 #
814 #    See class StructuralElementPart for the description of the other parameters.
815 #  \ingroup parts
816 class ThickShell(StructuralElementPart2D):
817     """
818     This class defines a shell with a given thickness. It can be shifted from
819     the base face. The valid parameters for thick shells are:
820
821     * "Epais": thickness of the shell.
822     * "Excentre": offset of the shell from the base face.
823     * "angleAlpha": angle used to build the markers (see class
824       :class:`~salome.geom.structelem.orientation.Orientation2D`)
825     * "angleBeta": angle used to build the markers (see class
826       :class:`~salome.geom.structelem.orientation.Orientation2D`)
827     * "Vecteur": vector used instead of the angles to build the markers (see
828       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
829
830     See class :class:`StructuralElementPart` for the description of the
831     other parameters.
832     """
833
834     DEFAULT_NAME = "ThickShell"
835
836     def __init__(self, studyId, groupName, groupGeomObj, parameters,
837                  name = DEFAULT_NAME):
838         StructuralElementPart2D.__init__(self, studyId, groupName,
839                                          groupGeomObj, parameters, name)
840         self.thickness = self._getParameter(["Epais"])
841         logger.debug(repr(self))
842
843     ## Create the geometrical shapes corresponding to the thick shell.
844     def _buildPart(self):
845         """
846         Create the geometrical shapes corresponding to the thick shell.
847         """
848         subShapes = self._getSubShapes()
849         listSolids = []
850     
851         for subShape in subShapes:
852             faces = self.geom.SubShapeAll(subShape,
853                                           self.geom.ShapeType["FACE"])
854             for face in faces:
855                 shape = self._buildThickShellForFace(face)
856                 listSolids.append(shape)
857
858         if len(listSolids) == 0:
859             return None
860         elif len(listSolids) == 1:
861             return listSolids[0]
862         else:
863             return self.geom.MakeCompound(listSolids)
864
865     ## Create the geometrical shapes corresponding to the thick shell for a
866     #  given face.
867     def _buildThickShellForFace(self, face):
868         """
869         Create the geometrical shapes corresponding to the thick shell for a
870         given face.
871         """
872         epsilon = 1e-6
873         if self.thickness < 2 * epsilon:
874             return self._makeFaceOffset(face, self.offset, epsilon)
875
876         upperOffset = self.offset + self.thickness / 2.0
877         lowerOffset = self.offset - self.thickness / 2.0
878         ruledMode = True
879         modeSolid = False
880
881         upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
882         lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
883         listShapes = [upperFace, lowerFace]
884         upperWires = self.geom.SubShapeAll(upperFace,
885                                            self.geom.ShapeType["WIRE"])
886         lowerWires = self.geom.SubShapeAll(lowerFace,
887                                            self.geom.ShapeType["WIRE"])
888         if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
889             # if the face is a cylinder, we remove the extra side edge
890             upperWires = self._removeCylinderExtraEdge(upperWires)
891             lowerWires = self._removeCylinderExtraEdge(lowerWires)
892         for i in range(len(upperWires)):
893             resShape = self.geom.MakeThruSections([upperWires[i],
894                                                    lowerWires[i]],
895                                                   modeSolid, epsilon,
896                                                   ruledMode)
897             listShapes.append(resShape)
898         resultShell = self.geom.MakeShell(listShapes)
899         resultSolid = self.geom.MakeSolid([resultShell])
900         return resultSolid
901
902     ## Remove the side edge in a cylinder.
903     def _removeCylinderExtraEdge(self, wires):
904         """
905         Remove the side edge in a cylinder.
906         """
907         result = []
908         for wire in wires:
909             edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
910             for edge in edges:
911                 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
912                     result.append(edge)
913         return result
914
915     ## Build the markers defining the orientation of the thick shell.
916     def _buildMarkers(self):
917         """
918         Build the markers defining the orientation of the thick shell.
919         """
920         return self._buildMarkersWithOffset(self.offset +
921                                             self.thickness / 2.0)
922
923 ## This class defines a grid. A grid is represented by a 2D face patterned
924 #  with small lines in the main direction of the grid frame. The valid
925 #  parameters for grids are:
926 #  - "Excentre": offset of the grid from the base face.
927 #  - "angleAlpha": angle used to build the markers (see class
928 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
929 #  - "angleBeta": angle used to build the markers (see class
930 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
931 #  - "Vecteur": vector used instead of the angles to build the markers (see
932 #    \ref orientation.Orientation2D "salome.geom.structelem.orientation.Orientation2D")
933 #  - "origAxeX": X coordinate of the origin of the axis used to determine the
934 #    orientation of the frame in the case of a cylindrical grid.
935 #  - "origAxeY": Y coordinate of the origin of the axis used to determine the
936 #    orientation of the frame in the case of a cylindrical grid.
937 #  - "origAxeZ": Z coordinate of the origin of the axis used to determine the
938 #    orientation of the frame in the case of a cylindrical grid.
939 #  - "axeX": X coordinate of the axis used to determine the orientation of
940 #    the frame in the case of a cylindrical grid.
941 #  - "axeY": Y coordinate of the axis used to determine the orientation of
942 #    the frame in the case of a cylindrical grid.
943 #  - "axeZ": Z coordinate of the axis used to determine the orientation of
944 #    the frame in the case of a cylindrical grid.
945 #
946 #    See class StructuralElementPart for the description of the other parameters.
947 #  \ingroup parts
948 class Grid(StructuralElementPart2D):
949     """
950     This class defines a grid. A grid is represented by a 2D face patterned
951     with small lines in the main direction of the grid frame. The valid
952     parameters for grids are:
953
954     * "Excentre": offset of the grid from the base face.
955     * "angleAlpha": angle used to build the markers (see class
956       :class:`~salome.geom.structelem.orientation.Orientation2D`)
957     * "angleBeta": angle used to build the markers (see class
958       :class:`~salome.geom.structelem.orientation.Orientation2D`)
959     * "Vecteur": vector used instead of the angles to build the markers (see
960       class :class:`~salome.geom.structelem.orientation.Orientation2D`)
961     * "origAxeX": X coordinate of the origin of the axis used to determine the
962       orientation of the frame in the case of a cylindrical grid.
963     * "origAxeY": Y coordinate of the origin of the axis used to determine the
964       orientation of the frame in the case of a cylindrical grid.
965     * "origAxeZ": Z coordinate of the origin of the axis used to determine the
966       orientation of the frame in the case of a cylindrical grid.
967     * "axeX": X coordinate of the axis used to determine the orientation of
968       the frame in the case of a cylindrical grid.
969     * "axeY": Y coordinate of the axis used to determine the orientation of
970       the frame in the case of a cylindrical grid.
971     * "axeZ": Z coordinate of the axis used to determine the orientation of
972       the frame in the case of a cylindrical grid.
973
974     See class :class:`StructuralElementPart` for the description of the
975     other parameters.
976     """
977
978     DEFAULT_NAME = "Grid"
979
980     def __init__(self, studyId, groupName, groupGeomObj, parameters,
981                  name = DEFAULT_NAME):
982         StructuralElementPart2D.__init__(self, studyId, groupName,
983                                          groupGeomObj, parameters, name)
984         self.xr = self._getParameter(["origAxeX"])
985         self.yr = self._getParameter(["origAxeY"])
986         self.zr = self._getParameter(["origAxeZ"])
987         self.vx = self._getParameter(["axeX"])
988         self.vy = self._getParameter(["axeY"])
989         self.vz = self._getParameter(["axeZ"])
990         logger.debug(repr(self))
991
992     ## Create the geometrical shapes representing the grid.
993     def _buildPart(self):
994         """
995         Create the geometrical shapes representing the grid.
996         """
997         subShapes = self._getSubShapes()
998         listGridShapes = []
999     
1000         for subShape in subShapes:
1001             faces = self.geom.SubShapeAll(subShape,
1002                                           self.geom.ShapeType["FACE"])
1003             for face in faces:
1004                 if self.geom.KindOfShape(face)[0] == \
1005                                         self.geom.kind.CYLINDER2D and \
1006                         self.xr is not None and self.yr is not None and \
1007                         self.zr is not None and self.vx is not None and \
1008                         self.vy is not None and self.vz is not None:
1009                     shape = self._buildGridForCylinderFace(face)
1010                 else:
1011                     shape = self._buildGridForNormalFace(face)
1012                 listGridShapes.append(shape)
1013
1014         if len(listGridShapes) == 0:
1015             return None
1016         elif len(listGridShapes) == 1:
1017             return listGridShapes[0]
1018         else:
1019             return self.geom.MakeCompound(listGridShapes)
1020
1021     ## Create the geometrical shapes representing the grid for a given
1022     #  non-cylindrical face.
1023     def _buildGridForNormalFace(self, face):
1024         """
1025         Create the geometrical shapes representing the grid for a given
1026         non-cylindrical face.
1027         """
1028         baseFace = self._makeFaceOffset(face, self.offset)
1029         gridList = [baseFace]
1030         
1031         # Compute display length for grid elements
1032         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1033         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1034         length = self.geom.MinDistance(p1, p2) / 2.0
1035
1036         for u in range(1, 10):
1037             uParam = u * 0.1
1038             for v in range(1, 10):
1039                 vParam = v * 0.1
1040                 # get tangent plane on surface by parameters
1041                 center = self.geom.MakeVertexOnSurface(baseFace,
1042                                                        uParam, vParam)
1043                 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
1044                                                              vParam, 1.0)
1045                 
1046                 # use the marker to get the orientation of the frame
1047                 normal = self.geom.GetNormal(tangPlane)
1048                 marker = self._orientation.buildMarker(self.geom, center,
1049                                                        normal, False)
1050                 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
1051                 xPoint = self.geom.MakeTranslation(center, Xx * length,
1052                                                    Xy * length, Xz * length)
1053                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1054                 gridList.append(gridLine)
1055         grid = self.geom.MakeCompound(gridList)
1056         return grid
1057
1058     ## Create the geometrical shapes representing the grid for a given
1059     #  cylindrical face.
1060     def _buildGridForCylinderFace(self, face):
1061         """
1062         Create the geometrical shapes representing the grid for a given
1063         cylindrical face.
1064         """
1065         baseFace = self._makeFaceOffset(face, self.offset)
1066         gridList = [baseFace]
1067         
1068         # Compute display length for grid elements
1069         p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
1070         p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
1071         length = self.geom.MinDistance(p1, p2) / 2.0
1072         
1073         # Create reference vector V
1074         origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
1075         vPoint = self.geom.MakeTranslation(origPoint,
1076                                            self.vx, self.vy, self.vz)
1077         refVec = self.geom.MakeVector(origPoint, vPoint)
1078
1079         for u in range(10):
1080             uParam = u * 0.1
1081             for v in range(1, 10):
1082                 vParam = v * 0.1
1083                 
1084                 # Compute the local orientation of the frame
1085                 center = self.geom.MakeVertexOnSurface(baseFace,
1086                                                        uParam, vParam)
1087                 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
1088                                                          vPoint, 1.0)
1089                 locOrient = self.geom.GetNormal(locPlaneYZ)
1090                 xPoint = self.geom.MakeTranslationVectorDistance(center,
1091                                                                  locOrient,
1092                                                                  length)
1093                 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
1094                 gridList.append(gridLine)
1095
1096         grid = self.geom.MakeCompound(gridList)
1097         return grid
1098
1099     ## Create the markers defining the orientation of the grid.
1100     def _buildMarkers(self):
1101         """
1102         Create the markers defining the orientation of the grid.
1103         """
1104         return self._buildMarkersWithOffset(self.offset)
1105
1106 ## Alias for class GeneralBeam.
1107 #  \ingroup parts
1108 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
1109                        name = "POUTRE"):
1110     """
1111     Alias for class :class:`GeneralBeam`.
1112     """
1113     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
1114
1115 ## Alias for class CircularBeam.
1116 #  \ingroup parts
1117 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
1118                      name = "POUTRE"):
1119     """
1120     Alias for class :class:`CircularBeam`.
1121     """
1122     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
1123
1124 ## Alias for class RectangularBeam. 
1125 #  \ingroup parts
1126 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
1127                         name = "POUTRE"):
1128     """
1129     Alias for class :class:`RectangularBeam`.
1130     """
1131     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
1132
1133 ## Alias for class GeneralBeam.  
1134 #  \ingroup parts
1135 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
1136                       name = "BARRE"):
1137     """
1138     Alias for class :class:`GeneralBeam`.
1139     """
1140     return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
1141                        color = ORANGE)
1142
1143 ## Alias for class RectangularBeam.      
1144 #  \ingroup parts
1145 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
1146                        name = "BARRE"):
1147     """
1148     Alias for class :class:`RectangularBeam`.
1149     """
1150     return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
1151                            color = ORANGE)
1152
1153 ## Alias for class CircularBeam.
1154 #  \ingroup parts
1155 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
1156                     name = "BARRE"):
1157     """
1158     Alias for class :class:`CircularBeam`.
1159     """
1160     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1161                         color = ORANGE)
1162
1163 ## Alias for class CircularBeam.
1164 #  \ingroup parts
1165 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
1166     """
1167     Alias for class :class:`CircularBeam`.
1168     """
1169     return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1170                         color = PURPLE)
1171
1172 ## Alias for class ThickShell.
1173 #  \ingroup parts
1174 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
1175     """
1176     Alias for class :class:`ThickShell`.
1177     """
1178     return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
1179
1180 ## Alias for class Grid.
1181 #  \ingroup parts
1182 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
1183     """
1184     Alias for class :class:`Grid`.
1185     """
1186     return Grid(studyId, groupName, groupGeomObj, parameters, name)