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, lcs):
535 Create a rectangle in the specified plane.
539 sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
540 sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
541 sketchStr += "TT %g %g:" % (halfHY, halfHZ)
542 sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
543 logger.debug('Drawing rectangle: "%s"' % sketchStr)
544 sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
547 def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
549 Create one side of the rectangular sections used to build the pipe.
551 (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
552 lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
553 outerRect = self._makeRectangle(HY, HZ, lcs)
554 if self.filling == HOLLOW:
555 innerRect = self._makeRectangle(HY - 2.0 * EPY,
560 return (outerRect, innerRect)
562 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
564 Create the rectangular sections used to build the pipe.
566 (outerRect1, innerRect1) = \
567 self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
568 self.EPY1, self.EPZ1)
569 (outerRect2, innerRect2) = \
570 self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
571 self.EPY2, self.EPZ2)
572 return (outerRect1, innerRect1, outerRect2, innerRect2)
575 class StructuralElementPart2D(StructuralElementPart):
577 This class is an "abstract" class for all 2D structural element parts. It
578 should not be instantiated directly. See class
579 :class:`StructuralElementPart` for the description of the parameters.
582 DEFAULT_NAME = "StructuralElementPart2D"
584 def __init__(self, studyId, groupName, groupGeomObj, parameters,
585 name = DEFAULT_NAME):
586 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
588 self._orientation = orientation.Orientation2D(
589 self._getParameter(["angleAlpha"]),
590 self._getParameter(["angleBeta"]),
591 self._getParameter(["Vecteur"]))
592 self.offset = self._getParameter(["Excentre"], 0.0)
594 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
596 Create a copy of a face at a given offset.
598 if abs(offset) < epsilon:
599 return self.geom.MakeCopy(face)
601 offsetObj = self.geom.MakeOffset(face, offset)
602 # We have to explode the resulting object into faces because it is
603 # created as a polyhedron and not as a single face
604 faces = self.geom.SubShapeAll(offsetObj,
605 self.geom.ShapeType["FACE"])
608 def _buildMarkersWithOffset(self, offset):
610 Build the markers for the structural element part with a given offset
616 subShapes = self._getSubShapes()
618 for subShape in subShapes:
619 faces = self.geom.SubShapeAll(subShape,
620 self.geom.ShapeType["FACE"])
622 offsetFace = self._makeFaceOffset(face, offset)
623 # get tangent plane on surface by parameters
624 center = self.geom.MakeVertexOnSurface(offsetFace,
626 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
629 normal = self.geom.GetNormal(tangPlane)
630 marker = self._orientation.buildMarker(self.geom,
632 listMarkers.append(marker)
637 class ThickShell(StructuralElementPart2D):
639 This class defines a shell with a given thickness. It can be shifted from
640 the base face. The valid parameters for thick shells are:
642 * "Epais": thickness of the shell.
643 * "Excentre": offset of the shell from the base face.
644 * "angleAlpha": angle used to build the markers (see class
645 :class:`~salome.geom.structelem.orientation.Orientation2D`)
646 * "angleBeta": angle used to build the markers (see class
647 :class:`~salome.geom.structelem.orientation.Orientation2D`)
648 * "Vecteur": vector used instead of the angles to build the markers (see
649 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
651 See class :class:`StructuralElementPart` for the description of the
655 DEFAULT_NAME = "ThickShell"
657 def __init__(self, studyId, groupName, groupGeomObj, parameters,
658 name = DEFAULT_NAME):
659 StructuralElementPart2D.__init__(self, studyId, groupName,
660 groupGeomObj, parameters, name)
661 self.thickness = self._getParameter(["Epais"])
662 logger.debug(repr(self))
664 def _buildPart(self):
666 Create the geometrical shapes corresponding to the thick shell.
668 subShapes = self._getSubShapes()
671 for subShape in subShapes:
672 faces = self.geom.SubShapeAll(subShape,
673 self.geom.ShapeType["FACE"])
675 shape = self._buildThickShellForFace(face)
676 listSolids.append(shape)
678 if len(listSolids) == 0:
680 elif len(listSolids) == 1:
683 return self.geom.MakeCompound(listSolids)
685 def _buildThickShellForFace(self, face):
687 Create the geometrical shapes corresponding to the thick shell for a
691 if self.thickness < 2 * epsilon:
692 return self._makeFaceOffset(face, self.offset, epsilon)
694 upperOffset = self.offset + self.thickness / 2.0
695 lowerOffset = self.offset - self.thickness / 2.0
699 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
700 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
701 listShapes = [upperFace, lowerFace]
702 upperWires = self.geom.SubShapeAll(upperFace,
703 self.geom.ShapeType["WIRE"])
704 lowerWires = self.geom.SubShapeAll(lowerFace,
705 self.geom.ShapeType["WIRE"])
706 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
707 # if the face is a cylinder, we remove the extra side edge
708 upperWires = self._removeCylinderExtraEdge(upperWires)
709 lowerWires = self._removeCylinderExtraEdge(lowerWires)
710 for i in range(len(upperWires)):
711 resShape = self.geom.MakeThruSections([upperWires[i],
715 listShapes.append(resShape)
716 resultShell = self.geom.MakeShell(listShapes)
717 resultSolid = self.geom.MakeSolid([resultShell])
720 def _removeCylinderExtraEdge(self, wires):
722 Remove the side edge in a cylinder.
726 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
728 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
732 def _buildMarkers(self):
734 Build the markers defining the orientation of the thick shell.
736 return self._buildMarkersWithOffset(self.offset +
737 self.thickness / 2.0)
740 class Grid(StructuralElementPart2D):
742 This class defines a grid. A grid is represented by a 2D face patterned
743 with small lines in the main direction of the grid frame. The valid
744 parameters for grids are:
746 * "Excentre": offset of the grid from the base face.
747 * "angleAlpha": angle used to build the markers (see class
748 :class:`~salome.geom.structelem.orientation.Orientation2D`)
749 * "angleBeta": angle used to build the markers (see class
750 :class:`~salome.geom.structelem.orientation.Orientation2D`)
751 * "Vecteur": vector used instead of the angles to build the markers (see
752 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
753 * "origAxeX": X coordinate of the origin of the axis used to determine the
754 orientation of the frame in the case of a cylindrical grid.
755 * "origAxeY": Y coordinate of the origin of the axis used to determine the
756 orientation of the frame in the case of a cylindrical grid.
757 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
758 orientation of the frame in the case of a cylindrical grid.
759 * "axeX": X coordinate of the axis used to determine the orientation of
760 the frame in the case of a cylindrical grid.
761 * "axeY": Y coordinate of the axis used to determine the orientation of
762 the frame in the case of a cylindrical grid.
763 * "axeZ": Z coordinate of the axis used to determine the orientation of
764 the frame in the case of a cylindrical grid.
766 See class :class:`StructuralElementPart` for the description of the
770 DEFAULT_NAME = "Grid"
772 def __init__(self, studyId, groupName, groupGeomObj, parameters,
773 name = DEFAULT_NAME):
774 StructuralElementPart2D.__init__(self, studyId, groupName,
775 groupGeomObj, parameters, name)
776 self.xr = self._getParameter(["origAxeX"])
777 self.yr = self._getParameter(["origAxeY"])
778 self.zr = self._getParameter(["origAxeZ"])
779 self.vx = self._getParameter(["axeX"])
780 self.vy = self._getParameter(["axeY"])
781 self.vz = self._getParameter(["axeZ"])
782 logger.debug(repr(self))
784 def _buildPart(self):
786 Create the geometrical shapes representing the grid.
788 subShapes = self._getSubShapes()
791 for subShape in subShapes:
792 faces = self.geom.SubShapeAll(subShape,
793 self.geom.ShapeType["FACE"])
795 if self.geom.KindOfShape(face)[0] == \
796 self.geom.kind.CYLINDER2D and \
797 self.xr is not None and self.yr is not None and \
798 self.zr is not None and self.vx is not None and \
799 self.vy is not None and self.vz is not None:
800 shape = self._buildGridForCylinderFace(face)
802 shape = self._buildGridForNormalFace(face)
803 listGridShapes.append(shape)
805 if len(listGridShapes) == 0:
807 elif len(listGridShapes) == 1:
808 return listGridShapes[0]
810 return self.geom.MakeCompound(listGridShapes)
812 def _buildGridForNormalFace(self, face):
814 Create the geometrical shapes representing the grid for a given
815 non-cylindrical face.
817 baseFace = self._makeFaceOffset(face, self.offset)
818 gridList = [baseFace]
820 # Compute display length for grid elements
821 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
822 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
823 length = self.geom.MinDistance(p1, p2) / 2.0
825 for u in range(1, 10):
827 for v in range(1, 10):
829 # get tangent plane on surface by parameters
830 center = self.geom.MakeVertexOnSurface(baseFace,
832 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
835 # use the marker to get the orientation of the frame
836 normal = self.geom.GetNormal(tangPlane)
837 marker = self._orientation.buildMarker(self.geom, center,
839 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
840 xPoint = self.geom.MakeTranslation(center, Xx * length,
841 Xy * length, Xz * length)
842 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
843 gridList.append(gridLine)
844 grid = self.geom.MakeCompound(gridList)
847 def _buildGridForCylinderFace(self, face):
849 Create the geometrical shapes representing the grid for a given
852 baseFace = self._makeFaceOffset(face, self.offset)
853 gridList = [baseFace]
855 # Compute display length for grid elements
856 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
857 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
858 length = self.geom.MinDistance(p1, p2) / 2.0
860 # Create reference vector V
861 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
862 vPoint = self.geom.MakeTranslation(origPoint,
863 self.vx, self.vy, self.vz)
864 refVec = self.geom.MakeVector(origPoint, vPoint)
868 for v in range(1, 10):
871 # Compute the local orientation of the frame
872 center = self.geom.MakeVertexOnSurface(baseFace,
874 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
876 locOrient = self.geom.GetNormal(locPlaneYZ)
877 xPoint = self.geom.MakeTranslationVectorDistance(center,
880 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
881 gridList.append(gridLine)
883 grid = self.geom.MakeCompound(gridList)
886 def _buildMarkers(self):
888 Create the markers defining the orientation of the grid.
890 return self._buildMarkersWithOffset(self.offset)
893 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
896 Alias for class :class:`GeneralBeam`.
898 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
900 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
903 Alias for class :class:`CircularBeam`.
905 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
907 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
910 Alias for class :class:`RectangularBeam`.
912 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
914 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
917 Alias for class :class:`GeneralBeam`.
919 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
921 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
924 Alias for class :class:`RectangularBeam`.
926 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
928 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
931 Alias for class :class:`CircularBeam`.
933 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
935 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
937 Alias for class :class:`CircularBeam`.
939 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
941 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
943 Alias for class :class:`ThickShell`.
945 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
947 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
949 Alias for class :class:`Grid`.
951 return Grid(studyId, groupName, groupGeomObj, parameters, name)