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