1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Creating a `Picture` from `Shape`s

use std::rc::Rc;

use vector::Vector;
use canvas::Box as Bx;
use shape::{Shape, ControlPoint};
use style::Style;
use picture::Rendering;

/// Creates a `Picture`, i.e. a `Fn(canvas::Box) -> Vec<(Shape, Style)>`, from
/// `Vec<Shape>`.
pub fn create_picture(shapes: Vec<Shape>) -> Rc<impl Fn(&Bx) -> Rendering> {
    Rc::new(move |bx: &Bx| {
        let style = style_for(&bx);
        let transformation = transformation_from_box(&bx);
        let result: Vec<(Shape, Style)> = shapes.iter()
        	  .map(|shape| map_shape(&transformation, &shape))
            .map(|shape| (shape, style.clone()))
        	  .collect();
        result
    })
}

fn style_for(bx: &Bx) -> Style {
    Style::new(stroke_width_for(&bx))
}

fn stroke_width_for(bx: &Bx) -> f64 {
    bx.b.length().max(bx.c.length()) / 80f64
}

fn transformation_from_box(cx: &Bx) -> impl Fn(&Vector<f64>) -> Vector<f64> {
	let bx = cx.clone();
	move |v: &Vector<f64>| {
		bx.a.add(&bx.b.scale(&v.x).add(&bx.c.scale(&v.y)))
	}
}

fn map_shape(transformation: impl Fn(&Vector<f64>) -> Vector<f64>, shape: &Shape) -> Shape {
	  match shape {
		    Shape::Line(line_start, line_end) =>
            Shape::Line(transformation(line_start), transformation(line_end)),
        Shape::PolyLine(points) => {
            let transformed_points: Vec<Vector<f64>> = points.iter()
                .map(transformation)
                .collect();
            Shape::PolyLine(transformed_points)
        },
        Shape::Polygon(points) => {
            let transformed_points: Vec<Vector<f64>> = points.iter()
                .map(transformation)
                .collect();
            Shape::Polygon(transformed_points)
        },
        Shape::Curve(p1, p2, p3, p4) =>
            Shape::Curve(transformation(p1), transformation(p2), transformation(p3), transformation(p4)) ,
        Shape::Path(start, controls) => {
            let new_controls: Vec<ControlPoint> = controls.iter()
                .map(|control| ControlPoint::new(
                    transformation(&control.mid_point1),
                    transformation(&control.mid_point2),
                    transformation(&control.end_point)
                ))
                .collect();

            Shape::Path(transformation(start), new_controls)
        }

	  }
}