home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / crdtemp.c < prev    next >
C/C++ Source or Header  |  1991-06-21  |  9KB  |  283 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    crdtemp.c (Coordinate Temporary)
  6.  * Purpose:    Calculate display coordinates for pan and zoom
  7.  * Subroutine:    set_tdisp()            returns: void
  8.  * Subroutine:    reset_tdisp()            returns: void
  9.  * Subroutine:    set_disptran()            returns: void
  10.  * Subroutine:    panedge_zoom()            returns: void
  11.  * Subroutine:    set_dispoff()            returns: void
  12.  * Xlib calls:    none
  13.  * Copyright:    1988 Smithsonian Astrophysical Observatory
  14.  *        You may do anything you like with this file except remove
  15.  *        this copyright.  The Smithsonian Astrophysical Observatory
  16.  *        makes no representations about the suitability of this
  17.  *        software for any purpose.  It is provided "as is" without
  18.  *        express or implied warranty.
  19.  * Modified:    {0} Michael VanHilst    initial version         1 September 1988
  20.  *        {1} MVH Kludged set_dispoff to trap overrrun    28 April 1990
  21.  *        {n} <who> -- <does what> -- <when>
  22.  */
  23.  
  24. #include <stdio.h>        /* stderr, NULL, etc */
  25. #include "hfiles/coord.h"    /* coord structs */
  26.  
  27. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  28.  
  29. /*
  30.  * Subroutine:    set_tdisp
  31.  * Purpose:    set needed parameters for proposed display
  32.  * PreState:    tid.cenX, tid.cenY, tid.zoom, and tid.block must be set
  33.  */
  34. void set_tdisp ( coord )
  35.      struct coordRec *coord;
  36. {
  37.   /* calculate corners of display in img coords */
  38.   /* 0.5 accounts for rounding to nearest pixel, 0.499 rounding at limit */
  39.   coord->tid.srcX1 = (int)
  40.     (coord->tid.cenX - ((coord->disp.cenX - 0.5) / coord->tid.zoom));
  41.   coord->tid.srcX2 = (int)
  42.     (coord->tid.cenX +
  43.      ((0.499 + (float)coord->disp.width - coord->disp.cenX) /
  44.       coord->tid.zoom));
  45.   coord->tid.srcY1 = (int)
  46.     (coord->tid.cenY - ((coord->disp.cenY - 0.5) / coord->tid.zoom));
  47.   coord->tid.srcY2 = (int)
  48.     (coord->tid.cenY +
  49.      ((0.499 + (float)coord->disp.height - coord->disp.cenY) /
  50.       coord->tid.zoom));
  51.   /* limit display area to img area */
  52.   coord->tid.clip = 0;
  53.   if( coord->tid.srcX1 < coord->img.X1i ) {
  54.     coord->tid.srcX1 = coord->img.X1i;
  55.     coord->tid.clip += LX;
  56.   }
  57.   if( coord->tid.srcX2 > coord->img.X2i ) {
  58.     coord->tid.srcX2 = coord->img.X2i;
  59.     coord->tid.clip += RX;
  60.   }
  61.   if( coord->tid.srcY1 < coord->img.Y1i ) {
  62.     coord->tid.srcY1 = coord->img.Y1i;
  63.     coord->tid.clip += TY;
  64.   }
  65.   if( coord->tid.srcY2 > coord->img.Y2i ) {
  66.     coord->tid.srcY2 = coord->img.Y2i;
  67.     coord->tid.clip += BY;
  68.   }
  69.   /* check display parameters against buf contents */
  70.   if( coord->bufcheck ) {
  71.     /* request outside coverage of buffer contents */
  72.     if( (coord->tid.srcX1 < coord->ib.srcX1) ||
  73.         (coord->tid.srcX2 > coord->ib.srcX2) ||
  74.     (coord->tid.srcY1 < coord->ib.srcY1) ||
  75.         (coord->tid.srcY2 > coord->ib.srcY2) )
  76.       coord->buferror = 1;
  77.     else if( coord->ib.block != 1 ) {
  78.       if( coord->tid.block < coord->ib.block )
  79.     /* request for finer resolution than currently in buffer */
  80.     coord->buferror = 1;
  81.       else if( ((int)coord->tid.block % coord->ib.block) != 0 )
  82.     /* request for incompatible blocking */
  83.     coord->buferror = 1;
  84.       else
  85.     coord->buferror = 0;
  86.     } else
  87.       coord->buferror = 0;
  88.   }
  89. }
  90.  
  91. /*
  92.  * Subroutine:    reset_tdisp
  93.  * Purpose:    Reset temp disp proposal to the current disp params
  94.  */
  95. void reset_tdisp ( coord )
  96.      struct coordRec *coord;
  97. {
  98.   bcopy((char *)&coord->id, (char *)&coord->tid, sizeof(Edges));
  99.   coord->buferror = 0;
  100. }
  101.  
  102. /*
  103.  * Subroutine:    set_disptran
  104.  * Purpose:    Set display parameters and translations as per temp
  105.  */
  106. void set_disptran ( coord )
  107.      struct coordRec *coord;
  108. {
  109.   void set_transform(), combine_transform(), invert_transform();
  110.  
  111.   bcopy((char *)&coord->tid, (char *)&coord->id, sizeof(Edges));
  112.   /* compute coordinate conversions between pan and img systems */
  113.   set_transform(coord->id.cenX, coord->id.cenY, coord->id.zoom,
  114.         &coord->disp, &coord->img,
  115.         &coord->disptoimg, &coord->imgtodisp);
  116.   /* compute transform from display to file and the reverse */
  117.   combine_transform(&coord->disptofile,
  118.             &coord->disptoimg, &coord->imgtofile);
  119.   invert_transform(&coord->filetodisp, &coord->disptofile,
  120.            (double)coord->file.ioff);
  121. }
  122.  
  123. /*
  124.  * Subroutine:    panedge_zoom
  125.  * Purpose:    set up zoom given edges of desired display and
  126.  *        appropriate img transform
  127.  */
  128. void panedge_zoom ( coord, wintoimgtrans, win_x, win_y )
  129.      struct coordRec *coord;    /* i: collected coords */
  130.      Transform *wintoimgtrans;    /* i: transform from mouse's window to img */
  131.      int win_x, win_y;        /* i: window coords of mouse event */
  132. {
  133.   float imgX, imgY;
  134.   int box_width, box_height;
  135.   void i_transform();
  136.   static int choose_zoom();
  137.  
  138.   /* calculate image coordinates of win_x and win_y */
  139.   i_transform(wintoimgtrans, win_x, win_y, &imgX, &imgY);
  140.   /* select zoom based on this box */
  141.   box_width = abs((int)coord->tid.cenX - (int)imgX) * 2 + 1;
  142.   box_height = abs((int)coord->tid.cenY - (int)imgY) * 2 + 1;
  143.   coord->tid.block = choose_zoom(coord->disp.width, coord->disp.height,
  144.                  box_width, box_height);
  145.   /* check against already generous limits and set float zoom factor */
  146.   if( coord->tid.block > 0 ) {
  147.     if( coord->tid.block > 400 )
  148.       coord->tid.block = 400;
  149.     coord->tid.zoom = 1.0 / (double)coord->tid.block;
  150.   } else {
  151.     if( coord->tid.block < -100 )
  152.       coord->tid.block = -100;
  153.     coord->tid.zoom = -(double)coord->tid.block;
  154.   }
  155. }
  156.  
  157. /*
  158.  * Subroutine:    choose_zoom
  159.  * Purpose:    Select the zoom to best fit indicated image subsection to
  160.  *        display window
  161.  * Method:    Choose a zoom which comes closest to putting the ref point
  162.  *        on an edge while still enclosing it
  163.  * Returns:    Source-to-dest integer blocking code
  164.  */
  165.  static int choose_zoom ( dst_width, dst_height, src_width, src_height )
  166.      int dst_width;    /* width of window */
  167.      int dst_height;    /* height of window */
  168.      int src_width;    /* width of image section */
  169.      int src_height;    /* height of image section */
  170. {
  171.   int i;
  172.  
  173.   /* limit width and height just in case */
  174.   src_width = MAX(1, src_width);
  175.   src_height = MAX(1, src_height);
  176. #ifdef DEBUG
  177.   if( (dst_width <= 0) || (dst_height <= 0) ) {
  178.     (void)fprintf(stderr, "WARNING: no window size for choose_zoom\n");
  179.     return(1.0);
  180.   }
  181. #endif
  182.   /* will we zoom up or down */
  183.   /* if source image section has more pixels than destination, block */
  184.   if( (src_width > dst_width) || (src_height > dst_height) ) {
  185.     /* point is outside zoom-1 frame, enlarge source until we include it */
  186.     for( i = 1;
  187.     (((dst_width * i) <= src_width) || ((dst_height * i) <= src_height));
  188.     i++ );
  189.     return( i );
  190.   } else {
  191.     /* point is inside zoom-one frame */
  192.     /* try shrinking source until we no-longer include it, then back-up one */
  193.     /* (count until we reach a point where one error changes sign) */
  194.     for( i = 1;
  195.     (((src_width * i) <= dst_width) &&
  196.      ((src_height * i) <= dst_height));
  197.     i++ );
  198.     if( --i == 1 ) return(1);
  199.     else return( -i );
  200.   }
  201. }
  202.  
  203. /*
  204.  * Subroutine:    set_dispoff
  205.  * Purpose:    Set the special window (dest) coords for mapping a display
  206.  * Note:    Round pixel index in if on an edge between pixels
  207.  * Note:    A is src (buf), B is dst (disp)
  208.  */
  209. void set_dispoff ( BAtrans, Bsys, AB )
  210.      Transform *BAtrans;
  211.      Coordsys *Bsys;
  212.      Edges *AB;
  213. {
  214.   float x, y;
  215.   int BAblock;
  216.  
  217.   /*  Compute simple coords for simplified display routines  */
  218.   x = -BAtrans->add_outx / BAtrans->inx_outx;
  219.   if( x < 0 )
  220.     AB->dst_x = (int)(x - 0.5);
  221.   else
  222.     AB->dst_x = (int)(x + 0.5);
  223.   y = -BAtrans->add_outy / BAtrans->iny_outy;
  224.   if( y < 0 )
  225.     AB->dst_y = (int)(y - 0.5);
  226.   else
  227.     AB->dst_y = (int)(y + 0.5);
  228.   d_transform(BAtrans, 0.0, 0.0, &x, &y);
  229.   if( x < 0 )
  230.     AB->src_x = (int)(x - 0.5);
  231.   else
  232.     AB->src_x = (int)(x + 0.5);
  233.   if( x < 0 )
  234.     AB->src_y = (int)(y - 0.5);
  235.   else
  236.     AB->src_y = (int)(y + 0.5);
  237.   /*  Compute [not completely correctly] paramaters for old display code  */
  238.   BAblock = -AB->block;
  239.   /* do coords for top-left corner */
  240.   if( (BAblock > 0) || ((AB->clip & LXTY) != 0) ) {
  241.     /* calculate upperleft edge backwards through transform */
  242.     x = ((float)AB->srcX1 - BAtrans->add_outx) / BAtrans->inx_outx;
  243.     y = ((float)AB->srcY1 - BAtrans->add_outy) / BAtrans->iny_outy;
  244.     AB->dstX1 = (int)(x + 0.001);
  245.     AB->dstY1 = (int)(y + 0.001);
  246.     if( AB->dstX1 < Bsys->X1i )
  247.       AB->dstX1 = Bsys->X1i;
  248.     if( AB->dstY1 < Bsys->Y1i )
  249.       AB->dstY1 = Bsys->Y1i;
  250.   } else {
  251.     /* block 1 or less */
  252.     AB->dstX1 = Bsys->X1;
  253.     AB->dstY1 = Bsys->Y1;
  254.   }
  255.   if( (BAblock > 0) || ((AB->clip & RXBY) != 0) ) {
  256.     /* calculate lowerright edge backwards through transform */
  257.     x = ((float)(AB->srcX2 + 1) - BAtrans->add_outx) / BAtrans->inx_outx;
  258.     y = ((float)(AB->srcY2 + 1) - BAtrans->add_outy) / BAtrans->iny_outy;
  259.     AB->dstX2 = (int)(x - 0.001);
  260.     AB->dstY2 = (int)(y - 0.001);
  261.     if( AB->dstX2 > Bsys->X2i )
  262.       AB->dstX2 = Bsys->X2i;
  263.     if( AB->dstY2 > Bsys->Y2i )
  264.       AB->dstY2 = Bsys->Y2i;
  265.   } else {
  266.     AB->dstX2 = Bsys->X2;
  267.     AB->dstY2 = Bsys->Y2;
  268.   }
  269.   AB->dstXwdth = 1 + AB->dstX2 - AB->dstX1;
  270.   AB->dstYhght = 1 + AB->dstY2 - AB->dstY1;
  271.   /* kludge trap to prevent algorithm from overshooting image buffer */
  272.   if( (BAtrans->inx_outx >= 1.0) &&
  273.       ((AB->dstXwdth * BAtrans->inx_outx) > AB->srcXwdth) ) {
  274.     AB->dstX2--;
  275.     AB->dstXwdth--;
  276.   }
  277.   if( (BAtrans->iny_outy >= 1.0) &&
  278.       ((AB->dstYhght * BAtrans->iny_outy) > AB->srcYhght) ) {
  279.     AB->dstY2--;
  280.     AB->dstYhght--;
  281.   }
  282. }
  283.