1mod draw_line;
2mod solver;
3
4pub use draw_line::VrellisAlgorithm;
5use serde::{Deserialize, Serialize};
6use std::{collections::VecDeque, f32::consts::PI};
7
8#[derive(Serialize, Deserialize, Debug, Clone)]
9pub enum VrellisShape {
10 Circle,
11 Triangle,
12 Square,
13 Parabola,
14 Polygon {
16 corners: Vec<(f32, f32)>,
17 },
18 Custom {
20 points: Vec<VrellisPoint>,
21 },
22}
23
24#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
25pub struct VrellisPoint {
26 pub n: u32,
27 pub x: u32,
28 pub y: u32,
29}
30
31#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
32pub enum VrellisColorMode {
33 Grayscale = 0,
34 Colorful = 1,
35 LayerMask = 2,
36}
37
38impl Default for VrellisShape {
39 fn default() -> Self {
40 Self::Circle
41 }
42}
43
44impl Default for VrellisPoint {
45 fn default() -> Self {
46 Self { n: 0, x: 0, y: 0 }
47 }
48}
49
50impl Default for VrellisColorMode {
51 fn default() -> Self {
52 Self::Grayscale
53 }
54}
55
56impl VrellisShape {
57 pub fn sample(&self, num: u32, width: u32, height: u32) -> Vec<VrellisPoint> {
58 assert!(num > 7, "too less samples!");
59 let mut out = Vec::with_capacity(num as usize);
60 match self {
61 VrellisShape::Circle => {
62 for n in 0..num {
63 let x = 1.0 + (2.0 * PI * n as f32 / num as f32).cos();
65 let y = 1.0 - (2.0 * PI * n as f32 / num as f32).sin();
66 out.push(VrellisPoint {
67 n,
68 x: (x * width as f32 / 2.0).round() as u32,
69 y: (y * height as f32 / 2.0).round() as u32,
70 })
71 }
72 }
73 VrellisShape::Triangle => {
74 let poly = Self::Polygon { corners: vec![(0.5, 1.0 - 3.0_f32.sqrt() / 2.0), (1.0, 1.0), (0.0, 1.0)] };
75 return poly.sample(num, width, height);
76 }
77 VrellisShape::Square => {
78 let poly = Self::Polygon { corners: vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] };
79 return poly.sample(num, width, height);
80 }
81 VrellisShape::Polygon { corners } => {
82 let mut shifted = VecDeque::from(corners.clone());
84 let head = shifted.pop_front().unwrap();
85 shifted.push_back(head);
86 let mut circumference = 0.0;
88 let mut temp_line = vec![];
89 for (a, b) in corners.iter().zip(shifted.iter()) {
90 let p1 = circumference;
91 circumference += ((a.0 - b.0).powf(2.0) + (a.1 - b.1).powf(2.0)).sqrt();
92 let p2 = circumference;
93 temp_line.push(VrellisLine { p1, p2, x1: a.0, y1: a.1, x2: b.0, y2: b.1 });
94 }
95 temp_line.iter_mut().for_each(|e| e.resize(circumference));
96 let mut edges = temp_line.into_iter();
98 let mut this_edge = edges.next().unwrap();
99 for n in 0..num {
100 let percent = n as f32 / num as f32;
101 while percent > this_edge.p2 {
102 match edges.next() {
103 Some(s) => {
104 this_edge = s;
105 }
106 None => {
107 return out;
108 }
109 }
110 }
111 let (x, y) = this_edge.get_percent_position(percent);
112 out.push(VrellisPoint { n, x: (x * width as f32).round() as u32, y: (y * height as f32).round() as u32 })
113 }
114 }
115 VrellisShape::Parabola => unimplemented!(),
116 VrellisShape::Custom { points } => return points.clone(),
117 }
118 return out;
119 }
120}
121
122struct VrellisLine {
123 p1: f32,
124 p2: f32,
125 x1: f32,
126 y1: f32,
127 x2: f32,
128 y2: f32,
129}
130
131impl VrellisLine {
132 fn resize(&mut self, c: f32) {
133 self.p1 /= c;
134 self.p2 /= c;
135 }
136 fn rescale_p(&self, p: f32) -> f32 {
137 (p - self.p1) / (self.p2 - self.p1)
138 }
139 fn percent_x(&self, p: f32) -> f32 {
140 self.x1 + self.rescale_p(p) * (self.x2 - self.x1)
141 }
142 fn percent_y(&self, p: f32) -> f32 {
143 self.y1 + self.rescale_p(p) * (self.y2 - self.y1)
144 }
145 fn get_percent_position(&self, p: f32) -> (f32, f32) {
146 assert!(self.p1 <= p && p <= self.p2);
147 (self.percent_x(p), self.percent_y(p))
148 }
149}