Problem with gluProject

Hey gang,
Got a small problem here - and am looking for some advice on what to do (cause I am stumped). Here’s the situation - I have a Globe made with a gluSphere and I need to put “overlays” on it, such as little dots and little circles (to define certain locations on the globe).

Anyways - to place these things on the globe, what I am doing is disabling the Depth Test and using gluProgect to get the window coordinates for both the globe and the circles or dots that I am trying to place on them. I am then comparing the Z window coordinate to see if the circle and/or dot is visible to the user or not (if it’s behind the globe - don’t draw it).

Now - I seem to be at a good starting point - because this works (well most of the time). But I do have a slight problem - it seems that gluProject is not accurate enough, (Or more likely I am doing something wrong) and some of the dots and circles draw when they should be behind the globe. (For example - you can see a circle in cape cod bay - but in all actuality - it’s some place in central Europe, which at this time is on the other side of the visible globe.) If I keep rotating though - the circles then stop drawing (as they should). So it seems to me that I am off by a tiny factor in my calculations. . .

Here’s some code!

Globe3d::draw()
{

// screen clear. We want this even if we aren’t going
// to paint anything else.
//
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);

if (!attributes_.isHidden_) {

  // now do the globe work.  First push the matrix on 
  //the stack
  glPushMatrix();

  
  // move it to where it should be - note these values change
  glTranslatef(attributes_.currentPos_.x_,
               attributes_.currentPos_.y_,
               attributes_.zoomDist_);
  
  // set the pixel zoom where 1.0 is no zoom.  
  // This is for drawing text
  //
  double pixelZoom = attributes_.zoomDist_/280.0;
  if (pixelZoom < 0) {
     pixelZoom = pixelZoom * -1;
  }
  glPixelZoom(pixelZoom, pixelZoom);
  glPolygonOffset(1.0, 1.0);
  
  // because we are rotating the globe by 90, the x and y
  // rotation need to be on the other axis
  glRotatef(attributes_.yRotation_.measuredIn(degree), 
            1.0, 0.0, 0.0);
  glRotatef(attributes_.xRotation_.measuredIn(degree),
            0.0, 1.0, 0.0);
  
  // if the globe needs to be created again
  //
  if (attributes_.createGlobeDisplayList_) {
     createGlobeDisplayList();
  }

  // We are enabling Polygon Offsetting to help eliminate
  // Z fighting of the overlays that come close to or are
  // directly on top of the globe's surface.
  glPolygonMode(GL_FRONT, GL_FILL);
  glEnable(GL_POLYGON_OFFSET_FILL);
  
  // enable the texture
  glEnable(GL_TEXTURE_2D);
  
  // call the  display list that contains the earth
  glCallList(attributes_.globeDisplayList_);
  
  //nothing else should have a texture
  //
  glDisable(GL_TEXTURE_2D);

  //
  // For gluProject - we need to get the current projection
  // matrix, current viewport matrix, and current viewport. 
  // We will use glGet functions to query the graphics 
  // hardware on what these values are.
  //
  GLdouble modelMatrix[16];
  GLdouble projectionMatrix[16];
  GLint viewport[4];

  //
  // Use the glGet functions to query the graphics hardware
  // for the current matrices and viewport.
  //
  glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
  glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
  glGetIntegerv(GL_VIEWPORT, viewport);
     
  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

  //
  // These will be the window coordinates for the Globe. 
  // In this case
  // all we really need is the Z window coordinate, 
  // as we will compare
  // the globeZ value with the winZ value.
  //
  GLdouble globeWinX;
  GLdouble globeWinY;
  GLdouble globeWinZ;

  // 
  // Get the window coordiates for the globe. 
  // Note that we are using
  // 0, 0, 0 as object coordinates for the globe because 
  // the globe's
  // object coordinates are represented in the 
  // current matrices that
  // we are passing in. We only actualy care about 
  // the Z window 
  // coordinates as we will be compareing the labelWinZ with the
  // globeWinZ to see if we need to draw the current label.
  //
  gluProject(0, 0, 0, modelMatrix,
             projectionMatrix, viewport, &globeWinX, 
             &globeWinY,
             &globeWinZ);
  
  
  glDisable(GL_POLYGON_OFFSET_FILL);
  
  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

  // now draw all of the overlays.  They are to be drawn in a
  // specific order which follows.
  //
  // We are passing in the matrixs and the
  // globe window coordinates to the overlays so that 
  // they can compare
  // their window coordinates with the 
  // globe's window coordinates and
  // do depth testing manually. We manually do depth 
  // testing on the
  // overlays that deal with labels that might 
  // curve into the earth
  // (such as tracks and threat regions). 
  // The matrixs and viewport
  // are also passed in so that the overlays can use 
  // the gluProject method.
  // the gluProject method converts object coordinates to
  // window coordinates.  Because the calls to get 
  // the matrixs
  // (using glGet) are expensive, we only want to do 
  // these once. 
  //
  
  // first the tracks
  //
  drawTracks(modelMatrix, projectionMatrix, viewport, globeWinX,  globeWinY, globeWinZ);

// this matrix pop is for the general “move the earth to the right place”
// matrix push
//
glPopMatrix();
}

// While glXSwapBuffers will call a glFlush before it
// swaps the buffers, we want to make sure that all the
// openGL calls are finished before we swap the bufffers.
glFinish();

// this pushes all the information out of the
// back buffer onto the screen
//
glXSwapBuffers(display_, window_);

// make sure this is done drawing before leaving
glXWaitGL();

// check and report for any errors
GlobeError::OpenGLError(ARCH_LOCATION);

}

void drawTracks(GLdouble modelviewMatrix[16],
GLdouble projectionMatrix[16], GLint viewport[4],
GLdouble globeWinX, GLdouble globeWinY,
GLdouble globeWinZ)
{
// enable polygon offsetting for Lines.
glPolygonMode(GL_FRONT, GL_LINE);
glEnable(GL_POLYGON_OFFSET_LINE);

  glColor3dv(GLOBE_LAUNCH_COLOR);
  
  // set line width of the launch platforms.
  glLineWidth(1.0);
  
  for (int i = 0; i < launchDisplay_.size(); ++i) {
     
     // we will use a gluQuadric Disk to draw the
     // circles for the Launch Platforms.
     GLUquadricObj *launchPlatform = gluNewQuadric();
     
     // check and report error status
     GlobeError::OpenGLError(ARCH_LOCATION);
     
     // if the quadric did get created
     //
     if (launchPlatform != 0) {
        gluQuadricDrawStyle(launchPlatform, GLU_LINE);
        
        // should be based on range of probibility - TBD
        int launchPlatformRadius = 1;
        
        double vec[3];
        launchDisplay_[i].xyzVector(vec);

        //
        // These will be the window coordinates for the 
        //launch platforms.
        // The window coordinates are the "true" X, Y, 
        // and Z values (i.e. actual pixel values)
        //
        GLdouble platformWinX;
        GLdouble platformWinY;
        GLdouble platformWinZ;
  
        //
        // Get the window coordinates for the launch 
        // platforms. We use
        // the object coordinates for the current launch 
        // platform to get
        // the proper window coordinates. We only actually
        //care about the Z window coordinates as we will be 
        // compareing the paltformWinZ with the globeWinZ 
        // to see if we need to draw the current label.
        // 
        gluProject(vec[0], vec[1], vec[2], modelMatrix,
                   projectionMatrix, viewport, &platformWinX,
                   &platformWinY,
                   &platformWinZ);
  
        // check and report for any errors
        GlobeError::OpenGLError(ARCH_LOCATION);

        // Disable the depth testing for the labels
        glDisable(GL_DEPTH_TEST);
  
        //
        // Compare the platform Z values with the Globe Z
        // values. The lower the Z value, the closer the 
        // object is to the eye. If the platform Z value is
        // less than the Globe Z value, we then draw
        // the launch platform. If not don't draw anything.
        //
        if (platformWinZ  < globeWinZ)
        {
           // glPushMatrix/glPopMatrix is needed around
           // this code
           // because the translate affects the matrix.
           //
           glPushMatrix();
           glTranslated(vec[0], vec[1], vec[2]);
           
           // make sure the inner and outer radius are 
           // the same.
           gluDisk(launchPlatform, launchPlatformRadius,
                   launchPlatformRadius, 60, 2);
         
     
           gluDeleteQuadric(launchPlatform);
           glPopMatrix();
        }
      
        glEnable(GL_DEPTH_TEST);
        
     } // end of (if (launchPlatform != 0) 
     
  } // end of for
        
  glDisable(GL_POLYGON_OFFSET_LINE);

  // check and report for any errors
  GlobeError::OpenGLError(ARCH_LOCATION);

}
}