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()
46 return self.
bezierbezier.in_tangents[self.
indexindex]
50 self.
bezierbezier.in_tangents[self.
indexindex] = point
54 return self.
bezierbezier.out_tangents[self.
indexindex]
58 self.
bezierbezier.out_tangents[self.
indexindex] = point
96 return len(self.
bezierbezier.vertices)
99 if isinstance(key, slice):
104 return self.
pointpoint(key)
107 for i
in range(len(self)):
108 yield self.
pointpoint(i)
111 if isinstance(point, NVector):
112 self.
bezierbezier.add_point(point.clone())
114 bpt = point.relative()
115 self.
bezierbezier.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.
closedclosed
150 clone.in_tangents = [p.clone()
for p
in self.
in_tangentsin_tangents]
151 clone.out_tangents = [p.clone()
for p
in self.
out_tangentsout_tangents]
152 clone.vertices = [p.clone()
for p
in self.
verticesvertices]
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
165 self.
verticesvertices.insert(index, pos)
166 self.
in_tangentsin_tangents.insert(index, inp.clone())
167 self.
out_tangentsout_tangents.insert(index, outp.clone())
175 Appends a point to the curve
183 Appends a point with symmetrical tangents
192 @returns @c self, for easy chaining
194 self.
closedclosed = closed
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_split(t)
258 for j
in range(i+2, len(self.
verticesvertices)):
261 seg1.add_point(split1[0], self.
in_tangentsin_tangents[i].
clone(), split1[1])
262 seg1.add_point(split1[3], split1[2], split2[1])
264 seg2.insert_point(0, split2[0], split1[2], split2[1])
265 seg2.insert_point(1, split2[3], split2[2], self.
out_tangentsout_tangents[i+1].
clone())
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
278 copy.add_point(self.
verticesvertices[0])
280 return copy.segment(t1, t2)
296 seg1, seg2 = self.
split_atsplit_at(t1)
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):
309 seg1, seg2 = self.
split_atsplit_at(t1)
314 self.
verticesvertices = seg1.vertices[:-1]
315 self.
in_tangentsin_tangents = seg1.in_tangents[:-1]
318 for t2
in positions[1:]:
320 seg1, seg2 = seg2.split_at(t)
322 self.
verticesvertices += seg1.vertices[:-1]
323 self.
in_tangentsin_tangents += seg1.in_tangents[:-1]
326 self.
verticesvertices += seg2.vertices
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_pointadd_point(vertices[0], in_tangents[0], split1[1])
349 self.
add_pointadd_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):
403 return len(self.
verticesvertices)-2, 1
410 return i, (t - (i/n)) * n
414 Reverses the Bezier curve
417 out_tangents = list(reversed(self.
in_tangentsin_tangents))
418 in_tangents = list(reversed(self.
out_tangentsout_tangents))
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.
closedclosed
435 round_corner = 0.5519
437 def _get_vt(closest_index):
438 closer_v = self.
verticesvertices[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.
verticesvertices):
446 if not self.
closedclosed
and (i == 0
or i == len(self.
pointspoints) - 1):
447 cloned.points.append(self.
pointspoints[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.
pointspoints))
452 cloned.add_point(vert2, in_t,
NVector(0, 0))
462 if len(other.vertices) != len(self.
verticesvertices):
468 bez.closed = self.
closedclosed
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.
verticesvertices[0]).length
493 def __init__(self, p0: NVector, p1: NVector, p2: NVector, p3: NVector):
494 self.a, self.b, self.c, self.
dd = self.
coefficientscoefficients(p0, p1, p2, p3)
498 def coeff3(p0: NVector, p1: NVector, p2: NVector, p3: NVector) -> NVector:
500 Coefficient of the cubic term
502 return p0 - p1 * 3 + p2 * 3 - p3
505 def coeff2(p0: NVector, p1: NVector, p2: NVector, p3: NVector) -> NVector:
507 Coefficient of the quadratic term
509 return -p0 * 3 + p1 * 6 - p2 * 3
512 def coeff1(p0: NVector, p1: NVector, p2: NVector, p3: NVector) -> NVector:
514 Coefficient of the linear term
516 return p0 * 3 - p1 * 3
519 def coeff0(p0: NVector, p1: NVector, p2: NVector, p3: NVector) -> NVector:
521 Coefficient of the constant term
528 Returns a tuble (a, b, c, d) such that
530 `a t**3 + b t**2 + c t + d = 0`
533 CubicBezierSegment.coeff3(p0, p1, p2, p3),
534 CubicBezierSegment.coeff2(p0, p1, p2, p3),
535 CubicBezierSegment.coeff1(p0, p1, p2, p3),
536 CubicBezierSegment.coeff0(p0, p1, p2, p3),
539 def solve(self, t: float) -> NVector:
540 return ((self.a * t + self.b) * t + self.c) * t + self. d
542 def length(self, steps: int = 20) -> float:
546 for i
in range(1, steps+1):
548 q = self.
solvesolve(t)
def clone(self)
Returns a copy of the object.
Base class for mapping Python classes into Lottie JSON objects.
def clone(self)
Returns a copy of the object.
Lottie <-> Python property mapper.
def __init__(self, bezier, index)
def smooth(cls, point, in_tangent)
def __init__(self, vertex, in_tangent=None, out_tangent=None)
def from_absolute(cls, point, in_tangent=None, out_tangent=None)
def __getitem__(self, key)
def __init__(self, bezier, absolute=False)
vertices
Bezier curve vertices.
def reverse(self)
Reverses the Bezier curve.
def split_at(self, t)
Get two pieces out of a Bezier curve.
def add_smooth_point(self, pos, inp)
Appends a point with symmetrical tangents.
def rounded(self, round_distance)
def segment(self, t1, t2)
Splits a Bezier in two points and returns the segment between the.
def _solve_bezier(self, t, points)
def split_self_multi(self, positions)
Adds more points to the Bezier.
def clone(self)
Returns a copy of the object.
def _split_segment(self, t, cub)
def _solve_bezier_coeff(self, i, n, t)
def _solve_bezier_step(self, t, points)
closed
Closed property of shape.
def split_each_segment(self)
Adds a point in the middle of the segment between every pair of points in the Bezier.
def split_self_chunks(self, n_chunks)
Adds points the Bezier, splitting it into n_chunks additional chunks.
def insert_point(self, index, pos, inp=NVector(0, 0), outp=NVector(0, 0))
Inserts a point at the given index.
def close(self, closed=True)
Updates self.closed.
points
More convent way to access points.
def tangent_angle_at(self, t)
def add_point(self, pos, inp=NVector(0, 0), outp=NVector(0, 0))
Appends a point to the curve.
in_tangents
Cubic bezier handles for the segments before each vertex.
def _bezier_points(self, i, optimize)
out_tangents
Cubic bezier handles for the segments after each vertex.
float length(self, int steps=20)
def coefficients(NVector p0, NVector p1, NVector p2, NVector p3)
Returns a tuble (a, b, c, d) such that.
NVector solve(self, float t)
NVector coeff2(NVector p0, NVector p1, NVector p2, NVector p3)
Coefficient of the quadratic term.
NVector coeff1(NVector p0, NVector p1, NVector p2, NVector p3)
Coefficient of the linear term.
def __init__(self, NVector p0, NVector p1, NVector p2, NVector p3)
NVector coeff3(NVector p0, NVector p1, NVector p2, NVector p3)
Coefficient of the cubic term.
NVector coeff0(NVector p0, NVector p1, NVector p2, NVector p3)
Coefficient of the constant term.