created moving bubbles
This commit is contained in:
parent
21e8aba2f8
commit
bb082dd8a0
3 changed files with 73 additions and 26 deletions
BIN
output.gif
BIN
output.gif
Binary file not shown.
Before Width: | Height: | Size: 472 KiB After Width: | Height: | Size: 13 MiB |
87
src/lib.rs
87
src/lib.rs
|
@ -13,7 +13,7 @@
|
||||||
with this program. If not, see https://www.gnu.org/licenses/.
|
with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
*/
|
*/
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::vec;
|
use std::{f64::consts::PI, vec};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
|
@ -24,13 +24,22 @@ pub struct Image {
|
||||||
pub pixels: Vec<u8>,
|
pub pixels: Vec<u8>,
|
||||||
point_data: Vec<PointData>,
|
point_data: Vec<PointData>,
|
||||||
cross_distance: f64,
|
cross_distance: f64,
|
||||||
points: Vec<Point>,
|
ellipses: Vec<Ellipse>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Ellipse {
|
||||||
|
centre: Point,
|
||||||
|
height: f64,
|
||||||
|
width: f64,
|
||||||
|
angle: f64,
|
||||||
|
curr_point: Point,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Point {
|
struct Point {
|
||||||
pub x: u16,
|
x: i64,
|
||||||
pub y: u16,
|
y: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -84,25 +93,41 @@ impl Image {
|
||||||
args.height as usize * args.width as usize
|
args.height as usize * args.width as usize
|
||||||
],
|
],
|
||||||
cross_distance: Point { x: 0, y: 0 }.distance(&Point {
|
cross_distance: Point { x: 0, y: 0 }.distance(&Point {
|
||||||
x: args.width - 1,
|
x: args.width as i64 - 1,
|
||||||
y: args.height - 1,
|
y: args.height as i64 - 1,
|
||||||
}),
|
}),
|
||||||
points: generate_points(args.width, args.height, args.num_cells),
|
ellipses: generate_points(args.width, args.height, args.num_cells),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_canvas(&mut self) {
|
pub fn fill_canvas(&mut self, frame: u16) {
|
||||||
self.generate_noise();
|
self.generate_noise(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_noise(&mut self) {
|
fn generate_noise(&mut self, frame: u16) {
|
||||||
let mut max_dist = 0.0;
|
let mut max_dist = 0.0;
|
||||||
|
|
||||||
|
let pos = 2.0 * PI * frame as f64 / self.frames as f64;
|
||||||
|
for ellipse in &mut self.ellipses {
|
||||||
|
let radius = (ellipse.height * ellipse.width)
|
||||||
|
/ (ellipse.width * ellipse.width * (ellipse.angle + pos).sin()
|
||||||
|
+ ellipse.height * ellipse.height * (ellipse.angle + pos).sin())
|
||||||
|
.sqrt();
|
||||||
|
ellipse.curr_point.x = (ellipse.centre.x as f64 + radius * pos.sin()) as i64;
|
||||||
|
ellipse.curr_point.y = (ellipse.centre.y as f64 + radius * pos.cos()) as i64;
|
||||||
|
}
|
||||||
|
|
||||||
// Get distance and nearest point for each point on the canvas
|
// Get distance and nearest point for each point on the canvas
|
||||||
for y in 0..self.height {
|
for y in 0..self.height {
|
||||||
for x in 0..self.width {
|
for x in 0..self.width {
|
||||||
let index = y as usize * self.width as usize + x as usize;
|
let index = y as usize * self.width as usize + x as usize;
|
||||||
self.point_data[index] = PointData::get_point_data(self, Point { x, y });
|
self.point_data[index] = PointData::get_point_data(
|
||||||
|
self,
|
||||||
|
Point {
|
||||||
|
x: x as i64,
|
||||||
|
y: y as i64,
|
||||||
|
},
|
||||||
|
);
|
||||||
max_dist = f64::max(max_dist, self.point_data[index].min_dist);
|
max_dist = f64::max(max_dist, self.point_data[index].min_dist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +145,15 @@ impl Image {
|
||||||
for x in 0..self.width {
|
for x in 0..self.width {
|
||||||
let index = y as usize * self.width as usize + x as usize;
|
let index = y as usize * self.width as usize + x as usize;
|
||||||
let val = 0xFF - (0xFF as f64 * self.point_data[index].min_dist) as u8;
|
let val = 0xFF - (0xFF as f64 * self.point_data[index].min_dist) as u8;
|
||||||
self.set_pixel(val, val, val, Point { x, y });
|
self.set_pixel(
|
||||||
|
0xCC,
|
||||||
|
val,
|
||||||
|
val,
|
||||||
|
Point {
|
||||||
|
x: x as i64,
|
||||||
|
y: y as i64,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,11 +172,11 @@ impl PointData {
|
||||||
closest_point: Point { x: 0, y: 0 },
|
closest_point: Point { x: 0, y: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
for point in &image.points {
|
for ellipse in &image.ellipses {
|
||||||
let d = p.distance(point);
|
let d = p.distance(&ellipse.curr_point);
|
||||||
if d < pd.min_dist {
|
if d < pd.min_dist {
|
||||||
pd.min_dist = d;
|
pd.min_dist = d;
|
||||||
pd.closest_point = point.clone();
|
pd.closest_point = ellipse.curr_point.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,13 +193,25 @@ impl Point {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_points(width: u16, height: u16, num_cells: usize) -> Vec<Point> {
|
fn generate_points(width: u16, height: u16, num_cells: usize) -> Vec<Ellipse> {
|
||||||
let mut points = vec![Point { x: 0, y: 0 }; num_cells];
|
let mut ellipses = vec![
|
||||||
|
Ellipse {
|
||||||
|
centre: Point { x: 0, y: 0 },
|
||||||
|
height: 0.0,
|
||||||
|
width: 0.0,
|
||||||
|
angle: 0.0,
|
||||||
|
curr_point: Point { x: 0, y: 0 }
|
||||||
|
};
|
||||||
|
num_cells
|
||||||
|
];
|
||||||
|
|
||||||
for p in &mut points {
|
for ellipse in &mut ellipses {
|
||||||
p.x = rand::thread_rng().gen_range(0..width);
|
ellipse.centre.x = rand::thread_rng().gen_range(0..width) as i64;
|
||||||
p.y = rand::thread_rng().gen_range(0..height);
|
ellipse.centre.y = rand::thread_rng().gen_range(0..height) as i64;
|
||||||
|
ellipse.height = rand::thread_rng().gen_range(1.0..height as f64 / 5.0);
|
||||||
|
ellipse.width = rand::thread_rng().gen_range(1.0..width as f64 / 5.0);
|
||||||
|
ellipse.angle = rand::thread_rng().gen_range(0.0..2.0 * PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
points
|
ellipses
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,12 @@ fn main() {
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 0..data.frames {
|
||||||
// Create pixel array
|
// Create pixel array
|
||||||
data.fill_canvas();
|
data.fill_canvas(i);
|
||||||
let frame = gif::Frame::from_rgb(data.width, data.height, &mut data.pixels);
|
let frame = gif::Frame::from_rgb(data.width, data.height, &mut data.pixels);
|
||||||
|
|
||||||
// Write frame to file
|
// Write frame to file
|
||||||
encoder.write_frame(&frame).unwrap();
|
encoder.write_frame(&frame).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue