Initial Commit

This commit is contained in:
OmniLottie
2026-03-01 21:36:54 +08:00
commit a386c803e1
199 changed files with 42253 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
from..nvector import NVector
# FABRIK
class Chain:
def __init__(self, tail, fixed_tail=True, tolerance=0.5, max_iter=8):
self.joints = [tail.clone()]
self.fixed_tail = fixed_tail
self.lengths = []
self.total_length = 0
self.tolerance = tolerance
self.max_iter = max_iter
def add_joint(self, point):
length = (point - self.joints[-1]).length
self.lengths.append(length)
self.total_length += length
self.joints.append(point.clone())
def add_joints(self, head, n):
delta = head - self.joints[-1]
self.total_length += delta.length
segment = delta / n
seglen = segment.length
for i in range(n):
self.lengths.append(seglen)
self.joints.append(self.joints[-1] + segment)
def backward(self, target):
"""!
target -> -> start
"""
self.joints[-1] = target
for i in range(len(self.joints)-2, -1, -1):
r = self.joints[i+1] - self.joints[i]
l = self.lengths[i] / r.length
self.joints[i] = self.joints[i+1].lerp(self.joints[i], l)
def forward(self, target):
"""!
start -> -> tail
"""
self.joints[0] = target
for i in range(0, len(self.joints)-1):
r = self.joints[i+1] - self.joints[i]
l = self.lengths[i] / r.length
self.joints[i+1] = self.joints[i].lerp(self.joints[i+1], l)
def reach(self, target):
if not self.fixed_tail:
self.backward(target)
return
distance = (target - self.joints[0]).length
if distance >= self.total_length:
for i in range(len(self.joints)-1):
r = target - self.joints[i]
l = self.lengths[i] / r.length
self.joints[i+1] = self.joints[i].lerp(target, l)
return
base = self.joints[0]
distance = (target - self.joints[-1]).length
n_it = 0
while distance > self.tolerance and n_it < self.max_iter:
self.backward(target)
self.forward(base)
distance = (target - self.joints[-1]).length
n_it += 1
class Octopus:
def __init__(self, master):
self.chains = {"master": master}
self.master = master
@property
def base(self):
return self.master.joints[-1]
def add_chain(self, name):
ch = Chain(self.base)
self.chains[name] = ch
return ch
def reach(self, target_map):
centroid = NVector(0, 0)
for chain, target in target_map.items():
self.chains[chain].backward(target)
centroid += self.chains[chain].joints[0]
centroid /= len(target_map)
self.master.reach(centroid)
for chain in target_map.keys():
self.chains[chain].forward(self.base)