#include <math.h>
#include <string.h>
#include <stdio.h>
#include <helianthus.h>
int printed = 0;
int started = 0;
double mx, my, ax, ay;
void vec3set(double *v, double x, double y, double z)
{ v[0] = x, v[1] = y, v[2] = z; }
void vec3cpy(double *v, const double *vv)
{ memcpy(v, vv, sizeof(*v)*3); }
void vec3add(double *v, const double *vv)
{ v[0] += vv[0]; v[1] += vv[1]; v[2] += vv[2]; }
void vec3sub(double *v, const double *vv)
{ v[0] -= vv[0]; v[1] -= vv[1]; v[2] -= vv[2]; }
void vec3mul(double *v, double x)
{ v[0] *= x; v[1] *= x; v[2] *= x; }
double vec3dot(const double *a, const double *b)
{ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
void vec3trans(double *v, const double *m) {
vec3set(v, v[0]*m[0] + v[1]*m[3] + v[2]*m[6],
v[0]*m[1] + v[1]*m[4] + v[2]*m[7],
v[0]*m[2] + v[1]*m[5] + v[2]*m[8] );
}
void mat3cpy(double *m, double *mm)
{ memcpy(m, mm, sizeof(*m)*9); }
void mat3one(double *m) {
m[1] = m[2] = m[3] = m[5] = m[6] = m[7] = 0;
m[0] = m[4] = m[8] = 1;
}
void mat3rotX(double *m, double a) {
rotateVector(&m[1], &m[2], a);
rotateVector(&m[4], &m[5], a);
rotateVector(&m[7], &m[8], a);
}
void mat3rotY(double *m, double a) {
rotateVector(&m[2], &m[0], a);
rotateVector(&m[5], &m[3], a);
rotateVector(&m[8], &m[6], a);
}
void mat3rotZ(double *m, double a) {
rotateVector(&m[0], &m[1], a);
rotateVector(&m[3], &m[4], a);
rotateVector(&m[6], &m[7], a);
}
void lineTo3d(const double *m, double x, double y, double z) {
double v[] = {x, y, z};
vec3trans(v, m);
lineTo(v[0], v[1]);
}
void lineTo3dv(const double *m, const double *v)
{ lineTo3d(m, v[0], v[1], v[2]); }
void func(double *v, double x, double y) {
double angle = 1.5*PI*y;
double radius = 4*(1-y) + 2*y;
double size = (1-y)*0.25;
double ss = sin(angle), cc = cos(angle);
double a = 2*PI*(x-0.5)*size + PI/2, s = sin(a), c = cos(a);
vec3set(v, c*radius, s*cc*radius, s*ss*radius);
rotateVector(&v[0], &v[1], 45);
}
void tangent(double *v, double x, double y, double dx, double dy) {
double p[3];
func(p, x-dx, y-dy);
func(v, x+dx, y+dy);
vec3sub(v, p);
double l = sqrt(vec3dot(v, v));
vec3mul(v, 1/l);
}
void drawCubic(const double *m, const double *vv) {
for(int i = 0; i <= 16; ++i) {
double l = i/16.0, k = 1-l;
double v[3] = {};
double vc[4][3];
memcpy(vc, vv, sizeof(vc));
vec3mul(vc[0], k*k*k);
vec3mul(vc[1], 3*k*k*l);
vec3mul(vc[2], 3*l*l*k);
vec3mul(vc[3], l*l*l);
vec3add(v, vc[0]);
vec3add(v, vc[1]);
vec3add(v, vc[2]);
vec3add(v, vc[3]);
lineTo3dv(m, v);
}
strokePath();
}
void makeCubicBase(double *vv, double *p0, double *t0, double *p1, double *t1) {
double d[3], tt0[3], tt1[3];
vec3cpy(d, p1);
vec3sub(d, p0);
double ld = sqrt(vec3dot(d, d));
double l0 = sqrt(vec3dot(t0, t0));
double l1 = sqrt(vec3dot(t1, t1));
double k = ld/3;
vec3cpy(tt0, t0); vec3mul(tt0, k/l0);
vec3cpy(tt1, t1); vec3mul(tt1, k/l1);
double pp0[3], pp1[3];
vec3cpy(pp0, p0); vec3add(pp0, tt0);
vec3cpy(pp1, p1); vec3sub(pp1, tt1);
vec3cpy(&vv[0], p0);
vec3cpy(&vv[3], pp0);
vec3cpy(&vv[6], pp1);
vec3cpy(&vv[9], p1);
if (!printed) {
if (started)
printf(" \"");
else
printf("\" [%.2f][%.2f][%.2f]", vv[0]+4, vv[1]+4, vv[2]+4);
for(int i = 1; i < 4; ++i) {
printf("-[%.2f][%.2f][%.2f]", vv[3*i+0]+4, vv[3*i+1]+4, vv[3*i+2]+4);
}
printf("\"\n");
}
started = 1;
}
void makeCubic(
double *vv,
double x0, double y0, double dx0, double dy0,
double x1, double y1, double dx1, double dy1 )
{
double p0[3], t0[3], p1[3], t1[3];
func(p0, x0, y0);
func(p1, x1, y1);
tangent(t0, x0, y0, dx0, dy0);
tangent(t1, x1, y1, dx1, dy1);
makeCubicBase(vv, p0, t0, p1, t1);
}
void makeCubicBase2(const double *m, double *vv, double *p0, double *t0, double *p1, double *t1) {
makeCubicBase(vv, p0, t0, p1, t1);
drawCubic(m, vv);
}
void makeCubic2(
const double *m, double *vv,
double x0, double y0, double dx0, double dy0,
double x1, double y1, double dx1, double dy1 )
{
makeCubic(vv, x0, y0, dx0, dy0, x1, y1, dx1, dy1);
drawCubic(m, vv);
}
void init() { }
void draw() {
double w = windowGetWidth();
double h = windowGetHeight();
saveState();
translate(w/2, h/2);
int ml = mouseDown("left");
int mr = mouseDown("right");
double pmx = mx, pmy = my;
mx = mouseX(), my = mouseY();
if (ml || mr) { ax += pmx - mx; ay += my - pmy; }
ax = fmod(ax, 360);
ay = fmod(ay, 360);
double step = 128/8.0;
double mat[9] = {step, 0, 0, 0, 0, step, 0, -step, 0};
mat3rotY(mat, ax);
mat3rotX(mat, ay);
double axislen = 1;
strokeWidth(2);
stroke(COLOR_RED); line(0, 0, mat[0]*axislen, mat[1]*axislen);
stroke(COLOR_BLACK); line(0, 0, mat[3]*axislen, mat[4]*axislen);
stroke(COLOR_BLUE); line(0, 0, mat[6]*axislen, mat[7]*axislen);
strokeWidth(1);
stroke(COLOR_BLACK);
noFill();
for(int i = 0; i <= 16; ++i) {
for(int j = 0; j <= 16; ++j) {
double v[3];
func(v, i/16.0, j/16.0);
vec3trans(v, mat);
point(v[0], v[1]);
}
}
double curve[12];
double p0[3], t0[3], p1[3], t1[3];
started = 0;
vec3set(p0, 4, 0, -4); vec3set(t0, 0, 1, 0);
func(p1, 0, 0); tangent(t1, 0, 0, 0, 0.001);
makeCubicBase2(mat, curve, p0, t0, p1, t1);
for(int i = 0; i < 6; ++i)
makeCubic2(mat, curve, 0, i/6.0, 0, 0.001, 0, (i+1)/6.0, 0, 0.001 );
for(int i = 0; i < 6; ++i)
makeCubic2(mat, curve, 1, 1-i/6.0, 0, -0.001, 1, 1-(i+1)/6.0, 0, -0.001 );
func(p0, 1, 0); tangent(t0, 1, 0, 0, -0.001);
vec3set(p1, 0, -4, -4); vec3set(t1, 1, 0, 0);
makeCubicBase2(mat, curve, p0, t0, p1, t1);
started = 0;
makeCubic2(mat, curve, 0, 1/3.0, 0.001, 0, 1, 1/3.0, 0.001, 0);
started = 0;
makeCubic2(mat, curve, 0, 2/3.0, 0.001, 0, 1, 2/3.0, 0.001, 0);
lineTo3d(mat, 4, 0, -4);
lineTo3d(mat, 4, -4, -4);
lineTo3d(mat, 0, -4, -4);
lineTo3d(mat, 0, 0, -4);
closePath();
printed = 1;
restoreState();
}
int main() {
windowSetVariableFrameRate();
windowSetResizable(TRUE);
windowSetInit(&init);
windowSetDraw(&draw);
windowRun();
}