-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathInterp.py
349 lines (305 loc) · 8.09 KB
/
Interp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
from pythonfrp.Signal import *
from pythonfrp.Types import *
import math
"""
Bug: repeating a "to" doesn't work since it assumes that the value is
always the same at the start of the to.
at p c = \p0 t -> c p t
to p i c = \p0 t -> if t < i then t/i * p0 + (1-t/i) * p else c p (t-i)
hold = \p0 t -> p0
Need something to tag interpolants so that we can interpolate
more than one thing at a time - this is probably needed elsewhere
Need to describe
uses/description
return type
example
parameters
describe generic space
figure out pydoc vs developer notes/comments
"""
infiniteDur = 1000000
class Interp:
"""
Base Interpolation Class
Defines a path between two points in an arbitrary space(color, location, etc.)
"""
def __init__(self):
self.interpolant = None
self._type = interpableType
def __add__(self, x):
"""
Infix (+) operator
Concat two interps together using an InterpNext object
x = InterpAt(p1)
y = InterpTo(5, p2)
z = x + y
returns an InterpNext()
"""
return InterpNext(self, x)
class InterpNext(Interp):
"""
represents a path between two interpolants
"""
def __init__(self, i1, i2):
"""
constructor
i1: Interp
i2: Interp
connects the two interpolants where i1 is the start position and i2 is the end
"""
Interp.__init__(self)
self.i1 = i1
self.i2 = i2
def getInterpolant(self, prev):
"""
returns running interpolant
"""
return RInterpNext(prev, self.i1, self.i2)
class InterpAt(Interp):
"""
Start point for a Interp path
"""
def __init__(self, p):
"""
Constructor
p: this point
ty: interpolant type
"""
Interp.__init__(self)
self.p = p
def getInterpolant(self, prev):
"""
gets the running interpolant
"""
return RInterpAt(prev, self.p)
class InterpTo(Interp):
"""
Describes a point along the interpolation path and a duration to that point.
The point is described as an absolute location in the path
"""
def __init__(self, dur, p):
"""
Constructor
dur: float
p: interp
duration defines the time to point p
"""
Interp.__init__(self)
self.dur = float(dur)
self.p = p
def getInterpolant(self, prev):
"""
returns the running interpolant
"""
return RInterpTo(prev, self.dur, self.p, False)
class InterpMove(Interp):
"""
Decribes an Interp with an relative path
"""
def __init__(self, dur, p):
"""
constructor
dur: float
p: interp
ty: interpolant type
duration defines time to point p
"""
Interp.__init__(self)
self.dur = float(dur)
self.p = p
def getInterpolant(self, prev):
"""
returns running interpolant
"""
return RInterpTo(prev, self.dur, self.p, True)
class InterpCycle(Interp):
"""
Follow a path repeatedly starting at the first point
"""
def __init__(self, n, i):
"""
constructor
n: a point in the interpolation path
i: a point in the interpolation path
ty: interpolant type
"""
Interp.__init__(self)
self.type = anyType #See if this is correct - 6/16/14 - Lucas
self.n = n
self.i = i
def getInterpolant(self, prev):
return RInterpCycle(prev, self.n, self.i)
class InterpRev(Interp):
"""
An Interp that goes backwards along path
"""
def __init__(self, i):
"""
constructor
"""
Interp.__init__(self)
self.i = i
def getInterpolant(self, prev):
return RInterpRev(prev, self.i)
# Interpolant caching:
def getInterpolant(i):
"""
returns the interpolant of i
"""
if i.interpolant is None:
i.interpolant = i.getInterpolant(None)
return i.interpolant
# Classes for running interpolants:
class RInterpNext:
"""
Running version of the InterpNext. this actually follows the path
"""
def __init__(self, prev, i1, i2):
self.i1 = i1.getInterpolant(prev)
self.i2 = i2.getInterpolant(self.i1)
self.first = self.i1.first
self.last = self.i2.last
if self.i1.delta == None or self.i2.delta == None:
self.delta = None
else:
self.delta = self.i1.delta + self.i2.delta
self.dur = self.i1.dur + self.i2.dur
def interp(self, t):
"""
Return the current interp point recursively of whichever path we are currently on
"""
if t < self.i1.dur:
return self.i1.interp(t)
else:
return self.i2.interp(t - self.i1.dur)
class RInterpAt:
"""
Running version of InterpAt
"""
def __init__(self, prev, p):
self.p = p
self.first = p
self.last = p
self.dur = 0
self.delta = None
def interp(self, t):
"""
returns the point of the interpolant
"""
return self.p
class RInterpTo:
"""
Running version of InterpTo
"""
def __init__(self, prev, dur, p, relative):
if (prev is None):
interpMissingAt()
if relative:
self.delta = p
p = p + prev.last
else:
self.delta = None
self.last = p
self.dur = dur
self.first = prev.last
def interp(self, t):
"""
Retutns the path location between two Interp s based on time
"""
return lerpStatic(t/self.dur, self.first, self.last)
class RInterpCycle:
"""
The running version of we don't know
"""
def __init__(self, prev, n, i):
self.i = i.getInterpolant(prev)
if n == -1:
self.dur = infiniteDur
else:
self.dur = n * self.i.dur
self.first = self.i.first
if self.i.delta == None:
self.delta = None
self.last = self.i.last
else:
self.delta = self.i.delta * n
self.last = self.i.first + self.delta
def interp(self, t):
"""
has something to do with delta
"""
f = math.floor(t/self.i.dur)
t1 = t - f*self.i.dur
r = self.i.interp(t1)
if self.delta != None:
r = r + self.i.delta * f
return r
class RInterpRev:
"""
Running version of a reverse path Interp
"""
def __init__(self, prev, i):
self.i = i.getInterpolant(prev)
if self.i.delta is not None:
print("Cannot reverse an interpolant of moves")
exit()
self.first = self.i.last
self.last = self.i.first
self.dur = self.i.dur
self.delta = None
def interp(self, t):
"""
Returns current path location along reverse Interp recursive
"""
return self.i.interp(self.i.dur - t)
def to(d, p):
"""
Front End version of a InterpTo object
"""
return InterpTo(d, p)
# Reverse an interpolation
def reverse(i):
"""
Front End version of a InterpRev object
"""
return InterpRev(i)
def move(d, p):
"""
Front End version of a InterpMove object
"""
return InterpMove(d, p)
def at(p):
"""
Front End version of a InterpAt object
"""
return InterpAt(p)
def repeat(n, i):
"""
Front End version of a InterpCycle object
(not sure what this does)
"""
return InterpCycle(n, i)
def forever(i):
return repeat(-1, i)
def lerpStatic(t, v1, v2):
"""
Return the actual location along the current path (used as base case in RInterpTo)
"""
if type(v1) is type(1) or type(v1) is type(1.0):
return (1-t) * v1 + t * v2
return v1.interp(t, v2)
# two interpolants:
# lerp(t, v1, v2) - linear interpolation
# interpolate(t, i) - use interpolation class
def interpolateStatic(t, i):
"""
Returns the current point along the Interp i
"""
i1 = getInterpolant(i)
if t < 0:
return i1.first
if t >= i1.dur:
return i1.last
result = i1.interp(t)
#print(result)
return result