Blob Blame Raw

#include <helianthus.h>
#include <math.h>


#define COUNT     16
#define SIZE      17
#define RADIUS    5
#define PRECISION 1e-5


double points[COUNT][2];
double *curPoint;
double curPointOffset[2];

int graphs[10];


double value(int ix)
  { return points[ ((ix + COUNT/2)%COUNT + COUNT)%COUNT ][1]; }

double nearest(double x)
  { return value(floor(x)); }

double linear(double x) {
  x -= 0.5;
  int ix = floor(x);
  x -= ix;
  return value(ix)*(1-x) + value(ix+1)*x;
}

double cubic(double x) {
  x -= 0.5;
  int ix = floor(x);
  x -= ix;

  double a = value(ix-1);
  double b = value(ix+0);
  double c = value(ix+1);
  double d = value(ix+2);

  return a*( -0.5*x*x*x +     x*x - 0.5*x )
			 + b*(  1.5*x*x*x - 2.5*x*x + 1.0   )
			 + c*( -1.5*x*x*x + 2.0*x*x + 0.5*x )
			 + d*(  0.5*x*x*x - 0.5*x*x         );
}

double bspline(double x) {
  x -= 0.5;
  int ix = floor(x);
  x -= ix;

  double a = value(ix-1);
  double b = value(ix+0);
  double c = value(ix+1);
  double d = value(ix+2);

  return a*(  -x*x*x + 3*x*x - 3*x + 1)/6
			 + b*( 3*x*x*x - 6*x*x + 4      )/6
			 + c*(-3*x*x*x + 3*x*x + 3*x + 1)/6
			 + d*(   x*x*x                  )/6;
}


void graph(double kx, double ky, double (*func)(double), unsigned int color) {
  saveState();
  strokeWidth(2);
  stroke(color);
  int hs = (int)ceil(SIZE*kx/2);
  for(int x = -hs; x <= hs; ++x)
    lineTo(x, func(x/kx)*ky);
  strokePath();
  restoreState();
}


void grid(double kx, double ky) {
  saveState();
  strokeWidth(1);
  stroke(colorByRGBA(0, 0, 1, 0.125));
  double hs = 0.5*SIZE;
  for(int step = 16; step; step >>= 1) {
    for(int i = 0; i <= SIZE/2; i += step) {
      line(-hs*kx,  i*ky, hs*kx,  i*ky);
      line(-hs*kx, -i*ky, hs*kx, -i*ky);
      line( i*kx, -hs*ky,  i*kx, hs*ky);
      line(-i*kx, -hs*ky, -i*kx, hs*ky);
    }
  }
  restoreState();
}

void randomize() {
  for(int i = 0; i < COUNT; ++i)
    points[i][1] = randomFloat()*SIZE - SIZE/2.0;
}

void zero() {
  for(int i = 0; i < COUNT; ++i)
    points[i][1] = 0;
}

void init() {
  for(int i = 0; i < COUNT; ++i)
    points[i][0] = i - COUNT/2 + 0.5;
  randomize();
}


void draw() {
  double w = windowGetWidth();
  double h = windowGetHeight();
  double kx = w/SIZE;
  double ky = h/SIZE;

  saveState();
  translate(w/2, h/2);
  scale(1, -1);

  if (keyWentDown("r")) { randomize(); curPoint = 0; }
  if (keyWentDown("z")) { zero(); curPoint = 0; }
  char key[] = "0";
  for(int i = 0; i < 10; ++i, ++*key)
    if (keyWentDown(key)) graphs[i] = !graphs[i];

  int m = mouseWentDown("left");
  double mx = mouseTransformedX();
  double my = mouseTransformedY();
  if (!mouseDown("left"))
    { m = FALSE; curPoint = 0; }
  if (curPoint) {
    //curPoint[0] = (mx + curPointOffset[0])/kx;
    curPoint[1] = (my + curPointOffset[1])/ky;
  }

  grid(kx, ky);
  if (graphs[0]) graph(kx, ky, nearest, colorByRGBA(0, 0, 0, 0.5));
  if (graphs[1]) graph(kx, ky, linear , colorByRGBA(0, 1, 0, 0.5));
  if (graphs[2]) graph(kx, ky, cubic  , colorByRGBA(0, 0, 1, 0.5));
  if (graphs[3]) graph(kx, ky, bspline, colorByRGBA(1, 0, 0, 0.5));

  strokeWidth(2);
  stroke(COLOR_BLUE);
  fill(COLOR_WHITE);
  for(int i = 0; i < COUNT; ++i) {
    double x = points[i][0]*kx, y = points[i][1]*ky;
    line(x, 0, x, y);
    circle(x, y, RADIUS);
    if (i == COUNT/2)
      circle(x, y, RADIUS + 1);
    double dx = x-mx, dy = y-my;
    if (m && dx*dx + dy*dy <= RADIUS*RADIUS) {
      curPoint = points[i];
      curPointOffset[0] = dx;
      curPointOffset[1] = dy;
    }
  }

  restoreState();
}


int main() {
  windowSetVariableFrameRate();
  windowSetResizable(TRUE);
  windowSetInit(&init);
  windowSetDraw(&draw);
  windowRun();
  return 0;
}