Sindbad~EG File Manager

Current Path : /home/beeson/cgraph/
Upload File :
Current File : //home/beeson/cgraph/snap.c

/*
M. Beeson, for Mathpert.  Code to make the crosshairs snap to a
nearby extremum, zero crossing, or crossing with another graph on
the same axes.

8.27.98 original date
9.18.98 last modified
7.23.24  modified to use ->newaxes instead of ->whichgraph
*/

#include <assert.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>   /* gcvt, alloca */
#include "globals.h"
#include "graphstr.h"
#include "grapher.h"
#include "cgraph.h"
#include "ratsimp.h"
#include "mpdoc.h"
#include "snap.h"
#include "deval.h"

/*____________________________________________________________*/
#define SNAP_N 3
int snap(PDOCDATA pDocData)
/* if p = (g->selectedx, g->selectedy) is within three pixels of
an extremum of the function (for ordinary graphs) then adjust
it to be right on the extremum.  Similarly for zero crossings and
y-intercepts (where g->selectedx is near zero).
If g is one of several graphs on the same axes, then use
pDocData  to access the other graphs, and if p is within three
pixels of a crossing point of two graphs, adjust it to be
right on the crossing point.
   So we are looking for zeroes of g->function, or zeros of
g->fprime, with respect to g->independent_variable, in case
g->graphtype is ORDINARY.  g->whichgraph tells us if there are
lower-numbered graphs on the same axes; g->crosshairsflag tells
us which window owns the crosshairs.
   Return 0 if the crosshairs will be relocated, 1 if not.
*/

