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