#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;
}