Skip to content

Commit

Permalink
Merge pull request #102 from FayCarsons/randomness
Browse files Browse the repository at this point in the history
Random and Noise module
  • Loading branch information
FayCarsons authored Mar 1, 2024
2 parents 393d183 + 6b8d89f commit 9e6f891
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 35 deletions.
9 changes: 3 additions & 6 deletions examples/circle_packing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ let num_circles = 10000
(* Maximum attempts at finding new non-overlapping circles *)
let max_attempts = 100_000

(* Factor circles are scaled by *)
let _ = Random.self_init ()

let palette =
[
(* purple *)
Expand All @@ -35,12 +32,12 @@ let palette =
]

(* utility Functions *)
let rand_nth coll = List.length coll |> random |> List.nth coll
let tmap f (a, b) = (f a, f b)
let rand_nth coll = List.length coll |> Random.full_int |> List.nth coll

(* Pareto distribution float random for radii *)
let pareto scl alpha =
let x = Random.float (1. -. Float.epsilon) +. Float.epsilon in
let x = frandom (1. -. Float.epsilon) +. Float.epsilon in
scl *. ((1. -. x) ** (-1. /. alpha))

(* Clamp floats to [min..max] *)
Expand All @@ -63,7 +60,7 @@ let overlaps (x1, y1, r1) (x2, y2, r2) =
(* Creates a random point within screen bounds *)
let rand_point () =
let w, h = tmap float_of_int size in
(Random.float w -. (w /. 2.), Random.float h -. (h /. 2.))
(frandom w -. (w /. 2.), frandom h -. (h /. 2.))

(* Creates a circle with a random center point and radius *)
let rand_circle () =
Expand Down
4 changes: 2 additions & 2 deletions examples/dune
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@

(executable
(name flowfield)
(modules flowfield noise)
(libraries joy base))
(modules flowfield)
(libraries joy))

(executable
(name color)
Expand Down
13 changes: 6 additions & 7 deletions examples/flowfield.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ let size = 1200
let tau = 2. *. Float.pi
let num_steps = 6
let grid_divisor = 128
let _ = Random.self_init ()
let octaves = 4
let noise_scale = 2. +. Random.float 3.
let noise_scale = 2. +. Joy.frandom 3.

(* Utilities & color palette *)

(* Randomly shuffles a list *)
let shuffle xs =
let pairs = List.map (fun c -> (Random.bits (), c)) xs in
let pairs = List.map (fun c -> (Joy.random 0xFFFF, c)) xs in
let sorted = List.sort compare pairs in
List.map snd sorted

Expand All @@ -35,12 +34,12 @@ 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
let seed = Joy.frandom 100. in
Bigarray.Array2.init Bigarray.Float32 Bigarray.c_layout size size (fun x y ->
let noise =
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)
Joy.fractal_noise ~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)
Expand Down
12 changes: 0 additions & 12 deletions examples/noise.mli

This file was deleted.

9 changes: 3 additions & 6 deletions examples/quadtree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ let point_size = 1
let box_color = (0, 0, 0)
let point_color = (255, 1, 1)

(* Init rng *)
let _ = Random.self_init ()

(* Point utils *)
let splat n : point = { x = n; y = n }

Expand All @@ -27,17 +24,17 @@ let ( /! ) ({ x; y } : point) scalar : point =

(* Random utils for creating random clustered points *)
let rand_point () : point =
{ x = Random.float size -. half_size; y = Random.float size -. half_size }
{ x = Joy.frandom size -. half_size; y = Joy.frandom size -. half_size }

(* Creates a point within 50 units of a center *)
let centered_point (center : point) _: point =
let offset () = Random.float 100. -. 50. in
let offset () = Joy.frandom 100. -. 50. in
center +~ { x = offset (); y = offset () }

(* Creates a list of random points clustered around a center point *)
let cluster _ =
let center = rand_point () in
List.init (8 + Random.int 24) (centered_point center)
List.init (8 + Joy.random 24) (centered_point center)

(* Box and utils *)

Expand Down
2 changes: 1 addition & 1 deletion lib/dune
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(library
(name joy)
(public_name joy)
(libraries cairo2)
(libraries cairo2 base)
(wrapped false))
3 changes: 3 additions & 0 deletions lib/joy.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
include Random
include Shape
include Transform
include Color
Expand All @@ -19,3 +20,5 @@ let write ?(filename = "joy.png") () =
| None -> Context.fail ()

let show shapes = Render.show shapes


6 changes: 6 additions & 0 deletions lib/joy.mli
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ val compose : transformation -> transformation -> transformation
val repeat : int -> transformation -> transformation
val map_stroke : (color -> color) -> shape -> shape
val map_fill : (color -> color) -> shape -> shape

val random : ?min:int -> int -> int
val frandom : ?min:float -> float -> float
val noise : float list -> float
val fractal_noise : ?octaves:int -> float list -> float

val context : Context.context option ref
val set_line_width : int -> unit
val black : color
Expand Down
48 changes: 47 additions & 1 deletion examples/noise.ml → lib/random.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
open Base
(* Internal module for noise *)
module Noise = struct
open Base

(* borrowed from
https://gist.githubusercontent.com/tjammer/509981fed4d50683cdb800da5bf16ab1/raw/da2b8cc86718ef7e93e2e2c707dcfe443809d7cc/simplex.ml *)
Expand Down Expand Up @@ -122,3 +124,47 @@ let fractal2 octaves x y =
(amp +. amplitude) (i - 1)
in
loop 0.0 0.0 octaves
end

(* Library exposed to users *)

let initialized = ref false

let initialize () = Stdlib.Random.self_init (); initialized := true

(** Ranged integer random, produces a random int in range 0/min to max *)
let random ?(min = 0) max =
if not !initialized then initialize ();
min + Stdlib.Random.int (max - min)

(** Ranged float random, produces a random float in range 0./min to max *)
let frandom ?(min = 0.) max =
if not !initialized then initialize ();
min +. Stdlib.Random.float (max -. min)

(** Simplex noise, output in range -1..1 *)
let noise = function
| [] ->
print_endline "Noise noise requires 1-2 elements in arg list";
0.
| [ x ] ->
Noise.snoise1 x
| x :: y :: _ ->
Noise.snoise2 x y

(** Layered 'fractal' noise, output in range -1..1 *)
let fractal_noise ?(octaves = 5) = function
| [] ->
print_endline "Fractal noise requires 1-2 elements in arg list";
0.
| [ x ] ->
Noise.fractal1 octaves x
| x :: y :: _ ->
Noise.fractal2 octaves x y

(** Sets ref parameters of fractal noise, adjuting the visual character of the noise *)
let set_fractal_params ?frequency ?amplitude ?lacunarity ?persistence () =
Option.iter (fun n -> Noise.frequency := n) frequency;
Option.iter (fun n -> Noise.amplitude := n) amplitude;
Option.iter (fun n -> Noise.lacunarity := n) lacunarity;
Option.iter (fun n -> Noise.persistence := n) persistence

0 comments on commit 9e6f891

Please sign in to comment.