-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding color handling #90
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This is useful refactoring. Some comments below.
lib/shape.mli
Outdated
type circle = { c : point; radius : float; color : Color.color } | ||
type ellipse = { c : point; rx : float; ry : float; color : Color.color } | ||
type polygon = { vertices : point list; color : Color.color } | ||
type line = { a : point; b : point; color : Color.color } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we need not expose the internals of shape types in the mli file. But, I see that they're used in the Transform
module, so we can't do away with it. Makes me wonder whether we should put them all in the Shape module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put all the transforms in shape.ml? I don't think that would bulk it up too much so I wouldn't have a problem with it, but I think I do have a small preference for breaking up projects like this.
1690e13
to
b1a2518
Compare
Thanks! This looks great! I have suggested some renaming and refactor changes. Please go through the review. |
examples/circle_packing.ml
Outdated
@@ -7,7 +8,7 @@ let max_radius = 150. | |||
let num_circles = 5_000 | |||
let max_attempts = 100_000 | |||
let shrink_factor = 0.85 | |||
let _ = Stdlib.Random.self_init () | |||
let _ = Rand.self_init () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renaming seems unnecessary. Because Random is part of Stdlib, you can e.g. do Random.self_init
. I would recommend that so it is easier to read for someone who knows the module (no need to wonder if this is part of the stdlib or a module defined in this repo).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm planning on entirely rewriting this example as it broke when we migrated to the Cairo backend. Will keep comments regarding it in mind, though
examples/circle_packing.ml
Outdated
@@ -29,20 +30,21 @@ let palette = | |||
|
|||
(* utility Functions *) | |||
|
|||
let rand_nth coll = List.length coll |> Rand.full_int |> List.nth coll |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is coll
here?
Can you think of a name so it is obvious what it stands for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also refactor this to make the random selection clearer. Something like this:
let n = Random.full_int (List.length coll) in
List.nth n coll
I like this blog's explanation on why it's helpful (find for Explaining variables) https://henrikwarne.com/2024/01/10/tidy-first/
examples/circle_packing.ml
Outdated
|
||
(* creates a circle with a random center point and radius *) | ||
let rand_circle () = | ||
let point = rand_point () in | ||
(point, min_radius +. Stdlib.Random.float (max_radius -. min_radius)) | ||
(point, min_radius +. Rand.float (max_radius -. min_radius)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here as above, please use Random
directly
examples/circle_packing.ml
Outdated
List.map | ||
(fun ((x, y), radius) -> | ||
circle | ||
~c:(point (int_of_float x) (int_of_float y)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay to lose the accuracy here when converting from float to int?
lib/context.ml
Outdated
@@ -65,3 +52,15 @@ let save () = | |||
|
|||
let restore () = | |||
match !context with Some ctx -> Cairo.restore ctx.ctx | None -> fail () | |||
|
|||
let init_context background_color line_width ((x, y) : int * int) axes = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't only have a type signature for one parameter.
That should be in the .mli
file.
Also, if these are the dimensions of the canvas, w
and h
would be more consistent names - x
, y
for point coordinates, and w
, h
for canvas size
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah this was left over from the type inference system insisting that these were floats, I should just be able to remove it.
Will rename x,y as well
@@ -10,7 +10,7 @@ val fail : unit -> unit | |||
|
|||
exception Context of string | |||
|
|||
val init_context : float -> int * int -> bool -> unit | |||
val init_context : int * int * int * int -> float -> int * int -> bool -> unit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have a named type for int * int * int * int
, but that doesn't have to be part of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an RGBA color which is only used in setting the background color. Which is why I was hesitant to give it an alias. I think our current color type should probably keep its name, any thoughts what this should be named?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conflict is why I thought it would be better to deal with it later. This is OK for now and shouldn't block the merge.
Q - can we have only one color type for both background/fill that has RGBA parts, or is that not supported by Cairo for strokes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought was that since the focus of this library is simplicity, making users deal with an alpha value(which is almost always going to be at 255/1.0) every time they want to set the color of a shape would be a nuisance.
In my experience, creative coding libraries have a 'set_color' function that takes RGB and maybe another that takes RGBA or just alpha.
Cairo (and I believe HTML canvas) does support both
Applied changes, caught a couple of small issues, and added color mapping functions: |
|
||
(** Converts RGB color into opaque RGBA color. | ||
For use w/ `Context.background` *) | ||
let opaque (r, g, b) = (r, g, b, 255) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the same function to create custom colours as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand what you're asking, this function is for setting the background color in the init
function. To make it easier to use RGB colors, that are maybe being used elsewhere, as an opaque background color. It wouldn't work for adding stroke
or fill
fields because those don't have an alpha field.
Do you think there should be a color constructor function? I didn't add one because I thought a three-tuple was easy enough to construct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left the minor comment above, otherwise LGTM! 👍
A circle in a rectangular canvas should not become an ellipse.
* Fix scaling factor: shouldn't be sqrt * Format with dune * Add donut-with-scaling example
…ap fns for applying fns to those fields
c94f844
to
14d1f2d
Compare
Fixed merge conflicts! |
My first attempt at a system for coloring shapes and setting background in
init
. Shapes now have acolor
field that is an 8bit RGB three-tuple. Shape constructors are the same, inserting black as default, but shapes can be piped to a new functionwith_color
that returns a new shape with the color field set to the arg.So creating a gray circle can look like this: