package picasso

  1. Overview
  2. Docs

Source file drawer.ml

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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
module Make (D : Manager.T) = struct
  (* Initialization and Backend setting *)

  let x_min = ref 0.

  let x_max = ref 0.

  let y_min = ref 0.

  let y_max = ref 0.

  let nb_graduation =
    10. (* target number of graduation, the actual will differ slightly *)

  let square ((a, b) as bl) ((c, d) as tr) = [bl; (c, b); tr; (a, d)]

  (* screen as a polygon *)
  let screen () = square (0., 0.) (D.width (), D.height ())

  let to_backend_coord (x, y) =
    D.normalize (!x_min, !x_max) (!y_min, !y_max) (x, y)

  (* few constants colors *)
  let black = D.rgb 0 0 0

  let red = D.rgb 255 0 0

  let white = D.rgb 255 255 255

  let darkgray = D.rgb 64 64 64

  let lightgray = D.rgb 230 230 230

  let gray = D.rgb 128 128 128

  (* redefining drawing utilities *)

  let clear () = D.fill_poly white (screen ())

  let draw_line ~dashed col p1 p2 =
    let p1 = to_backend_coord p1 and p2 = to_backend_coord p2 in
    D.draw_line ~dashed col p1 p2

  let draw_text col pos p text =
    let p = to_backend_coord p in
    D.draw_text col pos p text

  let fill_circle col ((cx, cy) as center) rad =
    let ((px, _) as p) = to_backend_coord center in
    let px', _ = to_backend_coord (cx +. rad, cy) in
    let rad = px' -. px in
    D.fill_circle col p rad

  let poly f col vertices =
    match vertices with
    | [] -> ()
    | [x] -> fill_circle col x 2.
    | [(xa, ya); (xb, yb)] -> draw_line ~dashed:false col (xa, ya) (xb, yb)
    | _ ->
        let vertices = List.rev_map to_backend_coord vertices in
        f col vertices

  let draw_poly = poly D.draw_poly

  let fill_poly = poly D.fill_poly

  (* Filled, black-outlined polygon *)
  let polygon col vertices = fill_poly col vertices ; draw_poly black vertices

  let xline r cur =
    let open Rendering in
    let up = r.scene.y_max and down = r.scene.y_min in
    let p1 = normalize r (cur, down) and p2 = normalize r (cur, up) in
    draw_line ~dashed:true lightgray p1 p2

  let yline r cur =
    let open Rendering in
    let left = r.scene.x_min and right = r.scene.x_max in
    let p1 = normalize r (left, cur) and p2 = normalize r (right, cur) in
    draw_line ~dashed:true lightgray p1 p2

  let closest_power_of_10 x =
    let xl10 = log10 x in
    10. ** Float.round xl10

  let closest_half_power_of_10 x =
    let xl10 = log10 x in
    let up = 10. ** Float.ceil xl10 in
    let down = 10. ** Float.floor xl10 in
    let mid = up /. 2. in
    let dif_down = abs_float (down -. x) in
    let dif_up = abs_float (up -. x) in
    let dif_mid = abs_float (mid -. x) in
    if dif_mid < dif_down then if dif_mid < dif_up then mid else up
    else if dif_down < dif_up then down
    else up

  let draw_grid render =
    let open Rendering in
    let sx = render.scene.x_max -. render.scene.x_min in
    let sy = render.scene.y_max -. render.scene.y_min in
    let step_x = closest_power_of_10 sx /. 10. in
    let step_y = closest_power_of_10 sy /. 10. in
    let fst_x = (render.scene.x_min /. step_x |> floor) *. step_x in
    let fst_y = (render.scene.y_min /. step_y |> floor) *. step_y in
    Tools.iterate (xline render) fst_x (( +. ) step_x)
      (( < ) render.scene.x_max) ;
    Tools.iterate (yline render) fst_y (( +. ) step_y)
      (( < ) render.scene.y_max)

  let graduation fx fy render =
    let open Rendering in
    let sx = render.scene.x_max -. render.scene.x_min in
    let sy = render.scene.y_max -. render.scene.y_min in
    let step_x = closest_half_power_of_10 sx /. 2. in
    let step_y = closest_half_power_of_10 sy /. 2. in
    let fst_x = (render.scene.x_min /. step_x |> floor) *. step_x in
    let fst_y = (render.scene.y_min /. step_y |> floor) *. step_y in
    Tools.iterate fx fst_x
      (fun x -> x +. step_x)
      (( < ) (render.scene.x_max +. step_x)) ;
    Tools.iterate fy fst_y
      (fun x -> x +. step_x)
      (( < ) (render.scene.y_max +. step_y))

  let nb_digits n = if n > 1. then 0 else int_of_float (ceil ~-.(log10 n))

  let draw_axes r =
    let open Rendering in
    let x0, y0 = (10., 10.) in
    let left = 0. and right = r.window.sx in
    let up = r.window.sy and down = 0. in
    let hx, hy = (left, y0) and hx', hy' = (right, y0) in
    let th = 3. in
    let thick_line =
      [(hx, hy +. th); (hx, hy -. th); (hx', hy' -. th); (hx', hy' +. th)]
    in
    fill_poly gray thick_line ;
    let vx, vy = (x0, down) and vx', vy' = (x0, up) in
    let thick_line =
      [(vx +. th, vy); (vx -. th, vy); (vx' -. th, vy'); (vx' +. th, vy')]
    in
    fill_poly gray thick_line ;
    let mb_size = 6. in
    let sx = r.scene.x_max -. r.scene.x_min in
    let sy = r.scene.y_max -. r.scene.y_min in
    let step_x = closest_half_power_of_10 sx /. 2. in
    let step_y = closest_half_power_of_10 sy /. 2. in
    (* horizontal minibars and coordinates *)
    let fx cur =
      let text =
        Format.asprintf "%a"
          (Tools.pp_float ~max_decimals:(nb_digits step_x))
          cur
      in
      let x, _ = normalize r (cur, down) in
      draw_line ~dashed:false gray (x, hy -. mb_size) (x, hy +. mb_size) ;
      draw_text darkgray `Center (x, hy +. 20.) text
    in
    (* vertical minibar coordinates *)
    let fy cur =
      let text =
        Format.asprintf "%a"
          (Tools.pp_float ~max_decimals:(nb_digits step_y))
          cur
      in
      let _, y = normalize r (left, cur) in
      draw_line ~dashed:false gray (vx -. mb_size, y) (vx +. mb_size, y) ;
      draw_text darkgray `Center (vx, y) text
    in
    graduation fx fy r ;
    draw_text black `Center (r.window.sx /. 2., 0.) r.abciss ;
    draw_text black `Center (0., r.window.sy /. 2.) r.ordinate

  (* main drawing function *)
  let draw r =
    let open Rendering in
    x_min := r.scene.x_min ;
    x_max := r.scene.x_max ;
    y_min := r.scene.y_min ;
    y_max := r.scene.y_max ;
    r |> to_vertices
    |> List.iter (fun ((r, g, b), e) ->
           let c = D.rgb r g b in
           polygon c e ) ;
    let highlight = highlight_to_vertices r in
    List.iter
      (fun ((r, g, b), e) ->
        let c = D.rgb (r / 2) (g / 2) (b / 2) in
        polygon c e )
      highlight ;
    if r.grid then draw_grid r ;
    if r.axis then draw_axes r
end
OCaml

Innovation. Community. Security.