|
|
2ed0d1 |
|
|
|
2ed0d1 |
#include <helianthus.h></helianthus.h>
|
|
|
2ed0d1 |
#include <math.h></math.h>
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
#define COUNT 16
|
|
|
2ed0d1 |
#define SIZE 17
|
|
|
2ed0d1 |
#define RADIUS 5
|
|
|
2ed0d1 |
#define PRECISION 1e-5
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double points[COUNT][2];
|
|
|
2ed0d1 |
double *curPoint;
|
|
|
2ed0d1 |
double curPointOffset[2];
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
int graphs[10];
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double value(int ix)
|
|
|
2ed0d1 |
{ return points[ ((ix + COUNT/2)%COUNT + COUNT)%COUNT ][1]; }
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double nearest(double x)
|
|
|
2ed0d1 |
{ return value(floor(x)); }
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double linear(double x) {
|
|
|
2ed0d1 |
x -= 0.5;
|
|
|
2ed0d1 |
int ix = floor(x);
|
|
|
2ed0d1 |
x -= ix;
|
|
|
2ed0d1 |
return value(ix)*(1-x) + value(ix+1)*x;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double cubic(double x) {
|
|
|
2ed0d1 |
x -= 0.5;
|
|
|
2ed0d1 |
int ix = floor(x);
|
|
|
2ed0d1 |
x -= ix;
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double a = value(ix-1);
|
|
|
2ed0d1 |
double b = value(ix+0);
|
|
|
2ed0d1 |
double c = value(ix+1);
|
|
|
2ed0d1 |
double d = value(ix+2);
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
return a*( -0.5*x*x*x + x*x - 0.5*x )
|
|
|
2ed0d1 |
+ b*( 1.5*x*x*x - 2.5*x*x + 1.0 )
|
|
|
2ed0d1 |
+ c*( -1.5*x*x*x + 2.0*x*x + 0.5*x )
|
|
|
2ed0d1 |
+ d*( 0.5*x*x*x - 0.5*x*x );
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double bspline(double x) {
|
|
|
2ed0d1 |
x -= 0.5;
|
|
|
2ed0d1 |
int ix = floor(x);
|
|
|
2ed0d1 |
x -= ix;
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
double a = value(ix-1);
|
|
|
2ed0d1 |
double b = value(ix+0);
|
|
|
2ed0d1 |
double c = value(ix+1);
|
|
|
2ed0d1 |
double d = value(ix+2);
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
return a*( -x*x*x + 3*x*x - 3*x + 1)/6
|
|
|
2ed0d1 |
+ b*( 3*x*x*x - 6*x*x + 4 )/6
|
|
|
2ed0d1 |
+ c*(-3*x*x*x + 3*x*x + 3*x + 1)/6
|
|
|
2ed0d1 |
+ d*( x*x*x )/6;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void graph(double kx, double ky, double (*func)(double), unsigned int color) {
|
|
|
2ed0d1 |
saveState();
|
|
|
2ed0d1 |
strokeWidth(2);
|
|
|
2ed0d1 |
stroke(color);
|
|
|
2ed0d1 |
int hs = (int)ceil(SIZE*kx/2);
|
|
|
2ed0d1 |
for(int x = -hs; x <= hs; ++x)
|
|
|
2ed0d1 |
lineTo(x, func(x/kx)*ky);
|
|
|
2ed0d1 |
strokePath();
|
|
|
2ed0d1 |
restoreState();
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void grid(double kx, double ky) {
|
|
|
2ed0d1 |
saveState();
|
|
|
2ed0d1 |
strokeWidth(1);
|
|
|
2ed0d1 |
stroke(colorByRGBA(0, 0, 1, 0.125));
|
|
|
2ed0d1 |
double hs = 0.5*SIZE;
|
|
|
2ed0d1 |
for(int step = 16; step; step >>= 1) {
|
|
|
2ed0d1 |
for(int i = 0; i <= SIZE/2; i += step) {
|
|
|
2ed0d1 |
line(-hs*kx, i*ky, hs*kx, i*ky);
|
|
|
2ed0d1 |
line(-hs*kx, -i*ky, hs*kx, -i*ky);
|
|
|
2ed0d1 |
line( i*kx, -hs*ky, i*kx, hs*ky);
|
|
|
2ed0d1 |
line(-i*kx, -hs*ky, -i*kx, hs*ky);
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
restoreState();
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void randomize() {
|
|
|
2ed0d1 |
for(int i = 0; i < COUNT; ++i)
|
|
|
2ed0d1 |
points[i][1] = randomFloat()*SIZE - SIZE/2.0;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void zero() {
|
|
|
2ed0d1 |
for(int i = 0; i < COUNT; ++i)
|
|
|
2ed0d1 |
points[i][1] = 0;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void init() {
|
|
|
2ed0d1 |
for(int i = 0; i < COUNT; ++i)
|
|
|
2ed0d1 |
points[i][0] = i - COUNT/2 + 0.5;
|
|
|
2ed0d1 |
randomize();
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
void draw() {
|
|
|
2ed0d1 |
double w = windowGetWidth();
|
|
|
2ed0d1 |
double h = windowGetHeight();
|
|
|
2ed0d1 |
double kx = w/SIZE;
|
|
|
2ed0d1 |
double ky = h/SIZE;
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
saveState();
|
|
|
2ed0d1 |
translate(w/2, h/2);
|
|
|
2ed0d1 |
scale(1, -1);
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
if (keyWentDown("r")) { randomize(); curPoint = 0; }
|
|
|
2ed0d1 |
if (keyWentDown("z")) { zero(); curPoint = 0; }
|
|
|
2ed0d1 |
char key[] = "0";
|
|
|
2ed0d1 |
for(int i = 0; i < 10; ++i, ++*key)
|
|
|
2ed0d1 |
if (keyWentDown(key)) graphs[i] = !graphs[i];
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
int m = mouseWentDown("left");
|
|
|
2ed0d1 |
double mx = mouseTransformedX();
|
|
|
2ed0d1 |
double my = mouseTransformedY();
|
|
|
2ed0d1 |
if (!mouseDown("left"))
|
|
|
2ed0d1 |
{ m = FALSE; curPoint = 0; }
|
|
|
2ed0d1 |
if (curPoint) {
|
|
|
2ed0d1 |
//curPoint[0] = (mx + curPointOffset[0])/kx;
|
|
|
2ed0d1 |
curPoint[1] = (my + curPointOffset[1])/ky;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
grid(kx, ky);
|
|
|
2ed0d1 |
if (graphs[0]) graph(kx, ky, nearest, colorByRGBA(0, 0, 0, 0.5));
|
|
|
2ed0d1 |
if (graphs[1]) graph(kx, ky, linear , colorByRGBA(0, 1, 0, 0.5));
|
|
|
2ed0d1 |
if (graphs[2]) graph(kx, ky, cubic , colorByRGBA(0, 0, 1, 0.5));
|
|
|
2ed0d1 |
if (graphs[3]) graph(kx, ky, bspline, colorByRGBA(1, 0, 0, 0.5));
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
strokeWidth(2);
|
|
|
2ed0d1 |
stroke(COLOR_BLUE);
|
|
|
2ed0d1 |
fill(COLOR_WHITE);
|
|
|
2ed0d1 |
for(int i = 0; i < COUNT; ++i) {
|
|
|
2ed0d1 |
double x = points[i][0]*kx, y = points[i][1]*ky;
|
|
|
2ed0d1 |
line(x, 0, x, y);
|
|
|
2ed0d1 |
circle(x, y, RADIUS);
|
|
|
2ed0d1 |
if (i == COUNT/2)
|
|
|
2ed0d1 |
circle(x, y, RADIUS + 1);
|
|
|
2ed0d1 |
double dx = x-mx, dy = y-my;
|
|
|
2ed0d1 |
if (m && dx*dx + dy*dy <= RADIUS*RADIUS) {
|
|
|
2ed0d1 |
curPoint = points[i];
|
|
|
2ed0d1 |
curPointOffset[0] = dx;
|
|
|
2ed0d1 |
curPointOffset[1] = dy;
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
restoreState();
|
|
|
2ed0d1 |
}
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
|
|
|
2ed0d1 |
int main() {
|
|
|
2ed0d1 |
windowSetVariableFrameRate();
|
|
|
2ed0d1 |
windowSetResizable(TRUE);
|
|
|
2ed0d1 |
windowSetInit(&init);
|
|
|
2ed0d1 |
windowSetDraw(&draw);
|
|
|
2ed0d1 |
windowRun();
|
|
|
2ed0d1 |
return 0;
|
|
|
2ed0d1 |
}
|