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`.
33 from salome.kernel.logger import Logger
34 from salome.kernel import termcolor
35 logger = Logger("salome.geom.structelem.parts", color = termcolor.RED)
36 from salome.geom.geomtools import getGeompy
40 # Filling for the beams
44 # Minimum dimension for the shapes to extrude
45 MIN_DIM_FOR_EXTRUDED_SHAPE = 2e-4
46 MIN_LENGTH_FOR_EXTRUSION = 1e-4
49 # Colors for the structural elements
50 GREEN = SALOMEDS.Color(0.0, 1.0, 0.0)
51 LIGHT_GREEN = SALOMEDS.Color(0.0, 1.0, 170.0/255.0)
52 BLUE = SALOMEDS.Color(0.0, 0.0, 1.0)
53 LIGHT_BLUE = SALOMEDS.Color(0.0, 0.5, 1.0)
54 RED = SALOMEDS.Color(1.0, 0.0, 0.0)
55 LIGHT_RED = SALOMEDS.Color(1.0, 0.5, 0.5)
56 PURPLE = SALOMEDS.Color(170.0/255.0, 85.0/255.0, 1.0)
57 ORANGE = SALOMEDS.Color(1.0, 170.0/255.0, 0.0)
60 class InvalidParameterError(Exception):
62 This exception is raised when an invalid parameter is used to build a
63 structural element part.
66 def __init__(self, groupName, expression, minValue, value):
67 self.groupName = groupName
68 self.expression = expression
69 self.minValue = minValue
73 return "%s < %g (%s = %g in %s)" % (self.expression, self.minValue,
74 self.expression, self.value,
80 This class enables the use of sub-shapes in sets or as dictionary keys.
81 It implements __eq__ and __hash__ methods so that sub-shapes with the same
82 CORBA object `mainShape` and the same `id` are considered equal.
85 def __init__(self, mainShape, id):
86 self._mainShape = mainShape
89 def getObj(self, geom):
91 Return the sub-shape (GEOM object). `geom` is a pseudo-geompy object
92 used to find the geometrical object.
94 return geom.GetSubShape(self._mainShape, [self._id])
96 def __eq__(self, other):
97 return self._mainShape._is_equivalent(other._mainShape) and \
101 return self._mainShape._hash(2147483647) ^ self._id
104 class StructuralElementPart:
106 This class is the base class for all structural element parts. It should
107 not be instantiated directly (consider it as an "abstract" class).
109 :type studyId: integer
110 :param studyId: the ID of the study in which the part is created.
112 :type groupName: string
113 :param groupName: the name of the underlying geometrical primitive in the
116 :type groupGeomObj: GEOM object
117 :param groupGeomObj: the underlying geometrical primitive.
119 :type parameters: dictionary
120 :param parameters: parameters defining the structural element (see
121 subclasses for details).
124 :param name: name to use for the created object in the study.
128 DEFAULT_NAME = "StructElemPart"
130 def __init__(self, studyId, groupName, groupGeomObj, parameters,
131 name = DEFAULT_NAME, color = None):
132 self._parameters = parameters
133 self.groupName = groupName
134 self._groupGeomObj = groupGeomObj
135 self._orientation = None
136 self._paramUserName = {}
138 self.geom = getGeompy(studyId)
139 self.baseShapesSet = set()
140 mainShape = self.geom.GetMainShape(groupGeomObj)
141 listIDs = self.geom.GetObjectIDs(groupGeomObj)
142 if mainShape is not None and listIDs is not None:
144 self.baseShapesSet.add(SubShapeID(mainShape, id))
146 if self.color is None:
147 self.color = self._groupGeomObj.GetColor()
149 def _getParameter(self, nameList, default = None):
151 This method finds the value of a parameter in the parameters
152 dictionary. The argument is a list because some parameters can have
153 several different names.
155 if len(nameList) > 0:
156 paramName = nameList[0]
157 for name in nameList:
158 if self._parameters.has_key(name):
159 self._paramUserName[paramName] = name
160 return self._parameters[name]
163 def _getParamUserName(self, paramName):
165 This method finds the user name for a parameter.
167 if self._paramUserName.has_key(paramName):
168 return self._paramUserName[paramName]
173 reprdict = self.__dict__.copy()
174 del reprdict["_parameters"]
175 del reprdict["groupName"]
176 del reprdict["_groupGeomObj"]
177 del reprdict["_paramUserName"]
180 del reprdict["baseShapesSet"]
181 return '%s("%s", %s)' % (self.__class__.__name__, self.groupName,
184 def addOrientation(self, orientParams):
186 Add orientation information to the structural element part. See class
187 :class:`~salome.geom.structelem.orientation.Orientation1D` for the description
190 self._orientation.addParams(orientParams)
192 def _checkSize(self, value, mindim, expression):
194 This method checks that some parameters or some expressions involving
195 those parameters are greater than a minimum value.
198 raise InvalidParameterError(self.groupName, expression,
203 Build the geometric shapes and the markers corresponding to the
204 structural element part in the study `studyId`.
206 shape = self._buildPart()
207 markers = self._buildMarkers()
208 shape.SetColor(self.color)
209 for marker in markers:
210 marker.SetColor(self.color)
211 return (shape, markers)
213 def _buildPart(self):
215 This abstract method must be implemented in subclasses and should
216 create the geometrical shape(s) of the structural element part.
218 raise NotImplementedError("Method _buildPart not implemented in class"
219 " %s (it must be implemented in "
220 "StructuralElementPart subclasses)." %
221 self.__class__.__name__)
223 def _buildMarkers(self):
225 This abstract method must be implemented in subclasses and should
226 create the markers defining the orientation of the structural element
229 raise NotImplementedError("Method _buildMarker not implemented in "
230 "class %s (it must be implemented in "
231 "StructuralElementPart subclasses)." %
232 self.__class__.__name__)
234 def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
236 Find and return the base sub-shapes in the structural element part.
239 for subShapeID in self.baseShapesSet:
240 subShape = subShapeID.getObj(self.geom)
241 length = self.geom.BasicProperties(subShape)[0]
243 logger.warning("Length too short (%s - ID %s, length = %g), "
244 "subshape will not be used in structural "
245 "element" % (self.groupName, subShapeID._id,
248 subShapes.append(subShape)
252 class Beam(StructuralElementPart):
254 This class is an "abstract" class for all 1D structural element parts. It
255 should not be instantiated directly. See class
256 :class:`StructuralElementPart` for the description of the parameters.
259 DEFAULT_NAME = "Beam"
261 def __init__(self, studyId, groupName, groupGeomObj, parameters,
262 name = DEFAULT_NAME, color = None):
263 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
264 parameters, name, color)
265 self._orientation = orientation.Orientation1D()
267 def _isReversed(self, path):
269 This method checks if a 1D object is "reversed", i.e. if its
270 orientation is different than the orientation of the underlying OCC
273 length = self.geom.BasicProperties(path)[0]
274 p1 = self.geom.MakeVertexOnCurve(path, 0.0)
275 p2 = self.geom.GetFirstVertex(path)
276 dist = self.geom.MinDistance(p1, p2)
277 return dist > length / 2
279 def _getVertexAndTangentOnOrientedWire(self, path, param):
281 Get a vertex and the corresponding tangent on a wire by parameter.
282 This method takes into account the "real" orientation of the wire
283 (i.e. the orientation of the underlying OCC object).
285 if self._isReversed(path):
286 vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
287 invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
288 tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
291 tangent = self.geom.MakeVector(vertex, tanpoint)
293 vertex = self.geom.MakeVertexOnCurve(path, param)
294 tangent = self.geom.MakeTangentOnCurve(path, param)
295 return (vertex, tangent)
297 def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
299 Create a solid by the extrusion of section `wire1` to section `wire2`
302 face1 = self.geom.MakeFace(wire1, True)
303 face2 = self.geom.MakeFace(wire2, True)
304 shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
307 closedShell = self.geom.MakeShell([face1, face2, shell])
308 solid = self.geom.MakeSolid([closedShell])
311 def _buildPart(self):
313 Build the structural element part.
315 # Get all the sub-shapes in the group (normally only edges and wires)
316 paths = self._getSubShapes()
319 withCorrection = False
322 # Build the sections (rectangular or circular) at each end of the
324 (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
326 (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
328 (outerWire1, innerWire1, outerWire2, innerWire2) = \
329 self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
331 # Create the resulting solid
332 outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
333 fPoint, lPoint, path)
334 if self.filling == HOLLOW:
335 innerSolid = self._makeSolidPipeFromWires(innerWire1,
338 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
339 listPipes.append(resultSolid)
341 listPipes.append(outerSolid)
343 if len(listPipes) == 0:
345 elif len(listPipes) == 1:
348 return self.geom.MakeCompound(listPipes)
350 def _buildMarkers(self):
352 Build the markers defining the orientation of the structural element
356 paths = self._getSubShapes()
359 (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
361 marker = self._orientation.buildMarker(self.geom, center, vecX)
362 listMarkers.append(marker)
366 class CircularBeam(Beam):
368 This class defines a beam with a circular section. It can be full or
369 hollow, and its radius and thickness can vary from one end of the beam to
370 the other. The valid parameters for circular beams are:
372 * "R1" or "R": radius at the first end of the beam.
373 * "R2" or "R": radius at the other end of the beam.
374 * "EP1" or "EP" (optional): thickness at the first end of the beam.
375 If not specified or equal to 0, the beam is considered full.
376 * "EP2" or "EP" (optional): thickness at the other end of the beam.
377 If not specified or equal to 0, the beam is considered full.
379 See class :class:`StructuralElementPart` for the description of the
384 def __init__(self, studyId, groupName, groupGeomObj, parameters,
385 name = Beam.DEFAULT_NAME, color = None):
387 if parameters.has_key("R1"): # variable section
389 else: # constant section
392 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
395 self.R1 = self._getParameter(["R1", "R"])
396 self.R2 = self._getParameter(["R2", "R"])
397 self.EP1 = self._getParameter(["EP1", "EP"])
398 self.EP2 = self._getParameter(["EP2", "EP"])
400 if self.EP1 is None or self.EP2 is None or \
401 self.EP1 == 0 or self.EP2 == 0:
404 self.filling = HOLLOW
406 logger.debug(repr(self))
409 self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
410 self._getParamUserName("R1"))
411 self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
412 self._getParamUserName("R2"))
413 if self.filling == HOLLOW:
414 self._checkSize(self.EP1, MIN_THICKNESS,
415 self._getParamUserName("EP1"))
416 self._checkSize(self.EP2, MIN_THICKNESS,
417 self._getParamUserName("EP2"))
418 self._checkSize(self.R1 - self.EP1,
419 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
420 "%s - %s" % (self._getParamUserName("R1"),
421 self._getParamUserName("EP1")))
422 self._checkSize(self.R2 - self.EP2,
423 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
424 "%s - %s" % (self._getParamUserName("R2"),
425 self._getParamUserName("EP2")))
427 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
429 Create the circular sections used to build the pipe.
431 outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
432 outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
433 if self.filling == HOLLOW:
434 innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
436 innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
442 return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
445 class RectangularBeam(Beam):
447 This class defines a beam with a rectangular section. It can be full or
448 hollow, and its dimensions can vary from one end of the beam to the other.
449 The valid parameters for rectangular beams are:
451 * "HY1", "HY", "H1" or "H": width at the first end of the beam.
452 * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
453 * "HY2", "HY", "H2" or "H": width at the other end of the beam.
454 * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
455 * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
456 direction at the first end of the beam. If not specified or equal to 0,
457 the beam is considered full.
458 * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
459 direction at the first end of the beam. If not specified or equal to 0,
460 the beam is considered full.
461 * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
462 direction at the other end of the beam. If not specified or equal to 0,
463 the beam is considered full.
464 * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
465 direction at the other end of the beam. If not specified or equal to 0,
466 the beam is considered full.
468 See class :class:`StructuralElementPart` for the description of the
473 def __init__(self, studyId, groupName, groupGeomObj, parameters,
474 name = Beam.DEFAULT_NAME, color = None):
476 if parameters.has_key("HY1") or parameters.has_key("H1"):
477 color = LIGHT_BLUE # variable section
478 else: # constant section
481 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
484 self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
485 self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
486 self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
487 self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
488 self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
489 self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
490 self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
491 self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
493 if self.EPY1 is None or self.EPZ1 is None or \
494 self.EPY2 is None or self.EPZ2 is None or \
495 self.EPY1 == 0 or self.EPZ1 == 0 or \
496 self.EPY2 == 0 or self.EPZ2 == 0:
499 self.filling = HOLLOW
501 logger.debug(repr(self))
504 self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
505 self._getParamUserName("HY1"))
506 self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
507 self._getParamUserName("HZ1"))
508 self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
509 self._getParamUserName("HY2"))
510 self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
511 self._getParamUserName("HZ2"))
512 if self.filling == HOLLOW:
513 self._checkSize(self.EPY1, MIN_THICKNESS,
514 self._getParamUserName("EPY1"))
515 self._checkSize(self.EPZ1, MIN_THICKNESS,
516 self._getParamUserName("EPZ1"))
517 self._checkSize(self.EPY2, MIN_THICKNESS,
518 self._getParamUserName("EPY2"))
519 self._checkSize(self.EPZ2, MIN_THICKNESS,
520 self._getParamUserName("EPZ2"))
521 self._checkSize(self.HY1 - 2 * self.EPY1,
522 MIN_DIM_FOR_EXTRUDED_SHAPE,
523 "%s - 2 * %s" % (self._getParamUserName("HY1"),
524 self._getParamUserName("EPY1")))
525 self._checkSize(self.HZ1 - 2 * self.EPZ1,
526 MIN_DIM_FOR_EXTRUDED_SHAPE,
527 "%s - 2 * %s" % (self._getParamUserName("HZ1"),
528 self._getParamUserName("EPZ1")))
529 self._checkSize(self.HY2 - 2 * self.EPY2,
530 MIN_DIM_FOR_EXTRUDED_SHAPE,
531 "%s - 2 * %s" % (self._getParamUserName("HY2"),
532 self._getParamUserName("EPY2")))
533 self._checkSize(self.HZ2 - 2 * self.EPZ2,
534 MIN_DIM_FOR_EXTRUDED_SHAPE,
535 "%s - 2 * %s" % (self._getParamUserName("HZ2"),
536 self._getParamUserName("EPZ2")))
538 def _makeRectangle(self, HY, HZ, lcs):
540 Create a rectangle in the specified plane.
544 sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
545 sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
546 sketchStr += "TT %g %g:" % (halfHY, halfHZ)
547 sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
548 logger.debug('Drawing rectangle: "%s"' % sketchStr)
549 sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
552 def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
554 Create one side of the rectangular sections used to build the pipe.
556 (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
557 lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
558 outerRect = self._makeRectangle(HY, HZ, lcs)
559 if self.filling == HOLLOW:
560 innerRect = self._makeRectangle(HY - 2.0 * EPY,
565 return (outerRect, innerRect)
567 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
569 Create the rectangular sections used to build the pipe.
571 (outerRect1, innerRect1) = \
572 self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
573 self.EPY1, self.EPZ1)
574 (outerRect2, innerRect2) = \
575 self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
576 self.EPY2, self.EPZ2)
577 return (outerRect1, innerRect1, outerRect2, innerRect2)
580 def getParameterInDict(nameList, parametersDict, default = None):
582 This method finds the value of a parameter in the parameters
583 dictionary. The argument is a list because some parameters can have
584 several different names.
586 for name in nameList:
587 if parametersDict.has_key(name):
588 return parametersDict[name]
592 class GeneralBeam(RectangularBeam):
594 This class defines a beam with a generic section. It is represented as a
595 full rectangular beam with the following parameters:
597 * HY1 = sqrt(12 * IZ1 / A1)
598 * HZ1 = sqrt(12 * IY1 / A1)
599 * HY2 = sqrt(12 * IZ2 / A2)
600 * HZ2 = sqrt(12 * IY2 / A2)
602 See class :class:`StructuralElementPart` for the description of the other
606 def __init__(self, studyId, groupName, groupGeomObj, parameters,
607 name = Beam.DEFAULT_NAME, color = None):
608 self.IY1 = getParameterInDict(["IY1", "IY"], parameters)
609 self.IZ1 = getParameterInDict(["IZ1", "IZ"], parameters)
610 self.IY2 = getParameterInDict(["IY2", "IY"], parameters)
611 self.IZ2 = getParameterInDict(["IZ2", "IZ"], parameters)
612 self.A1 = getParameterInDict(["A1", "A"], parameters)
613 self.A2 = getParameterInDict(["A2", "A"], parameters)
614 parameters["HY1"] = math.sqrt(12 * self.IZ1 / self.A1)
615 parameters["HZ1"] = math.sqrt(12 * self.IY1 / self.A1)
616 parameters["HY2"] = math.sqrt(12 * self.IZ2 / self.A2)
617 parameters["HZ2"] = math.sqrt(12 * self.IY2 / self.A2)
620 if parameters.has_key("IY1"): # variable section
622 else: # constant section
625 RectangularBeam.__init__(self, studyId, groupName, groupGeomObj, parameters,
629 class StructuralElementPart2D(StructuralElementPart):
631 This class is an "abstract" class for all 2D structural element parts. It
632 should not be instantiated directly. See class
633 :class:`StructuralElementPart` for the description of the parameters.
636 DEFAULT_NAME = "StructuralElementPart2D"
638 def __init__(self, studyId, groupName, groupGeomObj, parameters,
639 name = DEFAULT_NAME):
640 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
642 self._orientation = orientation.Orientation2D(
643 self._getParameter(["angleAlpha"]),
644 self._getParameter(["angleBeta"]),
645 self._getParameter(["Vecteur"]))
646 self.offset = self._getParameter(["Excentre"], 0.0)
648 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
650 Create a copy of a face at a given offset.
652 if abs(offset) < epsilon:
653 return self.geom.MakeCopy(face)
655 offsetObj = self.geom.MakeOffset(face, offset)
656 # We have to explode the resulting object into faces because it is
657 # created as a polyhedron and not as a single face
658 faces = self.geom.SubShapeAll(offsetObj,
659 self.geom.ShapeType["FACE"])
662 def _buildMarkersWithOffset(self, offset):
664 Build the markers for the structural element part with a given offset
670 subShapes = self._getSubShapes()
672 for subShape in subShapes:
673 faces = self.geom.SubShapeAll(subShape,
674 self.geom.ShapeType["FACE"])
676 offsetFace = self._makeFaceOffset(face, offset)
677 # get tangent plane on surface by parameters
678 center = self.geom.MakeVertexOnSurface(offsetFace,
680 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
683 normal = self.geom.GetNormal(tangPlane)
684 marker = self._orientation.buildMarker(self.geom,
686 listMarkers.append(marker)
691 class ThickShell(StructuralElementPart2D):
693 This class defines a shell with a given thickness. It can be shifted from
694 the base face. The valid parameters for thick shells are:
696 * "Epais": thickness of the shell.
697 * "Excentre": offset of the shell from the base face.
698 * "angleAlpha": angle used to build the markers (see class
699 :class:`~salome.geom.structelem.orientation.Orientation2D`)
700 * "angleBeta": angle used to build the markers (see class
701 :class:`~salome.geom.structelem.orientation.Orientation2D`)
702 * "Vecteur": vector used instead of the angles to build the markers (see
703 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
705 See class :class:`StructuralElementPart` for the description of the
709 DEFAULT_NAME = "ThickShell"
711 def __init__(self, studyId, groupName, groupGeomObj, parameters,
712 name = DEFAULT_NAME):
713 StructuralElementPart2D.__init__(self, studyId, groupName,
714 groupGeomObj, parameters, name)
715 self.thickness = self._getParameter(["Epais"])
716 logger.debug(repr(self))
718 def _buildPart(self):
720 Create the geometrical shapes corresponding to the thick shell.
722 subShapes = self._getSubShapes()
725 for subShape in subShapes:
726 faces = self.geom.SubShapeAll(subShape,
727 self.geom.ShapeType["FACE"])
729 shape = self._buildThickShellForFace(face)
730 listSolids.append(shape)
732 if len(listSolids) == 0:
734 elif len(listSolids) == 1:
737 return self.geom.MakeCompound(listSolids)
739 def _buildThickShellForFace(self, face):
741 Create the geometrical shapes corresponding to the thick shell for a
745 if self.thickness < 2 * epsilon:
746 return self._makeFaceOffset(face, self.offset, epsilon)
748 upperOffset = self.offset + self.thickness / 2.0
749 lowerOffset = self.offset - self.thickness / 2.0
753 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
754 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
755 listShapes = [upperFace, lowerFace]
756 upperWires = self.geom.SubShapeAll(upperFace,
757 self.geom.ShapeType["WIRE"])
758 lowerWires = self.geom.SubShapeAll(lowerFace,
759 self.geom.ShapeType["WIRE"])
760 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
761 # if the face is a cylinder, we remove the extra side edge
762 upperWires = self._removeCylinderExtraEdge(upperWires)
763 lowerWires = self._removeCylinderExtraEdge(lowerWires)
764 for i in range(len(upperWires)):
765 resShape = self.geom.MakeThruSections([upperWires[i],
769 listShapes.append(resShape)
770 resultShell = self.geom.MakeShell(listShapes)
771 resultSolid = self.geom.MakeSolid([resultShell])
774 def _removeCylinderExtraEdge(self, wires):
776 Remove the side edge in a cylinder.
780 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
782 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
786 def _buildMarkers(self):
788 Build the markers defining the orientation of the thick shell.
790 return self._buildMarkersWithOffset(self.offset +
791 self.thickness / 2.0)
794 class Grid(StructuralElementPart2D):
796 This class defines a grid. A grid is represented by a 2D face patterned
797 with small lines in the main direction of the grid frame. The valid
798 parameters for grids are:
800 * "Excentre": offset of the grid from the base face.
801 * "angleAlpha": angle used to build the markers (see class
802 :class:`~salome.geom.structelem.orientation.Orientation2D`)
803 * "angleBeta": angle used to build the markers (see class
804 :class:`~salome.geom.structelem.orientation.Orientation2D`)
805 * "Vecteur": vector used instead of the angles to build the markers (see
806 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
807 * "origAxeX": X coordinate of the origin of the axis used to determine the
808 orientation of the frame in the case of a cylindrical grid.
809 * "origAxeY": Y coordinate of the origin of the axis used to determine the
810 orientation of the frame in the case of a cylindrical grid.
811 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
812 orientation of the frame in the case of a cylindrical grid.
813 * "axeX": X coordinate of the axis used to determine the orientation of
814 the frame in the case of a cylindrical grid.
815 * "axeY": Y coordinate of the axis used to determine the orientation of
816 the frame in the case of a cylindrical grid.
817 * "axeZ": Z coordinate of the axis used to determine the orientation of
818 the frame in the case of a cylindrical grid.
820 See class :class:`StructuralElementPart` for the description of the
824 DEFAULT_NAME = "Grid"
826 def __init__(self, studyId, groupName, groupGeomObj, parameters,
827 name = DEFAULT_NAME):
828 StructuralElementPart2D.__init__(self, studyId, groupName,
829 groupGeomObj, parameters, name)
830 self.xr = self._getParameter(["origAxeX"])
831 self.yr = self._getParameter(["origAxeY"])
832 self.zr = self._getParameter(["origAxeZ"])
833 self.vx = self._getParameter(["axeX"])
834 self.vy = self._getParameter(["axeY"])
835 self.vz = self._getParameter(["axeZ"])
836 logger.debug(repr(self))
838 def _buildPart(self):
840 Create the geometrical shapes representing the grid.
842 subShapes = self._getSubShapes()
845 for subShape in subShapes:
846 faces = self.geom.SubShapeAll(subShape,
847 self.geom.ShapeType["FACE"])
849 if self.geom.KindOfShape(face)[0] == \
850 self.geom.kind.CYLINDER2D and \
851 self.xr is not None and self.yr is not None and \
852 self.zr is not None and self.vx is not None and \
853 self.vy is not None and self.vz is not None:
854 shape = self._buildGridForCylinderFace(face)
856 shape = self._buildGridForNormalFace(face)
857 listGridShapes.append(shape)
859 if len(listGridShapes) == 0:
861 elif len(listGridShapes) == 1:
862 return listGridShapes[0]
864 return self.geom.MakeCompound(listGridShapes)
866 def _buildGridForNormalFace(self, face):
868 Create the geometrical shapes representing the grid for a given
869 non-cylindrical face.
871 baseFace = self._makeFaceOffset(face, self.offset)
872 gridList = [baseFace]
874 # Compute display length for grid elements
875 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
876 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
877 length = self.geom.MinDistance(p1, p2) / 2.0
879 for u in range(1, 10):
881 for v in range(1, 10):
883 # get tangent plane on surface by parameters
884 center = self.geom.MakeVertexOnSurface(baseFace,
886 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
889 # use the marker to get the orientation of the frame
890 normal = self.geom.GetNormal(tangPlane)
891 marker = self._orientation.buildMarker(self.geom, center,
893 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
894 xPoint = self.geom.MakeTranslation(center, Xx * length,
895 Xy * length, Xz * length)
896 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
897 gridList.append(gridLine)
898 grid = self.geom.MakeCompound(gridList)
901 def _buildGridForCylinderFace(self, face):
903 Create the geometrical shapes representing the grid for a given
906 baseFace = self._makeFaceOffset(face, self.offset)
907 gridList = [baseFace]
909 # Compute display length for grid elements
910 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
911 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
912 length = self.geom.MinDistance(p1, p2) / 2.0
914 # Create reference vector V
915 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
916 vPoint = self.geom.MakeTranslation(origPoint,
917 self.vx, self.vy, self.vz)
918 refVec = self.geom.MakeVector(origPoint, vPoint)
922 for v in range(1, 10):
925 # Compute the local orientation of the frame
926 center = self.geom.MakeVertexOnSurface(baseFace,
928 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
930 locOrient = self.geom.GetNormal(locPlaneYZ)
931 xPoint = self.geom.MakeTranslationVectorDistance(center,
934 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
935 gridList.append(gridLine)
937 grid = self.geom.MakeCompound(gridList)
940 def _buildMarkers(self):
942 Create the markers defining the orientation of the grid.
944 return self._buildMarkersWithOffset(self.offset)
947 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
950 Alias for class :class:`GeneralBeam`.
952 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
954 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
957 Alias for class :class:`CircularBeam`.
959 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
961 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
964 Alias for class :class:`RectangularBeam`.
966 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
968 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
971 Alias for class :class:`GeneralBeam`.
973 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
976 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
979 Alias for class :class:`RectangularBeam`.
981 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
984 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
987 Alias for class :class:`CircularBeam`.
989 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
992 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
994 Alias for class :class:`CircularBeam`.
996 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
999 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
1001 Alias for class :class:`ThickShell`.
1003 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
1005 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
1007 Alias for class :class:`Grid`.
1009 return Grid(studyId, groupName, groupGeomObj, parameters, name)