From 34817ebc3f9f06113e5e6c56f473c34834198860 Mon Sep 17 00:00:00 2001 From: Fay Carsons Date: Sat, 13 Jan 2024 13:17:22 -0500 Subject: [PATCH 1/5] added flowfield example, dune fmt --- examples/dune | 5 ++ examples/flowfield.ml | 96 ++++++++++++++++++++++++++++++++ examples/noise.ml | 124 ++++++++++++++++++++++++++++++++++++++++++ examples/noise.mli | 12 ++++ lib/shape.ml | 4 ++ 5 files changed, 241 insertions(+) create mode 100644 examples/flowfield.ml create mode 100644 examples/noise.ml create mode 100644 examples/noise.mli diff --git a/examples/dune b/examples/dune index 1c42610..0887f20 100644 --- a/examples/dune +++ b/examples/dune @@ -102,3 +102,8 @@ (name donut_with_scale) (modules donut_with_scale) (libraries joy)) + +(executable + (name flowfield) + (modules flowfield noise) + (libraries joy base)) diff --git a/examples/flowfield.ml b/examples/flowfield.ml new file mode 100644 index 0000000..4c726e3 --- /dev/null +++ b/examples/flowfield.ml @@ -0,0 +1,96 @@ +open Noise +open Joy + +let size = 800 +let tau = 2. *. Float.pi +let num_steps = 8 +let grid_divisor = 64 +let octaves = 6 +let noise_scale = 4. +let _ = Stdlib.Random.self_init +let seed = Stdlib.Random.float 1000. + +let palette = + List.map + (fun (r, g, b) -> (r /. 255., g /. 255., b /. 255.)) + [ + (74., 58., 59.); + (152., 65., 54.); + (194., 106., 122.); + (236., 192., 161.); + (240., 240., 228.); + ] + +let clamp = function + | n when n > size - 1 -> size - 1 + | n when n < 0 -> 0 + | n -> n + +let fclamp max = function f when f > max -> max | f when f < 0. -> 0. | f -> f + +let flowfield () = + Bigarray.Array2.init Bigarray.Float32 Bigarray.c_layout size size (fun x y -> + let noise = + fractal2 octaves + ((float_of_int x /. float_of_int size *. noise_scale) +. seed) + ((float_of_int y /. float_of_int size *. noise_scale) +. seed) + in + let uni = (noise *. 0.5) +. 0.5 in + fclamp tau uni *. tau) + +let grid divison = + let grid_size = size / divison in + let spacing = size / grid_size in + List.init (grid_size * grid_size) (fun i -> + (i / grid_size * spacing, i mod grid_size * spacing)) + +let uni_to_bi (x, y) = + let x = x - (size / 2) in + let y = y - (size / 2) in + (float_of_int x, float_of_int y) + +let vector_of_angle angle = + ( sin angle |> Float.round |> int_of_float, + cos angle |> Float.round |> int_of_float ) + +let rec step n (x, y) flowfield = + if n >= 0 then + let cx, cy = (clamp x, clamp y) in + let angle = Bigarray.Array2.get flowfield cx cy in + let dx, dy = vector_of_angle angle in + step (n - 1) (x + dx, y + dy) flowfield + else (x, y) + +let make_line flowfield (x, y) = + let cx, cy = (clamp x, clamp y) in + let angle = Bigarray.Array2.get flowfield cx cy in + let dx, dy = vector_of_angle angle in + let next = (x + dx, y + dy) in + let final = step num_steps next flowfield in + let ax, ay = uni_to_bi (x, y) in + let bx, by = uni_to_bi final in + (line ~a:(point ax ay) (point bx by), (cx, cy)) + +let render_with_color flowfield line (x, y) = + let color_idx = + Bigarray.Array2.get flowfield x y /. tau + |> ( *. ) (float_of_int (List.length palette)) + |> int_of_float + in + let _ = print_int color_idx in + let color = List.nth palette color_idx in + set_color color; + render line + +let () = + init (); + background (1., 1., 1., 1.); + let flowfield = flowfield () in + let interval = size / grid_divisor in + let indices = grid interval in + let lines, points = List.map (make_line flowfield) indices |> List.split in + let centered = + List.map (translate (float_of_int interval) (float_of_int interval)) lines + in + List.iter2 (render_with_color flowfield) centered points; + write ~filename:"flowfield.png" () diff --git a/examples/noise.ml b/examples/noise.ml new file mode 100644 index 0000000..b8c6016 --- /dev/null +++ b/examples/noise.ml @@ -0,0 +1,124 @@ +open Base + +(* borrowed from + https://gist.githubusercontent.com/tjammer/509981fed4d50683cdb800da5bf16ab1/raw/da2b8cc86718ef7e93e2e2c707dcfe443809d7cc/simplex.ml *) +let permutation = + [| + 151; 160; 137; 91; 90; 15; 131; 13; 201; 95; 96; 53; 194; 233; 7; 225; 140; + 36; 103; 30; 69; 142; 8; 99; 37; 240; 21; 10; 23; 190; 6; 148; 247; 120; + 234; 75; 0; 26; 197; 62; 94; 252; 219; 203; 117; 35; 11; 32; 57; 177; 33; + 88; 237; 149; 56; 87; 174; 20; 125; 136; 171; 168; 68; 175; 74; 165; 71; + 134; 139; 48; 27; 166; 77; 146; 158; 231; 83; 111; 229; 122; 60; 211; 133; + 230; 220; 105; 92; 41; 55; 46; 245; 40; 244; 102; 143; 54; 65; 25; 63; 161; + 1; 216; 80; 73; 209; 76; 132; 187; 208; 89; 18; 169; 200; 196; 135; 130; + 116; 188; 159; 86; 164; 100; 109; 198; 173; 186; 3; 64; 52; 217; 226; 250; + 124; 123; 5; 202; 38; 147; 118; 126; 255; 82; 85; 212; 207; 206; 59; 227; + 47; 16; 58; 17; 182; 189; 28; 42; 223; 183; 170; 213; 119; 248; 152; 2; 44; + 154; 163; 70; 221; 153; 101; 155; 167; 43; 172; 9; 129; 22; 39; 253; 19; 98; + 108; 110; 79; 113; 224; 232; 178; 185; 112; 104; 218; 246; 97; 228; 251; 34; + 242; 193; 238; 210; 144; 12; 191; 179; 162; 241; 81; 51; 145; 235; 249; 14; + 239; 107; 49; 192; 214; 31; 181; 199; 106; 157; 184; 84; 204; 176; 115; 121; + 50; 45; 127; 4; 150; 254; 138; 236; 205; 93; 222; 114; 67; 29; 24; 72; 243; + 141; 128; 195; 78; 66; 215; 61; 156; 180; + |] +[@@ocamlformat "break-collection-expressions=wrap"] + +let hash n = permutation.(Int.of_float n land 255) + +let grad1 hash x = + let h = hash land 0x0F in + (* gradient value 1.0, 2.0 .. 8.0 *) + let grad = 1.0 +. Float.of_int (h land 7) in + let grad = if h land 8 <> 0 then -.grad else grad in + grad *. x + +let grad2 hash x y = + let h = hash land 0x3F in + let u, v = if h < 4 then (x, y) else (y, x) in + (if h land 1 <> 0 then -.u else u) + +. if h land 2 <> 0 then -2.0 *. v else 2.0 *. v + +let snoise1 x = + let i0 = Float.round_down x in + let i1 = i0 +. 1.0 in + let x0 = x -. i0 in + let x1 = x0 -. 1.0 in + let t0 = 1.0 -. (x0 *. x0) in + let t0 = t0 *. t0 in + let n0 = t0 *. t0 *. grad1 (hash i0) x0 in + let t1 = 1.0 -. (x1 *. x1) in + let t1 = t1 *. t1 in + let n1 = t1 *. t1 *. grad1 (hash i1) x1 in + (* The maximum value of this noise is 8*(3/4)^4 = 2.53125 *) + (* A factor of 0.395 scales to fit exactly within [-1,1] *) + 0.395 *. (n0 +. n1) + +let snoise2 x y = + let _F2 = 0.366025403 in + (* F2 = (sqrt(3) - 1) / 2*) + let _G2 = 0.211324865 in + (*G2 = (3 - sqrt(3)) / 6 = F2 / (1 + 2 * K)*) + (* skew the input space to determine which simplex cell we're in *) + let s = (x +. y) *. _F2 in + let xs, ys = (x +. s, y +. s) in + let i, j = Float.(round_down xs, round_down ys) in + (* unskew the cell origin back to (x, y) space *) + let t = (i +. j) *. _G2 in + let _X0 = i -. t in + let _Y0 = j -. t in + let x0, y0 = (x -. _X0, y -. _Y0) in + (* determine which simplex we're in *) + let i1, j1 = if Poly.(x0 > y0) then (1., 0.) else (0., 1.) in + (* A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and *) + (* a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where *) + (* c = (3-sqrt(3))/6 *) + let x1, y1 = Float.(x0 - i1 + _G2, y0 - j1 + _G2) in + let x2, y2 = Float.(x0 - 1.0 + (2.0 * _G2), y0 - 1.0 + (2.0 * _G2)) in + (* Work out the hashed gradient indices of the three simplex corners *) + let gi0 = (j |> hash |> Float.of_int) +. i |> hash in + let gi1 = (j +. j1 |> hash |> Float.of_int) +. i +. i1 |> hash in + let gi2 = (j +. 1. |> hash |> Float.of_int) +. i +. 1. |> hash in + let contrib x y gi = + let t = 0.5 -. (x *. x) -. (y *. y) in + if Float.(t < 0.0) then 0.0 + else + let t = t *. t in + t *. t *. grad2 gi x y + in + (* Calculate the contribution from the first corner *) + let n0 = contrib x0 y0 gi0 in + (* Calculate the contribution from the second corner *) + let n1 = contrib x1 y1 gi1 in + (* Calculate the contribution from the third corner *) + let n2 = contrib x2 y2 gi2 in + 45.23065 *. (n0 +. n1 +. n2) + +(* constants *) +let frequency = ref 1.0 +let amplitude = ref 1.0 +let lacunarity = ref 2.0 +let persistence = ref 0.5 + +let fractal1 octaves x = + let rec loop noise amp i = + if i = 0 then noise /. amp + else + let frequency = !frequency *. Float.int_pow !lacunarity (i - 1) in + let amplitude = !amplitude *. Float.int_pow !persistence (i - 1) in + loop + (noise +. (amplitude *. snoise1 (x *. frequency))) + (amp +. amplitude) (i - 1) + in + loop 0.0 0.0 octaves + +let fractal2 octaves x y = + let rec loop noise amp i = + if i = 0 then noise /. amp + else + let frequency = !frequency *. Float.int_pow !lacunarity (i - 1) in + let amplitude = !amplitude *. Float.int_pow !persistence (i - 1) in + loop + (noise +. (amplitude *. snoise2 (x *. frequency) (y *. frequency))) + (amp +. amplitude) (i - 1) + in + loop 0.0 0.0 octaves diff --git a/examples/noise.mli b/examples/noise.mli new file mode 100644 index 0000000..af1455a --- /dev/null +++ b/examples/noise.mli @@ -0,0 +1,12 @@ +val permutation : int array +val hash : float -> int +val grad1 : int -> float -> float +val grad2 : int -> float -> float -> float +val snoise1 : float -> float +val snoise2 : float -> float -> float +val frequency : float ref +val amplitude : float ref +val lacunarity : float ref +val persistence : float ref +val fractal1 : int -> float -> float +val fractal2 : int -> float -> float -> float diff --git a/lib/shape.ml b/lib/shape.ml index b47b594..d6f7089 100644 --- a/lib/shape.ml +++ b/lib/shape.ml @@ -41,10 +41,14 @@ let rectangle ?(c = center) width height = { x = x1 +. w; y = y1 }; ] +<<<<<<< HEAD let ellipse ?(c = center) rx ry = let rx, ry = (float_of_int rx, float_of_int ry) in Ellipse { c; rx; ry } +======= +let ellipse ?(c = center) rx ry = Ellipse { c; rx; ry } +>>>>>>> 7ad720e (added flowfield example, dune fmt) let line ?(a = center) b = Line { a; b } let polygon lst_points = Polygon lst_points From d403b072aab1a1c91d2da47b3daf08c8569ada23 Mon Sep 17 00:00:00 2001 From: Fay Carsons Date: Mon, 22 Jan 2024 21:23:14 -0500 Subject: [PATCH 2/5] fixed random seeding issue, switched line list to array, fmt --- examples/flowfield.ml | 44 +++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/examples/flowfield.ml b/examples/flowfield.ml index 4c726e3..a6fa592 100644 --- a/examples/flowfield.ml +++ b/examples/flowfield.ml @@ -1,14 +1,20 @@ -open Noise open Joy -let size = 800 +(* Constants *) +let size = 1200 let tau = 2. *. Float.pi -let num_steps = 8 -let grid_divisor = 64 -let octaves = 6 -let noise_scale = 4. -let _ = Stdlib.Random.self_init -let seed = Stdlib.Random.float 1000. +let num_steps = 12 +let grid_divisor = 256 +let _ = Random.self_init () +let octaves = 4 +let noise_scale = 2. +. Random.float 3. + +(* Utilities & color palette *) + +let shuffle xs = + let nd = List.map (fun c -> (Random.bits (), c)) xs in + let sond = List.sort compare nd in + List.map snd sond let palette = List.map @@ -20,6 +26,7 @@ let palette = (236., 192., 161.); (240., 240., 228.); ] + |> shuffle let clamp = function | n when n > size - 1 -> size - 1 @@ -28,31 +35,38 @@ let clamp = function let fclamp max = function f when f > max -> max | f when f < 0. -> 0. | f -> f +(* Initialize flowfield, a large 2D array containing angles determined by + seeded simplex noise sampled at each coordinate *) let flowfield () = + let seed = Random.float 100. in Bigarray.Array2.init Bigarray.Float32 Bigarray.c_layout size size (fun x y -> let noise = - fractal2 octaves + Noise.fractal2 octaves ((float_of_int x /. float_of_int size *. noise_scale) +. seed) ((float_of_int y /. float_of_int size *. noise_scale) +. seed) in let uni = (noise *. 0.5) +. 0.5 in fclamp tau uni *. tau) +(* Create a n*n grid of points where lines will be placed *) let grid divison = let grid_size = size / divison in let spacing = size / grid_size in - List.init (grid_size * grid_size) (fun i -> + Array.init (grid_size * grid_size) (fun i -> (i / grid_size * spacing, i mod grid_size * spacing)) +(* scale 0-n coordinates to [-n/2..n/2] *) let uni_to_bi (x, y) = let x = x - (size / 2) in let y = y - (size / 2) in (float_of_int x, float_of_int y) +(* Create a 2D vector from an angle *) let vector_of_angle angle = ( sin angle |> Float.round |> int_of_float, cos angle |> Float.round |> int_of_float ) +(* Step along the flowfield, following the angles at each point visited *) let rec step n (x, y) flowfield = if n >= 0 then let cx, cy = (clamp x, clamp y) in @@ -61,6 +75,7 @@ let rec step n (x, y) flowfield = step (n - 1) (x + dx, y + dy) flowfield else (x, y) +(* Given a coordinate, draws a line starting at that point, following flowfield *) let make_line flowfield (x, y) = let cx, cy = (clamp x, clamp y) in let angle = Bigarray.Array2.get flowfield cx cy in @@ -71,13 +86,13 @@ let make_line flowfield (x, y) = let bx, by = uni_to_bi final in (line ~a:(point ax ay) (point bx by), (cx, cy)) +(* Renders line with color based on its angle *) let render_with_color flowfield line (x, y) = let color_idx = Bigarray.Array2.get flowfield x y /. tau |> ( *. ) (float_of_int (List.length palette)) |> int_of_float in - let _ = print_int color_idx in let color = List.nth palette color_idx in set_color color; render line @@ -85,12 +100,13 @@ let render_with_color flowfield line (x, y) = let () = init (); background (1., 1., 1., 1.); + set_line_width 0.0005; let flowfield = flowfield () in let interval = size / grid_divisor in let indices = grid interval in - let lines, points = List.map (make_line flowfield) indices |> List.split in + let lines, points = Array.map (make_line flowfield) indices |> Array.split in let centered = - List.map (translate (float_of_int interval) (float_of_int interval)) lines + Array.map (translate (float_of_int interval) (float_of_int interval)) lines in - List.iter2 (render_with_color flowfield) centered points; + Array.iter2 (render_with_color flowfield) centered points; write ~filename:"flowfield.png" () From 49922426ee2bc78bb59daff12c8adac07c6d2071 Mon Sep 17 00:00:00 2001 From: Fay Carsons Date: Fri, 2 Feb 2024 11:46:33 -0500 Subject: [PATCH 3/5] migrate to int api --- examples/flowfield.ml | 38 ++++++++++++++++++-------------------- lib/shape.ml | 4 ---- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/examples/flowfield.ml b/examples/flowfield.ml index a6fa592..0678512 100644 --- a/examples/flowfield.ml +++ b/examples/flowfield.ml @@ -1,30 +1,27 @@ -open Joy - (* Constants *) let size = 1200 let tau = 2. *. Float.pi -let num_steps = 12 -let grid_divisor = 256 +let num_steps = 6 +let grid_divisor = 128 let _ = Random.self_init () let octaves = 4 let noise_scale = 2. +. Random.float 3. (* Utilities & color palette *) +(* Randomly shuffles a list *) let shuffle xs = - let nd = List.map (fun c -> (Random.bits (), c)) xs in - let sond = List.sort compare nd in - List.map snd sond + let pairs = List.map (fun c -> (Random.bits (), c)) xs in + let sorted = List.sort compare pairs in + List.map snd sorted let palette = - List.map - (fun (r, g, b) -> (r /. 255., g /. 255., b /. 255.)) [ - (74., 58., 59.); - (152., 65., 54.); - (194., 106., 122.); - (236., 192., 161.); - (240., 240., 228.); + (74, 58, 59); + (152, 65, 54); + (194, 106, 122); + (236, 192, 161); + (240, 240, 228); ] |> shuffle @@ -84,7 +81,7 @@ let make_line flowfield (x, y) = let final = step num_steps next flowfield in let ax, ay = uni_to_bi (x, y) in let bx, by = uni_to_bi final in - (line ~a:(point ax ay) (point bx by), (cx, cy)) + (Joy.line ~a:{x = ax;y = ay} {x = bx; y = by}, (cx, cy)) (* Renders line with color based on its angle *) let render_with_color flowfield line (x, y) = @@ -94,19 +91,20 @@ let render_with_color flowfield line (x, y) = |> int_of_float in let color = List.nth palette color_idx in - set_color color; - render line + Joy.set_color color; + Joy.render line let () = + let open Joy in init (); - background (1., 1., 1., 1.); - set_line_width 0.0005; + background (255, 255, 255, 255); + set_line_width 3; let flowfield = flowfield () in let interval = size / grid_divisor in let indices = grid interval in let lines, points = Array.map (make_line flowfield) indices |> Array.split in let centered = - Array.map (translate (float_of_int interval) (float_of_int interval)) lines + Array.map (translate interval interval) lines in Array.iter2 (render_with_color flowfield) centered points; write ~filename:"flowfield.png" () diff --git a/lib/shape.ml b/lib/shape.ml index d6f7089..b47b594 100644 --- a/lib/shape.ml +++ b/lib/shape.ml @@ -41,14 +41,10 @@ let rectangle ?(c = center) width height = { x = x1 +. w; y = y1 }; ] -<<<<<<< HEAD let ellipse ?(c = center) rx ry = let rx, ry = (float_of_int rx, float_of_int ry) in Ellipse { c; rx; ry } -======= -let ellipse ?(c = center) rx ry = Ellipse { c; rx; ry } ->>>>>>> 7ad720e (added flowfield example, dune fmt) let line ?(a = center) b = Line { a; b } let polygon lst_points = Polygon lst_points From 1d7d6a0842fe41a339391cf3c7dba52a57411a59 Mon Sep 17 00:00:00 2001 From: Fay Carsons Date: Tue, 27 Feb 2024 14:07:06 -0500 Subject: [PATCH 4/5] update flowfield.ml to new API --- examples/flowfield.ml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/flowfield.ml b/examples/flowfield.ml index 0678512..906f56d 100644 --- a/examples/flowfield.ml +++ b/examples/flowfield.ml @@ -49,7 +49,7 @@ let flowfield () = let grid divison = let grid_size = size / divison in let spacing = size / grid_size in - Array.init (grid_size * grid_size) (fun i -> + List.init (grid_size * grid_size) (fun i -> (i / grid_size * spacing, i mod grid_size * spacing)) (* scale 0-n coordinates to [-n/2..n/2] *) @@ -83,28 +83,27 @@ let make_line flowfield (x, y) = let bx, by = uni_to_bi final in (Joy.line ~a:{x = ax;y = ay} {x = bx; y = by}, (cx, cy)) -(* Renders line with color based on its angle *) -let render_with_color flowfield line (x, y) = - let color_idx = - Bigarray.Array2.get flowfield x y /. tau +(* Adds color to line, based on its angle *) +let add_color flowfield line (x, y) = + let color = + Bigarray.Array2.get flowfield x y /. tau |> ( *. ) (float_of_int (List.length palette)) |> int_of_float + |> List.nth palette in - let color = List.nth palette color_idx in - Joy.set_color color; - Joy.render line + line |> Joy.with_stroke color let () = let open Joy in init (); - background (255, 255, 255, 255); set_line_width 3; let flowfield = flowfield () in let interval = size / grid_divisor in let indices = grid interval in - let lines, points = Array.map (make_line flowfield) indices |> Array.split in + let lines, points = List.map (make_line flowfield) indices |> List.split in let centered = - Array.map (translate interval interval) lines + List.map (translate interval interval) lines in - Array.iter2 (render_with_color flowfield) centered points; + let lines = List.map2 (add_color flowfield) centered points in + show lines; write ~filename:"flowfield.png" () From 1b3f42e21ad82bdbf06274b42193c8a51ada6d0e Mon Sep 17 00:00:00 2001 From: Fay Carsons Date: Tue, 27 Feb 2024 14:09:14 -0500 Subject: [PATCH 5/5] fmt --- examples/circle_packing.ml | 4 +--- examples/dune | 2 +- examples/flowfield.ml | 33 +++++++++++++++------------------ lib/joy.ml | 5 ++--- lib/render.ml | 7 ++----- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/examples/circle_packing.ml b/examples/circle_packing.ml index e94d733..4b20e27 100644 --- a/examples/circle_packing.ml +++ b/examples/circle_packing.ml @@ -94,9 +94,7 @@ let () = let circles = List.map (fun ((x, y), radius) -> - circle - ~c:{x; y} - (int_of_float radius) + circle ~c:{ x; y } (int_of_float radius) |> with_stroke (rand_nth palette)) concentric in diff --git a/examples/dune b/examples/dune index b3a8ec1..139ec32 100644 --- a/examples/dune +++ b/examples/dune @@ -103,7 +103,7 @@ (modules donut_with_scale) (libraries joy)) -(executable +(executable (name flowfield) (modules flowfield noise) (libraries joy base)) diff --git a/examples/flowfield.ml b/examples/flowfield.ml index 906f56d..6903b4f 100644 --- a/examples/flowfield.ml +++ b/examples/flowfield.ml @@ -16,13 +16,13 @@ let shuffle xs = List.map snd sorted let palette = - [ - (74, 58, 59); - (152, 65, 54); - (194, 106, 122); - (236, 192, 161); - (240, 240, 228); - ] + [ + (74, 58, 59); + (152, 65, 54); + (194, 106, 122); + (236, 192, 161); + (240, 240, 228); + ] |> shuffle let clamp = function @@ -81,17 +81,16 @@ let make_line flowfield (x, y) = let final = step num_steps next flowfield in let ax, ay = uni_to_bi (x, y) in let bx, by = uni_to_bi final in - (Joy.line ~a:{x = ax;y = ay} {x = bx; y = by}, (cx, cy)) + (Joy.line ~a:{ x = ax; y = ay } { x = bx; y = by }, (cx, cy)) (* Adds color to line, based on its angle *) -let add_color flowfield line (x, y) = - let color = - Bigarray.Array2.get flowfield x y /. tau +let add_color flowfield line (x, y) = + let color = + Bigarray.Array2.get flowfield x y /. tau |> ( *. ) (float_of_int (List.length palette)) - |> int_of_float - |> List.nth palette + |> int_of_float |> List.nth palette in - line |> Joy.with_stroke color + line |> Joy.with_stroke color let () = let open Joy in @@ -101,9 +100,7 @@ let () = let interval = size / grid_divisor in let indices = grid interval in let lines, points = List.map (make_line flowfield) indices |> List.split in - let centered = - List.map (translate interval interval) lines - in - let lines = List.map2 (add_color flowfield) centered points in + let centered = List.map (translate interval interval) lines in + let lines = List.map2 (add_color flowfield) centered points in show lines; write ~filename:"flowfield.png" () diff --git a/lib/joy.ml b/lib/joy.ml index b6eb36a..a48308c 100644 --- a/lib/joy.ml +++ b/lib/joy.ml @@ -36,9 +36,8 @@ let set_line_width = Context.set_line_width let init ?(background = Color.white) ?(line_width = 2) ?(size = (500, 500)) ?(axes = false) () = - Context.init_context (Color.opaque background) - (float_of_int line_width) - size axes + Context.init_context (Color.opaque background) (float_of_int line_width) size + axes let write ?(filename = "joy.png") () = match !Context.context with diff --git a/lib/render.ml b/lib/render.ml index eca4a77..fdf029b 100644 --- a/lib/render.ml +++ b/lib/render.ml @@ -17,7 +17,7 @@ let draw_circle ctx ({ c; radius; stroke; fill } : circle) = Option.iter fill_circle fill; Cairo.Path.clear ctx.ctx -let create_control_points ({x; y}, rx, ry) = +let create_control_points ({ x; y }, rx, ry) = let half_height = ry /. 2. in let width_two_thirds = rx *. (2. /. 3.) *. 2. in ( { x; y = y -. half_height }, @@ -74,10 +74,7 @@ let rec partition n ?(step = 0) lst = | [] -> [] | _ -> let taken, _ = take n lst in - if List.length taken = n then - taken - :: - partition n ~step (List.tl lst) + if List.length taken = n then taken :: partition n ~step (List.tl lst) else [] let draw_polygon ctx { vertices = points; stroke; fill } =