Coverage for lib/lottie/utils/ik.py: 0%
72 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-20 16:17 +0100
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-20 16:17 +0100
1from ..nvector import NVector
4# FABRIK
5class Chain:
6 def __init__(self, tail, fixed_tail=True, tolerance=0.5, max_iter=8):
7 self.joints = [tail.clone()]
8 self.fixed_tail = fixed_tail
9 self.lengths = []
10 self.total_length = 0
11 self.tolerance = tolerance
12 self.max_iter = max_iter
14 def add_joint(self, point):
15 length = (point - self.joints[-1]).length
16 self.lengths.append(length)
17 self.total_length += length
18 self.joints.append(point.clone())
20 def add_joints(self, head, n):
21 delta = head - self.joints[-1]
22 self.total_length += delta.length
23 segment = delta / n
24 seglen = segment.length
25 for i in range(n):
26 self.lengths.append(seglen)
27 self.joints.append(self.joints[-1] + segment)
29 def backward(self, target):
30 """!
31 target -> -> start
32 """
33 self.joints[-1] = target
34 for i in range(len(self.joints)-2, -1, -1):
35 r = self.joints[i+1] - self.joints[i]
36 l = self.lengths[i] / r.length
37 self.joints[i] = self.joints[i+1].lerp(self.joints[i], l)
39 def forward(self, target):
40 """!
41 start -> -> tail
42 """
43 self.joints[0] = target
44 for i in range(0, len(self.joints)-1):
45 r = self.joints[i+1] - self.joints[i]
46 l = self.lengths[i] / r.length
47 self.joints[i+1] = self.joints[i].lerp(self.joints[i+1], l)
49 def reach(self, target):
50 if not self.fixed_tail:
51 self.backward(target)
52 return
54 distance = (target - self.joints[0]).length
55 if distance >= self.total_length:
56 for i in range(len(self.joints)-1):
57 r = target - self.joints[i]
58 l = self.lengths[i] / r.length
59 self.joints[i+1] = self.joints[i].lerp(target, l)
60 return
62 base = self.joints[0]
64 distance = (target - self.joints[-1]).length
65 n_it = 0
66 while distance > self.tolerance and n_it < self.max_iter:
67 self.backward(target)
68 self.forward(base)
69 distance = (target - self.joints[-1]).length
70 n_it += 1
73class Octopus:
74 def __init__(self, master):
75 self.chains = {"master": master}
76 self.master = master
78 @property
79 def base(self):
80 return self.master.joints[-1]
82 def add_chain(self, name):
83 ch = Chain(self.base)
84 self.chains[name] = ch
85 return ch
87 def reach(self, target_map):
88 centroid = NVector(0, 0)
89 for chain, target in target_map.items():
90 self.chains[chain].backward(target)
91 centroid += self.chains[chain].joints[0]
92 centroid /= len(target_map)
94 self.master.reach(centroid)
96 for chain in target_map.keys():
97 self.chains[chain].forward(self.base)