python-lottie  0.6.11+devcecd248
A framework to work with lottie files and telegram animated stickers (tgs)
ellipse.py
Go to the documentation of this file.
1 import math
2 
3 from ..nvector import NVector, PolarVector
4 from ..objects.bezier import BezierPoint
5 
6 
7 ## @todo Just output a Bezier object
8 class Ellipse:
9  def __init__(self, center, radii, xrot):
10  """
11  @param center 2D vector, center of the ellipse
12  @param radii 2D vector, x/y radius of the ellipse
13  @param xrot Angle between the main axis of the ellipse and the x axis (in radians)
14  """
15  self.center = center
16  self.radii = radii
17  self.xrot = xrot
18 
19  def point(self, t):
20  return NVector(
21  self.center[0]
22  + self.radii[0] * math.cos(self.xrot) * math.cos(t)
23  - self.radii[1] * math.sin(self.xrot) * math.sin(t),
24 
25  self.center[1]
26  + self.radii[0] * math.sin(self.xrot) * math.cos(t)
27  + self.radii[1] * math.cos(self.xrot) * math.sin(t)
28  )
29 
30  def derivative(self, t):
31  return NVector(
32  - self.radii[0] * math.cos(self.xrot) * math.sin(t)
33  - self.radii[1] * math.sin(self.xrot) * math.cos(t),
34 
35  - self.radii[0] * math.sin(self.xrot) * math.sin(t)
36  + self.radii[1] * math.cos(self.xrot) * math.cos(t)
37  )
38 
39  def to_bezier(self, anglestart, angle_delta):
40  points = []
41  angle1 = anglestart
42  angle_left = abs(angle_delta)
43  step = math.pi / 2
44  sign = -1 if anglestart+angle_delta < angle1 else 1
45  tolerance = math.pi / 100
46  if angle_left % step > tolerance:
47  step = angle_left / max(1, round(angle_left / step))
48 
49  # We need to fix the first handle
50  firststep = min(angle_left, step) * sign
51  alpha = self._alpha(firststep)
52  q1 = self.derivative(angle1) * alpha
53  points.append(BezierPoint(self.point(angle1), NVector(0, 0), q1))
54 
55  # Then we iterate until the angle has been completed
56  half_step = step / 2
57  while True:
58  if angle_left < half_step:
59  break
60 
61  lstep = min(angle_left, step)
62  step_sign = lstep * sign
63  angle2 = angle1 + step_sign
64  angle_left -= abs(lstep)
65 
66  alpha = self._alpha(step_sign)
67  p2 = self.point(angle2)
68  q2 = self.derivative(angle2) * alpha
69 
70  points.append(BezierPoint(p2, -q2, q2))
71  angle1 = angle2
72 
73  return points
74 
75  def _alpha(self, step):
76  return math.sin(step) * (math.sqrt(4+3*math.tan(step/2)**2) - 1) / 3
77 
78  @classmethod
79  def from_svg_arc(cls, start, rx, ry, xrot, large, sweep, dest):
80  rx = abs(rx)
81  ry = abs(ry)
82 
83  x1 = start[0]
84  y1 = start[1]
85  x2 = dest[0]
86  y2 = dest[1]
87  phi = math.pi * xrot / 180
88 
89  x1p, y1p = _matrix_mul(phi, (start-dest)/2, -1)
90 
91  cr = x1p ** 2 / rx**2 + y1p**2 / ry**2
92  if cr > 1:
93  s = math.sqrt(cr)
94  rx *= s
95  ry *= s
96 
97  dq = rx**2 * y1p**2 + ry**2 * x1p**2
98  pq = (rx**2 * ry**2 - dq) / dq
99  cpm = math.sqrt(max(0, pq))
100  if large == sweep:
101  cpm = -cpm
102  cp = NVector(cpm * rx * y1p / ry, -cpm * ry * x1p / rx)
103  c = _matrix_mul(phi, cp) + NVector((x1+x2)/2, (y1+y2)/2)
104  theta1 = _angle(NVector(1, 0), NVector((x1p - cp[0]) / rx, (y1p - cp[1]) / ry))
105  deltatheta = _angle(
106  NVector((x1p - cp[0]) / rx, (y1p - cp[1]) / ry),
107  NVector((-x1p - cp[0]) / rx, (-y1p - cp[1]) / ry)
108  ) % (2*math.pi)
109 
110  if not sweep and deltatheta > 0:
111  deltatheta -= 2*math.pi
112  elif sweep and deltatheta < 0:
113  deltatheta += 2*math.pi
114 
115  return cls(c, NVector(rx, ry), phi), theta1, deltatheta
116 
117 
118 def _matrix_mul(phi, p, sin_mul=1):
119  c = math.cos(phi)
120  s = math.sin(phi) * sin_mul
121 
122  xr = c * p.x - s * p.y
123  yr = s * p.x + c * p.y
124  return NVector(xr, yr)
125 
126 
127 def _angle(u, v):
128  arg = math.acos(max(-1, min(1, u.dot(v) / (u.length * v.length))))
129  if u[0] * v[1] - u[1] * v[0] < 0:
130  return -arg
131  return arg
lottie.utils.ellipse.Ellipse.center
center
Definition: ellipse.py:15
lottie.utils.ellipse.Ellipse.derivative
def derivative(self, t)
Definition: ellipse.py:30
lottie.utils.ellipse.Ellipse.radii
radii
Definition: ellipse.py:16
lottie.utils.ellipse.Ellipse
Definition: ellipse.py:8
lottie.utils.ellipse.Ellipse.from_svg_arc
def from_svg_arc(cls, start, rx, ry, xrot, large, sweep, dest)
Definition: ellipse.py:79
lottie.utils.ellipse.Ellipse.point
def point(self, t)
Definition: ellipse.py:19
lottie.utils.ellipse.Ellipse._alpha
def _alpha(self, step)
Definition: ellipse.py:75
lottie.objects.bezier.BezierPoint
Definition: bezier.py:6
lottie.utils.ellipse.Ellipse.to_bezier
def to_bezier(self, anglestart, angle_delta)
Definition: ellipse.py:39
lottie.utils.ellipse.Ellipse.xrot
xrot
Definition: ellipse.py:17
lottie.nvector.NVector
Definition: nvector.py:9
lottie.utils.ellipse.Ellipse.__init__
def __init__(self, center, radii, xrot)
Definition: ellipse.py:9