mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
Improve TransformMatchingString to match longest common substrings by default
This commit is contained in:
parent
b8fe7b0172
commit
fab917ccee
1 changed files with 51 additions and 19 deletions
|
@ -1,19 +1,15 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import itertools as it
|
import itertools as it
|
||||||
|
from difflib import SequenceMatcher
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from manimlib.animation.composition import AnimationGroup
|
from manimlib.animation.composition import AnimationGroup
|
||||||
from manimlib.animation.fading import FadeInFromPoint
|
from manimlib.animation.fading import FadeInFromPoint
|
||||||
from manimlib.animation.fading import FadeOutToPoint
|
from manimlib.animation.fading import FadeOutToPoint
|
||||||
from manimlib.animation.fading import FadeTransformPieces
|
|
||||||
from manimlib.animation.transform import Transform
|
from manimlib.animation.transform import Transform
|
||||||
from manimlib.mobject.mobject import Mobject
|
from manimlib.mobject.mobject import Mobject
|
||||||
from manimlib.mobject.mobject import Group
|
|
||||||
from manimlib.mobject.svg.string_mobject import StringMobject
|
|
||||||
from manimlib.mobject.types.vectorized_mobject import VGroup
|
|
||||||
from manimlib.mobject.types.vectorized_mobject import VMobject
|
from manimlib.mobject.types.vectorized_mobject import VMobject
|
||||||
|
from manimlib.mobject.svg.string_mobject import StringMobject
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
@ -131,28 +127,64 @@ class TransformMatchingStrings(TransformMatchingParts):
|
||||||
target: StringMobject,
|
target: StringMobject,
|
||||||
matched_keys: Iterable[str] = [],
|
matched_keys: Iterable[str] = [],
|
||||||
key_map: dict[str, str] = dict(),
|
key_map: dict[str, str] = dict(),
|
||||||
matched_pairs: Iterable[tuple[Mobject, Mobject]] = [],
|
matched_pairs: Iterable[tuple[VMobject, VMobject]] = [],
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
matched_pairs = list(matched_pairs) + [
|
matched_pairs = [
|
||||||
*[(source[key], target[key]) for key in matched_keys],
|
*matched_pairs,
|
||||||
*[(source[key1], target[key2]) for key1, key2 in key_map.items()],
|
*self.matching_blocks(source, target, matched_keys, key_map),
|
||||||
*[
|
|
||||||
(source[substr], target[substr])
|
|
||||||
for substr in [
|
|
||||||
*source.get_specified_substrings(),
|
|
||||||
*target.get_specified_substrings(),
|
|
||||||
*source.get_symbol_substrings(),
|
|
||||||
*target.get_symbol_substrings(),
|
|
||||||
]
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
source, target,
|
source, target,
|
||||||
matched_pairs=matched_pairs,
|
matched_pairs=matched_pairs,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def matching_blocks(
|
||||||
|
self,
|
||||||
|
source: StringMobject,
|
||||||
|
target: StringMobject,
|
||||||
|
matched_keys: Iterable[str],
|
||||||
|
key_map: dict[str, str]
|
||||||
|
) -> list[tuple[VMobject, VMobject]]:
|
||||||
|
syms1 = source.get_symbol_substrings()
|
||||||
|
syms2 = target.get_symbol_substrings()
|
||||||
|
counts1 = list(map(source.substr_to_path_count, syms1))
|
||||||
|
counts2 = list(map(target.substr_to_path_count, syms2))
|
||||||
|
|
||||||
|
# Start with user specified matches
|
||||||
|
blocks = [(source[key], target[key]) for key in matched_keys]
|
||||||
|
blocks += [(source[key1], target[key2]) for key1, key2 in key_map.items()]
|
||||||
|
|
||||||
|
# Nullify any intersections with those matches in the two symbol lists
|
||||||
|
for sub_source, sub_target in blocks:
|
||||||
|
for i in range(len(syms1)):
|
||||||
|
if source[i] in sub_source.family_members_with_points():
|
||||||
|
syms1[i] = "Null1"
|
||||||
|
for j in range(len(syms2)):
|
||||||
|
if target[j] in sub_target.family_members_with_points():
|
||||||
|
syms2[j] = "Null2"
|
||||||
|
|
||||||
|
# Group together longest matching substrings
|
||||||
|
while True:
|
||||||
|
matcher = SequenceMatcher(None, syms1, syms2)
|
||||||
|
match = matcher.find_longest_match(0, len(syms1), 0, len(syms2))
|
||||||
|
if match.size == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
i1 = sum(counts1[:match.a])
|
||||||
|
i2 = sum(counts2[:match.b])
|
||||||
|
size = sum(counts1[match.a:match.a + match.size])
|
||||||
|
|
||||||
|
blocks.append((source[i1:i1 + size], target[i2:i2 + size]))
|
||||||
|
|
||||||
|
for i in range(match.size):
|
||||||
|
syms1[match.a + i] = "Null1"
|
||||||
|
syms2[match.b + i] = "Null2"
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
|
||||||
|
|
||||||
class TransformMatchingTex(TransformMatchingStrings):
|
class TransformMatchingTex(TransformMatchingStrings):
|
||||||
"""Alias for TransformMatchingStrings"""
|
"""Alias for TransformMatchingStrings"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue