It’s been long since I last posted about my GSOC work, so today I’ll be writing about how I achieved the color picker. There are several points that comes to the mind when we thing about the colorpicker.
- How to achieve the gradient color selection area
- Use a pre-rendered image ?
- Generate using computer algorithm ? If what are the appropriate opengl calls?
- What is the algorithm for picking the color from the location ?
- Use opengl methods to pick the pixel from the point where the user touches ?
- Or use some algorithmic technique to determine where the user is touching local to the gradient and then calculate the appropriate RGB values
There is a humongous list of resources available for Color pickers especially AJAX based, but my problem was different, I wanted a Quarter Circle Color Picker 🙂 , nowhere in the internet did i find one single open-source quarter circle color pickers, but hey no pain no gain :), so I set out to create a Opengl rendered quarter circle color picker with algorithmic based color picking.
1. Rendering the Gradient Circle
So my first goal was to create a opengl rendered quarter circle, well its very easy to generate a single color circles in opengl like the ones that I have used in my previous widgets, Rendering a gradient one is a very hard task. I know that opengl allows to blend colors by specifying different colors at different vertices of a polygon, but how can one do the same in a circle ?!!, circle has no vertex edges.
A Color Blended Triangle
I did not find any way to get around this problem using Circle render, so the alternative solution was to render thin triangles and arrange it in the form of a fan, and when i looked around the net for this one, to my surprise there was one opening call to make such a polygon using triangle fan.
def drawPartialCircle(pos=(0,0), radius=100):
with gx_begin(GL_TRIANGLE_FAN):
glColor3f(0,0,1)
glVertex2f(0,0)
for angle in range (90,185,5):
glColor3f(sin(radians(angle-90))*sqrt(2),cos(radians(angle-90))*sqrt(2),0)
glVertex2f(int(cos(radians(angle))*radius),int(sin(radians(angle))*radius))
So in the above algorithm i’ve chosen the angle range from 90 to 185 because i want it to appear at the bottom right corner. So what the algoritm does it,
- It generates 5 degree triangles to form a quater circle.
- The center of the circle is blue so the other two edges of the two radii will be red and green respectively.
- The mid way of the circumference must be yellow that is RGB =>(1,1,0) , so to we know that only at 45 degrees sin 45 = cos 45.
- sin 45 = 1/sqrt(2), so to obtain 1 at the center we multiply it by sqrt(2), so we get (1,1,0) at the center.
Opengl rendered Quarter Circle
If you have any queries regarding this algo, feel free to comment.
2. Calculating color at the touch point
I used the similar sine cos formula to calculate the RGB values, The R and G values varies according to the angle made by the line joining the center and the touch point with the horizontal line. Whereas the blue value is a function of the distance touch point from the center. So here goes the algorithm
def calculate_color(self):
b = 1-self.point_distance/self.size[0]
r = (sin(radians(self.point_angle))-b)*sqrt(2)
g = (cos(radians(self.point_angle))-b)*sqrt(2)
where self.size[0] is the radius of the circle.
3. Hue and Saturation
As you can see in the rendered quarter circle above there is no range of black nor white, so this posed a new challenge to use a slider to make a hue saturation variation, HSV[Hue, Saturation, Value] is an alernative representation of RGB color space, something similar to Rectangular to Polar coordinates conversion.
HSV Representation
Since I need to vary the color from White>>Color>>Black, the variation has to be done in two steps
- White >> Color variation, which is nothing but variation of the Saturation, here saturation = 0 implies White
- Color >> Black which is variation of the Value field
Thomas (My mentor) pointed me to this really nifty function in core python rgb_to_hsv and hsv_to_rgb , which converts between the colorspaces with ease. So I divide the slider into two portions lower limit to middle value for saturation, middle value to upper limit for Value. I chose to take 2 as the maximum range of the slider, so it varies from 0 to 2, and middle i get 1. I developed the following algorithm.
value = rgb_to_hsv(self.slider.slider_color[0],self.slider.slider_color[1],self.slider.slider_color[2])
h,s,v = value[0],value[1],value[2]
if self.slider._value <= 1.0:
s = self.slider._value
else:
v = 2-self.slider._value
self.slider.slider_color = hsv_to_rgb(h,s,v)
[/sourcecode]
Overall this entire widget was very complex to build, but I got to learn alot from this tiny project. If you have queries regarding any of the algorithm that I developed, or if you have suggestions of better algorithm, or anything at all feel free to comment :), it will definitely help me make this project better