chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / fabmetheus_utilities / vector3.py
1 """
2 Vector3 is a three dimensional vector class.
3
4 Below are examples of Vector3 use.
5
6 >>> from vector3 import Vector3
7 >>> origin = Vector3()
8 >>> origin
9 0.0, 0.0, 0.0
10 >>> pythagoras = Vector3( 3, 4, 0 )
11 >>> pythagoras
12 3.0, 4.0, 0.0
13 >>> pythagoras.magnitude()
14 5.0
15 >>> pythagoras.magnitudeSquared()
16 25
17 >>> triplePythagoras = pythagoras * 3.0
18 >>> triplePythagoras
19 9.0, 12.0, 0.0
20 >>> plane = pythagoras.dropAxis()
21 >>> plane
22 (3+4j)
23 """
24
25 from __future__ import absolute_import
26 try:
27         import psyco
28         psyco.full()
29 except:
30         pass
31 #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
32 import __init__
33
34 from fabmetheus_utilities import xml_simple_writer
35 import math
36 import operator
37
38
39 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
40 __credits__ = 'Nophead <http://forums.reprap.org/profile.php?12,28>\nArt of Illusion <http://www.artofillusion.org/>'
41 __date__ = '$Date: 2008/21/04 $'
42 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
43
44
45 class Vector3:
46         'A three dimensional vector class.'
47         __slots__ = ['x', 'y', 'z']
48
49         def __init__(self, x=0.0, y=0.0, z=0.0):
50                 self.x = x
51                 self.y = y
52                 self.z = z
53
54         def __abs__(self):
55                 'Get the magnitude of the Vector3.'
56                 return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z )
57
58         magnitude = __abs__
59
60         def __add__(self, other):
61                 'Get the sum of this Vector3 and other one.'
62                 return Vector3( self.x + other.x, self.y + other.y, self.z + other.z )
63
64         def __copy__(self):
65                 'Get the copy of this Vector3.'
66                 return Vector3( self.x, self.y, self.z )
67
68         __pos__ = __copy__
69
70         copy = __copy__
71
72         def __div__(self, other):
73                 'Get a new Vector3 by dividing each component of this one.'
74                 return Vector3( self.x / other, self.y / other, self.z / other )
75
76         def __eq__(self, other):
77                 'Determine whether this vector is identical to other one.'
78                 if other == None:
79                         return False
80                 if other.__class__ != self.__class__:
81                         return False
82                 return self.x == other.x and self.y == other.y and self.z == other.z
83
84         def __floordiv__(self, other):
85                 'Get a new Vector3 by floor dividing each component of this one.'
86                 return Vector3( self.x // other, self.y // other, self.z // other )
87
88         def __hash__(self):
89                 'Determine whether this vector is identical to other one.'
90                 return self.__repr__().__hash__()
91
92         def __iadd__(self, other):
93                 'Add other Vector3 to this one.'
94                 self.x += other.x
95                 self.y += other.y
96                 self.z += other.z
97                 return self
98
99         def __idiv__(self, other):
100                 'Divide each component of this Vector3.'
101                 self.x /= other
102                 self.y /= other
103                 self.z /= other
104                 return self
105
106         def __ifloordiv__(self, other):
107                 'Floor divide each component of this Vector3.'
108                 self.x //= other
109                 self.y //= other
110                 self.z //= other
111                 return self
112
113         def __imul__(self, other):
114                 'Multiply each component of this Vector3.'
115                 self.x *= other
116                 self.y *= other
117                 self.z *= other
118                 return self
119
120         def __isub__(self, other):
121                 'Subtract other Vector3 from this one.'
122                 self.x -= other.x
123                 self.y -= other.y
124                 self.z -= other.z
125                 return self
126
127         def __itruediv__(self, other):
128                 'True divide each component of this Vector3.'
129                 self.x = operator.truediv( self.x, other )
130                 self.y = operator.truediv( self.y, other )
131                 self.z = operator.truediv( self.z, other )
132                 return self
133
134         def __mul__(self, other):
135                 'Get a new Vector3 by multiplying each component of this one.'
136                 return Vector3( self.x * other, self.y * other, self.z * other )
137
138         def __ne__(self, other):
139                 'Determine whether this vector is not identical to other one.'
140                 return not self.__eq__(other)
141
142         def __neg__(self):
143                 return Vector3( - self.x, - self.y, - self.z )
144
145         def __nonzero__(self):
146                 return self.x != 0 or self.y != 0 or self.z != 0
147
148         def __rdiv__(self, other):
149                 'Get a new Vector3 by dividing each component of this one.'
150                 return Vector3( other / self.x, other / self.y, other / self.z )
151
152         def __repr__(self):
153                 'Get the string representation of this Vector3.'
154                 return '(%s, %s, %s)' % ( self.x, self.y, self.z )
155
156         def __rfloordiv__(self, other):
157                 'Get a new Vector3 by floor dividing each component of this one.'
158                 return Vector3( other // self.x, other // self.y, other // self.z )
159
160         def __rmul__(self, other):
161                 'Get a new Vector3 by multiplying each component of this one.'
162                 return Vector3( self.x * other, self.y * other, self.z * other )
163
164         def __rtruediv__(self, other):
165                 'Get a new Vector3 by true dividing each component of this one.'
166                 return Vector3( operator.truediv( other , self.x ), operator.truediv( other, self.y ), operator.truediv( other, self.z ) )
167
168         def __sub__(self, other):
169                 'Get the difference between the Vector3 and other one.'
170                 return Vector3( self.x - other.x, self.y - other.y, self.z - other.z )
171
172         def __truediv__(self, other):
173                 'Get a new Vector3 by true dividing each component of this one.'
174                 return Vector3( operator.truediv( self.x, other ), operator.truediv( self.y, other ), operator.truediv( self.z, other ) )
175
176         def _getAccessibleAttribute(self, attributeName):
177                 'Get the accessible attribute.'
178                 if attributeName in globalGetAccessibleAttributeSet:
179                         return getattr(self, attributeName, None)
180                 return None
181
182         def _setAccessibleAttribute(self, attributeName, value):
183                 'Set the accessible attribute.'
184                 if attributeName in globalSetAccessibleAttributeSet:
185                         setattr(self, attributeName, value)
186
187         def cross(self, other):
188                 'Calculate the cross product of this vector with other one.'
189                 return Vector3(self.y * other.z - self.z * other.y, -self.x * other.z + self.z * other.x, self.x * other.y - self.y * other.x)
190
191         def distance(self, other):
192                 'Get the Euclidean distance between this vector and other one.'
193                 return math.sqrt( self.distanceSquared(other) )
194
195         def distanceSquared(self, other):
196                 'Get the square of the Euclidean distance between this vector and other one.'
197                 separationX = self.x - other.x
198                 separationY = self.y - other.y
199                 separationZ = self.z - other.z
200                 return separationX * separationX + separationY * separationY + separationZ * separationZ
201
202         def dot(self, other):
203                 'Calculate the dot product of this vector with other one.'
204                 return self.x * other.x + self.y * other.y + self.z * other.z
205
206         def dropAxis( self, which = 2 ):
207                 'Get a complex by removing one axis of the vector3.'
208                 if which == 0:
209                         return complex( self.y, self.z )
210                 if which == 1:
211                         return complex( self.x, self.z )
212                 if which == 2:
213                         return complex( self.x, self.y )
214
215         def getFloatList(self):
216                 'Get the vector as a list of floats.'
217                 return [ float( self.x ), float( self.y ), float( self.z ) ]
218
219         def getIsDefault(self):
220                 'Determine if this is the zero vector.'
221                 if self.x != 0.0:
222                         return False
223                 if self.y != 0.0:
224                         return False
225                 return self.z == 0.0
226
227         def getNormalized(self):
228                 'Get the normalized Vector3.'
229                 magnitude = abs(self)
230                 if magnitude == 0.0:
231                         return self.copy()
232                 return self / magnitude
233
234         def magnitudeSquared(self):
235                 'Get the square of the magnitude of the Vector3.'
236                 return self.x * self.x + self.y * self.y + self.z * self.z
237
238         def maximize(self, other):
239                 'Maximize the Vector3.'
240                 self.x = max(other.x, self.x)
241                 self.y = max(other.y, self.y)
242                 self.z = max(other.z, self.z)
243
244         def minimize(self, other):
245                 'Minimize the Vector3.'
246                 self.x = min(other.x, self.x)
247                 self.y = min(other.y, self.y)
248                 self.z = min(other.z, self.z)
249
250         def normalize(self):
251                 'Scale each component of this Vector3 so that it has a magnitude of 1. If this Vector3 has a magnitude of 0, this method has no effect.'
252                 magnitude = abs(self)
253                 if magnitude != 0.0:
254                         self /= magnitude
255
256         def reflect( self, normal ):
257                 'Reflect the Vector3 across the normal, which is assumed to be normalized.'
258                 distance = 2 * ( self.x * normal.x + self.y * normal.y + self.z * normal.z )
259                 return Vector3( self.x - distance * normal.x, self.y - distance * normal.y, self.z - distance * normal.z )
260
261         def setToVector3(self, other):
262                 'Set this Vector3 to be identical to other one.'
263                 self.x = other.x
264                 self.y = other.y
265                 self.z = other.z
266
267         def setToXYZ( self, x, y, z ):
268                 'Set the x, y, and z components of this Vector3.'
269                 self.x = x
270                 self.y = y
271                 self.z = z
272
273
274 globalGetAccessibleAttributeSet = 'x y z'.split()
275 globalSetAccessibleAttributeSet = globalGetAccessibleAttributeSet
276
277 """
278 class Vector3:
279         __slots__ = ['x', 'y', 'z']
280
281
282         copy = __copy__
283
284         def __eq__(self, other):
285                 if isinstance(other, Vector3):
286                         return self.x == other.x and \
287                                    self.y == other.y and \
288                                    self.z == other.z
289                 else:
290                         assert hasattr(other, '__len__') and len(other) == 3
291                         return self.x == other[0] and \
292                                    self.y == other[1] and \
293                                    self.z == other[2]
294
295         def __getattr__(self, name):
296                 try:
297                         return tuple([(self.x, self.y, self.z)['xyz'.index(c)] \
298                                                   for c in name])
299                 except ValueError:
300                         raise AttributeError, name
301
302         def __getitem__(self, key):
303                 return (self.x, self.y, self.z)[key]
304
305         def __iter__(self):
306                 return iter((self.x, self.y, self.z))
307
308         def __len__(self):
309                 return 3
310
311         def __repr__(self):
312                 return 'Vector3(%.2f, %.2f, %.2f)' % (self.x,
313                                                                                           self.y,
314                                                                                           self.z)
315
316         if _enable_swizzle_set:
317                 # This has detrimental performance on ordinary setattr as well
318                 # if enabled
319                 def __setattr__(self, name, value):
320                         if len(name) == 1:
321                                 object.__setattr__(self, name, value)
322                         else:
323                                 try:
324                                         l = [self.x, self.y, self.z]
325                                         for c, v in map(None, name, value):
326                                                 l['xyz'.index(c)] = v
327                                         self.x, self.y, self.z = l
328                                 except ValueError:
329                                         raise AttributeError, name
330
331         def __setitem__(self, key, value):
332                 l = [self.x, self.y, self.z]
333                 l[key] = value
334                 self.x, self.y, self.z = l
335
336 """