Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit af3e110

Browse files
committed
Gathering code for Python talk
1 parent 3a9e856 commit af3e110

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed

python_thinking/Frame.py

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
"""Exploration of Vectors and Frames.
2+
3+
Copyright 2012 Allen B. Downey
4+
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
5+
6+
"""
7+
8+
from __future__ import print_function, division
9+
10+
import sys
11+
import numpy
12+
import math
13+
14+
def println(s):
15+
print(s, '\n')
16+
17+
class FrameError(ValueError):
18+
"""Represents a problem with frame of reference."""
19+
20+
class Vector:
21+
def __init__(self, array, frame=None):
22+
"""A vector is an array of coordinates and a frame of reference.
23+
24+
array:
25+
frame: Frame object
26+
"""
27+
self.array = array
28+
self.frame = frame
29+
30+
def __str__(self):
31+
if self.frame == None:
32+
return '^{O}%s' % (str(self.array), )
33+
else:
34+
return '^{%s}%s' % (str(self.frame), str(self.array))
35+
36+
def __add__(self, other):
37+
if self.frame != other.frame:
38+
raise FrameError("Vectors must be relative to the same frame.")
39+
40+
return Vector(self.array + other.array, self.frame)
41+
42+
@staticmethod
43+
def from_list(t, frame=None):
44+
"""Makes a vector from a list.
45+
46+
t: list of coordinates
47+
frame: reference Frame
48+
"""
49+
return Vector(numpy.array(t), frame)
50+
51+
52+
class Rotation:
53+
def __init__(self, array):
54+
self.array = array
55+
56+
def __str__(self):
57+
return 'Rotation\n%s' % str(self.array)
58+
59+
def __neg__(self):
60+
return Rotation(-self.array)
61+
62+
def __mul__(self, other):
63+
"""Apply the rotation to a Vector."""
64+
return numpy.dot(self.array, other.array)
65+
66+
__call__ = __mul__
67+
68+
@staticmethod
69+
def from_axis(axis, theta):
70+
x, y, z = numpy.ravel(axis.array)
71+
c = math.cos(theta)
72+
u = 1.0-c
73+
s = math.sqrt(1.0-c*c)
74+
xu, yu, zu = x*u, y*u, z*u
75+
v1 = [x*xu + c, x*yu - z*s, x*zu + y*s]
76+
v2 = [x*yu + z*s, y*yu + c, y*zu - x*s]
77+
v3 = [x*zu - y*s, y*zu + x*s, z*zu + c]
78+
return Rotation(numpy.array([v1, v2, v3]))
79+
80+
def to_axis(self):
81+
# return the equivalent angle-axis as (khat, theta)
82+
pass
83+
84+
def transpose(self):
85+
return Rotation(numpy.transpose(self.array))
86+
87+
inverse = transpose
88+
89+
90+
class Transform:
91+
"""Represents a transform from one Frame to another."""
92+
93+
def __init__(self, rot, org, source=None):
94+
"""Instantiates a Transform.
95+
96+
rot: Rotation object
97+
org: origin Vector
98+
source: source Frame
99+
"""
100+
self.rot = rot
101+
self.org = org
102+
self.dest = org.frame
103+
self.source = source
104+
self.source.add_transform(self)
105+
106+
def __str__(self):
107+
"""Returns a string representation of the Transform."""
108+
if self.dest == None:
109+
return '%s' % self.source.name
110+
return '_{%s}^{O}T' % self.source.name
111+
else:
112+
return '_{%s}^{%s}T' % (self.source.name, self.dest.name)
113+
114+
def __mul__(self, other):
115+
"""Applies a Transform to a Vector or Transform."""
116+
if isinstance(other, Vector):
117+
return self.mul_vector(other)
118+
119+
if isinstance(other, Transform):
120+
return self.mul_transform(other)
121+
122+
__call__ = __mul__
123+
124+
def mul_vector(self, p):
125+
"""Applies a Transform to a Vector.
126+
127+
p: Vector
128+
129+
Returns: Vector
130+
"""
131+
if p.frame != self.source:
132+
raise FrameError(
133+
"The frame of the vector must be the source of the transform")
134+
return Vector(self.rot * p, self.dest) + self.org
135+
136+
def mul_transform(self, other):
137+
"""Applies a Transform to another Transform.
138+
139+
other: Transform
140+
141+
Returns Transform
142+
"""
143+
if other.dest != self.source:
144+
raise FrameError(
145+
"This frames source must be the other frame's destination.")
146+
147+
rot = Rotation(self.rot * other.rot)
148+
t = Transform(rot, self * other.org, other.source)
149+
return t
150+
151+
def inverse(self):
152+
"""Computes the inverse transform.
153+
154+
Returns: Transform
155+
"""
156+
irot = self.rot.inverse()
157+
iorg = Vector(-(irot * self.org), self.source)
158+
t = Transform(irot, iorg, self.dest)
159+
return t
160+
161+
162+
class Frame:
163+
"""Represents a frame of reference."""
164+
165+
# list of Frames
166+
roster = []
167+
168+
def __init__(self, name):
169+
"""Instantiate a Frame.
170+
171+
name: string
172+
"""
173+
self.name = name
174+
self.transforms = {}
175+
Frame.roster.append(self)
176+
177+
def __str__(self):
178+
return self.name
179+
180+
def add_transform(self, transform):
181+
"""A frames is defined by a Transform relative to another Frame.
182+
183+
transform: Transform object
184+
"""
185+
if transform.source != self:
186+
raise FrameError("Source of the transform must be this Frame.")
187+
188+
if transform.dest:
189+
self.transforms[transform.dest] = transform
190+
191+
def dests(self):
192+
"""Returns a list of the Frames we know how to Transform to."""
193+
return self.transforms.keys()
194+
195+
196+
class Vertex:
197+
"""Represents a node in a graph."""
198+
199+
def __init__(self, frame):
200+
self.frame = frame
201+
self.dist = 1000000
202+
self.out = []
203+
204+
def __str__(self):
205+
return '%s %d' % (self.frame.name, self.dist)
206+
207+
208+
def shortest_path(start, frames):
209+
"""For a given list of frames and a starting frame,
210+
find the shortest path of transforms from the
211+
starting frame to all other frames.
212+
The 'distance' is the number of inverse transformations
213+
that must be calculated.
214+
The result is a dictionary of vertices, where
215+
each vertex is labeled with the frame it corresponds
216+
to, the distance from the starting frame, and the prev
217+
frame along the path from start. """
218+
219+
map = dict([(f, Vertex(f)) for f in frames])
220+
221+
length = {}
222+
for v in map.values():
223+
for dest in v.frame.transforms:
224+
w = map[dest]
225+
v.out.append(w)
226+
length[(v, w)] = 0
227+
228+
w.out.append(v)
229+
length[(w, v)] = 1
230+
231+
s = map[start]
232+
s.dist = 0
233+
queue = [s]
234+
235+
while queue:
236+
v = queue.pop()
237+
for w in v.out:
238+
d = v.dist + length[(v,w)]
239+
if d < w.dist:
240+
w.dist = d
241+
w.prev = v
242+
if w not in queue: queue.append(w)
243+
244+
return map
245+
246+
def print_shortest_path(map):
247+
for source, v in map.items():
248+
try:
249+
v.prev
250+
print(source, v.dist, v.prev.frame)
251+
except:
252+
print(source, v.dist)
253+
254+
def print_length(length):
255+
for v, w in length:
256+
print(v.frame.name, w.frame.name, length[(v, w)])
257+
print()
258+
259+
260+
def main(name):
261+
262+
theta = math.pi/2
263+
264+
#v_o = Vector.from_list([0, 0, 0], None)
265+
origin = Frame('O')
266+
#o_trans = Transform(None, v_o, origin)
267+
268+
xhat = Vector.from_list([1, 0, 0], origin)
269+
rx = Rotation.from_axis(xhat, theta)
270+
a = Frame('A')
271+
t_ao = Transform(rx, xhat, a)
272+
273+
yhat = Vector.from_list([0, 1, 0], a)
274+
ry = Rotation.from_axis(yhat, theta)
275+
b = Frame('B')
276+
t_ba = Transform(ry, yhat, b)
277+
278+
zhat = Vector.from_list([0, 0, 1], b)
279+
rz = Rotation.from_axis(zhat, theta)
280+
c = Frame('C')
281+
t_cb = Transform(rz, zhat, c)
282+
283+
p_c = Vector.from_list([1, 1, 1], c)
284+
println(p_c)
285+
286+
p_b = t_cb(p_c)
287+
println(p_b)
288+
289+
p_a = t_ba(p_b)
290+
println(p_a)
291+
292+
p = t_ao(p_a)
293+
println(p)
294+
295+
map = shortest_path(origin, Frame.roster)
296+
print_shortest_path(map)
297+
298+
cbao = t_ao(t_ba(t_cb))
299+
p = cbao(p_c)
300+
println(p)
301+
302+
inv = cbao.inverse()
303+
p_c = inv(p)
304+
println(p_c)
305+
306+
map = shortest_path(origin, Frame.roster)
307+
print_shortest_path(map)
308+
309+
310+
if __name__ == '__main__':
311+
main(*sys.argv)

0 commit comments

Comments
 (0)