Search code examples
c++openglpointareadisk

Check if a point is within a "gluPartialDisk" (OpenGL and C++)


I'm making a pie chart program and I'm creating the pie segments with "gluPartialDisks". However, I also want to check if a point is within the area of one of the disks (The point in question being my mouse cursor). I know how to find the position of a mouse cursor, but how can I check if it is within the area of a disk?

Quick snippet of code:

glTranslatef(-0.3, 0, 0);

gluPartialDisk(gluNewQuadric(), 0, 0.65, 10, 1,
              ((2 * 3.141592654 * 0.65) * (/*Specific angle*/) - (/*Specific angle*/ * 5),
              /*Different angle*/ * 360);

Solution

  • As long as your partial disks are parallel to the screen, and rendered with a parallel projection, it's easiest to do the math without getting OpenGL involved at all.

    Say you were drawing a partial disk with:

    glTranslatef(xPos, yPos, 0.0f);
    gluPartialDisk(quadric, innerRad, outerRad, slices, loops, startAng, sweepAng);
    

    Now if you want to test point (x0, y0), you subtract the translation vector, and then calculate the polar coordinates:

    x0 -= xPos;
    y0 -= yPos;
    float dist = sqrt(xPos * xPos + yPos * yPos);
    float ang = atan2(yPos, xPos);
    

    To be inside the partial disk, the distance to the center would have to be within the range of radii:

    if (dist < innerRad || dist > outerRad) {
        // it's outside!
    }
    

    The angle is slightly trickier because it wraps around. Also, the result of atan2() is in radians, measured counter-clockwise from the x-axis in a range [-PI, PI] while the arguments to gluPartialDisk() are in degrees, and measured clockwise from the y-axis. With startAng and sweepAng in the range [0.0, 360.0] degrees, the interval test logic could look like this (untested):

    ang *= 180.0f / PI; // convert to degrees
    ang = 90.0f - ang;  // make clockwise, relative to y-axis
    if (ang < 0.0f) {
        ang += 360.0f;  // wrap into range [0.0, 360.0]
    }
    ang -= startAng;    // make relative to startAng
    if (ang < 0.0f) {
        ang += 360.0f;  // ... and back into range [0.0, 360.0]
    }
    if (ang > sweepAng) {
        // it's outside!
    } else {
        // it's inside!
    }