home *** CD-ROM | disk | FTP | other *** search
/ Fractal Creations (Second Edition) / FRACTALS_2E.iso / frasrc.exe / ZOOM.C < prev   
C/C++ Source or Header  |  1993-01-05  |  19KB  |  540 lines

  1. /*
  2.     zoom.c - routines for zoombox manipulation and for panning
  3.  
  4. */
  5.  
  6. #include <float.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "fractint.h"
  11. #include "prototyp.h"
  12.  
  13. /* screen dimensions here are (1.0,1.0) corresponding to (xdots-1,ydots-1) */
  14. extern double zbx,zby;           /* topleft of unrotated zoombox  */
  15. extern double zwidth,zdepth,zskew; /* zoombox size & shape        */
  16. extern int zrotate;           /* * 2.5 degree increments        */
  17. extern int boxcount,boxx[],boxy[]; /* co-ords of each zoombox pixel */
  18. extern int xdots,ydots,sxdots,sydots,sxoffs,syoffs;
  19. extern double dxsize,dysize;       /* xdots-1, ydots-1            */
  20. extern double xxmin,yymin,xxmax,yymax,xx3rd,yy3rd;
  21. extern double sxmin,symin,sxmax,symax,sx3rd,sy3rd;
  22. /* top      left    corner of screen is (xxmin,yymax) */
  23. /* bottom left    corner of screen is (xx3rd,yy3rd) */
  24. /* bottom right corner of screen is (xxmax,yymin) */
  25. extern double plotmx1,plotmx2,plotmy1,plotmy2;
  26.  
  27. extern int  calc_status;       /* status of calculations */
  28. extern int  fractype;           /* fractal type */
  29. extern char stdcalcmode;       /* '1', '2', 'g', 'b', or 't' */
  30. extern int  num_worklist;       /* resume worklist for standard engine */
  31. extern struct workliststuff worklist[MAXCALCWORK];
  32. extern char dstack[4096];       /* common temp, used for get_line/put_line */
  33. extern int  potflag;
  34. extern int  pot16bit;
  35. extern float finalaspectratio;
  36. extern float  screenaspect;
  37.  
  38. struct coords {
  39.     int x,y;
  40.     };
  41.  
  42. #define PIXELROUND 0.00001
  43.  
  44. static void _fastcall drawlines(struct coords, struct coords, int, int);
  45. static void _fastcall addbox(struct coords);
  46. static void _fastcall zmo_calc(double, double, double *, double *);
  47. static int  check_pan();
  48. static void fix_worklist();
  49. static void _fastcall move_row(int fromrow,int torow,int col);
  50.  
  51. void drawbox(int drawit)
  52. {   struct coords tl,bl,tr,br; /* dot addr of topleft, botleft, etc */
  53.     double tmpx,tmpy,dx,dy,rotcos,rotsin,ftemp1,ftemp2;
  54.     double fxwidth,fxskew,fydepth,fyskew,fxadj;
  55.  
  56.     if (zwidth==0) { /* no box to draw */
  57.     if (boxcount!=0) { /* remove the old box from display */
  58.         clearbox();   /* asm routine */
  59.         boxcount = 0; }
  60.     reset_zoom_corners();
  61.     return; }
  62.  
  63.     ftemp1 = PI*zrotate/72; /* convert to radians */
  64.     rotcos = cos(ftemp1);   /* sin & cos of rotation */
  65.     rotsin = sin(ftemp1);
  66.  
  67.     /* do some calcs just once here to reduce fp work a bit */
  68.     fxwidth = sxmax-sx3rd;
  69.     fxskew  = sx3rd-sxmin;
  70.     fydepth = sy3rd-symax;
  71.     fyskew  = symin-sy3rd;
  72.     fxadj   = zwidth*zskew;
  73.  
  74.     /* calc co-ords of topleft & botright corners of box */
  75.     tmpx = zwidth/-2+fxadj; /* from zoombox center as origin, on xdots scale */
  76.     tmpy = zdepth*finalaspectratio/2;
  77.     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx; /* delta x to rotate topleft */
  78.     dy = tmpy - (rotsin*tmpx + rotcos*tmpy); /* delta y to rotate topleft */
  79.     /* calc co-ords of topleft */
  80.     ftemp1 = zbx + dx + fxadj;
  81.     ftemp2 = zby + dy/finalaspectratio;
  82.     tl.x   = ftemp1*(dxsize+PIXELROUND); /* screen co-ords */
  83.     tl.y   = ftemp2*(dysize+PIXELROUND);
  84.     xxmin  = sxmin + ftemp1*fxwidth + ftemp2*fxskew; /* real co-ords */
  85.     yymax  = symax + ftemp2*fydepth + ftemp1*fyskew;
  86.     /* calc co-ords of bottom right */
  87.     ftemp1 = zbx + zwidth - dx - fxadj;
  88.     ftemp2 = zby - dy/finalaspectratio + zdepth;
  89.     br.x   = ftemp1*(dxsize+PIXELROUND);
  90.     br.y   = ftemp2*(dysize+PIXELROUND);
  91.     xxmax  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  92.     yymin  = symax + ftemp2*fydepth + ftemp1*fyskew;
  93.  
  94.     /* do the same for botleft & topright */
  95.     tmpx = zwidth/-2 - fxadj;
  96.     tmpy = 0.0-tmpy;
  97.     dx = (rotcos*tmpx - rotsin*tmpy) - tmpx;
  98.     dy = tmpy - (rotsin*tmpx + rotcos*tmpy);
  99.     ftemp1 = zbx + dx - fxadj;
  100.     ftemp2 = zby + dy/finalaspectratio + zdepth;
  101.     bl.x   = ftemp1*(dxsize+PIXELROUND);
  102.     bl.y   = ftemp2*(dysize+PIXELROUND);
  103.     xx3rd  = sxmin + ftemp1*fxwidth + ftemp2*fxskew;
  104.     yy3rd  = symax + ftemp2*fydepth + ftemp1*fyskew;
  105.     ftemp1 = zbx + zwidth - dx + fxadj;
  106.     ftemp2 = zby - dy/finalaspectratio;
  107.     tr.x   = ftemp1*(dxsize+PIXELROUND);
  108.     tr.y   = ftemp2*(dysize+PIXELROUND);
  109.  
  110.     if (boxcount!=0) { /* remove the old box from display */
  111.     clearbox();   /* asm routine */
  112.     boxcount = 0; }
  113.  
  114.     if (drawit) { /* caller wants box drawn as well as co-ords calc'd */
  115. #ifndef XFRACT
  116.     /* build the list of zoom box pixels */
  117.     addbox(tl); addbox(tr);           /* corner pixels */
  118.     addbox(bl); addbox(br);
  119.     drawlines(tl,tr,bl.x-tl.x,bl.y-tl.y); /* top & bottom lines */
  120.     drawlines(tl,bl,tr.x-tl.x,tr.y-tl.y); /* left & right lines */
  121. #else
  122.         boxx[0] = tl.x + sxoffs;
  123.         boxy[0] = tl.y + syoffs;
  124.         boxx[1] = tr.x + sxoffs;
  125.         boxy[1] = tr.y + syoffs;
  126.         boxx[2] = br.x + sxoffs;
  127.         boxy[2] = br.y + syoffs;
  128.         boxx[3] = bl.x + sxoffs;
  129.         boxy[3] = bl.y + syoffs;
  130.         boxcount = 1;
  131. #endif
  132.     dispbox();                  /* asm routine to paint it */
  133.     }
  134.     }
  135.  
  136. static void _fastcall drawlines(struct coords fr, struct coords to,
  137.                 int dx, int dy)
  138. {   int xincr,yincr,ctr;
  139.     int altctr,altdec,altinc;
  140.     struct coords tmpp,line1,line2;
  141.  
  142.     if (abs(to.x-fr.x) > abs(to.y-fr.y)) { /* delta.x > delta.y */
  143.     if (fr.x>to.x) { /* swap so from.x is < to.x */
  144.         tmpp = fr; fr = to; to = tmpp; }
  145.     xincr = (to.x-fr.x)*4/sxdots+1; /* do every 1st, 2nd, 3rd, or 4th dot */
  146.     ctr = (to.x-fr.x-1)/xincr;
  147.     altdec = abs(to.y-fr.y)*xincr;
  148.     altinc = to.x-fr.x;
  149.     altctr = altinc/2;
  150.     yincr = (to.y>fr.y)?1:-1;
  151.     line2.x = (line1.x = fr.x) + dx;
  152.     line2.y = (line1.y = fr.y) + dy;
  153.     while (--ctr>=0) {
  154.         line1.x += xincr;
  155.         line2.x += xincr;
  156.         altctr -= altdec;
  157.         while (altctr<0) {
  158.         altctr    += altinc;
  159.         line1.y += yincr;
  160.         line2.y += yincr;
  161.         }
  162.         addbox(line1);
  163.         addbox(line2);
  164.         }
  165.     }
  166.  
  167.     else { /* delta.y > delta.x */
  168.     if (fr.y>to.y) { /* swap so from.y is < to.y */
  169.         tmpp = fr; fr = to; to = tmpp; }
  170.     yincr = (to.y-fr.y)*4/sydots+1; /* do every 1st, 2nd, 3rd, or 4th dot */
  171.     ctr = (to.y-fr.y-1)/yincr;
  172.     altdec = abs(to.x-fr.x)*yincr;
  173.     altinc = to.y-fr.y;
  174.     altctr = altinc/2;
  175.     xincr = (to.x>fr.x) ? 1 : -1;
  176.     line2.x = (line1.x = fr.x) + dx;
  177.     line2.y = (line1.y = fr.y) + dy;
  178.     while (--ctr>=0) {
  179.         line1.y += yincr;
  180.         line2.y += yincr;
  181.         altctr  -= altdec;
  182.         while (altctr<0) {
  183.         altctr    += altinc;
  184.         line1.x += xincr;
  185.         line2.x += xincr;
  186.         }
  187.         addbox(line1);
  188.         addbox(line2);
  189.         }
  190.     }
  191.     }
  192.  
  193. static void _fastcall addbox(struct coords point)
  194. {
  195.     point.x += sxoffs;
  196.     point.y += syoffs;
  197.     if (point.x >= 0 && point.x < sxdots && point.y >= 0 && point.y < sydots) {
  198.     boxx[boxcount] = point.x;
  199.     boxy[boxcount] = point.y;
  200.     ++boxcount;
  201.     }
  202.     }
  203.  
  204. void moveboxf(double dx, double dy)
  205. {   int align,row,col;
  206.     align = check_pan();
  207.     if (dx!=0.0) {
  208.     if ((zbx += dx) + zwidth/2 < 0)  /* center must stay onscreen */
  209.         zbx = zwidth/-2;
  210.     if (zbx + zwidth/2 > 1)
  211.         zbx = 1.0 - zwidth/2;
  212.     if (align != 0
  213.       && ((col = zbx*(dxsize+PIXELROUND)) & (align-1)) != 0) {
  214.         if (dx > 0) col += align;
  215.         col -= col & (align-1); /* adjust col to pass alignment */
  216.         zbx = (double)col/dxsize; }
  217.     }
  218.     if (dy!=0.0) {
  219.     if ((zby += dy) + zdepth/2 < 0)
  220.         zby = zdepth/-2;
  221.     if (zby + zdepth/2 > 1)
  222.         zby = 1.0 - zdepth/2;
  223.     if (align != 0
  224.       && ((row = zby*(dysize+PIXELROUND)) & (align-1)) != 0) {
  225.         if (dy > 0) row += align;
  226.         row -= row & (align-1);
  227.         zby = (double)row/dysize; }
  228.     }
  229.     }
  230.  
  231. static void _fastcall chgboxf(double dwidth, double ddepth)
  232. {
  233.     if (zwidth+dwidth > 1)
  234.     dwidth = 1.0-zwidth;
  235.     if (zwidth+dwidth < 0.05)
  236.     dwidth = 0.05-zwidth;
  237.     zwidth += dwidth;
  238.     if (zdepth+ddepth > 1)
  239.     ddepth = 1.0-zdepth;
  240.     if (zdepth+ddepth < 0.05)
  241.     ddepth = 0.05-zdepth;
  242.     zdepth += ddepth;
  243.     moveboxf(dwidth/-2,ddepth/-2); /* keep it centered & check limits */
  244.     }
  245.  
  246. void resizebox(int steps)
  247. {
  248.     double deltax,deltay;
  249.     if (zdepth*screenaspect > zwidth) { /* box larger on y axis */
  250.     deltay = steps * 0.036 / screenaspect;
  251.     deltax = zwidth * deltay / zdepth;
  252.     }
  253.     else {                /* box larger on x axis */
  254.     deltax = steps * 0.036;
  255.     deltay = zdepth * deltax / zwidth;
  256.     }
  257.     chgboxf(deltax,deltay);
  258.     }
  259.  
  260. void chgboxi(int dw, int dd)
  261. {   /* change size by pixels */
  262.     chgboxf( (double)dw/dxsize, (double)dd/dysize );
  263.     }
  264.  
  265. #ifdef C6
  266. #pragma optimize("e",off)  /* MSC 6.00A messes up next rtn with "e" on */
  267. #endif
  268.  
  269. void zoomout() /* for ctl-enter, calc corners for zooming out */
  270. {   double savxxmin,savyymax,ftemp;
  271.     /* (xxmin,yymax), etc, are already set to zoombox corners;
  272.        (sxmin,symax), etc, are still the screen's corners;
  273.        use the same logic as plot_orbit stuff to first calculate current screen
  274.        corners relative to the zoombox, as if the zoombox were a square with
  275.        upper left (0,0) and width/depth 1; ie calc the current screen corners
  276.        as if plotting them from the zoombox;
  277.        then extend these co-ords from current real screen corners to get
  278.        new actual corners
  279.        */
  280.     ftemp = (yymin-yy3rd)*(xx3rd-xxmin) - (xxmax-xx3rd)*(yy3rd-yymax);
  281.     plotmx1 = (xx3rd-xxmin) / ftemp; /* reuse the plotxxx vars is safe */
  282.     plotmx2 = (yy3rd-yymax) / ftemp;
  283.     plotmy1 = (yymin-yy3rd) / ftemp;
  284.     plotmy2 = (xxmax-xx3rd) / ftemp;
  285.     savxxmin = xxmin; savyymax = yymax;
  286.     zmo_calc(sxmin-savxxmin,symax-savyymax,&xxmin,&yymax); /* new xxmin/xxmax */
  287.     zmo_calc(sxmax-savxxmin,symin-savyymax,&xxmax,&yymin);
  288.     zmo_calc(sx3rd-savxxmin,sy3rd-savyymax,&xx3rd,&yy3rd);
  289.     }
  290.  
  291. #ifdef C6
  292. #pragma optimize("e",on)  /* back to normal */
  293. #endif
  294.  
  295. static void _fastcall zmo_calc(double dx, double dy, double *newx, double *newy)
  296. {   double tempx,tempy;
  297.     /* calc cur screen corner relative to zoombox, when zoombox co-ords
  298.        are taken as (0,0) topleft thru (1,1) bottom right */
  299.     tempx = dy * plotmx1 - dx * plotmx2;
  300.     tempy = dx * plotmy1 - dy * plotmy2;
  301.     /* calc new corner by extending from current screen corners */
  302.     *newx = sxmin + tempx*(sxmax-sx3rd) + tempy*(sx3rd-sxmin);
  303.     *newy = symax + tempy*(sy3rd-symax) + tempx*(symin-sy3rd);
  304.     }
  305.  
  306. void aspectratio_crop(float oldaspect,float newaspect)
  307. {
  308.    double ftemp,xmargin,ymargin;
  309.    if (newaspect > oldaspect) { /* new ratio is taller, crop x */
  310.       ftemp = (1.0 - oldaspect / newaspect) / 2;
  311.       xmargin = (xxmax - xx3rd) * ftemp;
  312.       ymargin = (yymin - yy3rd) * ftemp;
  313.       xx3rd += xmargin;
  314.       yy3rd += ymargin;
  315.       }
  316.    else               { /* new ratio is wider, crop y */
  317.       ftemp = (1.0 - newaspect / oldaspect) / 2;
  318.       xmargin = (xx3rd - xxmin) * ftemp;
  319.       ymargin = (yy3rd - yymax) * ftemp;
  320.       xx3rd -= xmargin;
  321.       yy3rd -= ymargin;
  322.       }
  323.    xxmin += xmargin;
  324.    yymax += ymargin;
  325.    xxmax -= xmargin;
  326.    yymin -= ymargin;
  327. }
  328.  
  329. static int check_pan() /* return 0 if can't, alignment requirement if can */
  330. {   int i,j;
  331.     if (calc_status != 2 && calc_status != 4)
  332.     return(0); /* not resumable, not complete */
  333.     if ( curfractalspecific->calctype != StandardFractal
  334.       && curfractalspecific->calctype != calcmand
  335.       && curfractalspecific->calctype != calcmandfp
  336.       && curfractalspecific->calctype != lyapunov)
  337.     return(0); /* not a worklist-driven type */
  338.     if (zwidth != 1.0 || zdepth != 1.0 || zskew != 0.0 || zrotate != 0.0)
  339.     return(0); /* not a full size unrotated unskewed zoombox */
  340.     /* can pan if we get this far */
  341.     if (calc_status == 4)
  342.     return(1); /* image completed, align on any pixel */
  343.     if (potflag && pot16bit)
  344.     return(1); /* 1 pass forced so align on any pixel */
  345.     if (stdcalcmode == 'b')
  346.     return(1); /* btm, align on any pixel */
  347.     if (stdcalcmode == 't')
  348.     return(0); /* tesselate, can't do it */
  349.     if (stdcalcmode != 'g' || (curfractalspecific->flags&NOGUESS)) {
  350.     if (stdcalcmode == '2') /* align on even pixel for 2pass */
  351.        return(2);
  352.     return(1); /* assume 1pass */
  353.     }
  354.     /* solid guessing */
  355.     start_resume();
  356.     get_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  357.     /* don't do end_resume! we're just looking */
  358.     i = 9;
  359.     for (j=0; j<num_worklist; ++j) /* find lowest pass in any pending window */
  360.     if (worklist[j].pass < i)
  361.         i = worklist[j].pass;
  362.     j = ssg_blocksize(); /* worst-case alignment requirement */
  363.     while (--i >= 0)
  364.     j = j>>1; /* reduce requirement */
  365.     return(j);
  366.     }
  367.  
  368. static void _fastcall move_row(int fromrow,int torow,int col)
  369. /* move a row on the screen */
  370. {   int startcol,endcol,tocol;
  371.     memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */
  372.     if (fromrow >= 0 && fromrow < ydots) {
  373.     tocol = startcol = 0;
  374.     endcol = xdots-1;
  375.     if (col < 0) {
  376.         tocol -= col;
  377.         endcol += col; }
  378.     if (col > 0)
  379.         startcol += col;
  380.     get_line(fromrow,startcol,endcol,(BYTE *)&dstack[tocol]);
  381.     }
  382.     put_line(torow,0,xdots-1,(BYTE *)dstack);
  383.     }
  384.  
  385. int init_pan_or_recalc(int do_zoomout) /* decide to recalc, or to chg worklist & pan */
  386. {   int i,j,row,col,y,alignmask,listfull;
  387.     if (zwidth == 0.0)
  388.     return(0); /* no zoombox, leave calc_status as is */
  389.     /* got a zoombox */
  390.     if ((alignmask=check_pan()-1) < 0) {
  391.     calc_status = 0; /* can't pan, trigger recalc */
  392.     return(0); }
  393.     if (zbx == 0.0 && zby == 0.0) {
  394.     clearbox();
  395.     return(0); } /* box is full screen, leave calc_status as is */
  396.     col = zbx*(dxsize+PIXELROUND); /* calc dest col,row of topleft pixel */
  397.     row = zby*(dysize+PIXELROUND);
  398.     if (do_zoomout) { /* invert row and col */
  399.     row = 0-row;
  400.     col = 0-col; }
  401.     if ((row&alignmask) != 0 || (col&alignmask) != 0) {
  402.     calc_status = 0; /* not on useable pixel alignment, trigger recalc */
  403.     return(0); }
  404.     /* pan */
  405.     num_worklist = 0;
  406.     if (calc_status == 2) {
  407.        start_resume();
  408.        get_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  409.        } /* don't do end_resume! we might still change our mind */
  410.     /* adjust existing worklist entries */
  411.     for (i=0; i<num_worklist; ++i) {
  412.     worklist[i].yystart -= row;
  413.     worklist[i].yystop  -= row;
  414.     worklist[i].yybegin -= row;
  415.     worklist[i].xxstart -= col;
  416.     worklist[i].xxstop  -= col;
  417.     }
  418.     /* add worklist entries for the new edges */
  419.     listfull = i = 0;
  420.     j = ydots-1;
  421.     if (row < 0) {
  422.     listfull |= add_worklist(0,xdots-1,0,0-row-1,0,0,0);
  423.     i = 0 - row; }
  424.     if (row > 0) {
  425.     listfull |= add_worklist(0,xdots-1,ydots-row,ydots-1,ydots-row,0,0);
  426.     j = ydots - row - 1; }
  427.     if (col < 0)
  428.     listfull |= add_worklist(0,0-col-1,i,j,i,0,0);
  429.     if (col > 0)
  430.     listfull |= add_worklist(xdots-col,xdots-1,i,j,i,0,0);
  431.     if (listfull != 0) {
  432.     static char far msg[] = {"\
  433. Tables full, can't pan current image.\n\
  434. Cancel resumes old image, continue pans and calculates a new one."};
  435.     if (stopmsg(2,msg)) {
  436.         zwidth = 0; /* cancel the zoombox */
  437.         drawbox(1); }
  438.     else
  439.         calc_status = 0; /* trigger recalc */
  440.     return(0); }
  441.     /* now we're committed */
  442.     calc_status = 2;
  443.     clearbox();
  444.     if (row > 0) /* move image up */
  445.     for (y=0; y<ydots; ++y) move_row(y+row,y,col);
  446.     else     /* move image down */
  447.     for (y=ydots; --y>=0;)    move_row(y+row,y,col);
  448.     fix_worklist(); /* fixup any out of bounds worklist entries */
  449.     alloc_resume(sizeof(worklist)+10,1); /* post the new worklist */
  450.     put_resume(sizeof(int),&num_worklist,sizeof(worklist),worklist,0);
  451.     return(0);
  452.     }
  453.  
  454. static void _fastcall restart_window(int wknum)
  455. /* force a worklist entry to restart */
  456. {   int yfrom,yto,xfrom,xto;
  457.     if ((yfrom = worklist[wknum].yystart) < 0) yfrom = 0;
  458.     if ((xfrom = worklist[wknum].xxstart) < 0) xfrom = 0;
  459.     if ((yto = worklist[wknum].yystop) >= ydots) yto = ydots - 1;
  460.     if ((xto = worklist[wknum].xxstop) >= xdots) xto = xdots - 1;
  461.     memset(dstack,0,xdots); /* use dstack as a temp for the row; clear it */
  462.     while (yfrom <= yto)
  463.     put_line(yfrom++,xfrom,xto,(BYTE *)dstack);
  464.     worklist[wknum].sym = worklist[wknum].pass = 0;
  465.     worklist[wknum].yybegin = worklist[wknum].yystart;
  466. }
  467.  
  468. static void fix_worklist() /* fix out of bounds and symmetry related stuff */
  469. {   int i,j,k;
  470.     struct workliststuff *wk;
  471.     for (i=0; i<num_worklist; ++i) {
  472.     wk = &worklist[i];
  473.     if ( wk->yystart >= ydots || wk->yystop < 0
  474.       || wk->xxstart >= xdots || wk->xxstop < 0) { /* offscreen, delete */
  475.         for (j=i+1; j<num_worklist; ++j)
  476.         worklist[j-1] = worklist[j];
  477.         --num_worklist;
  478.         --i;
  479.         continue; }
  480.     if (wk->yystart < 0) /* partly off top edge */
  481.         if ((wk->sym&1) == 0) /* no sym, easy */
  482.         wk->yystart = 0;
  483.         else { /* xaxis symmetry */
  484.         if ((j = wk->yystop + wk->yystart) > 0
  485.           && num_worklist < MAXCALCWORK) { /* split the sym part */
  486.             worklist[num_worklist] = worklist[i];
  487.             worklist[num_worklist].yystart = 0;
  488.             worklist[num_worklist++].yystop = j;
  489.             wk->yystart = j+1; }
  490.         else
  491.             wk->yystart = 0;
  492.         restart_window(i); /* restart the no-longer sym part */
  493.         }
  494.     if (wk->yystop >= ydots) { /* partly off bottom edge */
  495.        j = ydots-1;
  496.        if ((wk->sym&1) != 0) { /* uses xaxis symmetry */
  497.           if ((k = wk->yystart + (wk->yystop - j)) < j)
  498.          if (num_worklist >= MAXCALCWORK) /* no room to split */
  499.             restart_window(i);
  500.          else { /* split it */
  501.             worklist[num_worklist] = worklist[i];
  502.             worklist[num_worklist].yystart = k;
  503.             worklist[num_worklist++].yystop = j;
  504.             j = k-1; }
  505.           wk->sym &= -1 - 1; }
  506.        wk->yystop = j; }
  507.     if (wk->xxstart < 0) /* partly off left edge */
  508.         if ((wk->sym&2) == 0) /* no sym, easy */
  509.         wk->xxstart = 0;
  510.         else { /* yaxis symmetry */
  511.         if ((j = wk->xxstop + wk->xxstart) > 0
  512.           && num_worklist < MAXCALCWORK) { /* split the sym part */
  513.             worklist[num_worklist] = worklist[i];
  514.             worklist[num_worklist].xxstart = 0;
  515.             worklist[num_worklist++].xxstop = j;
  516.             wk->xxstart = j+1; }
  517.         else
  518.             wk->xxstart = 0;
  519.         restart_window(i); /* restart the no-longer sym part */
  520.         }
  521.     if (wk->xxstop >= xdots) { /* partly off right edge */
  522.        j = xdots-1;
  523.        if ((wk->sym&2) != 0) { /* uses xaxis symmetry */
  524.           if ((k = wk->xxstart + (wk->xxstop - j)) < j)
  525.          if (num_worklist >= MAXCALCWORK) /* no room to split */
  526.             restart_window(i);
  527.          else { /* split it */
  528.             worklist[num_worklist] = worklist[i];
  529.             worklist[num_worklist].xxstart = k;
  530.             worklist[num_worklist++].xxstop = j;
  531.             j = k-1; }
  532.           wk->sym &= -1 - 2; }
  533.        wk->xxstop = j; }
  534.     if (wk->yybegin < wk->yystart) wk->yybegin = wk->yystart;
  535.     if (wk->yybegin > wk->yystop)  wk->yybegin = wk->yystop;
  536.     }
  537.     tidy_worklist(); /* combine where possible, re-sort */
  538. }
  539.  
  540.