#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= 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 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 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= 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= 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= 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= 1) for (k=0; k= 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= 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= 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; k4.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 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 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 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 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 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; i0.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 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= 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= 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 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= 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 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= 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 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= 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 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= 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 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 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= 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 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 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 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= 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) -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 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 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= 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= LAMBDA)||(vabs(y) >= 1.0)) return(0); else { condition = 1; for (k=0; k= LAMBDA)||(vabs(y) >= 1.0)) return(0); else { condition = 1; for (k=0; k 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 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= 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; ix1 = 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 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 NMAXPOLY) { printf("NMAXPOLY has to be increased to at least %i\n", nsides); nsides = NMAXPOLY; } for (i=0; i DPI) angle -= DPI; while (angle < 0.0) angle += DPI; } for (i=0; i0)||(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; i0)||(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 (((i0)||(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; i0)||(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; i0)||(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 (((i0)||(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; i0)||(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 NMAXPOLY) { printf("NMAXPOLY has to be increased to at least %i\n", nsides); nsides = NMAXPOLY; } for (i=0; i DPI) angle -= DPI; while (angle < 0.0) angle += DPI; } for (i=0; i= 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 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= 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); }