User:Kopophex/venn.ml

From Wikipedia, the free encyclopedia

This is a program I wrote to draw venn diagrams of any degree. It is a little rough, but all the parts are there.

(* An experiment in drawing n-degree Venn diagrams. *)
(* to compile: ocamlc -o venn -I +cairo bigarray.cma cairo.cma venn.ml *)
(* To run: ./venn n
   where, n is the degree of the diagram to draw. *)
 
open List
 
let rec take n l = match (n,l) with
    0,_ -> []
  | _,h::t -> h :: take (n-1) t
  | _,[] -> failwith "take: empty list"
 
 
 
let pi = 4. *. atan 1.
 
let alpha = 0.65
 
let (cx,cy) = (alpha /. (sqrt 2.)), -.(alpha /. (sqrt 2.))
 
let draw1 ctx =
  Cairo.arc ctx cx cy 1.0 0.0 (2.*.pi) ; 
  Cairo.stroke ctx
 
let draw2 ctx =
  let theta = 5. *. pi /. 12. in
  Cairo.arc ctx 
    (alpha *. (cos theta))
    (alpha *. (sin theta)) 
    1.0 0.0 (2.*.pi) ;
  Cairo.stroke ctx
 
let draw3 ctx =
  let theta = 13. *. pi /. 12. in
  Cairo.arc ctx
    (alpha *. (cos theta))
    (alpha *. (sin theta))    
    1.0 0.0 (2.0*.pi) ;
  Cairo.stroke ctx
 
 
let rec draw_n_curves ctx r = function
    i when i <= 0. -> ()
  | i ->
      Cairo.arc ctx cx cy ((1.0 +. i*.r) -. (r /. 2.0)) 0.0 (-. pi) ;
      Cairo.stroke ctx;
      Cairo.arc ctx cx cy ((1.0 -. i*.r) +. (r /. 2.0)) 0.0 (-. pi) ;
      Cairo.stroke ctx ;
      draw_n_curves ctx r (i-.1.0)
 
let rec draw_n_right_arcs ctx r = function
    i when i <= 0. -> ()
  | i ->
      Cairo.arc ctx (cx+.1.0) cy (((i-.1.0)*.r)+.(r/.2.0)) (-. pi) 0.0 ;
      Cairo.stroke ctx ;
      draw_n_right_arcs ctx r (i-.1.0)
 
 
let rec draw_n_left_arcs ctx r x = function
    i when i = 0. ->
      Cairo.arc ctx (x+.r) cy (r/.2.0) (-. pi) 0.0 ; Cairo.stroke ctx
  | i ->
      let rec draw_arcs x = function
          j when j <= 0. -> ()
        | j -> Cairo.arc ctx x cy ((r*.(j-.1.0))+.(r/.2.0)) (-. pi) 0.0 ; 
               Cairo.stroke ctx ; 
               draw_arcs x (j-.1.0) in
 
        draw_arcs (x+.(r*.(i/.2.0))) (i/.2.0) ;
        draw_n_left_arcs ctx r (x-.(r*.(i/.2.0))) (i/.2.0)
 
 
 
let base_r = 1.5 
 
let draw_n ctx n =
  let i = 2.0 ** ((float_of_int n) -. 1.0) in
  let r = base_r /. 2.0 ** (float_of_int n) in
    draw_n_curves ctx r i ; 
    draw_n_right_arcs ctx r i ;
    draw_n_left_arcs ctx r (cx-.1.0) i
 
 
let rec draw ctx colors = function
    0 -> ()
  | i ->
      let (r,g,b,a) = (hd colors) in
        Cairo.set_source_rgba ctx r g b a ;
        (match i with
            1 -> draw1 ctx
          | 2 -> draw2 ctx
          | 3 -> draw3 ctx
          | _ -> draw_n ctx (i-3)) ;
        draw ctx (tl colors) (i-1)
 
 
 
 
let () =
  let n = int_of_string Sys.argv.(1) in
  let colors = rev (take n [
    (0.0,0.0,0.0,1.0); (0.0,0.0,0.0,1.0); (0.0,0.0,0.0,1.0);
    (6.0,0.0,0.0,1.0); (0.0,6.0,0.0,1.0); (0.0,0.0,6.0,1.0) ]) in
  let (width,height) = (600,530) in
  let (fwidth,fheight) = (float_of_int width, float_of_int height) in
  let scale = 160. in
  let file = open_out "out.svg" in
  let surface = Cairo_svg.surface_create_for_channel file 650.0 520.0 in
  let ctx = Cairo.create surface in
    Cairo.translate ctx (fwidth/.2.) (fheight/.2.) ;
    Cairo.scale ctx scale (-.scale) ;
    Cairo.set_line_width ctx (2.0/.scale) ;
 
    draw ctx colors n ;
 
    Cairo.surface_finish surface