Sindbad~EG File Manager
/* contour plots */
/*
9.17.92, file created
7.10.96 code last modified
6.14.98 last modified
4.19.00 removed calls to user_interrupt
2.24.24 changed include cgraph. to svgGraph.h, added include rgb,
changed svgDevice to svgDevice
removed code for printers
3.25.24 changed color variables to unsigned from unsigned long
*/
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#include "rgb.h"
#include "globals.h"
#include "graphstr.h"
#include "svgGraph.h"
#include "grapher.h"
#include "dcomplex.h"
#include "deval.h"
#include "ceval.h"
#include "heap.h"
#include "wcolors.h"
static int promising(double a,double b,double c, double d,double e, double spacing);
static unsigned colors[] =
{ RED24, LIGHTGRAY24, BLUE24, GREEN24, CYAN24,
MAGENTA24, YELLOW24, WHITE24, BLACK24
};
#define NCOLORS (sizeof(colors)/ sizeof(unsigned)-1)
/* -1 because the last entry is the background */
/*__________________________________________________________*/
static unsigned colorfunction(double x, double y, double spacing)
/* return the color to use when a 'crossing' of a level line is found */
{ int n,xx,yy;
if(x == y)
return colors[NCOLORS]; /* speed up this common call */
xx = (int)(x/spacing);
yy = (int)(y/spacing);
if(xx >= 0)
++xx; /* avoid duplicating a color for small negative and positive values */
if(yy >= 0)
++yy;
if(xx < yy)
n = xx;
else if(yy < xx)
n = yy;
else if(x < 0.0 && y >= 0.0)
n = 0;
else if(y < 0.0 && x >= 0.0)
n = 0;
else
return colors[NCOLORS]; /* the background color */
/* Now n show which multiple of 'spacing' we are
crossing. It can be negative and/or large. */
/* return a color depending on n that is one of
the colors in the colors array and not equal
to the background color */
n = n % NCOLORS;
if(n < 0)
n += NCOLORS;
/* Now n is nonnegative and < NCOLORS */
return colors[n];
}
/*__________________________________________________________*/
void contourplot(term f, /* relation to be graphed */
double *xp, double *yp, /* pointers to values of x,y */
double spacing,
unsigned background
)
/* graph level lines f(x,y)=constant */
/* The code is a copy of graph_relation, except for the assignment of
color to CROSSING, and 'promising' has one more argument.
It gives different results only because the macro SIGNCHANGE is replaced by CROSSING
and the static function 'promising'
are different in this file than in graphrel.c. */
{ int nx1,nx2,ny1,ny2; /* pixel coordinates of the viewport */
int bigstep;
svgDevice *device = get_device();
int i,j; /* loop variables */
double e;
double xpixel = device -> xpixel;
double ypixel = device -> ypixel;
double square[32][32]; /* for promising rectangles */
double *col0; /* dynamic array for one column of numbers */
double *col1; /* alternate with col0 to save copying */
double *col,*othercol; /* will be col0 and col1 alternately */
unsigned color;
int u,v;
double savex,savey;
bigstep = 9;
assert(bigstep <= 29);
/* don't ever make it bigger or bounds on 'square' will be exceeded */
/* bigstep must be odd; for the screen it should be 9; for
postscript 29 might be a better value */
if(background != colors[NCOLORS])
{ /* find the background color in the COLORS array
and swap it into last position, namely colors[NCOLORS] */
for(i=0;i<NCOLORS;i++)
{ if(colors[i] == background)
{ unsigned temp = colors[NCOLORS];
colors[NCOLORS] = colors[i];
colors[i] = temp;
break;
}
}
}
nx1 = device->pxmin;
nx2 = device->pxmax;
ny1 = device->pymin;
ny2 = device->pymax;
assert(ny1 < ny2);
/* pixel coordinates are smaller at the top */
/* so ny1 goes with ymax, and ny2 goes with ymin */
col0 = (double *) callocate(ny2-ny1+bigstep+1,sizeof(double));
if(col0==NULL)
nospace();
col1 = (double *) callocate(ny2-ny1+bigstep+1,sizeof(double));
if(col1==NULL)
nospace();
col0 -= ny1-bigstep; /* so legal indices are col[ny1-bigstep]...col[ny2] */
col1 -= ny1-bigstep;
*xp = device->xmin + 0.5*device->xpixel;
/* world coordinates begin half a pixel left of the first pixel */
for(i=nx1; i<=nx2; i+=bigstep)
{ *yp = device->ymin + 0.5*ypixel;
if( i & 1 ) /* i is odd */
{ col = col1;
othercol = col0;
}
else /* i is even */
{ col = col0;
othercol = col1;
}
deval(f,col+ny2); /* outside loop so don't have to check j > ny2 in loop */
*yp += bigstep *ypixel; /* set correct initial value of y */
for(j=ny2-bigstep; j>ny1-bigstep; j-=bigstep) /* compute the i-th column */
{ deval(f,col + j);
savex = *xp;
savey = *yp;
*xp -= 0.5 * bigstep * xpixel;
*yp -= 0.5 * bigstep * ypixel;
deval(f,&e);
*xp = savex;
*yp = savey;
if(i > nx1 && promising(col[j],col[j+bigstep],othercol[j+bigstep],othercol[j],e,spacing))
/* then fill in the 'square' array with every-pixel
values for the 14 by 14-pixel rectangle with (*xp,*yp) at the
upper right (if bigstep is 11) */
{ *xp -= (bigstep+1) * xpixel;
for(u=0;u <= bigstep+2;u++)
{ *yp = savey - (bigstep+1) *ypixel;
for(v=0; v <= bigstep+2;v++)
{ deval(f,&square[u][v]);
if(v > 0)
{ color = colorfunction(square[u][v],square[u][v-1],spacing);
if(color != background)
{ draw_pixel(i-bigstep -1 + u,j+bigstep+1-v,color);
draw_pixel(i-bigstep -1 + u,j+bigstep+2-v,color);
if(u>0)
{ color = colorfunction(square[u-1][v],square[u][v],spacing);
if(color != background)
draw_pixel(i-bigstep+u-2,j+bigstep+1-v,color);
}
}
}
if(u > 0)
{ color = colorfunction(square[u-1][v],square[u][v],spacing);
if(color != background)
{ draw_pixel(i-bigstep+u-1,j+bigstep+1-v,color);
draw_pixel(i-bigstep+u,j+bigstep+1-v,color);
}
}
*yp += ypixel;
}
*xp += xpixel;
}
*xp = savex;
*yp = savey;
}
*yp += bigstep *ypixel;
}
*xp += bigstep * xpixel;
}
free2(col0 + ny1-bigstep);
free2(col1 + ny1-bigstep);
}
/*______________________________________________________________________*/
static int promising(double a,double b,double c, double d,double e,double spacing)
/* a,b,c,d, are function values of f at corners of a rectangle,
in clockwise order, and e is the value in the middle.
Is there any chance of a zero of f inside the
rectangle? If so return 1, else return 0. */
{ double laplacian;
if(colorfunction(a,b,spacing) || colorfunction(b,c,spacing) ||
colorfunction(c,d,spacing) || colorfunction(d,e,spacing)
)
return 1;
/* Now they all have the same sign */
/* Compute the Laplacian; does it has the same sign as f? */
laplacian = a+b+c+d -4.0*e;
if (fabs(laplacian) > 0.5 * spacing)
return 1; /* too curvy to ignore this square */
else
return 0; /* take the risk of ignoring this square */
}
/*__________________________________________________________*/
void complex_contourplot(term f, /* relation to be graphed */
double *xp, double *yp, /* pointers to values of x,y */
double spacing,
unsigned background
)
/* graph level lines f(x,y)=constant */
/* f is supposed to be real-valued; actually it can be complex-valued
and the real part is graphed. */
/* code is a copy of that for contourplot except it uses ceval
instead of deval */
{ int nx1,nx2,ny1,ny2; /* pixel coordinates of the viewport */
int bigstep;
dcomplex temp;
unsigned color;
svgDevice *device = get_device();
int i,j; /* loop variables */
double e;
double xpixel = device -> xpixel;
double ypixel = device -> ypixel;
double square[32][32]; /* for promising rectangles */
double *col0; /* dynamic array for one column of numbers */
double *col1; /* alternate with col0 to save copying */
double *col,*othercol; /* will be col0 and col1 alternately */
int u,v;
double savex,savey;
bigstep = 9;
assert(bigstep <= 29); /* don't ever make it bigger or bounds on 'square' will be exceeded */
/* bigstep must be odd; for the screen it should be 9; for
postscript 29 might be a better value */
if(background != colors[NCOLORS])
{ /* find the background color in the COLORS array
and swap it into last position, colors[NCOLORS] */
for(i=0;i<NCOLORS;i++)
{ if(colors[i] == background)
{ unsigned temp = colors[NCOLORS];
colors[NCOLORS] = colors[i];
colors[i] = temp;
break;
}
}
}
nx1 = device->pxmin;
nx2 = device->pxmax;
ny1 = device->pymin;
ny2 = device->pymax;
assert(ny1 < ny2);
/* pixel coordinates are smaller at the top */
/* so ny1 goes with ymax, and ny2 goes with ymin */
col0 = (double *) callocate(ny2-ny1+bigstep+1,sizeof(double));
if(col0==NULL) nospace();
col1 = (double *) callocate(ny2-ny1+bigstep+1,sizeof(double));
if(col1==NULL) nospace();
col0 -= ny1-bigstep; /* so legal indices are col[ny1-bigstep]...col[ny2] */
col1 -= ny1-bigstep;
*xp = device->xmin + 0.5 *device->xpixel;
/* world coordinates begin half a pixel left of the first pixel */
for(i=nx1; i<=nx2; i+=bigstep)
{ *yp = device->ymin + 0.5 *device->ypixel;
if( i & 1 ) /* i is odd */
{ col = col1;
othercol = col0;
}
else /* i is even */
{ col = col0;
othercol = col1;
}
ceval(f,&temp);
col[ny2] = temp.r; /* outside loop so don't have to check j > ny2 in loop */
*yp += bigstep *ypixel; /* set correct initial value of y */
for(j=ny2-bigstep; j>ny1-bigstep; j-=bigstep) /* compute the i-th column */
{ ceval(f,&temp);
col[j] = temp.r;
savex = *xp;
savey = *yp;
*xp -= 0.5 * bigstep * xpixel;
*yp -= 0.5 * bigstep * ypixel;
ceval(f,&temp);
e = temp.r;
*xp = savex;
*yp = savey;
if(i > nx1 && promising(col[j],col[j+bigstep],othercol[j+bigstep],othercol[j],e,spacing))
/* then fill in the 'square' array with every-pixel
values for the 14 by 14-pixel rectangle with (*xp,*yp) at the
upper right (if bigstep is 11) */
{ *xp -= (bigstep+1) * xpixel;
for(u=0;u <= bigstep+2;u++)
{ *yp = savey - (bigstep+1) *ypixel;
for(v=0; v <= bigstep+2;v++)
{ ceval(f,&temp);
square[u][v] = temp.r;
if(v > 0)
{ color = colorfunction(square[u][v],square[u][v-1],spacing);
if(color != background)
{ draw_pixel(i-bigstep -1 + u,j+bigstep+1-v,color);
draw_pixel(i-bigstep -1 + u,j+bigstep+2-v,color);
if(u>0)
{ color = colorfunction(square[u-1][v],square[u][v],spacing);
if(color != background)
draw_pixel(i-bigstep+u-2,j+bigstep+1-v,color);
}
}
}
if(u > 0)
{ color = colorfunction(square[u-1][v],square[u][v],spacing);
if(color != background)
{ draw_pixel(i-bigstep+u-1,j+bigstep+1-v,color);
draw_pixel(i-bigstep+u,j+bigstep+1-v,color);
}
}
*yp += ypixel;
}
*xp += xpixel;
}
*xp = savex;
*yp = savey;
}
*yp += bigstep *ypixel;
}
*xp += bigstep * xpixel;
}
free2(col0 + ny1-bigstep);
free2(col1 + ny1-bigstep);
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists