Blob Blame Raw

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


#define COUNT     10
#define TL        20
#define RADIUS    5
#define PRECISION 1e-5


typedef struct { double x, y, tx, ty; } Point;
typedef struct { double A, B, C, D; } Spline;


Point points[COUNT];
Point *curPoint;
double curPointOffset[2];
int curTangent;


void splineInit(Spline *s, double a, double b, double ta, double tb) {
  double d = b - a;
  if (!(fabs(d) > 1e-6))
    { s->A = a; s->B = s->C = s->D = 0; return; }

  double B = ta;
  double C = ((ta*ta - tb*tb)/d - d)*0.5;
  double A = a - C;
  double x = ta*tb + C*(d + C);
  double y = ta*d + C*(ta - tb);
  double D = atan2(fabs(y), x);
  //if (D < 0) D += PI;
  if (d < 0) D = -D;

  s->A = A;
  s->B = B;
  s->C = C;
  s->D = D;
}

double splineValue(const Spline *s, double l) {
  l *= s->D;
  return s->A + s->B*sin(l) + s->C*cos(l);
}

double splineTangent(const Spline *s, double l) {
  l *= s->D;
  return s->B*cos(l) + s->C*sin(l);
}

void drawSplineSegment(const Point *a, const Point *b) {
  Spline sx, sy;
  splineInit(&sx, a->x, b->x, a->tx, b->tx);
  splineInit(&sy, a->y, b->y, a->ty, b->ty);
  int count = 10;
  for(int i = 1; i < count; ++i) {
    double l = i/(double)count;
    double x = splineValue(&sx, l);
    double y = splineValue(&sy, l);
    lineTo(x, y);
  }
  lineTo(b->x, b->y);
}

void drawSpline(const Point *p, int count) {
  if (count < 2) return;
  moveTo(p->x, p->y);
  for(int i = 1; i < count; ++i)
    drawSplineSegment(p+i-1, p+i);
  strokePath();
}



void init() {
  for(int i = 0; i < COUNT; ++i) {
    points[i].x = (i/(COUNT - 1.0) - 0.5)*256;
    points[i].tx = 100.0;
  }
}


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

  saveState();
  translate(w/2, h/2);

  int m = mouseWentDown("left");
  double mx = mouseTransformedX();
  double my = mouseTransformedY();
  if (!mouseDown("left"))
    { m = FALSE; curPoint = 0; }
  if (curPoint) {
    curPoint->x = mx + curPointOffset[0];
    curPoint->y = my + curPointOffset[1];
  }

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

  restoreState();
}


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