1use glam::{DVec3, dvec2};
2use rand::{SeedableRng, seq::SliceRandom};
3use ranim::{
4 animation::transform::TransformAnimSchedule, color::palettes::manim, components::Anchor,
5 items::vitem::Rectangle, prelude::*, timeline::TimeMark, utils::rate_functions::linear,
6};
7
8#[scene]
9struct SelectiveSortScene(pub usize);
10
11impl TimelineConstructor for SelectiveSortScene {
12 fn construct(self, timeline: &RanimTimeline, _camera: &mut Rabject<CameraFrame>) {
13 let num = self.0;
14
15 let frame_size = dvec2(8.0 * 16.0 / 9.0, 8.0);
16 let padded_frame_size = frame_size * 0.9;
17
18 let anim_step_duration = 15.0 / num.pow(2) as f64;
19
20 let width_unit = padded_frame_size.x / num as f64;
21 let height_unit = padded_frame_size.y / num as f64;
22
23 let mut rng = rand_chacha::ChaChaRng::seed_from_u64(114514);
24 let mut heights = (1..=num)
25 .map(|x| x as f64 * height_unit)
26 .collect::<Vec<f64>>();
27 heights.shuffle(&mut rng);
28
29 let padded_frame_bl = dvec2(padded_frame_size.x / -2.0, padded_frame_size.y / -2.0);
30 let mut rects = heights
31 .iter()
32 .enumerate()
33 .map(|(i, &height)| {
34 let mut rect = Rectangle(width_unit, height).build();
35 let target_bc_coord = padded_frame_bl.extend(0.0)
36 + DVec3::X * (width_unit * i as f64 + width_unit / 2.0);
37 rect.scale(DVec3::splat(0.8))
38 .put_anchor_on(Anchor::edge(0, -1, 0), target_bc_coord)
39 .set_color(manim::WHITE)
40 .set_stroke_width(0.0)
41 .set_fill_opacity(0.5);
42 timeline.insert(rect)
43 })
44 .collect::<Vec<_>>();
45
46 let shift_right = DVec3::X * width_unit;
47 for i in 0..num - 1 {
48 timeline.play(
49 rects[i]
50 .transform(|data| {
51 data.set_color(manim::RED_C).set_fill_opacity(0.5);
52 })
53 .with_duration(anim_step_duration)
54 .with_rate_func(linear)
55 .apply(),
56 );
57 for j in i + 1..num {
58 timeline.play(
59 rects[j]
60 .transform(|data| {
61 data.set_color(manim::BLUE_C).set_fill_opacity(0.5);
62 })
63 .with_duration(anim_step_duration)
64 .with_rate_func(linear)
65 .apply(),
66 );
67 timeline.sync();
68
69 if heights[i] > heights[j] {
70 timeline.play(
71 rects[i]
72 .transform(|data| {
73 data.shift(shift_right * (j - i) as f64)
74 .set_color(manim::BLUE_C)
75 .set_fill_opacity(0.5);
76 })
77 .with_duration(anim_step_duration)
78 .with_rate_func(linear)
79 .apply(),
80 );
81 timeline.play(
82 rects[j]
83 .transform(|data| {
84 data.shift(-shift_right * (j - i) as f64)
85 .set_color(manim::RED_C)
86 .set_fill_opacity(0.5);
87 })
88 .with_duration(anim_step_duration)
89 .with_rate_func(linear)
90 .apply(),
91 );
92 timeline.sync();
93 heights.swap(i, j);
94 rects.swap(i, j);
95 }
96 timeline.play(
97 rects[j]
98 .transform(|data| {
99 data.set_color(manim::WHITE).set_fill_opacity(0.5);
100 })
101 .with_duration(anim_step_duration)
102 .with_rate_func(linear)
103 .apply(),
104 );
105 timeline.sync();
106 }
107 timeline.play(
108 rects[i]
109 .transform(|data| {
110 data.set_color(manim::WHITE).set_fill_opacity(0.5);
111 })
112 .with_duration(anim_step_duration)
113 .with_rate_func(linear)
114 .apply(),
115 );
116 timeline.sync();
117 }
118
119 timeline.insert_time_mark(
120 timeline.duration_secs() / 2.0,
121 TimeMark::Capture(format!("preview-{num}.png")),
122 );
123 }
124}
125
126fn main() {
127 render_scene(
128 SelectiveSortScene(10),
129 &AppOptions {
130 output_filename: "output-10.mp4",
131 ..Default::default()
132 },
133 );
134 render_scene(
135 SelectiveSortScene(100),
136 &AppOptions {
137 output_filename: "output-100.mp4",
138 ..Default::default()
139 },
140 );
141}
142