#include "colormaps.c" #define DUMMY_ABSORBING -1000.0 /* dummy value of config[0] for absorbing circles */ #define BOUNDARY_SHIFT 100000.0 /* shift of boundary parametrisation for circles in domain */ #define DUMMY_SIDE_ABS -10000 /* dummy value of returned side for absorbing circles */ 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); } /*********************/ /* Graphics routines */ /*********************/ int writetiff(char *filename, char *description, int x, int y, int width, int height, int compression) { TIFF *file; GLubyte *image, *p; int i; file = TIFFOpen(filename, "w"); if (file == NULL) { return 1; } image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3); /* OpenGL's default 4 byte pack alignment would leave extra bytes at the end of each image row so that each full row contained a number of bytes divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist just to pad the row out to 12 bytes (12 is divisible by 4). To make sure the rows are packed as tight as possible (no row padding), set the pack alignment to 1. */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) width); TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) height); TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(file, TIFFTAG_COMPRESSION, compression); TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(file, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1); TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, description); p = image; for (i = height - 1; i >= 0; i--) { // if (TIFFWriteScanline(file, p, height - i - 1, 0) < 0) if (TIFFWriteScanline(file, p, i, 0) < 0) { free(image); TIFFClose(file); return 1; } p += width * sizeof(GLubyte) * 3; } TIFFClose(file); 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_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 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 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_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_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(circlecolor[k], 0.85, rgb1); // newcircle[k]--; // } // else rgb_color_scheme(circlecolor[k], rgb1); // draw_colored_circle(circlex[k], circley[k], circlerad[k], 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*MU*sin(s1); pos[1] = MU*cos(s1); phi = argument(0.5*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*MU*sin(s1); pos[1] = -MU*cos(s1); phi = argument(-0.5*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; b = 4.0*(pos[0] - cc)*ca + pos[1]*sa; d = 4.0*(pos[0] - cc)*(pos[0] - cc) + pos[1]*pos[1] - MU*MU; 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); tempconf[nt][1] = argument(0.5*y, 2.0*(cc-x)) - 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); tempconf[nt][1] = argument(0.5*y, 2.0*(cc-x)) - alpha; nt++; } } /* intersection with left ellipse */ b = 4.0*(pos[0] + cc)*ca + pos[1]*sa; d = 4.0*(pos[0] + cc)*(pos[0] + cc) + pos[1]*pos[1] - MU*MU; 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); tempconf[nt][1] = argument(0.5*y, -2.0*(cc+x)) - 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); tempconf[nt][1] = argument(0.5*y, -2.0*(cc+x)) - 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 = 1000.0; 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 = 1000.0; 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); 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; } 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; } 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; } 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) + 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; 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