开发者

Place an ofImage around a circle

开发者 https://www.devze.com 2023-02-16 08:14 出处:网络
I\'m developing for Reactivision using Openframeworks, and I need to place an ofImage (which can be place anywhere in the screen) around a circle, and also rotating it by a specific angle. I include a

I'm developing for Reactivision using Openframeworks, and I need to place an ofImage (which can be place anywhere in the screen) around a circle, and also rotating it by a specific angle. I include an image to help with this.

http://i.stac开发者_如何学编程k.imgur.com/WCyPu.png

As you see, the x and y axes go from 0,0 to 1,1, and I have a circle in the middle of the screen (the center is placed at 0.5,0.5), with a radius of 0.42 (so it doesn't fill the screen).

Eventually the user places an ofImage (in this case, a red smiley) on the screen, at position 0.2,0.2. Its width and height are both 0.08 and the rotation center is at its top-left corner (as usual).

What I need to do is to take that smiley, place it just around the circle, in the nearest position (it can follow the radius if it turns easier) it would be able to be and rotate it, so it would be facing the center of the circle.

I also need to find the smileys "nose", at 0.04 0.04 from the ofImage axes, move it and rotate it to keep being the smileys nose and not a dot in the void. The best for the red smiley to be should be the green smiley.

My trigonometry is a bit rusty and my best approach isn't working. I define its final position inside the constructor and rotating the sprite in the draw() step.

Smiley::Smiley(int _id, float x, float y)
{
    smileyImg.loadImage("smiley.png");

    float tangent = (0.5-x)/(0.5-y);
    //angle is a private float variable; 
    angle = atanf(tangent);
    //those 0.06 just lets me move the smiley a little over the circle itself
    x = 0.5+cos(angle)*(RADIUS+0.06);
    y = 0.5+sin(angle)*(RADIUS+0.06);
    float xNose = 0.5+cos(angle)*(RADIUS+0.06);
    float yNose = 0.5+sin(angle)*(RADIUS+0.06);
    angle = ofRadToDeg(angle);
    //pos and nose are Vector3 classes which hold three floats. Nothing too much important here
    pos.set(x, y, 0.0);
    nose.set(xNose, yNose, 0.0);
}

void Smiley::draw()
{
    ofPushMatrix();
    ofTranslate(pos.x,pos.y);
    ofRotateZ(angle);
    ofTranslate(-pos.x,-pos.y);
    ofSetColor(255,255,255);
    ofEnableAlphaBlending();
    smileyImg.draw(pos.x,pos.y,0.08,0.08);
    ofDisableAlphaBlending();
    ofPopMatrix();
}

Can anyone help me with this, please? Really thanks in advance.

Edit: After adapting @datenwolf solution, the positions I'm getting are perfect, but when I put rotation and translation (or just translation) into a transformation matrix, it makes the smileys disappear. I'm plenty sure I'm doing wrong with the matrix:

Smiley::Smiley(int _id, float x, float y)
{
    smileyImg.loadImage("smiley.png");

    float distance = sqrt( pow((x - 0.46),2) + pow((y - 0.42),2));
    Vector3 director((x - 0.46)/ distance, (y - 0.42)/ distance, 0.0);
    pos.x = 0.46 + RADIUS * director.x;
    pos.y = 0.42 + RADIUS * director.y;

    float distanceNose = sqrt( pow((x - 0.46),2) + pow((y - 0.42),2));
    Vector3 noseDirector((x - 0.46)/ distanceNose, (y - 0.42)/ distanceNose, 0.0);
    nose.x = 0.46 + RADIUS * noseDirector.x;
    nose.y = 0.42 + RADIUS * noseDirector.y;

    /* matrix is a float matrix[16]. I think the indexing is ok, but even going from
    0 4 8 12... to 0 1 2 3..., it still doesn't work*/
    matrix[0] = -director.y; matrix[4] = director.x; matrix[8] = 0.0; matrix[12] = pos.x;
    matrix[1] = director.x; matrix[5] = director.y; matrix[9] = 0.0; matrix[13] = pos.y;
    matrix[2] = 0.0; matrix[6] = 0.0; matrix[10] = 1.0; matrix[14] = 0.0;
    matrix[3] = 0.0; matrix[7] = 0.0; matrix[11] = 0.0; matrix[15] = 1.0;
}

void Smiley::draw()
{
    ofPushMatrix();
    glLoadMatrixf(matrix);
    ofSetColor(255,255,255);
    ofEnableAlphaBlending();
    // Now that I have a transformation matrix that also transposes, I don't need to define the coordinates here, so I put 0.0,0.0
    noseImg.draw(0.0,0.0,0.08,0.08);
    ofDisableAlphaBlending();
    ofPopMatrix();
}

Moreover, I need to rotate the nose position according to each smiley. Which do you think is the best way? Thank you so much


Like so often you don't need trigonometry for this. Let C be the circle's center, r the radius and P the point the user clicks. Then the position U of the click projected to the circle is

U = C + r * (P - C)/|P - C|

where

| A | = sqrt(A_x² + A_y² + …);

So in case of two dimensions you get

U.x = C.x + r * (P.x - C.x)/sqrt( (P.x - C.x)² + (P.y - C.y)² )
U.y = C.y + r * (P.y - C.y)/sqrt( (P.x - C.x)² + (P.y - C.y)² )

The rotation can be described by a rotation matrix R, which consists of the direction from circle C to P and the perpendicular T to it. So Big fat EDIT: normalizing the directional:

D = P - C = (P.x - C.x , P.y - C.y)/sqrt( (P.x - C.x)² + (P.y - C.y)² )
T = Z × D 

also note you can write U in terms of D

U = C + r*D

use this to construct a rotation matrix

    | T.x D.x |
R = |         |
    | T.y D.y |

R being a rotation matrix it follows T.y == D.x and evaluating T.x

T.x = -P.y + C.y = -D.y

so

    | -D.y D.x |
R = |          |
    |  D.x D.y |

Big fat EDIT: I used the wrong components for the last column of the matrix. It's U.{x,y}, not D.{x.y}. My bad sorry!

We can put this into a complete transformation matrix M:

    | -D.y D.x   0 U.x |   | -D.y D.x   0 (C + r*D.x) |
M = |  D.x D.y   0 U.y | = |  D.x D.y   0 (C + r*D.y) |
    |    0   0   1   0 |   |    0   0   1      0      |
    |    0   0   0   1 |   |    0   0   0      1      |

You can load this matrix using glLoadMatrix to place the sprite.

0

精彩评论

暂无评论...
验证码 换一张
取 消