1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2013 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 self.isMainShape = (groupGeomObj.GetType() != 37) # See geompyDC.ShapeIdToType for type codes
141 if not self.isMainShape:
142 mainShape = self.geom.GetMainShape(groupGeomObj)
143 listIDs = self.geom.GetObjectIDs(groupGeomObj)
144 if mainShape is not None and listIDs is not None:
146 self.baseShapesSet.add(SubShapeID(mainShape, id))
148 if self.color is None:
149 self.color = self._groupGeomObj.GetColor()
151 def _getParameter(self, nameList, default = None):
153 This method finds the value of a parameter in the parameters
154 dictionary. The argument is a list because some parameters can have
155 several different names.
157 if len(nameList) > 0:
158 paramName = nameList[0]
159 for name in nameList:
160 if self._parameters.has_key(name):
161 self._paramUserName[paramName] = name
162 return self._parameters[name]
165 def _getParamUserName(self, paramName):
167 This method finds the user name for a parameter.
169 if self._paramUserName.has_key(paramName):
170 return self._paramUserName[paramName]
175 reprdict = self.__dict__.copy()
176 del reprdict["_parameters"]
177 del reprdict["groupName"]
178 del reprdict["_groupGeomObj"]
179 del reprdict["_paramUserName"]
182 del reprdict["baseShapesSet"]
183 return '%s("%s", %s)' % (self.__class__.__name__, self.groupName,
186 def addOrientation(self, orientParams):
188 Add orientation information to the structural element part. See class
189 :class:`~salome.geom.structelem.orientation.Orientation1D` for the description
192 self._orientation.addParams(orientParams)
194 def _checkSize(self, value, mindim, expression):
196 This method checks that some parameters or some expressions involving
197 those parameters are greater than a minimum value.
200 raise InvalidParameterError(self.groupName, expression,
205 Build the geometric shapes and the markers corresponding to the
206 structural element part in the study `studyId`.
208 shape = self._buildPart()
209 markers = self._buildMarkers()
210 shape.SetColor(self.color)
211 for marker in markers:
212 marker.SetColor(self.color)
213 return (shape, markers)
215 def _buildPart(self):
217 This abstract method must be implemented in subclasses and should
218 create the geometrical shape(s) of the structural element part.
220 raise NotImplementedError("Method _buildPart not implemented in class"
221 " %s (it must be implemented in "
222 "StructuralElementPart subclasses)." %
223 self.__class__.__name__)
225 def _buildMarkers(self):
227 This abstract method must be implemented in subclasses and should
228 create the markers defining the orientation of the structural element
231 raise NotImplementedError("Method _buildMarker not implemented in "
232 "class %s (it must be implemented in "
233 "StructuralElementPart subclasses)." %
234 self.__class__.__name__)
236 def _getSubShapes(self, minDim = MIN_LENGTH_FOR_EXTRUSION):
238 Find and return the base sub-shapes in the structural element part.
241 return [self._groupGeomObj]
243 for subShapeID in self.baseShapesSet:
244 subShape = subShapeID.getObj(self.geom)
245 length = self.geom.BasicProperties(subShape)[0]
247 logger.warning("Length too short (%s - ID %s, length = %g), "
248 "subshape will not be used in structural "
249 "element" % (self.groupName, subShapeID._id,
252 subShapes.append(subShape)
256 class Beam(StructuralElementPart):
258 This class is an "abstract" class for all 1D structural element parts. It
259 should not be instantiated directly. See class
260 :class:`StructuralElementPart` for the description of the parameters.
263 DEFAULT_NAME = "Beam"
265 def __init__(self, studyId, groupName, groupGeomObj, parameters,
266 name = DEFAULT_NAME, color = None):
267 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
268 parameters, name, color)
269 self._orientation = orientation.Orientation1D()
271 def _isReversed(self, path):
273 This method checks if a 1D object is "reversed", i.e. if its
274 orientation is different than the orientation of the underlying OCC
277 length = self.geom.BasicProperties(path)[0]
278 p1 = self.geom.MakeVertexOnCurve(path, 0.0)
279 p2 = self.geom.GetFirstVertex(path)
280 dist = self.geom.MinDistance(p1, p2)
281 return dist > length / 2
283 def _getVertexAndTangentOnOrientedWire(self, path, param):
285 Get a vertex and the corresponding tangent on a wire by parameter.
286 This method takes into account the "real" orientation of the wire
287 (i.e. the orientation of the underlying OCC object).
289 if self._isReversed(path):
290 vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
291 invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
292 tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
295 tangent = self.geom.MakeVector(vertex, tanpoint)
297 vertex = self.geom.MakeVertexOnCurve(path, param)
298 tangent = self.geom.MakeTangentOnCurve(path, param)
299 return (vertex, tangent)
301 def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
303 Create a solid by the extrusion of section `wire1` to section `wire2`
306 face1 = self.geom.MakeFace(wire1, True)
307 face2 = self.geom.MakeFace(wire2, True)
308 shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
311 closedShell = self.geom.MakeShell([face1, face2, shell])
312 solid = self.geom.MakeSolid([closedShell])
315 def _buildPart(self):
317 Build the structural element part.
319 # Get all the sub-shapes in the group (normally only edges and wires)
320 paths = self._getSubShapes()
323 withCorrection = False
326 # Build the sections (rectangular or circular) at each end of the
328 (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
330 (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
332 (outerWire1, innerWire1, outerWire2, innerWire2) = \
333 self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
335 # Create the resulting solid
336 outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
337 fPoint, lPoint, path)
338 if self.filling == HOLLOW:
339 innerSolid = self._makeSolidPipeFromWires(innerWire1,
342 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
343 listPipes.append(resultSolid)
345 listPipes.append(outerSolid)
347 if len(listPipes) == 0:
349 elif len(listPipes) == 1:
352 return self.geom.MakeCompound(listPipes)
354 def _buildMarkers(self):
356 Build the markers defining the orientation of the structural element
360 paths = self._getSubShapes()
363 (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
365 marker = self._orientation.buildMarker(self.geom, center, vecX)
366 listMarkers.append(marker)
370 class CircularBeam(Beam):
372 This class defines a beam with a circular section. It can be full or
373 hollow, and its radius and thickness can vary from one end of the beam to
374 the other. The valid parameters for circular beams are:
376 * "R1" or "R": radius at the first end of the beam.
377 * "R2" or "R": radius at the other end of the beam.
378 * "EP1" or "EP" (optional): thickness at the first end of the beam.
379 If not specified or equal to 0, the beam is considered full.
380 * "EP2" or "EP" (optional): thickness at the other end of the beam.
381 If not specified or equal to 0, the beam is considered full.
383 See class :class:`StructuralElementPart` for the description of the
388 def __init__(self, studyId, groupName, groupGeomObj, parameters,
389 name = Beam.DEFAULT_NAME, color = None):
391 if parameters.has_key("R1"): # variable section
393 else: # constant section
396 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
399 self.R1 = self._getParameter(["R1", "R"])
400 self.R2 = self._getParameter(["R2", "R"])
401 self.EP1 = self._getParameter(["EP1", "EP"])
402 self.EP2 = self._getParameter(["EP2", "EP"])
404 if self.EP1 is None or self.EP2 is None or \
405 self.EP1 == 0 or self.EP2 == 0:
408 self.filling = HOLLOW
410 logger.debug(repr(self))
413 self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
414 self._getParamUserName("R1"))
415 self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
416 self._getParamUserName("R2"))
417 if self.filling == HOLLOW:
418 self._checkSize(self.EP1, MIN_THICKNESS,
419 self._getParamUserName("EP1"))
420 self._checkSize(self.EP2, MIN_THICKNESS,
421 self._getParamUserName("EP2"))
422 self._checkSize(self.R1 - self.EP1,
423 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
424 "%s - %s" % (self._getParamUserName("R1"),
425 self._getParamUserName("EP1")))
426 self._checkSize(self.R2 - self.EP2,
427 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
428 "%s - %s" % (self._getParamUserName("R2"),
429 self._getParamUserName("EP2")))
431 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
433 Create the circular sections used to build the pipe.
435 outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
436 outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
437 if self.filling == HOLLOW:
438 innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
440 innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
446 return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
449 class RectangularBeam(Beam):
451 This class defines a beam with a rectangular section. It can be full or
452 hollow, and its dimensions can vary from one end of the beam to the other.
453 The valid parameters for rectangular beams are:
455 * "HY1", "HY", "H1" or "H": width at the first end of the beam.
456 * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
457 * "HY2", "HY", "H2" or "H": width at the other end of the beam.
458 * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
459 * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
460 direction at the first end of the beam. If not specified or equal to 0,
461 the beam is considered full.
462 * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
463 direction at the first end of the beam. If not specified or equal to 0,
464 the beam is considered full.
465 * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
466 direction at the other end of the beam. If not specified or equal to 0,
467 the beam is considered full.
468 * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
469 direction at the other end of the beam. If not specified or equal to 0,
470 the beam is considered full.
472 See class :class:`StructuralElementPart` for the description of the
477 def __init__(self, studyId, groupName, groupGeomObj, parameters,
478 name = Beam.DEFAULT_NAME, color = None):
480 if parameters.has_key("HY1") or parameters.has_key("H1"):
481 color = LIGHT_BLUE # variable section
482 else: # constant section
485 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
488 self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
489 self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
490 self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
491 self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
492 self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
493 self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
494 self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
495 self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
497 if self.EPY1 is None or self.EPZ1 is None or \
498 self.EPY2 is None or self.EPZ2 is None or \
499 self.EPY1 == 0 or self.EPZ1 == 0 or \
500 self.EPY2 == 0 or self.EPZ2 == 0:
503 self.filling = HOLLOW
505 logger.debug(repr(self))
508 self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
509 self._getParamUserName("HY1"))
510 self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
511 self._getParamUserName("HZ1"))
512 self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
513 self._getParamUserName("HY2"))
514 self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
515 self._getParamUserName("HZ2"))
516 if self.filling == HOLLOW:
517 self._checkSize(self.EPY1, MIN_THICKNESS,
518 self._getParamUserName("EPY1"))
519 self._checkSize(self.EPZ1, MIN_THICKNESS,
520 self._getParamUserName("EPZ1"))
521 self._checkSize(self.EPY2, MIN_THICKNESS,
522 self._getParamUserName("EPY2"))
523 self._checkSize(self.EPZ2, MIN_THICKNESS,
524 self._getParamUserName("EPZ2"))
525 self._checkSize(self.HY1 - 2 * self.EPY1,
526 MIN_DIM_FOR_EXTRUDED_SHAPE,
527 "%s - 2 * %s" % (self._getParamUserName("HY1"),
528 self._getParamUserName("EPY1")))
529 self._checkSize(self.HZ1 - 2 * self.EPZ1,
530 MIN_DIM_FOR_EXTRUDED_SHAPE,
531 "%s - 2 * %s" % (self._getParamUserName("HZ1"),
532 self._getParamUserName("EPZ1")))
533 self._checkSize(self.HY2 - 2 * self.EPY2,
534 MIN_DIM_FOR_EXTRUDED_SHAPE,
535 "%s - 2 * %s" % (self._getParamUserName("HY2"),
536 self._getParamUserName("EPY2")))
537 self._checkSize(self.HZ2 - 2 * self.EPZ2,
538 MIN_DIM_FOR_EXTRUDED_SHAPE,
539 "%s - 2 * %s" % (self._getParamUserName("HZ2"),
540 self._getParamUserName("EPZ2")))
542 def _makeRectangle(self, HY, HZ, lcs):
544 Create a rectangle in the specified plane.
548 sketchStr = "Sketcher:F %g %g:" % (-halfHY, -halfHZ)
549 sketchStr += "TT %g %g:" % (halfHY, -halfHZ)
550 sketchStr += "TT %g %g:" % (halfHY, halfHZ)
551 sketchStr += "TT %g %g:WW" % (-halfHY, halfHZ)
552 logger.debug('Drawing rectangle: "%s"' % sketchStr)
553 sketch = self.geom.MakeSketcherOnPlane(sketchStr, lcs)
556 def _makeSectionRectangles(self, point, vecX, HY, HZ, EPY, EPZ):
558 Create one side of the rectangular sections used to build the pipe.
560 (vecY, vecZ) = self._orientation.getVecYZ(self.geom, point, vecX)
561 lcs = self.geom.MakeMarkerPntTwoVec(point, vecY, vecZ)
562 outerRect = self._makeRectangle(HY, HZ, lcs)
563 if self.filling == HOLLOW:
564 innerRect = self._makeRectangle(HY - 2.0 * EPY,
569 return (outerRect, innerRect)
571 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
573 Create the rectangular sections used to build the pipe.
575 (outerRect1, innerRect1) = \
576 self._makeSectionRectangles(fPoint, fNormal, self.HY1, self.HZ1,
577 self.EPY1, self.EPZ1)
578 (outerRect2, innerRect2) = \
579 self._makeSectionRectangles(lPoint, lNormal, self.HY2, self.HZ2,
580 self.EPY2, self.EPZ2)
581 return (outerRect1, innerRect1, outerRect2, innerRect2)
584 def getParameterInDict(nameList, parametersDict, default = None):
586 This method finds the value of a parameter in the parameters
587 dictionary. The argument is a list because some parameters can have
588 several different names.
590 for name in nameList:
591 if parametersDict.has_key(name):
592 return parametersDict[name]
596 class GeneralBeam(RectangularBeam):
598 This class defines a beam with a generic section. It is represented as a
599 full rectangular beam with the following parameters:
601 * HY1 = sqrt(12 * IZ1 / A1)
602 * HZ1 = sqrt(12 * IY1 / A1)
603 * HY2 = sqrt(12 * IZ2 / A2)
604 * HZ2 = sqrt(12 * IY2 / A2)
606 See class :class:`StructuralElementPart` for the description of the other
610 def __init__(self, studyId, groupName, groupGeomObj, parameters,
611 name = Beam.DEFAULT_NAME, color = None):
612 self.IY1 = getParameterInDict(["IY1", "IY"], parameters)
613 self.IZ1 = getParameterInDict(["IZ1", "IZ"], parameters)
614 self.IY2 = getParameterInDict(["IY2", "IY"], parameters)
615 self.IZ2 = getParameterInDict(["IZ2", "IZ"], parameters)
616 self.A1 = getParameterInDict(["A1", "A"], parameters)
617 self.A2 = getParameterInDict(["A2", "A"], parameters)
618 parameters["HY1"] = math.sqrt(12 * self.IZ1 / self.A1)
619 parameters["HZ1"] = math.sqrt(12 * self.IY1 / self.A1)
620 parameters["HY2"] = math.sqrt(12 * self.IZ2 / self.A2)
621 parameters["HZ2"] = math.sqrt(12 * self.IY2 / self.A2)
624 if parameters.has_key("IY1"): # variable section
626 else: # constant section
629 RectangularBeam.__init__(self, studyId, groupName, groupGeomObj, parameters,
633 class StructuralElementPart2D(StructuralElementPart):
635 This class is an "abstract" class for all 2D structural element parts. It
636 should not be instantiated directly. See class
637 :class:`StructuralElementPart` for the description of the parameters.
640 DEFAULT_NAME = "StructuralElementPart2D"
642 def __init__(self, studyId, groupName, groupGeomObj, parameters,
643 name = DEFAULT_NAME):
644 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
646 self._orientation = orientation.Orientation2D(
647 self._getParameter(["angleAlpha"]),
648 self._getParameter(["angleBeta"]),
649 self._getParameter(["Vecteur"]))
650 self.offset = self._getParameter(["Excentre"], 0.0)
652 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
654 Create a copy of a face at a given offset.
656 if abs(offset) < epsilon:
657 return self.geom.MakeCopy(face)
659 offsetObj = self.geom.MakeOffset(face, offset)
660 # We have to explode the resulting object into faces because it is
661 # created as a polyhedron and not as a single face
662 faces = self.geom.SubShapeAll(offsetObj,
663 self.geom.ShapeType["FACE"])
666 def _buildMarkersWithOffset(self, offset):
668 Build the markers for the structural element part with a given offset
674 subShapes = self._getSubShapes()
676 for subShape in subShapes:
677 faces = self.geom.SubShapeAll(subShape,
678 self.geom.ShapeType["FACE"])
680 offsetFace = self._makeFaceOffset(face, offset)
681 # get tangent plane on surface by parameters
682 center = self.geom.MakeVertexOnSurface(offsetFace,
684 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
687 normal = self.geom.GetNormal(tangPlane)
688 marker = self._orientation.buildMarker(self.geom,
690 listMarkers.append(marker)
695 class ThickShell(StructuralElementPart2D):
697 This class defines a shell with a given thickness. It can be shifted from
698 the base face. The valid parameters for thick shells are:
700 * "Epais": thickness of the shell.
701 * "Excentre": offset of the shell from the base face.
702 * "angleAlpha": angle used to build the markers (see class
703 :class:`~salome.geom.structelem.orientation.Orientation2D`)
704 * "angleBeta": angle used to build the markers (see class
705 :class:`~salome.geom.structelem.orientation.Orientation2D`)
706 * "Vecteur": vector used instead of the angles to build the markers (see
707 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
709 See class :class:`StructuralElementPart` for the description of the
713 DEFAULT_NAME = "ThickShell"
715 def __init__(self, studyId, groupName, groupGeomObj, parameters,
716 name = DEFAULT_NAME):
717 StructuralElementPart2D.__init__(self, studyId, groupName,
718 groupGeomObj, parameters, name)
719 self.thickness = self._getParameter(["Epais"])
720 logger.debug(repr(self))
722 def _buildPart(self):
724 Create the geometrical shapes corresponding to the thick shell.
726 subShapes = self._getSubShapes()
729 for subShape in subShapes:
730 faces = self.geom.SubShapeAll(subShape,
731 self.geom.ShapeType["FACE"])
733 shape = self._buildThickShellForFace(face)
734 listSolids.append(shape)
736 if len(listSolids) == 0:
738 elif len(listSolids) == 1:
741 return self.geom.MakeCompound(listSolids)
743 def _buildThickShellForFace(self, face):
745 Create the geometrical shapes corresponding to the thick shell for a
749 if self.thickness < 2 * epsilon:
750 return self._makeFaceOffset(face, self.offset, epsilon)
752 upperOffset = self.offset + self.thickness / 2.0
753 lowerOffset = self.offset - self.thickness / 2.0
757 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
758 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
759 listShapes = [upperFace, lowerFace]
760 upperWires = self.geom.SubShapeAll(upperFace,
761 self.geom.ShapeType["WIRE"])
762 lowerWires = self.geom.SubShapeAll(lowerFace,
763 self.geom.ShapeType["WIRE"])
764 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
765 # if the face is a cylinder, we remove the extra side edge
766 upperWires = self._removeCylinderExtraEdge(upperWires)
767 lowerWires = self._removeCylinderExtraEdge(lowerWires)
768 for i in range(len(upperWires)):
769 resShape = self.geom.MakeThruSections([upperWires[i],
773 listShapes.append(resShape)
774 resultShell = self.geom.MakeShell(listShapes)
775 resultSolid = self.geom.MakeSolid([resultShell])
778 def _removeCylinderExtraEdge(self, wires):
780 Remove the side edge in a cylinder.
784 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
786 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
790 def _buildMarkers(self):
792 Build the markers defining the orientation of the thick shell.
794 return self._buildMarkersWithOffset(self.offset +
795 self.thickness / 2.0)
798 class Grid(StructuralElementPart2D):
800 This class defines a grid. A grid is represented by a 2D face patterned
801 with small lines in the main direction of the grid frame. The valid
802 parameters for grids are:
804 * "Excentre": offset of the grid from the base face.
805 * "angleAlpha": angle used to build the markers (see class
806 :class:`~salome.geom.structelem.orientation.Orientation2D`)
807 * "angleBeta": angle used to build the markers (see class
808 :class:`~salome.geom.structelem.orientation.Orientation2D`)
809 * "Vecteur": vector used instead of the angles to build the markers (see
810 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
811 * "origAxeX": X coordinate of the origin of the axis used to determine the
812 orientation of the frame in the case of a cylindrical grid.
813 * "origAxeY": Y coordinate of the origin of the axis used to determine the
814 orientation of the frame in the case of a cylindrical grid.
815 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
816 orientation of the frame in the case of a cylindrical grid.
817 * "axeX": X coordinate of the axis used to determine the orientation of
818 the frame in the case of a cylindrical grid.
819 * "axeY": Y coordinate of the axis used to determine the orientation of
820 the frame in the case of a cylindrical grid.
821 * "axeZ": Z coordinate of the axis used to determine the orientation of
822 the frame in the case of a cylindrical grid.
824 See class :class:`StructuralElementPart` for the description of the
828 DEFAULT_NAME = "Grid"
830 def __init__(self, studyId, groupName, groupGeomObj, parameters,
831 name = DEFAULT_NAME):
832 StructuralElementPart2D.__init__(self, studyId, groupName,
833 groupGeomObj, parameters, name)
834 self.xr = self._getParameter(["origAxeX"])
835 self.yr = self._getParameter(["origAxeY"])
836 self.zr = self._getParameter(["origAxeZ"])
837 self.vx = self._getParameter(["axeX"])
838 self.vy = self._getParameter(["axeY"])
839 self.vz = self._getParameter(["axeZ"])
840 logger.debug(repr(self))
842 def _buildPart(self):
844 Create the geometrical shapes representing the grid.
846 subShapes = self._getSubShapes()
849 for subShape in subShapes:
850 faces = self.geom.SubShapeAll(subShape,
851 self.geom.ShapeType["FACE"])
853 if self.geom.KindOfShape(face)[0] == \
854 self.geom.kind.CYLINDER2D and \
855 self.xr is not None and self.yr is not None and \
856 self.zr is not None and self.vx is not None and \
857 self.vy is not None and self.vz is not None:
858 shape = self._buildGridForCylinderFace(face)
860 shape = self._buildGridForNormalFace(face)
861 listGridShapes.append(shape)
863 if len(listGridShapes) == 0:
865 elif len(listGridShapes) == 1:
866 return listGridShapes[0]
868 return self.geom.MakeCompound(listGridShapes)
870 def _buildGridForNormalFace(self, face):
872 Create the geometrical shapes representing the grid for a given
873 non-cylindrical face.
875 baseFace = self._makeFaceOffset(face, self.offset)
876 gridList = [baseFace]
878 # Compute display length for grid elements
879 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
880 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
881 length = self.geom.MinDistance(p1, p2) / 2.0
883 for u in range(1, 10):
885 for v in range(1, 10):
887 # get tangent plane on surface by parameters
888 center = self.geom.MakeVertexOnSurface(baseFace,
890 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
893 # use the marker to get the orientation of the frame
894 normal = self.geom.GetNormal(tangPlane)
895 marker = self._orientation.buildMarker(self.geom, center,
897 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
898 xPoint = self.geom.MakeTranslation(center, Xx * length,
899 Xy * length, Xz * length)
900 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
901 gridList.append(gridLine)
902 grid = self.geom.MakeCompound(gridList)
905 def _buildGridForCylinderFace(self, face):
907 Create the geometrical shapes representing the grid for a given
910 baseFace = self._makeFaceOffset(face, self.offset)
911 gridList = [baseFace]
913 # Compute display length for grid elements
914 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
915 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
916 length = self.geom.MinDistance(p1, p2) / 2.0
918 # Create reference vector V
919 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
920 vPoint = self.geom.MakeTranslation(origPoint,
921 self.vx, self.vy, self.vz)
922 refVec = self.geom.MakeVector(origPoint, vPoint)
926 for v in range(1, 10):
929 # Compute the local orientation of the frame
930 center = self.geom.MakeVertexOnSurface(baseFace,
932 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
934 locOrient = self.geom.GetNormal(locPlaneYZ)
935 xPoint = self.geom.MakeTranslationVectorDistance(center,
938 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
939 gridList.append(gridLine)
941 grid = self.geom.MakeCompound(gridList)
944 def _buildMarkers(self):
946 Create the markers defining the orientation of the grid.
948 return self._buildMarkersWithOffset(self.offset)
951 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
954 Alias for class :class:`GeneralBeam`.
956 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
958 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
961 Alias for class :class:`CircularBeam`.
963 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
965 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
968 Alias for class :class:`RectangularBeam`.
970 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
972 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
975 Alias for class :class:`GeneralBeam`.
977 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name,
980 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
983 Alias for class :class:`RectangularBeam`.
985 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name,
988 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
991 Alias for class :class:`CircularBeam`.
993 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
996 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
998 Alias for class :class:`CircularBeam`.
1000 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name,
1003 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
1005 Alias for class :class:`ThickShell`.
1007 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
1009 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
1011 Alias for class :class:`Grid`.
1013 return Grid(studyId, groupName, groupGeomObj, parameters, name)