Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » color picker (saga) ... triangle aera....

This thread is locked; no one can reply to it. rss feed Print
 1   2 
color picker (saga) ... triangle aera....
karistouf
Member #5,126
October 2004
avatar

hi johan. i m using dev-cpp, but with the original mingw32 of version 4.9.
i have cleaned the project and it works now ok. or I think so.

I have finally decided to stop this geometrical nightmare and go to a more simple solution that was suggested before: rotating the hue wheel by a blitrotated,and not moving the darkness / saturation triangle.

this is quite a pain , but really i didn t arrived to get a correct result working, i mean like i would like to have it work.
schiffys sources were very interresting thought. but the wall in wich i crashed was too hard... thats a real pity, as you were around nicely to give a strong help.

thanks, merci, shoukrane, domo, gracie mille !

now i m just discovering that this routine is not very good. I have an effect of steps while moving continuosly around my hue wheel 5 to 5 somehow...

1for(angle = 0 ; angle <(PI*360) / 180 ; angle+=0.1)//radians
2{
3 vx = cos(angle)*rayon;
4 vy = sin(angle)*rayon;
5 if(mouse_x>xchroma+vx-10 && mouse_x< xchroma+vx+10 && mouse_y>ychroma+vy-10 && mouse_y<ychroma+vy+10 )
6 {
7 if( mouse_b&1)
8 {
9 angle_snap=angle;//angle rotation roue couleur
10 position_curseur_hue_x= xchroma+vx;
11 position_curseur_hue_y=ychroma+vy ;
12 cref=getpixel(screen,xchroma,ychroma+rayon);//le picker est sous la fleche
13 r_pick=getr(cref);
14 v_pick=getg(cref);
15 b_pick=getb(cref);
16 }
17 }
18}

yours, christoph

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Quote:

I have an effect of steps while moving continuously around my hue wheel 5 to 5 somehow...

Because that's the way you programmed it. ???

To find the hue that the user picks is simple :
1. If the user clicks the mouse then :
1a - Find the distance from the mouse to the center of the circle. If the distance is greater than or equal to the inner radius of the hue wheel and less than or equal to the outer radius of the hue wheel, they've chosen a new hue.
1b - Find the angle from the mouse to the center of the circle. Using degrees, this translates directly to the value for your hue. You will also have to store the current rotation of the hue wheel and adjust the value by it to find the correct new value.

I made an example program that shows the rotating hue wheel and the saturation/value triangle in the middle of it. LMB click on the hue wheel to set the hue, and LMB drag on the hue wheel to turn it (also setting the hue). I'll add in clicking on the triangle tomorrow, but hopefully you'll see what I mean now.
Source + dynamic win32 exe (needs alleg42.dll)

http://www.allegro.cc/files/attachment/596770

Johan Halmén
Member #1,550
September 2001

