1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 length = self.geom.BasicProperties(path)[0]
258 p1 = self.geom.MakeVertexOnCurve(path, 0.0)
259 p2 = self.geom.GetFirstVertex(path)
260 dist = self.geom.MinDistance(p1, p2)
261 return dist > length / 2
263 def _getVertexAndTangentOnOrientedWire(self, path, param):
265 Get a vertex and the corresponding tangent on a wire by parameter.
266 This method takes into account the "real" orientation of the wire
267 (i.e. the orientation of the underlying OCC object).
269 if self._isReversed(path):
270 vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
271 invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
272 tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
275 tangent = self.geom.MakeVector(vertex, tanpoint)
277 vertex = self.geom.MakeVertexOnCurve(path, param)
278 tangent = self.geom.MakeTangentOnCurve(path, param)
279 return (vertex, tangent)
281 def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
283 Create a solid by the extrusion of section `wire1` to section `wire2`
286 face1 = self.geom.MakeFace(wire1, True)
287 face2 = self.geom.MakeFace(wire2, True)
288 shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
291 closedShell = self.geom.MakeShell([face1, face2, shell])
292 solid = self.geom.MakeSolid([closedShell])
295 def _buildPart(self):
297 Build the structural element part.
299 # Get all the subshapes in the group (normally only edges and wires)
300 paths = self._getSubShapes()
303 withCorrection = False
306 # Build the sections (rectangular or circular) at each end of the
308 (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
310 (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
312 (outerWire1, innerWire1, outerWire2, innerWire2) = \
313 self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
315 # Create the resulting solid
316 outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
317 fPoint, lPoint, path)
318 if self.filling == HOLLOW:
319 innerSolid = self._makeSolidPipeFromWires(innerWire1,
322 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
323 listPipes.append(resultSolid)
325 listPipes.append(outerSolid)
327 if len(listPipes) == 0:
329 elif len(listPipes) == 1:
332 return self.geom.MakeCompound(listPipes)
334 def _buildMarkers(self):
336 Build the markers defining the orientation of the structural element
340 paths = self._getSubShapes()
343 (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
345 marker = self._orientation.buildMarker(self.geom, center, vecX)
346 listMarkers.append(marker)
350 class GeneralBeam(Beam):
352 This class defines a beam with a generic section. It is represented only
353 as the underlying wire. See class :class:`StructuralElementPart` for the
354 description of the parameters.
357 def __init__(self, studyId, groupName, groupGeomObj, parameters,
358 name = Beam.DEFAULT_NAME):
359 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
361 logger.debug(repr(self))
363 def _buildPart(self):
365 Create a copy of the underlying wire.
367 edges = self._getSubShapes(1e-7)
370 wire = self.geom.MakeWire(edges)
374 class CircularBeam(Beam):
376 This class defines a beam with a circular section. It can be full or
377 hollow, and its radius and thickness can vary from one end of the beam to
378 the other. The valid parameters for circular beams are:
380 * "R1" or "R": radius at the first end of the beam.
381 * "R2" or "R": radius at the other end of the beam.
382 * "EP1" or "EP" (optional): thickness at the first end of the beam.
383 If not specified or equal to 0, the beam is considered full.
384 * "EP2" or "EP" (optional): thickness at the other end of the beam.
385 If not specified or equal to 0, the beam is considered full.
387 See class :class:`StructuralElementPart` for the description of the
392 def __init__(self, studyId, groupName, groupGeomObj, parameters,
393 name = Beam.DEFAULT_NAME):
394 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
397 self.R1 = self._getParameter(["R1", "R"])
398 self.R2 = self._getParameter(["R2", "R"])
399 self.EP1 = self._getParameter(["EP1", "EP"])
400 self.EP2 = self._getParameter(["EP2", "EP"])
402 if self.EP1 is None or self.EP2 is None or \
403 self.EP1 == 0 or self.EP2 == 0:
406 self.filling = HOLLOW
408 logger.debug(repr(self))
411 self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
412 self._getParamUserName("R1"))
413 self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
414 self._getParamUserName("R2"))
415 if self.filling == HOLLOW:
416 self._checkSize(self.EP1, MIN_THICKNESS,
417 self._getParamUserName("EP1"))
418 self._checkSize(self.EP2, MIN_THICKNESS,
419 self._getParamUserName("EP2"))
420 self._checkSize(self.R1 - self.EP1,
421 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
422 "%s - %s" % (self._getParamUserName("R1"),
423 self._getParamUserName("EP1")))
424 self._checkSize(self.R2 - self.EP2,
425 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
426 "%s - %s" % (self._getParamUserName("R2"),
427 self._getParamUserName("EP2")))
429 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
431 Create the circular sections used to build the pipe.
433 outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
434 outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
435 if self.filling == HOLLOW:
436 innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
438 innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
444 return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
447 class RectangularBeam(Beam):
449 This class defines a beam with a rectangular section. It can be full or
450 hollow, and its dimensions can vary from one end of the beam to the other.
451 The valid parameters for rectangular beams are:
453 * "HY1", "HY", "H1" or "H": width at the first end of the beam.
454 * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
455 * "HY2", "HY", "H2" or "H": width at the other end of the beam.
456 * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
457 * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
458 direction at the first end of the beam. If not specified or equal to 0,
459 the beam is considered full.
460 * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
461 direction at the first end of the beam. If not specified or equal to 0,
462 the beam is considered full.
463 * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
464 direction at the other end of the beam. If not specified or equal to 0,
465 the beam is considered full.
466 * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
467 direction at the other end of the beam. If not specified or equal to 0,
468 the beam is considered full.
470 See class :class:`StructuralElementPart` for the description of the
475 def __init__(self, studyId, groupName, groupGeomObj, parameters,
476 name = Beam.DEFAULT_NAME):
477 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
480 self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
481 self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
482 self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
483 self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
484 self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
485 self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
486 self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
487 self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
489 if self.EPY1 is None or self.EPZ1 is None or \
490 self.EPY2 is None or self.EPZ2 is None or \
491 self.EPY1 == 0 or self.EPZ1 == 0 or \
492 self.EPY2 == 0 or self.EPZ2 == 0:
495 self.filling = HOLLOW
497 logger.debug(repr(self))
500 self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
501 self._getParamUserName("HY1"))
502 self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
503 self._getParamUserName("HZ1"))
504 self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
505 self._getParamUserName("HY2"))
506 self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
507 self._getParamUserName("HZ2"))
508 if self.filling == HOLLOW:
509 self._checkSize(self.EPY1, MIN_THICKNESS,
510 self._getParamUserName("EPY1"))
511 self._checkSize(self.EPZ1, MIN_THICKNESS,
512 self._getParamUserName("EPZ1"))
513 self._checkSize(self.EPY2, MIN_THICKNESS,
514 self._getParamUserName("EPY2"))
515 self._checkSize(self.EPZ2, MIN_THICKNESS,
516 self._getParamUserName("EPZ2"))
517 self._checkSize(self.HY1 - 2 * self.EPY1,
518 MIN_DIM_FOR_EXTRUDED_SHAPE,
519 "%s - 2 * %s" % (self._getParamUserName("HY1"),
520 self._getParamUserName("EPY1")))
521 self._checkSize(self.HZ1 - 2 * self.EPZ1,
522 MIN_DIM_FOR_EXTRUDED_SHAPE,
523 "%s - 2 * %s" % (self._getParamUserName("HZ1"),
524 self._getParamUserName("EPZ1")))
525 self._checkSize(self.HY2 - 2 * self.EPY2,
526 MIN_DIM_FOR_EXTRUDED_SHAPE,
527 "%s - 2 * %s" % (self._getParamUserName("HY2"),
528 self._getParamUserName("EPY2")))
529 self._checkSize(self.HZ2 - 2 * self.EPZ2,
530 MIN_DIM_FOR_EXTRUDED_SHAPE,
531 "%s - 2 * %s" % (self._getParamUserName("HZ2"),
532 self._getParamUserName("EPZ2")))
534 def _makeRectangle(self, HY, HZ, lcs):
536 Create a rectangle in the specified plane.
540 sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
541 sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
542 sketchStr += "TT %g %g:" % (halfHY, halfHZ)
543 sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
544 logger.debug('Drawing rectangle: "%s"' % sketchStr)
545 sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
548 def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
550 Create one side of the rectangular sections used to build the pipe.
552 (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
553 lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
554 outerRect = self._makeRectangle(HY, HZ, lcs)
555 if self.filling == HOLLOW:
556 innerRect = self._makeRectangle(HY - 2.0 * EPY,
561 return (outerRect, innerRect)
563 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
565 Create the rectangular sections used to build the pipe.
567 (outerRect1, innerRect1) = \
568 self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
569 self.EPY1, self.EPZ1)
570 (outerRect2, innerRect2) = \
571 self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
572 self.EPY2, self.EPZ2)
573 return (outerRect1, innerRect1, outerRect2, innerRect2)
576 class StructuralElementPart2D(StructuralElementPart):
578 This class is an "abstract" class for all 2D structural element parts. It
579 should not be instantiated directly. See class
580 :class:`StructuralElementPart` for the description of the parameters.
583 DEFAULT_NAME = "StructuralElementPart2D"
585 def __init__(self, studyId, groupName, groupGeomObj, parameters,
586 name = DEFAULT_NAME):
587 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
589 self._orientation = orientation.Orientation2D(
590 self._getParameter(["angleAlpha"]),
591 self._getParameter(["angleBeta"]),
592 self._getParameter(["Vecteur"]))
593 self.offset = self._getParameter(["Excentre"], 0.0)
595 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
597 Create a copy of a face at a given offset.
599 if abs(offset) < epsilon:
600 return self.geom.MakeCopy(face)
602 offsetObj = self.geom.MakeOffset(face, offset)
603 # We have to explode the resulting object into faces because it is
604 # created as a polyhedron and not as a single face
605 faces = self.geom.SubShapeAll(offsetObj,
606 self.geom.ShapeType["FACE"])
609 def _buildMarkersWithOffset(self, offset):
611 Build the markers for the structural element part with a given offset
617 subShapes = self._getSubShapes()
619 for subShape in subShapes:
620 faces = self.geom.SubShapeAll(subShape,
621 self.geom.ShapeType["FACE"])
623 offsetFace = self._makeFaceOffset(face, offset)
624 # get tangent plane on surface by parameters
625 center = self.geom.MakeVertexOnSurface(offsetFace,
627 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
630 normal = self.geom.GetNormal(tangPlane)
631 marker = self._orientation.buildMarker(self.geom,
633 listMarkers.append(marker)
638 class ThickShell(StructuralElementPart2D):
640 This class defines a shell with a given thickness. It can be shifted from
641 the base face. The valid parameters for thick shells are:
643 * "Epais": thickness of the shell.
644 * "Excentre": offset of the shell from the base face.
645 * "angleAlpha": angle used to build the markers (see class
646 :class:`~salome.geom.structelem.orientation.Orientation2D`)
647 * "angleBeta": angle used to build the markers (see class
648 :class:`~salome.geom.structelem.orientation.Orientation2D`)
649 * "Vecteur": vector used instead of the angles to build the markers (see
650 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
652 See class :class:`StructuralElementPart` for the description of the
656 DEFAULT_NAME = "ThickShell"
658 def __init__(self, studyId, groupName, groupGeomObj, parameters,
659 name = DEFAULT_NAME):
660 StructuralElementPart2D.__init__(self, studyId, groupName,
661 groupGeomObj, parameters, name)
662 self.thickness = self._getParameter(["Epais"])
663 logger.debug(repr(self))
665 def _buildPart(self):
667 Create the geometrical shapes corresponding to the thick shell.
669 subShapes = self._getSubShapes()
672 for subShape in subShapes:
673 faces = self.geom.SubShapeAll(subShape,
674 self.geom.ShapeType["FACE"])
676 shape = self._buildThickShellForFace(face)
677 listSolids.append(shape)
679 if len(listSolids) == 0:
681 elif len(listSolids) == 1:
684 return self.geom.MakeCompound(listSolids)
686 def _buildThickShellForFace(self, face):
688 Create the geometrical shapes corresponding to the thick shell for a
692 if self.thickness < 2 * epsilon:
693 return self._makeFaceOffset(face, self.offset, epsilon)
695 upperOffset = self.offset + self.thickness / 2.0
696 lowerOffset = self.offset - self.thickness / 2.0
700 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
701 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
702 listShapes = [upperFace, lowerFace]
703 upperWires = self.geom.SubShapeAll(upperFace,
704 self.geom.ShapeType["WIRE"])
705 lowerWires = self.geom.SubShapeAll(lowerFace,
706 self.geom.ShapeType["WIRE"])
707 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
708 # if the face is a cylinder, we remove the extra side edge
709 upperWires = self._removeCylinderExtraEdge(upperWires)
710 lowerWires = self._removeCylinderExtraEdge(lowerWires)
711 for i in range(len(upperWires)):
712 resShape = self.geom.MakeThruSections([upperWires[i],
716 listShapes.append(resShape)
717 resultShell = self.geom.MakeShell(listShapes)
718 resultSolid = self.geom.MakeSolid([resultShell])
721 def _removeCylinderExtraEdge(self, wires):
723 Remove the side edge in a cylinder.
727 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
729 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
733 def _buildMarkers(self):
735 Build the markers defining the orientation of the thick shell.
737 return self._buildMarkersWithOffset(self.offset +
738 self.thickness / 2.0)
741 class Grid(StructuralElementPart2D):
743 This class defines a grid. A grid is represented by a 2D face patterned
744 with small lines in the main direction of the grid frame. The valid
745 parameters for grids are:
747 * "Excentre": offset of the grid from the base face.
748 * "angleAlpha": angle used to build the markers (see class
749 :class:`~salome.geom.structelem.orientation.Orientation2D`)
750 * "angleBeta": angle used to build the markers (see class
751 :class:`~salome.geom.structelem.orientation.Orientation2D`)
752 * "Vecteur": vector used instead of the angles to build the markers (see
753 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
754 * "origAxeX": X coordinate of the origin of the axis used to determine the
755 orientation of the frame in the case of a cylindrical grid.
756 * "origAxeY": Y coordinate of the origin of the axis used to determine the
757 orientation of the frame in the case of a cylindrical grid.
758 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
759 orientation of the frame in the case of a cylindrical grid.
760 * "axeX": X coordinate of the axis used to determine the orientation of
761 the frame in the case of a cylindrical grid.
762 * "axeY": Y coordinate of the axis used to determine the orientation of
763 the frame in the case of a cylindrical grid.
764 * "axeZ": Z coordinate of the axis used to determine the orientation of
765 the frame in the case of a cylindrical grid.
767 See class :class:`StructuralElementPart` for the description of the
771 DEFAULT_NAME = "Grid"
773 def __init__(self, studyId, groupName, groupGeomObj, parameters,
774 name = DEFAULT_NAME):
775 StructuralElementPart2D.__init__(self, studyId, groupName,
776 groupGeomObj, parameters, name)
777 self.xr = self._getParameter(["origAxeX"])
778 self.yr = self._getParameter(["origAxeY"])
779 self.zr = self._getParameter(["origAxeZ"])
780 self.vx = self._getParameter(["axeX"])
781 self.vy = self._getParameter(["axeY"])
782 self.vz = self._getParameter(["axeZ"])
783 logger.debug(repr(self))
785 def _buildPart(self):
787 Create the geometrical shapes representing the grid.
789 subShapes = self._getSubShapes()
792 for subShape in subShapes:
793 faces = self.geom.SubShapeAll(subShape,
794 self.geom.ShapeType["FACE"])
796 if self.geom.KindOfShape(face)[0] == \
797 self.geom.kind.CYLINDER2D and \
798 self.xr is not None and self.yr is not None and \
799 self.zr is not None and self.vx is not None and \
800 self.vy is not None and self.vz is not None:
801 shape = self._buildGridForCylinderFace(face)
803 shape = self._buildGridForNormalFace(face)
804 listGridShapes.append(shape)
806 if len(listGridShapes) == 0:
808 elif len(listGridShapes) == 1:
809 return listGridShapes[0]
811 return self.geom.MakeCompound(listGridShapes)
813 def _buildGridForNormalFace(self, face):
815 Create the geometrical shapes representing the grid for a given
816 non-cylindrical face.
818 baseFace = self._makeFaceOffset(face, self.offset)
819 gridList = [baseFace]
821 # Compute display length for grid elements
822 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
823 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
824 length = self.geom.MinDistance(p1, p2) / 2.0
826 for u in range(1, 10):
828 for v in range(1, 10):
830 # get tangent plane on surface by parameters
831 center = self.geom.MakeVertexOnSurface(baseFace,
833 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
836 # use the marker to get the orientation of the frame
837 normal = self.geom.GetNormal(tangPlane)
838 marker = self._orientation.buildMarker(self.geom, center,
840 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
841 xPoint = self.geom.MakeTranslation(center, Xx * length,
842 Xy * length, Xz * length)
843 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
844 gridList.append(gridLine)
845 grid = self.geom.MakeCompound(gridList)
848 def _buildGridForCylinderFace(self, face):
850 Create the geometrical shapes representing the grid for a given
853 baseFace = self._makeFaceOffset(face, self.offset)
854 gridList = [baseFace]
856 # Compute display length for grid elements
857 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
858 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
859 length = self.geom.MinDistance(p1, p2) / 2.0
861 # Create reference vector V
862 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
863 vPoint = self.geom.MakeTranslation(origPoint,
864 self.vx, self.vy, self.vz)
865 refVec = self.geom.MakeVector(origPoint, vPoint)
869 for v in range(1, 10):
872 # Compute the local orientation of the frame
873 center = self.geom.MakeVertexOnSurface(baseFace,
875 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
877 locOrient = self.geom.GetNormal(locPlaneYZ)
878 xPoint = self.geom.MakeTranslationVectorDistance(center,
881 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
882 gridList.append(gridLine)
884 grid = self.geom.MakeCompound(gridList)
887 def _buildMarkers(self):
889 Create the markers defining the orientation of the grid.
891 return self._buildMarkersWithOffset(self.offset)
894 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
897 Alias for class :class:`GeneralBeam`.
899 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
901 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
904 Alias for class :class:`CircularBeam`.
906 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
908 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
911 Alias for class :class:`RectangularBeam`.
913 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
915 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
918 Alias for class :class:`GeneralBeam`.
920 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
922 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
925 Alias for class :class:`RectangularBeam`.
927 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
929 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
932 Alias for class :class:`CircularBeam`.
934 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
936 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
938 Alias for class :class:`CircularBeam`.
940 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
942 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
944 Alias for class :class:`ThickShell`.
946 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
948 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
950 Alias for class :class:`Grid`.
952 return Grid(studyId, groupName, groupGeomObj, parameters, name)