Change how joint_angles are computed

This commit is contained in:
Grant Sanderson 2024-08-21 17:19:42 -05:00
parent 11df256369
commit d5575cf1ef

View file

@ -13,6 +13,7 @@ from manimlib.constants import DEFAULT_STROKE_WIDTH
from manimlib.constants import DEGREES from manimlib.constants import DEGREES
from manimlib.constants import JOINT_TYPE_MAP from manimlib.constants import JOINT_TYPE_MAP
from manimlib.constants import ORIGIN, OUT from manimlib.constants import ORIGIN, OUT
from manimlib.constants import PI
from manimlib.constants import TAU from manimlib.constants import TAU
from manimlib.mobject.mobject import Mobject from manimlib.mobject.mobject import Mobject
from manimlib.mobject.mobject import Group from manimlib.mobject.mobject import Group
@ -654,7 +655,7 @@ class VMobject(Mobject):
return self return self
def is_smooth(self) -> bool: def is_smooth(self) -> bool:
dots = np.cos(self.get_joint_angles()[0::2, :]) dots = np.cos(self.get_joint_angles()[0::2])
return bool((dots > 1 - 1e-3).all()) return bool((dots > 1 - 1e-3).all())
def change_anchor_mode(self, mode: str) -> Self: def change_anchor_mode(self, mode: str) -> Self:
@ -1167,18 +1168,19 @@ class VMobject(Mobject):
product between tangent vectors at a joint product between tangent vectors at a joint
""" """
if not self.needs_new_joint_angles and not refresh: if not self.needs_new_joint_angles and not refresh:
return self.data["joint_angle"] return self.data["joint_angle"][:, 0]
if "joint_angle" in self.locked_data_keys: if "joint_angle" in self.locked_data_keys:
return self.data["joint_angle"] return self.data["joint_angle"][:, 0]
self.needs_new_joint_angles = False self.needs_new_joint_angles = False
self._data_has_changed = True self._data_has_changed = True
points = self.get_points() # Rotate points such that positive z direction is the normal
points = self.get_points() @ rotation_between_vectors(OUT, self.get_unit_normal())
if len(points) < 3: if len(points) < 3:
return self.data["joint_angle"] return self.data["joint_angle"][:, 0]
# Find all the unit tangent vectors at each joint # Find all the unit tangent vectors at each joint
a0, h, a1 = points[0:-1:2], points[1::2], points[2::2] a0, h, a1 = points[0:-1:2], points[1::2], points[2::2]
@ -1201,23 +1203,19 @@ class VMobject(Mobject):
for start, end in zip(starts, ends): for start, end in zip(starts, ends):
if start >= end - 2: if start >= end - 2:
continue continue
if self.consider_points_equal(points[start], points[end]): if (points[start] == points[end]).all():
v_in[start] = v_out[end - 1] v_in[start] = v_out[end - 1]
v_out[end] = v_in[start + 1] v_out[end] = v_in[start + 1]
else: else:
v_in[start] = v_out[start] v_in[start] = v_out[start]
v_out[end] = v_in[end] v_out[end] = v_in[end]
# Compute dot and cross products # Find the angles between vectors into each vertex, and out of it
in_dot_out = (v_in * v_out).sum(1) angles_in = np.arctan2(v_in[:, 1], v_in[:, 0])
norm_product = np.sqrt((v_in * v_in).sum(1) * (v_out * v_out).sum(1)) angles_out = np.arctan2(v_out[:, 1], v_out[:, 0])
angles = np.arccos(fdiv(in_dot_out, norm_product, zero_over_zero_value=1)) angle_diffs = angles_out - angles_in
self.data["joint_angle"][:, 0] = (angle_diffs + PI) % TAU - PI
crosses = cross(v_in, v_out) return self.data["joint_angle"][:, 0]
unit_normal = self.get_unit_normal()
angles[(crosses * unit_normal[np.newaxis, :]).sum(1) < 0] *= -1
self.data["joint_angle"][:, 0] = angles
return self.data["joint_angle"]
def lock_matching_data(self, vmobject1: VMobject, vmobject2: VMobject) -> Self: def lock_matching_data(self, vmobject1: VMobject, vmobject2: VMobject) -> Self:
for mob in [self, vmobject1, vmobject2]: for mob in [self, vmobject1, vmobject2]: