Sindbad~EG File Manager
/* M. Beeson, for Mathpert.
Implement the Spot for parametric graphs
*/
/* Original date 8.10.95
last modified 1.29.98
2.24.24 removed windows.h etc.
2.25.24 removed get_aspect() call
2.28.24 modified place_spot to use double coordinates
7.22.24 commented out some lines so it can compile with WebMathXpert
even though it isn't yet used.
*/
#include <assert.h>
#include <math.h> /* fabs */
#include "globals.h"
#include "graphstr.h"
#include "deval.h"
#include "svgGraph.h"
#define ROUNDOFF(x) (int)((x)+0.5)
/*___________________________________________________________________*/
static void place_spot(graph *g, double x, double y)
/* draw the "spot" at(x,y), and record the upper left coordinates
for the spot in g->root_xcoords[0] and g->root_ycoords[0].
Here j starts from 1, not 0.
*/
{
static double aspect = 1.0;
int hradius,vradius;
// int k,hdistance,vdistance;
svgDevice *device = get_device();
double radius;
double *pleft = g->root_xcoords;
double *ptop = g->root_ycoords;
/* space to record where the roots are written by putimage */
hradius = (int) g->linewidth * 3;
vradius = ROUNDOFF( hradius * device->numypixels/(device->numxpixels * aspect));
/* vertical radius of filled circle in device coordinates */
radius = device -> xpixel * hradius; /* world coord horiz radius */
filled_circle(x,y,radius);
world_to_pixel(x,y,pleft,ptop);
}
/*______________________________________________________________*/
void draw_spot(graph *g)
/* It is assumed that g is a parametric graph or a space curve.
Draw the Spot at location given by g->tselected.
*/
{ double t = g->tselected;
double x,y,z;
int mainchoice = g->graphtype;
assert(mainchoice == PARAMETRIC || mainchoice == SPACECURVE);
/* Compute the coordinate values for the Spot */
SETVALUE(g->independent_variable,t);
deval(g->xfunction,&x);
if(x == BADVAL || x < g->xmin || x > g->xmax)
return;
deval(g->yfunction,&y);
if(y == BADVAL || y < g->ymin || y > g->ymax)
return;
if(mainchoice == SPACECURVE)
{ deval(g->zfunction,&z);
if(z == BADVAL || z < g->zmin || z > g->zmax)
return;
return; /* FINISH THIS: convert x,y,z to pixel coords and
draw the bitmap */
}
if(mainchoice == PARAMETRIC)
{ place_spot(g,x,y);
}
}
/*______________________________________________________________*/
void erase_spot(graph *g)
/* It is assumed that g is a parametric graph or a space curve.
Erase the Spot at location given by g->tselected by filling
the Spot's rectangle with the color given by g->background,
and then redrawing a portion of the graph line near g->tselected.
*/
{ double t = g->tselected;
double x,y,z,u,v,tgap,lo,hi;
double *tp;
svgDevice *device;
int stoploop, count;
term xf, yf;
static int pwidth, pheight;
double dwidth, dheight;
int mainchoice = g->graphtype;
assert(mainchoice == PARAMETRIC || mainchoice == SPACECURVE);
/* Compute the coordinate values for the Spot */
SETVALUE(g->independent_variable,t);
deval(g->xfunction,&x);
if(x == BADVAL || x < g->xmin || x > g->xmax)
return;
deval(g->yfunction,&y);
if(y == BADVAL || y < g->ymin || y > g->ymax)
return;
// if(pwidth == 0)
// get_image_size(g->spot,&pwidth,&pheight);
if(mainchoice == SPACECURVE)
{ deval(g->zfunction,&z);
if(z == BADVAL || z < g->zmin || z > g->zmax)
return;
return; /* FINISH THIS: convert x,y,z to pixel coords and
proceed */
}
if(mainchoice == PARAMETRIC)
{ device = get_device();
dwidth = device->xpixel * pwidth;
dheight = device->ypixel * pheight;
set_graphbackgroundcolor(g->background);
filled_rect(x-dwidth/2,y-dheight/2,x+dwidth/2, y+dheight/2);
/* 'black out' the old spot with background color */
set_graphpencolor(g->graphcolor);
/* If the rectangle covers part of the axes, we must repaint
the axes over that part. */
if(x-dwidth <= 0.0 && x+dwidth >= 0.0)
{ /* repaint part of the y-axis */
set_linewidth(THIN);
set_graphpencolor(g->axescolor);
move_to(0.0, y-dheight);
line_to(0.0, y+dheight);
set_graphpencolor(g->graphcolor);
set_linewidth(THICK);
}
if(y-dheight <= 0.0 && y+dheight >= 0.0)
{ /* repaint part of the x-axis */
set_linewidth(THIN);
set_graphpencolor(g->axescolor);
move_to(x-dwidth,0.0);
line_to(x+dwidth,0.0);
set_graphpencolor(g->graphcolor);
set_linewidth(THICK);
}
/* Now draw the portion of the graph line over this rectangle */
tp = (double *) (ARGPTR(g->independent_variable));
xf = g->xfunction;
yf = g->yfunction;
/* Now, how big a t-interval is required? */
tgap = (g->tmax - g->tmin)/200.0;
count = 1;
for(stoploop = 0; count == 1 && stoploop < 5; ++stoploop)
{ u = x;
v = y;
*tp = t;
for(count = 0; fabs(u-x) < dwidth && fabs(v-y) < dheight && count < 20; ++count)
{ /* while (u,v) is inside the rectangle increase the gap */
/* But don't die here--if 20 increments isn't enough give up. */
*tp -= tgap;
deval(xf,&u);
if(u == BADVAL)
break;
deval(yf,&v);
if(v == BADVAL)
break;
}
if(count == 1) /* out of the rectangle in one step */
tgap /= 2.0; /* and try again */
if(u == BADVAL || v == BADVAL)
{ count = 1;
tgap /= 2.0; /* and try again */
}
if(count == 20)
{ count = 1;
tgap *= 2.0; /* and try again */
}
}
if(stoploop == 5)
return; /* Failed */
lo = *tp;
if(lo < g->tmin)
lo = g->tmin;
*tp = t;
u = x;
v = y;
for(count = 0; count < 20 && fabs(u-x) < dwidth && fabs(v-y) < dheight;++count)
{ /* while (u,v) is inside the rectangle increase the gap */
*tp += tgap;
deval(xf,&u);
}
hi = *tp;
if(hi > g->tmax)
hi = g->tmax;
*tp = t;
/* Now divide the interval into five steps and go for it. */
tgap = (hi-lo)/5.0;
if(tgap == 0.0)
return; /* BADVAL's immediately on both sides */
*tp = lo;
deval(xf,&u);
deval(yf,&v);
move_to(u,v);
for(count = 1;count < 5; ++count)
{ *tp = lo + tgap *count;
deval(xf,&u);
deval(yf,&v);
if(u != BADVAL && v != BADVAL)
line_to(u,v);
}
*tp = t;
}
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists