Advertisement
tadejpetric

binary tree picture

Aug 2nd, 2019
455
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.82 KB | None | 0 0
  1. use std::fs::File;
  2. use std::io::Write;
  3. use std::cmp;
  4.  
  5. const SCALING_FACTOR: f64 = 1.4 as f64;
  6.  
  7. #[derive(Clone)]
  8. struct RGB {
  9.     red: u8,
  10.     green: u8,
  11.     blue: u8
  12. }
  13.  
  14. fn serialize_rgb(pixels: &Vec<RGB>, size: usize) -> Vec<u8> {
  15.     // for saving to a file. Is there any way we could do this
  16.     // without constructing a new array? Would be much faster
  17.     let mut output: Vec<u8> = Vec::with_capacity(size * 3);
  18.     for pix in pixels {
  19.         output.push(pix.red);
  20.         output.push(pix.green);
  21.         output.push(pix.blue);
  22.     }
  23.     output
  24. }
  25.  
  26. struct Canvas {
  27.     // Using 1D array so the bytes are together in memory, should be more efficient than Vec<Vec>
  28.     // since that would store pointers to vectors?
  29.     pixels: Vec<RGB>,
  30.     width: i32,
  31.     height: i32
  32. }
  33.  
  34. impl Canvas {
  35.     fn set_colour(&mut self, x: i32, y: i32, colour: &RGB) {
  36.         // make this more natural? In C++ you can overload () to get a functor
  37.         if x > 0 && y > 0 &&  x < self.width && y <  self.height {
  38.             self.pixels[(self.width * y + x) as usize] = colour.clone();
  39.         }
  40.     }
  41.  
  42.     fn write_to_file(&mut self, filename: &str) {
  43.         let mut file = init_ppm(filename, self.width, self.height);
  44.         file.write_all(&serialize_rgb(&self.pixels, (self.width * self.height) as usize)).expect("error");
  45.         /* slow
  46.         for pixel in &self.pixels {
  47.             file.write_all(&[pixel.red, pixel.green, pixel.blue]).expect("error writing to a file");
  48.         }*/
  49.     }
  50.  
  51.     fn new(width: i32, height: i32) -> Canvas {
  52.         Canvas {
  53.             width,
  54.             height,
  55.             pixels: vec![RGB{red:0, green:0, blue:0}; (width * height) as usize]
  56.         }
  57.     }
  58.  
  59.     fn draw_square(&mut self, center: &Point, width: i32, colour: &RGB) {
  60.         for y in cmp::max(0, center.y - width) .. cmp::min(self.height, center.y + width) {
  61.             for x in cmp::max(0, center.x - width) .. cmp::min(self.width, center.x + width) {
  62.                 self.set_colour(x ,y, &colour);
  63.             }
  64.         }
  65.     }
  66.  
  67.     fn draw_line(&mut self, from: &Point, to: &Point, width: i32, colour: &RGB) {
  68.         // function that connects two points on the grid with a line
  69.         if from.x == to.x { // vertical lines
  70.             let startx = cmp::max(from.x - width, 0);
  71.             let endx = cmp::min(from.x + width, self.width);
  72.             let endy = cmp::max(from.y, to.y) + 1;
  73.             let starty = cmp::min(from.y, to.y);
  74.             for y in starty .. endy {
  75.                 for x in  startx .. endx {
  76.                     self.set_colour(x, y, colour);
  77.                 }
  78.  
  79.             }
  80.         }
  81.         else {
  82.             let k = (to.y - from.y) as f64 / (to.x - from.x) as f64;
  83.             let n = to.y as f64 - k * to.x as f64;
  84.             let lower = cmp::min(from.x, to.x);
  85.             let upper = cmp::max(from.x, to.x) + 1;
  86.             for x in lower .. upper {
  87.                 // We colour y's as a function of x's
  88.                 self.draw_square(
  89.                     &Point {x: x, y: (k * x as f64 + n) as i32},
  90.                     width,
  91.                     colour
  92.                 );
  93.             }
  94.             if k.abs() > 1.0 {
  95.                 // for steep lines, we also have to consider x as a function of y to get good results
  96.                 let lower = cmp::min(from.y, to.y);
  97.                 let upper = cmp::max(from.y, to.y) + 1;
  98.                 for y in lower .. upper {
  99.                     self.draw_square(
  100.                         &Point {x: ((y as f64 - n) / k) as i32, y: y},
  101.                         width,
  102.                         colour
  103.                     );
  104.                 }
  105.             }
  106.         }
  107.     }
  108.  
  109. }
  110.  
  111. fn rotate_point(center: &Point, point: &Point, angle: f64) -> Point {
  112.     // also scales down a bit
  113.     let (sin, cos) = angle.sin_cos();
  114.     let translated = Point {x: ((point.x - center.x) as f64 / SCALING_FACTOR) as i32,
  115.                             y: ((point.y - center.y) as f64 / SCALING_FACTOR) as i32};
  116.     let rotated = Point {x: (translated.x as f64 * cos - translated.y as f64 * sin) as i32,
  117.                          y: (translated.x as f64 * sin + translated.y as f64 * cos) as i32
  118.     };
  119.     Point {x: rotated.x + center.x, y: rotated.y + center.y}
  120. }
  121.  
  122. fn init_ppm(filename: &str, width: i32, height: i32) -> File {
  123.     let mut file = File::create(format!("{}.ppm",filename)).expect("couldn't create");
  124.     file.write_all(format!("P6 {} {} 255 ", width, height).as_bytes()).expect("error writing to a file");
  125.     file
  126. }
  127.  
  128. struct Point {
  129.     x: i32,
  130.     y: i32
  131. }
  132.  
  133. fn main() {
  134.     const WIDTH: i32 = 1500;
  135.     const HEIGHT: i32 = 1500;
  136.     let mut picture = Canvas::new(WIDTH, HEIGHT);
  137.     draw_tree(&mut picture,
  138.               &Point {x: WIDTH/2, y: HEIGHT},
  139.               &Point {x: WIDTH/2, y: 3*HEIGHT/4},
  140.               15,
  141.               &RGB {red: 255, blue: 255, green: 255},
  142.               0.6,
  143.               2);
  144.     picture.write_to_file("neki");
  145. }
  146.  
  147.  
  148. fn draw_tree(mut canvas: &mut Canvas, prev: &Point, next: &Point, iter: i32, colour: &RGB, angle: f64, branches: i32) {
  149.     // recursively generates branches.
  150.     if iter == 0 {
  151.         return;
  152.     }
  153.     canvas.draw_line(prev, next, 1, colour);
  154.     let prev = Point {x: 2 * next.x - prev.x, y: 2 * next.y - prev.y};
  155.    
  156.     if branches % 2 == 1 {
  157.         draw_tree(&mut canvas, &next, &rotate_point(next, &prev, 0.0), iter - 1, colour, angle, branches);
  158.     }
  159.     for i in 1 .. branches / 2 + 1 {
  160.         let rot_left = rotate_point(next, &prev, i as f64 * angle);
  161.         draw_tree(&mut canvas, &next, &rot_left, iter - 1, &RGB{red: 247, green: 97, blue: 74}, angle, branches);
  162.  
  163.         let rot_right = rotate_point(next, &prev, - i as f64 * angle);
  164.         draw_tree(&mut canvas, &next, &rot_right, iter - 1, &RGB{red: 26, green: 121, blue: 244}, angle, branches);
  165.     }
  166. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement