예제 #1
0
void PSDisplayDevice::render(const VMDDisplayList *display_list) {
   DepthSortObject depth_obj;
   char *cmd_ptr;
   int draw;
   int tok;
   int nc;
   float a[3], b[3], c[3], d[3];
   float cent[3];
   float r;
   Matrix4 ident;
   float textsize=1.0f; // default text size

   // first we want to clear the transformation matrix stack
   while (transMat.num())
      transMat.pop();

   // push on the identity matrix
   transMat.push(ident);

   // load the display list's transformation matrix
   super_multmatrix(display_list->mat.mat);

   // Now we need to calculate the normalized position of the light
   // so we can compute angles of surfaces to that light for shading
   norm_light[0] = lightState[0].pos[0];
   norm_light[1] = lightState[0].pos[1];
   norm_light[2] = lightState[0].pos[2];
   if (norm_light[0] || norm_light[1] || norm_light[2])
      vec_normalize(norm_light);

   // Computer periodic images
   ResizeArray<Matrix4> pbcImages;
   find_pbc_images(display_list, pbcImages);
   int nimages = pbcImages.num();

   for (int pbcimage = 0; pbcimage < nimages; pbcimage++) {
     transMat.dup();
     super_multmatrix(pbcImages[pbcimage].mat);

   // Loop through the display list and add each object to our
   // depth-sort list for final rendering.
   VMDDisplayList::VMDLinkIter cmditer;
   display_list->first(&cmditer);
   while ((tok = display_list->next(&cmditer, cmd_ptr)) != DLASTCOMMAND) {
      draw = 0;
      nc = -1;

      switch (tok) {
         case DPOINT:
            // allocate memory
            depth_obj.points = (float *) malloc(sizeof(float) * 2);
            if (!depth_obj.points) {
               // memory error
               if (!memerror) {
                  memerror = 1;
                  msgErr << "PSDisplayDevice: Out of memory. Some " <<
                     "objects were not drawn." << sendmsg;
               }
               break;
            }

            // copy data
            depth_obj.npoints = 1;
            depth_obj.color = colorIndex;
            (transMat.top()).multpoint3d(((DispCmdPoint *) cmd_ptr)->pos, a);
            memcpy(depth_obj.points, a, sizeof(float) * 2);

            // compute the distance to the eye
            depth_obj.dist = compute_dist(a);

            // valid object to depth sort
            draw = 1;
            break;

         case DSPHERE:
         {
            (transMat.top()).multpoint3d(((DispCmdSphere *) cmd_ptr)->pos_r, c);
            r = scale_radius(((DispCmdSphere *) cmd_ptr)->pos_r[3]);

            sphere_approx(c, r);
            break;
         }

         case DSPHEREARRAY:
         {
            DispCmdSphereArray *sa = (DispCmdSphereArray *) cmd_ptr;
            int cIndex, rIndex; // cIndex: index of colors & centers
                                // rIndex: index of radii.
            float * centers;
            float * radii;
            float * colors;
            sa->getpointers(centers, radii, colors);

            set_sphere_res(sa->sphereres);

            for (cIndex = 0, rIndex=0; rIndex < sa->numspheres; 
                 cIndex+=3, rIndex++)
            {
                colorIndex = nearest_index(colors[cIndex],
                                           colors[cIndex+1],
                                           colors[cIndex+2]);
                (transMat.top()).multpoint3d(&centers[cIndex] , c);
                r = scale_radius(radii[rIndex]);

                sphere_approx(c, r);
            }

            break;
         }   

         case DLINE:
            // check for zero-length line (degenerate)
            if (!memcmp(((DispCmdLine *) cmd_ptr)->pos1,
                        ((DispCmdLine *) cmd_ptr)->pos2,
                        sizeof(float) * 3)) {
               // degenerate line
               break;
            }

            // allocate memory
            depth_obj.points = (float *) malloc(sizeof(float) * 4);
            if (!depth_obj.points) {
               // memory error
               if (!memerror) {
                  memerror = 1;
                  msgErr << "PSDisplayDevice: Out of memory. Some " <<
                     "objects were not drawn." << sendmsg;
               }
               break;
            }

            // copy data
            depth_obj.npoints = 2;
            depth_obj.color = colorIndex;
            (transMat.top()).multpoint3d(((DispCmdLine *) cmd_ptr)->pos1, a);
            (transMat.top()).multpoint3d(((DispCmdLine *) cmd_ptr)->pos2, b);
            memcpy(depth_obj.points, a, sizeof(float) * 2);
            memcpy(&depth_obj.points[2], b, sizeof(float) * 2);

            // compute the centerpoint of the object
            cent[0] = (a[0] + b[0]) / 2;
            cent[1] = (a[1] + b[1]) / 2;
            cent[2] = (a[2] + b[2]) / 2;

            // compute the distance to the eye
            depth_obj.dist = compute_dist(cent);

            // valid object to depth sort
            draw = 1;
            break;

         case DLINEARRAY:
           {
            // XXX much replicated code from DLINE
            float *v = (float *)cmd_ptr;
            int nlines = (int)v[0];
            v++;
            for (int i=0; i<nlines; i++) {
              // check for degenerate line
              if (!memcmp(v,v+3,3*sizeof(float)))
                break;

              // allocate memory
              depth_obj.points = (float *) malloc(sizeof(float) * 4);
              if (!depth_obj.points) {
                 // memory error
                 if (!memerror) {
                    memerror = 1;
                    msgErr << "PSDisplayDevice: Out of memory. Some " <<
                       "objects were not drawn." << sendmsg;
                 }
                 break;
              }

              // copy data
              depth_obj.npoints = 2;
              depth_obj.color = colorIndex;
              (transMat.top()).multpoint3d(v, a);
              (transMat.top()).multpoint3d(v+3, b);
              memcpy(depth_obj.points, a, sizeof(float) * 2);
              memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
  
              // compute the centerpoint of the object
              cent[0] = (a[0] + b[0]) / 2;
              cent[1] = (a[1] + b[1]) / 2;
              cent[2] = (a[2] + b[2]) / 2;
  
              // compute the distance to the eye
              depth_obj.dist = compute_dist(cent);
 
              // we'll add the object here, since we have multiple objects 
              draw = 0;
              memusage += sizeof(float) * 2 * depth_obj.npoints;
              points += depth_obj.npoints;
              objects++;
              depth_list.append(depth_obj);

              v += 6;
            } 
           }
           break;           

         case DPOLYLINEARRAY:
           {
            // XXX much replicated code from DLINE / DLINEARRAY
            float *v = (float *)cmd_ptr;
            int nverts = (int)v[0];
            v++;
            for (int i=0; i<nverts-1; i++) {
              // check for degenerate line
              if (!memcmp(v,v+3,3*sizeof(float)))
                break;

              // allocate memory
              depth_obj.points = (float *) malloc(sizeof(float) * 4);
              if (!depth_obj.points) {
                 // memory error
                 if (!memerror) {
                    memerror = 1;
                    msgErr << "PSDisplayDevice: Out of memory. Some " <<
                       "objects were not drawn." << sendmsg;
                 }
                 break;
              }

              // copy data
              depth_obj.npoints = 2;
              depth_obj.color = colorIndex;
              (transMat.top()).multpoint3d(v, a);
              (transMat.top()).multpoint3d(v+3, b);
              memcpy(depth_obj.points, a, sizeof(float) * 2);
              memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
  
              // compute the centerpoint of the object
              cent[0] = (a[0] + b[0]) / 2;
              cent[1] = (a[1] + b[1]) / 2;
              cent[2] = (a[2] + b[2]) / 2;
  
              // compute the distance to the eye
              depth_obj.dist = compute_dist(cent);
 
              // we'll add the object here, since we have multiple objects 
              draw = 0;
              memusage += sizeof(float) * 2 * depth_obj.npoints;
              points += depth_obj.npoints;
              objects++;
              depth_list.append(depth_obj);

              v += 3;
            } 
           }
           break;           
 
         case DCYLINDER:
         {
            int res;

            (transMat.top()).multpoint3d((float *) cmd_ptr, a);
            (transMat.top()).multpoint3d(&((float *) cmd_ptr)[3], b);
            r = scale_radius(((float *) cmd_ptr)[6]);
            res = (int) ((float *) cmd_ptr)[7];

            cylinder_approx(a, b, r, res, (int) ((float *) cmd_ptr)[8]);
            break;
         }

         case DCONE:
         {
            (transMat.top()).multpoint3d(((DispCmdCone *) cmd_ptr)->pos1, a);
            (transMat.top()).multpoint3d(((DispCmdCone *) cmd_ptr)->pos2, b);
            float r1 = scale_radius(((DispCmdCone *) cmd_ptr)->radius);
            float r2 = scale_radius(((DispCmdCone *) cmd_ptr)->radius2);

            // XXX current implementation can't draw truncated cones.
            if (r2 > 0.0f) {
              msgWarn << "PSDisplayDevice) can't draw truncated cones" 
                      << sendmsg;
            }
            cone_approx(a, b, r1);
            break;
         }

        case DTEXTSIZE:
          textsize = ((DispCmdTextSize *)cmd_ptr)->size;
          break;

        case DTEXT:
        {
            float* pos = (float *)cmd_ptr;
#if 0
            // thickness not implemented yet
            float thickness = pos[3];    // thickness is stored in 4th slot
#endif
            char* txt = (char *)(pos+4);
            int   txtlen = strlen(txt);
            // allocate memory
            depth_obj.points = (float *) malloc(sizeof(float) * 2);
            depth_obj.text   = (char  *) malloc(sizeof(char) * (txtlen+1));
            if ( !(depth_obj.points || depth_obj.text) ) {
              // memory error
              if (!memerror) {
                 memerror = 1;
                 msgErr << "PSDisplayDevice: Out of memory. Some " <<
                    "objects were not drawn." << sendmsg;
              }
              break;
           }

            // copy data
            depth_obj.npoints = 1;
            depth_obj.color = colorIndex;
            (transMat.top()).multpoint3d(((DispCmdPoint *) cmd_ptr)->pos, a);
            memcpy(depth_obj.points, a, sizeof(float) * 2);
            strcpy(depth_obj.text , txt);

            // note scale factor, stored into "light_scale", so we didn't
            // have to add a new structure member just for this.
            depth_obj.light_scale = textsize * 15;

            // compute the distance to the eye
            depth_obj.dist = compute_dist(a);

            // valid object to depth sort
            draw = 1;
            break;
         }

         case DTRIANGLE:
            // check for degenerate triangle
            if (!memcmp(((DispCmdTriangle *) cmd_ptr)->pos1,
                        ((DispCmdTriangle *) cmd_ptr)->pos2,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdTriangle *) cmd_ptr)->pos2,
                        ((DispCmdTriangle *) cmd_ptr)->pos3,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdTriangle *) cmd_ptr)->pos2,
                        ((DispCmdTriangle *) cmd_ptr)->pos3,
                        sizeof(float) * 3)) {
               // degenerate triangle
               break;
            }

            // allocate memory
            depth_obj.points = (float *) malloc(sizeof(float) * 6);
            if (!depth_obj.points) {
               // memory error
               if (!memerror) {
                  memerror = 1;
                  msgErr << "PSDisplayDevice: Out of memory. Some " <<
                     "objects were not drawn." << sendmsg;
               }
               break;
            }

            // copy data
            depth_obj.npoints = 3;
            depth_obj.color = (nc >= 0) ? nc : colorIndex;
            (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos1, a);
            (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos2, b);
            (transMat.top()).multpoint3d(((DispCmdTriangle *) cmd_ptr)->pos3, c);
            memcpy(depth_obj.points, a, sizeof(float) * 2);
            memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
            memcpy(&depth_obj.points[4], c, sizeof(float) * 2);

            // compute the centerpoint of the object
            cent[0] = (a[0] + b[0] + c[0]) / 3;
            cent[1] = (a[1] + b[1] + c[1]) / 3;
            cent[2] = (a[2] + b[2] + c[2]) / 3;

            // compute the distance to the eye for depth sorting
            depth_obj.dist = compute_dist(cent);

            // compute a light shading factor
            depth_obj.light_scale = compute_light(a, b, c);

            // valid object to depth sort
            draw = 1;
            break;

         case DTRIMESH_C4F_N3F_V3F:
            // call a separate routine to break up the mesh into
            // its component triangles
            decompose_mesh((DispCmdTriMesh *) cmd_ptr);
            break;

         case DTRISTRIP:
            // call a separate routine to break up the strip into
            // its component triangles
            decompose_tristrip((DispCmdTriStrips *) cmd_ptr);
            break;

         case DSQUARE:
            // check for degenerate quadrilateral
            if (!memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
                        ((DispCmdSquare *) cmd_ptr)->pos2,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
                        ((DispCmdSquare *) cmd_ptr)->pos3,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdSquare *) cmd_ptr)->pos1,
                        ((DispCmdSquare *) cmd_ptr)->pos4,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdSquare *) cmd_ptr)->pos2,
                        ((DispCmdSquare *) cmd_ptr)->pos3,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdSquare *) cmd_ptr)->pos2,
                        ((DispCmdSquare *) cmd_ptr)->pos4,
                        sizeof(float) * 3) ||
                !memcmp(((DispCmdSquare *) cmd_ptr)->pos3,
                        ((DispCmdSquare *) cmd_ptr)->pos4,
                        sizeof(float) * 3)) {
               // degenerate quadrilateral
               break;
            }

            // allocate memory
            depth_obj.points = (float *) malloc(sizeof(float) * 8);
            if (!depth_obj.points) {
               // memory error
               if (!memerror) {
                  memerror = 1;
                  msgErr << "PSDisplayDevice: Out of memory. Some " <<
                     "objects were not drawn." << sendmsg;
               }
               break;
            }

            // copy data
            depth_obj.npoints = 4;
            depth_obj.color = colorIndex;
            (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos1, a);
            (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos2, b);
            (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos3, c);
            (transMat.top()).multpoint3d(((DispCmdSquare *) cmd_ptr)->pos4, d);
            memcpy(depth_obj.points, a, sizeof(float) * 2);
            memcpy(&depth_obj.points[2], b, sizeof(float) * 2);
            memcpy(&depth_obj.points[4], c, sizeof(float) * 2);
            memcpy(&depth_obj.points[6], d, sizeof(float) * 2);

            // compute the centerpoint of the object
            cent[0] = (a[0] + b[0] + c[0] + d[0]) / 4;
            cent[1] = (a[1] + b[1] + c[1] + d[1]) / 4;
            cent[2] = (a[2] + b[2] + c[2] + d[2]) / 4;

            // compute the distance to the eye for depth sorting
            depth_obj.dist = compute_dist(cent);

            // compute a light shading factor
            depth_obj.light_scale = compute_light(a, b, c);

            // valid object to depth sort
            draw = 1;
            break;

         case DCOLORINDEX:
            colorIndex = ((DispCmdColorIndex *) cmd_ptr)->color;
            break;

         case DSPHERERES:
            set_sphere_res(((int *) cmd_ptr)[0]);
            break;

         default:
            // unknown object, so just skip it
            break;
      }

      // if we have a valid object to add to the depth sort list
      if (draw && depth_obj.npoints) {
         memusage += sizeof(float) * 2 * depth_obj.npoints;
         if ( depth_obj.text )
           memusage += sizeof(char) * (1+strlen(depth_obj.text));
         points += depth_obj.npoints;
         objects++;
         depth_list.append(depth_obj);
      }

      depth_obj.npoints = 0;
      depth_obj.points = NULL;

   } // while (tok != DLASTCOMMAND)

     transMat.pop();
   } // end for() [periodic images]
}
예제 #2
0
int DisplayDevice::pick(int dim, const float *pos, const VMDDisplayList *cmdList,
			float &eyedist, int *unitcell, float window_size) {
  char *cmdptr = NULL;
  int tok;
  float newEyeDist, currEyeDist = eyedist;
  int tag = (-1), inRegion, currTag;
  float minX=0.0f, minY=0.0f, maxX=0.0f, maxY=0.0f;
  float fminX=0.0f, fminY=0.0f, fminZ=0.0f, fmaxX=0.0f, fmaxY=0.0f, fmaxZ=0.0f;
  float wpntpos[3], pntpos[3], cpos[3];

  if(!cmdList)
    return (-1);

  // initialize picking: find screen region to look for object
  if (dim == 2) {
    fminX = pos[0] - window_size;
    fmaxX = pos[0] + window_size;
    fminY = pos[1] - window_size;
    fmaxY = pos[1] + window_size;
    abs_screen_pos(fminX, fminY);
    abs_screen_pos(fmaxX, fmaxY);
#if defined(_MSC_VER)
    // Win32 lacks the C99 round() routine
    // Add +/- 0.5 then then round towards zero.
#if 1
    minX = (int) ((float) (fminX + (fminX >= 0.0f ?  0.5f : -0.5f)));
    maxX = (int) ((float) (fmaxX + (fmaxX >= 0.0f ?  0.5f : -0.5f)));
    minY = (int) ((float) (fminY + (fminY >= 0.0f ?  0.5f : -0.5f)));
    maxY = (int) ((float) (fmaxY + (fmaxY >= 0.0f ?  0.5f : -0.5f)));
#else
    minX = truncf(fminX + (fminX >= 0.0f ?  0.5f : -0.5f));
    maxX = truncf(fmaxX + (fmaxX >= 0.0f ?  0.5f : -0.5f));
    minY = truncf(fminY + (fminY >= 0.0f ?  0.5f : -0.5f));
    maxY = truncf(fmaxY + (fmaxY >= 0.0f ?  0.5f : -0.5f));
//    minX = floor(fminX + 0.5);
//    maxX = floor(fmaxX + 0.5);
//    minY = floor(fminY + 0.5);
//    maxY = floor(fmaxY + 0.5);
#endif
#else
    minX = round(fminX);
    maxX = round(fmaxX);
    minY = round(fminY);
    maxY = round(fmaxY);
#endif

  } else {
    fminX = pos[0] - window_size;
    fmaxX = pos[0] + window_size;
    fminY = pos[1] - window_size;
    fmaxY = pos[1] + window_size;
    fminZ = pos[2] - window_size;
    fmaxZ = pos[2] + window_size;
  }

  // make sure we do not disturb the regular transformation matrix
  transMat.dup();
  (transMat.top()).multmatrix(cmdList->mat);

  // Transform the current pick point for each periodic image 
  ResizeArray<Matrix4> pbcImages;
  ResizeArray<int> pbcCells;
  find_pbc_images(cmdList, pbcImages);
  find_pbc_cells(cmdList, pbcCells);
  int pbcimg;
  for (pbcimg=0; pbcimg<pbcImages.num(); pbcimg++) {
    transMat.dup();
    (transMat.top()).multmatrix(pbcImages[pbcimg]);

    // scan through the list, getting each command and executing it, until
    // the end of commands token is found
    VMDDisplayList::VMDLinkIter cmditer;
    cmdList->first(&cmditer);
    while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) {
      switch (tok) {
        case DPICKPOINT:
          // calculate the transformed position of the point
          {
            DispCmdPickPoint *cmd = (DispCmdPickPoint *)cmdptr;
            vec_copy(wpntpos, cmd->postag);
            currTag = cmd->tag;
          }
          (transMat.top()).multpoint3d(wpntpos, pntpos);

          // check if in picking region ... different for 2D and 3D
          if (dim == 2) {
            // convert the 3D world coordinate to 2D (XY) absolute screen 
            // coordinate, and a normalized Z coordinate.
            abs_screen_loc_3D(pntpos, cpos);
      
            // check to see if the projected picking position falls within the 
            // view frustum, with the XY coords falling within the displayed 
            // window, and the Z coordinate falling within the view volume
            // between the front and rear clipping planes.
            inRegion = (cpos[0] >= minX && cpos[0] <= maxX &&
                        cpos[1] >= minY && cpos[1] <= maxY &&
                        cpos[2] >= 0.0  && cpos[2] <= 1.0);
          } else {
            // just check to see if the position is in a box centered on our
            // pointer.  The pointer position should already be transformed.
            inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX &&	
                        pntpos[1] >= fminY && pntpos[1] <= fmaxY &&
                        pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
          }

          // Clip still-viable pick points against all active clipping planes
          if (inRegion) {
            // We must perform a check against all of the active
            // user-defined clipping planes to ensure that only pick points
            // associated with visible geometry can be selected.
            int cp;
            for (cp=0; cp < VMD_MAX_CLIP_PLANE; cp++) {
              // The final result is the intersection of all of the
              // individual clipping plane tests...
              if (cmdList->clipplanes[cp].mode) {
                float cpdist[3];
                vec_sub(cpdist, wpntpos, cmdList->clipplanes[cp].center);
                inRegion &= (dot_prod(cpdist, 
                                      cmdList->clipplanes[cp].normal) > 0.0f);
              }
            }
          }
      
          // has a hit occurred?
          if (inRegion) {
            // yes, see if it is closer to the eye position than earlier objects
            if(dim==2) 
              newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
            else 
              newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);

            if(currEyeDist < 0.0 || newEyeDist < currEyeDist) {
              currEyeDist = newEyeDist;
              tag = currTag;
              if (unitcell) {
                unitcell[0] = pbcCells[3*pbcimg  ];
                unitcell[1] = pbcCells[3*pbcimg+1];
                unitcell[2] = pbcCells[3*pbcimg+2];
              }
            }
          }
          break;

        case DPICKPOINT_ARRAY:
          // loop over all of the pick points in the pick point index array
          DispCmdPickPointArray *cmd = (DispCmdPickPointArray *)cmdptr;
          float *pickpos=NULL;
          float *crds=NULL;
          int *indices=NULL;
          cmd->getpointers(crds, indices); 

          int i;
          for (i=0; i<cmd->numpicks; i++) {
            pickpos = crds + i*3;
            if (cmd->allselected) {
              currTag = i + cmd->firstindex;
            } else {
              currTag = indices[i];
            }
            vec_copy(wpntpos, pickpos);

            (transMat.top()).multpoint3d(pickpos, pntpos);

            // check if in picking region ... different for 2D and 3D
            if (dim == 2) {
              // convert the 3D world coordinate to 2D absolute screen coord
              abs_screen_loc_3D(pntpos, cpos);

              // check to see if the position falls in our picking region
              // including the clipping region (cpos[2])
              inRegion = (cpos[0] >= minX && cpos[0] <= maxX &&
                          cpos[1] >= minY && cpos[1] <= maxY &&
                          cpos[2] >= 0.0  && cpos[2] <= 1.0);
            } else {
              // just check to see if the position is in a box centered on our
              // pointer.  The pointer position should already be transformed.
              inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX &&
                          pntpos[1] >= fminY && pntpos[1] <= fmaxY &&
                          pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
            }

            // Clip still-viable pick points against all active clipping planes
            if (inRegion) {
              // We must perform a check against all of the active
              // user-defined clipping planes to ensure that only pick points
              // associated with visible geometry can be selected.
              int cp;
              for (cp=0; cp < VMD_MAX_CLIP_PLANE; cp++) {
                // The final result is the intersection of all of the
                // individual clipping plane tests...
                if (cmdList->clipplanes[cp].mode) {
                  float cpdist[3];
                  vec_sub(cpdist, wpntpos, cmdList->clipplanes[cp].center);
                  inRegion &= (dot_prod(cpdist, 
                                        cmdList->clipplanes[cp].normal) > 0.0f);
                }
              }
            }

            // has a hit occurred?
            if (inRegion) {
              // yes, see if it is closer to the eye than earlier hits
              if (dim==2)
                newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
              else
                newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);

              if (currEyeDist < 0.0 || newEyeDist < currEyeDist) {
                currEyeDist = newEyeDist;
                tag = currTag;
                if (unitcell) {
                  unitcell[0] = pbcCells[3*pbcimg  ];
                  unitcell[1] = pbcCells[3*pbcimg+1];
                  unitcell[2] = pbcCells[3*pbcimg+2];
                }
              }
            }
          }
          break;
      }
    }

    // Pop the PBC image transform
    transMat.pop();
  } // end of loop over PBC images

  // make sure we do not disturb the regular transformation matrix
  transMat.pop();

  // return result; if tag >= 0, we found something
  eyedist = currEyeDist;
  return tag;
}
예제 #3
0
  int
  DisplayDevice::pick (int dim, const float *pos, const VMDDisplayList *cmdList,
      float &eyedist, int *unitcell, float window_size)
  {
    char *cmdptr = NULL;
    int tok;
    float newEyeDist, currEyeDist = eyedist;
    int tag = (-1), inRegion, currTag;
    int minX = 0, minY = 0, maxX = 0, maxY = 0;
    float fminX = 0.0f, fminY = 0.0f, fminZ = 0.0f, fmaxX = 0.0f, fmaxY = 0.0f,
        fmaxZ = 0.0f;
    float pntpos[3];
    long cpos[2];

    if (!cmdList)
      return (-1);

    // initialize picking: find screen region to look for object
    if (dim == 2)
    {
      fminX = pos[0] - window_size;
      fmaxX = pos[0] + window_size;
      fminY = pos[1] - window_size;
      fmaxY = pos[1] + window_size;
      abs_screen_pos (fminX, fminY);
      abs_screen_pos (fmaxX, fmaxY);
      minX = (int) fminX;
      maxX = (int) fmaxX;
      minY = (int) fminY;
      maxY = (int) fmaxY;
    }
    else
    {
      fminX = pos[0] - window_size;
      fmaxX = pos[0] + window_size;
      fminY = pos[1] - window_size;
      fmaxY = pos[1] + window_size;
      fminZ = pos[2] - window_size;
      fmaxZ = pos[2] + window_size;
    }

    // make sure we do not disturb the regular transformation matrix
    transMat.dup ();
    (transMat.top ()).multmatrix (cmdList->mat);

    // Transform the current pick point for each periodic image
    ResizeArray<Matrix4> pbcImages;
    ResizeArray<int> pbcCells;
    find_pbc_images (cmdList, pbcImages);
    find_pbc_cells (cmdList, pbcCells);
    int pbcimg;
    for (pbcimg = 0; pbcimg < pbcImages.num (); pbcimg++)
    {
      transMat.dup ();
      (transMat.top ()).multmatrix (pbcImages[pbcimg]);

      // scan through the list, getting each command and executing it, until
      // the end of commands token is found
      VMDDisplayList::VMDLinkIter cmditer;
      cmdList->first (&cmditer);
      float *dataBlock = NULL;
      while ((tok = cmdList->next (&cmditer, cmdptr)) != DLASTCOMMAND)
      {
        switch (tok)
        {
          case DDATABLOCK:
#ifdef VMDCAVE
            dataBlock = (float *)cmdptr;
#else
            dataBlock = ((DispCmdDataBlock *) cmdptr)->data;
#endif
            break;

          case DPICKPOINT:
          case DPICKPOINT_I:
            // calculate the transformed position of the point
            if (tok == DPICKPOINT)
            {
              DispCmdPickPoint *cmd = (DispCmdPickPoint *) cmdptr;
              (transMat.top ()).multpoint3d (cmd->postag, pntpos);
              currTag = cmd->tag;
            }
            else
            {
              DispCmdPickPointIndex *cmd = (DispCmdPickPointIndex *) cmdptr;
              (transMat.top ()).multpoint3d (dataBlock + cmd->pos, pntpos);
              currTag = cmd->tag;
            }

            // check if in picking region ... different for 2D and 3D
            if (dim == 2)
            {
              // convert the 3D world coordinate to 2D absolute screen coord
              abs_screen_loc_3D (pntpos, cpos);

              // check to see if the position falls in our picking region
              inRegion = (cpos[0] >= minX && cpos[0] <= maxX && cpos[1] >= minY
                  && cpos[1] <= maxY);
            }
            else
            {
              // just check to see if the position is in a box centered on our
              // pointer.  The pointer position should already be transformed.
              inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX
                  && pntpos[1] >= fminY && pntpos[1] <= fmaxY
                  && pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
            }

            // has a hit occurred?
            if (inRegion)
            {
              // yes, see if it is closer to the eye position than earlier objects
              if (dim == 2)
                newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
              else
                newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);

              if (currEyeDist < 0.0 || newEyeDist < currEyeDist)
              {
                currEyeDist = newEyeDist;
                tag = currTag;
                if (unitcell)
                {
                  unitcell[0] = pbcCells[3 * pbcimg];
                  unitcell[1] = pbcCells[3 * pbcimg + 1];
                  unitcell[2] = pbcCells[3 * pbcimg + 2];
                }
              }
            }
            break;

          case DPICKPOINT_IARRAY:
            // loop over all of the pick points in the pick point index array
            DispCmdPickPointIndexArray *cmd =
                (DispCmdPickPointIndexArray *) cmdptr;
            float *pickpos;
            int *indices;
            cmd->getpointers (indices);

            int i;
            for (i = 0; i < cmd->numpicks; i++)
            {
              if (cmd->allselected)
              {
                pickpos = dataBlock + i * 3;
                currTag = i;
              }
              else
              {
                pickpos = dataBlock + indices[i] * 3;
                currTag = indices[i];
              }

              (transMat.top ()).multpoint3d (pickpos, pntpos);

              // check if in picking region ... different for 2D and 3D
              if (dim == 2)
              {
                // convert the 3D world coordinate to 2D absolute screen coord
                abs_screen_loc_3D (pntpos, cpos);

                // check to see if the position falls in our picking region
                inRegion = (cpos[0] >= minX && cpos[0] <= maxX
                    && cpos[1] >= minY && cpos[1] <= maxY);
              }
              else
              {
                // just check to see if the position is in a box centered on our
                // pointer.  The pointer position should already be transformed.
                inRegion = (pntpos[0] >= fminX && pntpos[0] <= fmaxX
                    && pntpos[1] >= fminY && pntpos[1] <= fmaxY
                    && pntpos[2] >= fminZ && pntpos[2] <= fmaxZ);
              }

              // has a hit occurred?
              if (inRegion)
              {
                // yes, see if it is closer to the eye than earlier hits
                if (dim == 2)
                  newEyeDist = DTOEYE(pntpos[0], pntpos[1], pntpos[2]);
                else
                  newEyeDist = DTOPOINT(pntpos[0],pntpos[1],pntpos[2]);

                if (currEyeDist < 0.0 || newEyeDist < currEyeDist)
                {
                  currEyeDist = newEyeDist;
                  tag = currTag;
                  if (unitcell)
                  {
                    unitcell[0] = pbcCells[3 * pbcimg];
                    unitcell[1] = pbcCells[3 * pbcimg + 1];
                    unitcell[2] = pbcCells[3 * pbcimg + 2];
                  }
                }
              }
            }
            break;
        }
      }

      // Pop the PBC image transform
      transMat.pop ();
    } // end of loop over PBC images

    // make sure we do not disturb the regular transformation matrix
    transMat.pop ();

    // return result; if tag >= 0, we found something
    eyedist = currEyeDist;
    return tag;
  }