Skip to content

Commit

Permalink
Fix ellipse rotation to work correctly (#126)
Browse files Browse the repository at this point in the history
* Fix ellipse rotation to work correctly

Previously, we only rotated the center of the ellipse, similar to the circle.
This commit adds a rotation field to the ellipse shape type which stores the
rotation of the ellipse in radians. And we use Cairo's rotate function when
rendering the ellipse.

Fixes #116 along with #121.

* Add example with ellipse rotation
  • Loading branch information
punchagan authored Mar 12, 2024
1 parent 4703b64 commit 48e067e
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 4 deletions.
6 changes: 5 additions & 1 deletion examples/dune
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
(modules rotate)
(libraries joy))

(executable
(name rotate_ellipse)
(modules rotate_ellipse)
(libraries joy))

(executable
(name line)
(modules line)
Expand Down Expand Up @@ -127,4 +132,3 @@
(name smile)
(modules smile)
(libraries joy))

15 changes: 15 additions & 0 deletions examples/rotate_ellipse.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
open Joy

let max = 32.
let rec range a b = if a > b then [] else a :: range (a +. 1.) b

let _ =
init ();
let rect = rectangle 100 50 |> translate 195 220 in
let ell = ellipse 100 50 |> translate 60 60 in
let nums = range 0. max in
let rotated =
List.map (fun i -> rotate (int_of_float (i /. max *. 360.0)) ell) nums
in
show (rect :: rotated);
write ~filename:"rotate_ellipse.png" ()
3 changes: 2 additions & 1 deletion lib/render.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let draw_circle ctx ({ c; radius; stroke; fill } : circle) =
Option.iter fill_circle fill;
Cairo.Path.clear ctx.ctx

let draw_ellipse ctx { c; rx; ry; stroke; fill } =
let draw_ellipse ctx { c; rx; ry; stroke; fill; rotation } =
let stroke_ellipse stroke =
set_color stroke;
Cairo.stroke_preserve ctx.ctx
Expand All @@ -31,6 +31,7 @@ let draw_ellipse ctx { c; rx; ry; stroke; fill } =

(* Translate and scale to create an ellipse from a circle *)
Cairo.translate ctx.ctx c.x (Float.neg c.y);
Cairo.rotate ctx.ctx rotation;
Cairo.scale ctx.ctx rx ry;
Cairo.arc ctx.ctx 0. 0. ~r:1. ~a1:0. ~a2:(2. *. Float.pi);

Expand Down
3 changes: 2 additions & 1 deletion lib/shape.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type ellipse = {
c : float point;
rx : float;
ry : float;
rotation : float;
stroke : color option;
fill : color option;
}
Expand Down Expand Up @@ -55,7 +56,7 @@ let rectangle ?(c = center) width height =

let ellipse ?(c = center) rx ry =
let rx, ry = (float_of_int rx, float_of_int ry) in
Ellipse { c; rx; ry; stroke = Some Color.black; fill = None }
Ellipse { c; rx; ry; stroke = Some Color.black; fill = None; rotation = 0. }

let line ?(a = center) b = Line { a; b; stroke = Color.black }

Expand Down
1 change: 1 addition & 0 deletions lib/shape.mli
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type ellipse = {
c : float point;
rx : float;
ry : float;
rotation : float;
stroke : color option;
fill : color option;
}
Expand Down
7 changes: 6 additions & 1 deletion lib/transform.ml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ let rotate_point degrees point =
let rec rotate degrees = function
| Circle circle' -> Circle { circle' with c = rotate_point degrees circle'.c }
| Ellipse ellipse' ->
Ellipse { ellipse' with c = rotate_point degrees ellipse'.c }
Ellipse
{
ellipse' with
c = rotate_point degrees ellipse'.c;
rotation = ellipse'.rotation +. to_radians degrees;
}
| Line line' -> Line { line' with a = rotate_point degrees line'.a; b = rotate_point degrees line'.b }
| Polygon polygon' ->
Polygon
Expand Down
1 change: 1 addition & 0 deletions lib/util.ml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ let rec partition n ?(step = 0) lst =

(* Misc *)
let range n = List.init n Fun.id
let to_radians degrees = degrees *. Stdlib.Float.pi /. 180.
1 change: 1 addition & 0 deletions lib/util.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ val ( >> ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
val take : int -> 'a list -> 'a list * 'a list
val partition : int -> ?step:int -> 'a list -> 'a list list
val range : int -> int list
val to_radians : float -> float

0 comments on commit 48e067e

Please sign in to comment.