I tried to draw the hue ring with an antialiased edge:
{"name":"596772","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/e\/ae9c5b9ab2e12da8bdaee61a6ecb3b8b.png","w":260,"h":259,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/e\/ae9c5b9ab2e12da8bdaee61a6ecb3b8b"}596772
But rotating it with rotate_sprite() might still make it jagged. One could perhaps use some alpha magic to make the edge softer. I would prefer to rotate the triangle, though.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

To get rid of the jaggedness of the hue wheel when it's turned with rotate_sprite, I was going to rotate it into a buffer first, draw a magic pink circle over the inner and outer edges and then use draw_sprite with the buffer. That way the edges would never move at least. I'll try it later.

Johan Halmén
Member #1,550
September 2001

Good idea. If you still want the edge antialiased, yse some alpha masking instead of magic oink.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

karistouf
Member #5,126
October 2004
avatar

hi edgardo. yes its impressively smooth !

and sure i would never have arrived to this...

is it possible to know what are those few lines in your code ( please :-/ )?

    mx = mpos >> 16;
    my = mpos & 0x0000ffff;

and could you re-explain to me the importance of ftofix ?

yours

Johan Halmén
Member #1,550
September 2001

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Quote:

is it possible to know what are those few lines in your code ( please :-/ )?

Read over this -

So mouse_pos is a 4 byte integer. The x and y positions of the mouse are stored inside it, with each given two bytes to store their value. So it's layout is like this :

XXYY

The bit shift operator (>>) shifts the bit values inside a variable so when you say

int mouse_xpos = mouse_pos >> 16;

Then you have the top two bytes of mouse_pos stored inside the mouse_xpos variable. (Because the bits in mouse_pos are shifted to the right 16 places (bits), which is two bytes)

When using the bitwise AND operator (&), it will only return a 1 bit if the corresponding bits of both sides of the expression are 1. 0x0000ffff has all the bits in the lower two bytes set to 1 so when you bitwise AND a number with 0x0000ffff, you are guaranteed to have only the values that were in the lower two bytes of that number. This is how you get the y value out of mouse_pos.

int mouse_ypos = mouse_pos & 0x0000ffff;

Quote:

and could you re-explain to me the importance of ftofix ?

float to fixed
Since the last parameter of rotate_sprite takes an allegro fixed data type, you need to convert the float to a fixed type for the function. Remember that the range for allegro's fixed type is [0.0 , 256.0).

If you have any other questions about what I did or why, just ask.

karistouf
Member #5,126
October 2004
avatar

thanks for this explanations edgardo ! thanks johan for the link !
:D
you were right ( once again ) about the fact it was me putting a step effect.

i m obtaining better smooth results if doing angle+=0.01 and not +=0.1

i know it could sound as somehow an heresy of code for someone like you. i need now to test it with strong spotlight to see if what was comitted there is smooth enough for lights.

if you have time to show triangle picking as you proposed, on your code, it would be very nice ! ( just for me to understand why damned i didn t succeed in !) . I learn truth your code this interresting way to use *bmp and sprites ! thanks !

ps: no reply for this story of OpenGL coder announcement ! ;D

{"name":"596786","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/b\/bb0ce6930a91b1453d9c55bb0cfd26cf.jpg","w":663,"h":734,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/b\/bb0ce6930a91b1453d9c55bb0cfd26cf"}596786

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Quote:

if you have time to show triangle picking as you proposed, on your code, it would be very nice !

I won't be able to get to it until tomorrow. I've just started learning about dot products and cross products myself, so I want to make sure my math is correct first.

If you've already got the test for checking whether a point is inside the triangle completed, you can just use getpixel, then getr, getg, and getb to get the rgb value of the pixel underneath the mouse click, then use rgb_to_hsv to get the saturation and value of the color picked.

Johan Halmén
Member #1,550
September 2001

I thought of the cross product. If the vertices of the triagles are A, B and C and the mouse click is at P, I would check ABxAP, BCxBP and CAxCP. If all three cross products have same sign, P lies inside the triangle.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Johan Halmén
Member #1,550
September 2001

AB and AP are vectors in XY plane, no Z. Their cross product will be a vector parallel to Z axis. That means no X or Y dimension. So you just read the sign of the Z component. It's either + or -. If it's zero, P equals A or B.

This means you need 3D. The unit vectors are i, j and k.

|              |
| i    j    k  |
| xAB  yAB  0  |
| xAP  yAP  0  |
|              |

[edit]
This started to get interesting! I found a funny way to convert the hue and saturation to a coordinate for the picker inside the triangle. You got the black vertex, the white vertex and the hue vertex, right? Let's call them B, W and H. First you get the coordinates of a point along the HW side, where you would place the circle if you would have v = 1. Call this point F (for full value). If s == 0, it would be at W. If s == 1, it would be at H.

F = s * H + (1 - s) * W

Well, if v would be 1, you would have found your spot. But it's somewhere between B and F, namely:

P = v * F + (1 - v) * B

(P for picker)

This should be possible to do backwards, too. I mean, click at a spot (which becomes P) and calculate s and v out of that. Draw a line through B and P and check where it crosses HW. That way you get F and s. Measure BP and PF and you get v. I guess you can forget the cross product. From these calculations you can find out whether the user clicked outside the triangle. s and v would simply be either negative or greater than 1.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

karistouf
Member #5,126
October 2004
avatar

thanks edgardo !

links are somehow frightening ! (brrrrrr) terrific !
i suppose you will perhaps make a color picker for your pattern generator to edit ranges of colors? :D
i m very happy if i can see the result !

by the way in general, how do you translate in code this vector in xy maths ?

for example the a.(b+c) = a.b + a.c ?

cheers :D

Johan Halmén
Member #1,550
September 2001

This is what I did. It has pretty much everything I think I would need. Actually I have an old graphic application project somewhere, which had a colour picker consisting of only the sliders. I might dust it off a bit.

http://www.allegro.cc/files/attachment/596796

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Quote:

i suppose you will perhaps make a color picker for your pattern generator to edit ranges of colors?

I may include it, I'm not sure yet though as it has to be fairly large pixel wise to get precise values without using sliders to adjust the values.

Sorry it took so long to reply, but I had some really annoying bugs I had a hard time finding. Incidentally, between a header and a source file, you can use different names for the same function parameters, and MinGW 3.4.5 won't bother to warn you. That was only part of it though.

I used vectors and scalar projection to find the saturation and color value. It turns out I didn't need dot products or cross products to do any of it.

To see what scalar projection is, take a look at the graphic on the right at http://en.wikipedia.org/wiki/Dot_Product#Geometric_interpretation.

Using the convenient naming convention Johan used (H is the vertice with full hue value, B is black, W is white, M is the midpoint of H and W, and P is the mouse position), here are the steps I use to find the saturation and value for the mouse location.
1. Find the vector from B to P (Px - Bx , Py - By) (BPx,BPy)
2. Find the vector from W to P (Px - Wx , Py - Wy) (WPx,WPy)
3. Find the distance from B to P (distBP)
4. Find the distance from W to P (distWP)
5. If distBP is 0.0, then value is 0.0 and saturation is undefined (leave unchanged)
6. If distWP is 0.0 then value is 1.0 and saturation is 0.0
7. Find the angle of vector BP ( atan2(BPy,BPx) )
8. Find the angle of vector WP ( atan2(WPy,WPx) )
9. Find the angle from vector BM to vector BP (angleBP - angleBM)
10. Find the angle from vector WH to vector WP (angleWP - angle WH)
11. Find the scalar projection of BP onto BM ( distBP*cos(angle_BM_to_BP) )
12. Find the scalar projection of WP onto WH ( distWP*cos(angle_WH_to_WP) )
13. The color value is equivalent to the scalar projection of BP onto BM divided by the distance from B to M :
value = SPBPBM/distBM
14. If the value is not zero then the saturation is equal to this :
saturation = (SPWPWH + (value - 1.0)*distMW)/(value*distWH);

Finding the position of the point on the triangle from the saturation and color value is much nicer though :
Using vectors :
<math>P = B + \overrightarrow{B to P on BW} + \overrightarrow{P on BW to P}</math>

Finding the vector from B to P on BW is easy :
<math>\overrightarrow{BtoPonBW} = B + value*\overrightarrow{BW}</math>

The vector from P on BW to P isn't so bad though :
<math>\overrightarrow{PonBWtoP} = \overrightarrow{WH}*saturation*value</math>

Translated directly to coordinates instead of vectors, the formulas are :

<math>Px = Bx + value*\left(\left(Wx - Bx\right) + Saturation*\left(Hx - Wx\right)\right)</math>

<math>Py = By + value*\left(\left(Wy - By\right) + Saturation*\left(Hy - Wy\right)\right)</math>

These formulas will work as long as the triangle is isosceles and the two equal sides correspond to the HB and BW sides of the saturation value triangle.

I also added an algorithm to find the closest edge of the triangle when the mouse is outside it. Basically, for each vertice, find the angle from the vector of the current vertice to the next vertice to the vector from the current vertice to the mouse position. If the angle indicates the mouse is outside the triangle, find the scalar projection of the mouse vector onto the edge vector. If the scalar projection is negative, it corresponds to a corner of the triangle, else if the scalar projection is less than the length of that edge, then divide it by the length of the edge and you will have a ratio you can use to assign a value and saturation for that position. If the scalar projection is larger than or equal to the edge length then it corresponds to the next corner of the triangle.

I finished an example program that demonstrates the technique visually with on screen vectors indicating scalar projections and finding the closest edge point, along with showing the vectors that produce the mouse position from the saturation and value.
Key s (scalar) - toggle visibility of scalar projections onto vector BM and vector WH
Key c (closest) - toggle visibility of scalar projections onto the triangle edges for finding the closest point from outside the triangle
Key p (position) - toggle visibility of position vectors for the current saturation and value
LMB click on the hue wheel or the saturation value triangle to set a new value.
LMB click and drag on them to drag the wheel or track the closest point on the triangle.
ESC quits

Images of program with vectors visible :
http://www.allegro.cc/files/attachment/596829 http://www.allegro.cc/files/attachment/596830 http://www.allegro.cc/files/attachment/596831

Zip file with win32 exe + source code (C++) (needs alleg42.dll)

I may clean it up some and add a new constructor and/or some resize functions, but feel free to use the HueWheelRR class in your (anyone's) project (with due credit). That will have to wait until I finish my year as overseer of Unolrigoth though, which I have been delaying to finish this HSV wheel/triangle.

Johan Halmén
Member #1,550
September 2001

This is what I did:
1. Define a line 1 through B and P
2. Define a line 2 through W and H
3. Find the crossing point (C) of line 1 and line 2. The crossing point divides the WH side according to the saturation. saturation = (C - W)/(H - W)
4. P divides BC according to value. value = (P - B)/(C - B)

This looks much simpler than Edgar's way, but it includes lots of stuff. First of all you have to define the lines out of two points. You have to use a line equation without the slope to avoid problems with lines like x = k. Then you have to find the crossing point of two lines. Finally the (C - W)/(H - W) and (P - B)/(C - B) thing. Well it's not difficult. What I did was I just did it for the x values or for the y values, which ever made bigger differences, to avoid dividing with... the forbidden denominator next to one. And as I mentioned earlier, if either value gets < 0 or > 1, it means you clicked outside the triangle.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Quick question, what's "(C - W)/(H - W)"?

Is that the length of vector WC divided by the length of the vector WH? I don't recognize your notation. It looks interesting, and if there's a simpler way to do it, it'd be nice to know.

Edit
Using the 's' option in my program, it's easy to see what you're doing, but I'm not sure how you are determining which direction WC lies along WH and which direction BP lies along BC.

karistouf
Member #5,126
October 2004
avatar

edgardo.... this is a master piece ! this should be archived on allegro.cc in utilities !
merci ! ;-)

Johan Halmén
Member #1,550
September 2001

Edgar said:

Quick question, what's "(C - W)/(H - W)"?

C is a point between W and H, right. Think of W as zero and H as one. C is somewhere inbetween, right? C is saturation, right? Well, to get out the actual values, you have to measure the length from W to C and the length from W to H. But if you use Pythagoras, you only get positive results. It's quite allright to only measure the x coordinates of the points. Or only the y coordinates. Because the points are on the same line. You don't want to use the ones that lead to dividing with zero, like if H.x == W.x.

So after I got the coordinates of H, W and C, I go:

if (abs(H.x - W.x) > abs(H.y - W.y))
    saturation = (C.x - W.x)/(H.x - W.x);
else
    saturation = (C.y - W.y)/(H.y - W.y);

This way, if I click outside the triangle, outside the BW line, I get negative saturation values. And clicking outside the BH line, i get saturation values over 1.

Again, using the same approach, I calculate the value comparing the distance BP with the distance BC. If it goes over 1, I'm outside the triangle at the HW side. Negative value means I clicked outside the B vertex.

[edit]
My method makes it useless to calculate with the vectors to find out if the mouse was clicked outside the triangle. OTOH if you just set saturation to 0 each time it went < 0 and to 1 each time it went > 1, the picker won't be set at the most intuitive point on the edge, but at a line starting at the mouse position and parallel to the HW edge.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Years of thorough research have revealed that the red "x" that closes a window, really isn't red, but white on red background.

Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Hey, that's pretty simple. No sqrt's or cos's and I could whip up a general first degree line equation and interception pretty simply. Thanks for the explanation.

Quote:

edgardo.... this is a master piece ! this should be archived on allegro.cc in utilities !

I'm glad you like it, thanks for the compliment.

 1   2 


Go to: