Solving for the position on a color wheel

I’ve been working on a color wheel for the past few hours, and have really great progress so far:
image
I’m successfully able to, given the X and Y of the mouse in the local space of the wheel, solve for the Hue and Saturation as follows:

-- mid = midpoint of the circle (also the radius)
-- dist = distance from the mouse to the midpoint
local hue = (math.pi - math.atan2(y - mid, x - mid)) / (math.pi * 2)
local sat = dist / mid

This works super well, my issue comes in that I now have to go the reverse way: Solve for an X and Y given a Hue and Saturation.
Here are my algebra steps to solve down the original hue equation for the angle:
.1) h = (π - arctan(a)) / (2π)
.2) 2πh = π - arctan(a)
.3) 2πh - π = -arctan(a)
.4) π - 2πh = arctan(a)
So I’ve arrived at where I would reverse the arctan, and normally I would take the tan of both sides. I tried this and got really undesirable numbers.

I believe I’m left with two options, either my algebra is wrong (which is totally possible), or the atan2 function does more under the hood than just an arctan which I need to account for in my equation, which I think is the more likely option but I don’t really know. So now I ask for help, how should I solve for a? And overall, what else should I know to solve for x and y given a?

I think a different approach to this problem will give a clearer view of what is going on.

This problem can be seen as working with polar coordinates. Normally you work with an X and Y coordinate, which is a horizontal and vertical distance. However, polar coordinates work by using an angle and a radius to cover a space, which perfectly matches your problem! In your case, hue is the angle, and saturation is the radius.

When working with polar coordinates, the sine and cosine are your friends, and this is best illustrated with the unit circle. Here is a random image from Google to help illustrate the situation:

image

The middle of the circle is (0, 0). The circle has a radius of 1. If you know the angle (which should be a number between 0 and 2*pi), you can get a X and Y coordinate on the border of this unit circle (the blue outline) using Lua’s math.cos() and math.sin().

So let’s take this image as an example. The given angle is 60 degrees, which is equivalent to 1/6th of a full rotation, so (1/6) * math.pi*2. We can now compute the location P using cos() and sin():

local angle = (1/6) * math.pi*2
local xLocation = math.cos(angle)
local yLocation = math.sin(angle)
print(xLocation, yLocation)

This prints 0.5 and 0.86602540378444. That looks very accurate!

Now that the location on the edge of the circle is known, finding the location within the circle when the saturation is given is very simple. Saturation should be a number between 0 and 1, where 0 is completely white (the middle of the circle) and 1 around the edge of the circle. So you can simply multiply your X and Y coordinates that were found by the saturation and your new X and Y coordinates should be the right coordinates on the circle for the given hue and saturation.


On a side note, I notice that your color wheel looks a little different from the art programs I am used to. In paint.net the color wheel is mirrored on the Y-axis and in Clip Studio Paint the color wheel seems to be rotated compared to your color wheel, so it might be that you will have to tweak your variables a little bit afterwards so it matches the visuals of your color wheel, but the approach of the calculation I showed should still be right.

1 Like

Thanks! Polar coordinates makes a lot of sense, and will definitely help my logic out in the future. Unfortunately, I’m still struggling with the problem of actually discovering the angle from the given color to begin with. Once I have the angle though, I’m sure that will be a huge help! :grinning_face_with_smiling_eyes:

Unless I am misunderstanding the question, the angle of a color is basically the same as the hue, but in a slightly different format. Hue is represented in degrees, so in the range of 0 to 360. So you can basically divide the number by 360 and then multiply it by math.pi*2 and you will get a number suitable for the calculation I showed.