aboutsummaryrefslogtreecommitdiff
path: root/layer/fillPrinter.ml
blob: 3093adae841622b135e25007b7a985b78ad2350c (plain)
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
module Point = Path.Point



module Make(Repr: Repr.PRINTER) = struct

  (* Divide a curve in subelements *)
  let rec divide level p0 ctrl0 ctrl1 p1 path =

    let bezier =
      { Shapes.Bezier.p0 = Path.Point.get_coord p0
      ; ctrl0
      ; ctrl1
      ; p1 = Path.Point.get_coord p1
      } in

    let ratio = 0.5 in
    let bezier0, bezier1 = Shapes.Bezier.slice ratio bezier in
    let point = Path.Point.mix ratio bezier0.Shapes.Bezier.p1 p0 p1 in

    let ctrl0_0 = Point.copy p0 bezier0.Shapes.Bezier.ctrl0
    and ctrl0_1 = Point.copy point bezier0.Shapes.Bezier.ctrl1

    and ctrl1_0 = Point.copy point bezier1.Shapes.Bezier.ctrl0
    and ctrl1_1 = Point.copy p1 bezier1.Shapes.Bezier.ctrl1 in


    match level with
    | 0 ->
      path :=
        Repr.quadratic_to
          (Point.get_coord' @@ ctrl1_1)
          (Point.get_coord' @@ ctrl1_0)
          (Point.get_coord' point) !path;

      path :=
        Repr.quadratic_to
          (Point.get_coord' @@ ctrl0_1)
          (Point.get_coord' @@ ctrl0_0)
          (Point.get_coord' p0) !path;
    | n ->
      divide (n-1) point (Point.get_coord ctrl1_0) (Point.get_coord ctrl1_1) p1 path;
      divide (n-1) p0 (Point.get_coord ctrl0_0) (Point.get_coord ctrl0_1) point path;

  type t = Point.t

  type repr =
    { path: Repr.t
    ; close : Repr.t -> Repr.t
    }

  let create_path
    : (Repr.t -> Repr.t) -> repr
    = fun f ->
      { close = f
      ; path = Repr.create ()
      }

  (* Start a new path. *)
  let start
    : Path.Point.t -> repr -> repr
    = fun t {close ; path } ->
      let path = Repr.move_to (Point.get_coord t) path in
      { close
      ; path
      }

  let line_to
    : Point.t -> Point.t -> repr -> repr
    = fun p0 p1 t ->
      let path =
        Repr.move_to (Point.get_coord p1) t.path
        |> Repr.line_to (Point.get_coord' p1)
        |> Repr.line_to (Point.get_coord' p0)
        |> Repr.line_to (Point.get_coord p0)
        |> Repr.line_to (Point.get_coord p1)
        |> Repr.close in
      let path = t.close path in
      { t with path}

  let quadratic_to
    : Point.t -> Gg.v2 -> Gg.v2 -> Point.t -> repr -> repr
    = fun p0 ctrl0 ctrl1 p1 t ->

      let ctrl0' = Point.copy p1 ctrl0
      and ctrl1' = Point.copy p1 ctrl1 in

      let path = Repr.move_to (Point.get_coord p1) t.path
                 |> Repr.line_to (Point.get_coord' p1) in
      let path = ref path in

      (* Backward *)
      divide 3 p0 ctrl0 ctrl1 p1 path ;
      path := Repr.line_to (Point.get_coord p0) !path;

      (* Forward *)
      path := Repr.quadratic_to
          (Point.get_coord ctrl0')
          (Point.get_coord ctrl1')
          (Point.get_coord p1) !path;

      let path = !path in

      let path = Repr.close path in

      let path = t.close path in
      { t with path}


  let stop
    : repr -> repr
    = fun t ->
      t

  let get
    : repr -> Repr.t
    = fun t ->
      t.path
end