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

1from ..nvector import NVector 

2 

3 

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 

13 

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()) 

19 

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) 

28 

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) 

38 

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) 

48 

49 def reach(self, target): 

50 if not self.fixed_tail: 

51 self.backward(target) 

52 return 

53 

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 

61 

62 base = self.joints[0] 

63 

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 

71 

72 

73class Octopus: 

74 def __init__(self, master): 

75 self.chains = {"master": master} 

76 self.master = master 

77 

78 @property 

79 def base(self): 

80 return self.master.joints[-1] 

81 

82 def add_chain(self, name): 

83 ch = Chain(self.base) 

84 self.chains[name] = ch 

85 return ch 

86 

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) 

93 

94 self.master.reach(centroid) 

95 

96 for chain in target_map.keys(): 

97 self.chains[chain].forward(self.base)