Preview App bubble_sort 示例输出 bubble_sort 示例输出
use rand::{SeedableRng, seq::SliceRandom};
use ranim::{
    anims::morph::MorphAnim,
    color::palettes::manim,
    core::animation::{compose::sequence::AnimSequence, eval::StaticAnim},
    glam::{DVec3, dvec2, dvec3},
    items::vitem::{VItem, geometry::Rectangle},
    prelude::*,
    utils::rate_functions::linear,
};

fn bubble_sort(r: &mut RanimScene, num: usize) {
    let frame_size = dvec2(8.0 * 16.0 / 9.0, 8.0);
    let padded_frame_size = frame_size * 0.9;

    let anim_step_duration = 15.0 / num.pow(2) as f64;

    let width_unit = padded_frame_size.x / num as f64;
    let height_unit = padded_frame_size.y / num as f64;

    let mut rng = rand_chacha::ChaChaRng::seed_from_u64(114514);
    let mut heights = (1..=num)
        .map(|x| x as f64 * height_unit)
        .collect::<Vec<f64>>();
    heights.shuffle(&mut rng);

    let padded_frame_bl = dvec2(padded_frame_size.x / -2.0, padded_frame_size.y / -2.0);
    let mut rects = heights
        .iter()
        .enumerate()
        .map(|(i, &height)| {
            let target_bc_coord =
                padded_frame_bl.extend(0.0) + DVec3::X * (width_unit * i as f64 + width_unit / 2.0);
            let rect = Rectangle::new(width_unit, height).with(|rect| {
                rect.stroke_width = 0.0;
                rect.set_fill_color(manim::WHITE.with_alpha(0.5))
                    .scale_axes(dvec2(0.8, 0.8));
            });
            let mut rect = VItem::from(rect);
            rect.move_anchor_to(AabbPoint(dvec3(0.0, -1.0, 0.0)), target_bc_coord);
            let sequence = seq![rect.show()];
            (sequence, rect)
        })
        .collect::<Vec<_>>();

    let sync = |rects: &mut [(AnimSequence, VItem)]| {
        let target = rects
            .iter()
            .map(|(sequence, _)| sequence.cursor_sec())
            .fold(0.0, f64::max);
        rects.iter_mut().for_each(|(sequence, _)| {
            sequence.hold_to(target);
        });
    };
    let shift_right = DVec3::X * width_unit;

    for i in (1..num).rev() {
        for j in 0..i {
            for (sequence, rect) in rects.get_disjoint_mut([j, j + 1]).unwrap() {
                sequence.push(
                    rect.morph(|rect| {
                        rect.set_fill_color(manim::BLUE_C.with_alpha(0.5));
                    })
                    .with_duration(anim_step_duration)
                    .with_rate_func(linear),
                );
            }

            if heights[j] > heights[j + 1] {
                for ((sequence, rect), shift) in rects
                    .get_disjoint_mut([j, j + 1])
                    .unwrap()
                    .into_iter()
                    .zip([shift_right, -shift_right])
                {
                    sequence.push(
                        rect.morph(|rect| {
                            rect.shift(shift);
                        })
                        .with_duration(anim_step_duration)
                        .with_rate_func(linear),
                    );
                }
                sync(&mut rects);
                heights.swap(j, j + 1);
                rects.swap(j, j + 1);
            }

            for (sequence, rect) in rects.get_disjoint_mut([j, j + 1]).unwrap() {
                sequence.push(
                    rect.morph(|rect| {
                        rect.set_fill_color(manim::WHITE.with_alpha(0.5));
                    })
                    .with_duration(anim_step_duration)
                    .with_rate_func(linear),
                );
            }
            sync(&mut rects);
        }
    }

    let total_secs = rects[0].0.cursor_sec();
    let mut content = AnimStack::new();
    for (sequence, _) in rects {
        content.push(sequence);
    }
    r.play(CameraFrame::default().show().with_duration(total_secs));
    r.play(content);

    r.insert_time_mark(total_secs, TimeMark::Capture(format!("preview-{num}.png")));
}

#[scene]
#[wasm_demo_doc]
#[output(dir = "./output/bubble_sort")]
fn bubble_sort_10(r: &mut RanimScene) {
    bubble_sort(r, 10);
}

#[scene(name = "bubble_sort")]
#[wasm_demo_doc]
#[output(dir = "./output/bubble_sort")]
fn bubble_sort_100(r: &mut RanimScene) {
    bubble_sort(r, 100);
}