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 79 lines 2.6 kB view raw
1use crate::{Containable, Point, Region}; 2use rand::{Rng, distr::uniform::SampleRange, seq::IteratorRandom}; 3 4impl Region { 5 pub fn random_end(&self, rng: &mut impl Rng, start: Point) -> Point { 6 // End anchors are always a square diagonal from the start anchor (for now) 7 // that means taking steps of the form n * (one of (1, 1), (1, -1), (-1, 1), (-1, -1)) 8 // Except that the end anchor needs to stay in the bounds of the shape. 9 10 // Determine all possible end anchors that are in a square diagonal from the start anchor 11 let mut possible_end_anchors = vec![]; 12 13 // shapes can end on the next cell, since that's where they end 14 let actual_region = self.enlarged(1, 1); 15 16 for x in actual_region.mirrored_width_range() { 17 for y in actual_region.mirrored_height_range() { 18 let end_anchor = start.translated(x, y); 19 20 if end_anchor == start { 21 continue; 22 } 23 24 // Check that the end anchor is in a square diagonal from the start anchor and that the end anchor is in bounds 25 if x.abs() == y.abs() && actual_region.contains(&end_anchor) { 26 possible_end_anchors.push(end_anchor); 27 } 28 } 29 } 30 31 // Pick a random end anchor from the possible end anchors 32 possible_end_anchors[rng.random_range(0..possible_end_anchors.len())] 33 } 34 35 pub fn random(rng: &mut impl Rng, within: &Region) -> Self { 36 let start = Point::random(rng, within); 37 let end = within.random_end(rng, start); 38 Region::from(if start.x() > end.x() { 39 (end, start) 40 } else { 41 (start, end) 42 }) 43 } 44 45 pub fn random_point(&self, rng: &mut impl Rng) -> Point { 46 Point::random(rng, self) 47 } 48 49 pub fn random_point_except( 50 &self, 51 rng: &mut impl Rng, 52 except: &Region, 53 ) -> Point { 54 self.iter() 55 .filter(|p| !except.contains(p)) 56 .choose(rng) 57 .unwrap() 58 } 59} 60 61impl SampleRange<Point> for Region { 62 fn is_empty(&self) -> bool { 63 self.is_empty() 64 } 65 66 fn sample_single<R: rand::RngCore + ?Sized>( 67 self, 68 rng: &mut R, 69 ) -> Result<Point, rand::distr::uniform::Error> { 70 if self.is_empty() { 71 return Err(rand::distr::uniform::Error::EmptyRange); 72 } 73 74 Ok(Point::Corner( 75 rng.random_range(self.x_range()), 76 rng.random_range(self.y_range()), 77 )) 78 } 79}