Blame onefile/splines.c

2ed0d1
2ed0d1
#include <math.h></math.h>
2ed0d1
#include <helianthus.h></helianthus.h>
2ed0d1
2ed0d1
2ed0d1
#define COUNT     10
2ed0d1
#define TL        20
2ed0d1
#define RADIUS    5
2ed0d1
#define PRECISION 1e-5
2ed0d1
2ed0d1
2ed0d1
typedef struct { double x, y, tx, ty; } Point;
2ed0d1
typedef struct { double A, B, C, D; } Spline;
2ed0d1
2ed0d1
2ed0d1
Point points[COUNT];
2ed0d1
Point *curPoint;
2ed0d1
double curPointOffset[2];
2ed0d1
int curTangent;
2ed0d1
2ed0d1
2ed0d1
void splineInit(Spline *s, double a, double b, double ta, double tb) {
2ed0d1
  double d = b - a;
2ed0d1
  if (!(fabs(d) > 1e-6))
2ed0d1
    { s->A = a; s->B = s->C = s->D = 0; return; }
2ed0d1
2ed0d1
  double B = ta;
2ed0d1
  double C = ((ta*ta - tb*tb)/d - d)*0.5;
2ed0d1
  double A = a - C;
2ed0d1
  double x = ta*tb + C*(d + C);
2ed0d1
  double y = ta*d + C*(ta - tb);
2ed0d1
  double D = atan2(fabs(y), x);
2ed0d1
  //if (D < 0) D += PI;
2ed0d1
  if (d < 0) D = -D;
2ed0d1
2ed0d1
  s->A = A;
2ed0d1
  s->B = B;
2ed0d1
  s->C = C;
2ed0d1
  s->D = D;
2ed0d1
}
2ed0d1
2ed0d1
double splineValue(const Spline *s, double l) {
2ed0d1
  l *= s->D;
2ed0d1
  return s->A + s->B*sin(l) + s->C*cos(l);
2ed0d1
}
2ed0d1
2ed0d1
double splineTangent(const Spline *s, double l) {
2ed0d1
  l *= s->D;
2ed0d1
  return s->B*cos(l) + s->C*sin(l);
2ed0d1
}
2ed0d1
2ed0d1
void drawSplineSegment(const Point *a, const Point *b) {
2ed0d1
  Spline sx, sy;
2ed0d1
  splineInit(&sx, a->x, b->x, a->tx, b->tx);
2ed0d1
  splineInit(&sy, a->y, b->y, a->ty, b->ty);
2ed0d1
  int count = 10;
2ed0d1
  for(int i = 1; i < count; ++i) {
2ed0d1
    double l = i/(double)count;
2ed0d1
    double x = splineValue(&sx, l);
2ed0d1
    double y = splineValue(&sy, l);
2ed0d1
    lineTo(x, y);
2ed0d1
  }
2ed0d1
  lineTo(b->x, b->y);
2ed0d1
}
2ed0d1
2ed0d1
void drawSpline(const Point *p, int count) {
2ed0d1
  if (count < 2) return;
2ed0d1
  moveTo(p->x, p->y);
2ed0d1
  for(int i = 1; i < count; ++i)
2ed0d1
    drawSplineSegment(p+i-1, p+i);
2ed0d1
  strokePath();
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
2ed0d1
void init() {
2ed0d1
  for(int i = 0; i < COUNT; ++i) {
2ed0d1
    points[i].x = (i/(COUNT - 1.0) - 0.5)*256;
2ed0d1
    points[i].tx = 100.0;
2ed0d1
  }
2ed0d1
}
2ed0d1
2ed0d1
2ed0d1
void draw() {
2ed0d1
  double w = windowGetWidth();
2ed0d1
  double h = windowGetHeight();
2ed0d1
2ed0d1
  saveState();
2ed0d1
  translate(w/2, h/2);
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->x = mx + curPointOffset[0];
2ed0d1
    curPoint->y = my + curPointOffset[1];
2ed0d1
  }
2ed0d1
2ed0d1
  strokeWidth(2);
2ed0d1
  stroke(COLOR_BLUE);
2ed0d1
  fill(COLOR_WHITE);
2ed0d1
  drawSpline(points, COUNT);
2ed0d1
  for(int i = 0; i < COUNT; ++i) {
2ed0d1
    Point *p = points + i;
2ed0d1
    circle(p->x, p->y, RADIUS);
2ed0d1
    double dx = p->x-mx, dy = p->y-my;
2ed0d1
    if (m && dx*dx + dy*dy <= RADIUS*RADIUS) {
2ed0d1
      curPoint = p;
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
}