home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / crdrot.c < prev    next >
C/C++ Source or Header  |  1990-04-20  |  7KB  |  221 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    crdrot.c (Coordinate Rotate)
  6.  * Purpose:    Add a rotation to be applied through the transform
  7.  * Subroutine:    rotate_transform        returns: void
  8.  * Xlib calls:    none
  9.  * Copyright:    1988 Smithsonian Astrophysical Observatory
  10.  *        You may do anything you like with this file except remove
  11.  *        this copyright.  The Smithsonian Astrophysical Observatory
  12.  *        makes no representations about the suitability of this
  13.  *        software for any purpose.  It is provided "as is" without
  14.  *        express or implied warranty.
  15.  * Modified:    {0} Michael VanHilst    initial version            16 March 1988
  16.  *        {n} <who> -- <does what> -- <when>
  17.  */
  18.  
  19. #include "hfiles/coord.h"    /* coord structs */
  20.  
  21. /*
  22.  * rotation matrix for coordinates (rotate on perpendicular (Z) axis)
  23.  *
  24.  *    |  cos() sin() 0 |  cos(0)= 1, cos(90)= 0, cos(180)=-1, cos(270)= 0
  25.  *    | -sin() cos() 0 |  sin(0)= 0, sin(90)= 1, sin(180)= 0, sin(270)=-1
  26.  *    |   0     0    1 |
  27.  *
  28.  * mirror matrix flips coordinates on 0,0 X or Y axis
  29.  *
  30.  * X: | -1  0  0 |    Y: |  1  0  0 |
  31.  *    |  0  1  0 |       |  0 -1  0 |
  32.  *    |  0  0  1 |       |  0  0  1 |
  33.  *
  34.  * translation matrix to move 0,0 position
  35.  *
  36.  *    |   1     0    0 |  distance to move 0,0 to center
  37.  *    |   0     1    0 |  ((float)([width]or[height] + 1) / 2.0) - ioff
  38.  *    | xmove ymove  1 |  center of first pixel is 0.5(ioff=0.5), 1.0(ioff=0)
  39.  */
  40.  
  41. /*
  42.  * Subroutine:    rotate_transform
  43.  * Purpose:    Perform requested transformation of image coordinates
  44.  * Method:    Transform img coords to what they would be without rotation
  45.  * Parameter:    rotcode: 0 = no change
  46.  *         1, 2, 3 = rotation of 90, 180, and 270 degrees
  47.  *         4 = flip the Y coordinates (top becomes bottom
  48.  *         5, 6, 7 = rotate the flipped image 90, 180, and 270 degrees
  49.  * Notes:
  50.  * Sequence is applied before conversions already in imgtofile
  51.  *  - starting with img coords,
  52.  *   A. shift origin of img buffer coordinates to exact center of buffer
  53.  *   B. undo rotation of img buffer (about origin - now at center of buffer)
  54.  *   C. shift origin to where it would be in unrotated buffer
  55.  * As each transform is applied to the front, we apply them in reverse order
  56.  *  the result is, from img->A,B,C,imgtofile(as given)->file
  57.  */
  58. void rotate_transform ( img, imgtofile, flip, rotcode )
  59.      Coordsys *img;
  60.      Transform *imgtofile;
  61.      int flip;
  62.      int rotcode;
  63. {
  64.   double xmove, ymove;
  65.   int angle;
  66.   static void move_mtrx(), flip_mtrx(), turn_mtrx();
  67.  
  68.   /* if no rotation, do nothing */
  69.   if( (rotcode == 0) && (flip == 0) ) return;
  70.   /* determine offset from real edge to real center */
  71.   xmove = (double)img->width / 2.0;
  72.   ymove = (double)img->height / 2.0;
  73.   /* shift origin from buffer center (for rotation) to buffer edge */
  74.   move_mtrx(imgtofile, xmove, ymove, 0.5, 1);
  75.   /* flip Y coordinates about 0,0 (center), if requested */
  76.   if( flip )
  77.     flip_mtrx (imgtofile, 1);
  78.   /* rotate image about 0,0 (center), use -angle to undo rotation of buffer */
  79.   /* shift origin to 0,0 in rotated buffer */
  80.   if( rotcode != 0 ) {
  81.     angle = rotcode * -90;
  82.     turn_mtrx(imgtofile, angle, 1);
  83.   }
  84.   /* shift origin from buffer corner to buffer center (center of rotation) */
  85.   move_mtrx(imgtofile, -xmove, -ymove, 0.5, 1);
  86. }
  87.  
  88. /*
  89.  * Subroutine:    move_mtrx
  90.  * Purpose:    Apply a given linear translation to the passed Transform
  91.  * Parameter:    prior: 1: move, do transform, move, 0: do transform, move
  92.  * Parameter:    ioff: offset of integer coord (i.e. 0.5), needed for prior=1
  93.  * Note:    ioff is not used for turn or flip, as it is assumed that both
  94.  *         will be bracketed between two moves (to place origin at center)
  95.  */
  96. static void move_mtrx ( mtrx, xtran, ytran, ioff, prior )
  97.      Transform *mtrx;
  98.      double xtran, ytran;
  99.      double ioff;
  100.      int prior;
  101. {
  102.   Transform translate;
  103.   static void mult_mtrx();
  104.  
  105.   bzero((char *)(&translate), sizeof(Transform));
  106.   translate.inx_outx = 1.0;
  107.   translate.iny_outy = 1.0;
  108.   translate.add_outx = (float)xtran;
  109.   translate.add_outy = (float)ytran;
  110.   if( prior ) {
  111.     translate.iadd_outx = (float)(xtran + ioff);
  112.     translate.iadd_outy = (float)(ytran + ioff);
  113.     mult_mtrx(mtrx, &translate, mtrx);
  114.   } else
  115.     mult_mtrx(mtrx, mtrx, &translate);
  116. }
  117.  
  118. /*
  119.  * Subroutine:    flip_mtrx
  120.  * Purpose:    Apply a mirror reflection to the passed Transform
  121.  */
  122. static void flip_mtrx ( mtrx, prior )
  123.      Transform *mtrx;
  124.      int prior;        /* i: 1: move, transform, move, 0: transform, move */
  125. {
  126.   Transform reflect;
  127.   static void mult_mtrx();
  128.  
  129.   bzero((char *)(&reflect), sizeof(Transform));
  130.   reflect.inx_outx = 1.0;
  131.   reflect.iny_outy = -1.0;
  132.   if( prior )
  133.     mult_mtrx(mtrx, &reflect, mtrx);
  134.   else
  135.     mult_mtrx(mtrx, mtrx, &reflect);
  136. }
  137.  
  138. /*
  139.  * Subroutine:    turn_mtrx
  140.  * Purpose:    Apply given angular rotation to the passed Transform
  141.  * Note:    the pivot is 0,0 of the passed Transform's coordinate system
  142.  * Exception:    only multiples of 90 degrees are allowed
  143.  */
  144. static void turn_mtrx ( mtrx, angle, prior )
  145.      Transform *mtrx;
  146.      int angle;
  147.      int prior;        /* i: 1: move, transform, move, 0: transform, move */
  148. {
  149.   Transform rotate;
  150.   void exit_errmsg();
  151.   static void mult_mtrx();
  152.  
  153.   while( angle >= 360 ) angle -= 360;
  154.   while( angle < 0 ) angle += 360;
  155.   bzero((char *)(&rotate), sizeof(Transform));
  156.   switch( angle ) {
  157.   case 0:
  158.     rotate.inx_outx = 1.0;
  159.     rotate.iny_outy = 1.0;
  160.     rotate.no_rot = 1;
  161.     break;
  162.   case 90:
  163.     rotate.inx_outy = 1.0;
  164.     rotate.iny_outx = -1.0;
  165.     rotate.no_rot = 0;
  166.     break;
  167.   case 180:
  168.     rotate.inx_outx = -1.0;
  169.     rotate.iny_outy = -1.0;
  170.     rotate.no_rot = 1;
  171.     break;
  172.   case 270:
  173.     rotate.inx_outy = -1.0;
  174.     rotate.iny_outx = 1.0;
  175.     rotate.no_rot = 0;
  176.     break;
  177.   default:
  178.     exit_errmsg("Non-orthogonal rotate (90,180,270)");
  179.     break;
  180.   }
  181.   if( prior )
  182.     mult_mtrx(mtrx, &rotate, mtrx);
  183.   else
  184.     mult_mtrx(mtrx, mtrx, &rotate);
  185. }
  186.  
  187. /*
  188.  * Subroutine:    mult_mtrx
  189.  * Purpose:    Multiply two sets of transformation matrices to produce a
  190.  *        new combined matrix
  191.  * Method:    algorithm is 3x3 matrix multiplication (3rd row is 0 0 1)
  192.  *        [i][j] is sum of products of column j of 1st and row i of 2nd
  193.  * Note:    iadd is computed to be able to transform from integer coords
  194.  *  calculation uses integer input offset of first and float offset of second
  195.  */
  196. static void mult_mtrx ( new, first, second )
  197.      Transform *new;    /* i/o: gets result, can be same as first or second */
  198.      Transform *first;    /* i: matrices in non-commutative multiply */
  199.      Transform *second; /* i: as above (new = 1st * 2nd) */
  200. {
  201.   Transform temp;
  202.  
  203.   temp.inx_outx = ((second->inx_outx * first->inx_outx) +
  204.           (second->iny_outx * first->inx_outy));
  205.   temp.iny_outx = ((second->inx_outx * first->iny_outx) +
  206.           (second->iny_outx * first->iny_outy));
  207.   temp.add_outx = ((second->inx_outx * first->add_outx) +
  208.           (second->iny_outx * first->add_outy) + second->add_outx);
  209.   temp.iadd_outx = ((second->inx_outx * first->iadd_outx) +
  210.            (second->iny_outx * first->iadd_outy) + second->add_outx);
  211.   temp.inx_outy = ((second->inx_outy * first->inx_outx) +
  212.            (second->iny_outy * first->inx_outy));
  213.   temp.iny_outy = ((second->inx_outy * first->iny_outx) +
  214.            (second->iny_outy * first->iny_outy));
  215.   temp.add_outy = ((second->inx_outy * first->add_outx) +
  216.            (second->iny_outy * first->add_outy) + second->add_outy);
  217.   temp.iadd_outy = ((second->inx_outy * first->iadd_outx) +
  218.             (second->iny_outy * first->iadd_outy) + second->add_outy);
  219.   bcopy((char *)&temp, (char *)new, sizeof(Transform));
  220. }
  221.