Salome HOME
Merge from V6_4_BR 05/12/2011
[modules/geom.git] / src / GEOM_PY / structelem / orientation.py
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21 """
22 This module is used to compute the orientation of the different parts in a
23 structural element and to build the corresponding markers (trihedrons).
24 """
25
26 import math
27
28 from salome.kernel.logger import Logger
29 from salome.kernel import termcolor
30 logger = Logger("__PAL_GEOM__.structelem.orientation", color = termcolor.RED)
31
32
33 class Orientation1D:
34     """
35     This class is used to compute the orientation of 1D elements and to build
36     the corresponding markers.
37     """
38     
39     def __init__(self):
40         self.geom = None
41         self._vectorYCoords = None
42         self._angle = 0.0
43
44     def __repr__(self):
45         reprdict = self.__dict__.copy()
46         del reprdict["geom"]
47         return '%s(%s)' % (self.__class__.__name__, reprdict)
48
49     def addParams(self, params):
50         """
51         Add orientation parameters. `params` is a dictionary containing one or
52         several orientation parameters. The valid parameters are:
53
54         * "VECT_Y": Triplet defining the local Y axis (the X axis is the
55           main direction of the 1D element).
56         * "ANGL_VRIL": Angle of rotation along the X axis to define the local
57           coordinate system.
58         
59         The parameters can be specified several times. In this case, only the
60         first "VECT_Y" is taken into account, and the values of "ANGL_VRIL"
61         are added to obtain the total rotation angle.
62         """
63         mydict = params.copy()
64         if mydict.has_key("VECT_Y"):
65             newVecCoords = mydict.pop("VECT_Y")
66             if self._vectorYCoords is None:
67                 logger.debug("Setting orientation vector Y to %s" %
68                              str(newVecCoords))
69                 self._vectorYCoords = newVecCoords
70             else:
71                 logger.warning('Orientation parameter "VECT_Y" is specified '
72                                'several times for the same mesh group, vector'
73                                ' %s will be used' % str(self._vectorYCoords))
74         if mydict.has_key("ANGL_VRIL"):
75             newAngle = mydict.pop("ANGL_VRIL")
76             self._angle += newAngle
77             logger.debug("Adding angle %f to orientation, new angle is %f." %
78                          (newAngle, self._angle))
79         if len(mydict) > 0:
80             logger.warning("Invalid orientation parameter(s) (ignored): %s" %
81                            str(mydict))
82
83     def _getDefaultVecYZ(self, center, vecX):
84         """
85         Get the vectors Y and Z for the default LCS, that use the main
86         direction of the 1D object as the local X axis and the global Z axis
87         to determine the local Z axis.
88         """
89         xPoint = self.geom.MakeTranslationVector(center, vecX)
90         givenVecZ = self.geom.MakeVectorDXDYDZ(0.0, 0.0, 1.0)
91         angle = self.geom.GetAngleRadians(vecX, givenVecZ)
92         if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
93             logger.warning("Beam X axis is colinear to absolute Z axis. "
94                            "Absolute X axis will be used to determine "
95                            "local Z axis.")
96             givenVecZ = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
97         zPoint = self.geom.MakeTranslationVector(center, givenVecZ)
98         locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint, xPoint, 1.0)
99         locY = self.geom.GetNormal(locPlaneZX)
100         yPoint = self.geom.MakeTranslationVector(center, locY)
101         locPlaneXY = self.geom.MakePlaneThreePnt(center, xPoint, yPoint, 1.0)
102         locZ = self.geom.GetNormal(locPlaneXY)
103         return (locY, locZ)
104
105     def buildMarker(self, geom, center, vecX):
106         """
107         Create a marker with origin `center` and X axis `vecX`. `geom` is the
108         pseudo-geompy object used to build the geometric shapes.
109         """
110         (locY, locZ) = self.getVecYZ(geom, center, vecX)
111         marker = geom.MakeMarkerPntTwoVec(center, vecX, locY)
112         return marker
113
114     def getVecYZ(self, geom, center, vecX):
115         """
116         Get the vectors Y and Z for the LCS with origin `center` and X axis
117         `vecX`. `geom` is the pseudo-geompy object used to build the geometric
118         shapes.
119         """
120         self.geom = geom
121         locY = None
122         locZ = None
123         if self._vectorYCoords is None:
124             (locY, locZ) = self._getDefaultVecYZ(center, vecX)
125         else:
126             xPoint = self.geom.MakeTranslationVector(center, vecX)
127             givenLocY = self.geom.MakeVectorDXDYDZ(self._vectorYCoords[0],
128                                                    self._vectorYCoords[1],
129                                                    self._vectorYCoords[2])
130             angle = self.geom.GetAngleRadians(vecX, givenLocY)
131             if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
132                 logger.warning("Vector Y is colinear to the beam X axis, "
133                                "using default LCS.")
134                 (locY, locZ) = self._getDefaultVecYZ(center, vecX)
135             else:
136                 yPoint = self.geom.MakeTranslationVector(center, givenLocY)
137                 locPlaneXY = self.geom.MakePlaneThreePnt(center, xPoint,
138                                                          yPoint, 1.0)
139                 locZ = self.geom.GetNormal(locPlaneXY)
140                 zPoint = self.geom.MakeTranslationVector(center, locZ)
141                 locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint,
142                                                          xPoint, 1.0)
143                 locY = self.geom.GetNormal(locPlaneZX)
144
145         if self._angle != 0.0:
146             angleRad = math.radians(self._angle)
147             locY = self.geom.Rotate(locY, vecX, angleRad)
148             locZ = self.geom.Rotate(locZ, vecX, angleRad)
149
150         return (locY, locZ)
151
152
153 class Orientation2D:
154     """
155     This class is used to compute the orientation of 2D elements and to build
156     the corresponding markers. Angles `alpha` and `beta` are used to determine
157     the local coordinate system for the 2D element. If `vect` is not
158     :const:`None`, it is used instead of `alpha` and `beta`.
159     """
160
161     def __init__(self, alpha, beta, vect):
162         self.geom = None
163         self._alpha = alpha
164         self._beta = beta
165         self._vect = vect
166
167     def __repr__(self):
168         reprdict = self.__dict__.copy()
169         del reprdict["geom"]
170         return '%s(%s)' % (self.__class__.__name__, reprdict)
171
172     def _buildDefaultMarker(self, center, normal, warnings = True):
173         """
174         Create the default marker, that use the normal vector of the 2D object
175         as the local Z axis and the global X axis to determine the local X
176         axis. `warnings` can be used to enable or disable the logging of
177         warning messages.
178         """
179         marker = None
180         globalVecX = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
181         angle = self.geom.GetAngleRadians(normal, globalVecX)
182         if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
183             if warnings:
184                 logger.warning("Face normal is colinear to absolute X axis. "
185                                "Absolute Y axis will be used to determine "
186                                "local X axis.")
187             globalVecY = self.geom.MakeVectorDXDYDZ(0.0, 1.0, 0.0)
188             marker = self._buildMarkerRefVecX(center, normal, globalVecY)
189         else:
190             marker = self._buildMarkerRefVecX(center, normal, globalVecX)
191         return marker
192
193     def _buildMarkerRefVecX(self, center, normal, refVecX):
194         """
195         Create a marker using `normal` as Z axis and `refVecX` to determine
196         the X axis.
197         """
198         xPoint = self.geom.MakeTranslationVector(center, refVecX)
199         zPoint = self.geom.MakeTranslationVector(center, normal)
200         locPlaneZX = self.geom.MakePlaneThreePnt(center, zPoint, xPoint, 1.0)
201         locY = self.geom.GetNormal(locPlaneZX)
202         yPoint = self.geom.MakeTranslationVector(center, locY)
203         locPlaneYZ = self.geom.MakePlaneThreePnt(center, yPoint, zPoint, 1.0)
204         locX = self.geom.GetNormal(locPlaneYZ)
205         marker = self.geom.MakeMarkerPntTwoVec(center, locX, locY)
206         return marker
207
208     def buildMarker(self, geom, center, normal, warnings = True):
209         """
210         Create a marker with origin `center` and `normal` as Z axis. The other
211         axes are computed using the parameters alpha and beta of the
212         Orientation2D instance. `geom` is the pseudo-geompy object used to
213         build the geometric shapes. `warnings` can be used to enable or
214         disable the logging of warning messages.
215         """
216         self.geom = geom
217         marker = None
218         refVecX = None
219         if self._vect is not None:
220             # Using vector parameter
221             if abs(self._vect[0]) <= 1e-7 and abs(self._vect[1]) <= 1e-7 and \
222                                               abs(self._vect[2]) <= 1e-7:
223                 if warnings:
224                     logger.warning("Vector too small: %s, using default LCS" %
225                                    self._vect)
226             else:
227                 refVecX = self.geom.MakeVectorDXDYDZ(self._vect[0],
228                                                      self._vect[1],
229                                                      self._vect[2])
230         elif self._alpha is not None and self._beta is not None:
231             # Using alpha and beta angles
232             alphaRad = math.radians(self._alpha)
233             betaRad = math.radians(self._beta)
234             if abs(alphaRad) <= 1e-7 and abs(betaRad) <= 1e-7:
235                 if warnings:
236                     logger.warning("Angles too small: (%g, %g), using "
237                                    "default LCS" % (self._alpha, self._beta))
238             else:
239                 # rotate global CS with angles alpha and beta
240                 refVecX = self.geom.MakeVectorDXDYDZ(1.0, 0.0, 0.0)
241                 refVecY = self.geom.MakeVectorDXDYDZ(0.0, 1.0, 0.0)
242                 globalVecZ = self.geom.MakeVectorDXDYDZ(0.0, 0.0, 1.0)
243                 if abs(alphaRad) > 1e-7:
244                     refVecX = self.geom.Rotate(refVecX, globalVecZ, alphaRad)
245                     refVecY = self.geom.Rotate(refVecY, globalVecZ, alphaRad)
246                 if abs(betaRad) > 1e-7:
247                     refVecX = self.geom.Rotate(refVecX, refVecY, betaRad)
248     
249         if refVecX is not None:
250             # build local coordinate system
251             angle = self.geom.GetAngleRadians(normal, refVecX)
252             if abs(angle) < 1e-7 or abs(angle - math.pi) < 1e-7:
253                 if warnings:
254                     logger.warning("Face normal is colinear to the reference "
255                                    "X axis, using default LCS.")
256             else:
257                 marker = self._buildMarkerRefVecX(center, normal, refVecX)
258
259         if marker is None:
260             marker = self._buildDefaultMarker(center, normal, warnings)
261
262         return marker