4
\$\begingroup\$

I'm programming a simple graph game and so far I'm still doing a few tests in OpenGL. Right now, let's say I defined a GL_POINT with the glVertex2f(20.0f, 0.0f). I have this function to calculate the coordinates from the mouse input to world coordinates:

void converterCoords(GLfloat winX, GLfloat winY){

GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winZ = 0;

glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
glGetDoublev( GL_PROJECTION_MATRIX, projection );
glGetIntegerv( GL_VIEWPORT, viewport );

winX = (float)winX;
winY = (float)viewport[3] - (float)winY;
winZ = 0;

gluUnProject( winX, winY, winZ, modelview, projection, viewport, &worldX,
        &worldY, &worldZ);

}

After this I have a function to check if the mouse click coordinates are the same as one of the GL_POINTS I defined:

int determinaPosicao(double x, double y){


int i;
for(i = 0; i < nPontos; i++){
    if(pontos[i].vX == x || pontos[i].vY == y){
        pontos[i].seleccionado = 1;
    }   
}

glutSetWindow(window);
glutPostRedisplay();
return 0;

}

I can check just fine if the mouse click is the same as the if condition with the "||" function, however, if I have two points with the same x or y value, then it will declare the mouse has hit both points. However, if I use the "&&" function it never seems to go into the if condition and never declares any point as having been hit.

This certainly isn't the best way to achieve my goal and I would really like to ask for some opinions on how to do this.

Solution I found with help from user concept3d:

int determinaPosicao(double x, double y){

const double maxDist = (1e0);
int i;

printf("%f\n", x);

//Escala no rato após conversão: ~5510  

x = (x*xMaxRef)/10000;
y = (y*yMaxRef)/10000;

for(i = 0; i < nPontos; i++){
    if(pow((pontos[i].vX - x), 2) <= maxDist  && pow((pontos[i].vY - y), 2) <= maxDist){
        pontos[i].seleccionado = 1;
    }   
}

glutSetWindow(window);
glutPostRedisplay();
return 0;

}

The operations I used in x = (x*xMaxRef)/10000 is a simple rule to scale the mouse coordinates (that range from 0 to approx 5510) from the max ortho referencial scale which is x and y = {-100, 100}

\$\endgroup\$
  • 1
    \$\begingroup\$ You need to compare both the GL_POINT and the mouse click position in the same geometric space. Since you only have world space of the GL_POINT on the CPU, you would have to project the click position from screen space back to world space. \$\endgroup\$ – danijar Nov 17 '13 at 20:04
  • \$\begingroup\$ @danijar he is already doing that. \$\endgroup\$ – concept3d Nov 18 '13 at 9:34
  • \$\begingroup\$ @safm did my suggestion work ? \$\endgroup\$ – concept3d Nov 18 '13 at 18:00
  • \$\begingroup\$ @concept3d, I finally did it five minutes ago =) it did work. However I had to make a small change in your answer. I'm gonna try to post the code \$\endgroup\$ – Sasha Fonseca Nov 19 '13 at 13:06
  • \$\begingroup\$ @concept3d I just edited the original question with the solution I found. Thank you for your help \$\endgroup\$ – Sasha Fonseca Nov 19 '13 at 13:11
2
\$\begingroup\$

Well, I can see few problems in your approach, but I will assume both points are in the same coordinate system (world space).

Comparing doubles and floats using "==" is a bad idea. You need to introduce an error margin like this

const double err = 1e-15;
int i;
for(i = 0; i < nPontos; i++){
if( fabs(pontos[i].vX - x) < err  && fabs(pontos[i].vY - y) < err )
{
pontos[i].seleccionado = 1;
}

Better yet, you can calculate the distance squared to the point instead, and check if it's within an acceptable distance.

This has the advantage of using distances, which is more intuitive because you can determine which distance doesn't make the user frustrated with selecting the point, if you need him to exactly match the point, he will be frustrated.

const double maxAcceptableDistanceSqr = 1e-5; // You need to change this to your liking
int i;
for(i = 0; i < nPontos; i++)
{
    // [Edit] fix the dist calculation
    double distanceSqrd = (pontos[i].vX - x)^2 + (pontos[i].vY - y)^2;
    if( distanceSqrd < maxAcceptableDistanceSqr )
    {
        pontos[i].seleccionado = 1;
    }   
}

I recommend using the latter approach, this will make your point act as a circle/sphere (point with radius), which is more effective for selection than using the exact vertex position.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.