2 from .base
import LottieObject, LottieProp
3 from ..nvector
import NVector
7 def __init__(self, vertex, in_tangent=None, out_tangent=None):
17 return cls(point, in_tangent, -in_tangent)
22 in_tangent = point.clone()
24 out_tangent = point.clone()
96 return len(self.
bezier.vertices)
99 if isinstance(key, slice):
104 return self.
point(key)
107 for i
in range(len(self)):
111 if isinstance(point, NVector):
112 self.
bezier.add_point(point.clone())
114 bpt = point.relative()
115 self.
bezier.add_point(bpt.vertex.clone(), bpt.in_tangent.clone(), bpt.out_tangent.clone())
129 LottieProp(
"in_tangents",
"i", NVector,
True),
130 LottieProp(
"out_tangents",
"o", NVector,
True),
149 clone.closed = self.
closed
150 clone.in_tangents = [p.clone()
for p
in self.
in_tangents]
151 clone.out_tangents = [p.clone()
for p
in self.
out_tangents]
152 clone.vertices = [p.clone()
for p
in self.
vertices]
158 Inserts a point at the given index
159 @param index Index to insert the point at
160 @param pos Point to add
161 @param inp Tangent entering the point, as a vector relative to @p pos
162 @param outp Tangent exiting the point, as a vector relative to @p pos
163 @returns @c self, for easy chaining
175 Appends a point to the curve
183 Appends a point with symmetrical tangents
192 @returns @c self, for easy chaining
199 @param t A value between 0 and 1, percentage along the length of the curve
200 @returns The point at @p t in the curve
216 return math.atan2(delta.y, delta.x)
224 return i, split1, split2
226 def _split_segment(self, t, cub):
231 return split1, split2
239 split1 = [cub[0], quad[0]-cub[0], lin[0]-k, k]
240 split2 = [k, lin[-1]-k, quad[-1]-cub[-1], cub[-1]]
241 return split1, split2
245 Get two pieces out of a Bezier curve
246 @param t A value between 0 and 1, percentage along the length of the curve
247 @returns Two Bezier objects that correspond to self, but split at @p t
252 i, split1, split2 = self.
_split(t)
258 for j
in range(i+2, len(self.
vertices)):
262 seg1.add_point(split1[3], split1[2], split2[1])
264 seg2.insert_point(0, split2[0], split1[2], split2[1])
271 Splits a Bezier in two points and returns the segment between the
272 @param t1 A value between 0 and 1, percentage along the length of the curve
273 @param t2 A value between 0 and 1, percentage along the length of the curve
274 @returns Bezier object that correspond to the segment between @p t1 and @p t2
280 return copy.segment(t1, t2)
297 t2p = (t2-t1) / (1-t1)
298 seg3, seg4 = seg2.split_at(t2p)
303 Adds more points to the Bezier
304 @param positions list of percentages along the curve
306 if not len(positions):
318 for t2
in positions[1:]:
320 seg1, seg2 = seg2.split_at(t)
332 Adds a point in the middle of the segment between every pair of points in the Bezier
342 for i
in range(len(vertices)-1):
343 tocut = [vertices[i], out_tangents[i]+vertices[i], in_tangents[i+1]+vertices[i+1], vertices[i+1]]
348 self.
add_point(vertices[0], in_tangents[0], split1[1])
349 self.
add_point(split1[3], split1[2], split2[1])
354 Adds points the Bezier, splitting it into @p n_chunks additional chunks.
356 splits = [i/n_chunks
for i
in range(1, n_chunks)]
359 def _bezier_points(self, i, optimize):
364 if not optimize
or t1.length != 0:
367 if not optimize
or t1.length != 0:
372 def _solve_bezier_step(self, t, points):
375 for p2
in points[1:]:
376 next.append(p1 * (1-t) + p2 * t)
380 def _solve_bezier_coeff(self, i, n, t):
382 math.factorial(n) / (math.factorial(i) * math.factorial(n - i))
383 * (t ** i) * ((1 - t) ** (n-i))
386 def _solve_bezier(self, t, points):
398 def _index_t(self, t):
410 return i, (t - (i/n)) * n
414 Reverses the Bezier curve
422 """def to_absolute(self):
423 if self.rel_tangents:
424 self.rel_tangents = False
425 for i in range(len(self.vertices)):
427 self.in_tangents[i] += p
428 self.out_tangents[i] += p
433 cloned.closed = self.
closed
435 round_corner = 0.5519
437 def _get_vt(closest_index):
438 closer_v = self.
vertices[closest_index]
439 distance = (current - closer_v).length
440 new_pos_perc = min(distance/2, round_distance) / distance
if distance
else 0
441 vert = current + (closer_v - current) * new_pos_perc
442 tan = - (vert - current) * round_corner
445 for i, current
in enumerate(self.
vertices):
446 if not self.
closed and (i == 0
or i == len(self.
points) - 1):
447 cloned.points.append(self.
points[i])
449 vert1, out_t = _get_vt(i - 1)
450 cloned.add_point(vert1,
NVector(0, 0), out_t)
451 vert2, in_t = _get_vt((i+1) % len(self.
points))
452 cloned.add_point(vert2, in_t,
NVector(0, 0))
462 if len(other.vertices) != len(self.
vertices):
470 for vlist_name
in [
"vertices",
"in_tangents",
"out_tangents"]:
471 vlist = getattr(self, vlist_name)
472 olist = getattr(other, vlist_name)
473 out = getattr(bez, vlist_name)
474 for v, o
in zip(vlist, olist):
475 out.append(v.lerp(o, t))
485 length += (v-last).length
488 length += (last-self.
vertices[0]).length