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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
|
(***********************************************************************)
(* *)
(* Active-DVI *)
(* *)
(* Projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 2003 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* under the terms of the GNU Lesser General Public License. *)
(* *)
(* Pierre Weis *)
(* *)
(* Filling rectangles and arcs with gradients. *)
(* *)
(***********************************************************************)
(* $Id: gradient.ml,v 1.5 2004/03/27 14:22:35 weis Exp $ *)
open Graphics;;
type x = int
and y = int;;
type w = int
and h = int;;
type r = int
and rx = int
and ry = int;;
type from_angle = int
and to_angle = int;;
type from_color = Graphics.color
and to_color = Graphics.color;;
type arc_gradient_mode =
| Arc_Horizontal of from_color * to_color
| Arc_Vertical of from_color * to_color
| Arc_Circular of from_color * to_color
;;
type rectangle_gradient_mode =
| Rect_Horizontal of from_color * to_color
| Rect_Vertical of from_color * to_color
| Rect_Diagonal1 of from_color * to_color
| Rect_Diagonal2 of from_color * to_color
| Rect_Centered of from_color * to_color * x * y
| Rect_Circular of from_color * to_color * x * y
;;
(* Scaling from c to c', by i steps over w steps.
Meaning:
scale 0 w c c' = c (1)
scale w w c c' = c' (2)
scale i w c c' = a * i + b (3) for some real a and b.
We have b = c (due to (1))
and c'= a * w + c (due to (2))
hence a = (c' - c) / w
Finally, we get:
scale i w c c' = (c' * i + c * (w - i)) / w
*)
let scale i w c c' =
if w = 0 then c else
let mid = (w + 1) / 2 in
let round_quot w x = (x + mid) / w in
round_quot w (c' * i + c * (w - i));;
let r_of c = (c land 0xff0000) lsr 16
and g_of c = (c land 0x00ff00) lsr 8
and b_of c = (c land 0x0000ff);;
(* Scaling a color from c to c', by i steps over w steps. *)
let scale_color i w c c' =
assert (i >= 0 && i <= w);
rgb (scale i w (r_of c) (r_of c'))
(scale i w (g_of c) (g_of c'))
(scale i w (b_of c) (b_of c'));;
(* Filling arcs with gradients of colors. *)
let grad_arc gm x y rx ry a1 a2 =
let gmax, c, c' =
match gm with
| Arc_Horizontal (c, c') -> rx, c, c'
| Arc_Vertical (c, c') -> ry, c, c'
| Arc_Circular (c, c') -> max rx ry, c, c' in
(* Since
- draw_arc x y 0 ry does something,
- draw_arc x y rx 0 does something,
- draw_arc x y 0 0 does nothing,
- draw_arc x y 1 1 draws a square with one point cleared,
we must prevent rx, ry to be successively (0, 0) then (1, 1) otherwise
one single point would be left cleared at the very center of the arc.
Hence rxmin is 1 if rx is not 0 and rymin is 1 if rxmin = 0! *)
let rxmin = if rx > 0 then 1 else 0 in
let rymin = if rxmin > 0 then 0 else 1 in
let scale_rx =
match gm with
| Arc_Horizontal (_, _) -> (fun i -> i)
| Arc_Vertical (_, _) -> (fun i -> rx)
| Arc_Circular (_, _) -> (fun i -> scale i gmax rxmin rx) in
let scale_ry =
match gm with
| Arc_Horizontal (_, _) -> (fun i -> ry)
| Arc_Vertical (_, _) -> (fun i -> i)
| Arc_Circular (_, _) -> (fun i -> scale i gmax rymin ry) in
for i = 0 to gmax do
set_color (scale_color i gmax c c');
let rx = scale_rx i
and ry = scale_ry i in
draw_arc x y rx ry a1 a2;
done;;
(* Filling circles with gradients of colors. *)
let grad_circle gm xc yc r = grad_arc gm xc yc r r 0 360;;
(* Horizontal gradient into a rectangle *)
let grad_rect_h c1 c2 x y w h =
for i = 0 to w - 1 do
set_color (scale_color i w c1 c2);
fill_rect (x + i) y 1 h;
done;;
(* Vertical gradient into a rectangle *)
let grad_rect_v c1 c2 x y w h =
for i = 0 to h - 1 do
set_color (scale_color i h c1 c2);
fill_rect x (y + i) w 1;
done;;
(* First bissector gradient into a rectangle *)
let grad_rect_d1 c1 c2 x y w h =
let sc = w + h in
let limx = x + w - 1 in
let limy = y + h - 1 in
let rec loop i x0 y0 x1 y1 =
set_color (scale_color i sc c1 c2);
moveto x0 y0;
if i <= sc then lineto x1 y1;
if x0 < limx then
if y1 < limy then
loop (i + 1) (x0 + 1) y0 x1 (y1 + 1) else
loop (i + 1) (x0 + 1) y0 (x1 + 1) y1 else
if y0 < limy then
if y1 < limy then
loop (i + 1) x0 (y0 + 1) x1 (y1 + 1) else
loop (i + 1) x0 (y0 + 1) (x1 + 1) y1 else
() in
set_line_width 1;
loop 0 x y x y;;
(* Second bissector gradient into a rectangle *)
let grad_rect_d2 c1 c2 x y w h =
let sc = w + h in
let limx = x in
let limy = y + h - 1 in
let rec loop i x0 y0 x1 y1 =
set_color (scale_color i sc c1 c2);
moveto x0 y0;
if i <= sc then lineto x1 y1;
if x0 > limx then
if y1 < limy then
loop (i + 1) (x0 - 1) y0 x1 (y1 + 1) else
loop (i + 1) (x0 - 1) y0 (x1 - 1) y1 else
if y0 < limy then
if y1 < limy then
loop (i + 1) x0 (y0 + 1) x1 (y1 + 1) else
loop (i + 1) x0 (y0 + 1) (x1 - 1) y1 else
() in
set_line_width 1;
loop 0 (x + w - 1) y (x + w - 1) y;;
(* Circular gradient into a rectangle *)
let grad_rect_circular c1 c2 xc yc x y w h =
let xmin, xmax = x, x + w
and ymin, ymax = y, y + h in
let scx = min (xc - xmin) (xmax - xc)
and scy = min (yc - ymin) (ymax - yc) in
let sc = min scx scy in
(** sc is the number of steps to perform. *)
let rec loop r =
if r < sc then begin
set_color (scale_color r sc c1 c2);
draw_circle xc yc r;
loop (r + 1)
end in
set_color c2;
fill_rect x y w h;
if sc > 0 then (set_color c1; plot xc yc);
set_line_width 1;
loop 0;;
(* Centered gradient into a rectangle
(means growing squares with center xc yc). *)
let grad_rect_centered c1 c2 xc yc x y w h =
let xmin, xmax = x, x + w
and ymin, ymax = y, y + h in
let scx = min (xc - xmin) (xmax - xc)
and scy = min (yc - ymin) (ymax - yc) in
let sc = min scx scy in
(** sc is the number of steps to perform. *)
let rec loop x0 y0 x1 y1 =
if x1 >= xmax || y1 >= ymax ||
x0 < xmin || y0 < ymin then () else begin
moveto x0 y0;
set_color (scale_color (yc - y0) sc c1 c2);
lineto x1 y0;
set_color (scale_color (x1 - xc) sc c1 c2);
lineto x1 y1;
set_color (scale_color (y1 - yc) sc c1 c2);
lineto x0 y1;
set_color (scale_color (xc - x0) sc c1 c2);
lineto x0 y0;
loop (x0 - 1) (y0 - 1) (x1 + 1) (y1 + 1)
end in
set_color c2;
fill_rect x y w h;
set_line_width 1;
loop xc yc xc yc;;
(* Filling rectangles with gradients of colors. *)
let grad_rect gm x y w h =
match gm with
| Rect_Horizontal (c1, c2) ->
grad_rect_h c1 c2 x y w h
| Rect_Vertical (c1, c2) ->
grad_rect_v c1 c2 x y w h
| Rect_Diagonal1 (c1, c2) ->
grad_rect_d1 c1 c2 x y w h
| Rect_Diagonal2 (c1, c2) ->
grad_rect_d2 c1 c2 x y w h
| Rect_Centered (c1, c2, xc, yc) ->
grad_rect_centered c1 c2 xc yc x y w h
| Rect_Circular (c1, c2, xc, yc) ->
grad_rect_circular c1 c2 xc yc x y w h;;
|