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
259 fPoint = self.geom.MakeVertexOnCurve(path, fParam)
260 lPoint = self.geom.MakeVertexOnCurve(path, lParam)
262 fNormal = self.geom.MakeTangentOnCurve(path, fParam)
263 lNormal = self.geom.MakeTangentOnCurve(path, lParam)
265 fCircle = self.geom.MakeCircle(fPoint, fNormal, 10)
266 lCircle = self.geom.MakeCircle(lPoint, lNormal, 10)
269 pipe = self.geom.MakePipeWithDifferentSections([fCircle, lCircle],
272 except RuntimeError, e:
273 # This dirty trick is needed if the wire is not oriented in the
274 # direction corresponding to parameters 0.0 -> 1.0. In this case,
275 # we catch the error and invert the ends of the wire. This trick
276 # will be removed when the function giving the orientation of an
277 # edge will be added in geompy (see issue 1144 in PAL bugtracker).
278 if (str(e) == "MakePipeWithDifferentSections : First location "
279 "shapes is not coincided with first vertex of "
286 def _getVertexAndTangentOnOrientedWire(self, path, param):
288 Get a vertex and the corresponding tangent on a wire by parameter.
289 This method takes into account the "real" orientation of the wire
290 (i.e. the orientation of the underlying OCC object).
292 if self._isReversed(path):
293 vertex = self.geom.MakeVertexOnCurve(path, 1.0 - param)
294 invtangent = self.geom.MakeTangentOnCurve(path, 1.0 - param)
295 tanpoint = self.geom.MakeTranslationVectorDistance(vertex,
298 tangent = self.geom.MakeVector(vertex, tanpoint)
300 vertex = self.geom.MakeVertexOnCurve(path, param)
301 tangent = self.geom.MakeTangentOnCurve(path, param)
302 return (vertex, tangent)
304 def _makeSolidPipeFromWires(self, wire1, wire2, point1, point2, path):
306 Create a solid by the extrusion of section `wire1` to section `wire2`
309 face1 = self.geom.MakeFace(wire1, True)
310 face2 = self.geom.MakeFace(wire2, True)
311 shell = self.geom.MakePipeWithDifferentSections([wire1, wire2],
314 closedShell = self.geom.MakeShell([face1, face2, shell])
315 solid = self.geom.MakeSolid([closedShell])
318 def _buildPart(self):
320 Build the structural element part.
322 # Get all the subshapes in the group (normally only edges and wires)
323 paths = self._getSubShapes()
326 withCorrection = False
329 # Build the sections (rectangular or circular) at each end of the
331 (fPoint, fNormal) = self._getVertexAndTangentOnOrientedWire(path,
333 (lPoint, lNormal) = self._getVertexAndTangentOnOrientedWire(path,
335 (outerWire1, innerWire1, outerWire2, innerWire2) = \
336 self._makeSectionWires(fPoint, fNormal, lPoint, lNormal)
338 # Create the resulting solid
339 outerSolid = self._makeSolidPipeFromWires(outerWire1, outerWire2,
340 fPoint, lPoint, path)
341 if self.filling == HOLLOW:
342 innerSolid = self._makeSolidPipeFromWires(innerWire1,
345 resultSolid = self.geom.MakeCut(outerSolid, innerSolid)
346 listPipes.append(resultSolid)
348 listPipes.append(outerSolid)
350 if len(listPipes) == 0:
352 elif len(listPipes) == 1:
355 return self.geom.MakeCompound(listPipes)
357 def _buildMarkers(self):
359 Build the markers defining the orientation of the structural element
363 paths = self._getSubShapes()
366 (center, vecX) = self._getVertexAndTangentOnOrientedWire(path,
368 marker = self._orientation.buildMarker(self.geom, center, vecX)
369 listMarkers.append(marker)
373 class GeneralBeam(Beam):
375 This class defines a beam with a generic section. It is represented only
376 as the underlying wire. See class :class:`StructuralElementPart` for the
377 description of the parameters.
380 def __init__(self, studyId, groupName, groupGeomObj, parameters,
381 name = Beam.DEFAULT_NAME):
382 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
384 logger.debug(repr(self))
386 def _buildPart(self):
388 Create a copy of the underlying wire.
390 edges = self._getSubShapes(1e-7)
393 wire = self.geom.MakeWire(edges)
397 class CircularBeam(Beam):
399 This class defines a beam with a circular section. It can be full or
400 hollow, and its radius and thickness can vary from one end of the beam to
401 the other. The valid parameters for circular beams are:
403 * "R1" or "R": radius at the first end of the beam.
404 * "R2" or "R": radius at the other end of the beam.
405 * "EP1" or "EP" (optional): thickness at the first end of the beam.
406 If not specified or equal to 0, the beam is considered full.
407 * "EP2" or "EP" (optional): thickness at the other end of the beam.
408 If not specified or equal to 0, the beam is considered full.
410 See class :class:`StructuralElementPart` for the description of the
415 def __init__(self, studyId, groupName, groupGeomObj, parameters,
416 name = Beam.DEFAULT_NAME):
417 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
420 self.R1 = self._getParameter(["R1", "R"])
421 self.R2 = self._getParameter(["R2", "R"])
422 self.EP1 = self._getParameter(["EP1", "EP"])
423 self.EP2 = self._getParameter(["EP2", "EP"])
425 if self.EP1 is None or self.EP2 is None or \
426 self.EP1 == 0 or self.EP2 == 0:
429 self.filling = HOLLOW
431 logger.debug(repr(self))
434 self._checkSize(self.R1, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
435 self._getParamUserName("R1"))
436 self._checkSize(self.R2, MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
437 self._getParamUserName("R2"))
438 if self.filling == HOLLOW:
439 self._checkSize(self.EP1, MIN_THICKNESS,
440 self._getParamUserName("EP1"))
441 self._checkSize(self.EP2, MIN_THICKNESS,
442 self._getParamUserName("EP2"))
443 self._checkSize(self.R1 - self.EP1,
444 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
445 "%s - %s" % (self._getParamUserName("R1"),
446 self._getParamUserName("EP1")))
447 self._checkSize(self.R2 - self.EP2,
448 MIN_DIM_FOR_EXTRUDED_SHAPE / 2.0,
449 "%s - %s" % (self._getParamUserName("R2"),
450 self._getParamUserName("EP2")))
452 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
454 Create the circular sections used to build the pipe.
456 outerCircle1 = self.geom.MakeCircle(fPoint, fNormal, self.R1)
457 outerCircle2 = self.geom.MakeCircle(lPoint, lNormal, self.R2)
458 if self.filling == HOLLOW:
459 innerCircle1 = self.geom.MakeCircle(fPoint, fNormal,
461 innerCircle2 = self.geom.MakeCircle(lPoint, lNormal,
467 return (outerCircle1, innerCircle1, outerCircle2, innerCircle2)
470 class RectangularBeam(Beam):
472 This class defines a beam with a rectangular section. It can be full or
473 hollow, and its dimensions can vary from one end of the beam to the other.
474 The valid parameters for rectangular beams are:
476 * "HY1", "HY", "H1" or "H": width at the first end of the beam.
477 * "HZ1", "HZ", "H1" or "H": height at the first end of the beam.
478 * "HY2", "HY", "H2" or "H": width at the other end of the beam.
479 * "HZ2", "HZ", "H2" or "H": height at the other end of the beam.
480 * "EPY1", "EPY", "EP1" or "EP" (optional): thickness in the width
481 direction at the first end of the beam. If not specified or equal to 0,
482 the beam is considered full.
483 * "EPZ1", "EPZ", "EP1" or "EP" (optional): thickness in the height
484 direction at the first end of the beam. If not specified or equal to 0,
485 the beam is considered full.
486 * "EPY2", "EPY", "EP2" or "EP" (optional): thickness in the width
487 direction at the other end of the beam. If not specified or equal to 0,
488 the beam is considered full.
489 * "EPZ2", "EPZ", "EP2" or "EP" (optional): thickness in the height
490 direction at the other end of the beam. If not specified or equal to 0,
491 the beam is considered full.
493 See class :class:`StructuralElementPart` for the description of the
498 def __init__(self, studyId, groupName, groupGeomObj, parameters,
499 name = Beam.DEFAULT_NAME):
500 Beam.__init__(self, studyId, groupName, groupGeomObj, parameters,
503 self.HY1 = self._getParameter(["HY1", "HY", "H1", "H"])
504 self.HZ1 = self._getParameter(["HZ1", "HZ", "H1", "H"])
505 self.HY2 = self._getParameter(["HY2", "HY", "H2", "H"])
506 self.HZ2 = self._getParameter(["HZ2", "HZ", "H2", "H"])
507 self.EPY1 = self._getParameter(["EPY1", "EPY", "EP1", "EP"])
508 self.EPZ1 = self._getParameter(["EPZ1", "EPZ", "EP1", "EP"])
509 self.EPY2 = self._getParameter(["EPY2", "EPY", "EP2", "EP"])
510 self.EPZ2 = self._getParameter(["EPZ2", "EPZ", "EP2", "EP"])
512 if self.EPY1 is None or self.EPZ1 is None or \
513 self.EPY2 is None or self.EPZ2 is None or \
514 self.EPY1 == 0 or self.EPZ1 == 0 or \
515 self.EPY2 == 0 or self.EPZ2 == 0:
518 self.filling = HOLLOW
520 logger.debug(repr(self))
523 self._checkSize(self.HY1, MIN_DIM_FOR_EXTRUDED_SHAPE,
524 self._getParamUserName("HY1"))
525 self._checkSize(self.HZ1, MIN_DIM_FOR_EXTRUDED_SHAPE,
526 self._getParamUserName("HZ1"))
527 self._checkSize(self.HY2, MIN_DIM_FOR_EXTRUDED_SHAPE,
528 self._getParamUserName("HY2"))
529 self._checkSize(self.HZ2, MIN_DIM_FOR_EXTRUDED_SHAPE,
530 self._getParamUserName("HZ2"))
531 if self.filling == HOLLOW:
532 self._checkSize(self.EPY1, MIN_THICKNESS,
533 self._getParamUserName("EPY1"))
534 self._checkSize(self.EPZ1, MIN_THICKNESS,
535 self._getParamUserName("EPZ1"))
536 self._checkSize(self.EPY2, MIN_THICKNESS,
537 self._getParamUserName("EPY2"))
538 self._checkSize(self.EPZ2, MIN_THICKNESS,
539 self._getParamUserName("EPZ2"))
540 self._checkSize(self.HY1 - 2 * self.EPY1,
541 MIN_DIM_FOR_EXTRUDED_SHAPE,
542 "%s - 2 * %s" % (self._getParamUserName("HY1"),
543 self._getParamUserName("EPY1")))
544 self._checkSize(self.HZ1 - 2 * self.EPZ1,
545 MIN_DIM_FOR_EXTRUDED_SHAPE,
546 "%s - 2 * %s" % (self._getParamUserName("HZ1"),
547 self._getParamUserName("EPZ1")))
548 self._checkSize(self.HY2 - 2 * self.EPY2,
549 MIN_DIM_FOR_EXTRUDED_SHAPE,
550 "%s - 2 * %s" % (self._getParamUserName("HY2"),
551 self._getParamUserName("EPY2")))
552 self._checkSize(self.HZ2 - 2 * self.EPZ2,
553 MIN_DIM_FOR_EXTRUDED_SHAPE,
554 "%s - 2 * %s" % (self._getParamUserName("HZ2"),
555 self._getParamUserName("EPZ2")))
557 def _makeRectangle(self, HY, HZ, planeSect):
559 Create a rectangle in the specified plane.
563 sketchStr = "Sketcher:F %g" % (-halfHZ) + " %g" % (-halfHY) + ":"
564 sketchStr += "TT %g" % (halfHZ) + " %g" % (-halfHY) + ":"
565 sketchStr += "TT %g" % (halfHZ) + " %g" % (halfHY) + ":"
566 sketchStr += "TT %g" % (-halfHZ) + " %g" % (halfHY) + ":WW"
567 logger.debug('Drawing rectangle: "%s"' % sketchStr)
568 sketch = self.geom.MakeSketcherOnPlane(sketchStr, planeSect)
571 def _makeSectionWires(self, fPoint, fNormal, lPoint, lNormal):
573 Create the rectangular sections used to build the pipe.
575 planeSect1 = self.geom.MakePlane(fPoint, fNormal, 1.0)
576 outerRect1 = self._makeRectangle(self.HY1, self.HZ1, planeSect1)
577 planeSect2 = self.geom.MakePlane(lPoint, lNormal, 1.0)
578 outerRect2 = self._makeRectangle(self.HY2, self.HZ2, planeSect2)
579 if self.filling == HOLLOW:
580 innerRect1 = self._makeRectangle(self.HY1 - 2 * self.EPY1,
581 self.HZ1 - 2 * self.EPZ1,
583 innerRect2 = self._makeRectangle(self.HY2 - 2 * self.EPY2,
584 self.HZ2 - 2 * self.EPZ2,
590 return (outerRect1, innerRect1, outerRect2, innerRect2)
593 class StructuralElementPart2D(StructuralElementPart):
595 This class is an "abstract" class for all 2D structural element parts. It
596 should not be instantiated directly. See class
597 :class:`StructuralElementPart` for the description of the parameters.
600 DEFAULT_NAME = "StructuralElementPart2D"
602 def __init__(self, studyId, groupName, groupGeomObj, parameters,
603 name = DEFAULT_NAME):
604 StructuralElementPart.__init__(self, studyId, groupName, groupGeomObj,
606 self._orientation = orientation.Orientation2D(
607 self._getParameter(["angleAlpha"]),
608 self._getParameter(["angleBeta"]),
609 self._getParameter(["Vecteur"]))
610 self.offset = self._getParameter(["Excentre"], 0.0)
612 def _makeFaceOffset(self, face, offset, epsilon = 1e-6):
614 Create a copy of a face at a given offset.
616 if abs(offset) < epsilon:
617 return self.geom.MakeCopy(face)
619 offsetObj = self.geom.MakeOffset(face, offset)
620 # We have to explode the resulting object into faces because it is
621 # created as a polyhedron and not as a single face
622 faces = self.geom.SubShapeAll(offsetObj,
623 self.geom.ShapeType["FACE"])
626 def _buildMarkersWithOffset(self, offset):
628 Build the markers for the structural element part with a given offset
634 subShapes = self._getSubShapes()
636 for subShape in subShapes:
637 faces = self.geom.SubShapeAll(subShape,
638 self.geom.ShapeType["FACE"])
640 offsetFace = self._makeFaceOffset(face, offset)
641 # get tangent plane on surface by parameters
642 center = self.geom.MakeVertexOnSurface(offsetFace,
644 tangPlane = self.geom.MakeTangentPlaneOnFace(offsetFace,
647 normal = self.geom.GetNormal(tangPlane)
648 marker = self._orientation.buildMarker(self.geom,
650 listMarkers.append(marker)
655 class ThickShell(StructuralElementPart2D):
657 This class defines a shell with a given thickness. It can be shifted from
658 the base face. The valid parameters for thick shells are:
660 * "Epais": thickness of the shell.
661 * "Excentre": offset of the shell from the base face.
662 * "angleAlpha": angle used to build the markers (see class
663 :class:`~salome.geom.structelem.orientation.Orientation2D`)
664 * "angleBeta": angle used to build the markers (see class
665 :class:`~salome.geom.structelem.orientation.Orientation2D`)
666 * "Vecteur": vector used instead of the angles to build the markers (see
667 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
669 See class :class:`StructuralElementPart` for the description of the
673 DEFAULT_NAME = "ThickShell"
675 def __init__(self, studyId, groupName, groupGeomObj, parameters,
676 name = DEFAULT_NAME):
677 StructuralElementPart2D.__init__(self, studyId, groupName,
678 groupGeomObj, parameters, name)
679 self.thickness = self._getParameter(["Epais"])
680 logger.debug(repr(self))
682 def _buildPart(self):
684 Create the geometrical shapes corresponding to the thick shell.
686 subShapes = self._getSubShapes()
689 for subShape in subShapes:
690 faces = self.geom.SubShapeAll(subShape,
691 self.geom.ShapeType["FACE"])
693 shape = self._buildThickShellForFace(face)
694 listSolids.append(shape)
696 if len(listSolids) == 0:
698 elif len(listSolids) == 1:
701 return self.geom.MakeCompound(listSolids)
703 def _buildThickShellForFace(self, face):
705 Create the geometrical shapes corresponding to the thick shell for a
709 if self.thickness < 2 * epsilon:
710 return self._makeFaceOffset(face, self.offset, epsilon)
712 upperOffset = self.offset + self.thickness / 2.0
713 lowerOffset = self.offset - self.thickness / 2.0
717 upperFace = self._makeFaceOffset(face, upperOffset, epsilon)
718 lowerFace = self._makeFaceOffset(face, lowerOffset, epsilon)
719 listShapes = [upperFace, lowerFace]
720 upperWires = self.geom.SubShapeAll(upperFace,
721 self.geom.ShapeType["WIRE"])
722 lowerWires = self.geom.SubShapeAll(lowerFace,
723 self.geom.ShapeType["WIRE"])
724 if self.geom.KindOfShape(face)[0] == self.geom.kind.CYLINDER2D:
725 # if the face is a cylinder, we remove the extra side edge
726 upperWires = self._removeCylinderExtraEdge(upperWires)
727 lowerWires = self._removeCylinderExtraEdge(lowerWires)
728 for i in range(len(upperWires)):
729 resShape = self.geom.MakeThruSections([upperWires[i],
733 listShapes.append(resShape)
734 resultShell = self.geom.MakeShell(listShapes)
735 resultSolid = self.geom.MakeSolid([resultShell])
738 def _removeCylinderExtraEdge(self, wires):
740 Remove the side edge in a cylinder.
744 edges = self.geom.SubShapeAll(wire, self.geom.ShapeType["EDGE"])
746 if self.geom.KindOfShape(edge)[0] == self.geom.kind.CIRCLE:
750 def _buildMarkers(self):
752 Build the markers defining the orientation of the thick shell.
754 return self._buildMarkersWithOffset(self.offset +
755 self.thickness / 2.0)
758 class Grid(StructuralElementPart2D):
760 This class defines a grid. A grid is represented by a 2D face patterned
761 with small lines in the main direction of the grid frame. The valid
762 parameters for grids are:
764 * "Excentre": offset of the grid from the base face.
765 * "angleAlpha": angle used to build the markers (see class
766 :class:`~salome.geom.structelem.orientation.Orientation2D`)
767 * "angleBeta": angle used to build the markers (see class
768 :class:`~salome.geom.structelem.orientation.Orientation2D`)
769 * "Vecteur": vector used instead of the angles to build the markers (see
770 class :class:`~salome.geom.structelem.orientation.Orientation2D`)
771 * "origAxeX": X coordinate of the origin of the axis used to determine the
772 orientation of the frame in the case of a cylindrical grid.
773 * "origAxeY": Y coordinate of the origin of the axis used to determine the
774 orientation of the frame in the case of a cylindrical grid.
775 * "origAxeZ": Z coordinate of the origin of the axis used to determine the
776 orientation of the frame in the case of a cylindrical grid.
777 * "axeX": X coordinate of the axis used to determine the orientation of
778 the frame in the case of a cylindrical grid.
779 * "axeY": Y coordinate of the axis used to determine the orientation of
780 the frame in the case of a cylindrical grid.
781 * "axeZ": Z coordinate of the axis used to determine the orientation of
782 the frame in the case of a cylindrical grid.
784 See class :class:`StructuralElementPart` for the description of the
788 DEFAULT_NAME = "Grid"
790 def __init__(self, studyId, groupName, groupGeomObj, parameters,
791 name = DEFAULT_NAME):
792 StructuralElementPart2D.__init__(self, studyId, groupName,
793 groupGeomObj, parameters, name)
794 self.xr = self._getParameter(["origAxeX"])
795 self.yr = self._getParameter(["origAxeY"])
796 self.zr = self._getParameter(["origAxeZ"])
797 self.vx = self._getParameter(["axeX"])
798 self.vy = self._getParameter(["axeY"])
799 self.vz = self._getParameter(["axeZ"])
800 logger.debug(repr(self))
802 def _buildPart(self):
804 Create the geometrical shapes representing the grid.
806 subShapes = self._getSubShapes()
809 for subShape in subShapes:
810 faces = self.geom.SubShapeAll(subShape,
811 self.geom.ShapeType["FACE"])
813 if self.geom.KindOfShape(face)[0] == \
814 self.geom.kind.CYLINDER2D and \
815 self.xr is not None and self.yr is not None and \
816 self.zr is not None and self.vx is not None and \
817 self.vy is not None and self.vz is not None:
818 shape = self._buildGridForCylinderFace(face)
820 shape = self._buildGridForNormalFace(face)
821 listGridShapes.append(shape)
823 if len(listGridShapes) == 0:
825 elif len(listGridShapes) == 1:
826 return listGridShapes[0]
828 return self.geom.MakeCompound(listGridShapes)
830 def _buildGridForNormalFace(self, face):
832 Create the geometrical shapes representing the grid for a given
833 non-cylindrical face.
835 baseFace = self._makeFaceOffset(face, self.offset)
836 gridList = [baseFace]
838 # Compute display length for grid elements
839 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
840 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
841 length = self.geom.MinDistance(p1, p2) / 2.0
843 for u in range(1, 10):
845 for v in range(1, 10):
847 # get tangent plane on surface by parameters
848 center = self.geom.MakeVertexOnSurface(baseFace,
850 tangPlane = self.geom.MakeTangentPlaneOnFace(baseFace, uParam,
853 # use the marker to get the orientation of the frame
854 normal = self.geom.GetNormal(tangPlane)
855 marker = self._orientation.buildMarker(self.geom, center,
857 [Ox,Oy,Oz, Zx,Zy,Zz, Xx,Xy,Xz] = self.geom.GetPosition(marker)
858 xPoint = self.geom.MakeTranslation(center, Xx * length,
859 Xy * length, Xz * length)
860 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
861 gridList.append(gridLine)
862 grid = self.geom.MakeCompound(gridList)
865 def _buildGridForCylinderFace(self, face):
867 Create the geometrical shapes representing the grid for a given
870 baseFace = self._makeFaceOffset(face, self.offset)
871 gridList = [baseFace]
873 # Compute display length for grid elements
874 p1 = self.geom.MakeVertexOnSurface(baseFace, 0.0, 0.0)
875 p2 = self.geom.MakeVertexOnSurface(baseFace, 0.1, 0.1)
876 length = self.geom.MinDistance(p1, p2) / 2.0
878 # Create reference vector V
879 origPoint = self.geom.MakeVertex(self.xr, self.yr, self.zr)
880 vPoint = self.geom.MakeTranslation(origPoint,
881 self.vx, self.vy, self.vz)
882 refVec = self.geom.MakeVector(origPoint, vPoint)
886 for v in range(1, 10):
889 # Compute the local orientation of the frame
890 center = self.geom.MakeVertexOnSurface(baseFace,
892 locPlaneYZ = self.geom.MakePlaneThreePnt(origPoint, center,
894 locOrient = self.geom.GetNormal(locPlaneYZ)
895 xPoint = self.geom.MakeTranslationVectorDistance(center,
898 gridLine = self.geom.MakeLineTwoPnt(center, xPoint)
899 gridList.append(gridLine)
901 grid = self.geom.MakeCompound(gridList)
904 def _buildMarkers(self):
906 Create the markers defining the orientation of the grid.
908 return self._buildMarkersWithOffset(self.offset)
911 def VisuPoutreGenerale(studyId, groupName, groupGeomObj, parameters,
914 Alias for class :class:`GeneralBeam`.
916 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
918 def VisuPoutreCercle(studyId, groupName, groupGeomObj, parameters,
921 Alias for class :class:`CircularBeam`.
923 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
925 def VisuPoutreRectangle(studyId, groupName, groupGeomObj, parameters,
928 Alias for class :class:`RectangularBeam`.
930 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
932 def VisuBarreGenerale(studyId, groupName, groupGeomObj, parameters,
935 Alias for class :class:`GeneralBeam`.
937 return GeneralBeam(studyId, groupName, groupGeomObj, parameters, name)
939 def VisuBarreRectangle(studyId, groupName, groupGeomObj, parameters,
942 Alias for class :class:`RectangularBeam`.
944 return RectangularBeam(studyId, groupName, groupGeomObj, parameters, name)
946 def VisuBarreCercle(studyId, groupName, groupGeomObj, parameters,
949 Alias for class :class:`CircularBeam`.
951 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
953 def VisuCable(studyId, groupName, groupGeomObj, parameters, name = "CABLE"):
955 Alias for class :class:`CircularBeam`.
957 return CircularBeam(studyId, groupName, groupGeomObj, parameters, name)
959 def VisuCoque(studyId, groupName, groupGeomObj, parameters, name = "COQUE"):
961 Alias for class :class:`ThickShell`.
963 return ThickShell(studyId, groupName, groupGeomObj, parameters, name)
965 def VisuGrille(studyId, groupName, groupGeomObj, parameters, name = "GRILLE"):
967 Alias for class :class:`Grid`.
969 return Grid(studyId, groupName, groupGeomObj, parameters, name)