2019-02-03 12:18:14 +00:00
|
|
|
#include "main.h"
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
#define FMOD(x,y) (fmod(x,y) < 0 ? fmod(x,y) + y : fmod(x,y))
|
|
|
|
#define ANGLE_DIFF(x,y) (FMOD((x)-(y), 2*M_PI))
|
|
|
|
#define ANGLE_IN_INTERVAL(a,b,x) (ANGLE_DIFF(x,a) < ANGLE_DIFF(b,a))
|
|
|
|
#define FLIP(x,y) do {double tmp = x; x = y; y = tmp;} while(0)
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
// level 0: helper functions
|
|
|
|
|
2019-02-24 07:43:52 +00:00
|
|
|
int isInsideBB(DrawingContext *ctx, point_t p)
|
|
|
|
{
|
2019-04-12 09:51:57 +00:00
|
|
|
cairo_user_to_device(ctx->cairo, &p.x, &p.y);
|
2019-02-24 07:43:52 +00:00
|
|
|
return -p.x < ctx->dim->width && p.x < 3*ctx->dim->width && -p.y < ctx->dim->height && p.y < 3*ctx->dim->height;
|
|
|
|
}
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
vector_t cross(vector_t a, vector_t b)
|
|
|
|
{
|
|
|
|
vector_t result;
|
|
|
|
result.x[0] = a.x[1]*b.x[2] - a.x[2]*b.x[1];
|
|
|
|
result.x[1] = a.x[2]*b.x[0] - a.x[0]*b.x[2];
|
|
|
|
result.x[2] = a.x[0]*b.x[1] - a.x[1]*b.x[0];
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-04-12 09:51:57 +00:00
|
|
|
vector_t apply(gsl_matrix *m, vector_t x)
|
2019-02-03 12:18:14 +00:00
|
|
|
{
|
|
|
|
vector_t out;
|
|
|
|
|
2019-04-12 09:51:57 +00:00
|
|
|
LOOP(i) out.x[i] = 0.0;
|
|
|
|
LOOP(i) LOOP(j) out.x[i] += gsl_matrix_get(m, i, j) * x.x[j];
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-04-12 09:51:57 +00:00
|
|
|
return out;
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
vector_t apply_transpose(gsl_matrix *m, vector_t x)
|
|
|
|
{
|
|
|
|
vector_t out;
|
|
|
|
|
|
|
|
LOOP(i) out.x[i] = 0.0;
|
|
|
|
LOOP(i) LOOP(j) out.x[i] += gsl_matrix_get(m, j, i) * x.x[j];
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
int fixedPoints(DrawingContext *ctx, const char *word, vector_t *out)
|
|
|
|
{
|
2019-02-08 12:35:02 +00:00
|
|
|
gsl_matrix *tmp = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix *ev = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix **gen = getTempMatrices(ctx->ws, 3);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
initializeTriangleGenerators(gen, ctx->cartan);
|
|
|
|
|
|
|
|
gsl_matrix_set_identity(tmp);
|
|
|
|
for(int i = 0; i < strlen(word); i++) {
|
|
|
|
if(word[i] == ' ')
|
|
|
|
continue;
|
|
|
|
multiply_right(tmp, gen[word[i]-'a'], ctx->ws);
|
|
|
|
}
|
|
|
|
int count = real_eigenvectors(tmp, ev, ctx->ws);
|
|
|
|
|
|
|
|
LOOP(i) LOOP(j) out[i].x[j] = gsl_matrix_get(ev, j, i);
|
|
|
|
|
2019-02-08 12:35:02 +00:00
|
|
|
releaseTempMatrices(ctx->ws, 5);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// level 1: the elementary drawing functions, drawPoint, drawSegment2d
|
|
|
|
|
|
|
|
void drawPoint(DrawingContext *ctx, point_t p)
|
|
|
|
{
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
cairo_save(C);
|
|
|
|
cairo_arc(C, p.x, p.y, 5.0/ctx->dim->scalefactor, 0, 2*M_PI);
|
|
|
|
cairo_close_path(C);
|
|
|
|
cairo_fill(C);
|
|
|
|
cairo_restore(C);
|
|
|
|
|
|
|
|
/*
|
2019-02-03 12:18:14 +00:00
|
|
|
cairo_save(C);
|
|
|
|
cairo_move_to(C, p.x, p.y);
|
|
|
|
cairo_close_path(C);
|
|
|
|
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
|
|
|
cairo_set_line_width(C, 10.0/ctx->dim->scalefactor);
|
|
|
|
cairo_stroke(C);
|
|
|
|
cairo_restore(C);
|
2019-12-23 11:29:50 +00:00
|
|
|
*/
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void drawSegment2d(DrawingContext *ctx, point_t a, point_t b)
|
|
|
|
{
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
cairo_move_to(C, a.x, a.y);
|
|
|
|
cairo_line_to(C, b.x, b.y);
|
|
|
|
cairo_stroke(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
// level 2: drawVector, drawCovector, drawSegment
|
|
|
|
|
|
|
|
static point_t vectorToPoint(DrawingContext *ctx, vector_t in)
|
|
|
|
{
|
|
|
|
double x[3];
|
|
|
|
point_t out;
|
|
|
|
|
|
|
|
LOOP(i) x[i] = 0.0;
|
|
|
|
LOOP(i) LOOP(j) x[i] += gsl_matrix_get(ctx->cob, i, j) * in.x[j];
|
|
|
|
|
|
|
|
out.x = x[0] / x[2];
|
|
|
|
out.y = x[1] / x[2];
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawVector(DrawingContext *ctx, vector_t v)
|
|
|
|
{
|
|
|
|
drawPoint(ctx, vectorToPoint(ctx, v));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawImplicitLine(DrawingContext *ctx, double a, double b, double c)
|
|
|
|
{
|
|
|
|
double norm, lambda;
|
|
|
|
point_t m, s, xminus, xplus;
|
|
|
|
m.x = ctx->dim->center_x;
|
|
|
|
m.y = ctx->dim->center_y;
|
|
|
|
lambda = (a*m.x + b*m.y + c)/(a*a + b*b);
|
|
|
|
s.x = m.x - lambda*a;
|
|
|
|
s.y = m.y - lambda*b;
|
|
|
|
norm = sqrt(a*a + b*b);
|
|
|
|
xminus.x = s.x - ctx->dim->radius * b / norm;
|
|
|
|
xminus.y = s.y + ctx->dim->radius * a / norm;
|
|
|
|
xplus.x = s.x + ctx->dim->radius * b / norm;
|
|
|
|
xplus.y = s.y - ctx->dim->radius * a / norm;
|
|
|
|
|
|
|
|
drawSegment2d(ctx, xminus, xplus);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawCovector(DrawingContext *ctx, vector_t v)
|
|
|
|
{
|
|
|
|
double x[3];
|
|
|
|
double cofactor;
|
|
|
|
|
|
|
|
LOOP(i) x[i] = 0.0;
|
|
|
|
LOOP(i) LOOP(j) {
|
|
|
|
cofactor = gsl_matrix_get(ctx->cob, (i+1)%3, (j+1)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+2)%3)
|
|
|
|
- gsl_matrix_get(ctx->cob, (i+1)%3, (j+2)%3) * gsl_matrix_get(ctx->cob, (i+2)%3, (j+1)%3);
|
|
|
|
x[i] += cofactor * v.x[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
drawImplicitLine(ctx, x[0], x[1], x[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawSegment(DrawingContext *ctx, vector_t a, vector_t b)
|
|
|
|
{
|
|
|
|
drawSegment2d(ctx, vectorToPoint(ctx, a), vectorToPoint(ctx, b));
|
|
|
|
}
|
|
|
|
|
|
|
|
// level 3: boxes and polygons
|
|
|
|
|
2019-02-11 14:20:56 +00:00
|
|
|
void drawPolygon(DrawingContext *ctx, int segments, int sides, ...)
|
2019-02-03 12:18:14 +00:00
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
vector_t first, prev, current;
|
|
|
|
|
|
|
|
va_start(args, sides);
|
|
|
|
|
|
|
|
first = va_arg(args, vector_t);
|
|
|
|
current = first;
|
|
|
|
for(int i = 0; i < sides-1; i++) {
|
|
|
|
prev = current;
|
|
|
|
current = va_arg(args, vector_t);
|
2019-02-11 14:20:56 +00:00
|
|
|
if(segments)
|
|
|
|
drawSegment(ctx, prev, current);
|
|
|
|
else
|
|
|
|
drawCovector(ctx, cross(prev, current));
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
2019-02-11 14:20:56 +00:00
|
|
|
if(segments)
|
|
|
|
drawSegment(ctx, current, first);
|
|
|
|
else
|
|
|
|
drawCovector(ctx, cross(current, first));
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawTriangle(DrawingContext *ctx, const char *word)
|
|
|
|
{
|
|
|
|
vector_t p[3];
|
|
|
|
|
|
|
|
fixedPoints(ctx, word, p);
|
2019-02-11 14:20:56 +00:00
|
|
|
drawPolygon(ctx, 1, 3, p[0], p[1], p[2]);
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void drawBox(DrawingContext *ctx, const char *word1, const char *word2)
|
|
|
|
{
|
|
|
|
vector_t p[2][3],i[2];
|
|
|
|
|
|
|
|
fixedPoints(ctx, word1, p[0]);
|
|
|
|
fixedPoints(ctx, word2, p[1]);
|
|
|
|
|
|
|
|
// intersect attracting line with neutral line of the other element
|
|
|
|
for(int j = 0; j < 2; j++)
|
|
|
|
i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
|
|
|
|
|
2019-02-11 14:20:56 +00:00
|
|
|
drawPolygon(ctx, 1, 4, p[0][0], i[0], p[1][0], i[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawBoxLines(DrawingContext *ctx, const char *word1, const char *word2)
|
|
|
|
{
|
|
|
|
vector_t p[2][3],i[2];
|
|
|
|
|
|
|
|
fixedPoints(ctx, word1, p[0]);
|
|
|
|
fixedPoints(ctx, word2, p[1]);
|
|
|
|
|
|
|
|
// intersect attracting line with neutral line of the other element
|
|
|
|
for(int j = 0; j < 2; j++)
|
|
|
|
i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
|
|
|
|
|
|
|
|
drawPolygon(ctx, 0, 4, p[0][0], i[0], p[1][0], i[1]);
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
|
2020-01-11 14:35:47 +00:00
|
|
|
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
void drawBoxStd(DrawingContext *ctx, const char *word, char base)
|
|
|
|
{
|
|
|
|
char word1[100];
|
|
|
|
char word2[100];
|
|
|
|
|
|
|
|
int len = strlen(word);
|
|
|
|
if(len*2 + 4 > 100)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(int i = 0; i < len; i++) {
|
|
|
|
word1[i] = word1[2*len+2-i] = word[i];
|
|
|
|
word2[i] = word2[2*len+2-i] = word[i];
|
|
|
|
}
|
|
|
|
word1[2*len+3] = 0;
|
|
|
|
word2[2*len+3] = 0;
|
|
|
|
|
|
|
|
LOOP(i) word1[len+i] = (base-'A'+6+i+1)%3+'a';
|
|
|
|
LOOP(i) word2[len+i] = (base-'A'+6-i-1)%3+'a';
|
|
|
|
|
|
|
|
// printf("Words: %s %s\n", word1, word2);
|
|
|
|
|
|
|
|
drawBox(ctx, word1, word2);
|
|
|
|
}
|
|
|
|
|
2019-04-12 09:51:57 +00:00
|
|
|
void drawRotationOrbit(DrawingContext *ctx, const char *word, vector_t start)
|
|
|
|
{
|
|
|
|
vector_t v[3], w;
|
|
|
|
point_t p;
|
2019-12-23 11:29:50 +00:00
|
|
|
double parameter, startangle;
|
2019-04-12 09:51:57 +00:00
|
|
|
int iterations = 200;
|
|
|
|
gsl_matrix *frame = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix *inverse = getTempMatrix(ctx->ws);
|
|
|
|
gsl_vector *start_v = getTempVector(ctx->ws);
|
|
|
|
gsl_vector *start_in_frame = getTempVector(ctx->ws);
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
computeRotationMatrix(ctx, frame, word);
|
|
|
|
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
|
|
|
|
|
|
|
|
LOOP(i) gsl_vector_set(start_v, i, start.x[i]);
|
|
|
|
solve(frame, start_v, start_in_frame, ctx->ws);
|
|
|
|
parameter = gsl_vector_get(start_in_frame, 2);
|
|
|
|
parameter /= sqrt(gsl_vector_get(start_in_frame, 0)*gsl_vector_get(start_in_frame, 0) +
|
|
|
|
gsl_vector_get(start_in_frame, 1)*gsl_vector_get(start_in_frame, 1));
|
2019-12-23 11:29:50 +00:00
|
|
|
startangle = atan2(gsl_vector_get(start_in_frame, 1), gsl_vector_get(start_in_frame, 0));
|
|
|
|
|
|
|
|
int previous_inside = 0;
|
|
|
|
for(int k = 0; k <= iterations; k++) {
|
|
|
|
LOOP(i) w.x[i] = parameter * v[2].x[i] + cos(2*k*M_PI/iterations) * v[0].x[i] + sin(2*k*M_PI/iterations) * v[1].x[i];
|
|
|
|
p = vectorToPoint(ctx, w);
|
|
|
|
|
|
|
|
if(isInsideBB(ctx, p)) {
|
|
|
|
if(!previous_inside)
|
|
|
|
cairo_move_to(C, p.x, p.y);
|
|
|
|
else
|
|
|
|
cairo_line_to(C, p.x, p.y);
|
|
|
|
previous_inside = 1;
|
|
|
|
} else {
|
|
|
|
previous_inside = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_stroke(C);
|
|
|
|
|
|
|
|
releaseTempMatrices(ctx->ws, 2);
|
|
|
|
releaseTempVectors(ctx->ws, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawDualRotationOrbit(DrawingContext *ctx, const char *word, vector_t start)
|
|
|
|
{
|
|
|
|
vector_t v[3], w;
|
|
|
|
point_t p;
|
|
|
|
double parameter, startangle;
|
|
|
|
int iterations = 200;
|
|
|
|
gsl_matrix *frame = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix *inverse = getTempMatrix(ctx->ws);
|
|
|
|
gsl_vector *start_v = getTempVector(ctx->ws);
|
|
|
|
gsl_vector *start_in_frame = getTempVector(ctx->ws);
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
computeRotationMatrix(ctx, frame, word);
|
|
|
|
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
|
|
|
|
|
|
|
|
LOOP(i) gsl_vector_set(start_v, i, start.x[i]);
|
|
|
|
// solve(frame, start_v, start_in_frame, ctx->ws);
|
|
|
|
gsl_blas_dgemv(CblasTrans, 1.0, frame, start_v, 0.0, start_in_frame);
|
|
|
|
parameter = sqrt(gsl_vector_get(start_in_frame, 0)*gsl_vector_get(start_in_frame, 0) +
|
|
|
|
gsl_vector_get(start_in_frame, 1)*gsl_vector_get(start_in_frame, 1));
|
|
|
|
parameter /= gsl_vector_get(start_in_frame, 2);
|
|
|
|
startangle = atan2(gsl_vector_get(start_in_frame, 1), gsl_vector_get(start_in_frame, 0));
|
2019-04-12 09:51:57 +00:00
|
|
|
|
|
|
|
int previous_inside = 0;
|
|
|
|
for(int k = 0; k <= iterations; k++) {
|
|
|
|
LOOP(i) w.x[i] = parameter * v[2].x[i] + cos(2*k*M_PI/iterations) * v[0].x[i] + sin(2*k*M_PI/iterations) * v[1].x[i];
|
|
|
|
p = vectorToPoint(ctx, w);
|
|
|
|
|
|
|
|
if(isInsideBB(ctx, p)) {
|
|
|
|
if(!previous_inside)
|
|
|
|
cairo_move_to(C, p.x, p.y);
|
|
|
|
else
|
|
|
|
cairo_line_to(C, p.x, p.y);
|
|
|
|
previous_inside = 1;
|
|
|
|
} else {
|
|
|
|
previous_inside = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_stroke(C);
|
|
|
|
|
|
|
|
releaseTempMatrices(ctx->ws, 2);
|
|
|
|
releaseTempVectors(ctx->ws, 2);
|
|
|
|
}
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
void drawArc(DrawingContext *ctx, const char *word, vector_t start, vector_type_t starttype, vector_t end, vector_type_t endtype, vector_t third, int contain)
|
|
|
|
{
|
|
|
|
vector_t v[3], w;
|
|
|
|
point_t p;
|
|
|
|
double radius, angle_start, angle_end, angle_third, angle, angle_end_delta, sign, angle_start_final, angle_end_final, angle_end_other;
|
|
|
|
int iterations = 200;
|
|
|
|
gsl_matrix *frame = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix *inverse = getTempMatrix(ctx->ws);
|
|
|
|
gsl_vector *vector = getTempVector(ctx->ws);
|
|
|
|
gsl_vector *vector_in_frame = getTempVector(ctx->ws);
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
computeRotationMatrix(ctx, frame, word);
|
|
|
|
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(frame, j, i);
|
|
|
|
|
|
|
|
LOOP(i) gsl_vector_set(vector, i, start.x[i]);
|
|
|
|
if(starttype == VT_POINT) {
|
|
|
|
solve(frame, vector, vector_in_frame, ctx->ws);
|
|
|
|
radius = sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) +
|
|
|
|
gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1));
|
|
|
|
radius /= fabs(gsl_vector_get(vector_in_frame, 2));
|
|
|
|
angle_start = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2),
|
|
|
|
gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2));
|
|
|
|
} else {
|
|
|
|
gsl_blas_dgemv(CblasTrans, 1.0, frame, vector, 0.0, vector_in_frame);
|
|
|
|
radius = fabs(gsl_vector_get(vector_in_frame, 2));
|
|
|
|
radius /= sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) +
|
|
|
|
gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1));
|
|
|
|
|
|
|
|
angle_start = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2),
|
|
|
|
gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
LOOP(i) gsl_vector_set(vector, i, third.x[i]);
|
|
|
|
solve(frame, vector, vector_in_frame, ctx->ws);
|
|
|
|
angle_third = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2),
|
|
|
|
gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2));
|
|
|
|
|
|
|
|
LOOP(i) gsl_vector_set(vector, i, end.x[i]);
|
|
|
|
if(endtype == VT_POINT) {
|
|
|
|
solve(frame, vector, vector_in_frame, ctx->ws);
|
|
|
|
angle_end = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2),
|
|
|
|
gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2));
|
|
|
|
} else {
|
|
|
|
gsl_blas_dgemv(CblasTrans, 1.0, frame, vector, 0.0, vector_in_frame);
|
|
|
|
|
|
|
|
// this is only the average angle
|
|
|
|
angle_end = atan2(gsl_vector_get(vector_in_frame, 1)/gsl_vector_get(vector_in_frame, 2),
|
|
|
|
gsl_vector_get(vector_in_frame, 0)/gsl_vector_get(vector_in_frame, 2));
|
|
|
|
|
|
|
|
angle_end_delta = acos(-fabs(gsl_vector_get(vector_in_frame, 2))/radius/
|
|
|
|
sqrt(gsl_vector_get(vector_in_frame, 0)*gsl_vector_get(vector_in_frame, 0) +
|
|
|
|
gsl_vector_get(vector_in_frame, 1)*gsl_vector_get(vector_in_frame, 1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
int previous_inside = 0;
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
|
|
angle_start_final = angle_start;
|
|
|
|
|
|
|
|
if(endtype == VT_POINT) {
|
|
|
|
angle_end_final = angle_end;
|
|
|
|
} else {
|
|
|
|
if(i >= 2) {
|
|
|
|
angle_end_final = angle_end - angle_end_delta;
|
|
|
|
angle_end_other = angle_end + angle_end_delta;
|
|
|
|
} else {
|
|
|
|
angle_end_final = angle_end + angle_end_delta;
|
|
|
|
angle_end_other = angle_end - angle_end_delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i%2)
|
|
|
|
FLIP(angle_start_final, angle_end_final);
|
|
|
|
|
|
|
|
if(endtype == VT_LINE && ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_end_other))
|
|
|
|
continue;
|
|
|
|
if(contain && !ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_third))
|
|
|
|
continue;
|
|
|
|
if(!contain && ANGLE_IN_INTERVAL(angle_start_final, angle_end_final, angle_third))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int k = 0; k <= iterations; k++) {
|
|
|
|
angle = angle_start_final + (double)k/(double)iterations * ANGLE_DIFF(angle_end_final, angle_start_final);
|
|
|
|
|
|
|
|
LOOP(i) w.x[i] = v[2].x[i] / radius + cos(angle) * v[0].x[i] + sin(angle) * v[1].x[i];
|
|
|
|
p = vectorToPoint(ctx, w);
|
|
|
|
|
|
|
|
if(isInsideBB(ctx, p)) {
|
|
|
|
if(!previous_inside)
|
|
|
|
cairo_move_to(C, p.x, p.y);
|
|
|
|
else
|
|
|
|
cairo_line_to(C, p.x, p.y);
|
|
|
|
previous_inside = 1;
|
|
|
|
} else {
|
|
|
|
previous_inside = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_stroke(C);
|
|
|
|
|
|
|
|
releaseTempMatrices(ctx->ws, 2);
|
|
|
|
releaseTempVectors(ctx->ws, 2);
|
|
|
|
}
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
// level 4: draw the actual image components
|
|
|
|
|
|
|
|
void drawReflectors(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
vector_t v[3];
|
|
|
|
|
|
|
|
cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
|
|
|
|
|
|
|
|
LOOP(i) LOOP(j) { v[i].x[j] = (i==j) ? 1.0 : 0.0; }
|
|
|
|
LOOP(i) drawVector(ctx, v[i]);
|
|
|
|
|
|
|
|
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
|
|
|
|
LOOP(i) drawCovector(ctx, v[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawAttractors(DrawingContext *ctx)
|
|
|
|
{
|
2019-12-23 11:29:50 +00:00
|
|
|
int n = 3;
|
|
|
|
vector_t p[6][3];
|
|
|
|
vector_t l[6][3];
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
fixedPoints(ctx, "abc", p[0]);
|
2019-12-23 11:29:50 +00:00
|
|
|
fixedPoints(ctx, "bca", p[1]);
|
|
|
|
fixedPoints(ctx, "cab", p[2]);
|
|
|
|
fixedPoints(ctx, "a cab a", p[3]);
|
|
|
|
fixedPoints(ctx, "b abc b", p[4]);
|
|
|
|
fixedPoints(ctx, "c bca c", p[5]);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
double color[6][3] = {{1,0,0},{0,0.7,0},{0,0,1},{0,1,1},{0,1,1},{0,1,1}};
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
for(int i = 0; i < n; i++) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
for(int i = 0; i < n; i++) LOOP(j) {
|
2019-02-03 12:18:14 +00:00
|
|
|
cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
|
|
|
|
drawVector(ctx, p[i][j]);
|
|
|
|
}
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
for(int i = 0; i < n; i++) LOOP(j) {
|
2019-02-03 12:18:14 +00:00
|
|
|
cairo_set_source_rgb(ctx->cairo, color[i][0], color[i][1], color[i][2]);
|
|
|
|
drawCovector(ctx, l[i][j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-11 14:35:47 +00:00
|
|
|
char *conjugate_word(const char *word, int modifier, const char *conj, char *buffer)
|
|
|
|
{
|
|
|
|
int wordlen = strlen(word);
|
|
|
|
int conjlen = strlen(conj);
|
|
|
|
|
|
|
|
for(int i = 0; i < conjlen; i++) {
|
|
|
|
buffer[i] = conj[i];
|
|
|
|
buffer[2*conjlen+wordlen-1-i] = conj[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < wordlen; i++) {
|
|
|
|
if(word[i] == ' ')
|
|
|
|
buffer[conjlen+i] = word[i];
|
|
|
|
else
|
|
|
|
buffer[conjlen+i] = (word[i]+modifier-'a')%3 + 'a';
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[2*conjlen + wordlen] = 0;
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawCurvedBox(DrawingContext *ctx, int base, const char *conj)
|
2019-12-23 11:29:50 +00:00
|
|
|
{
|
|
|
|
vector_t p[6][3];
|
|
|
|
vector_t l[2][3];
|
2020-01-11 14:35:47 +00:00
|
|
|
char word[100];
|
|
|
|
int modifier = base - 'A';
|
|
|
|
|
|
|
|
conjugate_word("abc", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[0]);
|
|
|
|
conjugate_word("bca", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[1]);
|
|
|
|
conjugate_word("b abc b", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[2]);
|
|
|
|
conjugate_word("ab abc ba", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[3]);
|
|
|
|
conjugate_word("baca cab acab", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[4]);
|
|
|
|
conjugate_word("abaca cab acaba", modifier, conj, word);
|
|
|
|
fixedPoints(ctx, word, p[5]);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
|
|
|
LOOP(j) l[0][j] = cross(p[0][(3-j)%3], p[0][(4-j)%3]);
|
|
|
|
LOOP(j) l[1][j] = cross(p[1][(3-j)%3], p[1][(4-j)%3]);
|
|
|
|
|
2020-01-11 14:35:47 +00:00
|
|
|
conjugate_word("ab", modifier, conj, word);
|
|
|
|
drawArc(ctx, word, p[0][0], VT_POINT, p[2][0], VT_POINT, p[1][0], 0);
|
|
|
|
conjugate_word("bcab", modifier, conj, word);
|
|
|
|
drawArc(ctx, word, p[2][0], VT_POINT, l[1][0], VT_LINE, p[4][0], 1);
|
|
|
|
conjugate_word("ab", modifier, conj, word);
|
|
|
|
drawArc(ctx, word, p[1][0], VT_POINT, p[3][0], VT_POINT, p[0][0], 0);
|
|
|
|
conjugate_word("abcaba", modifier, conj, word);
|
|
|
|
drawArc(ctx, word, p[3][0], VT_POINT, l[0][0], VT_LINE, p[5][0], 1);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
|
|
|
drawCovector(ctx, l[0][0]);
|
|
|
|
drawCovector(ctx, l[1][0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
void drawBoxes(DrawingContext *ctx)
|
|
|
|
{
|
2019-12-23 11:29:50 +00:00
|
|
|
gsl_matrix *rot = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix **gen = getTempMatrices(ctx->ws, 3);
|
2019-02-03 12:18:14 +00:00
|
|
|
cairo_t *C = ctx->cairo;
|
2020-01-11 14:35:47 +00:00
|
|
|
cairo_save(C);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2020-01-11 14:35:47 +00:00
|
|
|
vector_t p[22][3];
|
2020-06-29 23:59:49 +00:00
|
|
|
vector_t l[22][3];
|
2019-12-23 11:29:50 +00:00
|
|
|
vector_t alpha[6];
|
|
|
|
|
|
|
|
fixedPoints(ctx, "abc", p[0]);
|
|
|
|
fixedPoints(ctx, "bca", p[1]);
|
|
|
|
fixedPoints(ctx, "cab", p[2]);
|
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
fixedPoints(ctx, "abc", p[3]);
|
2020-01-11 14:35:47 +00:00
|
|
|
fixedPoints(ctx, "ab abc ba", p[4]);
|
2020-06-29 23:59:49 +00:00
|
|
|
fixedPoints(ctx, "abab abc baba", p[5]);
|
|
|
|
fixedPoints(ctx, "ababab abc bababa", p[6]);
|
|
|
|
fixedPoints(ctx, "abababab abc babababa", p[7]);
|
|
|
|
fixedPoints(ctx, "babababa abc abababab", p[8]);
|
|
|
|
fixedPoints(ctx, "bababa abc ababab", p[9]);
|
|
|
|
fixedPoints(ctx, "baba abc abab", p[10]);
|
|
|
|
fixedPoints(ctx, "ba abc ab", p[11]);
|
|
|
|
|
|
|
|
fixedPoints(ctx, "bca", p[12]);
|
|
|
|
fixedPoints(ctx, "b abc b", p[13]);
|
|
|
|
fixedPoints(ctx, "bab abc bab", p[14]);
|
|
|
|
fixedPoints(ctx, "babab abc babab", p[15]);
|
|
|
|
fixedPoints(ctx, "bababab abc bababab", p[16]);
|
|
|
|
fixedPoints(ctx, "abababab bca babababa", p[17]);
|
|
|
|
fixedPoints(ctx, "ababab bca bababa", p[18]);
|
|
|
|
fixedPoints(ctx, "abab bca baba", p[19]);
|
|
|
|
fixedPoints(ctx, "ab bca ba", p[20]);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
initializeTriangleGenerators(gen, ctx->cartan);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
for(int i = 0; i < 22; i++) LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]);
|
|
|
|
// LOOP(i) LOOP(j) alpha[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_line_width(C, 2.0/ctx->dim->scalefactor);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_source_rgb(C, 0, 0, 0);
|
|
|
|
drawRotationOrbit(ctx, "ab", p[0][0]);
|
|
|
|
// drawRotationOrbit(ctx, "bc", p[0][0]);
|
|
|
|
|
|
|
|
cairo_set_source_rgb(C, 0.5, 0.5, 1);
|
|
|
|
// drawRotationOrbit(ctx, "ca", p[0][0]);
|
|
|
|
|
|
|
|
for(int i = 0; i < 18; i++) {
|
|
|
|
if(i == 0)
|
|
|
|
cairo_set_source_rgb(C, 1, 0, 0);
|
|
|
|
else if(i == 8 || i == 10)
|
|
|
|
cairo_set_source_rgb(C, 0, 0, 1);
|
|
|
|
else if(i == 9)
|
|
|
|
cairo_set_source_rgb(C, 0, 0.6, 0);
|
|
|
|
else
|
|
|
|
cairo_set_source_rgb(C, 0, 0, 0);
|
|
|
|
drawVector(ctx, p[3+i][0]);
|
|
|
|
drawCovector(ctx, l[3+i][0]);
|
|
|
|
}
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_source_rgb(C, 0, 0, 1.0);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// drawRotationOrbit(ctx, "ab", cross(l[0][0], l[2][1]));
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// drawRotationOrbit(ctx, "abca", p[0][0]);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_restore(C);
|
|
|
|
releaseTempMatrices(ctx->ws, 4);
|
|
|
|
}
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
void drawBoxes2(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
gsl_matrix *rot = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix **gen = getTempMatrices(ctx->ws, 3);
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
cairo_save(C);
|
|
|
|
initializeTriangleGenerators(gen, ctx->cartan);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
int p = 9;
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
vector_t fp[3][3],neutral_line[3],reflection_line[p],star[2*p],outer[2];
|
|
|
|
vector_t rotation_line = {0,0,1};
|
2020-01-11 14:35:47 +00:00
|
|
|
|
|
|
|
cairo_set_line_width(C, 1.5/ctx->dim->scalefactor);
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_source_rgb(C, 1, 0, 0);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
multiply(gen[0], gen[1], rot);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
fixedPoints(ctx, "abc", fp[0]);
|
|
|
|
fixedPoints(ctx, "bca", fp[1]);
|
|
|
|
fixedPoints(ctx, "cab", fp[2]);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
LOOP(i) neutral_line[i] = cross(fp[i][0], fp[i][2]);
|
|
|
|
LOOP(j) reflection_line[0].x[j] = gsl_matrix_get(ctx->cartan, 0, j);
|
|
|
|
star[0] = cross(neutral_line[0],reflection_line[0]);
|
|
|
|
star[p] = cross(neutral_line[2],reflection_line[0]);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
for(int j = 1; j < p; j++) {
|
|
|
|
reflection_line[j] = apply_transpose(rot, reflection_line[j-1]);
|
|
|
|
star[j] = apply(rot, star[j-1]);
|
|
|
|
star[j+p] = apply(rot, star[j+p-1]);
|
|
|
|
}
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
outer[0] = cross(neutral_line[0],reflection_line[5]);
|
|
|
|
outer[1] = cross(neutral_line[2],reflection_line[5]);
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
for(int j = 0; j < 8; j++) {
|
|
|
|
drawVector(ctx, star[j]);
|
|
|
|
drawVector(ctx, star[p+j]);
|
|
|
|
}
|
2020-01-11 14:35:47 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
for(int j = 0; j < 7; j++) {
|
|
|
|
// if(j == 3)
|
|
|
|
// continue;
|
|
|
|
drawSegment(ctx, star[j%p], star[(j+1)%p+p]);
|
|
|
|
drawSegment(ctx, star[(j+1)%p+p], star[(j+1)%p]);
|
|
|
|
drawSegment(ctx, star[(j+1)%p], star[j%p+p]);
|
|
|
|
drawSegment(ctx, star[j%p+p], star[j%p]);
|
|
|
|
}
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_source_rgb(C, 0, 0, 1);
|
|
|
|
drawVector(ctx,outer[0]);
|
|
|
|
drawVector(ctx,outer[1]);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// drawCovector(ctx, neutral_line[0]);
|
|
|
|
// drawCovector(ctx, neutral_line[2]);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
drawSegment(ctx, star[0], star[p]);
|
|
|
|
drawSegment(ctx, star[p], outer[1]);
|
|
|
|
drawSegment(ctx, outer[1], outer[0]);
|
|
|
|
drawSegment(ctx, outer[0], star[0]);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
cairo_set_source_rgb(C, 0, 0, 0);
|
|
|
|
drawCovector(ctx, rotation_line);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// for(int j = 0; j < 5; j++)
|
|
|
|
// drawCovector(ctx, reflection_line[j]);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// intersect attracting line with neutral line of the other element
|
|
|
|
// for(int j = 0; j < 2; j++)
|
|
|
|
// i[j] = cross(cross(p[j%2][0],p[j%2][1]),cross(p[(j+1)%2][0],p[(j+1)%2][2]));
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
// drawPolygon(ctx, 1, 4, p[0][0], i[0], p[1][0], i[1]);
|
2019-02-24 07:43:52 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
// abc, ababcba, abababcbaba, ..., cab
|
|
|
|
// bca, acaba, abacababa, ..., babcb
|
2020-06-29 23:59:49 +00:00
|
|
|
/*
|
2019-12-23 11:29:50 +00:00
|
|
|
vector_t v[4][3];
|
|
|
|
vector_t i[4];
|
|
|
|
|
|
|
|
fixedPoints(ctx, "abc", v[0]);
|
|
|
|
fixedPoints(ctx, "bca", v[1]);
|
|
|
|
fixedPoints(ctx, "cab", v[2]);
|
|
|
|
fixedPoints(ctx, "acaba", v[3]);
|
|
|
|
i[0] = cross(cross(v[0][1],v[0][2]),cross(v[2][0],v[2][2]));
|
|
|
|
i[1] = cross(cross(v[1][1],v[1][2]),cross(v[3][0],v[3][2]));
|
|
|
|
i[2] = cross(cross(v[2][0],v[2][2]),cross(v[3][0],v[3][2]));
|
|
|
|
i[3] = cross(cross(v[0][0],v[0][2]),cross(v[1][0],v[1][2]));
|
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
// cairo_set_source_rgb(C, 0, 0, 1);
|
2019-12-23 11:29:50 +00:00
|
|
|
// drawPolygon(ctx, 1, 6, v[2][2], v[1][1], v[0][1], v[3][2], v[3][1], v[2][1]);
|
|
|
|
// drawPolygon(ctx, 1, 6, v[1][2], i[1], i[2], i[0], v[0][2], i[3]);
|
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
cairo_set_line_width(C, 1.5/ctx->dim->scalefactor);
|
2019-12-23 11:29:50 +00:00
|
|
|
cairo_set_source_rgb(C, 1, 0, 0);
|
2020-06-29 23:59:49 +00:00
|
|
|
// drawBox(ctx, "bca", "abc");
|
2020-03-11 15:35:38 +00:00
|
|
|
|
2020-06-29 23:59:49 +00:00
|
|
|
drawCurvedBox(ctx, 'A', "");
|
|
|
|
*/
|
|
|
|
/*
|
2019-12-23 11:29:50 +00:00
|
|
|
cairo_set_source_rgb(C, 1, 0.5, 0);
|
|
|
|
drawBox(ctx, "ab abc ba", "ab cab ba");
|
|
|
|
drawBox(ctx, "abab abc baba", "abab cab baba");
|
|
|
|
drawBox(ctx, "ababab abc bababa", "ababab cab bababa");
|
|
|
|
drawBox(ctx, "abababab abc babababa", "abababab cab babababa");
|
2020-03-11 15:35:38 +00:00
|
|
|
// drawBox(ctx, "ababababab abc bababababa", "ababababab cab bababababa");
|
|
|
|
drawBox(ctx, "b abc b", "b cab b");
|
|
|
|
drawBox(ctx, "bab abc bab", "bab cab bab");
|
|
|
|
drawBox(ctx, "babab abc babab", "babab cab babab");
|
|
|
|
drawBox(ctx, "bababab abc bababab", "bababab cab bababab");
|
|
|
|
// drawBox(ctx, "babababab abc babababab", "babababab cab babababab");
|
2020-06-29 23:59:49 +00:00
|
|
|
*/
|
2019-12-23 11:29:50 +00:00
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
cairo_restore(C);
|
2019-12-23 11:29:50 +00:00
|
|
|
releaseTempMatrices(ctx->ws, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawRotatedReflectors(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
gsl_matrix *rot = getTempMatrix(ctx->ws);
|
|
|
|
gsl_matrix **gen = getTempMatrices(ctx->ws, 3);
|
|
|
|
cairo_t *C = ctx->cairo;
|
2019-04-12 09:51:57 +00:00
|
|
|
vector_t fp[3], fp2[3];
|
|
|
|
vector_t w;
|
2019-12-23 11:29:50 +00:00
|
|
|
vector_t v[3];
|
|
|
|
|
|
|
|
cairo_set_source_rgb(C, 0.7, 0.7, 0.7);
|
|
|
|
|
|
|
|
initializeTriangleGenerators(gen, ctx->cartan);
|
|
|
|
|
|
|
|
LOOP(i) LOOP(j) v[i].x[j] = gsl_matrix_get(ctx->cartan, i, j);
|
|
|
|
multiply(gen[0], gen[1], rot);
|
|
|
|
|
|
|
|
for(int j = 0; j < ctx->p[2]; j++) {
|
|
|
|
drawCovector(ctx, v[0]);
|
|
|
|
v[0] = apply_transpose(rot, v[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOOP(i) LOOP(j) { v[i].x[j] = (i==j) ? 1.0 : 0.0; }
|
|
|
|
|
|
|
|
for(int j = 0; j < ctx->p[2]; j++) {
|
|
|
|
drawVector(ctx, v[0]);
|
|
|
|
v[0] = apply(rot, v[0]);
|
|
|
|
}
|
2019-02-08 12:03:05 +00:00
|
|
|
|
2019-04-12 09:51:57 +00:00
|
|
|
fixedPoints(ctx, "cab", fp);
|
2019-12-23 11:29:50 +00:00
|
|
|
fixedPoints(ctx, "cacabac", fp2);
|
|
|
|
drawRotationOrbit(ctx, "ac", fp[0]);
|
2019-02-08 12:03:05 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
releaseTempMatrices(ctx->ws, 4);
|
|
|
|
}
|
2019-02-08 12:03:05 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
void drawDualLimitCurve(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
cairo_save(C);
|
2019-04-12 09:51:57 +00:00
|
|
|
cairo_set_source_rgb(C, 0, 0, 0);
|
2019-02-11 14:20:56 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
int n = 18;
|
2020-03-11 15:35:38 +00:00
|
|
|
vector_t p[n][3];
|
2019-12-23 11:29:50 +00:00
|
|
|
vector_t l[n][3];
|
2019-02-08 12:03:05 +00:00
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
fixedPoints(ctx, "abc", p[0]);
|
|
|
|
fixedPoints(ctx, "ab abc ba", p[1]);
|
|
|
|
fixedPoints(ctx, "abab abc baba", p[2]);
|
|
|
|
fixedPoints(ctx, "ababab abc bababa", p[3]);
|
|
|
|
fixedPoints(ctx, "abababab abc babababa", p[4]);
|
|
|
|
fixedPoints(ctx, "babababa abc abababab", p[5]);
|
|
|
|
fixedPoints(ctx, "bababa abc ababab", p[6]);
|
|
|
|
fixedPoints(ctx, "baba abc abab", p[7]);
|
|
|
|
fixedPoints(ctx, "ba abc ab", p[8]);
|
|
|
|
|
|
|
|
fixedPoints(ctx, "bca", p[9]);
|
|
|
|
fixedPoints(ctx, "ab bca ba", p[10]);
|
|
|
|
fixedPoints(ctx, "abab bca baba", p[11]);
|
|
|
|
fixedPoints(ctx, "ababab bca bababa", p[12]);
|
|
|
|
fixedPoints(ctx, "abababab bca babababa", p[13]);
|
|
|
|
fixedPoints(ctx, "babababa bca abababab", p[14]);
|
|
|
|
fixedPoints(ctx, "bababa bca ababab", p[15]);
|
|
|
|
fixedPoints(ctx, "baba bca abab", p[16]);
|
|
|
|
fixedPoints(ctx, "ba bca ab", p[17]);
|
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
|
|
|
|
/*
|
2019-12-23 11:29:50 +00:00
|
|
|
fixedPoints(ctx, "abc", p[0]);
|
|
|
|
fixedPoints(ctx, "ac abc ca", p[1]);
|
|
|
|
fixedPoints(ctx, "acac abc caca", p[2]);
|
|
|
|
fixedPoints(ctx, "acacac abc cacaca", p[3]);
|
|
|
|
fixedPoints(ctx, "acacacac abc cacacaca", p[4]);
|
|
|
|
fixedPoints(ctx, "cacacaca abc acacacac", p[5]);
|
|
|
|
fixedPoints(ctx, "cacaca abc acacac", p[6]);
|
|
|
|
fixedPoints(ctx, "caca abc acac", p[7]);
|
|
|
|
fixedPoints(ctx, "ca abc ac", p[8]);
|
|
|
|
|
|
|
|
fixedPoints(ctx, "bca", p[9]);
|
|
|
|
fixedPoints(ctx, "ac bca ca", p[10]);
|
|
|
|
fixedPoints(ctx, "acac bca caca", p[11]);
|
|
|
|
fixedPoints(ctx, "acacac bca cacaca", p[12]);
|
|
|
|
fixedPoints(ctx, "acacacac bca cacacaca", p[13]);
|
|
|
|
fixedPoints(ctx, "cacacaca bca acacacac", p[14]);
|
|
|
|
fixedPoints(ctx, "cacaca bca acacac", p[15]);
|
|
|
|
fixedPoints(ctx, "caca bca acac", p[16]);
|
|
|
|
fixedPoints(ctx, "ca bca ac", p[17]);
|
2020-03-11 15:35:38 +00:00
|
|
|
*/
|
2019-12-23 11:29:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
fixedPoints(ctx, "cab", p[2]);
|
|
|
|
fixedPoints(ctx, "b abc b", p[3]);
|
|
|
|
fixedPoints(ctx, "c bca c", p[4]);
|
|
|
|
fixedPoints(ctx, "a cab a", p[5]);
|
|
|
|
*/
|
|
|
|
|
|
|
|
for(int i = 0; i < n; i++) {
|
|
|
|
LOOP(j) l[i][j] = cross(p[i][(3-j)%3], p[i][(4-j)%3]);
|
2020-03-11 15:35:38 +00:00
|
|
|
drawCovector(ctx, l[i][0]);
|
2019-12-23 11:29:50 +00:00
|
|
|
drawCovector(ctx, l[i][2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_restore(C);
|
2019-02-08 12:03:05 +00:00
|
|
|
}
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
void drawLimitCurve(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
cairo_save(C);
|
|
|
|
|
2020-03-11 15:35:38 +00:00
|
|
|
cairo_set_source_rgb(C, 0.0, 0.0, 0.0);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(ctx->limit_with_lines) {
|
|
|
|
int previous_inside = 0;
|
|
|
|
for(int i = 0; i < ctx->limit_curve_count; i++) {
|
|
|
|
point_t p;
|
|
|
|
p.x = ctx->limit_curve[3*i];
|
|
|
|
p.y = ctx->limit_curve[3*i+1];
|
|
|
|
|
|
|
|
if(isInsideBB(ctx, p)) {
|
2019-02-03 12:18:14 +00:00
|
|
|
if(!previous_inside)
|
2019-04-12 09:51:57 +00:00
|
|
|
cairo_move_to(C, p.x, p.y);
|
2019-02-03 12:18:14 +00:00
|
|
|
else
|
2019-04-12 09:51:57 +00:00
|
|
|
cairo_line_to(C, p.x, p.y);
|
2019-12-23 11:29:50 +00:00
|
|
|
previous_inside = 1;
|
2019-02-03 12:18:14 +00:00
|
|
|
} else {
|
2019-12-23 11:29:50 +00:00
|
|
|
previous_inside = 0;
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
cairo_stroke(C);
|
|
|
|
} else {
|
|
|
|
for(int i = 0; i < ctx->limit_curve_count; i++) {
|
|
|
|
point_t p;
|
|
|
|
p.x = ctx->limit_curve[3*i];
|
|
|
|
p.y = ctx->limit_curve[3*i+1];
|
2019-02-03 12:18:14 +00:00
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(isInsideBB(ctx, p)) {
|
2020-03-11 15:35:38 +00:00
|
|
|
cairo_arc(C, p.x, p.y, 0.5/ctx->dim->scalefactor, 0, 2*M_PI);
|
2019-12-23 11:29:50 +00:00
|
|
|
cairo_close_path(C);
|
|
|
|
cairo_fill(C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
cairo_restore(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawText(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
cairo_move_to(ctx->cairo, 15, 30);
|
|
|
|
cairo_set_source_rgb(ctx->cairo, 0, 0, 0);
|
|
|
|
char buf[100];
|
|
|
|
sprintf(buf, "t = exp(%.8f) = %.8f", log(ctx->parameter), ctx->parameter);
|
|
|
|
cairo_show_text(ctx->cairo, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
// level 5: put everything together
|
|
|
|
|
|
|
|
void draw(DrawingContext *ctx)
|
|
|
|
{
|
|
|
|
cairo_t *C = ctx->cairo;
|
|
|
|
|
|
|
|
cairo_set_source_rgb(C, 1, 1, 1);
|
|
|
|
cairo_paint(C);
|
|
|
|
|
|
|
|
cairo_set_matrix(C, &ctx->dim->matrix);
|
|
|
|
|
|
|
|
// defaults; use save/restore whenever these are changed
|
|
|
|
cairo_set_line_width(C, 1.0/ctx->dim->scalefactor);
|
|
|
|
cairo_set_font_size(C, 16);
|
|
|
|
cairo_set_line_join(C, CAIRO_LINE_JOIN_BEVEL);
|
|
|
|
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(ctx->limit_curve_count >= 0) {
|
2019-02-03 12:18:14 +00:00
|
|
|
if(ctx->show_limit)
|
|
|
|
drawLimitCurve(ctx);
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(ctx->show_dual_limit)
|
|
|
|
drawDualLimitCurve(ctx);
|
2019-02-08 12:03:05 +00:00
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
if(ctx->show_attractors)
|
|
|
|
drawAttractors(ctx);
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(ctx->show_rotated_reflectors)
|
|
|
|
drawRotatedReflectors(ctx);
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
if(ctx->show_reflectors)
|
|
|
|
drawReflectors(ctx);
|
2019-12-23 11:29:50 +00:00
|
|
|
|
|
|
|
if(ctx->show_boxes)
|
|
|
|
drawBoxes(ctx);
|
|
|
|
|
|
|
|
if(ctx->show_boxes2)
|
|
|
|
drawBoxes2(ctx);
|
|
|
|
|
2019-02-03 12:18:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cairo_identity_matrix(C); // text is in screen coordinates
|
|
|
|
|
2019-12-23 11:29:50 +00:00
|
|
|
if(ctx->show_text)
|
|
|
|
drawText(ctx);
|
2019-02-03 12:18:14 +00:00
|
|
|
|
|
|
|
cairo_surface_flush(cairo_get_target(C));
|
|
|
|
}
|