diff --git a/ellipse.py b/ellipse.py deleted file mode 100644 index 38df470..0000000 --- a/ellipse.py +++ /dev/null @@ -1,28 +0,0 @@ -import numpy as np -from joy import * - - -class Ellipse: - def __init__(self, center, radius_x, radius_y): - self.center = np.array(center) - self.radius_x = radius_x - self.radius_y = radius_y - - def rotate(self, angle): - # Translate to origin - translated_center = np.array([0, 0]) - translated_center[0] = self.center[0] - self.radius_x - translated_center[1] = self.center[1] - self.radius_y - - # Rotate around the origin - rotated_center = self.rotate_point(translated_center, angle) - - # Translate back to the original center - self.center[0] = rotated_center[0] + self.radius_x - self.center[1] = rotated_center[1] + self.radius_y - - @staticmethod - def rotate_point(point, angle): - x_rot = point[0] * np.cos(angle) - point[1] * np.sin(angle) - y_rot = point[0] * np.sin(angle) + point[1] * np.cos(angle) - return np.array([x_rot, y_rot]) diff --git a/examples/axes.ml b/examples/axes.ml index 3cd16eb..b59f718 100644 --- a/examples/axes.ml +++ b/examples/axes.ml @@ -5,10 +5,10 @@ open Joy let _ = (* intialize rendering context with the axes flag set to true *) init ~axes:true (); - background (1., 1., 1., 1.); (* set background to opaque white *) - let c = circle 50. in - set_color (0., 0., 0.); + background (255, 255, 255, 255); + let c = circle 50 in + set_color (0, 0, 0); render c; (* Write to PNG! *) write ~filename:"axes.png" () diff --git a/examples/circle.ml b/examples/circle.ml index 4b04dae..adb20e3 100644 --- a/examples/circle.ml +++ b/examples/circle.ml @@ -2,8 +2,8 @@ open Joy let () = init (); - background (1., 1., 1., 1.); - let c = circle 50. in - set_color (0., 0., 0.); + background (255, 255, 255, 255); + let c = circle 50 in + set_color (0, 0, 0); render c; write ~filename:"circle.png" () diff --git a/examples/circle_packing.ml b/examples/circle_packing.ml index 09cf955..5deff7a 100644 --- a/examples/circle_packing.ml +++ b/examples/circle_packing.ml @@ -1,7 +1,7 @@ open Joy (* global constants // RNG initialization *) -let resolution = (1200., 900.) +let w, h = (900., 900.) let min_radius = 20. let max_radius = 150. let num_circles = 5_000 @@ -10,24 +10,22 @@ let shrink_factor = 0.85 let _ = Stdlib.Random.self_init () let palette = - List.map - (fun (r, g, b) -> (r /. 255., g /. 255., b /. 255.)) - [ - (* purple *) - (107., 108., 163.); - (* light blue *) - (135., 188., 189.); - (* green *) - (111., 153., 84.); - (* light purple *) - (150., 155., 199.); - (* light green *) - (137., 171., 124.); - (* dark purple *) - (67., 68., 117.); - (* darker purple *) - (44., 45., 84.); - ] + [ + (* purple *) + (107, 108, 163); + (* light blue *) + (135, 188, 189); + (* green *) + (111, 153, 84); + (* light purple *) + (150, 155, 199); + (* light green *) + (137, 171, 124); + (* dark purple *) + (67, 68, 117); + (* darker purple *) + (44, 45, 84); + ] (* utility Functions *) @@ -37,15 +35,9 @@ let distance (x1, y1) (x2, y2) = let dy = y2 -. y1 in sqrt ((dx *. dx) +. (dy *. dy)) -(* determines if two circles overlaps *) -let overlaps (p1, r1) (p2, r2) = - let dist = distance p1 p2 in - dist < r1 +. r2 - (* creates a random point within screen bounds *) let rand_point () = - ( Stdlib.Random.float (fst resolution *. 2.) -. fst resolution, - Stdlib.Random.float (snd resolution *. 2.) -. snd resolution ) + (Stdlib.Random.float w -. (w /. 2.), Stdlib.Random.float h -. (h /. 2.)) (* creates a circle with a random center point and radius *) let rand_circle () = @@ -54,6 +46,11 @@ let rand_circle () = (* creates a lis of packed circles *) let pack_circles () = + (* determines if two circles overlap *) + let overlaps (p1, r1) (p2, r2) = + let dist = distance p1 p2 in + dist < r1 +. r2 + in (* checks whether a circle intersects with a list of circles *) let check_overlaps lst current = List.fold_right (fun circle acc -> overlaps circle current || acc) lst false @@ -67,9 +64,10 @@ let pack_circles () = let new_circle = rand_circle () in let does_overlap = check_overlaps lst new_circle in let safe = List.length lst < num_circles - 1 && attempts < max_attempts in - if does_overlap && safe then pack lst (attempts + 1) - else if not safe then new_circle :: lst - else pack (new_circle :: lst) attempts + match (does_overlap, safe) with + | true, true -> pack lst (attempts + 1) + | true, false -> new_circle :: lst + | _ -> pack (new_circle :: lst) attempts in let attempts = 0 in let lst = [ rand_circle () ] in @@ -96,12 +94,16 @@ let make_concentric circle = (* main fn *) let () = - init ~size:resolution (); - background (1., 1., 1., 1.); - set_line_width 0.001; + init ~size:(int_of_float w, int_of_float h) (); + background (255, 255, 255, 255); + set_line_width 1; let circles = pack_circles () in let circles = List.flatten (List.map make_concentric circles) in List.iter - (fun ((x, y), radius) -> draw_with_color (circle ~c:(point x y) radius)) + (fun ((x, y), radius) -> + draw_with_color + (circle + ~c:(point (int_of_float x) (int_of_float y)) + (int_of_float radius))) circles; write ~filename:"Circle packing.png" () diff --git a/examples/circle_row_joy.ml b/examples/circle_row_joy.ml index 441b6c6..891037c 100644 --- a/examples/circle_row_joy.ml +++ b/examples/circle_row_joy.ml @@ -2,9 +2,10 @@ open Joy let () = init (); - background (1., 1., 1., 1.); - let base_circle = circle 50. in - let circle1 = base_circle |> translate (-100.) 0. in - let circle2 = base_circle |> translate 100. 0. in + background (255, 255, 255, 255); + let base_circle = circle 50 in + let circle1 = base_circle |> translate (-100) 0 in + let circle2 = base_circle |> translate 100 0 in + set_color (0, 0, 0); show [ circle1; base_circle; circle2 ]; write ~filename:"circle_row.png" () diff --git a/examples/complex.ml b/examples/complex.ml index 7fb0359..1e26925 100644 --- a/examples/complex.ml +++ b/examples/complex.ml @@ -7,7 +7,7 @@ open Joy *) (* creates a list containing numbers between a and b *) -let rec range a b = if a > b then [] else a :: range (a +. 1.) b +let rec range a b = if a > b then [] else a :: range (a + 1) b (* creates a list of (int * int) tuples, containing every combination of the elements of the two passsed lists *) @@ -16,21 +16,21 @@ let cartesian_product l l' = let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* radius which also acts as grid spacing *) - let radius = 50. in - let half_radius = radius /. 2. in + let radius = 50 in + let half_radius = radius / 2 in (* creating a grid with cartesian_product *) - let coords = cartesian_product (range (-5.) 5.) (range (-5.) 5.) in + let coords = cartesian_product (range (-5) 5) (range (-5) 5) in (* using map to turn that into a complex shape that is a grid of circles *) let complex_shape = complex (List.map - (fun (x, y) -> circle ~c:(point (x *. radius) (y *. radius)) radius) + (fun (x, y) -> circle ~c:(point (x * radius) (y * radius)) radius) coords) in (* translating that complex shape by radius / 2 *) let complex_transformed = translate half_radius half_radius complex_shape in - set_color (0., 0., 0.); + set_color (0, 0, 0); show [ complex_shape; complex_transformed ]; write ~filename:"complex.png" () diff --git a/examples/concentric_circles.ml b/examples/concentric_circles.ml index 7fd5521..fda373c 100644 --- a/examples/concentric_circles.ml +++ b/examples/concentric_circles.ml @@ -2,9 +2,9 @@ open Joy let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); - let init_circle = circle 200. in + let init_circle = circle 200 in let interval = 1. -. (1. /. 20.) in let rec make_concentric (arr : shape list) (i : int) : shape list = match (arr, i) with @@ -14,6 +14,6 @@ let () = | _, _ -> arr in let circles = complex (make_concentric [] 21) in - set_color (0., 0., 0.); + set_color (0, 0, 0); render circles; write ~filename:"concentric_circles.png" () diff --git a/examples/ellipse.ml b/examples/ellipse.ml index f0ae191..de47d44 100644 --- a/examples/ellipse.ml +++ b/examples/ellipse.ml @@ -2,10 +2,10 @@ open Joy let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* create an ellipse *) - let e = ellipse 100. 75. in + let e = ellipse 100 75 in (* render it *) - set_color (0., 0., 0.); + set_color (0, 0, 0); render e; write ~filename:"ellipse.png" () diff --git a/examples/higher_transforms.ml b/examples/higher_transforms.ml index e5ebc98..4e7e3a2 100644 --- a/examples/higher_transforms.ml +++ b/examples/higher_transforms.ml @@ -4,13 +4,13 @@ open Joy which applies its function args right-to-left. This allows us to create complex series transformations, that can be applied iteratively *) -let transform = compose (translate 10. 10.) (scale 0.9) +let transform = compose (translate 10 10) (scale 0.9) let () = init (); - background (1., 1., 1., 1.); - let initial = rectangle ~c:(point (-250.) (-250.)) 100. 100. in + background (255, 255, 255, 255); + let initial = rectangle ~c:(point (-250) (-250)) 100 100 in let shapes = repeat 32 transform initial in - set_color (0., 0., 0.); + set_color (0, 0, 0); render shapes; write ~filename:"higher_transforms.png" () diff --git a/examples/line.ml b/examples/line.ml index 91efb8d..40a0d57 100644 --- a/examples/line.ml +++ b/examples/line.ml @@ -1,24 +1,24 @@ open Joy -let size = 800. -let interval = 16. -let line_interval = 800. /. interval -let rec range a b = if a > b then [] else a :: range (a +. 1.) b -let inc x = x +. 1. +let size = 800 +let interval = 16 +let line_interval = 800 / interval +let rec range a b = if a > b then [] else a :: range (a + 1) b +let inc x = x + 1 let _ = init ~size:(size, size) (); - let half_size = size /. 2. in - background (1., 1., 1., 1.); + let half_size = size / 2 in + background (255, 255, 255, 255); let lines = List.map (fun i -> - let newx = i |> inc |> ( *. ) line_interval in + let newx = i |> inc |> ( * ) line_interval in line - ~a:(point (newx -. half_size) (-.half_size)) - (point (newx -. half_size) half_size)) - (range 0. interval) + ~a:(point (newx - half_size) (-half_size)) + (point (newx - half_size) half_size)) + (range 0 interval) in - set_color (0., 0., 0.); + set_color (0, 0, 0); show lines; write ~filename:"line.png" () diff --git a/examples/polygon.ml b/examples/polygon.ml index 8f6b355..4edf65f 100644 --- a/examples/polygon.ml +++ b/examples/polygon.ml @@ -4,11 +4,11 @@ let size = 100. let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); let poly = polygon [ { x = -.size; y = 0. }; { x = 0.; y = size }; { x = size; y = 0. } ] in - set_color (0., 0., 0.); + set_color (0, 0, 0); render poly; write ~filename:"polygon.png" () diff --git a/examples/rectangle.ml b/examples/rectangle.ml index ee8ab6c..32707ba 100644 --- a/examples/rectangle.ml +++ b/examples/rectangle.ml @@ -1,12 +1,12 @@ open Joy -let size = 100. +let size = 100 let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* creating a rectangle from points *) let rect = rectangle size size in - set_color (0., 0., 0.); + set_color (0, 0, 0); render rect; write ~filename:"rectangle.png" () diff --git a/examples/repeat.ml b/examples/repeat.ml index c762ca0..074a52f 100644 --- a/examples/repeat.ml +++ b/examples/repeat.ml @@ -10,9 +10,9 @@ open Joy let () = init (); - background (1., 1., 1., 1.); - let circle = circle ~c:(point (-100.) 0.) 50. in - let shapes = repeat 10 (translate 10. 0.) circle in - set_color (0., 0., 0.); + background (255, 255, 255, 255); + let circle = circle ~c:(point (-100) 0) 50 in + let shapes = repeat 10 (translate 10 0) circle in + set_color (0, 0, 0); render shapes; write ~filename:"repeat.png" () diff --git a/examples/rotate.ml b/examples/rotate.ml index ae593d5..81e68fc 100644 --- a/examples/rotate.ml +++ b/examples/rotate.ml @@ -5,12 +5,12 @@ let rec range a b = if a > b then [] else a :: range (a +. 1.) b let _ = init (); - background (1., 1., 1., 1.); - let rect = rectangle 100. 100. in + background (255, 255, 255, 255); + let rect = rectangle 100 100 in let nums = range 0. max in let rotated = List.map (fun i -> rotate (int_of_float (i /. max *. 360.0)) rect) nums in - set_color (0., 0., 0.); + set_color (0, 0, 0); show rotated; write ~filename:"rotation.png" () diff --git a/examples/star.ml b/examples/star.ml index 92ed387..a58b92d 100644 --- a/examples/star.ml +++ b/examples/star.ml @@ -9,16 +9,16 @@ let star_section i = let i = float_of_int i in let x = outer_radius *. cos (angle_step *. i) and y = outer_radius *. sin (angle_step *. i) in - let outer_point : point = { x; y } in + let outer_point = point (int_of_float x) (int_of_float y) in let x = inner_radius *. cos ((i +. 0.5) *. angle_step) and y = inner_radius *. sin ((i +. 0.5) *. angle_step) in [ outer_point; { x; y } ] let () = init (); - background (1., 1., 1., 1.); - set_line_width 0.0035; + background (255, 255, 255, 255); + set_line_width 3; let star = List.init points star_section |> List.flatten |> polygon in - set_color (0., 0., 0.); + set_color (0, 0, 0); render star; write ~filename:"star.png" () diff --git a/examples/translate_circle.ml b/examples/translate_circle.ml index 8f8b3dd..e1faaa1 100644 --- a/examples/translate_circle.ml +++ b/examples/translate_circle.ml @@ -2,12 +2,12 @@ open Joy let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* Create circle *) - let c1 = circle 100. in + let c1 = circle 100 in (* Translate it to the right by 100 *) - let c2 = translate 100. 0. c1 in + let c2 = translate 100 0 c1 in (* Display both circles *) - set_color (0., 0., 0.); + set_color (0, 0, 0); show [ c1; c2 ]; write ~filename:"translate_circle.png" () diff --git a/examples/translate_ellipse.ml b/examples/translate_ellipse.ml index 764ad15..7c9c738 100644 --- a/examples/translate_ellipse.ml +++ b/examples/translate_ellipse.ml @@ -2,12 +2,12 @@ open Joy let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* Create ellipse *) - let e1 = ellipse 60. 30. in + let e1 = ellipse 60 30 in (* Translate it to the right by 100 and up by 50 *) - let e2 = translate 100. 50. e1 in + let e2 = translate 100 50 e1 in (* Display both ellipses *) - set_color (0., 0., 0.); + set_color (0, 0, 0); show [ e1; e2 ]; write ~filename:"translate_ellipse.png" () diff --git a/examples/translate_rectangle.ml b/examples/translate_rectangle.ml index cf25d6d..cf5b984 100644 --- a/examples/translate_rectangle.ml +++ b/examples/translate_rectangle.ml @@ -2,12 +2,12 @@ open Joy let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); (* Create rectangle transform *) - let r1 = rectangle 200. 100. in - let r2 = translate 100. 0. r1 in + let r1 = rectangle 200 100 in + let r2 = translate 100 0 r1 in (* Display rectangle transform *) - set_color (0., 0., 0.); + set_color (0, 0, 0); show [ r1; r2 ]; write ~filename:"translate_rectangle.png" () diff --git a/examples/triangle.ml b/examples/triangle.ml index 5679067..91d7e26 100644 --- a/examples/triangle.ml +++ b/examples/triangle.ml @@ -4,12 +4,12 @@ let size = 100. let () = init (); - background (1., 1., 1., 1.); + background (255, 255, 255, 255); let triangle = polygon [ { x = -.size; y = 0. }; { x = 0.; y = size }; { x = size; y = 0. } ] in - set_color (0., 0., 0.); + set_color (0, 0, 0); render triangle; write ~filename:"triangle.png" () diff --git a/lib/context.ml b/lib/context.ml index 24d2904..0266e1d 100644 --- a/lib/context.ml +++ b/lib/context.ml @@ -2,7 +2,7 @@ type context = { ctx : Cairo.context; surface : Cairo.Surface.t; - size : float * float; + size : int * int; axes : bool; } @@ -19,26 +19,27 @@ let () = let fail () = raise (Context "not initialized") -let init_context line_width (x, y) axes = +let init_context line_width (w, h) axes = (* Fail if context has already been instantiated *) if Option.is_some !context then raise (Context "Cannot initialize context twice"); - let surface = - Cairo.Image.create Cairo.Image.ARGB32 ~w:(int_of_float x) - ~h:(int_of_float y) - in + let surface = Cairo.Image.create Cairo.Image.ARGB32 ~w ~h in let ctx = Cairo.create surface in - Cairo.scale ctx x y; + Cairo.scale ctx (float_of_int w) (float_of_int h); Cairo.set_line_width ctx line_width; - context := Some { ctx; surface; size = (x, y); axes } + context := Some { ctx; surface; size = (w, h); axes } let resolution () = match !context with Some ctx -> ctx.size | None -> fail () +let tmap3 f (a, b, c) = (f a, f b, f c) +let tmap4 f (a, b, c, d) = (f a, f b, f c, f d) +let ( >> ) f g x = g (f x) +let scale_color_channel x = x /. 256. let set_color color = match !context with | Some ctx -> - let r, g, b = color in + let r, g, b = tmap3 (float_of_int >> scale_color_channel) color in Cairo.set_source_rgba ctx.ctx r g b 1. | None -> fail () @@ -46,14 +47,17 @@ let set_color color = let background color = match !context with | Some ctx -> - let r, g, b, a = color in + let r, g, b, a = tmap4 (float_of_int >> scale_color_channel) color in Cairo.set_source_rgba ctx.ctx r g b a; Cairo.paint ctx.ctx | None -> fail () +(** Sets the width of lines for both stroke of shapes and line primitives. + Can be any positive integer, with larger numbers producing thicker lines. + default is 2 *) let set_line_width line_width = match !context with - | Some ctx -> Cairo.set_line_width ctx.ctx line_width + | Some ctx -> Cairo.set_line_width ctx.ctx (float_of_int line_width /. 1000.) | None -> fail () let save () = diff --git a/lib/context.mli b/lib/context.mli index bebec82..07e5ab4 100644 --- a/lib/context.mli +++ b/lib/context.mli @@ -1,7 +1,7 @@ type context = { ctx : Cairo.context; surface : Cairo.Surface.t; - size : float * float; + size : int * int; axes : bool; } @@ -10,11 +10,11 @@ val fail : unit -> unit exception Context of string -val init_context : float -> float * float -> bool -> unit -val resolution : unit -> float * float -val set_color : float * float * float -> unit -val background : float * float * float * float -> unit -val set_line_width : float -> unit +val init_context : float -> int * int -> bool -> unit +val resolution : unit -> int * int +val set_color : int * int * int -> unit +val background : int * int * int * int -> unit +val set_line_width : int -> unit val write : context -> string -> unit val save : unit -> unit val restore : unit -> unit diff --git a/lib/joy.ml b/lib/joy.ml index b32fddd..1096e11 100644 --- a/lib/joy.ml +++ b/lib/joy.ml @@ -1,6 +1,6 @@ let context = Context.context -type point = Shape.point +type 'a point = 'a Shape.point type shape = Shape.shape type shapes = Shape.shapes @@ -20,8 +20,8 @@ let set_color = Context.set_color let background = Context.background let set_line_width = Context.set_line_width -let init ?(line_width = 0.002) ?(size = (800., 800.)) ?(axes = false) () = - Context.init_context line_width size axes +let init ?(line_width = 2) ?(size = (800, 800)) ?(axes = false) () = + Context.init_context (float_of_int line_width /. 1000.) size axes let write ?(filename = "joy.png") () = match !Context.context with diff --git a/lib/joy.mli b/lib/joy.mli index b45d4da..d612149 100644 --- a/lib/joy.mli +++ b/lib/joy.mli @@ -1,27 +1,24 @@ -type point = Shape.point +type 'a point = 'a Shape.point type shape = Shape.shape type shapes = Shape.shapes -val point : float -> float -> point -val circle : ?c:point -> float -> shape -val rectangle : ?c:point -> float -> float -> shape -val ellipse : ?c:point -> float -> float -> shape -val line : ?a:point -> point -> shape -val polygon : point list -> shape +val point : int -> int -> float point +val circle : ?c:float point -> int -> shape +val rectangle : ?c:float point -> int -> int -> shape +val ellipse : ?c:float point -> int -> int -> shape +val line : ?a:float point -> float point -> shape +val polygon : float point list -> shape val complex : shapes -> shape val rotate : int -> shape -> shape -val translate : float -> float -> shape -> shape +val translate : int -> int -> shape -> shape val scale : float -> shape -> shape val compose : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c val repeat : int -> (shape -> shape) -> shape -> shape val context : Context.context option ref -val set_color : float * float * float -> unit -val background : float * float * float * float -> unit -val set_line_width : float -> unit - -val init : - ?line_width:float -> ?size:float * float -> ?axes:bool -> unit -> unit - +val set_color : int * int * int -> unit +val background : int * int * int * int -> unit +val set_line_width : int -> unit +val init : ?line_width:int -> ?size:int * int -> ?axes:bool -> unit -> unit val render : shape -> unit val show : shapes -> unit val write : ?filename:string -> unit -> unit diff --git a/lib/render.ml b/lib/render.ml index 4e56884..eb61e95 100644 --- a/lib/render.ml +++ b/lib/render.ml @@ -1,26 +1,25 @@ open Shape open Context +let tmap f (x, y) = (f x, f y) + let denormalize point = - let x, y = Context.resolution () in + let x, y = Context.resolution () |> tmap float_of_int in let canvas_mid = { x; y } /! 2. in - { x = point.x +. canvas_mid.x; y = point.y +. canvas_mid.y } + ((point.x +. canvas_mid.x) /. x, (point.y +. canvas_mid.y) /. y) -(* Scales points from 0-image size to 0-1 on both axes *) -let scale_point size point = - let { x; y } = denormalize point in - let x, y = (x /. fst size, y /. snd size) in - (x, y) +let euclid_norm (x, y) = sqrt (Float.pow x 2. +. Float.pow y 2.) /. 2. let draw_circle ctx ({ c; radius } : circle) = - let x, y = scale_point ctx.size c in - let radius = radius /. min (fst ctx.size) (snd ctx.size) in + let size = tmap float_of_int ctx.size in + let x, y = denormalize c in + let radius = radius /. euclid_norm size in Cairo.arc ctx.ctx x y ~r:radius ~a1:0. ~a2:(Float.pi *. 2.); Cairo.stroke ctx.ctx let create_control_points { c; rx; ry } = - let size = resolution () in - let x, y = scale_point size c in + let size = resolution () |> tmap float_of_int in + let x, y = denormalize c in let half_height = ry /. snd size in let width_two_thirds = rx /. fst size *. (2. /. 3.) *. 2. in ( { x; y = y -. half_height }, @@ -50,8 +49,8 @@ let draw_ellipse ctx ellipse = let draw_line ctx line = save (); - let x1, y1 = scale_point ctx.size line.a in - let x2, y2 = scale_point ctx.size line.b in + let x1, y1 = denormalize line.a in + let x2, y2 = denormalize line.b in Cairo.move_to ctx.ctx x1 y1; Cairo.line_to ctx.ctx x2 y2; Cairo.stroke ctx.ctx; @@ -82,7 +81,7 @@ let draw_polygon ctx polygon = let points = partition 2 ~step:1 (polygon @ [ List.hd polygon ]) in List.iter (fun pair -> - let pair = List.map (scale_point ctx.size) pair in + let pair = List.map denormalize pair in let (x1, y1), (x2, y2) = (List.nth pair 0, List.nth pair 1) in Cairo.move_to ctx.ctx x1 y1; Cairo.line_to ctx.ctx x2 y2) @@ -90,8 +89,7 @@ let draw_polygon ctx polygon = Cairo.move_to ctx.ctx 0. 0.; Cairo.stroke ctx.ctx -let rec render_shape ctx shape = - match shape with +let rec render_shape ctx = function | Circle circle -> draw_circle ctx circle | Ellipse ellipse -> draw_ellipse ctx ellipse | Line line -> draw_line ctx line @@ -110,10 +108,10 @@ let show shapes = let render_axes () = print_endline "rendering axes!"; save (); - let x, y = Context.resolution () in + let x, y = Context.resolution () |> tmap float_of_int in let half_x, half_y = (x /. 2., y /. 2.) in let x_axis = line ~a:{ x = 0.; y = -.half_y } { x = 0.; y = half_y } in let y_axis = line ~a:{ x = -.half_x; y = 0. } { x = half_x; y = 0. } in - set_color (0., 0., 0.); + set_color (0, 0, 0); show [ x_axis; y_axis ]; restore () diff --git a/lib/shape.ml b/lib/shape.ml index 771a4a1..8c1934d 100644 --- a/lib/shape.ml +++ b/lib/shape.ml @@ -1,8 +1,8 @@ -type point = { x : float; y : float } -type line = { a : point; b : point } -type circle = { c : point; radius : float } -type ellipse = { c : point; rx : float; ry : float } -type polygon = point list +type 'a point = { x : 'a; y : 'a } +type line = { a : float point; b : float point } +type circle = { c : float point; radius : float } +type ellipse = { c : float point; rx : float; ry : float } +type polygon = float point list type shape = | Circle of circle @@ -20,11 +20,19 @@ let ( /~ ) p1 p2 = { x = p1.x /. p2.x; y = p1.x /. p2.x } let ( -! ) { x; y } scalar = { x = x -. scalar; y = y -. scalar } let ( /! ) { x; y } scalar = { x = x /. scalar; y = y /. scalar } let ( *! ) { x; y } scalar = { x = x *. scalar; y = y *. scalar } -let point x y = { x; y } + +let pmap f { x; y } = { x = f x; y = f y } + +let point x y = + let x, y = (float_of_int x, float_of_int y) in + { x; y } + let center = { x = 0.; y = 0. } -let circle ?(c = center) r = Circle { c; radius = r } +let circle ?(c = center) r = Circle { c; radius = float_of_int r } + let rectangle ?(c = center) width height = + let width, height = (float_of_int width, float_of_int height) in let { x; y } = c -! ((width +. height) /. 4.) in Polygon [ @@ -34,7 +42,10 @@ let rectangle ?(c = center) width height = { x = x +. width; y }; ] -let ellipse ?(c = center) rx ry = Ellipse { c; rx; ry } +let ellipse ?(c = center) rx ry = + let rx, ry = (float_of_int rx, float_of_int ry) in + Ellipse { c; rx; ry } + let line ?(a = center) b = Line { a; b } let polygon lst_points = Polygon lst_points diff --git a/lib/shape.mli b/lib/shape.mli index 52bcc0c..44e4e10 100644 --- a/lib/shape.mli +++ b/lib/shape.mli @@ -1,8 +1,8 @@ -type point = { x : float; y : float } -type circle = { c : point; radius : float } -type ellipse = { c : point; rx : float; ry : float } -type polygon = point list -type line = { a : point; b : point } +type 'a point = { x : 'a; y : 'a } +type circle = { c : float point; radius : float } +type ellipse = { c : float point; rx : float; ry : float } +type polygon = float point list +type line = { a : float point; b : float point } type shape = | Circle of circle @@ -13,14 +13,15 @@ type shape = type shapes = shape list -val point : float -> float -> point -val ( /~ ) : point -> point -> point -val ( -! ) : point -> float -> point -val ( /! ) : point -> float -> point -val ( *! ) : point -> float -> point -val circle : ?c:point -> float -> shape -val rectangle : ?c:point -> float -> float -> shape -val ellipse : ?c:point -> float -> float -> shape +val point : int -> int -> float point +val ( /~ ) : float point -> float point -> float point +val ( -! ) : float point -> float -> float point +val ( /! ) : float point -> float -> float point +val ( *! ) : float point -> float -> float point +val pmap : ('a -> 'b) -> 'a point -> 'b point +val circle : ?c:float point -> int -> shape +val rectangle : ?c:float point -> int -> int -> shape +val ellipse : ?c:float point -> int -> int -> shape val complex : shape list -> shape -val line : ?a:point -> point -> shape -val polygon : point list -> shape +val line : ?a:float point -> float point -> shape +val polygon : float point list -> shape diff --git a/lib/transform.ml b/lib/transform.ml index d8c5885..24831f5 100644 --- a/lib/transform.ml +++ b/lib/transform.ml @@ -3,17 +3,21 @@ open Shape let rec translate dx dy shape = match shape with | Circle circle -> + let dx, dy = (float_of_int dx, float_of_int dy) in Circle { circle with c = { x = circle.c.x +. dx; y = circle.c.y +. dy } } | Ellipse ellipse -> + let dx, dy = (float_of_int dx, float_of_int dy) in Ellipse { ellipse with c = { x = ellipse.c.x +. dx; y = ellipse.c.y +. dy } } | Line line -> + let dx, dy = (float_of_int dx, float_of_int dy) in Line { a = { x = line.a.x +. dx; y = line.a.y +. dy }; b = { x = line.b.x +. dx; y = line.b.y +. dy }; } | Polygon polygon' -> + let dx, dy = (float_of_int dx, float_of_int dy) in polygon (List.map (fun { x; y } -> { x = x +. dx; y = y +. dy }) polygon') | Complex shapes -> Complex (List.map (translate dx dy) shapes) diff --git a/lib/transform.mli b/lib/transform.mli index 7a13b10..4dde434 100644 --- a/lib/transform.mli +++ b/lib/transform.mli @@ -1,4 +1,4 @@ -val translate : float -> float -> Shape.shape -> Shape.shape +val translate : int -> int -> Shape.shape -> Shape.shape val scale : float -> Shape.shape -> Shape.shape val rotate : int -> Shape.shape -> Shape.shape val compose : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c diff --git a/test/test_circle.ml b/test/test_circle.ml index 88a1d39..6153bfd 100644 --- a/test/test_circle.ml +++ b/test/test_circle.ml @@ -2,6 +2,6 @@ open Joy let run () = init (); - let c1 = circle 50. in - let c2 = circle 100. in + let c1 = circle 50 in + let c2 = circle 100 in show [ c1; c2 ] diff --git a/test/test_ellipse.ml b/test/test_ellipse.ml index 5714c64..df8600c 100644 --- a/test/test_ellipse.ml +++ b/test/test_ellipse.ml @@ -3,7 +3,7 @@ open Joy let run () = init (); - let e1 = ellipse 50. 30. in - let e2 = ellipse 100. 60. in + let e1 = ellipse 50 30 in + let e2 = ellipse 100 60 in show [ e1; e2 ] diff --git a/test/test_rectangle.ml b/test/test_rectangle.ml index 082cc59..73734e5 100644 --- a/test/test_rectangle.ml +++ b/test/test_rectangle.ml @@ -3,7 +3,7 @@ open Joy let run () = init (); - let r1 = rectangle 50. 30. in - let r2 = rectangle 100. 60. in + let r1 = rectangle 50 30 in + let r2 = rectangle 100 60 in show [ r1; r2 ] diff --git a/test/test_scale_shape.ml b/test/test_scale_shape.ml index 2429834..3b3f0df 100644 --- a/test/test_scale_shape.ml +++ b/test/test_scale_shape.ml @@ -2,13 +2,13 @@ open Joy let run () = init (); - let c1 = circle 50. in + let c1 = circle 50 in let c2 = scale 2. c1 in let c3 = scale 0.5 c1 in - let r1 = rectangle 100. 100. |> translate 10. 500. in + let r1 = rectangle 100 100 |> translate 10 500 in let r2 = scale 2. r1 in let r3 = scale 0.02 r1 in - let e1 = ellipse 30. 50. |> translate 500. 500. in + let e1 = ellipse 30 50 |> translate 500 500 in let e2 = scale 2. e1 in let e3 = scale 0.7 e1 in show [ c1; c2; c3; r1; r2; r3; e1; e2; e3 ]