YouTube-simulations/sub_part_billiard.c

8356 lines
264 KiB
C

#include "colormaps.c"
#define DUMMY_ABSORBING 100000.0 /* dummy value of config[0] for absorbing circles */
#define BOUNDARY_SHIFT 10000.0 /* shift of boundary parametrisation for circles in domain */
#define DUMMY_SIDE_ABS -100000 /* dummy value of returned side for absorbing circles */
#define MAZE_VERTICAL_EXTENSION 1.0e10 /* extension of vertical lines in some mazes */
long int global_time = 0; /* counter to keep track of global time of simulation */
int nparticles=NPART;
/*********************/
/* some basic math */
/*********************/
double vabs(double x) /* absolute value */
{
double res;
if (x<0.0) res = -x;
else res = x;
return(res);
}
double module2(double x, double y) /* Euclidean norm */
{
double m;
m = sqrt(x*x + y*y);
return(m);
}
double argument(double x, double y)
{
double alph;
if (x!=0.0)
{
alph = atan(y/x);
if (x<0.0)
alph += PI;
}
else
{
alph = PID;
if (y<0.0)
alph = PI*1.5;
}
// if (alph < 0.0) alph += DPI;
return(alph);
}
int polynome(double a, double b, double c, double r[2])
{
double delta, rdelta;
int im = 1;
delta = b*b - 4*a*c;
if (delta<0.0)
{
/* printf("ca deconne!");*/
rdelta = 0.0;
im = 0;
}
else rdelta = sqrt(delta);
r[0] = (-b + rdelta)/(2.0*a);
r[1] = (-b - rdelta)/(2.0*a);
return(im);
}
double ipow(double x, int n)
{
double y;
int i;
y = x;
for (i=1; i<n; i++) y *= x;
return(y);
}
/*********************/
/* Graphics routines */
/*********************/
int writetiff(char *filename, char *description, int x, int y, int width, int height, int compression)
{
TIFF *file;
GLubyte *image, *p;
int i;
static int mem_counter = 0;
file = TIFFOpen(filename, "w");
if (file == NULL)
{
return 1;
}
image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3);
/* OpenGL's default 4 byte pack alignment would leave extra bytes at the
end of each image row so that each full row contained a number of bytes
divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would
be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist
just to pad the row out to 12 bytes (12 is divisible by 4). To make sure
the rows are packed as tight as possible (no row padding), set the pack
alignment to 1. */
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32_t) width);
TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32_t) height);
TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(file, TIFFTAG_COMPRESSION, compression);
TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(file, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1);
TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, description);
p = image;
for (i = height - 1; i >= 0; i--)
{
// if (TIFFWriteScanline(file, p, height - i - 1, 0) < 0)
if (TIFFWriteScanline(file, p, i, 0) < 0)
{
free(image);
TIFFClose(file);
return 1;
}
p += width * sizeof(GLubyte) * 3;
}
TIFFClose(file);
/* to avoid RAM overflow */
if (SAVE_MEMORY) free(image);
// mem_counter++;
// if (mem_counter >= 12)
// {
// free(image);
// mem_counter = 0;
// }
return 0;
}
void init() /* initialisation of window */
{
glLineWidth(3);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glOrtho(XMIN, XMAX, YMIN, YMAX , -1.0, 1.0);
}
void rgb_color_scheme(int i, double rgb[3]) /* color scheme */
{
double hue, y, r;
hue = (double)(COLORSHIFT + i*360/NCOLORS);
r = 0.9;
while (hue < 0.0) hue += 360.0;
while (hue >= 360.0) hue -= 360.0;
hsl_to_rgb(hue, r, 0.5, rgb);
/* saturation = r, luminosity = 0.5 */
}
void rgb_color_scheme_minmax(int i, double rgb[3])
/* color scheme with specified color interval */
{
double hue, y, r;
int delta_hue;
delta_hue = COLOR_HUEMAX - COLOR_HUEMIN;
hue = (double)(COLOR_HUEMIN + i*delta_hue/NCOLORS);
r = 0.9;
while (hue < COLOR_HUEMIN) hue += delta_hue;
while (hue >= COLOR_HUEMAX) hue -= delta_hue;
hsl_to_rgb(hue, r, 0.5, rgb);
/* saturation = r, luminosity = 0.5 */
}
void rgb_color_scheme_density(int part_number, double rgb[3], double minprop)
/* color scheme with specified color interval */
{
int k;
double hue, y, r, logprop, logmin;
if (part_number < 0) for (k=0; k<3; k++) rgb[k] = 0.25; /* visited cells */
else
{
if (part_number<=1) hue = COLOR_HUEMAX;
else
{
logmin = log(minprop*(double)NPART);
if (logmin > 0.0) logprop = log((double)part_number)/logmin + 0.01;
else (logprop = 0.0);
if (logprop > 1.0) logprop = 1.0;
if (logprop < 0.0) logprop = 0.0;
hue = COLOR_HUEMAX + (COLOR_HUEMIN - COLOR_HUEMAX)*logprop;
}
r = 0.9;
hsl_to_rgb(hue, r, 0.5, rgb);
/* saturation = r, luminosity = 0.5 */
}
}
void rgb_color_scheme_lum(int i, double lum, double rgb[3]) /* color scheme */
{
double hue, y, r;
hue = (double)(COLORSHIFT + i*360/NCOLORS);
r = 0.9;
while (hue < 0.0) hue += 360.0;
while (hue >= 360.0) hue -= 360.0;
hsl_to_rgb(hue, r, lum, rgb);
/* saturation = r */
}
void rgb_color_scheme_minmax_lum(int i, double lum, double rgb[3])
/* color scheme with specified color interval */
{
double hue, y, r;
int delta_hue;
delta_hue = COLOR_HUEMAX - COLOR_HUEMIN;
hue = (double)(COLOR_HUEMIN + i*delta_hue/NCOLORS);
r = 0.9;
while (hue < COLOR_HUEMIN) hue += delta_hue;
while (hue >= COLOR_HUEMAX) hue -= delta_hue;
hsl_to_rgb(hue, r, lum, rgb);
/* saturation = r */
}
void blank()
{
double rgb[3];
if (COLOR_OUTSIDE)
{
hsl_to_rgb(OUTER_COLOR, 0.9, 0.15, rgb);
glClearColor(rgb[0], rgb[1], rgb[2], 1.0);
}
else if (BLACK) glClearColor(0.0, 0.0, 0.0, 1.0);
else glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
void save_frame()
{
static int counter = 0;
char *name="part.", n2[100];
char format[6]=".%05i";
counter++;
// printf (" p2 counter = %d \n",counter);
strcpy(n2, name);
sprintf(strstr(n2,"."), format, counter);
strcat(n2, ".tif");
printf(" saving frame %s \n",n2);
writetiff(n2, "Billiard in an ellipse", 0, 0,
WINWIDTH, WINHEIGHT, COMPRESSION_LZW);
}
void save_frame_counter(int counter)
{
char *name="part.", n2[100];
char format[6]=".%05i";
strcpy(n2, name);
sprintf(strstr(n2,"."), format, counter);
strcat(n2, ".tif");
printf(" saving frame %s \n",n2);
writetiff(n2, "Billiard in an ellipse", 0, 0,
WINWIDTH, WINHEIGHT, COMPRESSION_LZW);
}
void write_text_fixedwidth( double x, double y, char *st)
{
int l, i;
l=strlen( st ); // see how many characters are in text string.
glRasterPos2d( x, y); // location to start printing text
for( i=0; i < l; i++) // loop until i is greater then l
{
// glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, st[i]); // Print a character on the screen
// glutBitmapCharacter(GLUT_BITMAP_8_BY_13, st[i]); // Print a character on the screen
glutBitmapCharacter(GLUT_BITMAP_9_BY_15, st[i]); // Print a character on the screen
}
}
void write_text( double x, double y, char *st)
{
int l,i;
l=strlen( st ); // see how many characters are in text string.
glRasterPos2d( x, y); // location to start printing text
for( i=0; i < l; i++) // loop until i is greater then l
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, st[i]); // Print a character on the screen
// glutBitmapCharacter(GLUT_BITMAP_8_BY_13, st[i]); // Print a character on the screen
}
}
void erase_area(double x, double y, double dx, double dy, double rgb[3])
{
glColor3f(rgb[0], rgb[1], rgb[2]);
glBegin(GL_QUADS);
glVertex2d(x - dx, y - dy);
glVertex2d(x + dx, y - dy);
glVertex2d(x + dx, y + dy);
glVertex2d(x - dx, y + dy);
glEnd();
}
void erase_rectangle(double x1, double y1, double x2, double y2, double rgb[3])
{
glColor3f(rgb[0], rgb[1], rgb[2]);
glBegin(GL_QUADS);
glVertex2d(x1, y1);
glVertex2d(x2, y1);
glVertex2d(x2, y2);
glVertex2d(x1, y2);
glEnd();
}
void erase_rectangle_outside(double h, double s, double l)
{
double rgb[3], dx;
int k;
dx = 0.5*(XMAX - LAMBDA);
hsl_to_rgb(h, s, l, rgb);
erase_rectangle(XMIN, YMIN, XMAX, -1.0, rgb);
erase_rectangle(XMIN, 1.0, XMAX, YMAX, rgb);
erase_rectangle(XMIN, YMIN, -LAMBDA, YMAX, rgb);
erase_rectangle(LAMBDA, YMIN, XMAX, YMAX, rgb);
// erase_area(0.0, 1.1, 2.0, 0.1, rgb);
// erase_area(0.0, -1.1, 2.0, 0.1, rgb);
// erase_area(LAMBDA + dx, 0.0, dx, 2.0, rgb);
// erase_area(-LAMBDA - dx, 0.0, dx, 2.0, rgb);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(BILLIARD_WIDTH);
glBegin(GL_LINE_LOOP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glVertex2d(-LAMBDA, 1.0);
glVertex2d(-LAMBDA, -1.0);
glEnd();
}
void draw_line(double x1, double y1, double x2, double y2)
{
glBegin(GL_LINE_STRIP);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
}
void draw_circle(double x, double y, double r, int nseg)
{
int i;
double phi, dphi, x1, y1;
dphi = DPI/(double)nseg;
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_LOOP);
for (i=0; i<=nseg; i++)
{
phi = (double)i*dphi;
x1 = x + r*cos(phi);
y1 = y + r*sin(phi);
glVertex2d(x1, y1);
}
glEnd ();
}
void draw_colored_circle(double x, double y, double r, int nseg, double rgb[3])
{
int i, ij[2];
double pos[2], alpha, dalpha;
dalpha = DPI/(double)nseg;
// glLineWidth(2);
glColor3f(rgb[0], rgb[1], rgb[2]);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(x,y);
for (i=0; i<=nseg; i++)
{
alpha = (double)i*dalpha;
glVertex2d(x + r*cos(alpha), y + r*sin(alpha));
}
glEnd();
}
void draw_colored_octahedron(double x, double y, double r, double rgb[3])
{
int i, ij[2];
double pos[2], alpha, dalpha;
dalpha = DPI*0.125;
glColor3f(rgb[0], rgb[1], rgb[2]);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(x,y);
for (i=0; i<=8; i++)
{
alpha = ((double)i+0.5)*dalpha;
glVertex2d(x + r*cos(alpha), y + r*sin(alpha));
}
glEnd();
}
void draw_colored_rectangle_rgb(double x1, double y1, double x2, double y2, double rgb[3])
{
glColor3f(rgb[0], rgb[1], rgb[2]);
glBegin(GL_QUADS);
glVertex2d(x1, y1);
glVertex2d(x2, y1);
glVertex2d(x2, y2);
glVertex2d(x1, y2);
glEnd();
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_LOOP);
glVertex2d(x1, y1);
glVertex2d(x2, y1);
glVertex2d(x2, y2);
glVertex2d(x1, y2);
glEnd();
}
void draw_colored_rectangle(double x1, double y1, double x2, double y2, double hue)
{
double rgb[3];
hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE);
draw_colored_rectangle_rgb(x1, y1, x2, y2, rgb);
}
void draw_filled_sector(double x, double y, double rmin, double rmax, double phi1, double dphi, int nseg, double rgb[3])
{
int i;
double alpha, dalpha;
dalpha = dphi/(double)nseg;
glColor3f(rgb[0], rgb[1], rgb[2]);
for (i=0; i<=nseg; i++)
{
alpha = phi1 + (double)i*dalpha;
glBegin(GL_TRIANGLE_FAN);
glVertex2d(x + rmin*cos(alpha), y + rmin*sin(alpha));
glVertex2d(x + rmax*cos(alpha), y + rmax*sin(alpha));
glVertex2d(x + rmax*cos(alpha+dalpha), y + rmax*sin(alpha+dalpha));
glVertex2d(x + rmin*cos(alpha+dalpha), y + rmin*sin(alpha+dalpha));
glEnd();
}
}
void draw_initial_condition_circle(double x, double y, double r, int color)
/* draws a colored circle to mark initial condition */
{
double rgb[3];
rgb_color_scheme(color, rgb);
draw_colored_circle(x, y, r, NSEG, rgb);
rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0;
glColor3f(rgb[0], rgb[1], rgb[2]);
glLineWidth(4);
draw_circle(x, y, r, NSEG);
}
int in_circle(double x, double y, double r)
/* test whether (x,y) is in circle of radius r */
{
return(x*x + y*y < r*r);
}
int out_circle(double x, double y, double r)
/* test whether (x,y) is in circle of radius r */
{
return(x*x + y*y > r*r);
}
int in_polygon(double x, double y, double r, int npoly, double apoly)
/* test whether (x,y) is in regular polygon of npoly sides inscribed in circle of radious r, turned by apoly Pi/2 */
{
int condition = 1, k;
double omega, cw, angle;
omega = DPI/((double)npoly);
cw = cos(omega*0.5);
for (k=0; k<npoly; k++)
{
angle = apoly*PID + (k+0.5)*omega;
condition = condition*(x*cos(angle) + y*sin(angle) < r*cw);
}
return(condition);
}
void compute_flower_parameters(double *omega, double *co, double *so, double *axis1, double *axis2, double *phimax)
/* compute parameters needed for the flower billiard in terms of LAMBDA and NPOLY */
// double *omega, *co, *so, *axis1, *axis2, *phimax;
{
double omega2, co2, so2, r, a, gamma, axissquare1;
/* various angles */
*omega = DPI/((double)NPOLY);
omega2 = PI/((double)NPOLY);
co2 = cos(omega2);
so2 = sin(omega2);
*co = cos(*omega);
*so = sin(*omega);
// *co = co2*co2 - so2*so2;
// *so = 2.0*co2*so2;
/* distance of edge of ellipse to the origin */
r = LAMBDA*co2/(*co);
a = (r*co2 - *co)*(r*co2 - *co);
gamma = 0.5*r*r - r*co2*(*co) + 0.5*cos(2.0*(*omega));
axissquare1 = gamma + sqrt(gamma*gamma + a*(*so)*(*so));
/* semi-minor axis */
*axis1 = sqrt(axissquare1);
/* semi-major axis */
*axis2 = sqrt(axissquare1 + (*so)*(*so));
/* max angle in ellipse parametrization */
*phimax = asin(r*so2/(*axis2));
}
void paint_billiard_interior() /* paints billiard interior, for use before draw_conf */
{
double x0, x, y, phi, r = 0.01, alpha, dphi, omega, beta2, x2, s, x1, y1, angle, co, so, axis1, axis2, phimax;
int i, j, k, c;
glLineWidth(4);
glEnable(GL_LINE_SMOOTH);
switch (B_DOMAIN) {
case (D_POLYGON):
{
omega = DPI/((double)NPOLY);
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(x, y);
x = cos((i+1)*omega + APOLY*PID);
y = sin((i+1)*omega + APOLY*PID);
glVertex2d(x, y);
}
glEnd();
}
break;
}
case (D_REULEAUX):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
if (LAMBDA > 0.0) x2 = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
else x2 = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
x1 = x2 - LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(x, y);
}
}
glEnd();
}
break;
}
case (D_FLOWER):
{
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*phimax;
x1 = co + axis1*cos(s);
y1 = axis2*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd();
}
break;
}
default:
{
}
}
}
void init_billiard_color()
/* initialise the color in which the billiard is drawn */
{
if (PAINT_INT) glColor3f(0.5, 0.5, 0.5);
else
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
}
}
void draw_billiard() /* draws the billiard boundary */
{
double x0, x, y, phi, r = 0.01, alpha, dphi, omega, x1, y1, x2, beta2, angle, s, x2plus, x2minus;
double omega2, co, so, axis1, axis2, phimax, rgb[3], rgb1[3], a, b, ymax, dy, width, cc;
int i, j, k, c, color;
init_billiard_color();
glLineWidth(BILLIARD_WIDTH);
glEnable(GL_LINE_SMOOTH);
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glVertex2d(-LAMBDA, 1.0);
glVertex2d(-LAMBDA, -1.0);
glEnd();
break;
}
case (D_ELLIPSE):
{
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd ();
/* draw foci */
if (FOCI)
{
glColor3f(0.3, 0.3, 0.3);
x0 = sqrt(LAMBDA*LAMBDA-1.0);
glLineWidth(2);
draw_circle(x0, 0.0, r, NSEG);
draw_circle(-x0, 0.0, r, NSEG);
}
break;
}
case (D_STADIUM):
{
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = -PID + (double)i*PI/(double)NSEG;
x = 0.5*LAMBDA + cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = PID + (double)i*PI/(double)NSEG;
x = -0.5*LAMBDA + cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_STRIP);
glVertex2d(-LAMBDA, -1.0);
glVertex2d(-LAMBDA, 1.0);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glEnd();
}
break;
}
case (D_SINAI):
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
break;
}
case (D_DIAMOND):
{
alpha = atan(1.0 - 1.0/LAMBDA);
dphi = (PID - 2.0*alpha)/(double)NSEG;
r = sqrt(LAMBDA*LAMBDA + (LAMBDA-1.0)*(LAMBDA-1.0));
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = alpha + (double)i*dphi;
x = -LAMBDA + r*cos(phi);
y = -LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha - PID + (double)i*dphi;
x = -LAMBDA + r*cos(phi);
y = LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha + PI + (double)i*dphi;
x = LAMBDA + r*cos(phi);
y = LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha + PID + (double)i*dphi;
x = LAMBDA + r*cos(phi);
y = -LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
glEnd();
break;
}
case (D_TRIANGLE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(-LAMBDA, -1.0);
glVertex2d(LAMBDA, -1.0);
glVertex2d(-LAMBDA, 1.0);
glEnd();
break;
}
case (D_ANNULUS):
{
/* color inner circle */
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(MU, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi) + MU;
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
/* color outer domain */
glColor3f(0.2, 0.2, 0.2);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMAX);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMAX);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + PID;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMIN);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + PI;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMIN);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + 3.0*PID;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLES);
glVertex2d(XMAX, YMAX);
glVertex2d(1.0, 0.0);
glVertex2d(XMAX, YMIN);
glVertex2d(XMAX, YMIN);
glVertex2d(0.0, -1.0);
glVertex2d(XMIN, YMIN);
glVertex2d(XMIN, YMIN);
glVertex2d(-1.0, 0.0);
glVertex2d(XMIN, YMAX);
glVertex2d(XMIN, YMAX);
glVertex2d(0.0, 1.0);
glVertex2d(XMAX, YMAX);
glEnd();
/* draw circles */
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
draw_circle(MU, 0.0, LAMBDA, NSEG);
draw_circle(0.0, 0.0, 1.0, NSEG);
break;
}
case (D_POLYGON):
{
omega = DPI/((double)NPOLY);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
break;
}
case (D_REULEAUX):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
if (LAMBDA > 0.0) x2 = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
else x2 = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
x1 = x2 - LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd ();
break;
}
case (D_FLOWER):
{
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
/* draw inner polygon and radial lines */
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
r = LAMBDA*cos(0.5*omega)/co;
for (i=0; i<=NPOLY; i++)
{
glBegin(GL_LINE_STRIP);
glVertex2d(0.0, 0.0);
x = r*cos(((double)i + 0.5)*omega + APOLY*PID);
y = r*sin(((double)i + 0.5)*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
glEnd ();
}
}
/* draw billiard boundary */
if (!PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
}
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
// for (i=0; i<=1; i++)
{
for (j=0; j<NSEG; j++)
{
// s = 2.0*(((double)j/(double)NSEG)-0.5)*PI;
s = 2.0*(((double)j/(double)NSEG)-0.5)*phimax;
x1 = co + axis1*cos(s);
y1 = axis2*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd ();
break;
}
case (D_ALT_REU):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
x2plus = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
x2minus = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
if (i%2==0) x1 = x2plus - LAMBDA*cos(s);
else x1 = x2minus + LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(x, y);
}
}
glEnd ();
break;
}
case (D_ANGLE):
{
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_STRIP);
phi = LAMBDA*PI;
r = 2.0*YMAX;
for (i=-(int)(PI/phi)-1; i <= (int)(PI/phi)+2; i++)
{
// printf("%i \n", i);
glVertex2d(0.0, 0.0);
glVertex2d(-r*cos((double)i*phi), r*sin((double)i*phi));
}
glEnd();
}
init_billiard_color();
glBegin(GL_LINE_STRIP);
glVertex2d(XMIN, 0.0);
glVertex2d(0.0, 0.0);
glVertex2d(-YMAX/tan(LAMBDA*PI), YMAX);
glEnd ();
break;
}
case (D_LSHAPE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(-1.0, -1.0);
glVertex2d(1.0, -1.0);
glVertex2d(1.0, 0.0);
glVertex2d(0.0, 0.0);
glVertex2d(0.0, 1.0);
glVertex2d(-1.0, 1.0);
glEnd();
break;
}
case (D_GENUSN): /* like for polygon */
{
omega = DPI/((double)NPOLY);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
break;
}
case (D_PARABOLAS):
{
omega = PI/((double)NPOLY);
a = 0.25/MU;
b = 1.0/tan(omega);
cc = LAMBDA + MU;
ymax = (-b + sqrt(b*b + 4.0*a*cc))/(2.0*a);
dy = 2.0*ymax/(double)NSEG;
if (PAINT_EXT) /* paint billiard exterior in another color */
{
glColor3f(0.1, 0.1, 0.1);
for (k=0; k<NPOLY; k++)
{
alpha = APOLY*PID + (2.0*(double)k)*omega;
glBegin(GL_TRIANGLE_FAN);
x1 = 10.0*(MU + LAMBDA);
x = x1*cos(alpha);
y = x1*sin(alpha);
glVertex2d(x, y);
for (i = 0; i < NSEG+1; i++)
{
y1 = -ymax + dy*(double)i;
x1 = MU + LAMBDA - 0.25*y1*y1/MU;
x = x1*cos(alpha) - y1*sin(alpha);
y = x1*sin(alpha) + y1*cos(alpha);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
x1 = 10.0*(MU + LAMBDA);
x = x1*cos(alpha);
y = x1*sin(alpha);
glVertex2d(x, y);
y1 = ymax;
x1 = MU + LAMBDA - 0.25*y1*y1/MU;
x = x1*cos(alpha) - y1*sin(alpha);
y = x1*sin(alpha) + y1*cos(alpha);
glVertex2d(x, y);
x1 = 10.0*(MU + LAMBDA);
x = x1*cos(alpha + 2.0*omega);
y = x1*sin(alpha + 2.0*omega);
glVertex2d(x, y);
glEnd();
}
// glVertex2d(cc, 0.0);
// for (i=0; i<=NSEG; i++)
// {
// phi = (double)i*dphi;
// x = cc - 0.5*MU*sin(phi);
// y = MU*cos(phi);
// glVertex2d(x, y);
// }
}
init_billiard_color();
glBegin(GL_LINE_LOOP);
// glColor3f(1.0, 1.0, 1.0);
for (k=0; k<NPOLY; k++)
{
// alpha = APOLY*PID + (2.0*(double)k+1.0)*omega;
alpha = APOLY*PID + (2.0*(double)k)*omega;
for (i = 0; i < NSEG+1; i++)
{
y1 = -ymax + dy*(double)i;
x1 = MU + LAMBDA - 0.25*y1*y1/MU;
x = x1*cos(alpha) - y1*sin(alpha);
y = x1*sin(alpha) + y1*cos(alpha);
glVertex2d(x, y);
}
}
glEnd ();
if (FOCI)
{
glColor3f(0.3, 0.3, 0.3);
for (k=0; k<NPOLY; k++)
{
alpha = APOLY*PID + (2.0*(double)k)*omega;
draw_circle(LAMBDA*cos(alpha), LAMBDA*sin(alpha), r, NSEG);
}
}
break;
}
case (D_PENROSE):
{
cc = sqrt(LAMBDA*LAMBDA - (1.0 - MU)*(1.0 - MU));
width = 0.1*MU;
x1 = vabs(x);
y1 = vabs(y);
dphi = PI/(double)NSEG;
if (PAINT_EXT) /* paint billiard exterior in another color */
{
rgb[0] = 0.1; rgb[1] = 0.1; rgb[2] = 0.1;
erase_rectangle(LAMBDA, YMIN, XMAX, YMAX, rgb);
erase_rectangle(-LAMBDA, YMIN, XMIN, YMAX, rgb);
erase_rectangle(XMIN, 1.0, XMAX, YMAX, rgb);
erase_rectangle(XMIN, -1.0, XMAX, YMIN, rgb);
erase_rectangle(cc, -width, LAMBDA, width, rgb);
erase_rectangle(-cc, -width, -LAMBDA, width, rgb);
glColor3f(0.1, 0.1, 0.1);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(cc, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = cc - 0.5*PENROSE_RATIO*MU*sin(phi);
y = MU*cos(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(-cc, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = -cc + 0.5*PENROSE_RATIO*MU*sin(phi);
y = MU*cos(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMAX);
for (i=0; i<=NSEG/2; i++)
{
phi = (double)i*dphi;
x = LAMBDA*cos(phi);
y = MU + (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMAX);
for (i=0; i<=NSEG/2; i++)
{
phi = (double)i*dphi;
x = -LAMBDA*cos(phi);
y = MU + (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMIN);
for (i=0; i<=NSEG/2; i++)
{
phi = (double)i*dphi;
x = LAMBDA*cos(phi);
y = -MU - (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMIN);
for (i=0; i<=NSEG/2; i++)
{
phi = (double)i*dphi;
x = -LAMBDA*cos(phi);
y = -MU - (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
glEnd();
}
init_billiard_color();
glBegin(GL_LINE_LOOP);
/* upper half ellipse */
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = LAMBDA*cos(phi);
y = MU + (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
/* straight parts */
glVertex2d(-LAMBDA, width);
glVertex2d(-cc, width);
glVertex2d(-cc, MU);
/* left half ellipse */
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = -cc + 0.5*MU*PENROSE_RATIO*sin(phi);
y = MU*cos(phi);
glVertex2d(x, y);
}
/* straight parts */
glVertex2d(-cc, -width);
glVertex2d(-LAMBDA, -width);
glVertex2d(-LAMBDA, -MU);
/* lower half ellipse */
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = -LAMBDA*cos(phi);
y = -MU - (1.0-MU)*sin(phi);
glVertex2d(x, y);
}
/* straight parts */
glVertex2d(LAMBDA, -width);
glVertex2d(cc, -width);
glVertex2d(cc, -MU);
/* right half ellipse */
for (i=0; i<=NSEG; i++)
{
phi = (double)i*dphi;
x = cc - 0.5*MU*PENROSE_RATIO*sin(phi);
y = -MU*cos(phi);
glVertex2d(x, y);
}
/* straight parts */
glVertex2d(cc, width);
glVertex2d(LAMBDA, width);
glVertex2d(LAMBDA, MU);
glEnd ();
break;
}
case (D_CIRCLES):
{
rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0;
for (k=0; k<ncircles; k++) if (circles[k].active)
{
if (circles[k].color == 0) draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
else
{
if (circles[k].new >= 1)
{
rgb_color_scheme_lum(circles[k].color, 0.85, rgb1);
circles[k].new--;
}
else rgb_color_scheme(circles[k].color, rgb1);
draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb1);
}
}
init_billiard_color();
for (k=0; k<ncircles; k++) if (circles[k].active)
draw_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG);
break;
}
case (D_CIRCLES_IN_RECT):
{
rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0;
for (k=0; k<ncircles; k++) if (circles[k].active)
{
// printf("k = %i, color = %i\n", k, circlecolor[k]);
if (circles[k].color == 0) draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
else
{
if (circles[k].new >= 1)
{
rgb_color_scheme_lum(circles[k].color, 0.85, rgb1);
circles[k].new--;
}
else rgb_color_scheme(circles[k].color, rgb1);
draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb1);
}
}
init_billiard_color();
for (k=0; k<ncircles; k++) if (circles[k].active >= 1)
{
if (circles[k].active == 2)
{
// hsl_to_rgb(150.0, 0.9, 0.4, rgb);
// glColor3f(rgb[0], rgb[1], rgb[2]);
glColor3f(0.0, 1.0, 0.0);
rgb[0] = 0.0; rgb[1] = 0.9; rgb[2] = 0.0;
draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
}
else draw_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG);
init_billiard_color();
}
/* draw shooter position for laser pattern */
if (CIRCLE_PATTERN == C_LASER)
{
hsl_to_rgb(0.0, 0.9, 0.5, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
draw_circle(x_shooter, y_shooter, circles[ncircles-1].radius, NSEG);
}
init_billiard_color();
glBegin(GL_LINE_LOOP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glVertex2d(-LAMBDA, 1.0);
glVertex2d(-LAMBDA, -1.0);
glEnd();
break;
}
case (D_CIRCLES_IN_GENUSN):
{
// for (k=0; k<ncircles; k++) if (circles[k].active >= 1)
for (k=0; k<ncircles; k++)
if ((circles[k].active >= 1)&&(in_polygon(circles[k].xc, circles[k].yc, 1.0, NPOLY, APOLY)))
{
if (circles[k].active == 2)
{
hsl_to_rgb(150.0, 0.9, 0.4, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
}
draw_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG);
init_billiard_color();
}
/* draw shooter position for laser pattern */
if ((CIRCLE_PATTERN == C_LASER)||(CIRCLE_PATTERN == C_LASER_GENUSN))
{
hsl_to_rgb(0.0, 0.9, 0.5, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
draw_circle(x_shooter, y_shooter, circles[ncircles-1].radius, NSEG);
}
/* draw polygon */
init_billiard_color();
omega = DPI/((double)NPOLY);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
break;
}
case (D_CIRCLES_IN_TORUS):
{
rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0;
for (k=0; k<ncircles; k++) if (circles[k].active)
{
// printf("k = %i, color = %i\n", k, circlecolor[k]);
if (circles[k].color == 0) draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
else
{
if (circles[k].new >= 1)
{
rgb_color_scheme_lum(circles[k].color, 0.85, rgb1);
circles[k].new--;
}
else rgb_color_scheme(circles[k].color, rgb1);
draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb1);
}
}
init_billiard_color();
for (k=0; k<ncircles; k++) if (circles[k].active >= 1)
{
if (circles[k].active == 2)
{
hsl_to_rgb(150.0, 0.9, 0.4, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
}
draw_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG);
init_billiard_color();
}
/* draw shooter position for laser pattern */
if (CIRCLE_PATTERN == C_LASER)
{
hsl_to_rgb(0.0, 0.9, 0.5, rgb);
glColor3f(rgb[0], rgb[1], rgb[2]);
draw_circle(x_shooter, y_shooter, circles[ncircles-1].radius, NSEG);
}
init_billiard_color();
glBegin(GL_LINE_LOOP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glVertex2d(-LAMBDA, 1.0);
glVertex2d(-LAMBDA, -1.0);
glEnd();
break;
}
case (D_POLYLINE):
{
for (k=0; k<nsides; k++)
{
glBegin(GL_LINE_STRIP);
glVertex2d(polyline[k].x1, polyline[k].y1);
glVertex2d(polyline[k].x2, polyline[k].y2);
glEnd();
}
if (FOCI)
{
switch (POLYLINE_PATTERN) {
case (P_TOKARSKY):
{
glLineWidth(2);
rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = 0.0;
draw_colored_circle(-0.95, 0.0, r, NSEG, rgb);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(0.95, 0.0, r, NSEG, rgb);
break;
}
case (P_TOKA_PRIME):
{
glLineWidth(2);
rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = 0.0;
draw_colored_circle(-polyline[84].x1, polyline[84].y1, r, NSEG, rgb);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(polyline[84].x1, polyline[84].y1, r, NSEG, rgb);
break;
}
case (P_TOKA_NONSELF):
{
glLineWidth(2);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(0.0, 0.0, r, NSEG, rgb);
break;
}
}
}
if (ABSORBING_CIRCLES)
{
rgb[0] = 0.7; rgb[1] = 0.7; rgb[2] = 0.7;
for (k=0; k<ncircles; k++) draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
}
break;
}
case (D_POLYLINE_ARCS):
{
for (k=0; k<nsides; k++)
{
glBegin(GL_LINE_STRIP);
glVertex2d(polyline[k].x1, polyline[k].y1);
glVertex2d(polyline[k].x2, polyline[k].y2);
glEnd();
}
for (k=0; k<narcs; k++)
{
glBegin(GL_LINE_STRIP);
for (i=0; i<=NSEG; i++)
{
phi = arcs[k].angle1 + (double)i*(arcs[k].dangle)/(double)NSEG;
x = arcs[k].xc + arcs[k].radius*cos(phi);
y = arcs[k].yc + arcs[k].radius*sin(phi);
glVertex2d(x, y);
}
glEnd();
}
if (FOCI)
{
switch (POLYLINE_PATTERN) {
case (P_TOKARSKY):
{
glLineWidth(2);
rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = 0.0;
draw_colored_circle(-0.95, 0.0, r, NSEG, rgb);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(0.95, 0.0, r, NSEG, rgb);
break;
}
case (P_TOKA_PRIME):
{
glLineWidth(2);
rgb[0] = 1.0; rgb[1] = 0.0; rgb[2] = 0.0;
draw_colored_circle(-polyline[84].x1, polyline[84].y1, r, NSEG, rgb);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(polyline[84].x1, polyline[84].y1, r, NSEG, rgb);
break;
}
case (P_TOKA_NONSELF):
{
glLineWidth(2);
rgb[0] = 0.0; rgb[1] = 0.8; rgb[2] = 0.2;
draw_colored_circle(0.0, 0.0, r, NSEG, rgb);
break;
}
}
}
if (ABSORBING_CIRCLES)
{
rgb[0] = 0.7; rgb[1] = 0.7; rgb[2] = 0.7;
for (k=0; k<ncircles; k++) draw_colored_circle(circles[k].xc, circles[k].yc, circles[k].radius, NSEG, rgb);
}
break;
}
default:
{
printf("Function draw_billiard not defined for this billiard \n");
}
}
}
/*********************************/
/* computation of the collisions */
/*********************************/
/* The variable config contains information on the state of the particle
* and on its next collision with the boundary:
* [0] position of next collision (ellipse parametrised by (LAMBDA*cos(s), sin(s))
* [1] angle to tangent of boundary after next collision
* [2] running time
* [3] initial distance to next collision
* [4,5] initial position
* [6,7] coordinates of next collision
* The running time is incremented until it equals the distance to the next collision
*/
void print_config(double conf[8]) /* for debugging purposes */
{
printf("s = %.3lg, u = %.3lg, t = %.3lg, L = %.3lg, x0 = %.3lg, y0 = %.3lg, x1 = %.3lg, y1 = %.3lg\n", conf[0], conf[1]/PI, conf[2], conf[3], conf[4], conf[5], conf[6], conf[7]);
}
void print_config_23(double conf[8]) /* for debugging purposes */
{
printf("t = %.8f, L = %.8f\n", conf[2], conf[3]);
}
void print_colors(int color[NPARTMAX]) /* for debugging purposes */
{
int i;
for (i=0; i<NPART; i++) printf("%i ", color[i]);
printf("\n");
}
/****************************************************************************************/
/* rectangle billiard */
/****************************************************************************************/
int pos_rectangle(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of rectangle */
/* the corners of the rectangle are (-LAMBDA,-1), ..., (LAMBDA,1) */
/* returns the number of the side hit, or 0 if hitting a corner */
{
double s, theta;
s = conf[0];
if (s<0.0) s = 0.0;
if (s>4.0*LAMBDA + 4.0) s = 4.0*LAMBDA + 4.0;
theta = conf[1];
/* we treat the cases of starting in one corner separately */
/* to avoid numerical problems due to hitting a corner */
/* bottom left corner */
if ((s==0)||(s==4.0*LAMBDA + 4.0))
{
pos[0] = -LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta;
return(0);
}
/* bottom right corner */
else if (s==2.0*LAMBDA)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + PID;
return(0);
}
/* top right corner */
else if (s==2.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + PI;
return(0);
}
/* top left corner */
else if (s==4.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + 3.0*PID;
return(0);
}
/* bottom side */
else if ((s>0)&&(s<2.0*LAMBDA))
{
pos[0] = s - LAMBDA;
pos[1] = -1.0;
*alpha = theta;
return(1);
}
/* right side */
else if (s<2.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = s - 2.0*LAMBDA - 1.0;
*alpha = theta + PID;
return(2);
}
/* top side */
else if (s<4.0*LAMBDA + 2.0)
{
pos[0] = 3.0*LAMBDA + 2.0 - s;
pos[1] = 1.0;
*alpha = theta + PI;
return(3);
}
/* left side */
else
{
pos[0] = -LAMBDA;
pos[1] = 4.0*LAMBDA + 3.0 - s;
*alpha = theta + 3.0*PID;
return(4);
}
}
int vrectangle_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double l, s0, c0, x1, y1, margin = 1e-12;
int c, intb=1;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
/* intersection with lower part of boundary */
if (s0<0.0)
{
x1 = pos[0] - c0*(1.0 + pos[1])/s0;
y1 = -1.0;
if ((x1>=-LAMBDA)&&(x1<=LAMBDA))
{
config[0] = x1 + LAMBDA;
if ((x1 <= -LAMBDA + margin)||(x1 >= LAMBDA -margin)) config[1] = alpha + PI; /* corners */
// if ((x1 == -LAMBDA)||(x1 == LAMBDA)) config[1] = alpha + PI; /* corners */
else config[1] = -alpha;
intb = 0;
}
}
/* intersection with right-hand part of boundary */
if (intb&&(c0>0.0))
{
x1 = LAMBDA;
y1 = pos[1] + s0*(LAMBDA - pos[0])/c0;
if ((y1>=-1.0)&&(y1<=1.0))
{
config[0] = 2.0*LAMBDA + 1.0 + y1;
if ((y1 <= -1.0 + margin)||(y1 >= 1.0 -margin)) config[1] = alpha + PI; /* corners */
// if ((y1 == -1.0)||(y1 == 1.0)) config[1] = alpha + PI; /* corners */
else config[1] = PID-alpha;
intb = 0;
}
}
/* intersection with upper part of boundary */
if (intb&&(s0>0.0))
{
x1 = pos[0] + c0*(1.0 - pos[1])/s0;
y1 = 1.0;
if ((x1>=-LAMBDA)&&(x1<=LAMBDA))
{
config[0] = 3.0*LAMBDA + 2.0 - x1;
if ((x1 <= -LAMBDA + margin)||(x1 >= LAMBDA -margin)) config[1] = alpha + PI; /* corners */
// if ((x1 == -LAMBDA)||(x1 == LAMBDA)) config[1] = alpha + PI; /* corners */
else config[1] = PI-alpha;
intb = 0;
}
}
/* intersection with left-hand part of boundary */
if (intb&&(c0<0.0))
{
x1 = -LAMBDA;
y1 = pos[1] + s0*(-LAMBDA - pos[0])/c0;
if ((y1>=-1.0)&&(y1<=1.0))
{
config[0] = 4.0*LAMBDA + 3.0 - y1;
if ((y1 <= -1.0 + margin)||(y1 >= 1.0 -margin)) config[1] = alpha + PI; /* corners */
// if ((y1 == -1.0)||(y1 == 1.0)) config[1] = alpha + PI; /* corners */
else config[1] = 3.0*PID-alpha;
intb = 0;
}
}
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(c);
}
int vrectangle(double config[8])
{
double pos[2], alpha;
int c;
/* position et vitesse de depart */
c = pos_rectangle(config, pos, &alpha);
vrectangle_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* elliptic billiard */
/****************************************************************************************/
int pos_ellipse(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of ellipse */
{
double theta;
pos[0] = LAMBDA*cos(conf[0]);
pos[1] = sin(conf[0]);
theta = argument(-LAMBDA*pos[1],pos[0]/LAMBDA);
*alpha = theta + conf[1];
return(1);
}
int vellipse_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double c0, s0, lam2, a, b, c, x1, y1, t, theta;
int i;
c0 = cos(alpha);
s0 = sin(alpha);
lam2 = LAMBDA*LAMBDA;
/* intersection with ellipse, using parametric equation of line */
a = c0*c0 + lam2*s0*s0;
b = pos[0]*c0 + lam2*pos[1]*s0;
c = pos[0]*pos[0] + lam2*pos[1]*pos[1] - lam2;
t = (-b+sqrt(b*b - a*c))/a;
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
/* parameter of intersection with boundary ellipse */
config[0] = argument(x1/LAMBDA, y1);
while (config[0] < 0.0) config[0] += DPI;
while (config[0] > DPI) config[0] -= DPI;
/* computation of outgoing angle after collision with boundary */
theta = argument(-LAMBDA*y1,x1/LAMBDA);
config[1] = theta - alpha;
while (config[1] < 0.0) config[1] += DPI;
while (config[1] > DPI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(1);
}
int vellipse(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], theta, alpha;
int i;
pos[0] = LAMBDA*cos(config[0]);
pos[1] = sin(config[0]);
theta = argument(-LAMBDA*pos[1],pos[0]/LAMBDA);
alpha = theta + config[1];
vellipse_xy(config, alpha, pos);
return(1);
}
/****************************************************************************************/
/* stadium billiard */
/****************************************************************************************/
int pos_stade(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of stadium */
{
double s, theta, l, psi0, psi;
s = conf[0];
theta = conf[1];
l = LAMBDA/2.0;
if (l >= 0.0)
{
if ((s>=0)&&(s<=LAMBDA))
{
pos[0] = s - l;
pos[1] = -1.0;
*alpha = theta;
return(0);
}
else if (s<=LAMBDA+PI)
{
pos[0] = l + sin(s - LAMBDA);
pos[1] = -cos(s - LAMBDA);
*alpha = theta + s - LAMBDA;
return(1);
}
else if (s<=2.0*LAMBDA+PI)
{
pos[0] = 3.0*l + PI - s;
pos[1] = 1.0;
*alpha = theta + PI;
return(2);
}
else
{
pos[0] = -l - sin(s - 2.0*LAMBDA - PI);
pos[1] = cos(s - 2.0*LAMBDA - PI);
*alpha = theta + s - 2.0*LAMBDA;
return(3);
}
}
else /* for lens-shaped billiard, to be checked */
{
psi0 = asin(-l);
if ((s>=0)&&(s<=PI-2.0*psi0))
{
psi = s + psi0;
pos[0] = sin(psi) + l;
pos[1] = -cos(psi);
*alpha = theta + psi;
return(0);
}
else
{
psi = s + 3.0*psi0 - PI;
pos[0] = - sin(psi) - l;
pos[1] = cos(psi);
*alpha = theta + psi + PI;
return(2);
}
}
}
int vstade_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double l, s0, c0, t, x, y, x1, y1, a, b, res[2];
double smin, psi, margin = 1e-12;
int c, intb=1, intc, i;
/* initial position and velocity */
l = LAMBDA/2.0;
if (l>=0.0) smin = 0.0; else smin = -l;
s0 = sin(alpha);
c0 = cos(alpha);
/* intersection with lower straight part of boundary */
if ((s0<0.0)&&(l>0))
{
x1 = pos[0] + c0*(-1.0 - pos[1])/s0;
y1 = -1.0;
if ((x1>=-l)&&(x1<=l))
{
config[0] = x1 + l;
config[1] = -alpha;
intb = 0;
}
}
/* intersection with upper straight part of boundary */
if (intb&&(s0>0.0)&&(l>0))
{
x1 = pos[0] + c0*(1.0 - pos[1])/s0;
y1 = 1.0;
if ((x1>=-l)&&(x1<=l))
{
config[0] = 3.0*l + PI - x1;
config[1] = PI-alpha;
intb = 0;
}
}
/* intersection with right-hand arc of boundary */
if (intb)
{
a = 2.0*pos[0]*c0 + 2.0*pos[1]*s0 - LAMBDA*c0;
b = pos[0]*pos[0] + pos[1]*pos[1] + l*l - LAMBDA*pos[0] - 1.0;
intc = polynome(1.0, a, b, res);
if (intc) for(i=0; i<2; i++)
{
x = pos[0] + c0*res[i];
y = pos[1] + s0*res[i];
psi = argument(-y, x-l);
if (intb&&(sin(psi) >= smin)&&(res[i]>margin))
{
if (l>0.0) config[0] = LAMBDA + psi;
else config[0] = psi - asin(-l);
config[1] = -alpha + psi;
intb = 0;
x1 = x; y1 = y;
}
}
}
/* intersection with left-hand arc of boundary */
if (intb)
{
a = 2.0*pos[0]*c0 + 2.0*pos[1]*s0 + LAMBDA*c0;
b = pos[0]*pos[0] + pos[1]*pos[1] + l*l + LAMBDA*pos[0] - 1.0;
intc = polynome(1.0, a, b, res);
if (intc) for(i=0; i<2; i++)
{
x = pos[0] + c0*res[i];
y = pos[1] + s0*res[i];
psi = argument(y, -l-x);
if (intb&&(sin(psi) >= smin)&&(res[i]>margin))
{
if (l>0.0) config[0] = 2.0*LAMBDA + PI + psi;
else config[0] = psi - 3.0*asin(-l) + PI;
config[1] = -alpha + psi + PI;
intb = 0;
x1 = x; y1 = y;
}
}
}
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(c);
}
int vstade(double config[8])
{
double alpha, pos[2];
int c;
c = pos_stade(config, pos, &alpha);
vstade_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Sinai billiard */
/****************************************************************************************/
int pos_sinai(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of Sinai billiard */
/* s in [0,2 Pi) is on the circle, other s are on boundary of window */
{
double s, theta, psi0, psi, s1, s2, s3, s4;
s = conf[0];
theta = conf[1];
if (conf[1] < 0.0) conf[1] += DPI;
s1 = DPI + XMAX - XMIN;
s2 = s1 + YMAX - YMIN;
s3 = s2 + XMAX - XMIN;
s4 = s3 + YMAX - YMIN;
if (s < DPI) /* circle */
{
pos[0] = LAMBDA*cos(s);
pos[1] = LAMBDA*sin(s);
theta = PID + s;
*alpha = theta - conf[1];
return(0);
}
else if (s < s1) /* boundary of window */
{
pos[0] = XMIN + s - DPI;
pos[1] = YMIN;
*alpha = conf[1];
return(-1);
}
else if (s < s2)
{
pos[0] = XMAX;
pos[1] = YMIN + s - s1;
*alpha = conf[1];
return(-2);
}
else if (s < s3)
{
pos[0] = XMAX - s + s2;
pos[1] = YMAX;
*alpha = conf[1];
return(-3);
}
else
{
pos[0] = XMIN;
pos[1] = YMAX - s + s3;
*alpha = conf[1];
return(-4);
}
}
int vsinai_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double l, s0, c0, t, t1, x, y, x1, y1, a, b, delta, res[2], s1, s2, s3, s4, s, r;
double psi, lam2, margin = 1e-12;
int c, intb=1, intc, i;
/* initial position and velocity */
c0 = cos(alpha);
s0 = sin(alpha);
s1 = DPI + XMAX - XMIN;
s2 = s1 + YMAX - YMIN;
s3 = s2 + XMAX - XMIN;
s4 = s3 + YMAX - YMIN;
/* intersection with circle, using parametric equation of line */
b = pos[0]*c0 + pos[1]*s0;
a = pos[0]*pos[0] + pos[1]*pos[1] - LAMBDA*LAMBDA;
delta = b*b - a;
if ((delta > margin)&&(a > margin))
{
t = - b - sqrt(delta);
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
s = argument(x1,y1);
if (s<0.0) s += DPI;
if (s>=DPI) s -= DPI;
config[0] = s;
config[1] = 3.0*PID - s + alpha;
c = 0;
}
else if (c0 > 0.0) /* intersection with boundary of window */
{
y1 = pos[1] + (XMAX - pos[0])*s0/c0;
if ((y1 >= YMIN)&&(y1 <= YMAX)) /* hitting right boundary */
{
x1 = XMAX;
config[0] = s3 + YMAX - y1;
config[1] = alpha;
c = 2;
}
else if (s0 > 0.0) /* hitting upper boundary */
{
x1 = pos[0] + (YMAX - pos[1])*c0/s0;
y1 = YMAX;
config[0] = DPI + x1 - XMIN;
config[1] = alpha;
c = 3;
}
else /* hitting lower boundary */
{
x1 = pos[0] + (YMIN - pos[1])*c0/s0;
y1 = YMIN;
config[0] = s2 + XMAX - x1;
config[1] = alpha;
c = 1;
}
}
else if (c0 < 0.0)
{
y1 = pos[1] + (XMIN - pos[0])*s0/c0;
if ((y1 >= YMIN)&&(y1 <= YMAX)) /* hitting left boundary */
{
x1 = XMIN;
config[0] = s1 + y1 - YMIN;
config[1] = alpha;
c = 4;
}
else if (s0 > 0.0) /* hitting upper boundary */
{
x1 = pos[0] + (YMAX - pos[1])*c0/s0;
y1 = YMAX;
config[0] = DPI + x1 - XMIN;
config[1] = alpha;
c = 3;
}
else /* hitting lower boundary */
{
x1 = pos[0] + (YMIN - pos[1])*c0/s0;
y1 = YMIN;
config[0] = s2 + XMAX - x1;
config[1] = alpha;
c = 1;
}
}
else /* vertical motion */
{
if (s0 > 0.0)
{
x1 = pos[0];
y1 = YMAX;
config[0] = DPI + x1 - XMIN;
config[1] = alpha;
c = 3;
}
else
{
x1 = pos[0];
y1 = YMIN;
config[0] = s2 + XMAX - x1;
config[1] = alpha;
c = 1;
}
}
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(-c);
/* return a negative value if the disc is not hit, for color scheme */
}
int vsinai(double config[8])
{
double alpha, pos[2];
int c;
/* position et vitesse de depart */
c = pos_sinai(config, pos, &alpha);
vsinai_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* triangle billiard */
/****************************************************************************************/
int pos_triangle(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of triangle */
/* the corners of the triangle are (-LAMBDA,-1), (LAMBDA,-1), (-LAMBDA,1) */
/* we use arclength for horizontal and vertical side, x for diagonal */
{
double s, theta;
s = conf[0];
theta = conf[1];
if ((s>=0)&&(s<=2.0*LAMBDA))
{
pos[0] = s - LAMBDA;
pos[1] = -1.0;
*alpha = theta;
return(0);
}
else if (s<=4.0*LAMBDA)
{
pos[0] = 3.0*LAMBDA - s;
pos[1] = -3.0 + s/LAMBDA;
*alpha = theta + PI - argument(LAMBDA, 1.0);
return(1);
}
else
{
pos[0] = -LAMBDA;
pos[1] = 4.0*LAMBDA + 1.0 - s;
*alpha = theta + 3.0*PID;
return(2);
}
}
int vtriangle_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
/* Warning: reflection in the corners is not yet implemented correctly */
{
double s0, c0, t, x, y, x1, y1, psi;
int c, intb=1, intc, i;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
/* intersection with lower part of boundary */
// if ((s0<0.0)&&(pos[1]>0.0))
if (s0<0.0)
{
x1 = pos[0] - c0*(1.0 + pos[1])/s0;
y1 = -1.0;
if ((x1>=-LAMBDA)&&(x1<=LAMBDA))
{
config[0] = x1 + LAMBDA;
config[1] = -alpha;
intb = 0;
}
}
/* intersection with left-hand part of boundary */
if (intb&&(c0<0.0))
{
x1 = -LAMBDA;
y1 = pos[1] + s0*(-LAMBDA - pos[0])/c0;
if ((y1>=-1.0)&&(y1<=1.0))
{
config[0] = 4.0*LAMBDA + 1.0 - y1;
config[1] = 3.0*PID-alpha;
intb = 0;
}
}
/* intersection with diagonal part of boundary */
if (intb)
{
t = -(pos[0] + LAMBDA*pos[1])/(c0 + LAMBDA*s0);
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
if ((x1>=-LAMBDA)&&(x1<=LAMBDA))
{
psi = argument(LAMBDA, 1.0);
config[0] = 3.0*LAMBDA - x1;
config[1] = PI - alpha - psi;
// config[1] = PI - alpha - atan(1.0/LAMBDA);
intb = 0;
}
}
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(c);
}
int vtriangle(double config[8])
{
double alpha, pos[2];
int c;
/* position et vitesse de depart */
c = pos_triangle(config, pos, &alpha);
vtriangle_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* annulus billiard */
/****************************************************************************************/
int pos_annulus(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of annulus */
{
double s, theta, psi0, psi, s1, s2, s3, s4;
s = conf[0];
theta = conf[1];
if (conf[1] < 0.0) conf[1] += DPI;
if (conf[0] < DPI) /* inner circle */
{
pos[0] = LAMBDA*cos(conf[0]) + MU;
pos[1] = LAMBDA*sin(conf[0]);
theta = PID + conf[0];
*alpha = theta - conf[1];
return(0);
}
else /* outer circle */
{
pos[0] = cos(conf[0]);
pos[1] = sin(conf[0]);
theta = argument(-pos[1],pos[0]);
*alpha = theta + conf[1];
return(1);
}
}
int vannulus_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double l, s0, c0, t, t1, x, y, x1, y1, a, b, delta, res[2], s, r;
double psi, lam2, margin = 1.0e-14, theta;
// double psi, lam2, margin = 1.0e-14, theta;
int c, intb=1, intc, i;
/* initial position and velocity */
c0 = cos(alpha);
s0 = sin(alpha);
/* intersection with inner circle, using parametric equation of line */
b = (pos[0]-MU)*c0 + pos[1]*s0;
a = (pos[0]-MU)*(pos[0]-MU) + pos[1]*pos[1] - LAMBDA*LAMBDA;
delta = b*b - a;
if ((delta > margin)&&(a > margin))
{
t = - b - sqrt(delta);
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
s = argument(x1-MU,y1);
while (s<0.0) s += DPI;
while (s>=DPI) s -= DPI;
config[0] = s;
config[1] = 3.0*PID - s + alpha;
c = 0;
}
else /* intersection with outer circle, using parametric equation of line */
{
b = pos[0]*c0 + pos[1]*s0;
a = pos[0]*pos[0] + pos[1]*pos[1] - 1.0;
t = (-b+sqrt(b*b - a));
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
/* parameter of intersection with outer circle */
config[0] = argument(x1, y1);
while (config[0] < DPI) config[0] += DPI;
while (config[0] >= 2.0*DPI) config[0] -= DPI;
/* computation of outgoing angle after collision with outer circle */
theta = argument(-y1,x1);
config[1] = theta - alpha;
// while (config[1] < 0.0) config[1] += DPI;
// while (config[1] > DPI) config[1] -= DPI;
c = 1;
}
if (config[1] < 0.0) config[1] += DPI;
// config[2] = 1.0e-12; /* running time */
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int vannulus(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_annulus(config, pos, &alpha);
vannulus_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* polygonal billiard */
/****************************************************************************************/
int pos_polygon(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
{
double s, theta, omega, length, s1, angle, x, y;
int c;
s = conf[0];
theta = conf[1];
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
c = (int)(s/length); /* side of polygon */
s1 = s - ((double)c)*length;
x = 1.0 + (cos(omega) - 1.0)*s1/length;
y = sin(omega)*s1/length;
angle = (double)c*omega + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = (0.5 + (double)c)*omega + theta + PID*(1.0 + APOLY);
return(c);
}
int vpolygon_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, omega, length, rlength, s1, rangle, x, y, xp, yp, x1, y1, ca, sa;
int k, c, intb=1, intc, i;
/* dimensions/angles of polygon */
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
rlength = cos(0.5*omega);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = (0.5 + (double)k)*omega + APOLY*PID;
theta = alpha - rangle;
if ((cos(theta) > 0.0)&&(intb))
{
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
xp = rlength;
yp = y + (xp-x)*tan(theta);
if (vabs(yp) < 0.5*length)
{
/* rotate back */
x1 = xp*ca - yp*sa;
y1 = xp*sa + yp*ca;
intb = 0;
c = k;
config[0] = ((double)k + 0.5)*length + yp;
config[1] = PID - theta;
}
}
}
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int vpolygon(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_polygon(config, pos, &alpha);
vpolygon_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Reuleaux-type and star-shaped billiard */
/****************************************************************************************/
int pos_reuleaux(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
{
double s, theta, omega2, beta2, beta, s1, angle, x2, x, y;
int c;
s = conf[0];
theta = conf[1];
omega2 = PI/((double)NPOLY);
beta2 = asin(sin(omega2)/vabs(LAMBDA));
beta = beta2*2.0;
c = (int)(s/beta); /* side of shape */
s1 = s - ((double)c)*beta;
if (LAMBDA > 0.0) x2 = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
else x2 = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
x = x2 - LAMBDA*cos(s1 - beta2);
y = LAMBDA*sin(s1 - beta2);
angle = 2.0*((double)c)*omega2 + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = PID - s1 + beta2 + theta + 2.0*(double)c*omega2 + APOLY*PID;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int vreuleaux_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, omega2, beta, s1, rangle, x, y, x1[NPOLY], y1[NPOLY], xi, yi, t, x2;
double ca, sa, a, b, margin = 1.0e-14, tmin, tval[NPOLY], tempconf[NPOLY][2];
int k, c, intb=1, intc, i, nt = 0, cval[NPOLY], ntmin;
/* dimensions/angles of polygon */
omega2 = PI/((double)NPOLY);
beta = 2.0*asin(sin(omega2)/vabs(LAMBDA));
// printf("beta = %.5lg\n", beta);
if (LAMBDA > 0.0) x2 = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
else x2 = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
// printf("x2 = %.5lg\n", x2);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = 2.0*(double)k*omega2 + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
a = (x-x2)*cos(theta) + y*sin(theta);
b = (x-x2)*(x-x2) + y*y - LAMBDA*LAMBDA;
if (a*a - b > margin)
{
if (LAMBDA > 0.0) t = -a - sqrt(a*a - b);
else t = -a + sqrt(a*a - b);
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if ((t > margin)&&(vabs(yi) <= sin(omega2)))
{
cval[nt] = k;
tval[nt] = t;
/* rotate back */
x1[nt] = xi*ca - yi*sa;
y1[nt] = xi*sa + yi*ca;
tempconf[nt][0] = ((double)k + 0.5)*beta + asin(yi/LAMBDA);
tempconf[nt][1] = PID - asin(yi/LAMBDA) - theta;
nt++;
}
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
// printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
return(c);
}
int vreuleaux(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_reuleaux(config, pos, &alpha);
vreuleaux_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Bunimovich flower billiard */
/****************************************************************************************/
int pos_flower(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary, it belongs to [0,2*NPOLY*phimax) */
{
double s, theta, omega, co, so, axis1, axis2, phimax, s1, x, y, angle;
int c;
s = conf[0];
theta = conf[1];
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
c = (int)(s/(2.0*phimax)); /* side of shape */
s1 = s - (((double)c)*2.0 + 1.0)*phimax;
x = co + axis1*cos(s1);
y = axis2*sin(s1);
angle = ((double)c)*omega + PID*APOLY;
// angle = 2.0*((double)c)*omega + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = argument(-axis1*sin(s1), axis2*cos(s1)) + theta + angle;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int vflower_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
// double config[8], alpha, pos[2];
{
double s, theta, omega, omega2, s1, rangle, x, y, x1, y1, xi, yi, t;
double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin;
double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2;
int k, c, intb=1, intc, i, nt = 0, ntmin, sign;
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
for (k=0; k<NPOLY; k++) if (intb)
{
/* rotate position so that kth side is vertical */
// rangle = (double)(2*k)*omega + APOLY*PID;
rangle = (double)k*omega + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
ct = cos(theta);
st = sin(theta);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
/* find intersection with elliptical arc */
aa = ct*ct/(axis1*axis1) + st*st/(axis2*axis2);
bb = (x-co)*ct/(axis1*axis1) + y*st/(axis2*axis2);
cc = (x-co)*(x-co)/(axis1*axis1) + y*y/(axis2*axis2) - 1.0;
// if (bb*bb - aa*cc > margin)
if (bb*bb - aa*cc >= 0.0)
{
t = (-bb + sqrt(bb*bb - aa*cc))/aa;
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2);
else phi = -argument((xi - co)/axis1, -yi/axis2);
if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
{
intb = 0;
c = k;
/* rotate back */
x1 = xi*ca - yi*sa;
y1 = xi*sa + yi*ca;
config[0] = (double)(2*k + 1)*phimax + phi;
config[1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta;
}
}
}
// if (nt == 0) printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
// int old_vflower_xy(config, alpha, pos)
// /* determine initial configuration for start at point pos = (x,y) */
// double config[8], alpha, pos[2];
//
// {
// double s, theta, omega, omega2, s1, rangle, x, y, x1[2*NPOLY], y1[2*NPOLY], xi, yi, t;
// double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin, tval[2*NPOLY], tempconf[2*NPOLY][2];
// double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2;
// int k, c, intb=1, intc, i, nt = 0, cval[2*NPOLY], ntmin, sign;
//
// compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
//
// for (k=0; k<NPOLY; k++)
// {
// /* rotate position so that kth side is vertical */
// // rangle = (double)(2*k)*omega + APOLY*PID;
// rangle = (double)k*omega + APOLY*PID;
// theta = alpha - rangle;
//
// ca = cos(rangle);
// sa = sin(rangle);
//
// ct = cos(theta);
// st = sin(theta);
//
// x = pos[0]*ca + pos[1]*sa;
// y = -pos[0]*sa + pos[1]*ca;
//
// /* find intersection with elliptical arc */
// aa = ct*ct/(axis1*axis1) + st*st/(axis2*axis2);
// bb = (x-co)*ct/(axis1*axis1) + y*st/(axis2*axis2);
// cc = (x-co)*(x-co)/(axis1*axis1) + y*y/(axis2*axis2) - 1.0;
//
// // if (bb*bb - aa*cc > margin)
// if (bb*bb - aa*cc >= 0.0)
// {
// t = (-bb + sqrt(bb*bb - aa*cc))/aa;
//
// xi = x + t*cos(theta);
// yi = y + t*sin(theta);
//
// if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2);
// else phi = -argument((xi - co)/axis1, -yi/axis2);
//
// // phi = argument((xi - co)/axis1, yi/axis2);
// // if (phi > PI) phi += -DPI;
//
// if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
// // if (((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
// // if ((t > margin))
// {
// cval[nt] = k;
// // cval[nt] = 2*k;
// tval[nt] = t;
//
// /* rotate back */
// x1[nt] = xi*ca - yi*sa;
// y1[nt] = xi*sa + yi*ca;
//
// tempconf[nt][0] = (double)(2*k + 1)*phimax + phi;
// tempconf[nt][1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta;
// nt++;
// }
// }
// }
//
// /* find earliest intersection */
// tmin = tval[0];
// ntmin = 0;
// for (i=1; i<nt; i++)
// if (tval[i] < tmin)
// {
// tmin = tval[i];
// ntmin = i;
// }
//
// config[0] = tempconf[ntmin][0];
// config[1] = tempconf[ntmin][1];
// c = cval[ntmin];
//
// if (nt == 0) printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
//
//
// if (config[1] < 0.0) config[1] += DPI;
//
// config[2] = 0.0; /* running time */
// config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
// config[4] = pos[0]; /* start position */
// config[5] = pos[1];
// config[6] = x1[ntmin]; /* position of collision */
// config[7] = y1[ntmin];
//
// return(c);
// }
int vflower(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_flower(config, pos, &alpha);
vflower_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Alternating between Reuleaux-type and star-shaped billiard */
/****************************************************************************************/
int pos_alt_reuleaux(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
{
double s, theta, omega2, beta2, beta, s1, angle, x2plus, x2minus, x, y;
int c;
s = conf[0];
theta = conf[1];
omega2 = PI/((double)NPOLY);
beta2 = asin(sin(omega2)/vabs(LAMBDA));
beta = beta2*2.0;
c = (int)(s/beta); /* side of shape */
s1 = s - ((double)c)*beta;
x2plus = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
x2minus = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
if (c%2 == 0) x = x2plus - LAMBDA*cos(s1 - beta2);
else x = x2minus + LAMBDA*cos(s1 - beta2);
if (c%2 == 0) y = LAMBDA*sin(s1 - beta2);
else y = -LAMBDA*sin(s1 - beta2);
/* test, to be removed */
// x = x2plus - LAMBDA*cos(s1 - beta2);
// y = LAMBDA*sin(s1 - beta2);
angle = 2.0*((double)c)*omega2 + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = PID - s1 + beta2 + theta + 2.0*(double)c*omega2 + APOLY*PID;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int valt_reuleaux_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, omega2, beta, s1, rangle, x, y, x1[NPOLY], y1[NPOLY], xi, yi, t, x2plus, x2minus, arcsine;
double ca, sa, a, b, margin = 1.0e-14, tmin, tval[NPOLY], tempconf[NPOLY][2];
int k, c, intb=1, intc, i, nt = 0, cval[NPOLY], ntmin;
/* dimensions/angles of polygon */
omega2 = PI/((double)NPOLY);
beta = 2.0*asin(sin(omega2)/vabs(LAMBDA));
// printf("beta = %.5lg\n", beta);
x2plus = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
x2minus = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
// printf("x2 = %.5lg\n", x2);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = 2.0*(double)k*omega2 + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
if (k%2==0)
{
a = (x-x2plus)*cos(theta) + y*sin(theta);
b = (x-x2plus)*(x-x2plus) + y*y - LAMBDA*LAMBDA;
}
else
{
a = (x-x2minus)*cos(theta) + y*sin(theta);
b = (x-x2minus)*(x-x2minus) + y*y - LAMBDA*LAMBDA;
}
if (a*a - b > margin)
{
if (k%2==0) t = -a - sqrt(a*a - b);
else t = -a + sqrt(a*a - b);
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if ((t > margin)&&(vabs(yi) <= sin(omega2)))
{
cval[nt] = k;
tval[nt] = t;
/* rotate back */
x1[nt] = xi*ca - yi*sa;
y1[nt] = xi*sa + yi*ca;
if (k%2==0) arcsine = asin(yi/LAMBDA);
else arcsine = -asin(yi/LAMBDA);
tempconf[nt][0] = ((double)k + 0.5)*beta + arcsine;
tempconf[nt][1] = PID - arcsine - theta;
nt++;
}
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
// printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
return(c);
}
int valt_reuleaux(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_alt_reuleaux(config, pos, &alpha);
valt_reuleaux_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* angle billiard */
/****************************************************************************************/
int pos_angle(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of triangle */
/* corner of angle is at (0,0), sides are horizontal and x*sin(a) = -y*cos(a), a=LAMBDA*PI */
/* we use arclength for horizontal and vertical side, y for diagonal */
{
double s, theta;
s = conf[0];
theta = conf[1];
if (s<=0)
{
pos[0] = s;
pos[1] = 0.0;
*alpha = theta;
return(0);
}
else
{
pos[0] = - s/tan(LAMBDA*PI);
pos[1] = s;
*alpha = theta + (1.0-LAMBDA)*PI;
return(1);
}
}
int vangle_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
/* Warning: reflection in the corners is not yet implemented correctly */
{
double s0, c0, t, x, y, x1, y1, phi;
int c, intb=1, intc, i;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
/* intersection with lower part of boundary */
if (s0<0.0)
{
x1 = pos[0] - pos[1]*c0/s0;
y1 = 0.0;
if (x1<=0.0)
{
config[0] = x1;
config[1] = -alpha;
intb = 0;
}
}
/* intersection with diagonal part of boundary */
if ((intb)&&(sin(alpha+LAMBDA*PI)>0.0))
{
phi = LAMBDA*PI;
t = -(pos[0]*sin(phi) + pos[1]*cos(phi))/sin(alpha+phi);
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
if (y1 > 0.0)
{
config[0] = y1;
config[1] = PI - alpha - phi;
intb = 0;
}
}
/* other cases, assign a dummy coordinate */
if (intb)
{
if (s0 > 0.0)
{
t = (1000.0 - pos[0])/s0;
x1 = pos[0] + t*c0;
y1 = 1000.0;
}
else
{
t = -(1000.0 + pos[0])/c0;
x1 = -1000.0;
y1 = pos[1] + t*s0;
}
config[0] = -1000.0;
config[1] = PID;
}
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(c);
}
int vangle(double config[8])
{
double alpha, pos[2];
int c;
/* position et vitesse de depart */
c = pos_angle(config, pos, &alpha);
vangle_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* L-shaped billiard (conical singularity) */
/****************************************************************************************/
int pos_lshape(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of L-shaped billiard */
/* the corners of the L shape are (-1,-1), (1,-1), (1,0), (0,0), (0,1), (-1,1) */
/* returns the number of the side hit, or 0 if hitting a corner */
{
double s, theta;
s = conf[0];
if (s<0.0) s = 0.0;
if (s>8.0) s = 8.0;
theta = conf[1];
/* bottom side */
if ((s>0)&&(s<2.0))
{
pos[0] = s -1.0;
pos[1] = -1.0;
*alpha = theta;
return(1);
}
/* lower right side */
else if (s<3.0)
{
pos[0] = 1.0;
pos[1] = s - 3.0;
*alpha = theta + PID;
return(2);
}
/* lower top side */
else if (s<4.0)
{
pos[0] = 4.0 - s;
pos[1] = 0.0;
*alpha = theta + PI;
return(3);
}
/* upper right side */
else if (s<5.0)
{
pos[0] = 0.0;
pos[1] = s - 4.0;
*alpha = theta + PID;
return(4);
}
/* upper top side */
else if (s<6.0)
{
pos[0] = 5.0 - s;
pos[1] = 1.0;
*alpha = theta + PI;
return(5);
}
/* left side */
else
{
pos[0] = -1.0;
pos[1] = 7.0 - s;
*alpha = theta - PID;
return(6);
}
}
int vlshape_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double t, l, s0, c0, margin = 1e-12, tmin;
double x1[6], y1[6], tval[6], tempconf[6][2];
int i, c, intb=1, cval[6], nt = 0, ntmin;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
// print_config(config);
/* intersection with lower part of boundary */
if (s0<0.0)
{
t = - (1.0 + pos[1])/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = -1.0;
if ((x1[nt]>=-1.0)&&(x1[nt]<=0.0))
{
tempconf[nt][0] = 5.0 - x1[nt];
tempconf[nt][1] = alpha + PI;
cval[nt] = 5;
tval[nt] = t;
nt++;
}
else if ((x1[nt]>0.0)&&(x1[nt]<=1.0))
{
tempconf[nt][0] = 4.0 - x1[nt];
tempconf[nt][1] = alpha + PI;
cval[nt] = 3;
tval[nt] = t;
nt++;
}
}
/* intersection with lower part of right-hand boundary */
if (c0>0.0)
{
t = (1.0 - pos[0])/c0;
x1[nt] = 1.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=-1.0)&&(y1[nt]<=0.0))
{
tempconf[nt][0] = 7.0 - y1[nt];
tempconf[nt][1] = PID + alpha;
cval[nt] = 6;
tval[nt] = t;
nt++;
}
}
/* intersection with upper part of right-hand boundary */
if ((pos[0] < 0.0)&&(c0>0.0))
{
t = - pos[0]/c0;
x1[nt] = 0.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=0.0)&&(y1[nt]<=1.0))
{
tempconf[nt][0] = 7.0 - y1[nt];
tempconf[nt][1] = PID + alpha;
cval[nt] = 4;
tval[nt] = t;
nt++;
}
}
/* intersection with right-hand part of upper boundary */
if ((pos[1] < 0.0)&&(s0>0.0))
{
t = - pos[1]/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = 0.0;
if ((x1[nt]>=-0.0)&&(x1[nt]<=1.0))
{
tempconf[nt][0] = 1.0 + x1[nt];
tempconf[nt][1] = alpha;
cval[nt] = 1;
tval[nt] = t;
nt++;
}
}
/* intersection with left-hand part of upper boundary */
if (s0>0.0)
{
t = (1.0 - pos[1])/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = 1.0;
if ((x1[nt]>=-1.0)&&(x1[nt]<=0.0))
{
tempconf[nt][0] = 1.0 + x1[nt];
tempconf[nt][1] = alpha;
cval[nt] = 1;
tval[nt] = t;
nt++;
}
}
/* intersection with left-hand part of boundary */
if (c0<0.0)
{
t = (-1.0 - pos[0])/c0;
x1[nt] = -1.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=0.0)&&(y1[nt]<=1.0))
{
tempconf[nt][0] = 4.0 + y1[nt];
tempconf[nt][1] = alpha - PID;
cval[nt] = 4;
tval[nt] = t;
nt++;
}
else if ((y1[nt]>=-1.0)&&(y1[nt]<0.0))
{
tempconf[nt][0] = 3.0 + y1[nt];
tempconf[nt][1] = alpha - PID;
cval[nt] = 2;
tval[nt] = t;
nt++;
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
// printf("nt = %i, ntmin = %i, cmin = %i\n", nt, ntmin, cval[ntmin]);
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1[ntmin];
config[7] = y1[ntmin];
// print_config(config);
return(c);
}
int vlshape(double config[8])
{
double pos[2], alpha;
int c;
/* position et vitesse de depart */
c = pos_lshape(config, pos, &alpha);
vlshape_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* genus n surface - polygon with opposite sides identified */
/****************************************************************************************/
int pos_genusn(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
{
double s, theta, omega, length, s1, angle, x, y;
int c;
s = conf[0];
theta = conf[1];
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
c = (int)(s/length); /* side of polygon */
s1 = s - ((double)c)*length;
x = 1.0 + (cos(omega) - 1.0)*s1/length;
y = sin(omega)*s1/length;
angle = (double)c*omega + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = (0.5 + (double)c)*omega + theta + PID*(1.0 + APOLY);
return(c);
}
int vgenusn_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, omega, length, rlength, s1, rangle, x, y, xp, yp, x1, y1, ca, sa, margin = 1.0e-14;
int k, c, intb=1, intc, i;
/* dimensions/angles of polygon */
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
rlength = cos(0.5*omega);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = (0.5 + (double)k)*omega + APOLY*PID;
theta = alpha - rangle;
if ((cos(theta) > 0.0)&&(intb))
{
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
// xp = -rlength;
xp = rlength;
yp = y + (xp-x)*tan(theta);
if (vabs(yp) < 0.5*length - margin)
{
/* rotate back */
x1 = xp*ca - yp*sa;
y1 = xp*sa + yp*ca;
intb = 0;
c = k + NPOLY/2;
if (c > NPOLY) c -= NPOLY;
config[0] = ((double)c + 0.5)*length - yp;
// if (config[0] > (double)NPOLY*length) config[0] -= (double)NPOLY*length;
config[1] = PID + theta;
// config[0] = ((double)k + 0.5)*length + yp;
// config[1] = PID - theta;
}
}
}
if (intb) x1 = 1.0e12; /* to make inactive particles too close to a corner */
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int vgenusn(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_genusn(config, pos, &alpha);
vgenusn_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Polygonal billiard with parabolic sides */
/****************************************************************************************/
int pos_parabolas(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of polygon */
/* conf[0] is y + ymax on first side */
{
double s, theta, omega2, aa, bb, cc, ymax, angle, x2, x, y;
int c;
s = conf[0];
theta = conf[1];
omega2 = PI/((double)NPOLY);
aa = 0.25/MU;
bb = 1.0/tan(omega2);
cc = LAMBDA + MU;
ymax = ( - bb + sqrt(bb*bb + 4.0*aa*cc))/(2.0*aa);
c = (int)(s/(2.0*ymax)); /* side of shape */
y = s - (2.0*(double)c + 1.0)*ymax;
x = LAMBDA + MU - 0.25*y*y/MU;
// printf("y = %.3lg\n", y);
angle = 2.0*((double)c)*omega2 + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = PID + theta + atan(0.5*y/MU) + angle;
// *alpha = PID + theta + atan(0.5*y/MU) + 2.0*(double)c*omega2 + APOLY*PID;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int vparabolas_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, omega2, beta, s1, rangle, x, y, x1, y1, xi, yi, t, x2;
double ca, sa, a, b, margin = 1.0e-14, tmin, aa, bb, cc, ymax;
int k, c, intb=1, intc, i, nt = 0, ntmin;
/* dimensions/angles of polygon */
omega2 = PI/((double)NPOLY);
aa = 0.25/MU;
bb = 1.0/tan(omega2);
cc = LAMBDA + MU;
ymax = ( - bb + sqrt(bb*bb + 4.0*aa*cc))/(2.0*aa);
// printf("ymax = %.3lg\n", ymax);
// print_config(config);
for (k=0; k<NPOLY; k++) if (intb)
{
/* rotate position so that kth side is vertical */
rangle = 2.0*((double)k)*omega2 + APOLY*PID;
theta = alpha - rangle;
// printf("theta = %.3lg\n", theta);
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
aa = sin(theta)*sin(theta);
bb = y*sin(theta) + 2.0*MU*cos(theta);
cc = y*y + 4.0*MU*x - 4.0*MU*(LAMBDA+MU);
// printf("y = %.3lg\n", y);
// if (cos(theta) == 1.0)
if (cos(theta) >= 1.0 - margin)
{
// t = -cc/(2.0*bb);
xi = LAMBDA + MU - 0.25*y*y/MU;
yi = y;
// if ((t > margin)&&(vabs(yi) <= ymax))
if (vabs(yi) <= ymax)
{
intb = 0;
/* rotate back */
x1 = xi*ca - yi*sa;
y1 = xi*sa + yi*ca;
config[0] = yi + (1.0 + 2.0*(double)k)*ymax;
config[1] = PID - theta + atan(0.5*yi/MU);
}
// printf("s = %.3lg\n", config[0]);
}
else if (bb*bb - aa*cc > margin)
{
t = (-bb + sqrt(bb*bb - aa*cc))/aa;
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if ((t > margin)&&(vabs(yi) <= ymax))
// if (vabs(yi) <= ymax)
{
intb = 0;
// printf("t = %.3lg\n", t);
/* rotate back */
x1 = xi*ca - yi*sa;
y1 = xi*sa + yi*ca;
config[0] = yi + (1.0 + 2.0*(double)k)*ymax;
config[1] = PID - theta + atan(0.5*yi/MU);
}
}
// if (!intb) printf("Intersection found with side %i\n", k);
}
// if (intb) printf("No intersection found!\n");
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
// print_config(config);
return(k);
}
int vparabolas(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_parabolas(config, pos, &alpha);
vparabolas_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Penrose solution to illumination problem */
/****************************************************************************************/
int pos_penrose(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of domain */
/* conf[0] parametrization of boundary by arclength or angle */
{
double s, s1, theta, cc, l1, l2, width, x, y, phi;
int c, i;
static int first = 1;
static double sval[17];
s = conf[0];
theta = conf[1];
cc = sqrt(LAMBDA*LAMBDA - (1.0-MU)*(1.0-MU));
width = 0.1*MU;
l1 = MU - width;
l2 = LAMBDA - cc;
/* s values of different boundary parts */
if (first)
{
sval[0] = 0.0; sval[1] = PI; sval[2] = sval[1] + l1;
sval[3] = sval[2] + l2; sval[4] = sval[3] + l1;
sval[5] = sval[4] + PI; sval[6] = sval[5] + l1;
sval[7] = sval[6] + l2; sval[8] = sval[7] + l1;
for (i=1; i<=8; i++) sval[8+i] = sval[8] + sval[i];
// for (i=0; i<16; i++) printf("sval[%i] = %.3lg\n", i, sval[i]);
first = 0;
}
if (s < sval[1]) /* upper ellipse */
{
pos[0] = LAMBDA*cos(s);
pos[1] = MU + (1.0-MU)*sin(s);
phi = argument(-LAMBDA*sin(s),(1.0-MU)*cos(s));
*alpha = phi + theta;
return(0);
}
else if (s < sval[2]) /* upper left straight parts */
{
pos[0] = -LAMBDA;
pos[1] = MU - s + PI;
*alpha = theta - PID;
return(1);
}
else if (s < sval[3])
{
pos[0] = -LAMBDA + s - sval[2];
pos[1] = width;
*alpha = theta;
return(2);
}
else if (s < sval[4])
{
pos[0] = -cc;
pos[1] = width + s -sval[3];
*alpha = theta + PID;
return(3);
}
else if (s < sval[5]) /* left ellipse/mushroom head */
{
s1 = s - sval[4];
pos[0] = -cc + 0.5*PENROSE_RATIO*MU*sin(s1);
pos[1] = MU*cos(s1);
phi = argument(0.5*PENROSE_RATIO*MU*cos(s1), -MU*sin(s1));
*alpha = phi + theta;
return(4);
}
else if (s < sval[6]) /* lower left straight parts */
{
s1 = s - sval[5];
pos[0] = -cc;
pos[1] = -MU + s1;
*alpha = theta + PID;
return(5);
}
else if (s < sval[7])
{
s1 = s - sval[6];
pos[0] = -cc - s1;
pos[1] = -width;
*alpha = theta + PI;
return(6);
}
else if (s < sval[8])
{
s1 = s - sval[7];
pos[0] = -LAMBDA;
pos[1] = -width - s1;
*alpha = theta - PID;
return(7);
}
else if (s < sval[9]) /* lower ellipse */
{
s1 = s - sval[8];
pos[0] = -LAMBDA*cos(s1);
pos[1] = -MU - (1.0-MU)*sin(s1);
phi = argument(LAMBDA*sin(s1),-(1.0-MU)*cos(s1));
*alpha = phi + theta;
return(8);
}
else if (s < sval[10]) /* lower right straight parts */
{
s1 = s - sval[9];
pos[0] = LAMBDA;
pos[1] = -MU + s1;
*alpha = theta + PID;
return(9);
}
else if (s < sval[11])
{
s1 = s - sval[10];
pos[0] = LAMBDA - s1;
pos[1] = -width;
*alpha = theta + PI;
return(10);
}
else if (s < sval[12])
{
s1 = s - sval[11];
pos[0] = cc;
pos[1] = -width -s1;
*alpha = theta - PID;
return(11);
}
else if (s < sval[13]) /* right ellipse/mushroom head */
{
s1 = s - sval[12];
pos[0] = cc - 0.5*PENROSE_RATIO*MU*sin(s1);
pos[1] = -MU*cos(s1);
phi = argument(-0.5*PENROSE_RATIO*MU*cos(s1), MU*sin(s1));
*alpha = phi + theta;
return(12);
}
else if (s < sval[14]) /* upper right straight parts */
{
s1 = s - sval[13];
pos[0] = cc;
pos[1] = MU - s1;
*alpha = theta - PID;
return(13);
}
else if (s < sval[15])
{
s1 = s - sval[14];
pos[0] = cc + s1;
pos[1] = width;
*alpha = theta;
return(14);
}
else
{
s1 = s - sval[15];
pos[0] = LAMBDA;
pos[1] = width + s1;
*alpha = theta + PID;
return(15);
}
}
int vpenrose_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double s, theta, cc, width, l1, l2, s1, rangle, x, y, x1[30], y1[30], xi, yi, t, x2;
double ca, sa, a, b, d, margin = 1.0e-14, tmin, tval[30], tempconf[30][2], lam2, mu2;
int k, c, intb=1, intc, i, nt = 0, cval[30], ntmin;
static int first = 1;
static double sval[17];
/* dimensions of domain */
cc = sqrt(LAMBDA*LAMBDA - (1.0-MU)*(1.0-MU));
width = 0.1*MU;
l1 = MU - width;
l2 = LAMBDA - cc;
lam2 = LAMBDA*LAMBDA;
mu2 = (1.0-MU)*(1.0-MU);
/* s values of different boundary parts */
/* USE STATIC DOUBLES ? */
if (first)
{
sval[0] = 0.0; sval[1] = PI; sval[2] = sval[1] + l1;
sval[3] = sval[2] + l2; sval[4] = sval[3] + l1;
sval[5] = sval[4] + PI; sval[6] = sval[5] + l1;
sval[7] = sval[6] + l2; sval[8] = sval[7] + l1;
for (i=1; i<=8; i++) sval[8+i] = sval[8] + sval[i];
// for (i=0; i<16; i++) printf("sval[%i] = %.3lg\n", i, sval[i]);
first = 0;
}
ca = cos(alpha);
sa = sin(alpha);
/* intersection with upper ellipse */
a = mu2*ca*ca + lam2*sa*sa;
b = mu2*pos[0]*ca + lam2*(pos[1]-MU)*sa;
d = mu2*pos[0]*pos[0] + lam2*(pos[1]-MU)*(pos[1]-MU) - lam2*mu2;
if (b*b > a*d)
{
t = (-b + sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
// printf("x = %.3lg, y = %.3lg\n", x, y);
if ((t > margin)&&(y >= MU))
{
cval[nt] = 0;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = argument(x/LAMBDA, (y-MU)/(1.0-MU));
tempconf[nt][1] = argument(-LAMBDA*(y-MU)/(1.0-MU), (1.0-MU)*x/LAMBDA) - alpha;
// tempconf[nt][1] = argument(-LAMBDA*(y-MU)/(1.0-MU), x/MU) - alpha;
nt++;
}
}
/* intersection with lower ellipse */
b = mu2*pos[0]*ca + lam2*(pos[1]+MU)*sa;
d = mu2*pos[0]*pos[0] + lam2*(pos[1]+MU)*(pos[1]+MU) - lam2*mu2;
if (b*b > a*d)
{
t = (-b + sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
if ((t > margin)&&(y <= -MU))
{
cval[nt] = 8;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[8] + argument(-x/LAMBDA, -(y+MU)/(1.0-MU));
tempconf[nt][1] = argument(-LAMBDA*(y+MU)/(1.0-MU), (1.0-MU)*x/LAMBDA) - alpha;
nt++;
}
}
/* intersection with right ellipse */
a = 4.0*ca*ca + sa*sa*PENROSE_RATIO*PENROSE_RATIO;
b = 4.0*(pos[0] - cc)*ca + pos[1]*sa*PENROSE_RATIO*PENROSE_RATIO;
d = 4.0*(pos[0] - cc)*(pos[0] - cc) + (pos[1]*pos[1] - MU*MU)*PENROSE_RATIO*PENROSE_RATIO;
if (b*b > a*d)
{
t = (-b + sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
if ((t > margin)&&(x <= cc))
{
cval[nt] = 12;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[12] + argument(-y/MU, 2.0*(cc-x)/(MU*PENROSE_RATIO));
tempconf[nt][1] = argument(0.5*PENROSE_RATIO*y, 2.0*(cc-x)/PENROSE_RATIO) - alpha;
nt++;
}
t = (-b - sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
if ((t > margin)&&(x <= cc))
{
cval[nt] = 12;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[12] + argument(-y/MU, 2.0*(cc-x)/(MU*PENROSE_RATIO));
tempconf[nt][1] = argument(0.5*PENROSE_RATIO*y, 2.0*(cc-x)/PENROSE_RATIO) - alpha;
nt++;
}
}
/* intersection with left ellipse */
b = 4.0*(pos[0] + cc)*ca + pos[1]*sa*PENROSE_RATIO*PENROSE_RATIO;
d = 4.0*(pos[0] + cc)*(pos[0] + cc) + (pos[1]*pos[1] - MU*MU)*PENROSE_RATIO*PENROSE_RATIO;
if (b*b > a*d)
{
t = (-b + sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
if ((t > margin)&&(x >= -cc))
{
cval[nt] = 4;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[4] + argument(y/MU, 2.0*(cc+x)/(MU*PENROSE_RATIO));
tempconf[nt][1] = argument(0.5*PENROSE_RATIO*y, -2.0*(cc+x)/PENROSE_RATIO) - alpha;
nt++;
}
t = (-b - sqrt(b*b - a*d))/a;
x = pos[0] + t*ca;
y = pos[1] + t*sa;
if ((t > margin)&&(x >= -cc))
{
cval[nt] = 4;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[4] + argument(y/MU, 2.0*(cc+x)/(MU*PENROSE_RATIO));
tempconf[nt][1] = argument(0.5*PENROSE_RATIO*y, -2.0*(cc+x)/PENROSE_RATIO) - alpha;
nt++;
}
}
/* rightmost vertical segments */
if (ca > 0.0)
{
t = (LAMBDA - pos[0])/ca;
x = LAMBDA;
y = pos[1] + t*sa;
if ((y >= width)&&(y < MU))
{
cval[nt] = 15;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[15] + y - width;
tempconf[nt][1] = PID - alpha;
nt++;
}
else if ((y <= -width)&&(y > -MU))
{
cval[nt] = 9;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[9] + y + MU;
tempconf[nt][1] = PID - alpha;
nt++;
}
}
/* leftmost vertical segments */
if (ca < 0.0)
{
t = -(LAMBDA + pos[0])/ca;
x = -LAMBDA;
y = pos[1] + t*sa;
if ((y >= width)&&(y < MU))
{
cval[nt] = 1;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[1] + MU - y;
tempconf[nt][1] = 3.0*PID - alpha;
nt++;
}
else if ((y <= -width)&&(y > -MU))
{
cval[nt] = 7;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[7] - width - y;
tempconf[nt][1] = 3.0*PID - alpha;
nt++;
}
}
/* vertical segments of right mushroom head */
if (ca < 0.0)
{
t = (cc - pos[0])/ca;
x = cc;
y = pos[1] + t*sa;
if ((t > 0.0)&&(y >= width)&&(y < MU))
{
cval[nt] = 13;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[13] - y + MU;
tempconf[nt][1] = 3.0*PID - alpha;
nt++;
}
else if ((t > 0.0)&&(y <= -width)&&(y > -MU))
{
cval[nt] = 11;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[11] - y - width;
tempconf[nt][1] = 3.0*PID - alpha;
nt++;
}
}
/* vertical segments of left mushroom head */
if (ca > 0.0)
{
t = (-cc - pos[0])/ca;
x = -cc;
y = pos[1] + t*sa;
if ((t > 0.0)&&(y >= width)&&(y < MU))
{
cval[nt] = 3;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[3] + y - width;
tempconf[nt][1] = PID - alpha;
nt++;
}
else if ((t > 0.0)&&(y <= -width)&&(y > -MU))
{
cval[nt] = 5;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[5] + y + MU;
tempconf[nt][1] = PID - alpha;
nt++;
}
}
/* upper horizontal segments */
if (sa < 0.0)
{
t = (width - pos[1])/sa;
x = pos[0] + t*ca;
y = width;
if ((t > 0.0)&&(x >= cc)&&(x < LAMBDA))
{
cval[nt] = 14;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[14] + x - cc;
tempconf[nt][1] = - alpha;
nt++;
}
else if ((t > 0.0)&&(x <= -cc)&&(x > -LAMBDA))
{
cval[nt] = 2;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[2] + x + LAMBDA;
tempconf[nt][1] = - alpha;
nt++;
}
}
/* lower horizontal segments - TO BE CORRECTED */
if (sa > 0.0)
{
t = (-width - pos[1])/sa;
x = pos[0] + t*ca;
y = -width;
if ((t > 0.0)&&(x >= cc)&&(x < LAMBDA))
{
cval[nt] = 10;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[10] - x + LAMBDA;
tempconf[nt][1] = PI - alpha;
nt++;
}
else if ((t > 0.0)&&(x <= -cc)&&(x > -LAMBDA))
{
cval[nt] = 6;
tval[nt] = t;
x1[nt] = x;
y1[nt] = y;
tempconf[nt][0] = sval[6] - x - cc;
tempconf[nt][1] = PI - alpha;
nt++;
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
// printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
// print_config(config);
return(c);
}
int vpenrose(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_penrose(config, pos, &alpha);
vpenrose_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard with circular scatterers */
/****************************************************************************************/
int pos_circles(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of circle */
/* position varies between 0 and ncircles*2Pi */
/* returns number of hit circle */
{
double angle;
int ncirc;
ncirc = (int)(conf[0]/DPI);
if (ncirc >= ncircles) ncirc = ncircles - 1;
angle = conf[0] - (double)ncirc*DPI;
pos[0] = circles[ncirc].xc + circles[ncirc].radius*cos(angle);
pos[1] = circles[ncirc].yc + circles[ncirc].radius*sin(angle);
*alpha = angle + PID + conf[1];
return(ncirc);
}
int vcircles_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double c0, s0, b, c, t, theta, delta, margin = 1.0e-12, tmin, rlarge = 1000.0;
double tval[ncircles], xint[ncircles], yint[ncircles], phiint[ncircles];
int i, nt = 0, nscat[ncircles], ntmin;
c0 = cos(alpha);
s0 = sin(alpha);
for (i=0; i<ncircles; i++) if (circles[i].active)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nscat[nt] = i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
phiint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
while (phiint[ntmin] < 0.0) phiint[ntmin] += DPI;
while (phiint[ntmin] >= DPI) phiint[ntmin] -= DPI;
config[0] = (double)nscat[ntmin]*DPI + phiint[ntmin];
config[1] = PID - alpha + phiint[ntmin]; /* CHECK */
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
/* set dummy coordinates if circles are absorbing */
if (ABSORBING_CIRCLES)
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
}
return(nscat[ntmin]);
}
else /* there is no intersection - set dummy values */
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
config[2] = 0.0;
config[3] = rlarge;
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = rlarge*cos(alpha);
config[7] = rlarge*sin(alpha);
return(-1);
}
}
int vcircles(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_circles(config, pos, &alpha);
c = vcircles_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard with circular scatterers in a rectangle */
/****************************************************************************************/
int pos_circles_in_rect(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of circle */
/* position varies between 0 and ncircles*2Pi for circles and between -BOUNDARY_SHIFT and 0 for boundary*/
/* returns number of hit circle */
{
double angle;
int ncirc, c;
if (conf[0] >= 0)
{
ncirc = (int)(conf[0]/DPI);
if (ncirc >= ncircles) ncirc = ncircles - 1;
angle = conf[0] - (double)ncirc*DPI;
pos[0] = circles[ncirc].xc + circles[ncirc].radius*cos(angle);
pos[1] = circles[ncirc].yc + circles[ncirc].radius*sin(angle);
*alpha = angle + PID + conf[1];
return(ncirc);
}
else /* particle starts on boundary */
{
// conf[0] += 4.0*(LAMBDA + 1.0);
conf[0] += BOUNDARY_SHIFT;
c = pos_rectangle(conf, pos, alpha);
// conf[0] -= 4.0*(LAMBDA + 1.0);
conf[0] -= BOUNDARY_SHIFT;
return(-c-1);
}
}
int vcircles_in_rect_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
// double config[8], alpha, pos[2];
{
double c0, s0, b, c, t, theta, delta, margin = 1.0e-12, tmin, rlarge = 1.0e10;
double tval[ncircles], xint[ncircles], yint[ncircles], phiint[ncircles];
int i, nt = 0, nscat[ncircles], ntmin, side;
c0 = cos(alpha);
s0 = sin(alpha);
for (i=0; i<ncircles; i++) if (circles[i].active)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nscat[nt] = i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
phiint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
/* test wether intersection is in rectangle */
if ((vabs(xint[nt]) < LAMBDA)&&(vabs(yint[nt]) < 1.0)) nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
while (phiint[ntmin] < 0.0) phiint[ntmin] += DPI;
while (phiint[ntmin] >= DPI) phiint[ntmin] -= DPI;
config[0] = (double)nscat[ntmin]*DPI + phiint[ntmin];
config[1] = PID - alpha + phiint[ntmin]; /* CHECK */
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
/* set dummy coordinates if circles are absorbing */
if (ABSORBING_CIRCLES)
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
// return(DUMMY_SIDE_ABS);
}
if (ABSORBING_CIRCLES) return(DUMMY_SIDE_ABS);
else return(nscat[ntmin]);
}
else /* there is no intersection with the circles - compute intersection with boundary */
{
side = vrectangle_xy(config, alpha, pos);
config[0] -= BOUNDARY_SHIFT;
// config[0] -= 4.0*(LAMBDA+1.0);
// printf("Hit side %i\n", side);
// print_config(config);
return(side - 5);
}
}
int vcircles_in_rect(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_circles_in_rect(config, pos, &alpha);
// vcircles_in_rect_xy(config, alpha, pos);
c = vcircles_in_rect_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard with circular scatterers in a genus n surface (polygon with identifies opposite sides) */
/****************************************************************************************/
int pos_circles_in_genusn(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of circle */
/* position varies between 0 and ncircles*2Pi for circles and between */
/* BOUNDARY_SHIFT and 0 for boundary*/
/* returns number of hit circle */
{
double s, theta, omega, length, s1, angle, x, y;
int ncirc, c;
if (conf[0] >= 0)
{
ncirc = (int)(conf[0]/DPI);
if (ncirc >= ncircles) ncirc = ncircles - 1;
angle = conf[0] - (double)ncirc*DPI;
pos[0] = circles[ncirc].xc + circles[ncirc].radius*cos(angle);
pos[1] = circles[ncirc].yc + circles[ncirc].radius*sin(angle);
*alpha = angle + PID + conf[1];
return(ncirc);
}
else /* particle starts on boundary */
{
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
// conf[0] += 2.0*length*(double)NPOLY;
conf[0] += BOUNDARY_SHIFT;
c = pos_genusn(conf, pos, alpha);
// conf[0] -= 2.0*length*(double)NPOLY;
conf[0] -= BOUNDARY_SHIFT;
return(-c);
}
}
int vcircles_in_genusn_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double c0, s0, b, c, t, theta, delta, margin = 1.0e-12, tmin, rlarge = 1.0e10, omega, length, angle, cw;
double tval[ncircles], xint[ncircles], yint[ncircles], phiint[ncircles];
int i, k, nt = 0, nscat[ncircles], ntmin, side, condition;
c0 = cos(alpha);
s0 = sin(alpha);
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
cw = cos(omega*0.5);
for (i=0; i<ncircles; i++) if (circles[i].active)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nscat[nt] = i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
phiint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
/* test wether intersection is in polygon */
if (in_polygon(xint[nt], yint[nt], 1.0, NPOLY, APOLY)) nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
while (phiint[ntmin] < 0.0) phiint[ntmin] += DPI;
while (phiint[ntmin] >= DPI) phiint[ntmin] -= DPI;
config[0] = (double)nscat[ntmin]*DPI + phiint[ntmin];
config[1] = PID - alpha + phiint[ntmin]; /* CHECK */
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
/* set dummy coordinates if circles are absorbing */
if (ABSORBING_CIRCLES)
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
}
return(nscat[ntmin]);
}
else /* there is no intersection with the circles - compute intersection with boundary */
{
side = vgenusn_xy(config, alpha, pos);
// config[0] -= 2.0*length*(double)NPOLY;
config[0] -= BOUNDARY_SHIFT;
return(side);
}
}
int vcircles_in_genusn(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_circles_in_genusn(config, pos, &alpha);
vcircles_in_genusn_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard with circular scatterers in a torus (rectangle with periodic boundary conditions) */
/****************************************************************************************/
int pos_circles_in_torus(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of circle */
/* position varies between 0 and ncircles*2Pi for circles and between -BOUNDARY_SHIFT and 0 for boundary*/
/* returns number of hit circle */
{
double angle;
int ncirc, c;
if (conf[0] >= 0)
{
ncirc = (int)(conf[0]/DPI);
if (ncirc >= ncircles) ncirc = ncircles - 1;
angle = conf[0] - (double)ncirc*DPI;
pos[0] = circles[ncirc].xc + circles[ncirc].radius*cos(angle);
pos[1] = circles[ncirc].yc + circles[ncirc].radius*sin(angle);
*alpha = angle + PID + conf[1];
return(ncirc);
}
else /* particle starts on boundary */
{
// conf[0] += 4.0*(LAMBDA + 1.0);
conf[0] += BOUNDARY_SHIFT;
c = pos_rectangle(conf, pos, alpha);
// conf[0] -= 4.0*(LAMBDA + 1.0);
conf[0] -= BOUNDARY_SHIFT;
return(-c-1);
}
}
int vcircles_in_torus_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
// double config[8], alpha, pos[2];
{
double c0, s0, b, c, t, theta, delta, margin = 1.0e-12, tmin, rlarge = 1.0e10;
double tval[ncircles], xint[ncircles], yint[ncircles], phiint[ncircles];
int i, nt = 0, nscat[ncircles], ntmin, side;
c0 = cos(alpha);
s0 = sin(alpha);
for (i=0; i<ncircles; i++) if (circles[i].active)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nscat[nt] = i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
phiint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
/* test wether intersection is in rectangle */
if ((vabs(xint[nt]) < LAMBDA)&&(vabs(yint[nt]) < 1.0)) nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
while (phiint[ntmin] < 0.0) phiint[ntmin] += DPI;
while (phiint[ntmin] >= DPI) phiint[ntmin] -= DPI;
config[0] = (double)nscat[ntmin]*DPI + phiint[ntmin];
config[1] = PID - alpha + phiint[ntmin]; /* CHECK */
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
/* set dummy coordinates if circles are absorbing */
if (ABSORBING_CIRCLES)
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
}
return(nscat[ntmin]);
}
else /* there is no intersection with the circles - compute intersection with boundary */
{
side = vrectangle_xy(config, alpha, pos);
if (config[0] < 2.0*LAMBDA) config[0] = 4.0*LAMBDA + 2.0 - config[0];
else if (config[0] < 2.0*LAMBDA + 2.0) config[0] = 6.0*LAMBDA + 4.0 - config[0];
else if (config[0] < 4.0*LAMBDA + 2.0) config[0] = 4.0*LAMBDA + 2.0 - config[0];
else config[0] = 6.0*LAMBDA + 4.0 - config[0];
config[0] -= BOUNDARY_SHIFT;
config[1] = PI - config[1];
// config[0] -= 4.0*(LAMBDA+1.0);
// printf("Hit side %i\n", side);
// print_config(config);
return(side - 5);
}
}
int vcircles_in_torus(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_circles_in_torus(config, pos, &alpha);
vcircles_in_torus_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard in poylgonal line */
/****************************************************************************************/
int pos_polyline(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of domain */
/* position varies between 0 and nsides */
/* returns number of hit setment */
{
double len, rlarge = 1.0e8;
int nside;
nside = (int)conf[0];
if (nside >= nsides) nside = nsides - 1;
if (nside >= 0) /* position is on a side of the polygonal line */
{
len = conf[0] - (double)nside;
pos[0] = polyline[nside].x1 + len*(polyline[nside].x2 - polyline[nside].x1);
pos[1] = polyline[nside].y1 + len*(polyline[nside].y2 - polyline[nside].y1);
*alpha = polyline[nside].angle + conf[1];
return(nside);
}
else /* position is on an absorbing circle */
{
pos[0] = rlarge;
pos[1] = 0.0;
*alpha = 0.0;
return(-1);
}
}
int vpolyline_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double c0, s0, a, b, c, t, dx, delta, s, xi, yi, margin = 1.0e-12, tmin, rlarge = 1.0e8;
double tval[nsides + ncircles], xint[nsides + ncircles], yint[nsides + ncircles], sint[nsides + ncircles];
int i, nt = 0, nsegment[nsides + ncircles], ntmin;
c0 = cos(alpha);
s0 = sin(alpha);
for (i=0; i<nsides; i++)
{
// printf("testing side %i\n", i);
a = polyline[i].y2 - polyline[i].y1;
b = - polyline[i].x2 + polyline[i].x1;
c = -a*polyline[i].x1 - b*polyline[i].y1;
// printf("a = %.2f, b = %.2f, c = %.2f\n", a, b, c);
delta = a*c0 + b*s0;
if (vabs(delta) > margin) /* there is an intersection with the line containing segment i */
{
t = -(a*pos[0] + b*pos[1] + c)/delta;
if (t > margin)
{
xi = pos[0] + t*c0;
yi = pos[1] + t*s0;
dx = polyline[i].x2 - polyline[i].x1;
if (vabs(dx) > margin) s = (xi - polyline[i].x1)/dx;
else s = (yi - polyline[i].y1)/(polyline[i].y2 - polyline[i].y1);
// printf("s = %.2f\n", s);
if ((s >= 0.0)&&(s <= 1.0))
/* the intersection is on the segment */
{
nsegment[nt] = i;
tval[nt] = t;
sint[nt] = s;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
// printf("s = %.2f, x = %.2f, y = %.2f\n", s, xint[nt], yint[nt]);
nt++;
}
}
}
}
if (ABSORBING_CIRCLES) for (i=0; i<ncircles; i++)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nsegment[nt] = -1-i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
sint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
// printf("ntmin = %i\n", ntmin);
if (nsegment[ntmin] >= 0)
{
config[0] = (double)nsegment[ntmin] + sint[ntmin];
config[1] = polyline[nsegment[ntmin]].angle - alpha;
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
}
/* set dummy coordinates if circles are absorbing */
else if ((ABSORBING_CIRCLES)&&(nsegment[ntmin] < 0))
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
}
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
// print_config(config);
return(nsegment[ntmin]);
}
else /* there is no intersection - set dummy values */
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
config[2] = 0.0;
config[3] = rlarge;
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = rlarge*cos(alpha);
config[7] = rlarge*sin(alpha);
return(-1);
}
}
int vpolyline(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_polyline(config, pos, &alpha);
vpolyline_xy(config, alpha, pos);
// c = vpolyline_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* billiard in poylgonal line with additional circular arcs */
/****************************************************************************************/
int pos_polyline_arc(double conf[2], double pos[2], double *alpha)
/* determine position on boundary of domain */
/* position varies between 0 and nsides */
/* returns number of hit setment */
{
double len, angle, rlarge = 1.0e8;
int nside, narc;
nside = (int)conf[0];
if (nside < BOUNDARY_SHIFT)
{
return (pos_polyline(conf, pos, alpha)); /* position is on a line segment */
}
else /* position is on a circular arc */
{
narc = nside - BOUNDARY_SHIFT;
if (narc > narcs) return(0);
len = conf[0] - (double)nside;
angle = arcs[narc].angle1 + len*(arcs[narc].dangle);
pos[0] = arcs[narc].xc + arcs[narc].radius*cos(angle);
pos[1] = arcs[narc].yc + arcs[narc].radius*sin(angle);
*alpha = angle + PID + conf[1];
return(narc + BOUNDARY_SHIFT);
}
}
int vpolyline_arc_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
double c0, s0, x1, y1, a, b, c, t, dx, delta, s, xi, yi, angle, margin = 1.0e-12, tmin, rlarge = 1.0e8;
double tval[nsides + ncircles], xint[nsides + ncircles], yint[nsides + ncircles], sint[nsides + ncircles],
aint[nsides + ncircles];
int i, nt = 0, nsegment[nsides + ncircles], narc[nsides + ncircles], ntmin, sign, type[nsides + ncircles];
c0 = cos(alpha);
s0 = sin(alpha);
/* look for intersections with line segments */
for (i=0; i<nsides; i++)
{
// printf("testing side %i\n", i);
a = polyline[i].y2 - polyline[i].y1;
b = - polyline[i].x2 + polyline[i].x1;
c = -a*polyline[i].x1 - b*polyline[i].y1;
// printf("a = %.2f, b = %.2f, c = %.2f\n", a, b, c);
delta = a*c0 + b*s0;
if (vabs(delta) > margin) /* there is an intersection with the line containing segment i */
{
t = -(a*pos[0] + b*pos[1] + c)/delta;
if (t > margin)
{
xi = pos[0] + t*c0;
yi = pos[1] + t*s0;
dx = polyline[i].x2 - polyline[i].x1;
if (vabs(dx) > margin) s = (xi - polyline[i].x1)/dx;
else s = (yi - polyline[i].y1)/(polyline[i].y2 - polyline[i].y1);
// printf("s = %.2f\n", s);
if ((s >= 0.0)&&(s <= 1.0))
/* the intersection is on the segment */
{
nsegment[nt] = i;
tval[nt] = t;
sint[nt] = s;
// xint[nt] = pos[0] + t*c0;
// yint[nt] = pos[1] + t*s0;
xint[nt] = xi;
yint[nt] = yi;
type[nt] = 0;
// printf("s = %.2f, x = %.2f, y = %.2f\n", s, xint[nt], yint[nt]);
nt++;
}
}
}
}
/* look for intersections with arcs */
for (i=0; i<narcs; i++)
{
x1 = pos[0] - arcs[i].xc;
y1 = pos[1] - arcs[i].yc;
b = x1*c0 + y1*s0;
c = x1*x1 + y1*y1 - arcs[i].radius*arcs[i].radius;
if (b*b - c > margin) for (sign=-1; sign<=1; sign+=2)
{
t = -b + (double)sign*sqrt(b*b - c);
if (t > margin)
{
xi = pos[0] + t*c0;
yi = pos[1] + t*s0;
angle = argument(xi - arcs[i].xc, yi - arcs[i].yc);
if (angle < 0.0) angle += DPI;
if ((angle > arcs[i].angle1)&&(angle < arcs[i].angle1 + arcs[i].dangle))
{
narc[nt] = i;
tval[nt] = t;
sint[nt] = (angle - arcs[i].angle1)/(arcs[i].dangle);
xint[nt] = xi;
yint[nt] = yi;
aint[nt] = angle;
type[nt] = 1;
// printf("s = %.2f, x = %.2f, y = %.2f\n", sint[nt], xint[nt], yint[nt]);
nt++;
}
}
}
}
if (ABSORBING_CIRCLES) for (i=0; i<ncircles; i++)
{
b = (pos[0]-circles[i].xc)*c0 + (pos[1]-circles[i].yc)*s0;
c = (pos[0]-circles[i].xc)*(pos[0]-circles[i].xc) + (pos[1]-circles[i].yc)*(pos[1]-circles[i].yc) - circles[i].radius*circles[i].radius;
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nsegment[nt] = -1-i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
sint[nt] = argument(xint[nt] - circles[i].xc, yint[nt] - circles[i].yc);
nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
// printf("ntmin = %i\n", ntmin);
if ((nsegment[ntmin] >= 0)&&(type[ntmin] == 0)) /* first intersection is with a segment */
{
config[0] = (double)nsegment[ntmin] + sint[ntmin];
config[1] = polyline[nsegment[ntmin]].angle - alpha;
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
}
// else if ((narc[ntmin] >= 0)&&(type[ntmin] == 1)) /* first intersection is with a segment */
else if ((type[ntmin] == 1)) /* first intersection is with an arc */
{
config[0] = BOUNDARY_SHIFT + (double)narc[ntmin] + sint[ntmin];
config[1] = PID + aint[ntmin] - alpha;
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= DPI) config[1] -= DPI;
// printf("s = %.2f, alpha = %.2f, normal = %.2f, theta = %.2f\n", config[0], alpha*180.0/PI, aint[ntmin]*180.0/PI, config[1]*180.0/PI);
}
/* set dummy coordinates if circles are absorbing */
else if ((ABSORBING_CIRCLES)&&(nsegment[ntmin] < 0))
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
}
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
// print_config(config);
/* returned value should be positive for end of trajectory detection */
if (nsegment[ntmin] > 0) return(nsegment[ntmin]);
else return(BOUNDARY_SHIFT-nsegment[ntmin]);
}
else /* there is no intersection - set dummy values */
{
config[0] = DUMMY_ABSORBING;
config[1] = PI;
config[2] = 0.0;
config[3] = rlarge;
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = rlarge*cos(alpha);
config[7] = rlarge*sin(alpha);
return(-1);
}
}
int vpolyline_arc(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], alpha;
int c;
c = pos_polyline_arc(config, pos, &alpha);
vpolyline_arc_xy(config, alpha, pos);
// c = vpolyline_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* general billiard */
/****************************************************************************************/
int pos_billiard(double conf[8], double pos[2], double *alpha)
/* determine initial configuration for start at point pos = (x,y) */
{
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
return(pos_rectangle(conf, pos, alpha));
break;
}
case (D_ELLIPSE):
{
return(pos_ellipse(conf, pos, alpha));
break;
}
case (D_STADIUM):
{
return(pos_stade(conf, pos, alpha));
break;
}
case (D_SINAI):
{
return(pos_sinai(conf, pos, alpha));
break;
}
case (D_TRIANGLE):
{
return(pos_triangle(conf, pos, alpha));
break;
}
case (D_ANNULUS):
{
return(pos_annulus(conf, pos, alpha));
break;
}
case (D_POLYGON):
{
return(pos_polygon(conf, pos, alpha));
break;
}
case (D_REULEAUX):
{
return(pos_reuleaux(conf, pos, alpha));
break;
}
case (D_FLOWER):
{
return(pos_flower(conf, pos, alpha));
break;
}
case (D_ALT_REU):
{
return(pos_alt_reuleaux(conf, pos, alpha));
break;
}
case (D_ANGLE):
{
return(pos_angle(conf, pos, alpha));
break;
}
case (D_LSHAPE):
{
return(pos_lshape(conf, pos, alpha));
break;
}
case (D_GENUSN):
{
return(pos_genusn(conf, pos, alpha));
break;
}
case (D_PARABOLAS):
{
return(pos_parabolas(conf, pos, alpha));
break;
}
case (D_PENROSE):
{
return(pos_penrose(conf, pos, alpha));
break;
}
case (D_CIRCLES):
{
return(pos_circles(conf, pos, alpha));
break;
}
case (D_CIRCLES_IN_RECT):
{
return(pos_circles_in_rect(conf, pos, alpha));
break;
}
case (D_CIRCLES_IN_GENUSN):
{
return(pos_circles_in_genusn(conf, pos, alpha));
break;
}
case (D_CIRCLES_IN_TORUS):
{
return(pos_circles_in_torus(conf, pos, alpha));
break;
}
case (D_POLYLINE):
{
return(pos_polyline(conf, pos, alpha));
break;
}
case (D_POLYLINE_ARCS):
{
return(pos_polyline_arc(conf, pos, alpha));
break;
}
default:
{
printf("Function pos_billiard not defined for this billiard \n");
}
}
}
int vbilliard_xy(double config[8], double alpha, double pos[2])
/* determine initial configuration for start at point pos = (x,y) */
{
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
return(vrectangle_xy(config, alpha, pos));
break;
}
case (D_ELLIPSE):
{
return(vellipse_xy(config, alpha, pos));
break;
}
case (D_STADIUM):
{
return(vstade_xy(config, alpha, pos));
break;
}
case (D_SINAI):
{
return(vsinai_xy(config, alpha, pos));
break;
}
case (D_TRIANGLE):
{
return(vtriangle_xy(config, alpha, pos));
break;
}
case (D_ANNULUS):
{
return(vannulus_xy(config, alpha, pos));
break;
}
case (D_POLYGON):
{
return(vpolygon_xy(config, alpha, pos));
break;
}
case (D_REULEAUX):
{
return(vreuleaux_xy(config, alpha, pos));
break;
}
case (D_FLOWER):
{
return(vflower_xy(config, alpha, pos));
break;
}
case (D_ALT_REU):
{
return(valt_reuleaux_xy(config, alpha, pos));
break;
}
case (D_ANGLE):
{
return(vangle_xy(config, alpha, pos));
break;
}
case (D_LSHAPE):
{
return(vlshape_xy(config, alpha, pos));
break;
}
case (D_GENUSN):
{
return(vgenusn_xy(config, alpha, pos));
break;
}
case (D_PARABOLAS):
{
return(vparabolas_xy(config, alpha, pos));
break;
}
case (D_PENROSE):
{
return(vpenrose_xy(config, alpha, pos));
break;
}
case (D_CIRCLES):
{
return(vcircles_xy(config, alpha, pos));
break;
}
case (D_CIRCLES_IN_RECT):
{
return(vcircles_in_rect_xy(config, alpha, pos));
break;
}
case (D_CIRCLES_IN_GENUSN):
{
return(vcircles_in_genusn_xy(config, alpha, pos));
break;
}
case (D_CIRCLES_IN_TORUS):
{
return(vcircles_in_torus_xy(config, alpha, pos));
break;
}
case (D_POLYLINE):
{
return(vpolyline_xy(config, alpha, pos));
break;
}
case (D_POLYLINE_ARCS):
{
return(vpolyline_arc_xy(config, alpha, pos));
break;
}
default:
{
printf("Function vbilliard_xy not defined for this billiard \n");
}
}
}
/* TO DO: fix returned value */
int vbilliard(double config[8])
/* determine initial configuration when starting from boundary */
{
double pos[2], theta, alpha;
int c;
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
c = pos_rectangle(config, pos, &alpha);
return(vrectangle(config));
break;
}
case (D_ELLIPSE):
{
c = pos_ellipse(config, pos, &alpha);
return(vellipse(config));
break;
}
case (D_STADIUM):
{
c = pos_stade(config, pos, &alpha);
return(vstade(config));
break;
}
case (D_SINAI):
{
c = pos_sinai(config, pos, &alpha);
return(vsinai(config));
break;
}
case (D_TRIANGLE):
{
c = pos_triangle(config, pos, &alpha);
return(vtriangle(config));
break;
}
case (D_ANNULUS):
{
c = pos_annulus(config, pos, &alpha);
return(vannulus(config));
break;
}
case (D_POLYGON):
{
c = pos_polygon(config, pos, &alpha);
return(vpolygon(config));
break;
}
case (D_REULEAUX):
{
c = pos_reuleaux(config, pos, &alpha);
return(vreuleaux(config));
break;
}
case (D_FLOWER):
{
c = pos_flower(config, pos, &alpha);
return(vflower(config));
break;
}
case (D_ALT_REU):
{
c = pos_alt_reuleaux(config, pos, &alpha);
return(valt_reuleaux(config));
break;
}
case (D_ANGLE):
{
c = pos_angle(config, pos, &alpha);
return(vangle(config));
break;
}
case (D_LSHAPE):
{
c = pos_lshape(config, pos, &alpha);
return(vlshape(config));
break;
}
case (D_GENUSN):
{
c = pos_genusn(config, pos, &alpha);
return(vgenusn(config));
break;
}
case (D_PARABOLAS):
{
c = pos_parabolas(config, pos, &alpha);
return(vparabolas(config));
break;
}
case (D_PENROSE):
{
c = pos_penrose(config, pos, &alpha);
return(vpenrose(config));
break;
}
case (D_CIRCLES):
{
c = pos_circles(config, pos, &alpha);
return(vcircles(config));
break;
}
case (D_CIRCLES_IN_RECT):
{
c = pos_circles_in_rect(config, pos, &alpha);
return(vcircles_in_rect(config));
break;
}
case (D_CIRCLES_IN_GENUSN):
{
c = pos_circles_in_genusn(config, pos, &alpha);
return(vcircles_in_genusn(config));
break;
}
case (D_CIRCLES_IN_TORUS):
{
c = pos_circles_in_torus(config, pos, &alpha);
return(vcircles_in_torus(config));
break;
}
case (D_POLYLINE):
{
c = pos_polyline(config, pos, &alpha);
return(vpolyline(config));
break;
}
case (D_POLYLINE_ARCS):
{
c = pos_polyline_arc(config, pos, &alpha);
return(vpolyline_arc(config));
break;
}
default:
{
printf("Function vbilliard not defined for this billiard \n");
}
}
}
int xy_in_billiard(double x, double y)
/* returns 1 if (x,y) represents a point in the billiard */
{
double l2, r1, r2, omega, omega2, c, angle, x1, y1, x2, co, so, x2plus, x2minus, width;
int condition, k;
switch (B_DOMAIN) {
case D_RECTANGLE:
{
if ((vabs(x) <LAMBDA)&&(vabs(y) < 1.0)) return(1);
else return(0);
break;
}
case D_ELLIPSE:
{
if (x*x/(LAMBDA*LAMBDA) + y*y < 1.0) return(1);
else return(0);
break;
}
case D_STADIUM:
{
if ((x > -0.5*LAMBDA)&&(x < 0.5*LAMBDA)&&(y > -1.0)&&(y < 1.0)) return(1);
else if (module2(x+0.5*LAMBDA, y) < 1.0) return(1);
else if (module2(x-0.5*LAMBDA, y) < 1.0) return(1);
else return(0);
break;
}
case D_SINAI:
{
if (x*x + y*y > LAMBDA*LAMBDA) return(1);
else return(0);
break;
}
case D_DIAMOND:
{
l2 = LAMBDA*LAMBDA;
r2 = l2 + (LAMBDA-1.0)*(LAMBDA-1.0);
if ((x*x + y*y < 1.0)&&((x-LAMBDA)*(x-LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2)
&&((x-LAMBDA)*(x-LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2)
&&((x+LAMBDA)*(x+LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2)
&&((x+LAMBDA)*(x+LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2)) return(1);
else return(0);
break;
}
case D_TRIANGLE:
{
if ((x>-LAMBDA)&&(y>-1.0)&&(LAMBDA*y+x<0.0)) return(1);
else return(0);
break;
}
case D_ANNULUS:
{
l2 = LAMBDA*LAMBDA;
r1 = x*x + y*y;
r2 = (x-MU)*(x-MU) + y*y;
if ((r2 > l2)&&(r1 < 1.0)) return(1);
else return(0);
break;
}
case D_POLYGON:
{
return(in_polygon(x, y, 1.0, NPOLY, APOLY));
break;
}
case D_REULEAUX:
{
condition = 1;
omega2 = PI/((double)NPOLY);
co = cos(omega2);
so = sin(omega2);
if (LAMBDA > 0.0) x2 = co + sqrt(LAMBDA*LAMBDA - so*so);
else x2 = co - sqrt(LAMBDA*LAMBDA - so*so);
for (k=0; k<NPOLY; k++)
{
angle = 2.0*(double)k*omega2 + APOLY*PID;
x1 = x*cos(angle) + y*sin(angle);
y1 = -x*sin(angle) + y*cos(angle);
if (LAMBDA > 0.0) condition = condition*((x1-x2)*(x1-x2) + y1*y1 > LAMBDA*LAMBDA);
else condition = condition*((x1-x2)*(x1-x2) + y1*y1 < LAMBDA*LAMBDA);
}
return(condition);
break;
}
/* D_REULEAUX : distance to all centers of arcs should be larger than LAMBDA */
case D_FLOWER:
{
/* TO DO */
return(1);
break;
}
case D_ALT_REU:
{
condition = 1;
omega2 = PI/((double)NPOLY);
co = cos(omega2);
so = sin(omega2);
x2plus = co + sqrt(LAMBDA*LAMBDA - so*so);
x2minus = co - sqrt(LAMBDA*LAMBDA - so*so);
for (k=0; k<NPOLY; k++)
{
angle = 2.0*(double)k*omega2 + APOLY*PID;
x1 = x*cos(angle) + y*sin(angle);
y1 = -x*sin(angle) + y*cos(angle);
if (k%2==0) condition = condition*((x1-x2plus)*(x1-x2plus) + y1*y1 > LAMBDA*LAMBDA);
else condition = condition*((x1-x2minus)*(x1-x2minus) + y1*y1 < LAMBDA*LAMBDA);
}
return(condition);
break;
}
case D_ANGLE:
{
if (y <= 0.0) return(0);
else if (x*sin(LAMBDA*PI) < -y*cos(LAMBDA*PI)) return(1);
else return(0);
break;
}
case D_LSHAPE:
{
if ((y <= 0.0)&&(x >= -1.0)&&(x <= 1.0)) return(1);
else if ((x >= -1.0)&&(x <= 0.0)) return(1);
else return(0);
break;
}
case D_GENUSN: /* same as polygon */
{
return(in_polygon(x, y, 1.0, NPOLY, APOLY));
break;
}
case D_PARABOLAS:
{
condition = 1;
omega = DPI/((double)NPOLY);
for (k=0; k<NPOLY; k++)
{
angle = APOLY*PID + (double)k*omega;
x1 = x*cos(angle) + y*sin(angle);
y1 = -x*sin(angle) + y*cos(angle);
condition = condition*(x1 < LAMBDA + MU - 0.25*y1*y1/MU);
}
return(condition);
}
case D_PENROSE:
{
c = sqrt(LAMBDA*LAMBDA - (1.0 - MU)*(1.0 - MU));
width = 0.1*MU;
x1 = vabs(x);
y1 = vabs(y);
/* sides */
if (vabs(x) >= LAMBDA) return(0);
/* upper and lower ellipse */
else if ((vabs(y) >= MU)&&(x*x/(LAMBDA*LAMBDA) + (y1-MU)*(y1-MU)/((1.0-MU)*(1.0-MU)) >= 1.0)) return(0);
/* small ellipses */
else if ((vabs(x) <= c)&&(4.0*(x1-c)*(x1-c)/(MU*MU*PENROSE_RATIO*PENROSE_RATIO) + y*y/(MU*MU) <= 1.0)) return(0);
/* straight parts */
else if ((vabs(x) >= c)&&(vabs(y) <= width)) return(0);
else return(1);
}
case D_CIRCLES:
{
condition = 1;
for (k=0; k<ncircles; k++)
if (circles[k].active) condition = condition*out_circle(x-circles[k].xc, y-circles[k].yc, circles[k].radius);
// if (circleactive[k]) condition = condition*out_circle(x-circlex[k], y-circles[k].yc, circlerad[k]);
return(condition);
break;
}
case D_CIRCLES_IN_RECT:
{
if ((vabs(x) >= LAMBDA)||(vabs(y) >= 1.0)) return(0);
else
{
condition = 1;
for (k=0; k<ncircles; k++)
if (circles[k].active) condition = condition*out_circle(x-circles[k].xc, y-circles[k].yc, circles[k].radius);
return(condition);
}
break;
}
case D_CIRCLES_IN_GENUSN:
{
condition = in_polygon(x, y, 1.0, NPOLY, APOLY);
if (condition == 0) return(0);
else /* test whether (x,y) outside all circles */
{
condition = 1;
for (k=0; k<ncircles; k++)
condition = condition*circles[k].active*out_circle(x-circles[k].xc, y-circles[k].yc, circles[k].radius);
return(condition);
}
break;
}
case D_CIRCLES_IN_TORUS: /* same as D_CIRCLES_IN_RECT */
{
if ((vabs(x) >= LAMBDA)||(vabs(y) >= 1.0)) return(0);
else
{
condition = 1;
for (k=0; k<ncircles; k++)
if (circles[k].active) condition = condition*out_circle(x-circles[k].xc, y-circles[k].yc, circles[k].radius);
return(condition);
}
break;
}
case D_POLYLINE:
{
/* not easy to implement for non-convex polygons */
if (POLYLINE_PATTERN == P_MAZE) return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else if ((POLYLINE_PATTERN == P_MAZE_DIAG)||(POLYLINE_PATTERN == P_MAZE_RANDOM))
return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else if ((POLYLINE_PATTERN == P_MAZE_CIRCULAR)||(POLYLINE_PATTERN == P_MAZE_HEX)||(POLYLINE_PATTERN == P_MAZE_OCT))
return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else return(1);
break;
}
case D_POLYLINE_ARCS:
{
/* not easy to implement for non-convex polygons */
if (POLYLINE_PATTERN == P_MAZE) return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else if ((POLYLINE_PATTERN == P_MAZE_DIAG)||(POLYLINE_PATTERN == P_MAZE_RANDOM))
return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else if (POLYLINE_PATTERN == P_MAZE_CIRCULAR)
return ((vabs(x) < 1.1*XMAX)&&(vabs(y) < 1.1*YMAX));
else return(1);
break;
}
default:
{
printf("Function ij_in_billiard not defined for this billiard \n");
return(1);
}
}
}
void init_circles(t_circle circles[NMAXCIRCLES])
{
int i, j, k, n, ncirc0, n_p_active, ncandidates=5000, naccepted;
double dx, dy, xx[4], yy[4], x, y, gamma, height, phi, r0, r, dpoisson = 3.25*MU;
short int active_poisson[NMAXCIRCLES], far;
switch (CIRCLE_PATTERN) {
case (C_FOUR_CIRCLES):
{
ncircles = 4;
circles[0].xc = 1.0;
circles[0].yc = 0.0;
circles[0].radius = 0.8;
circles[1].xc = -1.0;
circles[1].yc = 0.0;
circles[1].radius = 0.8;
circles[2].xc = 0.0;
circles[2].yc = 0.8;
circles[2].radius = 0.4;
circles[3].xc = 0.0;
circles[3].yc = -0.8;
circles[3].radius = 0.4;
for (i=0; i<4; i++) circles[i].active = 1;
break;
}
case (C_SQUARE):
{
ncircles = NCX*NCY;
dy = (YMAX - YMIN)/((double)NCY);
for (i = 0; i < NCX; i++)
for (j = 0; j < NCY; j++)
{
n = NCY*i + j;
circles[n].xc = ((double)(i-NCX/2) + 0.5)*dy;
circles[n].yc = YMIN + ((double)j + 0.5)*dy;
circles[n].radius = MU;
circles[n].active = 1;
}
break;
}
case (C_HEX):
{
ncircles = NCX*(NCY+1);
dy = (YMAX - YMIN)/((double)NCY);
dx = dy*0.5*sqrt(3.0);
for (i = 0; i < NCX; i++)
for (j = 0; j < NCY+1; j++)
{
n = (NCY+1)*i + j;
circles[n].xc = ((double)(i-NCX/2) + 0.5)*dy;
circles[n].yc = YMIN + ((double)j - 0.5)*dy;
if ((i+NCX)%2 == 1) circles[n].yc += 0.5*dy;
circles[n].radius = MU;
circles[n].active = 1;
}
break;
}
case (C_TRI):
{
ncircles = NCX*(NCY+1);
dy = (YMAX - YMIN)/((double)NCY);
dx = dy*0.5*sqrt(3.0);
// dx = (XMAX - XMIN)/((double)NCX);
// dy = dx/(0.5*sqrt(3.0));
for (i = 0; i < NCX; i++)
for (j = 0; j < NCY+1; j++)
{
n = (NCY+1)*i + j;
circles[n].xc = ((double)(i-NCX/2) + 0.5)*dx;
circles[n].yc = YMIN + ((double)j - 0.5)*dy;
if ((i+NCX)%2 == 1) circles[n].yc += 0.5*dy;
circles[n].radius = MU;
circles[n].active = 1;
}
break;
}
case (C_GOLDEN_MEAN):
{
ncircles = 200;
gamma = (sqrt(5.0) - 1.0)*0.5; /* golden mean */
height = YMAX - YMIN;
dx = 2.0*LAMBDA/((double)ncircles);
for (n = 0; n < ncircles; n++)
{
circles[n].xc = -LAMBDA + n*dx;
circles[n].yc = y;
y += height*gamma;
if (y > YMAX) y -= height;
circles[n].radius = MU;
circles[n].active = 1;
}
break;
}
case (C_GOLDEN_SPIRAL):
{
ncircles = 1;
circles[0].xc = 0.0;
circles[0].yc = 0.0;
gamma = (sqrt(5.0) - 1.0)*PI; /* golden mean times 2Pi */
phi = 0.0;
r0 = 2.0*MU;
r = r0 + MU;
for (i=0; i<NGOLDENSPIRAL; i++)
{
x = r*cos(phi);
y = r*sin(phi);
phi += gamma;
r += MU*r0/r;
if ((vabs(x) < LAMBDA)&&(vabs(y) < YMAX + MU))
{
circles[ncircles].xc = x;
circles[ncircles].yc = y;
ncircles++;
}
}
for (i=0; i<ncircles; i++)
{
circles[i].radius = MU;
/* inactivate circles outside the domain */
if ((circles[i].yc < YMAX + MU)&&(circles[i].yc > YMIN - MU)) circles[i].active = 1;
}
break;
}
case (C_RAND_DISPLACED):
{
ncircles = NCX*NCY;
dy = (YMAX - YMIN)/((double)NCY);
for (i = 0; i < NCX; i++)
for (j = 0; j < NCY; j++)
{
n = NCY*i + j;
circles[n].xc = ((double)(i-NCX/2) + 0.5*((double)rand()/RAND_MAX - 0.5))*dy;
circles[n].yc = YMIN + ((double)j + 0.5 + 0.5*((double)rand()/RAND_MAX - 0.5))*dy;
circles[n].radius = MU*sqrt(1.0 + 0.8*((double)rand()/RAND_MAX - 0.5));
circles[n].active = 1;
}
break;
}
case (C_RAND_POISSON):
{
ncircles = NPOISSON;
for (n = 0; n < NPOISSON; n++)
{
circles[n].xc = LAMBDA*(2.0*(double)rand()/RAND_MAX - 1.0);
circles[n].yc = (YMAX - YMIN)*(double)rand()/RAND_MAX + YMIN;
circles[n].radius = MU;
circles[n].active = 1;
}
break;
}
case (C_POISSON_DISC):
{
printf("Generating Poisson disc sample\n");
/* generate first circle */
circles[0].xc = LAMBDA*(2.0*(double)rand()/RAND_MAX - 1.0);
circles[0].yc = (YMAX - YMIN)*(double)rand()/RAND_MAX + YMIN;
active_poisson[0] = 1;
n_p_active = 1;
ncircles = 1;
while ((n_p_active > 0)&&(ncircles < NMAXCIRCLES))
{
/* randomly select an active circle */
i = rand()%(ncircles);
while (!active_poisson[i]) i = rand()%(ncircles);
// printf("Starting from circle %i at (%.3f,%.3f)\n", i, circlex[i], circley[i]);
/* generate new candidates */
naccepted = 0;
for (j=0; j<ncandidates; j++)
{
r = dpoisson*(2.0*(double)rand()/RAND_MAX + 1.0);
phi = DPI*(double)rand()/RAND_MAX;
x = circles[i].xc + r*cos(phi);
y = circles[i].yc + r*sin(phi);
// printf("Testing new circle at (%.3f,%.3f)\t", x, y);
far = 1;
for (k=0; k<ncircles; k++) if ((k!=i))
{
/* new circle is far away from circle k */
far = far*((x - circles[k].xc)*(x - circles[k].xc) + (y - circles[k].yc)*(y - circles[k].yc) >= dpoisson*dpoisson);
/* new circle is in domain */
far = far*(vabs(x) < LAMBDA)*(y < YMAX)*(y > YMIN);
}
if (far) /* accept new circle */
{
printf("New circle at (%.3f,%.3f) accepted\n", x, y);
circles[ncircles].xc = x;
circles[ncircles].xc = y;
circles[ncircles].radius = MU;
circles[ncircles].active = 1;
active_poisson[ncircles] = 1;
ncircles++;
n_p_active++;
naccepted++;
}
// else printf("Rejected\n");
}
if (naccepted == 0) /* inactivate circle i */
{
// printf("No candidates work, inactivate circle %i\n", i);
active_poisson[i] = 0;
n_p_active--;
}
printf("%i active circles\n", n_p_active);
}
printf("Generated %i circles\n", ncircles);
break;
}
case (C_LASER):
{
ncircles = 17;
xx[0] = 0.5*(x_shooter + x_target);
xx[1] = LAMBDA - 0.5*(x_target - x_shooter);
if (xx[1] > LAMBDA) xx[1] = 2.0*LAMBDA - xx[1];
xx[2] = -xx[0];
xx[3] = -xx[1];
yy[0] = 0.5*(y_shooter + y_target);
yy[1] = 1.0 - 0.5*(y_target - y_shooter);
if (yy[1] > 1.0) yy[1] = 2.0 - yy[1];
yy[2] = -yy[0];
yy[3] = -yy[1];
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
{
circles[4*i + j].xc = xx[i];
circles[4*i + j].yc = yy[j];
}
circles[ncircles - 1].xc = x_target;
circles[ncircles - 1].yc = y_target;
for (i=0; i<ncircles - 1; i++)
{
circles[i].radius = MU;
circles[i].active = 1;
}
circles[ncircles - 1].radius = 0.5*MU;
circles[ncircles - 1].active = 2;
break;
}
default:
{
printf("Function init_circle_config not defined for this pattern \n");
}
}
}
int add_rectangle_to_polyline(double xc, double yc, double width, double height, t_segment polyline[NMAXPOLY], t_circle circles[NMAXCIRCLES])
/* add a rectangle to polyline pattern */
{
int i;
polyline[nsides].x1 = xc - 0.5*width;
polyline[nsides].y1 = yc - 0.5*height;
polyline[nsides].length = width;
polyline[nsides].angle = 0.0;
polyline[nsides+1].x1 = xc + 0.5*width;
polyline[nsides+1].y1 = yc - 0.5*height;
polyline[nsides+1].length = height;
polyline[nsides+1].angle = PID;
polyline[nsides+2].x1 = xc + 0.5*width;
polyline[nsides+2].y1 = yc + 0.5*height;
polyline[nsides+2].length = width;
polyline[nsides+2].angle = PI;
polyline[nsides+3].x1 = xc - 0.5*width;
polyline[nsides+3].y1 = yc + 0.5*height;
polyline[nsides+3].length = height;
polyline[nsides+3].angle = 3.0*PID;
if (nsides+4 < NMAXPOLY) for (i=nsides; i<nsides+4; i++)
{
polyline[i].color = 0;
if (i < nsides+3) polyline[i].x2 = polyline[i+1].x1;
else polyline[i].x2 = polyline[nsides].x1;
if (i < nsides+3) polyline[i].y2 = polyline[i+1].y1;
else polyline[i].y2 = polyline[nsides].y1;
}
else printf("Increase NMAXPOLY\n");
if (nsides+4 < NMAXCIRCLES) for (i=nsides; i<nsides+4; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
else
{
printf("Increase NMAXCIRCLES\n");
return(0);
}
nsides += 4;
ncircles += 4;
return(1);
}
int axial_symmetry_tsegment(t_segment z1, t_segment z2, t_segment z, t_segment *zprime)
/* compute reflection of point z wrt axis through z1 and z2 */
{
double r, zdotu;
t_segment u, zparallel, zperp;
/* compute unit vector parallel to z1-z2 */
u.x1 = z2.x1 - z1.x1;
u.y1 = z2.y1 - z1.y1;
r = module2(u.x1, u.y1);
if (r == 0) return(0); /* z1 and z2 are the same */
u.x1 = u.x1/r;
u.y1 = u.y1/r;
/* projection of z1z on z1z2 */
zdotu = (z.x1 - z1.x1)*u.x1 + (z.y1 - z1.y1)*u.y1;
zparallel.x1 = zdotu*u.x1;
zparallel.y1 = zdotu*u.y1;
/* normal vector to z1z2 */
zperp.x1 = z.x1 - z1.x1 - zparallel.x1;
zperp.y1 = z.y1 - z1.y1 - zparallel.y1;
/* reflected point */
zprime->x1 = z.x1 - 2.0*zperp.x1;
zprime->y1 = z.y1 - 2.0*zperp.y1;
return(1);
}
void init_polyline_circular_maze(t_segment* polyline, t_circle* circles, t_arc* arcs, t_maze* maze)
{
int nblocks, block, i, j, n, p, q;
double rmin, rmax, angle, r, dr, phi, dphi, ww;
/* build walls of maze */
nblocks = NYMAZE/NXMAZE;
rmin = 0.15;
rmax = 1.0;
angle = DPI/(double)nblocks;
dr = (rmax - rmin)/(double)(NXMAZE);
nsides = 0;
ncircles = 0;
/* add straight walls */
for (block = 0; block < nblocks; block++)
{
dphi = angle;
/* first circle */
n = nmaze(0, block*NXMAZE);
r = rmin;
phi = (double)block*angle;
if (maze[n].south)
{
polyline[nsides].x1 = r*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y1 = r*sin(phi);
polyline[nsides].x2 = (r+dr)*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y2 = (r+dr)*sin(phi);
polyline[nsides].angle = phi;
nsides++;
}
/* second circle */
r = rmin + dr;
dphi *= 0.5;
for (q=0; q<2; q++)
{
n = nmaze(1, block*NXMAZE + q);
phi = (double)(block)*angle + (double)q*dphi;
if (maze[n].south)
{
polyline[nsides].x1 = r*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y1 = r*sin(phi);
polyline[nsides].x2 = (r+dr)*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y2 = (r+dr)*sin(phi);
polyline[nsides].angle = phi;
nsides++;
}
}
/* other circles */
ww = 2;
i = 2;
while (ww < NXMAZE)
{
dphi *= 0.5;
for (p = 0; p < ww; p++)
{
r = rmin + (double)i*dr;
// printf("Segment, i = %i, dphi = %.2lg, r = %.2lg\n", i, dphi, r);
for (q = 0; q < 2*ww; q++)
{
j = block*NXMAZE + q;
n = nmaze(i,j);
phi = (double)(block)*angle + (double)q*dphi;
if (maze[n].south)
{
polyline[nsides].x1 = r*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y1 = r*sin(phi);
polyline[nsides].x2 = (r+dr)*cos(phi) + MAZE_XSHIFT;
polyline[nsides].y2 = (r+dr)*sin(phi);
polyline[nsides].angle = phi;
nsides++;
}
}
i++;
}
ww *= 2;
}
}
/* add circular arcs */
narcs = 0;
for (block = 0; block < nblocks; block++)
{
dphi = angle;
/* first circle */
n = nmaze(0, block*NXMAZE);
r = rmin;
phi = (double)block*angle;
if ((block > 0)&&(maze[n].west))
{
arcs[narcs].xc = MAZE_XSHIFT;
arcs[narcs].yc = 0.0;
arcs[narcs].radius = r;
arcs[narcs].angle1 = phi;
arcs[narcs].dangle = dphi;
narcs++;
}
/* second circle */
r = rmin + dr;
dphi *= 0.5;
for (q=0; q<2; q++)
{
n = nmaze(1, block*NXMAZE + q);
phi = (double)(block)*angle + (double)q*dphi;
if (maze[n].west)
{
arcs[narcs].xc = MAZE_XSHIFT;
arcs[narcs].yc = 0.0;
arcs[narcs].radius = r;
arcs[narcs].angle1 = phi;
arcs[narcs].dangle = dphi;
narcs++;
}
}
/* other circles */
ww = 2;
i = 2;
while (ww < NXMAZE)
{
dphi *= 0.5;
for (p = 0; p < ww; p++)
{
r = rmin + (double)i*dr;
printf("Circle, i = %i, dphi = %.2lg, r = %.2lg\n", i, dphi, r);
for (q = 0; q < 2*ww; q++)
{
j = block*NXMAZE + q;
n = nmaze(i,j);
phi = (double)(block)*angle + (double)q*dphi;
if (maze[n].west)
{
arcs[narcs].xc = MAZE_XSHIFT;
arcs[narcs].yc = 0.0;
arcs[narcs].radius = r;
arcs[narcs].angle1 = phi;
arcs[narcs].dangle = dphi;
narcs++;
}
}
i++;
}
ww *= 2;
}
}
/* outer boundary of maze */
arcs[narcs].xc = MAZE_XSHIFT;
arcs[narcs].yc = 0.0;
arcs[narcs].radius = rmax;
if (CLOSE_MAZE)
{
arcs[narcs].angle1 = 0.0;
arcs[narcs].dangle = DPI;
}
else
{
arcs[narcs].angle1 = dphi;
arcs[narcs].dangle = DPI - dphi;
}
narcs++;
}
void init_polyline_hex_maze(t_segment* polyline, t_circle* circles, t_maze* maze)
{
int i, j, n;
double r, r1, x1, y1, padding = 0.02, h;
r = 2.0*(YMAX - YMIN)/(3.0*((double)(NXMAZE)-0.5));
r1 = (YMAX - YMIN)/(sqrt(3.0)*(double)(NYMAZE+1));
if (r1 < r) r = r1;
h = 0.5*sqrt(3.0)*r;
for (i = 0; i < NXMAZE; i++)
for (j = 0; j < NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + 1.5*(double)i*r + MAZE_XSHIFT;
y1 = YMIN + padding + h + 2.0*(double)j*h;
if (i%2 == 0) y1 += h;
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].southwest))
{
polyline[nsides].x1 = x1 - 0.5*r;
polyline[nsides].y1 = y1 - h;
polyline[nsides].x2 = x1 - r;
polyline[nsides].y2 = y1;
polyline[nsides].angle = DPI/3.0;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1 - 0.5*r;
polyline[nsides].y1 = y1 - h;
polyline[nsides].x2 = x1 + 0.5*r;
polyline[nsides].y2 = y1 - h;
polyline[nsides].angle = 0.0;
nsides++;
}
if (maze[n].northwest)
{
polyline[nsides].x1 = x1 - r;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1 - 0.5*r;
polyline[nsides].y2 = y1 + h;
polyline[nsides].angle = PI/3.0;
nsides++;
}
if (((j==0)||(i==NXMAZE-1))&&(maze[n].southeast))
{
polyline[nsides].x1 = x1 + 0.5*r;
polyline[nsides].y1 = y1 - h;
polyline[nsides].x2 = x1 + r;
polyline[nsides].y2 = y1;
polyline[nsides].angle = PI/3.0;
nsides++;
}
if ((j==NYMAZE-1)&&(maze[n].north))
{
polyline[nsides].x1 = x1 - 0.5*r;
polyline[nsides].y1 = y1 + h;
polyline[nsides].x2 = x1 + 0.5*r;
polyline[nsides].y2 = y1 + h;
polyline[nsides].angle = 0.0;
nsides++;
}
if (((j==NYMAZE-1)||((i==NXMAZE-1)&&(j!=NYMAZE/2-1)))&&(maze[n].northeast))
{
polyline[nsides].x1 = x1 + r;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1 + 0.5*r;
polyline[nsides].y2 = y1 + h;
polyline[nsides].angle = DPI/3.0;
nsides++;
}
}
/* left side of maze */
x1 = YMIN + padding + MAZE_XSHIFT - 0.5*r;
y1 = YMIN + padding + h;
polyline[nsides].x1 = x1 + 1.5*r;
polyline[nsides].y1 = YMIN - MAZE_VERTICAL_EXTENSION;
polyline[nsides].x2 = x1 + 1.5*r;
polyline[nsides].y2 = y1 - h;
polyline[nsides].angle = PID;
nsides++;
y1 = YMIN + padding + 3.0*h + 2.0*(double)(NYMAZE-1)*h;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + MAZE_VERTICAL_EXTENSION;
polyline[nsides].angle = PID;
nsides++;
/* right side of maze */
x1 = YMIN + padding + 1.5*(double)(NXMAZE-1)*r + MAZE_XSHIFT + 0.5*r;
y1 = YMIN + padding;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - MAZE_VERTICAL_EXTENSION;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1;
polyline[nsides].angle = PID;
nsides++;
y1 = YMIN + padding + 2.0*h + 2.0*(double)(NYMAZE-1)*h;
polyline[nsides].x1 = x1 - 1.5*r;
polyline[nsides].y1 = y1 + h;
polyline[nsides].x2 = x1 - 1.5*r;
polyline[nsides].y2 = YMAX + MAZE_VERTICAL_EXTENSION;
polyline[nsides].angle = PID;
nsides++;
/* add circular arcs in corners */
if (B_DOMAIN == D_POLYLINE_ARCS)
{
narcs = 0;
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + 1.5*(double)i*r + MAZE_XSHIFT;
y1 = YMIN + padding + h + 2.0*(double)j*h;
if (i%2 == 0) y1 += h;
if (((i < NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].northeast)&&(maze[n].north))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = PI/6.0;
narcs++;
}
if (((i > 0)||(j!=NYMAZE/2))&&(maze[n].north)&&(maze[n].northwest))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = PID;
narcs++;
}
if (((i > 0)||(j!=NYMAZE/2))&&(maze[n].northwest)&&(maze[n].southwest))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = 5.0*PI/6.0;
narcs++;
}
if (((i > 0)||(j!=NYMAZE/2))&&(maze[n].southwest)&&(maze[n].south))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = 7.0*PI/6.0;
narcs++;
}
if (((i > 0)||(j!=NYMAZE/2))&&(maze[n].south)&&(maze[n].southeast))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = 3.0*PID;
narcs++;
}
if (((i < NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].southeast)&&(maze[n].northeast))
{
arcs[narcs].xc = x1;
arcs[narcs].yc = y1;
arcs[narcs].radius = h;
arcs[narcs].dangle = PI/3.0;
arcs[narcs].angle1 = 11.0*PI/6.0;
narcs++;
}
}
}
}
void init_polyline_oct_maze(t_segment* polyline, t_circle* circles, t_maze* maze)
{
int i, j, n;
double a, b, a2, c, dx, x1, y1, padding = 0.02;
dx = (YMAX - YMIN - 2.0*padding)/((double)NYMAZE+0.5);
a = dx*(2.0 - sqrt(2.0));
b = a/sqrt(2.0);
a2 = 0.5*a;
c = a2 + b;
for (i = 0; i < NXMAZE; i++)
for (j = 0; j < NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + ((double)i + 0.5)*dx + MAZE_XSHIFT;
y1 = YMIN + padding + ((double)j + 0.75)*dx;
if ((i+j)%2 == 0)
{
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].west))
{
polyline[nsides].x1 = x1 - c;
polyline[nsides].y1 = y1 - a2;
polyline[nsides].x2 = x1 - c;
polyline[nsides].y2 = y1 + a2;
polyline[nsides].angle = PID;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1 - a2;
polyline[nsides].y1 = y1 - c;
polyline[nsides].x2 = x1 + a2;
polyline[nsides].y2 = y1 - c;
polyline[nsides].angle = 0.0;
nsides++;
}
if (maze[n].southwest)
{
polyline[nsides].x1 = x1 - a2;
polyline[nsides].y1 = y1 - c;
polyline[nsides].x2 = x1 - c;
polyline[nsides].y2 = y1 - a2;
polyline[nsides].angle = 1.5*PID;
nsides++;
}
if (maze[n].northwest)
{
polyline[nsides].x1 = x1 - c;
polyline[nsides].y1 = y1 + a2;
polyline[nsides].x2 = x1 - a2;
polyline[nsides].y2 = y1 + c;
polyline[nsides].angle = 0.5*PID;
nsides++;
}
}
else
{
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].west))
{
polyline[nsides].x1 = x1 - a2;
polyline[nsides].y1 = y1 - a2;
polyline[nsides].x2 = x1 - a2;
polyline[nsides].y2 = y1 + a2;
polyline[nsides].angle = PID;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1 - a2;
polyline[nsides].y1 = y1 - a2;
polyline[nsides].x2 = x1 + a2;
polyline[nsides].y2 = y1 - a2;
polyline[nsides].angle = 0.0;
nsides++;
}
}
}
/* bottom of maze */
for (i=0; i<NXMAZE; i+=2)
{
n = nmaze(i, 0);
x1 = YMIN + padding + ((double)i + 0.5)*dx + MAZE_XSHIFT;
y1 = YMIN + padding + 0.75*dx;
polyline[nsides].x1 = x1 + a2;
polyline[nsides].y1 = y1 - c;
polyline[nsides].x2 = x1 + c;
polyline[nsides].y2 = y1 - a2;
polyline[nsides].angle = 0.5*PID;
nsides++;
}
/* top of maze */
for (i=0; i<NXMAZE; i++)
{
n = nmaze(i, NYMAZE-1);
x1 = YMIN + padding + ((double)i + 0.5)*dx + MAZE_XSHIFT;
y1 = YMIN + padding + ((double)(NYMAZE-1) + 0.75)*dx;
if ((i+NYMAZE-1)%2 == 0)
{
polyline[nsides].x1 = x1 + c;
polyline[nsides].y1 = y1 + a2;
polyline[nsides].x2 = x1 + a2;
polyline[nsides].y2 = y1 + c;
polyline[nsides].angle = 1.5*PID;
nsides++;
polyline[nsides].x1 = x1 + a2;
polyline[nsides].y1 = y1 + c;
polyline[nsides].x2 = x1 - a2;
polyline[nsides].y2 = y1 + c;
polyline[nsides].angle = 0.0;
nsides++;
}
else
{
polyline[nsides].x1 = x1 + a2;
polyline[nsides].y1 = y1 + a2;
polyline[nsides].x2 = x1 - a2;
polyline[nsides].y2 = y1 + a2;
polyline[nsides].angle = 0.0;
nsides++;
}
}
/* right side of maze */
for (j=0; j<NYMAZE; j++)
{
n = nmaze(NXMAZE-1, j);
x1 = YMIN + padding + ((double)(NXMAZE-1) + 0.5)*dx + MAZE_XSHIFT;
y1 = YMIN + padding + ((double)j + 0.75)*dx;
if ((NXMAZE-1+j)%2 == 0)
{
polyline[nsides].x1 = x1 + a2;
polyline[nsides].y1 = y1 - c;
polyline[nsides].x2 = x1 + c;
polyline[nsides].y2 = y1 - a2;
polyline[nsides].angle = 0.5*PID;
nsides++;
polyline[nsides].x1 = x1 + c;
polyline[nsides].y1 = y1 + a2;
polyline[nsides].x2 = x1 + a2;
polyline[nsides].y2 = y1 + c;
polyline[nsides].angle = 1.5*PID;
nsides++;
if ((j!=NYMAZE/2)&&(j!=NYMAZE/2+1))
{
polyline[nsides].x1 = x1 + c;
polyline[nsides].y1 = y1 - a2;
polyline[nsides].x2 = x1 + c;
polyline[nsides].y2 = y1 + a2;
polyline[nsides].angle = PID;
nsides++;
}
}
else
{
polyline[nsides].x1 = x1 + a2;
polyline[nsides].y1 = y1 - a2;
polyline[nsides].x2 = x1 + a2;
polyline[nsides].y2 = y1 + a2;
polyline[nsides].angle = PID;
nsides++;
}
}
/* add circular arcs in corners */
if (B_DOMAIN == D_POLYLINE_ARCS)
{
narcs = 0;
}
}
void compute_maze_boundaries(int type, double *xmin, double *xmax)
{
double r, r1, h, padding = 0.02;
switch (type) {
case (P_MAZE_HEX):
{
r = 2.0*(YMAX - YMIN)/(3.0*((double)(NXMAZE)-0.5));
r1 = 2.0*(YMAX - YMIN)/(sqrt(3.0)*(double)(NYMAZE));
if (r1 < r) r = r1;
*xmin = YMIN + padding + MAZE_XSHIFT - 2.0*r;
*xmax = YMIN + padding + 1.5*(double)(NXMAZE-1)*r + MAZE_XSHIFT + 2.0*r;
printf("xmin = %.3lg, xmax = %.3lg\n", *xmin, *xmax);
break;
}
default:
{
*xmin = YMIN + MAZE_XSHIFT;
*xmax = YMAX + MAZE_XSHIFT;
break;
}
}
}
void init_polyline(t_segment polyline[NMAXPOLY], t_circle circles[NMAXCIRCLES], t_arc arcs[NMAXCIRCLES])
{
int i, j, k, l, n, z, ii, jj, terni[SDEPTH], ternj[SDEPTH], quater[SDEPTH], cond, p, q, block, nblocks, ww;
short int vkoch[NMAXCIRCLES], turnright;
double ratio, omega, angle, sw, length, dist, x, y, ta, tb, a, b, ra, rb, r,
x1, y1, x2, y2, dx, dy, padding = 0.02, width = 0.01, xright, yright, xtop, ytop, rand_factor, rmin, rmax, dr, phi, dphi, rscat;
double *maze_coords;
t_maze* maze;
narcs = 0; /* default value */
switch (POLYLINE_PATTERN) {
case (P_RECTANGLE):
{
add_rectangle_to_polyline(0.0, 0.0, 2.0*LAMBDA, 2.0, polyline, circles);
break;
}
case (P_TOKARSKY):
{
nsides = 26;
ncircles = 26;
polyline[0].x1 = 0.0; polyline[0].y1 = 2.0; polyline[0].angle = 0.0;
polyline[1].x1 = 1.0; polyline[1].y1 = 2.0; polyline[1].angle = -PID;
polyline[2].x1 = 1.0; polyline[2].y1 = 1.0; polyline[2].angle = 0.0;
polyline[3].x1 = 2.0; polyline[3].y1 = 1.0; polyline[3].angle = -PID;
polyline[4].x1 = 2.0; polyline[4].y1 = 0.0; polyline[4].angle = 0.5*PID;
polyline[5].x1 = 3.0; polyline[5].y1 = 1.0; polyline[5].angle = 0.0;
polyline[6].x1 = 4.0; polyline[6].y1 = 1.0; polyline[6].angle = -PID;
polyline[7].x1 = 4.0; polyline[7].y1 = 0.0; polyline[7].angle = 0.5*PID;
polyline[8].x1 = 5.0; polyline[8].y1 = 1.0; polyline[8].angle = 0.0;
polyline[9].x1 = 6.0; polyline[9].y1 = 1.0; polyline[9].angle = -PID;
polyline[10].x1 = 6.0; polyline[10].y1 = 0.0; polyline[10].angle = 0.5*PID;
polyline[11].x1 = 7.0; polyline[11].y1 = 1.0; polyline[11].angle = PID;
polyline[12].x1 = 7.0; polyline[12].y1 = 2.0; polyline[12].angle = 0.0;
polyline[13].x1 = 8.0; polyline[13].y1 = 2.0; polyline[13].angle = PID;
polyline[14].x1 = 8.0; polyline[14].y1 = 3.0; polyline[14].angle = PI;
polyline[15].x1 = 7.0; polyline[15].y1 = 3.0; polyline[15].angle = 1.5*PID;
polyline[16].x1 = 6.0; polyline[16].y1 = 4.0; polyline[16].angle = -PID;
polyline[17].x1 = 6.0; polyline[17].y1 = 3.0; polyline[17].angle = PI;
polyline[18].x1 = 5.0; polyline[18].y1 = 3.0; polyline[18].angle = -PID;
polyline[19].x1 = 5.0; polyline[19].y1 = 2.0; polyline[19].angle = PI;
polyline[20].x1 = 3.0; polyline[20].y1 = 2.0; polyline[20].angle = PID;
polyline[21].x1 = 3.0; polyline[21].y1 = 3.0; polyline[21].angle = PI;
polyline[22].x1 = 2.0; polyline[22].y1 = 3.0; polyline[22].angle = PID;
polyline[23].x1 = 2.0; polyline[23].y1 = 4.0; polyline[23].angle = PI;
polyline[24].x1 = 1.0; polyline[24].y1 = 4.0; polyline[24].angle = -PID;
polyline[25].x1 = 1.0; polyline[25].y1 = 3.0; polyline[25].angle = 2.5*PID;
ratio = (XMAX - XMIN)/8.4;
for (i=0; i<nsides; i++)
{
polyline[i].x1 = ratio*(polyline[i].x1 - 4.0);
polyline[i].y1 = ratio*(polyline[i].y1 - 2.0);
}
for (i=0; i<nsides; i++) if (i < nsides-1)
{
polyline[i].x2 = polyline[i+1].x1;
polyline[i].y2 = polyline[i+1].y1;
}
polyline[nsides-1].x2 = polyline[0].x1;
polyline[nsides-1].y2 = polyline[0].y1;
for (i=0; i<nsides; i++)
polyline[i].length = module2(polyline[i].x2 - polyline[i].x1, polyline[i].y2 - polyline[i].y1);
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
break;
}
case (P_POLYRING):
{
nsides = 2*NPOLY;
ncircles = 0;
omega = DPI/(double)NPOLY;
sw = sin(omega/2.0);
for (i=0; i<NPOLY; i++)
{
angle = APOLY + (double)i*omega;
polyline[i].x1 = LAMBDA*cos(angle);
polyline[i].y1 = LAMBDA*sin(angle);
polyline[i].angle = angle + PID + 0.5*omega;
polyline[i].length = 2.0*LAMBDA*sw;
}
for (i=0; i<NPOLY; i++)
{
polyline[i].x2 = polyline[(i+1)%NPOLY].x1;
polyline[i].y2 = polyline[(i+1)%NPOLY].y1;
}
for (i=0; i<NPOLY; i++)
{
angle = APOLY + ((double)i+0.5)*omega;
polyline[i+NPOLY].x1 = MU*cos(angle);
polyline[i+NPOLY].y1 = MU*sin(angle);
polyline[i+NPOLY].angle = angle + PID + 0.5*omega;
polyline[i+NPOLY].length = 2.0*MU*sw;
}
for (i=0; i<NPOLY; i++)
{
polyline[i+NPOLY].x2 = polyline[(i+1)%NPOLY+NPOLY].x1;
polyline[i+NPOLY].y2 = polyline[(i+1)%NPOLY+NPOLY].y1;
}
for (i=0; i<nsides; i++) polyline[i].color = 0;
break;
}
case (P_SIERPINSKI):
{
nsides = 0;
ncircles = 0;
add_rectangle_to_polyline(0.0, 0.0, 2.0*LAMBDA, 2.0, polyline, circles);
length = 2.0/3.0;
dist = 2.0;
n = 1;
for (k=0; k<SDEPTH; k++)
{
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
/* compute ternary expansion of i */
ii = i;
for (l=0; l<k; l++)
{
terni[l] = ii%3;
ii = ii - (ii%3);
ii = ii/3;
}
/* compute ternary expansion of j */
jj = j;
for (l=0; l<k; l++)
{
ternj[l] = jj%3;
jj = jj - (jj%3);
jj = jj/3;
}
/* check whether ternary expansions do not have 1 at same position */
cond = 1;
for (l=0; l<k; l++)
if ((terni[l] == 1)&&(ternj[l] == 1)) cond = 0;
if (cond)
{
x = -1.0 + dist*((double)i + 0.5);
y = -1.0 + dist*((double)j + 0.5);
add_rectangle_to_polyline(x, y, length, length, polyline, circles);
}
}
length = length/3.0;
dist = dist/3.0;
n = n*3;
}
printf("nsides = %i\n", nsides);
break;
}
case (P_VONKOCH):
{
nsides = 3;
for (k=0; k<SDEPTH; k++) nsides *= 4;
printf("nsides = %i\n", nsides);
ncircles = nsides;
if (nsides > NMAXPOLY)
{
printf("NMAXPOLY has to be increased to at least %i\n", nsides);
nsides = NMAXPOLY;
}
for (i=0; i<nsides/3; i++)
{
/* compute quaternary expansion of i */
ii = i;
for (l=0; l<SDEPTH; l++)
{
quater[l] = ii%4;
ii = ii - (ii%4);
ii = ii/4;
}
/* find first nonzero digit */
z = 0;
while ((quater[z] == 0)&&(z<SDEPTH)) z++;
/* compute left/right turns */
if (i==0) vkoch[0] = 0;
else if (z != SDEPTH)
{
if (quater[z] == 2) vkoch[i] = 0;
else vkoch[i] = 1;
}
// printf("%i", vkoch[i]);
}
printf("\n");
/* compute vertices */
angle = 2.0*PI/3.0;
x = cos(PI/6.0);
y = -sin(PI/6.0);
length = 2.0*sin(PI/3.0);
for (k=0; k<SDEPTH; k++) length = length/3.0;
printf("Length = %.2f\n", length);
for (i=0; i<nsides; i++)
{
polyline[i].x1 = x;
polyline[i].y1 = y;
polyline[i].angle = angle;
x += length*cos(angle);
y += length*sin(angle);
polyline[i].length = length;
turnright = vkoch[i%(nsides/3)+1];
if (turnright) angle -= PI/3.0;
else angle += 2.0*PI/3.0;
while (angle > DPI) angle -= DPI;
while (angle < 0.0) angle += DPI;
}
for (i=0; i<nsides; i++)
{
polyline[i].color = 0;
if (i < nsides-1) polyline[i].x2 = polyline[i+1].x1;
else polyline[i].x2 = polyline[0].x1;
if (i < nsides-1) polyline[i].y2 = polyline[i+1].y1;
else polyline[i].y2 = polyline[0].y1;
}
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
break;
}
case (P_POLYGON):
{
nsides = NPOLY;
ncircles = 0;
omega = DPI/(double)NPOLY;
sw = sin(omega/2.0);
for (i=0; i<NPOLY; i++)
{
angle = APOLY + (double)i*omega;
polyline[i].x1 = LAMBDA*cos(angle);
polyline[i].y1 = LAMBDA*sin(angle);
polyline[i].angle = angle + PID + 0.5*omega;
polyline[i].length = 2.0*LAMBDA*sw;
}
for (i=0; i<NPOLY; i++)
{
polyline[i].x2 = polyline[(i+1)%NPOLY].x1;
polyline[i].y2 = polyline[(i+1)%NPOLY].y1;
}
for (i=0; i<nsides; i++) polyline[i].color = 0;
break;
}
case (P_TOKA_PRIME):
{
nsides = 84;
ncircles = 84;
polyline[0].x1 = 0.0;
polyline[0].y1 = 1.0;
polyline[42].x1 = 0.0;
polyline[42].y1 = 1.0 - LAMBDA;
ta = tan(0.05*PI);
tb = tan(0.4*PI);
a = LAMBDA*tb/(ta + tb);
b = a*ta;
polyline[41].x1 = b;
polyline[41].y1 = 1.0 - a;
axial_symmetry_tsegment(polyline[0], polyline[41], polyline[42], &polyline[40]);
axial_symmetry_tsegment(polyline[0], polyline[40], polyline[41], &polyline[1]);
axial_symmetry_tsegment(polyline[40], polyline[1], polyline[0], &polyline[84]);
axial_symmetry_tsegment(polyline[1], polyline[84], polyline[40], &polyline[2]);
for (i=2; i<39; i++)
axial_symmetry_tsegment(polyline[i], polyline[84], polyline[i-1], &polyline[i+1]);
for (i=1; i<42; i++)
{
polyline[84-i].x1 = -polyline[i].x1;
polyline[84-i].y1 = polyline[i].y1;
}
printf("xc = %.5f, yc = %.5f\n", polyline[84].x1, polyline[84].y1);
for (i=0; i<nsides; i++)
{
// polyline[i].x1 += -MU;
x = polyline[(i+1)%nsides].x1;
y = polyline[(i+1)%nsides].y1;
polyline[i].x2 = x;
polyline[i].y2 = y;
polyline[i].length = module2(x - polyline[i].x1, y - polyline[i].y1);
polyline[i].angle = argument(x - polyline[i].x1, y - polyline[i].y1);
}
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
break;
}
case (P_TREE):
{
nsides = 11;
ncircles = 11;
polyline[0].x1 = 0.85;
polyline[0].y1 = -1.0;
polyline[1].x1 = 0.4;
polyline[1].y1 = -0.4;
polyline[2].x1 = 0.65;
polyline[2].y1 = -0.4;
polyline[3].x1 = 0.25;
polyline[3].y1 = 0.2;
polyline[4].x1 = 0.5;
polyline[4].y1 = 0.2;
polyline[5].x1 = 0.0;
polyline[5].y1 = 1.0;
for (i=6; i<11; i++)
{
polyline[i].x1 = -polyline[10-i].x1;
polyline[i].y1 = polyline[10-i].y1;
}
for (i=0; i<nsides; i++)
{
x = polyline[(i+1)%nsides].x1;
y = polyline[(i+1)%nsides].y1;
polyline[i].x2 = x;
polyline[i].y2 = y;
polyline[i].length = module2(x - polyline[i].x1, y - polyline[i].y1);
polyline[i].angle = argument(x - polyline[i].x1, y - polyline[i].y1);
}
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
break;
}
case (P_TOKA_NONSELF):
{
nsides = 12;
ncircles = 12;
polyline[0].x1 = 0.0; polyline[0].y1 = 2.0; polyline[0].angle = 3.0*PID;
polyline[1].x1 = 0.0; polyline[1].y1 = 1.0; polyline[1].angle = 0.0;
polyline[2].x1 = 1.0; polyline[2].y1 = 1.0; polyline[2].angle = 3.5*PID;
polyline[3].x1 = 2.0; polyline[3].y1 = 0.0; polyline[3].angle = PI;
polyline[4].x1 = 1.0; polyline[4].y1 = 0.0; polyline[4].angle = 3.0*PID;
polyline[5].x1 = 1.0; polyline[5].y1 = -1.0; polyline[5].angle = 2.5*PID;
polyline[6].x1 = 0.0; polyline[6].y1 = -2.0; polyline[6].angle = PID;
polyline[7].x1 = 0.0; polyline[7].y1 = -1.0; polyline[7].angle = PI;
polyline[8].x1 = -1.0; polyline[8].y1 = -1.0; polyline[8].angle = 1.5*PID;
polyline[9].x1 = -2.0; polyline[9].y1 = 0.0; polyline[9].angle = 0.0;
polyline[10].x1 = -1.0; polyline[10].y1 = 0.0; polyline[10].angle = PID;
polyline[11].x1 = -1.0; polyline[11].y1 = 1.0; polyline[11].angle = 0.5*PID;
ratio = (YMAX - YMIN)/4.5;
for (i=0; i<nsides; i++)
{
polyline[i].x1 = ratio*(polyline[i].x1);
polyline[i].y1 = ratio*(polyline[i].y1);
}
for (i=0; i<nsides; i++) if (i < nsides-1)
{
polyline[i].x2 = polyline[i+1].x1;
polyline[i].y2 = polyline[i+1].y1;
}
polyline[nsides-1].x2 = polyline[0].x1;
polyline[nsides-1].y2 = polyline[0].y1;
for (i=0; i<nsides; i++)
polyline[i].length = module2(polyline[i].x2 - polyline[i].x1, polyline[i].y2 - polyline[i].y1);
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = MU;
circles[i].active = 1;
}
break;
}
case (P_MAZE):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_maze_exit(0, NYMAZE/2, maze);
/* build walls of maze */
dx = (YMAX - YMIN - 2.0*padding)/(double)(NXMAZE);
dy = (YMAX - YMIN - 2.0*padding)/(double)(NYMAZE);
nsides = 0;
ncircles = 0;
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
y1 = YMIN + padding + (double)j*dy;
if (((i>0)||(j!=NYMAZE/2)||(CLOSE_MAZE))&&(maze[n].west))
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1 + dy;
polyline[nsides].angle = PID;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1 + dx;
polyline[nsides].y2 = y1;
polyline[nsides].angle = 0.0;
nsides++;
}
}
/* top side of maze */
polyline[nsides].x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].y2 = YMAX - padding;
polyline[nsides].angle = 0.0;
nsides++;
/* right side of maze */
y1 = YMIN + padding + dy*((double)NYMAZE/2);
x1 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
if (CLOSE_MAZE) polyline[nsides].y2 = y1;
else polyline[nsides].y2 = y1 - dy;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
/* left side of maze */
x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMIN + padding;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
/* add circular arcs in corners */
if (B_DOMAIN == D_POLYLINE_ARCS)
{
narcs = 0;
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
y1 = YMIN + padding + (double)j*dy;
ra = MAZE_CORNER_RADIUS;
rb = 1.0 - MAZE_CORNER_RADIUS;
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].south)&&(maze[n].west))
{
arcs[narcs].xc = x1 + ra*dx;
arcs[narcs].yc = y1 + ra*dy;
arcs[narcs].radius = ra*dx;
arcs[narcs].angle1 = PI;
arcs[narcs].dangle = PID;
narcs++;
}
if (((i<NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].south)&&(maze[n].east))
{
arcs[narcs].xc = x1 + rb*dx;
arcs[narcs].yc = y1 + ra*dy;
arcs[narcs].radius = ra*dx;
arcs[narcs].angle1 = 3.0*PID;
arcs[narcs].dangle = PID;
narcs++;
}
if (((i<NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].north)&&(maze[n].east))
{
arcs[narcs].xc = x1 + rb*dx;
arcs[narcs].yc = y1 + rb*dy;
arcs[narcs].radius = ra*dx;
arcs[narcs].angle1 = 0.0;
arcs[narcs].dangle = PID;
narcs++;
}
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].north)&&(maze[n].west))
{
arcs[narcs].xc = x1 + ra*dx;
arcs[narcs].yc = y1 + rb*dy;
arcs[narcs].radius = ra*dx;
arcs[narcs].angle1 = PID;
arcs[narcs].dangle = PID;
narcs++;
}
}
}
free(maze);
break;
}
case (P_MAZE_DIAG):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_maze_exit(0, NYMAZE/2, maze);
/* build walls of maze */
dx = (YMAX - YMIN - 2.0*padding)/(double)(NXMAZE);
dy = (YMAX - YMIN - 2.0*padding)/(double)(NYMAZE);
nsides = 0;
ncircles = 0;
/* deactivate sides for openings */
maze[nmaze(0,NYMAZE/2)].west = 0;
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
y1 = YMIN + padding + (double)j*dy;
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].west))
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1 + dy;
polyline[nsides].angle = PID;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1 + dx;
polyline[nsides].y2 = y1;
polyline[nsides].angle = 0.0;
nsides++;
}
}
/* 45 degrees parts */
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
y1 = YMIN + padding + (double)j*dy;
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].south)&&(maze[n].west))
{
polyline[nsides].x1 = x1 + 0.25*dx;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1 + 0.25*dy;
polyline[nsides].angle = 1.5*PID;
nsides++;
}
// if ((maze[n].south)&&(maze[n].east))
if (((i<NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].south)&&(maze[n].east)) {
polyline[nsides].x1 = x1 + 0.75*dx;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1 + dx;
polyline[nsides].y2 = y1 + 0.25*dy;
polyline[nsides].angle = 0.5*PID;
nsides++;
}
// if ((maze[n].north)&&(maze[n].east))
if (((i<NXMAZE-1)||(j!=NYMAZE/2-1))&&(maze[n].north)&&(maze[n].east))
{
polyline[nsides].x1 = x1 + dx;
polyline[nsides].y1 = y1 + 0.75*dy;
polyline[nsides].x2 = x1 + 0.75*dx;
polyline[nsides].y2 = y1 + dy;
polyline[nsides].angle = 1.5*PID;
nsides++;
}
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].north)&&(maze[n].west))
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1 + 0.75*dy;
polyline[nsides].x2 = x1 + 0.25*dx;
polyline[nsides].y2 = y1 + dy;
polyline[nsides].angle = 0.5*PID;
nsides++;
}
}
/* top side of maze */
polyline[nsides].x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].y2 = YMAX - padding;
polyline[nsides].angle = 0.0;
nsides++;
/* right side of maze */
y1 = YMIN + padding + dy*((double)NYMAZE/2);
x1 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1 - dy;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
/* left side of maze */
x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMIN + padding;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
free(maze);
break;
}
case (P_MAZE_RANDOM):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
maze_coords = (double *)malloc(2*NXMAZE*NYMAZE*sizeof(double));
init_maze_exit(0, NYMAZE/2, maze);
/* build walls of maze */
dx = (YMAX - YMIN - 2.0*padding)/(double)(NXMAZE);
dy = (YMAX - YMIN - 2.0*padding)/(double)(NYMAZE);
/* compute maze coordinates with random shift */
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
maze_coords[2*n] = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
maze_coords[2*n+1] = YMIN + padding + (double)j*dy;
}
for (i=1; i<NXMAZE-1; i++)
for (j=1; j<NYMAZE-1; j++)
{
n = nmaze(i, j);
maze_coords[2*n] += MAZE_RANDOM_FACTOR*dx*rand()/RAND_MAX;
maze_coords[2*n+1] += MAZE_RANDOM_FACTOR*dy*rand()/RAND_MAX;
}
// for (j=0; j<NYMAZE; j++) for (i=0; i<NXMAZE; i++)
// {
// n = nmaze(i, j);
// printf("i=%i, j=%i, coord[%i]=%.2lg, coord[%i]=%.2lg\n", i, j, 2*n, maze_coords[2*n], 2*n+1, maze_coords[2*n+1]);
// }
// sleep(3);
nsides = 0;
ncircles = 0;
for (i=0; i<NXMAZE; i++)
for (j=0; j<NYMAZE; j++)
{
n = nmaze(i, j);
x1 = maze_coords[2*n];
y1 = maze_coords[2*n+1];
xright = x1 + dx;
yright = y1;
xtop = x1;
ytop = y1 + dy;
// printf("i=%i, j=%i, x1=%.3lg, y1=%.3lg, x1+=%.3lg, y1+=%.3lg\n", i, j, x1, y1, xright, yright);
if (i<NXMAZE-1)
{
xright = maze_coords[2*nmaze(i+1, j)];
yright = maze_coords[2*nmaze(i+1, j)+1];
}
if (j<NYMAZE-1)
{
xtop = maze_coords[2*nmaze(i, j+1)];
ytop = maze_coords[2*nmaze(i, j+1)+1];
}
// printf("i=%i, j=%i, x1=%.3lg, y1=%.3lg, x1+=%.3lg, y1+=%.3lg\n\n", i, j, x1, y1, xright, yright);
if (((i>0)||(j!=NYMAZE/2))&&(maze[n].west))
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = xtop;
polyline[nsides].y2 = ytop;
polyline[nsides].angle = PID;
nsides++;
}
if (maze[n].south)
{
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = xright;
polyline[nsides].y2 = yright;
polyline[nsides].angle = 0.0;
nsides++;
}
}
// sleep(3);
/* top side of maze */
polyline[nsides].x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].y2 = YMAX - padding;
polyline[nsides].angle = 0.0;
nsides++;
/* right side of maze */
y1 = YMIN + padding + dy*((double)NYMAZE/2);
x1 = YMAX - padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = y1 - dy;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = y1;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
/* left side of maze */
x1 = YMIN + padding + MAZE_XSHIFT;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMIN - 1000.0;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMIN + padding;
polyline[nsides].angle = PID;
nsides++;
polyline[nsides].x1 = x1;
polyline[nsides].y1 = YMAX - padding;
polyline[nsides].x2 = x1;
polyline[nsides].y2 = YMAX + 1000.0;
polyline[nsides].angle = PID;
nsides++;
// ncircles = nsides;
// for (i=0; i<ncircles; i++)
// {
// circles[i].xc = polyline[i].x1;
// circles[i].yc = polyline[i].y1;
// circles[i].radius = MU;
// circles[i].active = 1;
// }
free(maze);
free(maze_coords);
break;
}
case (P_MAZE_CIRCULAR):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_circular_maze(maze);
init_polyline_circular_maze(polyline, circles, arcs, maze);
free(maze);
break;
}
case (P_MAZE_CIRC_SCATTERER):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_circular_maze(maze);
init_polyline_circular_maze(polyline, circles, arcs, maze);
/* add scatterers */
nblocks = NYMAZE/NXMAZE;
rmin = 0.15;
rmax = 1.0;
angle = DPI/(double)nblocks;
dphi = angle;
dr = (rmax - rmin)/(double)(NXMAZE);
rscat = 0.15*dr;
for (block = 0; block < nblocks; block++)
{
dphi = angle;
/* first circle */
r = rmin;
phi = (double)block*angle;
arcs[narcs].xc = rmin*cos(phi) + MAZE_XSHIFT;
arcs[narcs].yc = rmin*sin(phi);
arcs[narcs].radius = rscat;
arcs[narcs].angle1 = 0.0;
arcs[narcs].dangle = DPI;
narcs++;
/* second circle */
dphi *= 0.5;
for (q=0; q<2; q++)
{
r = rmin + dr;
phi = (double)block*angle + (double)q*dphi;
arcs[narcs].xc = r*cos(phi) + MAZE_XSHIFT;
arcs[narcs].yc = r*sin(phi);
arcs[narcs].radius = rscat;
arcs[narcs].angle1 = 0.0;
arcs[narcs].dangle = DPI;
narcs++;
}
/* other circles */
ww = 2;
i = 2;
while (ww < NXMAZE)
{
dphi *= 0.5;
for (p = 0; p < ww; p++)
{
r = rmin + (double)i*dr;
for (q = 0; q < 2*ww; q++)
{
phi = (double)block*angle + (double)q*dphi;
arcs[narcs].xc = r*cos(phi) + MAZE_XSHIFT;
arcs[narcs].yc = r*sin(phi);
arcs[narcs].radius = rscat;
arcs[narcs].angle1 = 0.0;
arcs[narcs].dangle = DPI;
narcs++;
}
i++;
}
ww *= 2;
}
}
free(maze);
break;
}
case (P_MAZE_HEX):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_hex_maze(maze);
nsides = 0;
ncircles = 0;
init_polyline_hex_maze(polyline, circles, maze);
free(maze);
break;
}
case (P_MAZE_OCT):
{
maze = (t_maze *)malloc(NXMAZE*NYMAZE*sizeof(t_maze));
init_oct_maze(maze);
nsides = 0;
ncircles = 0;
init_polyline_oct_maze(polyline, circles, maze);
free(maze);
break;
}
}
}
void init_polyline_depth(t_segment polyline[NMAXPOLY], t_circle circles[NMAXCIRCLES], int sdepth, double mu)
/* initialise polyline with variable depth parameter (for von Koch snowflake) */
{
int i, j, k, l, n, z, ii, jj, terni[SDEPTH], ternj[SDEPTH], quater[SDEPTH], cond;
short int vkoch[NMAXCIRCLES], turnright;
double ratio, omega, angle, sw, length, dist, x, y, ta, tb, a, b;
switch (POLYLINE_PATTERN) {
case (P_VONKOCH):
{
nsides = 3;
for (k=0; k<sdepth; k++) nsides *= 4;
printf("nsides = %i\n", nsides);
ncircles = nsides;
if (nsides > NMAXPOLY)
{
printf("NMAXPOLY has to be increased to at least %i\n", nsides);
nsides = NMAXPOLY;
}
for (i=0; i<nsides/3; i++)
{
/* compute quaternary expansion of i */
ii = i;
for (l=0; l<sdepth; l++)
{
quater[l] = ii%4;
ii = ii - (ii%4);
ii = ii/4;
}
/* find first nonzero digit */
z = 0;
while ((quater[z] == 0)&&(z<sdepth)) z++;
/* compute left/right turns */
if (i==0) vkoch[0] = 0;
else if (z != sdepth)
{
if (quater[z] == 2) vkoch[i] = 0;
else vkoch[i] = 1;
}
// printf("%i", vkoch[i]);
}
printf("\n");
/* compute vertices */
angle = 2.0*PI/3.0;
x = cos(PI/6.0);
y = -sin(PI/6.0);
length = 2.0*sin(PI/3.0);
for (k=0; k<sdepth; k++) length = length/3.0;
printf("Length = %.2f\n", length);
for (i=0; i<nsides; i++)
{
polyline[i].x1 = x;
polyline[i].y1 = y;
polyline[i].angle = angle;
x += length*cos(angle);
y += length*sin(angle);
polyline[i].length = length;
turnright = vkoch[i%(nsides/3)+1];
if (turnright) angle -= PI/3.0;
else angle += 2.0*PI/3.0;
while (angle > DPI) angle -= DPI;
while (angle < 0.0) angle += DPI;
}
for (i=0; i<nsides; i++)
{
polyline[i].color = 0;
if (i < nsides-1) polyline[i].x2 = polyline[i+1].x1;
else polyline[i].x2 = polyline[0].x1;
if (i < nsides-1) polyline[i].y2 = polyline[i+1].y1;
else polyline[i].y2 = polyline[0].y1;
}
for (i=0; i<ncircles; i++)
{
circles[i].xc = polyline[i].x1;
circles[i].yc = polyline[i].y1;
circles[i].radius = mu;
circles[i].active = 1;
}
break;
}
}
}
int test_initial_condition(double *configs[NPARTMAX], int active[NPARTMAX], int color[NPARTMAX])
/* apply a test to initial conditions - so far, whether particle has left maze on the right */
{
int i, j, time, nactive = 0, counter = 0, tmax[NPARTMAX], tmaxmax = 0, tmaxmin = 1000;
double conf[8], newconf[8], cosphi, x2, pcolor;
for (i=0; i<nparticles; i++)
{
for (j=0; j<8; j++) conf[j] = configs[i][j];
for (j=0; j<8; j++) newconf[j] = configs[i][j];
time = 0;
// while ((time < 100000)&&(newconf[4] < 1000.0))
while ((time < 100000)&&(newconf[0] < DUMMY_ABSORBING))
{
for (j=0; j<8; j++) conf[j] = newconf[j];
vbilliard(newconf);
time++;
}
tmax[i] = time;
printf("tmax = %i\n", time);
cosphi = (conf[6] - conf[4])/conf[3];
x2 = conf[4] + conf[2]*cosphi;
// x2 = conf[4] + 10.0*cosphi;
if ((conf[0] >= DUMMY_ABSORBING)&&(x2 > XMAX))
// if (conf[0] >= DUMMY_ABSORBING)
{
active[i] = 1;
if (time > tmaxmax) tmaxmax = time;
else if (time < tmaxmin) tmaxmin = time;
}
else active[i] = 0;
nactive += active[i];
}
printf("%i particles, %i active particles\n", nparticles, nactive);
printf("tmin = %i, tmax = %i\n", tmaxmin, tmaxmax);
// sleep(5);
/* reorder particles */
for (i=0; i<nparticles; i++)
{
if (active[i])
{
for (j=0; j<8; j++) configs[counter][j] = configs[i][j];
pcolor = sqrt((double)tmax[i] - (double)tmaxmin - 1.0)/sqrt((double)tmaxmax - (double)tmaxmin);
color[counter] = (int)((double)NCOLORS*pcolor);
active[counter] = 1;
counter++;
}
}
for (i=0; i<counter; i++) active[i] = 1;
for (i=counter; i<nparticles; i++) active[i] = 0;
return(counter);
}
int maze_type(int polyline_pattern)
/* group polyline pattern by type of maze */
{
switch (POLYLINE_PATTERN) {
case (P_MAZE): return(0);
case (P_MAZE_DIAG): return(0);
case (P_MAZE_CIRCULAR): return(1);
case (P_MAZE_CIRC_SCATTERER): return(1);
case (P_MAZE_HEX): return(2);
case (P_MAZE_OCT): return(3);
default: return(0);
}
}
int find_maze_cell(double x, double y)
/* return maze cell number for coordinates (x, y) */
{
int i, j, n, block, q, w, k, l;
double padding = 0.02, x1, y1, u, v, r, phi, phi1, angle1, dphi, r1, tolerance = 0.025, x2, y2;
static double dx, dy, rmin, rmax, angle, rr, rrtol, h, dr, dphi_table[5], x0, y0, a, b, d, a2, a2tol;
static int first = 1, nblocks;
if (first)
{
switch (maze_type(POLYLINE_PATTERN)) {
case (0): /* maze with square or rectangular cells */
{
dx = (YMAX - YMIN - 2.0*padding)/(double)(NXMAZE);
dy = (YMAX - YMIN - 2.0*padding)/(double)(NYMAZE);
break;
}
case (1): /* circular maze */
{
nblocks = NYMAZE/NXMAZE;
rmin = 0.15;
rmax = 1.0;
angle = DPI/(double)nblocks;
dphi_table[0] = angle;
for (i=1; i<5; i++) dphi_table[i] = 0.5*dphi_table[i-1];
dr = (rmax - rmin)/(double)(NXMAZE);
break;
}
case (2): /* honeycomb maze */
{
rr = 2.0*(YMAX - YMIN)/(3.0*((double)(NXMAZE)-0.5));
r1 = (YMAX - YMIN)/(sqrt(3.0)*(double)(NYMAZE+1));
if (r1 < rr) rr = r1;
h = 0.5*sqrt(3.0)*rr;
rrtol = rr*(1.0 - tolerance);
x0 = YMIN + padding + MAZE_XSHIFT;
y0 = YMIN + padding + h;
break;
}
case (3): /* octahedron-square maze */
{
dx = (YMAX - YMIN - 2.0*padding)/((double)NYMAZE+0.5);
a = dx*(2.0 - sqrt(2.0));
a2 = 0.5*a;
b = a/sqrt(2.0);
d = 2.0*dx;
x0 = YMIN + padding + MAZE_XSHIFT - 0.5*b;
y0 = YMIN + padding + 0.25*dx - 0.5*b;
rr = sqrt((b+a2)*(b+a2) + a2*a2);
rrtol = rr*(1.0 - tolerance);
a2tol = a2*(1.0 - tolerance);
break;
}
}
first = 0;
}
switch (maze_type(POLYLINE_PATTERN)) {
case (0): /* maze with square or rectangular cells */
{
if (x < YMIN + MAZE_XSHIFT) return (-1);
i = (int)((x - YMIN - padding - MAZE_XSHIFT)/dx);
j = (int)((y - YMIN - padding)/dy);
if (i < 0) return(-1);
if (i > NXMAZE-1) return(-1);
if (j < 0) return(-1);
if (j > NYMAZE-1) return(-1);
x1 = x - YMIN - padding - MAZE_XSHIFT - (double)i*dx;
y1 = y - YMIN - padding - (double)j*dy;
/* avoid finding wrong cell for particles close to wall */
if (x1 < tolerance*dx) return(-10);
if (x1 > dx - tolerance*dx) return(-10);
if (y1 < tolerance*dy) return(-10);
if (y1 > dy - tolerance*dy) return(-10);
n = nmaze(i, j);
if (n < NXMAZE*NYMAZE) return(n);
else return(-1);
}
case (1): /* circular maze */
{
r = module2(x - MAZE_XSHIFT,y);
phi = argument(x - MAZE_XSHIFT,y);
if (phi < 0.0) phi += DPI;
if (phi >= DPI) phi -= DPI;
if (r < rmin*(1.0 - tolerance)) return(NXMAZE*NYMAZE);
if (r < rmin*(1.0 + tolerance)) return(-10);
if (r > rmax) return(-2);
i = (int)((r - rmin)/dr);
if (i > NXMAZE-1) return(-1);
/* avoid finding wrong cell for particles close to wall */
if (r - rmin - (double)i*dr < tolerance*dr) return(-10);
if (r - rmin - (double)(i+1)*dr > -tolerance*dr) return(-10);
block = (int)(phi/angle);
phi1 = phi - (double)block*angle;
/* avoid finding wrong cell for particles close to wall */
if (phi1 < tolerance*angle)
return(-10);
if (phi1 - angle > -tolerance*angle)
return(-10);
if (i == 0) j = block*NXMAZE;
else
{
w = 1 + (int)(log((double)i)/log(2.0));
// dphi = angle/ipow(2.0, w);
dphi = dphi_table[w];
q = (int)(phi1/dphi);
j = block*NXMAZE + q;
/* avoid finding wrong cell for particles close to wall */
if (phi1 - (double)q*dphi < tolerance*dphi)
return(-1);
if (phi1 - (double)(q+1)*dphi > - tolerance*dphi)
return(-1);
}
n = nmaze(i, j);
if (n < NXMAZE*NYMAZE) return(n);
else return(-1);
}
case (2): /* honeycomb maze */
{
/* transformation to coordinate system along hexagon centers */
u = (x-x0)/(1.5*rr);
v = 0.5*(u + (y-y0)/h);
i = (int)u;
j = (int)v;
j -= i/2;
if (i < 0) return(-1);
if (i > NXMAZE-1) return(-1);
if (j < 0) return(-1);
if (j > NYMAZE-1) return(-1);
for (k=-1; k<2; k++) if ((i+k >= 0)&&(i+k < NXMAZE))
for (l=-1; l<2; l++) if ((j+l >= 0)&&(j+l < NYMAZE))
{
x1 = x0 + 1.5*(double)(i+k)*rr;
y1 = y0 + 2.0*(double)(j+l)*h;
if ((i+k)%2 == 0) y1 += h;
if (in_polygon(x - x1, y - y1, rrtol, 6, 0.0))
{
n = nmaze(i+k, j+l);
if (i+k < 0) return(-1);
if (i+k > NXMAZE-1) return(-1);
if (j+l < 0) return(-1);
if (j+l > NYMAZE-1) return(-1);
if (n < NXMAZE*NYMAZE) return(n);
else return(-1);
}
}
return(-10);
}
case (3): /* octahedron-square maze */
{
i = 2*(int)((x-x0)/d);
j = 2*(int)((y-y0)/d);
x1 = x - x0 - (double)(i)*dx;
y1 = y - y0 - (double)(j)*dx;
// printf("(x,y) = (%.3lg,%.3lg), (i,j) = (%i,%i), (x1,y1) = (%.3lg,%.3lg)\n", x, y, i, j, x1/d, y1/d);
if (i < 0) return(-1);
if (i > NXMAZE-1) return(-1);
if (j < 0) return(-1);
if (j > NYMAZE-1) return(-1);
if (x1 < b)
{
if (x1 + y1 < b) i--;
else if (y1 - x1 > dx) i--;
}
else if ((x1 > dx)&&(x1 < a + 2.0*b))
{
if (y1 - x1 < - dx) i++;
else if (x1 + y1 > 3.0*a + 2.0*b) i++;
}
else if (x1 >= a + 2.0*b) i++;
if (y1 < b)
{
if (x1 + y1 < b) j--;
else if (x1 - y1 > a + b) j--;
}
else if ((y1 > a + b)&&(y1 < a + 2.0*b))
{
if (x1 - y1 < - dx) j++;
else if (x1 + y1 > 3.0*a + 2.0*b) j++;
}
else if (y1 >= a + 2.0*b) j++;
if (i < 0) return(-1);
if (i > NXMAZE-1) return(-1);
if (j < 0) return(-1);
if (j > NYMAZE-1) return(-1);
/* avoid finding wrong cell for particles close to wall */
x2 = x - x0 - (double)i*dx - b - a2;
y2 = y - y0 - (double)j*dx - b - a2;
if ((i+j)%2 == 0)
{
if (!in_polygon(x2, y2, rrtol, 8, 0.25)) return(-10);
}
else
{
if (vabs(x2) > a2tol) return(-10);
if (vabs(y2) > a2tol) return(-10);
}
n = nmaze(i, j);
if (n < NXMAZE*NYMAZE) return(n);
else return(-1);
}
}
}
void draw_maze_cell(int n, int part_number, double minprop)
/* give specified color to maze cell */
{
int i, j, block, q;
double x, y, padding = 0.02, rgb[3], w;
static double dx, dy, rmin, rmax, angle, r, r1, dr, phi1, dphi, h, x0, y0, a, b, a2, square_prop;
static int first = 1, nblocks;
if (first) switch (maze_type(POLYLINE_PATTERN)) {
case (0): /* maze with square or rectangular cells */
{
dx = (YMAX - YMIN - 2.0*padding)/(double)(NXMAZE);
dy = (YMAX - YMIN - 2.0*padding)/(double)(NYMAZE);
break;
}
case (1): /* circular maze */
{
nblocks = NYMAZE/NXMAZE;
rmin = 0.15;
rmax = 1.0;
angle = DPI/(double)nblocks;
dr = (rmax - rmin)/(double)(NXMAZE);
break;
}
case (2): /* honeycomb maze */
{
r = 2.0*(YMAX - YMIN)/(3.0*((double)(NXMAZE)-0.5));
r1 = (YMAX - YMIN)/(sqrt(3.0)*(double)(NYMAZE+1));
if (r1 < r) r = r1;
h = 0.5*sqrt(3.0)*r;
x0 = YMIN + padding + MAZE_XSHIFT;
y0 = YMIN + padding + h;
break;
}
case (3): /* octahedron-square maze */
{
dx = (YMAX - YMIN - 2.0*padding)/((double)NYMAZE+0.5);
a = dx*(2.0 - sqrt(2.0));
b = a/sqrt(2.0);
a2 = 0.5*a;
r = sqrt((b+a2)*(b+a2) + a2*a2);
square_prop = 2.0*(sqrt(2.0) + 1.0);
x0 = YMIN + padding + MAZE_XSHIFT;
y0 = YMIN + padding + 0.25*dx;
break;
}
first = 0;
}
if (part_number != 0) switch (maze_type(POLYLINE_PATTERN)) {
case (0): /* maze with square or rectangular cells */
{
i = n%NXMAZE;
j = n/NXMAZE;
x = YMIN + padding + (double)i*dx + MAZE_XSHIFT;
y = YMIN + padding + (double)j*dy;
rgb_color_scheme_density(part_number, rgb, minprop);
erase_rectangle(x, y, x + dx, y + dy, rgb);
break;
}
case (1): /* circular maze */
{
if (n == NXMAZE*NYMAZE) /* inner circle */
{
rgb_color_scheme_density(part_number, rgb, minprop);
draw_filled_sector(MAZE_XSHIFT, 0.0, 0.0, rmin, 0.0, DPI, NSEG, rgb);
break;
}
i = n%NXMAZE;
j = n/NXMAZE;
block = j/NXMAZE;
r = rmin + (double)i*dr;
r1 = r + dr;
if (i == 0) /* first circle */
{
dphi = angle;
phi1 = (double)block*dphi;
}
else /* other circles */
{
w = 1 + (int)(log((double)i)/log(2.0));
dphi = angle*ipow(0.5, w);
q = j - block*NXMAZE;
phi1 = (double)block*angle + (double)q*dphi;
}
rgb_color_scheme_density(part_number, rgb, minprop);
draw_filled_sector(MAZE_XSHIFT, 0.0, r, r1, phi1, dphi, NSEG, rgb);
break;
}
case (2): /* honeycomb maze */
{
i = n%NXMAZE;
j = n/NXMAZE;
x = x0 + 1.5*(double)i*r;
y = y0 + 2.0*(double)j*h;
if (i%2 == 0) y += h;
rgb_color_scheme_density(part_number, rgb, minprop);
draw_colored_circle(x, y, r, 6, rgb);
break;
}
case (3): /* octahedron-square maze */
{
i = n%NXMAZE;
j = n/NXMAZE;
x = x0 + ((double)i + 0.5)*dx;
y = y0 + ((double)j + 0.5)*dx;
/* adapt particle number in square to have constant density */
if ((i+j)%2 == 1) part_number = (int)(square_prop*(double)part_number);
rgb_color_scheme_density(part_number, rgb, minprop);
if ((i+j)%2 == 0) draw_colored_octahedron(x, y, r,rgb);
else erase_rectangle(x-a2, y-a2, x+a2, y+a2, rgb);
break;
}
}
}
/* can probably be removed */
void print_left_right_part_number_old(double *configs[NPARTMAX], int active[NPARTMAX], double xl, double yl, double xr, double yr, double xmin, double xmax)
{
char message[50];
int i, nleft = 0, nright = 0;
double rgb[3], x1, y1, cosphi, sinphi;
static int maxnleft = 0, maxnright = 0;
/* count active particles, using the fact that absorbed particles have been given dummy coordinates */
for (i=0; i<nparticles; i++) if ((configs[i][0] >= DUMMY_ABSORBING))
{
cosphi = (configs[i][6] - configs[i][4])/configs[i][3];
sinphi = (configs[i][7] - configs[i][5])/configs[i][3];
x1 = configs[i][4] + configs[i][2]*cosphi;
y1 = configs[i][5] + configs[i][2]*cosphi;
if (x1 < xmin) nleft++;
// else if ((x1 > xmax)&&(y1 <= YMAX)&&(y1 >= YMIN))
else if ((x1 > xmax))
{
nright++;
printf("Detected leaving particle %i at (%.2f, %2f)\n", i, x1, y1);
}
}
if (nleft > maxnleft) maxnleft = nleft;
if (nright > maxnright) maxnright = nright;
hsl_to_rgb(0.0, 0.0, 0.0, rgb);
erase_area(xl, yl - 0.03, 0.45, 0.12, rgb);
erase_area(xr, yr - 0.03, 0.35, 0.12, rgb);
glColor3f(1.0, 1.0, 1.0);
if (maxnleft > 1) sprintf(message, "%i particles", maxnleft);
else sprintf(message, "%i particle", maxnleft);
write_text(xl, yl, message);
if (maxnright > 1) sprintf(message, "%i particles", maxnright);
else sprintf(message, "%i particle", maxnright);
write_text(xr, yr, message);
}