experimental SVG-based video rendering engine made for music videos. React to MIDI or arbitrary signals from your DAW through "probe" VSTs
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 223 lines 5.6 kB view raw
1use num::FromPrimitive; 2use serde::{Deserialize, Serialize}; 3 4use crate::{ 5 Point::{Center, Corner}, 6 Region, 7}; 8 9use super::Angle; 10 11#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)] 12#[cfg_attr(feature = "web", serde(tag = "type", content = "data"))] 13pub enum Point { 14 Corner(usize, usize), 15 Center(usize, usize), 16} 17 18impl Default for Point { 19 fn default() -> Self { 20 Self::Corner(0, 0) 21 } 22} 23 24impl Point { 25 pub fn coords(&self, cell_size: usize) -> (f32, f32) { 26 let (x, y) = self.xy::<f32>(); 27 let cell = cell_size as f32; 28 29 match self { 30 Point::Corner(..) => (x * cell, y * cell), 31 Point::Center(..) => (x * cell + cell / 2.0, y * cell + cell / 2.0), 32 } 33 } 34 35 pub fn as_centered(&self) -> Self { 36 match self { 37 Point::Corner(x, y) => Point::Center(*x, *y), 38 Point::Center(_, _) => *self, 39 } 40 } 41 42 pub fn as_corner(&self) -> Self { 43 match self { 44 Point::Center(x, y) => Point::Corner(*x, *y), 45 Point::Corner(_, _) => *self, 46 } 47 } 48 49 pub fn region(&self) -> Region { 50 Region::from((self.clone(), self.clone())) 51 } 52 53 pub fn with(&self, x: usize, y: usize) -> Self { 54 match self { 55 Point::Corner(..) => Point::Corner(x, y), 56 Point::Center(..) => Point::Center(x, y), 57 } 58 } 59 60 pub fn set(&mut self, x: usize, y: usize) { 61 *self = self.with(x, y); 62 } 63 64 pub fn set_x(&mut self, x: usize) { 65 self.set(x, self.y()); 66 } 67 68 pub fn with_x(&self, x: usize) -> Self { 69 self.with(x, self.y()) 70 } 71 72 pub fn increment_x(&mut self, by: isize) { 73 self.set_x(self.x().saturating_add_signed(by)); 74 } 75 76 pub fn set_y(&mut self, y: usize) { 77 self.set(self.x(), y); 78 } 79 80 pub fn increment_y(&mut self, by: isize) { 81 self.set_y(self.y().saturating_add_signed(by)); 82 } 83 84 pub fn with_y(&self, y: usize) -> Self { 85 self.with(self.x(), y) 86 } 87 88 pub fn xy<N: FromPrimitive>(&self) -> (N, N) { 89 let (x, y) = match self { 90 &Point::Corner(x, y) => (x, y), 91 &Point::Center(x, y) => (x, y), 92 }; 93 94 (N::from_usize(x).unwrap(), N::from_usize(y).unwrap()) 95 } 96 97 pub fn x(&self) -> usize { 98 self.xy().0 99 } 100 101 pub fn y(&self) -> usize { 102 self.xy().1 103 } 104 105 pub fn translated(&self, dx: i32, dy: i32) -> Self { 106 Self::from(( 107 (self.x() as i32 + dx) as usize, 108 (self.y() as i32 + dy) as usize, 109 )) 110 } 111 112 pub fn translated_by(&self, point: Point) -> Self { 113 Self::from((self.x() + point.x(), self.y() + point.y())) 114 } 115 116 pub fn translate(&mut self, dx: i32, dy: i32) { 117 *self = Self::from(( 118 (self.x() as i32 + dx) as usize, 119 (self.y() as i32 + dy) as usize, 120 )) 121 } 122 123 /// get SVG coordinates of the cell's center instead of its origin (top-left) 124 #[deprecated = "Use a CenterPoint instead (WIP)"] 125 pub fn center_coords(&self, cell_size: usize) -> (f32, f32) { 126 let (x, y) = self.coords(cell_size); 127 (x + cell_size as f32 / 2.0, y + cell_size as f32 / 2.0) 128 } 129 130 pub fn distance_to(&self, other: &Point) -> (usize, usize) { 131 ( 132 self.x().abs_diff(other.x()) + 1, 133 self.y().abs_diff(other.y()) + 1, 134 ) 135 } 136 137 pub fn rotated(&self, around: &Point, angle: Angle) -> Self { 138 let (dx, dy) = ( 139 self.x() as f32 - around.x() as f32, 140 self.y() as f32 - around.y() as f32, 141 ); 142 143 let (cos, sin) = angle.cos_sin(); 144 let new_x = dx * cos - dy * sin; 145 let new_y = dx * sin + dy * cos; 146 147 Self::from(( 148 (new_x + around.x() as f32) as usize, 149 (new_y + around.y() as f32) as usize, 150 )) 151 } 152} 153 154impl From<(usize, usize)> for Point { 155 fn from(value: (usize, usize)) -> Self { 156 Self::Corner(value.0, value.1) 157 } 158} 159 160impl From<(&usize, &usize)> for Point { 161 fn from(value: (&usize, &usize)) -> Self { 162 Self::Corner(*value.0, *value.1) 163 } 164} 165 166impl From<(i32, i32)> for Point { 167 fn from(value: (i32, i32)) -> Self { 168 Self::Corner(value.0 as usize, value.1 as usize) 169 } 170} 171 172impl PartialEq<(usize, usize)> for Point { 173 fn eq(&self, other: &(usize, usize)) -> bool { 174 self.xy() == other.clone() 175 } 176} 177 178impl Eq for Point {} 179 180impl std::fmt::Display for Point { 181 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 182 match self { 183 Point::Corner(x, y) => write!(f, "({x}, {y})"), 184 Point::Center(x, y) => write!(f, "[{x}, {y}]"), 185 } 186 } 187} 188 189impl std::fmt::Debug for Point { 190 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 191 match self { 192 Point::Corner(x, y) => write!(f, "({x}, {y})"), 193 Point::Center(x, y) => write!(f, "[{x}, {y}]"), 194 } 195 } 196} 197 198impl std::ops::Sub for Point { 199 type Output = (isize, isize); 200 201 fn sub(self, rhs: Point) -> Self::Output { 202 match (self, rhs) { 203 (Corner(..), Corner(..)) => {} 204 (Center(..), Center(..)) => {} 205 _ => panic!("Cannot subtract CornerPoint and CenterPoint"), 206 } 207 208 let (x1, y1) = self.xy::<isize>(); 209 let (x2, y2) = rhs.xy::<isize>(); 210 211 (x1 - x2, y1 - y2) 212 } 213} 214 215pub trait Norm { 216 fn norm(&self) -> f32; 217} 218 219impl Norm for (usize, usize) { 220 fn norm(&self) -> f32 { 221 ((self.0 * self.0 + self.1 * self.1) as f32).sqrt() 222 } 223}