fracviewer.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:13k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /*
  2.  * fractviewer.c [from agviewer.c  (version 1.0)]
  3.  *
  4.  * AGV: a glut viewer. Routines for viewing a 3d scene w/ glut
  5.  *
  6.  * See agv_example.c and agviewer.h comments within for more info.
  7.  *
  8.  * I welcome any feedback or improved versions!
  9.  *
  10.  * Philip Winston - 4/11/95
  11.  * pwinston@hmc.edu
  12.  * http://www.cs.hmc.edu/people/pwinston
  13.  */
  14. #include <GL/glut.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <math.h>
  18. #include "fracviewer.h"
  19. /* Some <math.h> files do not define M_PI... */
  20. #ifndef M_PI
  21. #define M_PI 3.14159265358979323846
  22. #endif
  23. /***************************************************************/
  24. /************************** SETTINGS ***************************/
  25. /***************************************************************/
  26.    /* Initial polar movement settings */
  27. #define INIT_POLAR_AZ  0.0
  28. #define INIT_POLAR_EL 30.0
  29. #define INIT_DIST      4.0
  30. #define INIT_AZ_SPIN   0.5
  31. #define INIT_EL_SPIN   0.0
  32.   /* Initial flying movement settings */
  33. #define INIT_EX        0.0
  34. #define INIT_EY       -2.0
  35. #define INIT_EZ       -2.0
  36. #define INIT_MOVE     0.01
  37. #define MINMOVE      0.001    
  38.   /* Start in this mode */
  39. #define INIT_MODE   POLAR   
  40.   /* Controls:  */
  41.   /* map 0-9 to an EyeMove value when number key is hit in FLYING mode */
  42. #define SPEEDFUNCTION(x) ((x)*(x)*0.001)  
  43.   /* Multiply EyeMove by (1+-MOVEFRACTION) when +/- hit in FLYING mode */
  44. #define MOVEFRACTION 0.25   
  45.   /* What to multiply number of pixels mouse moved by to get rotation amount */
  46. #define EL_SENS   0.5
  47. #define AZ_SENS   0.5
  48.   /* What to multiply number of pixels mouse moved by for movement amounts */
  49. #define DIST_SENS 0.01
  50. #define E_SENS    0.01
  51.   /* Minimum spin to allow in polar (lower forced to zero) */
  52. #define MIN_AZSPIN 0.1
  53. #define MIN_ELSPIN 0.1
  54.   /* Factors used in computing dAz and dEl (which determine AzSpin, ElSpin) */
  55. #define SLOW_DAZ 0.90
  56. #define SLOW_DEL 0.90
  57. #define PREV_DAZ 0.80
  58. #define PREV_DEL 0.80
  59. #define CUR_DAZ  0.20
  60. #define CUR_DEL  0.20
  61. /***************************************************************/
  62. /************************** GLOBALS ****************************/
  63. /***************************************************************/
  64. int     MoveMode = INIT_MODE;  /* FLYING or POLAR mode? */
  65. GLfloat Ex = INIT_EX,             /* flying parameters */
  66.         Ey = INIT_EY,
  67.         Ez = INIT_EZ,
  68.         EyeMove = INIT_MOVE,     
  69.         EyeDist = INIT_DIST,      /* polar params */
  70.         AzSpin  = INIT_AZ_SPIN,
  71.         ElSpin  = INIT_EL_SPIN,
  72.         EyeAz = INIT_POLAR_AZ,    /* used by both */
  73.         EyeEl = INIT_POLAR_EL;
  74. int agvMoving;    /* Currently moving?  */
  75. int downx, downy,   /* for tracking mouse position */
  76.     lastx, lasty,
  77.     downb = -1;     /* and button status */
  78. GLfloat downDist, downEl, downAz, /* for saving state of things */
  79.         downEx, downEy, downEz,   /* when button is pressed */
  80.         downEyeMove;                
  81. GLfloat dAz, dEl, lastAz, lastEl;  /* to calculate spinning w/ polar motion */
  82. int     AdjustingAzEl = 0;
  83. int AllowIdle, RedisplayWindow; 
  84.    /* If AllowIdle is 1 it means AGV will install its own idle which
  85.     * will update the viewpoint as needed and send glutPostRedisplay() to the
  86.     * window RedisplayWindow which was set in agvInit().  AllowIdle of 0
  87.     * means AGV won't install an idle funciton, and something like
  88.     * "if (agvMoving) agvMove()" should exist at the end of the running
  89.     * idle function.
  90.     */
  91. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  92. #define TORAD(x) ((M_PI/180.0)*(x))
  93. #define TODEG(x) ((180.0/M_PI)*(x))
  94. /***************************************************************/
  95. /************************ PROTOTYPES ***************************/
  96. /***************************************************************/
  97.   /*
  98.    * these are functions meant for internal use only
  99.    * the other prototypes are in agviewer.h
  100.    */
  101. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth);
  102. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z,
  103.                         GLfloat az, GLfloat el);
  104. int  ConstrainEl(void);
  105. void MoveOn(int v);
  106. void SetMove(float newmove);
  107. static void normalize(GLfloat v[3]);
  108. static void ncrossprod(float v1[3], float v2[3], float cp[3]);
  109. /***************************************************************/
  110. /************************ agvInit ******************************/
  111. /***************************************************************/
  112. void agvInit(int window)
  113. {
  114.   glutMouseFunc(agvHandleButton);
  115.   glutMotionFunc(agvHandleMotion);
  116.   glutKeyboardFunc(agvHandleKeys);
  117.   RedisplayWindow = glutGetWindow();
  118.   agvSetAllowIdle(window);
  119. }
  120. /***************************************************************/
  121. /************************ VIEWPOINT STUFF **********************/
  122. /***************************************************************/
  123.   /*
  124.    * viewing transformation modified from page 90 of red book
  125.    */
  126. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth)
  127. {
  128.   glTranslatef(0, 0, -dist);
  129.   glRotatef(elevation, 1, 0, 0);
  130.   glRotatef(azimuth, 0, 1, 0);
  131. }
  132.   /*
  133.    * I took the idea of tracking eye position in absolute
  134.    * coords and direction looking in Polar form from denis
  135.    */
  136. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z, GLfloat az, GLfloat el)
  137. {
  138.   float lookat[3], perp[3], up[3];
  139.   lookat[0] = sin(TORAD(az))*cos(TORAD(el));
  140.   lookat[1] = sin(TORAD(el));
  141.   lookat[2] = -cos(TORAD(az))*cos(TORAD(el));
  142.   normalize(lookat);
  143.   perp[0] = lookat[2];
  144.   perp[1] = 0;
  145.   perp[2] = -lookat[0];
  146.   normalize(perp);
  147.   ncrossprod(lookat, perp, up);
  148.   gluLookAt(x, y, z,
  149.             x+lookat[0], y+lookat[1], z+lookat[2],
  150.             up[0], up[1], up[2]);
  151. }
  152.   /*
  153.    * Call viewing transformation based on movement mode
  154.    */
  155. void agvViewTransform(void)
  156.   switch (MoveMode) {
  157.     case FLYING:
  158.       FlyLookFrom(Ex, Ey, Ez, EyeAz, EyeEl);
  159.       break;
  160.     case POLAR:
  161.       PolarLookFrom(EyeDist, EyeEl, EyeAz);
  162.       break;
  163.     }
  164. }
  165.   /*
  166.    * keep them vertical; I think this makes a lot of things easier, 
  167.    * but maybe it wouldn't be too hard to adapt things to let you go
  168.    * upside down
  169.    */
  170. int ConstrainEl(void)
  171. {
  172.   if (EyeEl <= -90) {
  173.     EyeEl = -89.99;
  174.     return 1;
  175.   } else if (EyeEl >= 90) {
  176.     EyeEl = 89.99;
  177.     return 1;
  178.   }
  179.   return 0;
  180. }
  181.  /*
  182.   * Idle Function - moves eyeposition
  183.   */
  184. void agvMove(void)
  185. {
  186.   switch (MoveMode)  {
  187.     case FLYING:
  188.       Ex += EyeMove*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  189.       Ey += EyeMove*sin(TORAD(EyeEl));
  190.       Ez -= EyeMove*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  191.       break;
  192.     case POLAR:
  193.       EyeEl += ElSpin;
  194.       EyeAz += AzSpin;
  195.       if (ConstrainEl()) {  /* weird spin thing to make things look     */
  196.         ElSpin = -ElSpin;      /* look better when you are kept from going */
  197.                                /* upside down while spinning - Isn't great */
  198.         if (fabs(ElSpin) > fabs(AzSpin))
  199.           AzSpin = fabs(ElSpin) * ((AzSpin > 0) ? 1 : -1);
  200.       }
  201.       break;
  202.     }
  203.   if (AdjustingAzEl) {
  204.     dAz *= SLOW_DAZ;
  205.     dEl *= SLOW_DEL;
  206.   }
  207.   if (AllowIdle) {
  208.     glutSetWindow(RedisplayWindow);
  209.     glutPostRedisplay();
  210.   }
  211. }
  212.   /*
  213.    * Don't install agvMove as idle unless we will be updating the view
  214.    * and we've been given a RedisplayWindow
  215.    */
  216. void MoveOn(int v)
  217. {
  218.   if (v && ((MoveMode == FLYING && EyeMove != 0) ||
  219.              (MoveMode == POLAR &&
  220.              (AzSpin != 0 || ElSpin != 0 || AdjustingAzEl)))) {
  221.     agvMoving = 1;
  222.     if (AllowIdle)
  223.       glutIdleFunc(agvMove);
  224.   } else {
  225.     agvMoving = 0;
  226.     if (AllowIdle)
  227.       glutIdleFunc(NULL);
  228.   }
  229. }
  230.   /*
  231.    * set new redisplay window.  If <= 0 it means we are not to install
  232.    * an idle function and will rely on whoever does install one to 
  233.    * put statement like "if (agvMoving) agvMove();" at end of it
  234.    */
  235. void agvSetAllowIdle(int allowidle)
  236. {
  237.   if ((AllowIdle = allowidle))
  238.     MoveOn(1);
  239. }
  240.   /*
  241.    * when moving to flying we stay in the same spot, moving to polar we
  242.    * reset since we have to be looking at the origin (though a pivot from
  243.    * current position to look at origin might be cooler)
  244.    */
  245. void agvSwitchMoveMode(int move)
  246. {
  247.   switch (move) {
  248.     case FLYING:
  249.       if (MoveMode == FLYING) return;
  250.       Ex    = -EyeDist*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  251.       Ey    =  EyeDist*sin(TORAD(EyeEl));
  252.       Ez    =  EyeDist*(cos(TORAD(EyeAz))*cos(TORAD(EyeEl)));
  253.       EyeAz =  EyeAz;
  254.       EyeEl = -EyeEl;
  255.       EyeMove = INIT_MOVE;
  256.       break;
  257.     case POLAR:
  258.       EyeDist = INIT_DIST;
  259.       EyeAz   = INIT_POLAR_AZ;
  260.       EyeEl   = INIT_POLAR_EL;
  261.       AzSpin  = INIT_AZ_SPIN;
  262.       ElSpin  = INIT_EL_SPIN;
  263.       break;
  264.     }
  265.   MoveMode = move;
  266.   MoveOn(1);
  267.   glutPostRedisplay();
  268. }
  269. /***************************************************************/
  270. /*******************    MOUSE HANDLING   ***********************/
  271. /***************************************************************/
  272. void agvHandleButton(int button, int state, int x, int y)
  273. {
  274.  if (state == GLUT_DOWN && downb == -1) {  
  275.     lastx = downx = x;
  276.     lasty = downy = y;
  277.     downb = button;    
  278.     switch (button) {
  279.       case GLUT_LEFT_BUTTON:
  280.         lastEl = downEl = EyeEl;
  281.         lastAz = downAz = EyeAz;
  282.         AzSpin = ElSpin = dAz = dEl = 0;
  283.         AdjustingAzEl = 1;
  284. MoveOn(1);
  285.         break;
  286.       case GLUT_MIDDLE_BUTTON:
  287.         downDist = EyeDist;
  288. downEx = Ex;
  289. downEy = Ey;
  290. downEz = Ez;
  291. downEyeMove = EyeMove;
  292. EyeMove = 0;
  293.     }
  294.   } else if (state == GLUT_UP && button == downb) {
  295.     downb = -1;
  296.     switch (button) {
  297.       case GLUT_LEFT_BUTTON:
  298.         if (MoveMode != FLYING) {
  299.   AzSpin =  -dAz;
  300.   if (AzSpin < MIN_AZSPIN && AzSpin > -MIN_AZSPIN)
  301.     AzSpin = 0;
  302.   ElSpin = -dEl;
  303.   if (ElSpin < MIN_ELSPIN && ElSpin > -MIN_ELSPIN)
  304.     ElSpin = 0; 
  305. }
  306.         AdjustingAzEl = 0;
  307.         MoveOn(1);
  308. break;
  309.       case GLUT_MIDDLE_BUTTON:
  310. EyeMove = downEyeMove;
  311.       }
  312.   }
  313. }
  314.  /*
  315.   * change EyeEl and EyeAz and position when mouse is moved w/ button down
  316.   */
  317. void agvHandleMotion(int x, int y)
  318. {
  319.   int deltax = x - downx, deltay = y - downy;
  320.   switch (downb) {
  321.     case GLUT_LEFT_BUTTON:
  322.       EyeEl  = downEl + EL_SENS * ((MoveMode == FLYING) ? -deltay : deltay);
  323.       ConstrainEl();
  324.       EyeAz  = downAz + AZ_SENS * deltax;
  325.       dAz    = PREV_DAZ*dAz + CUR_DAZ*(lastAz - EyeAz);
  326.       dEl    = PREV_DEL*dEl + CUR_DEL*(lastEl - EyeEl);
  327.       lastAz = EyeAz;
  328.       lastEl = EyeEl;
  329.       break;
  330.     case GLUT_MIDDLE_BUTTON:
  331.         EyeDist = downDist + DIST_SENS*deltay;
  332.         Ex = downEx - E_SENS*deltay*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  333.         Ey = downEy - E_SENS*deltay*sin(TORAD(EyeEl));
  334.         Ez = downEz + E_SENS*deltay*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  335.       break;
  336.   }
  337.   glutPostRedisplay();
  338. }
  339. /***************************************************************/
  340. /********************* KEYBOARD HANDLING ***********************/
  341. /***************************************************************/
  342.   /*
  343.    * set EyeMove (current speed) for FLYING mode
  344.    */
  345. void SetMove(float newmove)
  346. {
  347.   if (newmove > MINMOVE) {
  348.     EyeMove = newmove;
  349.     MoveOn(1);
  350.   } else {
  351.     EyeMove = 0;
  352.     MoveOn(0);
  353.   }
  354. }
  355.   /*
  356.    * 0->9 set speed, +/- adjust current speed  -- in FLYING mode
  357.    */
  358. /* ARGSUSED1 */
  359. void agvHandleKeys(unsigned char key, int x, int y)
  360. {
  361.   if (MoveMode != FLYING)
  362.     return;
  363.   if (key >= '0' && key <= '9')
  364.     SetMove(SPEEDFUNCTION((key-'0')));
  365.   else
  366.     switch(key) {
  367.       case '+':  
  368.         if (EyeMove == 0)
  369.           SetMove(MINMOVE);
  370.          else
  371.   SetMove(EyeMove *= (1 + MOVEFRACTION));
  372.         break;
  373.       case '-':
  374. SetMove(EyeMove *= (1 - MOVEFRACTION));
  375.         break;
  376.     }
  377. }
  378. /***************************************************************/
  379. /*********************** VECTOR STUFF **************************/
  380. /***************************************************************/
  381.   /* normalizes v */
  382. static void normalize(GLfloat v[3])
  383. {
  384.   GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  385.   if (d == 0)
  386.     fprintf(stderr, "Zero length vector in normalizen");
  387.   else
  388.     v[0] /= d; v[1] /= d; v[2] /= d;
  389. }
  390.   /* calculates a normalized crossproduct to v1, v2 */
  391. static void ncrossprod(float v1[3], float v2[3], float cp[3])
  392. {
  393.   cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
  394.   cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
  395.   cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
  396.   normalize(cp);
  397. }
  398. /***************************************************************/
  399. /**************************** AXES *****************************/
  400. /***************************************************************/
  401.   /* draw axes -- was helpful to debug/design things */
  402. void agvMakeAxesList(int displaylistnum)
  403. {
  404.   int i,j;
  405.   GLfloat axes_ambuse[] =   { 0.5, 0.0, 0.0, 1.0 };
  406.   glNewList(displaylistnum, GL_COMPILE);
  407.   glPushAttrib(GL_LIGHTING_BIT);
  408.   glMatrixMode(GL_MODELVIEW);
  409.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, axes_ambuse);
  410.     glBegin(GL_LINES);
  411.       glVertex3f(15, 0, 0); glVertex3f(-15, 0, 0);
  412.       glVertex3f(0, 15, 0); glVertex3f(0, -15, 0);
  413.       glVertex3f(0, 0, 15); glVertex3f(0, 0, -15);
  414.     glEnd();
  415.     for (i = 0; i < 3; i++) {
  416.       glPushMatrix();
  417.         glTranslatef(-10*(i==0), -10*(i==1), -10*(i==2));
  418.         for (j = 0; j < 21; j++) {
  419.           glutSolidCube(0.1);
  420.           glTranslatef(i==0, i==1, i==2);
  421. }
  422.       glPopMatrix();
  423.     }
  424.   glPopAttrib();
  425.   glEndList();  
  426. }