Loading...
Searching...
No Matches
KoulesPlayback.py
1#!/usr/bin/env python3
2
3
36
37# Author: Beck Chen, Mark Moll
38
39from sys import argv, stdout
40from os.path import basename, splitext
41from math import cos, sin, atan2, pi, ceil
42import matplotlib.pyplot as plt
43import matplotlib.animation as animation
44
45targetFrameRate = 30 # desired number of frames per second
46speedUp = 1.0
47# the parameters will be read from file
48sideLength = 0
49shipRadius = 0
50kouleRadius = 0
51propagationStepSize = 0
52shipAcceleration = 0
53shipRotVel = 0
54shipDelta = 0
55shipEps = 0
56
57fig = plt.figure(figsize=(6, 6))
58ax = plt.axes(xlim=(0, 1), ylim=(0, 1))
59fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)
60(handle,) = ax.plot([], [])
61path = None
62
63
64def normalizeAngle(theta):
65 if theta < -pi:
66 return theta + 2.0 * pi
67 if theta > pi:
68 return theta - 2.0 * pi
69 return theta
70
71
72def plotShip(x, u):
73 pos = (x[0], x[1])
74 theta = x[4]
75 (cs, ss) = (shipRadius * cos(theta), shipRadius * sin(theta))
76 v = [u[0] - x[2], u[1] - x[3]]
77 deltaTheta = normalizeAngle(atan2(v[1], v[0]) - theta)
78 if v[0] * v[0] + v[1] * v[1] >= shipDelta * shipDelta:
79 if abs(deltaTheta) < shipEps:
80 # accelerate forward, draw thruster on the back
81 ax.add_patch(
82 plt.Circle((pos[0] - cs, pos[1] - ss), 0.3 * shipRadius, color="red")
83 )
84 elif deltaTheta > 0:
85 # rotate counterclockwise, draw thruster on right side
86 ax.add_patch(
87 plt.Circle((pos[0] + ss, pos[1] - cs), 0.3 * shipRadius, color="red")
88 )
89 else:
90 # rotate clockwise, draw thruster on left side
91 ax.add_patch(
92 plt.Circle((pos[0] - ss, pos[1] + cs), 0.3 * shipRadius, color="red")
93 )
94 # draw ship
95 ax.add_patch(plt.Circle(x[:2], shipRadius, color="yellow"))
96 # draw two blue "eyes"
97 ax.add_patch(
98 plt.Circle(
99 (
100 pos[0] + 0.7 * shipRadius * cos(theta + 0.75),
101 pos[1] + 0.7 * shipRadius * sin(theta + 0.75),
102 ),
103 0.2 * shipRadius,
104 color="blue",
105 )
106 )
107 ax.add_patch(
108 plt.Circle(
109 (
110 pos[0] + 0.7 * shipRadius * cos(theta - 0.75),
111 pos[1] + 0.7 * shipRadius * sin(theta - 0.75),
112 ),
113 0.2 * shipRadius,
114 color="blue",
115 )
116 )
117
118
119def plotKoules(state):
120 numKoules = int(len(state) / 4)
121 for i in range(numKoules):
122 ax.add_patch(
123 plt.Circle((state[4 * i], state[4 * i + 1]), kouleRadius, color="red")
124 )
125
126
127def plotSystem(index):
128 ax.clear()
129 ax.add_patch(plt.Rectangle((0, 0), 1, 1, color="black"))
130 plotKoules(path[index][5:-3])
131 plotShip(path[index][0:5], path[index][-3:])
132 if index % 10 == 0:
133 stdout.write(".")
134 stdout.flush()
135 return (handle,)
136
137
138def makeMovie(fname):
139 with open(fname, "r") as f:
140 global \
141 sideLength, \
142 shipRadius, \
143 kouleRadius, \
144 propagationStepSize, \
145 shipAcceleration, \
146 shipRotVel, \
147 shipDelta, \
148 shipEps, \
149 path
150 (
151 sideLength,
152 shipRadius,
153 kouleRadius,
154 propagationStepSize,
155 shipAcceleration,
156 shipRotVel,
157 shipDelta,
158 shipEps,
159 ) = [float(x) for x in next(f).split()]
160 path = [[float(x) for x in line.split(" ")] for line in f]
161 if not path:
162 print("Error: %s contains no solution path" % fname)
163 return
164 step = int(ceil(speedUp / (propagationStepSize * targetFrameRate)))
165 path = path[0 : len(path) : step]
166 print("Creating a movie with %d frames..." % len(path))
167 print("Printing a '.' for every 10th frame:")
168 ani = animation.FuncAnimation(
169 fig, plotSystem, frames=len(path), interval=1000.0 / step, blit=True
170 )
171 (base, _) = splitext(basename(fname))
172 outfname = base + ".mp4"
173 ani.save(outfname, bitrate=300, fps=targetFrameRate)
174 print("")
175
176
177if __name__ == "__main__":
178 if len(argv) == 1:
179 print("Usage: KoulesPlayback.py <filename> [<filename2> ...]")
180 else:
181 for trajectory_file in argv[1:]:
182 makeMovie(trajectory_file)