Blob Blame Raw

#include <helianthus.h>


#define COUNT     5
#define RADIUS    5
#define PRECISION 1e-5


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



double calcCurveValue(double *curve, int count, double x) {
  if (count <= 0) return 0;
  if (count == 1) return curve[1];
  if (x <= curve[0]) return curve[1];
  if (x >= curve[(count-1)*2]) return curve[(count-1)*2 + 1];

  int i = 0;
  while(i+1 < count && curve[(i+1)*2] < x)
    ++i;

  double *p1 = &curve[i*2];
  double *p0 = i   > 0     ? p1-2 : p1;
  double *p2 = i+1 < count ? p1+2 : p1;
  double *p3 = i+2 < count ? p2+2 : p2;

  double dx = p2[0] - p1[0];
  if (dx <= PRECISION) return p1[1];

  double a = p1[1];
  double b = p2[1];
  double ta = p2[0]-p0[0]; ta = ta > PRECISION ? (p2[1]-p0[1])/ta*dx : 0;
  double tb = p3[0]-p1[0]; tb = tb > PRECISION ? (p3[1]-p1[1])/tb*dx : 0;
  double l = (x - p1[0])/dx;

  return a + (ta + (3*(b-a)-ta-ta-tb + (2*(a-b)+ta+tb)*l)*l)*l;
}


void init() {
  for(int i = 0; i < COUNT; ++i)
    points[i][0] = points[i][1] = i/(COUNT - 1.0);
  calcCurveValue(points[0], COUNT, 0.3);
}


void draw() {
  double w = windowGetWidth();
  double h = windowGetHeight();

  saveState();
  translate(0, h);
  scale(1, -1);

  noFill();
  stroke(colorByRGBA(0.75, 0.75, 0.75, 1));
  strokeWidth(2);
  rect(0, 0, w, h);

  strokeWidth(2);
  line(0, 0, w, h);

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

  stroke(COLOR_BLUE);
  fill(COLOR_WHITE);
  for(int i = 0; i < w+1; ++i)
    lineTo(i, calcCurveValue(points[0], COUNT, i/w)*h);
  strokePath();
  for(int i = 0; i < COUNT; ++i) {
    double x = points[i][0]*w, y = points[i][1]*h;
    circle(x, y, RADIUS);
    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;
}