{ int i,j,jj,k,min,max,err,k2;
  term t, deriv,x;
  double p,savex,delta,xpixel,test,dtest,oldtest,doldtest,temp,dcross;
  double crosstest[MAXGRAPHS];
  graph **graphs = pDocData->graphs;
  for(i=0;i<pDocData->ngraphs;i++)
     { if(graphs[i]->crosshairsflag)
          break;
     }
  if(i == pDocData->ngraphs)
     return 1;
  if(graphs[i]->graphtype != ORDINARY)
     return 1;
  j = i;
  while(j >= 0 && graphs[j]->newaxes == 0)
    --j;
  min = j;
  j = i+1;
  if(j >= pDocData->ngraphs)
     max = i;
  else
     { while(j < pDocData->ngraphs && graphs[j]->newaxes == 0)
          ++j;
       max = j == min? min : j-1;
     }
  /* graphs[min]... graphs[max] are the ones to examine
     for crossings with graphs[i] */

  x = graphs[i]->independent_variable;
  t = graphs[i]->function;
  deriv = graphs[i]->fprime;
  p = graphs[i]->selectedx;
  xpixel = (graphs[i]->xmax - graphs[i]->xmin)/
          (graphs[i]->pxmax - graphs[i]->pxmin);
  /* now xpixel is the measure of one pixel in world coordinates */
  savex = VALUE(x);
  SETVALUE(x,p);

  /* First check if there are singularities in the vicinity. In
  that case don't do any snapping. */

  delta = SNAP_N *xpixel;
  if(graphs[i]->nsingularities)
     { for(j=0;j<graphs[i]->nsingularities;j++)
          { if(fabs(graphs[i]->singularities[j]-p) < delta)
               return 1;
          }
     }

  /* Now look for zero-crossings, maxima, y-intercepts,
     or crossings with other graphs.
     We must snap to the NEAREST such point so we must search for all
     four simultaneously and in both directions from g->selectedx at once.
  */
  if(graphs[i]->selectedx == 0.0)
     return 1;  /* already on a y-intercept */
  SETVALUE(x,graphs[i]->selectedx);
  deval(t,&oldtest);
  if(oldtest == 0.0 || oldtest == BADVAL)
     { SETVALUE(x,savex);
       return 1;
     }
  deval(deriv,&doldtest);
  if(doldtest == 0.0 || doldtest == BADVAL)
     { SETVALUE(x,savex);
       return 1;
     }
  for(k=min;k<=max;k++)
     deval(graphs[k]->function,&crosstest[k]);
  for(jj=1; jj<=2*SNAP_N;jj++)
     { j = (jj & 1) ? 1 + jj/2 : -jj/2;  /* 1,-1,2,-2,3,-3,... */
       SETVALUE(x,p+j*xpixel);
       deval(t,&test);
       if(test == BADVAL)
          { SETVALUE(x,savex);
            return 1;
          }
       if(test == 0.0)
          { graphs[i]->selectedx = p+j*xpixel;
            SETVALUE(x,savex);
            return 1;
          }
       if(fabs(p + j*xpixel) <= xpixel)
          { /* close to a y-intercept */
            SETVALUE(x,0.0);
            deval(t,&test);
            if(test != BADVAL)
               { graphs[i]->selectedx = 0.0;
                 graphs[i]->selectedy = test;  /* snap to the y-intercept */
                 return 0;
               }
            SETVALUE(x,p+j*xpixel);
          }
       if(oldtest < 0.0 && test > 0.0)
          goto gotzero;
       if(test < 0.0 && oldtest > 0.0)
          goto gotzero;
       deval(deriv,&dtest);
       if(dtest == BADVAL || dtest == 0.0)
          /* it's BADVAL e.g. at the minimum of abs(x) */
          { SETVALUE(x,savex);
            graphs[i]->selectedx = p + j*xpixel;
            return 1;
          }
       if(doldtest < 0.0 && dtest > 0.0)
          goto gotextremum;
       if(dtest < 0.0 && doldtest > 0.0)
          goto gotextremum;
       if(min == max)
          continue;  /* one graph only, no need to check for crossings */
       /* Now check for a crossing with another graph */
       for(k = min;k <= max; k++)
          { if(k==i)
               continue;  /* checking for a crossing of graph i with some other graph */
            if(crosstest[k] == BADVAL)
               continue;
            deval(graphs[k]->function,&dcross);
            if(dcross == BADVAL)
               continue;
            if(test == dcross)
               { SETVALUE(x,savex);
                 for(k2 = min; k2 <= max; k2++)
                    { graphs[k2]->selectedy = test;
                      graphs[k2]->selectedx = p + j*xpixel;
                    }
                 return 1;
               }
            if(dcross-test < 0.0 && crosstest[k]-oldtest > 0.0)
               goto gotcrossing;
            if(dcross-test > 0.0 && crosstest[k]-oldtest < 0.0)
               goto gotcrossing;
          }
     }
  SETVALUE(x,savex);
  return 1;  /* found nothing */
  gotzero:
     err = solve(t,x,p+j*xpixel,p,&temp);
     if(!err)
        { graphs[i]->selectedx = temp;
          graphs[i]->selectedy = 0.0;
          return 0;
        }
     SETVALUE(x,savex);
     return 1;
  gotextremum:
     err = solve(deriv,x,p+j*xpixel,p,&temp);
     if(!err)
        { graphs[i]->selectedx = temp;
          SETVALUE(x,temp);
          deval(t,&temp);
          if(temp != BADVAL)
             graphs[i]->selectedy = temp;
          return 0;
        }
     SETVALUE(x,savex);
     return 1;
  gotcrossing:
     err = solve(sum(t,tnegate(graphs[k]->function)),x,p+j*xpixel,p,&temp);
     if(!err)
        { graphs[i]->selectedx = temp;
          SETVALUE(x,temp);
          deval(t,&temp);
          if(temp != BADVAL)
             graphs[i]->selectedy = temp;
        
          for(k2 = min;k2<=max;k2++)
             { if(k2 == i)
                 continue;
               graphs[k2]->selectedx = graphs[i]->selectedx;
               graphs[k2]->selectedy = graphs[i]->selectedy;
             }
         return 0;
        }
     SETVALUE(x,savex);
     return 1;
}


Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists