1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2009 EDF R&D
5 # This file is part of PAL_SRC.
7 # PAL_SRC is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # PAL_SRC is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with PAL_SRC; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 This module defines the different structural element parts. It is used to
23 build the geometric shapes of the structural elements. It should not be used
24 directly in the general case. Structural elements should be created by the
25 class :class:`~salome.geom.structelem.StructuralElementManager`.
30 from salome.kernel.logger import Logger
31 from salome.kernel import termcolor
32 logger = Logger("salome.geom.structelem.parts", color = termcolor.RED)
33 from salome.geom.geomtools import getGeompy
37 # Filling for the beams
41 # Minimum dimension for the shapes to extrude
42 MIN_DIM_FOR_EXTRUDED_SHAPE = 2e-4
43 MIN_LENGTH_FOR_EXTRUSION = 1e-4
47 class InvalidParameterError(Exception):
49 This exception is raised when an invalid parameter is used to build a
50 structural element part.
53 def __init__(self, groupName, expression, minValue, value):
54 self.groupName = groupName
55 self.expression = expression
56 self.minValue = minValue
60 return "%s < %g (%s = %g in %s)" % (self.expression, self.minValue,
61 self.expression, self.value,
67 This class enables the use of subshapes in sets or as dictionary keys.
68 It implements __eq__ and __hash__ methods so that subshapes with the same
69 CORBA object `mainShape` and the same `id` are considered equal.
72 def __init__(self, mainShape, id):
73 self._mainShape = mainShape
76 def getObj(self, geom):
78 Return the subshape (GEOM object). `geom` is a pseudo-geompy object
79 used to find the geometrical object.
81 return geom.GetSubShape(self._mainShape, [self._id])
83 def __eq__(self, other):
84 return self._mainShape._is_equivalent(other._mainShape) and \
88 return self._mainShape._hash(2147483647) ^ self._id
91 class StructuralElementPart:
93 This class is the base class for all structural element parts. It should
94 not be instantiated directly (consider it as an "abstract" class).
96 :type studyId: integer
97 :param studyId: the ID of the study in which the part is created.
99 :type groupName: string
100 :param groupName: the name of the underlying geometrical primitive in the
103 :type groupGeomObj: GEOM object
104 :param groupGeomObj: the underlying geometrical primitive.
106 :type parameters: dictionary
107 :param parameters: parameters defining the structural element (see
108 subclasses for details).
111 :param name: name to use for the created object in the study.
115 DEFAULT_NAME = "StructElemPart"
117 def __init__(self, studyId, groupName, groupGeomObj, parameters,
118 name = DEFAULT_NAME):
119 self._parameters = parameters
120 self.groupName = groupName
121 self._groupGeomObj = groupGeomObj
122 self._orientation = None
123 self._paramUserName = {}
125 self.geom = getGeompy(studyId)
126 self.baseShapesSet = set()
127 mainShape = self.geom.GetMainShape(groupGeomObj)
128 listIDs = self.geom.GetObjectIDs(groupGeomObj)
129 if mainShape is not None and listIDs is not None:
131 self.baseShapesSet.add(SubShapeID(mainShape, id))
133 def _getParameter(self, nameList, default = None):
135 This method finds the value of a parameter in the parameters
136 dictionary. The argument is a list because some parameters can have
137 several different names.
139 if len(nameList) > 0:
140 paramName = nameList[0]
141 for name in nameList:
142 if self._parameters.has_key(name):
143 self._paramUserName[paramName] = name
144 return self._parameters[name]
147 def _getParamUserName(self, paramName):
149 This method finds the user name for a parameter.
151 if self._paramUserName.has_key(paramName):
152 return self._paramUserName[paramName]
157 reprdict = self.__dict__.copy()
158 del reprdict["_parameters"]
159 del reprdict["groupName"]
160 del reprdict["_groupGeomObj"]
161 del reprdict["_paramUserName"]
164 del reprdict["baseShapesSet"]
165 return '%s("%s", %s)' % (self.__class__.__name__, self.groupName,
168 def addOrientation(self, orientParams):
170 Add orientation information to the structural element part. See class
171 :class:`~salome.geom.structelem.orientation.Orientation1D` for the description
174 self._orientation.addParams(orientParams)
176 def _checkSize(self, value, mindim, expression):
178 This method checks that some parameters or some expressions involving
179 those parameters are greater than a minimum value.
182 raise InvalidParameterError(self.groupName, expression,
187 Build the geometric shapes and the markers corresponding to the
188 structural element part in the study `studyId`.
190 shape = self._buildPart()
191 markers = self._buildMarkers()
192 shape.SetColor(self._groupGeomObj.GetColor())
193 for marker in markers:
194 marker.SetColor(self._groupGeomObj.GetColor())
195 return (shape, markers)
197 def _buildPart(self):
199 This abstract method must be implemented in subclasses and should
200 create the geometrical shape(s) of the structural element part.
202 raise NotImplementedError("Method _buildPart not implemented in class"
203 " %s (it must be implemented in "
204 "StructuralElementPart subclasses)." %
205 self.__class__.__name__)
207 def _buildMarkers(self):
209 This abstract method must be implemented in subclasses and should
210 create the markers defining the orientation of the structural element
213 raise NotImplementedError("Method _buildMarker not implemented in "
214 "class %s (it must be implemented in "
215 "StructuralElementPart subclasses)." %
216 self.__class__.__name__)
218 def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
220 Find and return the base subshapes in the structural element part.
223 for subShapeID in self.baseShapesSet:
224 subShape = subShapeID.getObj(self.geom)
225 length = self.geom.BasicProperties(subShape)[0]
227 logger.warning("Length too short (%s - ID %s, length = %g), "
228 "subshape will not be used in structural "
229 "element" % (self.groupName, subShapeID._id,
232 subShapes.append(subShape)
236 class Beam(StructuralElementPart):
238 This class is an "abstract" class for all 1D structural element parts. It
239 should not be instantiated directly. See class
240 :class:`StructuralElementPart` for the description of the parameters.
243 DEFAULT_NAME = "Beam"
245 def __init__(self, studyId, groupName, groupGeomObj, parameters,
246 name = DEFAULT_NAME):
247 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
249 self._orientation = orientation.Orientation1D()
251 def _isReversed(self, path):
253 This method checks if a 1D object is "reversed", i.e. if its
254 orientation is different than the orientation of the underlying OCC
257 p1 = self.geom.MakeVertexOnCurve(path, 0.0)
258 p2 = self.geom.GetFirstVertex(path)
259 dist = self.geom.MinDistance(p1, p2)
262 def _getVertexAndTangentOnOrientedWire(self, path, param):
264 Get a vertex and the corresponding tangent on a wire by parameter.
265 This method takes into account the "real" orientation of the wire
266 (i.e. the orientation of the underlying OCC object).
268 if self._isReversed(path):
269 vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
270 invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
271 tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
274 tangent = self.geom.MakeVector(vertex, tanpoint)
276 vertex = self.geom.MakeVertexOnCurve(path, param)
277 tangent = self.geom.MakeTangentOnCurve(path, param)
278 return (vertex, tangent)
280 def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
282 Create a solid by the extrusion of section `wire1` to section `wire2`
285 face1 = self.geom.MakeFace(wire1, True)
286 face2 = self.geom.MakeFace(wire2, True)
287 shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
290 closedShell = self.geom.MakeShell([face1, face2, shell])
291 solid = self.geom.MakeSolid([closedShell])
294 def _buildPart(self):
296 Build the structural element part.
298 # Get all the subshapes in the group (normally only edges and wires)
299 paths = self._getSubShapes()
302 withCorrection = False
305 # Build the sections (rectangular or circular) at each end of the
307 (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
309 (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
311 (outerWire1, innerWire1, outerWire2, innerWire2) = \
312 self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
314 # Create the resulting solid
315 outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
316 fPoint, lPoint, path)
317 if self.filling == HOLLOW:
318 innerSolid = self._makeSolidPipeFromWires(innerWire1,
321 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
322 listPipes.append(resultSolid)
324 listPipes.append(outerSolid)
326 if len(listPipes) == 0:
328 elif len(listPipes) == 1:
331 return self.geom.MakeCompound(listPipes)
333 def _buildMarkers(self):
335 Build the markers defining the orientation of the structural element
339 paths = self._getSubShapes()
342 (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
344 marker = self._orientation.buildMarker(self.geom, center, vecX)
345 listMarkers.append(marker)
349 class GeneralBeam(Beam):
351 This class defines a beam with a generic section. It is represented only
352 as the underlying wire. See class :class:`StructuralElementPart` for the
353 description of the parameters.
356 def __init__(self, studyId, groupName, groupGeomObj, parameters,
357 name = Beam.DEFAULT_NAME):
358 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
360 logger.debug(repr(self))
362 def _buildPart(self):
364 Create a copy of the underlying wire.
366 edges = self._getSubShapes(1e-7)
369 wire = self.geom.MakeWire(edges)
373 class CircularBeam(Beam):
375 This class defines a beam with a circular section. It can be full or
376 hollow, and its radius and thickness can vary from one end of the beam to
377 the other. The valid parameters for circular beams are:
379 * "R1" or "R": radius at the first end of the beam.
380 * "R2" or "R": radius at the other end of the beam.
381 * "EP1" or "EP" (optional): thickness at the first end of the beam.
382 If not specified or equal to 0, the beam is considered full.
383 * "EP2" or "EP" (optional): thickness at the other end of the beam.
384 If not specified or equal to 0, the beam is considered full.
386 See class :class:`StructuralElementPart` for the description of the
391 def __init__(self, studyId, groupName, groupGeomObj, parameters,
392 name = Beam.DEFAULT_NAME):
393 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
396 self.R1 = self._getParameter(["R1", "R"])
397 self.R2 = self._getParameter(["R2", "R"])
398 self.EP1 = self._getParameter(["EP1", "EP"])
399 self.EP2 = self._getParameter(["EP2", "EP"])
401 if self.EP1 is None or self.EP2 is None or \
402 self.EP1 == 0 or self.EP2 == 0:
405 self.filling = HOLLOW
407 logger.debug(repr(self))
410 self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
411 self._getParamUserName("R1"))
412 self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
413 self._getParamUserName("R2"))
414 if self.filling == HOLLOW:
415 self._checkSize(self.EP1, MIN_THICKNESS,
416 self._getParamUserName("EP1"))
417 self._checkSize(self.EP2, MIN_THICKNESS,
418 self._getParamUserName("EP2"))
419 self._checkSize(self.R1 - self.EP1,
420 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
421 "%s - %s" % (self._getParamUserName("R1"),
422 self._getParamUserName("EP1")))
423 self._checkSize(self.R2 - self.EP2,
424 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
425 "%s - %s" % (self._getParamUserName("R2"),
426 self._getParamUserName("EP2")))
428 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
430 Create the circular sections used to build the pipe.
432 outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
433 outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
434 if self.filling == HOLLOW:
435 innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
437 innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
443 return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
446 class RectangularBeam(Beam):
448 This class defines a beam with a rectangular section. It can be full or
449 hollow, and its dimensions can vary from one end of the beam to the other.
450 The valid parameters for rectangular beams are:
452 * "HY1", "HY", "H1" or "H": width at the first end of the beam.
453 * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
454 * "HY2", "HY", "H2" or "H": width at the other end of the beam.
455 * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
456 * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
457 direction at the first end of the beam. If not specified or equal to 0,
458 the beam is considered full.
459 * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
460 direction at the first end of the beam. If not specified or equal to 0,
461 the beam is considered full.
462 * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
463 direction at the other end of the beam. If not specified or equal to 0,
464 the beam is considered full.
465 * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
466 direction at the other end of the beam. If not specified or equal to 0,
467 the beam is considered full.
469 See class :class:`StructuralElementPart` for the description of the
474 def __init__(self, studyId, groupName, groupGeomObj, parameters,
475 name = Beam.DEFAULT_NAME):
476 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
479 self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
480 self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
481 self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
482 self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
483 self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
484 self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
485 self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
486 self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
488 if self.EPY1 is None or self.EPZ1 is None or \
489 self.EPY2 is None or self.EPZ2 is None or \
490 self.EPY1 == 0 or self.EPZ1 == 0 or \
491 self.EPY2 == 0 or self.EPZ2 == 0:
494 self.filling = HOLLOW
496 logger.debug(repr(self))
499 self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
500 self._getParamUserName("HY1"))
501 self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
502 self._getParamUserName("HZ1"))
503 self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
504 self._getParamUserName("HY2"))
505 self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
506 self._getParamUserName("HZ2"))
507 if self.filling == HOLLOW:
508 self._checkSize(self.EPY1, MIN_THICKNESS,
509 self._getParamUserName("EPY1"))
510 self._checkSize(self.EPZ1, MIN_THICKNESS,
511 self._getParamUserName("EPZ1"))
512 self._checkSize(self.EPY2, MIN_THICKNESS,
513 self._getParamUserName("EPY2"))
514 self._checkSize(self.EPZ2, MIN_THICKNESS,
515 self._getParamUserName("EPZ2"))
516 self._checkSize(self.HY1 - 2 * self.EPY1,
517 MIN_DIM_FOR_EXTRUDED_SHAPE,
518 "%s - 2 * %s" % (self._getParamUserName("HY1"),
519 self._getParamUserName("EPY1")))
520 self._checkSize(self.HZ1 - 2 * self.EPZ1,
521 MIN_DIM_FOR_EXTRUDED_SHAPE,
522 "%s - 2 * %s" % (self._getParamUserName("HZ1"),
523 self._getParamUserName("EPZ1")))
524 self._checkSize(self.HY2 - 2 * self.EPY2,
525 MIN_DIM_FOR_EXTRUDED_SHAPE,
526 "%s - 2 * %s" % (self._getParamUserName("HY2"),
527 self._getParamUserName("EPY2")))
528 self._checkSize(self.HZ2 - 2 * self.EPZ2,
529 MIN_DIM_FOR_EXTRUDED_SHAPE,
530 "%s - 2 * %s" % (self._getParamUserName("HZ2"),
531 self._getParamUserName("EPZ2")))
533 def _makeRectangle(self, HY, HZ, planeSect):
535 Create a rectangle in the specified plane.
539 sketchStr = "Sketcher:F %g" % (-halfHZ) + " %g" % (-halfHY) + ":"
540 sketchStr += "TT %g" % (halfHZ) + " %g" % (-halfHY) + ":"
541 sketchStr += "TT %g" % (halfHZ) + " %g" % (halfHY) + ":"
542 sketchStr += "TT %g" % (-halfHZ) + " %g" % (halfHY) + ":WW"
543 logger.debug('Drawing rectangle: "%s"' % sketchStr)
544 sketch = self.geom.MakeSketcherOnPlane(sketchStr, planeSect)
547 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
549 Create the rectangular sections used to build the pipe.
551 planeSect1 = self.geom.MakePlane(fPoint, fNormal, 1.0)
552 outerRect1 = self._makeRectangle(self.HY1, self.HZ1, planeSect1)
553 planeSect2 = self.geom.MakePlane(lPoint, lNormal, 1.0)
554 outerRect2 = self._makeRectangle(self.HY2, self.HZ2, planeSect2)
555 if self.filling == HOLLOW:
556 innerRect1 = self._makeRectangle(self.HY1 - 2 * self.EPY1,
557 self.HZ1 - 2 * self.EPZ1,
559 innerRect2 = self._makeRectangle(self.HY2 - 2 * self.EPY2,
560 self.HZ2 - 2 * self.EPZ2,
566 return (outerRect1, innerRect1, outerRect2, innerRect2)
569 class StructuralElementPart2D(StructuralElementPart):
571 This class is an "abstract" class for all 2D structural element parts. It
572 should not be instantiated directly. See class
573 :class:`StructuralElementPart` for the description of the parameters.
576 DEFAULT_NAME = "StructuralElementPart2D"
578 def __init__(self, studyId, groupName, groupGeomObj, parameters,
579 name = DEFAULT_NAME):
580 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
582 self._orientation = orientation.Orientation2D(
583 self._getParameter(["angleAlpha"]),
584 self._getParameter(["angleBeta"]),
585 self._getParameter(["Vecteur"]))
586 self.offset = self._getParameter(["Excentre"], 0.0)
588 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
590 Create a copy of a face at a given offset.
592 if abs(offset) < epsilon:
593 return self.geom.MakeCopy(face)
595 offsetObj = self.geom.MakeOffset(face, offset)
596 # We have to explode the resulting object into faces because it is
597 # created as a polyhedron and not as a single face
598 faces = self.geom.SubShapeAll(offsetObj,
599 self.geom.ShapeType["FACE"])
602 def _buildMarkersWithOffset(self, offset):
604 Build the markers for the structural element part with a given offset
610 subShapes = self._getSubShapes()
612 for subShape in subShapes:
613 faces = self.geom.SubShapeAll(subShape,
614 self.geom.ShapeType["FACE"])
616 offsetFace = self._makeFaceOffset(face, offset)
617 # get tangent plane on surface by parameters
618 center = self.geom.MakeVertexOnSurface(offsetFace,
620 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
623 normal = self.geom.GetNormal(tangPlane)
624 marker = self._orientation.buildMarker(self.geom,
626 listMarkers.append(marker)
631 class ThickShell(StructuralElementPart2D):
633 This class defines a shell with a given thickness. It can be shifted from
634 the base face. The valid parameters for thick shells are:
636 * "Epais": thickness of the shell.
637 * "Excentre": offset of the shell from the base face.
638 * "angleAlpha": angle used to build the markers (see class
639 :class:`~salome.geom.structelem.orientation.Orientation2D`)
640 * "angleBeta": angle used to build the markers (see class
641 :class:`~salome.geom.structelem.orientation.Orientation2D`)
642 * "Vecteur": vector used instead of the angles to build the markers (see
643 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
645 See class :class:`StructuralElementPart` for the description of the
649 DEFAULT_NAME = "ThickShell"
651 def __init__(self, studyId, groupName, groupGeomObj, parameters,
652 name = DEFAULT_NAME):
653 StructuralElementPart2D.__init__(self, studyId, groupName,
654 groupGeomObj, parameters, name)
655 self.thickness = self._getParameter(["Epais"])
656 logger.debug(repr(self))
658 def _buildPart(self):
660 Create the geometrical shapes corresponding to the thick shell.
662 subShapes = self._getSubShapes()
665 for subShape in subShapes:
666 faces = self.geom.SubShapeAll(subShape,
667 self.geom.ShapeType["FACE"])
669 shape = self._buildThickShellForFace(face)
670 listSolids.append(shape)
672 if len(listSolids) == 0:
674 elif len(listSolids) == 1:
677 return self.geom.MakeCompound(listSolids)
679 def _buildThickShellForFace(self, face):
681 Create the geometrical shapes corresponding to the thick shell for a
685 if self.thickness < 2 * epsilon:
686 return self._makeFaceOffset(face, self.offset, epsilon)
688 upperOffset = self.offset + self.thickness / 2.0
689 lowerOffset = self.offset - self.thickness / 2.0
693 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
694 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
695 listShapes = [upperFace, lowerFace]
696 upperWires = self.geom.SubShapeAll(upperFace,
697 self.geom.ShapeType["WIRE"])
698 lowerWires = self.geom.SubShapeAll(lowerFace,
699 self.geom.ShapeType["WIRE"])
700 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
701 # if the face is a cylinder, we remove the extra side edge
702 upperWires = self._removeCylinderExtraEdge(upperWires)
703 lowerWires = self._removeCylinderExtraEdge(lowerWires)
704 for i in range(len(upperWires)):
705 resShape = self.geom.MakeThruSections([upperWires[i],
709 listShapes.append(resShape)
710 resultShell = self.geom.MakeShell(listShapes)
711 resultSolid = self.geom.MakeSolid([resultShell])
714 def _removeCylinderExtraEdge(self, wires):
716 Remove the side edge in a cylinder.
720 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
722 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
726 def _buildMarkers(self):
728 Build the markers defining the orientation of the thick shell.
730 return self._buildMarkersWithOffset(self.offset +
731 self.thickness / 2.0)
734 class Grid(StructuralElementPart2D):
736 This class defines a grid. A grid is represented by a 2D face patterned
737 with small lines in the main direction of the grid frame. The valid
738 parameters for grids are:
740 * "Excentre": offset of the grid from the base face.
741 * "angleAlpha": angle used to build the markers (see class
742 :class:`~salome.geom.structelem.orientation.Orientation2D`)
743 * "angleBeta": angle used to build the markers (see class
744 :class:`~salome.geom.structelem.orientation.Orientation2D`)
745 * "Vecteur": vector used instead of the angles to build the markers (see
746 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
747 * "origAxeX": X coordinate of the origin of the axis used to determine the
748 orientation of the frame in the case of a cylindrical grid.
749 * "origAxeY": Y coordinate of the origin of the axis used to determine the
750 orientation of the frame in the case of a cylindrical grid.
751 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
752 orientation of the frame in the case of a cylindrical grid.
753 * "axeX": X coordinate of the axis used to determine the orientation of
754 the frame in the case of a cylindrical grid.
755 * "axeY": Y coordinate of the axis used to determine the orientation of
756 the frame in the case of a cylindrical grid.
757 * "axeZ": Z coordinate of the axis used to determine the orientation of
758 the frame in the case of a cylindrical grid.
760 See class :class:`StructuralElementPart` for the description of the
764 DEFAULT_NAME = "Grid"
766 def __init__(self, studyId, groupName, groupGeomObj, parameters,
767 name = DEFAULT_NAME):
768 StructuralElementPart2D.__init__(self, studyId, groupName,
769 groupGeomObj, parameters, name)
770 self.xr = self._getParameter(["origAxeX"])
771 self.yr = self._getParameter(["origAxeY"])
772 self.zr = self._getParameter(["origAxeZ"])
773 self.vx = self._getParameter(["axeX"])
774 self.vy = self._getParameter(["axeY"])
775 self.vz = self._getParameter(["axeZ"])
776 logger.debug(repr(self))
778 def _buildPart(self):
780 Create the geometrical shapes representing the grid.
782 subShapes = self._getSubShapes()
785 for subShape in subShapes:
786 faces = self.geom.SubShapeAll(subShape,
787 self.geom.ShapeType["FACE"])
789 if self.geom.KindOfShape(face)[0] == \
790 self.geom.kind.CYLINDER2D and \
791 self.xr is not None and self.yr is not None and \
792 self.zr is not None and self.vx is not None and \
793 self.vy is not None and self.vz is not None:
794 shape = self._buildGridForCylinderFace(face)
796 shape = self._buildGridForNormalFace(face)
797 listGridShapes.append(shape)
799 if len(listGridShapes) == 0:
801 elif len(listGridShapes) == 1:
802 return listGridShapes[0]
804 return self.geom.MakeCompound(listGridShapes)
806 def _buildGridForNormalFace(self, face):
808 Create the geometrical shapes representing the grid for a given
809 non-cylindrical face.
811 baseFace = self._makeFaceOffset(face, self.offset)
812 gridList = [baseFace]
814 # Compute display length for grid elements
815 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
816 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
817 length = self.geom.MinDistance(p1, p2) / 2.0
819 for u in range(1, 10):
821 for v in range(1, 10):
823 # get tangent plane on surface by parameters
824 center = self.geom.MakeVertexOnSurface(baseFace,
826 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
829 # use the marker to get the orientation of the frame
830 normal = self.geom.GetNormal(tangPlane)
831 marker = self._orientation.buildMarker(self.geom, center,
833 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
834 xPoint = self.geom.MakeTranslation(center, Xx * length,
835 Xy * length, Xz * length)
836 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
837 gridList.append(gridLine)
838 grid = self.geom.MakeCompound(gridList)
841 def _buildGridForCylinderFace(self, face):
843 Create the geometrical shapes representing the grid for a given
846 baseFace = self._makeFaceOffset(face, self.offset)
847 gridList = [baseFace]
849 # Compute display length for grid elements
850 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
851 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
852 length = self.geom.MinDistance(p1, p2) / 2.0
854 # Create reference vector V
855 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
856 vPoint = self.geom.MakeTranslation(origPoint,
857 self.vx, self.vy, self.vz)
858 refVec = self.geom.MakeVector(origPoint, vPoint)
862 for v in range(1, 10):
865 # Compute the local orientation of the frame
866 center = self.geom.MakeVertexOnSurface(baseFace,
868 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
870 locOrient = self.geom.GetNormal(locPlaneYZ)
871 xPoint = self.geom.MakeTranslationVectorDistance(center,
874 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
875 gridList.append(gridLine)
877 grid = self.geom.MakeCompound(gridList)
880 def _buildMarkers(self):
882 Create the markers defining the orientation of the grid.
884 return self._buildMarkersWithOffset(self.offset)
887 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
890 Alias for class :class:`GeneralBeam`.
892 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
894 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
897 Alias for class :class:`CircularBeam`.
899 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
901 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
904 Alias for class :class:`RectangularBeam`.
906 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
908 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
911 Alias for class :class:`GeneralBeam`.
913 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
915 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
918 Alias for class :class:`RectangularBeam`.
920 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
922 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
925 Alias for class :class:`CircularBeam`.
927 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
929 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
931 Alias for class :class:`CircularBeam`.
933 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
935 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
937 Alias for class :class:`ThickShell`.
939 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
941 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
943 Alias for class :class:`Grid`.
945 return Grid(studyId, groupName, groupGeomObj, parameters, name)