YouTube-simulations/sub_part_billiard.c

3464 lines
96 KiB
C

long int global_time = 0; /* counter to keep track of global time of simulation */
int nparticles=NPART;
/*********************/
/* some basic math */
/*********************/
double vabs(x) /* absolute value */
double x;
{
double res;
if (x<0.0) res = -x;
else res = x;
return(res);
}
double module2(x, y) /* Euclidean norm */
double x, y;
{
double m;
m = sqrt(x*x + y*y);
return(m);
}
double argument(x, y)
double x, 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(a, b, c, r)
double a, b, c, 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 hsl_to_rgb(h, s, l, rgb) /* color conversion from HSL to RGB */
/* h = hue, s = saturation, l = luminosity */
double h, s, l, rgb[3];
{
double c = 0.0, m = 0.0, x = 0.0;
c = (1.0 - fabs(2.0 * l - 1.0)) * s;
m = 1.0 * (l - 0.5 * c);
x = c * (1.0 - fabs(fmod(h / 60.0, 2) - 1.0));
if (h >= 0.0 && h < 60.0)
{
rgb[0] = c+m; rgb[1] = x+m; rgb[2] = m;
}
else if (h < 120.0)
{
rgb[0] = x+m; rgb[1] = c+m; rgb[2] = m;
}
else if (h < 180.0)
{
rgb[0] = m; rgb[1] = c+m; rgb[2] = x+m;
}
else if (h < 240.0)
{
rgb[0] = m; rgb[1] = x+m; rgb[2] = c+m;
}
else if (h < 300.0)
{
rgb[0] = x+m; rgb[1] = m; rgb[2] = c+m;
}
else if (h < 360.0)
{
rgb[0] = c+m; rgb[1] = m; rgb[2] = x+m;
}
else
{
rgb[0] = m; rgb[1] = m; rgb[2] = m;
}
}
void rgb_color_scheme(i, rgb) /* color scheme */
int i;
double rgb[3];
{
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 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( 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 compute_flower_parameters(omega, co, so, axis1, axis2, phimax)
/* compute parameters needed for the flower billiard in terms of LAMBDA and NPOLY */
double *omega, *co, *so, *axis1, *axis2, *phimax;
{
double omega2, co2, so2, r, a, gamma, axissquare1;
/* various angles */
*omega = DPI/((double)NPOLY);
omega2 = PI/((double)NPOLY);
co2 = cos(omega2);
so2 = sin(omega2);
*co = cos(*omega);
*so = sin(*omega);
// *co = co2*co2 - so2*so2;
// *so = 2.0*co2*so2;
/* distance of edge of ellipse to the origin */
r = LAMBDA*co2/(*co);
a = (r*co2 - *co)*(r*co2 - *co);
gamma = 0.5*r*r - r*co2*(*co) + 0.5*cos(2.0*(*omega));
axissquare1 = gamma + sqrt(gamma*gamma + a*(*so)*(*so));
/* semi-minor axis */
*axis1 = sqrt(axissquare1);
/* semi-major axis */
*axis2 = sqrt(axissquare1 + (*so)*(*so));
/* max angle in ellipse parametrization */
*phimax = asin(r*so2/(*axis2));
}
void paint_billiard_interior() /* paints billiard interior, for use before draw_conf */
{
double x0, x, y, phi, r = 0.01, alpha, dphi, omega, beta2, x2, s, x1, y1, angle, co, so, axis1, axis2, phimax;
int i, j, k, c;
glLineWidth(4);
glEnable(GL_LINE_SMOOTH);
switch (B_DOMAIN) {
case (D_POLYGON):
{
omega = DPI/((double)NPOLY);
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(x, y);
x = cos((i+1)*omega + APOLY*PID);
y = sin((i+1)*omega + APOLY*PID);
glVertex2d(x, y);
}
glEnd();
}
break;
}
case (D_REULEAUX):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
if (LAMBDA > 0.0) x2 = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
else x2 = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
x1 = x2 - LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(x, y);
}
}
glEnd();
}
break;
}
case (D_FLOWER):
{
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
if (PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*phimax;
x1 = co + axis1*cos(s);
y1 = axis2*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd();
}
break;
}
default:
{
}
}
}
void draw_billiard() /* draws the billiard boundary */
{
double x0, x, y, phi, r = 0.01, alpha, dphi, omega, x1, y1, x2, beta2, angle, s, x2plus, x2minus;
double omega2, co, so, axis1, axis2, phimax;
int i, j, k, c;
if (PAINT_INT) glColor3f(0.5, 0.5, 0.5);
else
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
}
glLineWidth(BILLIARD_WIDTH);
glEnable(GL_LINE_SMOOTH);
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glVertex2d(-LAMBDA, 1.0);
glVertex2d(-LAMBDA, -1.0);
glEnd();
break;
}
case (D_ELLIPSE):
{
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd ();
/* draw foci */
if (FOCI)
{
glColor3f(0.3, 0.3, 0.3);
x0 = sqrt(LAMBDA*LAMBDA-1.0);
glLineWidth(2);
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = x0 + r*cos(phi);
y = r*sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = -x0 + r*cos(phi);
y = r*sin(phi);
glVertex2d(x, y);
}
glEnd();
}
break;
}
case D_STADIUM:
{
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = -PID + (double)i*PI/(double)NSEG;
x = 0.5*LAMBDA + cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = PID + (double)i*PI/(double)NSEG;
x = -0.5*LAMBDA + cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_STRIP);
glVertex2d(-LAMBDA, -1.0);
glVertex2d(-LAMBDA, 1.0);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex2d(LAMBDA, -1.0);
glVertex2d(LAMBDA, 1.0);
glEnd();
}
break;
}
case D_SINAI:
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(0.0, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi);
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
break;
}
case D_DIAMOND:
{
alpha = atan(1.0 - 1.0/LAMBDA);
dphi = (PID - 2.0*alpha)/(double)NSEG;
r = sqrt(LAMBDA*LAMBDA + (LAMBDA-1.0)*(LAMBDA-1.0));
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = alpha + (double)i*dphi;
x = -LAMBDA + r*cos(phi);
y = -LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha - PID + (double)i*dphi;
x = -LAMBDA + r*cos(phi);
y = LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha + PI + (double)i*dphi;
x = LAMBDA + r*cos(phi);
y = LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
for (i=0; i<=NSEG; i++)
{
phi = alpha + PID + (double)i*dphi;
x = LAMBDA + r*cos(phi);
y = -LAMBDA + r*sin(phi);
glVertex2d(x, y);
}
glEnd();
break;
}
case (D_TRIANGLE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(-LAMBDA, -1.0);
glVertex2d(LAMBDA, -1.0);
glVertex2d(-LAMBDA, 1.0);
glEnd();
break;
}
case (D_ANNULUS):
{
/* color inner circle */
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(MU, 0.0);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi) + MU;
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd();
/* color outer domain */
glColor3f(0.2, 0.2, 0.2);
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMAX);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMAX);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + PID;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMIN, YMIN);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + PI;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
glVertex2d(XMAX, YMIN);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*PID/(double)NSEG + 3.0*PID;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd();
glBegin(GL_TRIANGLES);
glVertex2d(XMAX, YMAX);
glVertex2d(1.0, 0.0);
glVertex2d(XMAX, YMIN);
glVertex2d(XMAX, YMIN);
glVertex2d(0.0, -1.0);
glVertex2d(XMIN, YMIN);
glVertex2d(XMIN, YMIN);
glVertex2d(-1.0, 0.0);
glVertex2d(XMIN, YMAX);
glVertex2d(XMIN, YMAX);
glVertex2d(0.0, 1.0);
glVertex2d(XMAX, YMAX);
glEnd();
/* draw circles */
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = LAMBDA*cos(phi) + MU;
y = LAMBDA*sin(phi);
glVertex2d(x, y);
}
glEnd ();
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = cos(phi);
y = sin(phi);
glVertex2d(x, y);
}
glEnd ();
break;
}
case (D_POLYGON):
{
omega = DPI/((double)NPOLY);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
break;
}
case (D_REULEAUX):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
if (LAMBDA > 0.0) x2 = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
else x2 = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
x1 = x2 - LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd ();
break;
}
case (D_FLOWER):
{
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
/* draw inner polygon and radial lines */
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
r = LAMBDA*cos(0.5*omega)/co;
for (i=0; i<=NPOLY; i++)
{
glBegin(GL_LINE_STRIP);
glVertex2d(0.0, 0.0);
x = r*cos(((double)i + 0.5)*omega + APOLY*PID);
y = r*sin(((double)i + 0.5)*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
glEnd ();
}
}
/* draw billiard boundary */
if (!PAINT_INT)
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
}
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
// for (i=0; i<=1; i++)
{
for (j=0; j<NSEG; j++)
{
// s = 2.0*(((double)j/(double)NSEG)-0.5)*PI;
s = 2.0*(((double)j/(double)NSEG)-0.5)*phimax;
x1 = co + axis1*cos(s);
y1 = axis2*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
}
glEnd ();
break;
}
case (D_ALT_REU):
{
omega = DPI/((double)NPOLY);
beta2 = asin(sin(omega*0.5)/LAMBDA);
x2plus = cos(omega*0.5) + sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
x2minus = cos(omega*0.5) - sqrt(LAMBDA*LAMBDA - sin(omega*0.5)*sin(omega*0.5));
glBegin(GL_LINE_STRIP);
for (i=0; i<=NPOLY; i++)
{
for (j=0; j<NSEG; j++)
{
s = 2.0*(((double)j/(double)NSEG)-0.5)*beta2;
if (i%2==0) x1 = x2plus - LAMBDA*cos(s);
else x1 = x2minus + LAMBDA*cos(s);
y1 = LAMBDA*sin(s);
angle = i*omega + APOLY*PID;
x = cos(angle)*x1 - sin(angle)*y1;
y = sin(angle)*x1 + cos(angle)*y1;
glVertex2d(x, y);
}
}
glEnd ();
break;
}
case (D_ANGLE):
{
if (DRAW_CONSTRUCTION_LINES)
{
glColor3f(0.5, 0.5, 0.5);
glBegin(GL_LINE_STRIP);
phi = LAMBDA*PI;
r = 2.0*YMAX;
for (i=-(int)(PI/phi)-1; i <= (int)(PI/phi)+2; i++)
{
// printf("%i \n", i);
glVertex2d(0.0, 0.0);
glVertex2d(-r*cos((double)i*phi), r*sin((double)i*phi));
}
glEnd();
}
if (PAINT_INT) glColor3f(0.5, 0.5, 0.5);
else
{
if (BLACK) glColor3f(1.0, 1.0, 1.0);
else glColor3f(0.0, 0.0, 0.0);
}
glBegin(GL_LINE_STRIP);
glVertex2d(XMIN, 0.0);
glVertex2d(0.0, 0.0);
glVertex2d(-YMAX/tan(LAMBDA*PI), YMAX);
glEnd ();
break;
}
case (D_LSHAPE):
{
glBegin(GL_LINE_LOOP);
glVertex2d(-1.0, -1.0);
glVertex2d(1.0, -1.0);
glVertex2d(1.0, 0.0);
glVertex2d(0.0, 0.0);
glVertex2d(0.0, 1.0);
glVertex2d(-1.0, 1.0);
glEnd();
break;
}
case (D_GENUSN): /* like for polygon */
{
omega = DPI/((double)NPOLY);
glBegin(GL_LINE_LOOP);
for (i=0; i<=NPOLY; i++)
{
x = cos(i*omega + APOLY*PID);
y = sin(i*omega + APOLY*PID);
glVertex2d(SCALING_FACTOR*x, SCALING_FACTOR*y);
}
glEnd ();
break;
}
case (D_CIRCLES):
{
for (k=0; k<ncircles; k++) if (circleactive[k])
{
glBegin(GL_LINE_LOOP);
for (i=0; i<=NSEG; i++)
{
phi = (double)i*DPI/(double)NSEG;
x = circlex[k] + circlerad[k]*cos(phi);
y = circley[k] + circlerad[k]*sin(phi);
glVertex2d(x, y);
}
glEnd ();
}
break;
}
default:
{
printf("Function draw_billiard not defined for this billiard \n");
}
}
}
/*********************************/
/* computation of the collisions */
/*********************************/
/* The variable config contains information on the state of the particle
* and on its next collision with the boundary:
* [0] position of next collision (ellipse parametrised by (LAMBDA*cos(s), sin(s))
* [1] angle to tangent of boundary after next collision
* [2] running time
* [3] initial distance to next collision
* [4,5] initial position
* [6,7] coordinates of next collision
* The running time is incremented until it equals the distance to the next collision
*/
void print_config(conf) /* for debugging purposes */
double conf[8];
{
printf("s = %.3lg, u = %.3lg, t = %.3lg, L = %.3lg, x0 = %.3lg, y0 = %.3lg, x1 = %.3lg, y1 = %.3lg\n", conf[0], conf[1]/PI, conf[2], conf[3], conf[4], conf[5], conf[6], conf[7]);
}
void print_config_23(conf) /* for debugging purposes */
double conf[8];
{
printf("t = %.8f, L = %.8f\n", conf[2], conf[3]);
}
void print_colors(color) /* for debugging purposes */
int color[NPARTMAX];
{
int i;
for (i=0; i<NPART; i++) printf("%i ", color[i]);
printf("\n");
}
/****************************************************************************************/
/* rectangle billiard */
/****************************************************************************************/
int pos_rectangle(conf, pos, alpha)
/* determine position on boundary of rectangle */
/* the corners of the rectangle are (-LAMBDA,-1), ..., (LAMBDA,1) */
/* returns the number of the side hit, or 0 if hitting a corner */
double conf[2], pos[2], *alpha;
{
double s, theta;
s = conf[0];
if (s<0.0) s = 0.0;
if (s>4.0*LAMBDA + 4.0) s = 4.0*LAMBDA + 4.0;
theta = conf[1];
/* we treat the cases of starting in one corner separately */
/* to avoid numerical problems due to hitting a corner */
/* bottom left corner */
if ((s==0)||(s==4.0*LAMBDA + 4.0))
{
pos[0] = -LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta;
return(0);
}
/* bottom right corner */
else if (s==2.0*LAMBDA)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + PID;
return(0);
}
/* top right corner */
else if (s==2.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + PI;
return(0);
}
/* top left corner */
else if (s==4.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = -1.0;
if (theta > PID) theta = PID;
*alpha = theta + 3.0*PID;
return(0);
}
/* bottom side */
else if ((s>0)&&(s<2.0*LAMBDA))
{
pos[0] = s - LAMBDA;
pos[1] = -1.0;
*alpha = theta;
return(1);
}
/* right side */
else if (s<2.0*LAMBDA + 2.0)
{
pos[0] = LAMBDA;
pos[1] = s - 2.0*LAMBDA - 1.0;
*alpha = theta + PID;
return(2);
}
/* top side */
else if (s<4.0*LAMBDA + 2.0)
{
pos[0] = 3.0*LAMBDA + 2.0 - s;
pos[1] = 1.0;
*alpha = theta + PI;
return(3);
}
/* left side */
else
{
pos[0] = -LAMBDA;
pos[1] = 4.0*LAMBDA + 3.0 - s;
*alpha = theta + 3.0*PID;
return(4);
}
}
int vrectangle_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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(config)
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(conf, pos, alpha)
/* determine position on boundary of ellipse */
double conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
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(conf, pos, alpha)
/* determine position on boundary of stadium */
double conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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(config)
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(conf, pos, 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 conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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(config)
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(conf, pos, 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 conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
/* Warning: reflection in the corners is not yet implemented correctly */
double config[8], alpha, pos[2];
{
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(config)
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(conf, pos, alpha)
/* determine position on boundary of annulus */
double conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_annulus(config, pos, &alpha);
vannulus_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* polygonal billiard */
/****************************************************************************************/
int pos_polygon(conf, pos, alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
double conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double s, theta, omega, length, rlength, s1, rangle, x, y, xp, yp, x1, y1, ca, sa;
int k, c, intb=1, intc, i;
/* dimensions/angles of polygon */
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
rlength = cos(0.5*omega);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = (0.5 + (double)k)*omega + APOLY*PID;
theta = alpha - rangle;
if ((cos(theta) > 0.0)&&(intb))
{
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
xp = rlength;
yp = y + (xp-x)*tan(theta);
if (vabs(yp) < 0.5*length)
{
/* rotate back */
x1 = xp*ca - yp*sa;
y1 = xp*sa + yp*ca;
intb = 0;
c = k;
config[0] = ((double)k + 0.5)*length + yp;
config[1] = PID - theta;
}
}
}
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int vpolygon(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
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(conf, pos, alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
double conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double s, theta, omega2, beta, s1, rangle, x, y, x1[NPOLY], y1[NPOLY], xi, yi, t, x2;
double ca, sa, a, b, margin = 1.0e-14, tmin, tval[NPOLY], tempconf[NPOLY][2];
int k, c, intb=1, intc, i, nt = 0, cval[NPOLY], ntmin;
/* dimensions/angles of polygon */
omega2 = PI/((double)NPOLY);
beta = 2.0*asin(sin(omega2)/vabs(LAMBDA));
// printf("beta = %.5lg\n", beta);
if (LAMBDA > 0.0) x2 = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
else x2 = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
// printf("x2 = %.5lg\n", x2);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = 2.0*(double)k*omega2 + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
a = (x-x2)*cos(theta) + y*sin(theta);
b = (x-x2)*(x-x2) + y*y - LAMBDA*LAMBDA;
if (a*a - b > margin)
{
if (LAMBDA > 0.0) t = -a - sqrt(a*a - b);
else t = -a + sqrt(a*a - b);
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if ((t > margin)&&(vabs(yi) <= sin(omega2)))
{
cval[nt] = k;
tval[nt] = t;
/* rotate back */
x1[nt] = xi*ca - yi*sa;
y1[nt] = xi*sa + yi*ca;
tempconf[nt][0] = ((double)k + 0.5)*beta + asin(yi/LAMBDA);
tempconf[nt][1] = PID - asin(yi/LAMBDA) - theta;
nt++;
}
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
// printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
return(c);
}
int vreuleaux(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_reuleaux(config, pos, &alpha);
vreuleaux_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Bunimovich flower billiard */
/****************************************************************************************/
int pos_flower(conf, pos, alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary, it belongs to [0,2*NPOLY*phimax) */
double conf[2], pos[2], *alpha;
{
double s, theta, omega, co, so, axis1, axis2, phimax, s1, x, y, angle;
int c;
s = conf[0];
theta = conf[1];
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
c = (int)(s/(2.0*phimax)); /* side of shape */
s1 = s - (((double)c)*2.0 + 1.0)*phimax;
x = co + axis1*cos(s1);
y = axis2*sin(s1);
angle = ((double)c)*omega + PID*APOLY;
// angle = 2.0*((double)c)*omega + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = argument(-axis1*sin(s1), axis2*cos(s1)) + theta + angle;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int vflower_xy(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, y1, xi, yi, t;
double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin;
double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2;
int k, c, intb=1, intc, i, nt = 0, ntmin, sign;
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
for (k=0; k<NPOLY; k++) if (intb)
{
/* rotate position so that kth side is vertical */
// rangle = (double)(2*k)*omega + APOLY*PID;
rangle = (double)k*omega + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
ct = cos(theta);
st = sin(theta);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
/* find intersection with elliptical arc */
aa = ct*ct/(axis1*axis1) + st*st/(axis2*axis2);
bb = (x-co)*ct/(axis1*axis1) + y*st/(axis2*axis2);
cc = (x-co)*(x-co)/(axis1*axis1) + y*y/(axis2*axis2) - 1.0;
// if (bb*bb - aa*cc > margin)
if (bb*bb - aa*cc >= 0.0)
{
t = (-bb + sqrt(bb*bb - aa*cc))/aa;
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2);
else phi = -argument((xi - co)/axis1, -yi/axis2);
if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
{
intb = 0;
c = k;
/* rotate back */
x1 = xi*ca - yi*sa;
y1 = xi*sa + yi*ca;
config[0] = (double)(2*k + 1)*phimax + phi;
config[1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta;
}
}
}
// if (nt == 0) printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int old_vflower_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double s, theta, omega, omega2, s1, rangle, x, y, x1[2*NPOLY], y1[2*NPOLY], xi, yi, t;
double ca, sa, aa, bb, cc, margin = 1.0e-14, tmin, tval[2*NPOLY], tempconf[2*NPOLY][2];
double co, so, co2, so2, ct, st, phimax, phi, axis1, axis2;
int k, c, intb=1, intc, i, nt = 0, cval[2*NPOLY], ntmin, sign;
compute_flower_parameters(&omega, &co, &so, &axis1, &axis2, &phimax);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
// rangle = (double)(2*k)*omega + APOLY*PID;
rangle = (double)k*omega + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
ct = cos(theta);
st = sin(theta);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
/* find intersection with elliptical arc */
aa = ct*ct/(axis1*axis1) + st*st/(axis2*axis2);
bb = (x-co)*ct/(axis1*axis1) + y*st/(axis2*axis2);
cc = (x-co)*(x-co)/(axis1*axis1) + y*y/(axis2*axis2) - 1.0;
// if (bb*bb - aa*cc > margin)
if (bb*bb - aa*cc >= 0.0)
{
t = (-bb + sqrt(bb*bb - aa*cc))/aa;
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if (yi >= 0.0) phi = argument((xi - co)/axis1, yi/axis2);
else phi = -argument((xi - co)/axis1, -yi/axis2);
// phi = argument((xi - co)/axis1, yi/axis2);
// if (phi > PI) phi += -DPI;
if ((t > margin)&&((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
// if (((vabs(phi) <= phimax)||(vabs(phi-DPI) <= phimax)))
// if ((t > margin))
{
cval[nt] = k;
// cval[nt] = 2*k;
tval[nt] = t;
/* rotate back */
x1[nt] = xi*ca - yi*sa;
y1[nt] = xi*sa + yi*ca;
tempconf[nt][0] = (double)(2*k + 1)*phimax + phi;
tempconf[nt][1] = argument(-axis1*sin(phi), axis2*cos(phi)) - theta;
nt++;
}
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
if (nt == 0) printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
return(c);
}
int vflower(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_flower(config, pos, &alpha);
vflower_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* Alternating between Reuleaux-type and star-shaped billiard */
/****************************************************************************************/
int pos_alt_reuleaux(conf, pos, alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
double conf[2], pos[2], *alpha;
{
double s, theta, omega2, beta2, beta, s1, angle, x2plus, x2minus, x, y;
int c;
s = conf[0];
theta = conf[1];
omega2 = PI/((double)NPOLY);
beta2 = asin(sin(omega2)/vabs(LAMBDA));
beta = beta2*2.0;
c = (int)(s/beta); /* side of shape */
s1 = s - ((double)c)*beta;
x2plus = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
x2minus = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
if (c%2 == 0) x = x2plus - LAMBDA*cos(s1 - beta2);
else x = x2minus + LAMBDA*cos(s1 - beta2);
if (c%2 == 0) y = LAMBDA*sin(s1 - beta2);
else y = -LAMBDA*sin(s1 - beta2);
/* test, to be removed */
// x = x2plus - LAMBDA*cos(s1 - beta2);
// y = LAMBDA*sin(s1 - beta2);
angle = 2.0*((double)c)*omega2 + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = PID - s1 + beta2 + theta + 2.0*(double)c*omega2 + APOLY*PID;
// printf("alpha = %.5lg\t", *alpha);
return(c);
}
int valt_reuleaux_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double s, theta, omega2, beta, s1, rangle, x, y, x1[NPOLY], y1[NPOLY], xi, yi, t, x2plus, x2minus, arcsine;
double ca, sa, a, b, margin = 1.0e-14, tmin, tval[NPOLY], tempconf[NPOLY][2];
int k, c, intb=1, intc, i, nt = 0, cval[NPOLY], ntmin;
/* dimensions/angles of polygon */
omega2 = PI/((double)NPOLY);
beta = 2.0*asin(sin(omega2)/vabs(LAMBDA));
// printf("beta = %.5lg\n", beta);
x2plus = cos(omega2) + sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
x2minus = cos(omega2) - sqrt(LAMBDA*LAMBDA - sin(omega2)*sin(omega2));
// printf("x2 = %.5lg\n", x2);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = 2.0*(double)k*omega2 + APOLY*PID;
theta = alpha - rangle;
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
if (k%2==0)
{
a = (x-x2plus)*cos(theta) + y*sin(theta);
b = (x-x2plus)*(x-x2plus) + y*y - LAMBDA*LAMBDA;
}
else
{
a = (x-x2minus)*cos(theta) + y*sin(theta);
b = (x-x2minus)*(x-x2minus) + y*y - LAMBDA*LAMBDA;
}
if (a*a - b > margin)
{
if (k%2==0) t = -a - sqrt(a*a - b);
else t = -a + sqrt(a*a - b);
xi = x + t*cos(theta);
yi = y + t*sin(theta);
if ((t > margin)&&(vabs(yi) <= sin(omega2)))
{
cval[nt] = k;
tval[nt] = t;
/* rotate back */
x1[nt] = xi*ca - yi*sa;
y1[nt] = xi*sa + yi*ca;
if (k%2==0) arcsine = asin(yi/LAMBDA);
else arcsine = -asin(yi/LAMBDA);
tempconf[nt][0] = ((double)k + 0.5)*beta + arcsine;
tempconf[nt][1] = PID - arcsine - theta;
nt++;
}
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
// printf("nt = %i\t ntmin = %i \tcmin = %i\n", nt, ntmin, c);
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1[ntmin]; /* position of collision */
config[7] = y1[ntmin];
return(c);
}
int valt_reuleaux(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_alt_reuleaux(config, pos, &alpha);
valt_reuleaux_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* angle billiard */
/****************************************************************************************/
int pos_angle(conf, pos, alpha)
/* determine position on boundary of triangle */
/* corner of angle is at (0,0), sides are horizontal and x*sin(a) = -y*cos(a), a=LAMBDA*PI */
/* we use arclength for horizontal and vertical side, y for diagonal */
double conf[2], pos[2], *alpha;
{
double s, theta;
s = conf[0];
theta = conf[1];
if (s<=0)
{
pos[0] = s;
pos[1] = 0.0;
*alpha = theta;
return(0);
}
else
{
pos[0] = - s/tan(LAMBDA*PI);
pos[1] = s;
*alpha = theta + (1.0-LAMBDA)*PI;
return(1);
}
}
int vangle_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
/* Warning: reflection in the corners is not yet implemented correctly */
double config[8], alpha, pos[2];
{
double s0, c0, t, x, y, x1, y1, phi;
int c, intb=1, intc, i;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
/* intersection with lower part of boundary */
if (s0<0.0)
{
x1 = pos[0] - pos[1]*c0/s0;
y1 = 0.0;
if (x1<=0.0)
{
config[0] = x1;
config[1] = -alpha;
intb = 0;
}
}
/* intersection with diagonal part of boundary */
if ((intb)&&(sin(alpha+LAMBDA*PI)>0.0))
{
phi = LAMBDA*PI;
t = -(pos[0]*sin(phi) + pos[1]*cos(phi))/sin(alpha+phi);
x1 = pos[0] + t*c0;
y1 = pos[1] + t*s0;
if (y1 > 0.0)
{
config[0] = y1;
config[1] = PI - alpha - phi;
intb = 0;
}
}
/* other cases, assign a dummy coordinate */
if (intb)
{
if (s0 > 0.0)
{
t = (1000.0 - pos[0])/s0;
x1 = pos[0] + t*c0;
y1 = 1000.0;
}
else
{
t = -(1000.0 + pos[0])/c0;
x1 = -1000.0;
y1 = pos[1] + t*s0;
}
config[0] = -1000.0;
config[1] = PID;
}
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1;
config[7] = y1;
return(c);
}
int vangle(config)
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(conf, pos, 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 conf[2], pos[2], *alpha;
{
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(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double t, l, s0, c0, margin = 1e-12, tmin;
double x1[6], y1[6], tval[6], tempconf[6][2];
int i, c, intb=1, cval[6], nt = 0, ntmin;
/* initial position and velocity */
s0 = sin(alpha);
c0 = cos(alpha);
// print_config(config);
/* intersection with lower part of boundary */
if (s0<0.0)
{
t = - (1.0 + pos[1])/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = -1.0;
if ((x1[nt]>=-1.0)&&(x1[nt]<=0.0))
{
tempconf[nt][0] = 5.0 - x1[nt];
tempconf[nt][1] = alpha + PI;
cval[nt] = 5;
tval[nt] = t;
nt++;
}
else if ((x1[nt]>0.0)&&(x1[nt]<=1.0))
{
tempconf[nt][0] = 4.0 - x1[nt];
tempconf[nt][1] = alpha + PI;
cval[nt] = 3;
tval[nt] = t;
nt++;
}
}
/* intersection with lower part of right-hand boundary */
if (c0>0.0)
{
t = (1.0 - pos[0])/c0;
x1[nt] = 1.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=-1.0)&&(y1[nt]<=0.0))
{
tempconf[nt][0] = 7.0 - y1[nt];
tempconf[nt][1] = PID + alpha;
cval[nt] = 6;
tval[nt] = t;
nt++;
}
}
/* intersection with upper part of right-hand boundary */
if ((pos[0] < 0.0)&&(c0>0.0))
{
t = - pos[0]/c0;
x1[nt] = 0.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=0.0)&&(y1[nt]<=1.0))
{
tempconf[nt][0] = 7.0 - y1[nt];
tempconf[nt][1] = PID + alpha;
cval[nt] = 4;
tval[nt] = t;
nt++;
}
}
/* intersection with right-hand part of upper boundary */
if ((pos[1] < 0.0)&&(s0>0.0))
{
t = - pos[1]/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = 0.0;
if ((x1[nt]>=-0.0)&&(x1[nt]<=1.0))
{
tempconf[nt][0] = 1.0 + x1[nt];
tempconf[nt][1] = alpha;
cval[nt] = 1;
tval[nt] = t;
nt++;
}
}
/* intersection with left-hand part of upper boundary */
if (s0>0.0)
{
t = (1.0 - pos[1])/s0;
x1[nt] = pos[0] + c0*t;
y1[nt] = 1.0;
if ((x1[nt]>=-1.0)&&(x1[nt]<=0.0))
{
tempconf[nt][0] = 1.0 + x1[nt];
tempconf[nt][1] = alpha;
cval[nt] = 1;
tval[nt] = t;
nt++;
}
}
/* intersection with left-hand part of boundary */
if (c0<0.0)
{
t = (-1.0 - pos[0])/c0;
x1[nt] = -1.0;
y1[nt] = pos[1] + s0*t;
if ((y1[nt]>=0.0)&&(y1[nt]<=1.0))
{
tempconf[nt][0] = 4.0 + y1[nt];
tempconf[nt][1] = alpha - PID;
cval[nt] = 4;
tval[nt] = t;
nt++;
}
else if ((y1[nt]>=-1.0)&&(y1[nt]<0.0))
{
tempconf[nt][0] = 3.0 + y1[nt];
tempconf[nt][1] = alpha - PID;
cval[nt] = 2;
tval[nt] = t;
nt++;
}
}
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
// printf("nt = %i, ntmin = %i, cmin = %i\n", nt, ntmin, cval[ntmin]);
config[0] = tempconf[ntmin][0];
config[1] = tempconf[ntmin][1];
c = cval[ntmin];
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1[ntmin]-pos[0], y1[ntmin]-pos[1]);
config[4] = pos[0];
config[5] = pos[1];
config[6] = x1[ntmin];
config[7] = y1[ntmin];
// print_config(config);
return(c);
}
int vlshape(config)
double config[8];
{
double pos[2], alpha;
int c;
/* position et vitesse de depart */
c = pos_lshape(config, pos, &alpha);
vlshape_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* genus n surface - polygon with opposite sides identified */
/****************************************************************************************/
int pos_genusn(conf, pos, alpha)
/* determine position on boundary of polygon */
/* conf[0] is arclength on boundary */
double conf[2], pos[2], *alpha;
{
double s, theta, omega, length, s1, angle, x, y;
int c;
s = conf[0];
theta = conf[1];
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
c = (int)(s/length); /* side of polygon */
s1 = s - ((double)c)*length;
x = 1.0 + (cos(omega) - 1.0)*s1/length;
y = sin(omega)*s1/length;
angle = (double)c*omega + PID*APOLY;
pos[0] = x*cos(angle) - y*sin(angle);
pos[1] = x*sin(angle) + y*cos(angle);
*alpha = (0.5 + (double)c)*omega + theta + PID*(1.0 + APOLY);
return(c);
}
int vgenusn_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
double s, theta, omega, length, rlength, s1, rangle, x, y, xp, yp, x1, y1, ca, sa, margin = 1.0e-14;
int k, c, intb=1, intc, i;
/* dimensions/angles of polygon */
omega = DPI/((double)NPOLY);
length = 2.0*sin(0.5*omega);
rlength = cos(0.5*omega);
for (k=0; k<NPOLY; k++)
{
/* rotate position so that kth side is vertical */
rangle = (0.5 + (double)k)*omega + APOLY*PID;
theta = alpha - rangle;
if ((cos(theta) > 0.0)&&(intb))
{
ca = cos(rangle);
sa = sin(rangle);
x = pos[0]*ca + pos[1]*sa;
y = -pos[0]*sa + pos[1]*ca;
// xp = -rlength;
xp = rlength;
yp = y + (xp-x)*tan(theta);
if (vabs(yp) < 0.5*length - margin)
{
/* rotate back */
x1 = xp*ca - yp*sa;
y1 = xp*sa + yp*ca;
intb = 0;
c = k + NPOLY/2;
if (c > NPOLY) c -= NPOLY;
config[0] = ((double)c + 0.5)*length - yp;
// if (config[0] > (double)NPOLY*length) config[0] -= (double)NPOLY*length;
config[1] = PID + theta;
// config[0] = ((double)k + 0.5)*length + yp;
// config[1] = PID - theta;
}
}
}
if (intb) x1 = 1.0e12; /* to make inactive particles too close to a corner */
if (config[1] < 0.0) config[1] += DPI;
config[2] = 0.0; /* running time */
config[3] = module2(x1-pos[0], y1-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = x1; /* position of collision */
config[7] = y1;
return(c);
}
int vgenusn(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_genusn(config, pos, &alpha);
vgenusn_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* elliptic billiard */
/****************************************************************************************/
int pos_circles(conf, pos, alpha)
/* determine position on boundary of circle */
/* position varies between 0 and ncircles*2Pi */
/* returns number of hit circle */
double conf[2], pos[2], *alpha;
{
double angle;
int ncirc;
ncirc = (int)(conf[0]/DPI);
if (ncirc >= ncircles) ncirc = ncircles - 1;
angle = conf[0] - (double)ncirc*DPI;
pos[0] = circlex[ncirc] + circlerad[ncirc]*cos(angle);
pos[1] = circley[ncirc] + circlerad[ncirc]*sin(angle);
*alpha = angle + PID + conf[1];
return(ncirc);
}
int vcircles_xy(config, alpha, pos)
/* 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;
c0 = cos(alpha);
s0 = sin(alpha);
for (i=0; i<ncircles; i++)
{
b = (pos[0]-circlex[i])*c0 + (pos[1]-circley[i])*s0;
c = (pos[0]-circlex[i])*(pos[0]-circlex[i]) + (pos[1]-circley[i])*(pos[1]-circley[i]) - circlerad[i]*circlerad[i];
delta = b*b - c;
if (delta > margin) /* there is an intersection with circle i */
{
t = -b - sqrt(delta);
if (t > margin)
{
nscat[nt] = i;
tval[nt] = t;
xint[nt] = pos[0] + t*c0;
yint[nt] = pos[1] + t*s0;
phiint[nt] = argument(xint[nt] - circlex[i], yint[nt] - circley[i]);
nt++;
}
}
}
if (nt > 0) /* there is at least one intersection */
{
/* find earliest intersection */
tmin = tval[0];
ntmin = 0;
for (i=1; i<nt; i++)
if (tval[i] < tmin)
{
tmin = tval[i];
ntmin = i;
}
while (phiint[ntmin] < 0.0) phiint[ntmin] += DPI;
while (phiint[ntmin] >= DPI) phiint[ntmin] -= DPI;
config[0] = (double)nscat[ntmin]*DPI + phiint[ntmin];
config[1] = PID - alpha + phiint[ntmin]; /* CHECK */
if (config[1] < 0.0) config[1] += DPI;
if (config[1] >= PI) config[1] -= DPI;
config[2] = 0.0; /* running time */
config[3] = module2(xint[ntmin]-pos[0], yint[ntmin]-pos[1]); /* distance to collision */
config[4] = pos[0]; /* start position */
config[5] = pos[1];
config[6] = xint[ntmin]; /* position of collision */
config[7] = yint[ntmin];
return(nscat[ntmin]);
}
else /* there is no intersection - set dummy values */
{
config[0] = 0.0;
config[1] = 0.0;
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(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], alpha;
int c;
c = pos_circles(config, pos, &alpha);
vcircles_xy(config, alpha, pos);
return(c);
}
/****************************************************************************************/
/* general billiard */
/****************************************************************************************/
int pos_billiard(conf, pos, alpha)
/* determine initial configuration for start at point pos = (x,y) */
double conf[8], pos[2], *alpha;
{
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_CIRCLES):
{
return(pos_circles(conf, pos, &alpha));
break;
}
default:
{
printf("Function pos_billiard not defined for this billiard \n");
}
}
}
int vbilliard_xy(config, alpha, pos)
/* determine initial configuration for start at point pos = (x,y) */
double config[8], alpha, pos[2];
{
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_CIRCLES):
{
return(vcircles_xy(config, alpha, pos));
break;
}
default:
{
printf("Function vbilliard_xy not defined for this billiard \n");
}
}
}
/* TO DO: fix returned value */
int vbilliard(config)
/* determine initial configuration when starting from boundary */
double config[8];
{
double pos[2], theta, alpha;
int c;
switch (B_DOMAIN) {
case (D_RECTANGLE):
{
c = pos_rectangle(config, pos, &alpha);
return(vrectangle(config, alpha, pos));
break;
}
case (D_ELLIPSE):
{
c = pos_ellipse(config, pos, &alpha);
return(vellipse(config, alpha, pos));
break;
}
case (D_STADIUM):
{
c = pos_stade(config, pos, &alpha);
return(vstade(config, alpha, pos));
break;
}
case (D_SINAI):
{
c = pos_sinai(config, pos, &alpha);
return(vsinai(config, alpha, pos));
break;
}
case (D_TRIANGLE):
{
c = pos_triangle(config, pos, &alpha);
return(vtriangle(config, alpha, pos));
break;
}
case (D_ANNULUS):
{
c = pos_annulus(config, pos, &alpha);
return(vannulus(config, alpha, pos));
break;
}
case (D_POLYGON):
{
c = pos_polygon(config, pos, &alpha);
return(vpolygon(config, alpha, pos));
break;
}
case (D_REULEAUX):
{
c = pos_reuleaux(config, pos, &alpha);
return(vreuleaux(config, alpha, pos));
break;
}
case (D_FLOWER):
{
c = pos_flower(config, pos, &alpha);
return(vflower(config, alpha, pos));
break;
}
case (D_ALT_REU):
{
c = pos_alt_reuleaux(config, pos, &alpha);
return(valt_reuleaux(config, alpha, pos));
break;
}
case (D_ANGLE):
{
c = pos_angle(config, pos, &alpha);
return(vangle(config, alpha, pos));
break;
}
case (D_LSHAPE):
{
c = pos_lshape(config, pos, &alpha);
return(vlshape(config, alpha, pos));
break;
}
case (D_GENUSN):
{
c = pos_genusn(config, pos, &alpha);
return(vgenusn(config, alpha, pos));
break;
}
case (D_CIRCLES):
{
c = pos_circles(config, pos, &alpha);
return(vcircles(config, alpha, pos));
break;
}
default:
{
printf("Function vbilliard not defined for this billiard \n");
}
}
}
int xy_in_billiard(x, y)
/* returns 1 if (x,y) represents a point in the billiard */
double x, y;
{
double l2, r1, r2, omega, omega2, c, angle, x1, y1, x2, co, so, x2plus, x2minus;
int condition, k;
switch (B_DOMAIN) {
case D_RECTANGLE:
{
if ((vabs(x) <LAMBDA)&&(vabs(y) < 1.0)) return(1);
else return(0);
break;
}
case D_ELLIPSE:
{
if (x*x/(LAMBDA*LAMBDA) + y*y < 1.0) return(1);
else return(0);
break;
}
case D_STADIUM:
{
if ((x > -0.5*LAMBDA)&&(x < 0.5*LAMBDA)&&(y > -1.0)&&(y < 1.0)) return(1);
else if (module2(x+0.5*LAMBDA, y) < 1.0) return(1);
else if (module2(x-0.5*LAMBDA, y) < 1.0) return(1);
else return(0);
break;
}
case D_SINAI:
{
if (x*x + y*y > LAMBDA*LAMBDA) return(1);
else return(0);
break;
}
case D_DIAMOND:
{
l2 = LAMBDA*LAMBDA;
r2 = l2 + (LAMBDA-1.0)*(LAMBDA-1.0);
if ((x*x + y*y < 1.0)&&((x-LAMBDA)*(x-LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2)
&&((x-LAMBDA)*(x-LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2)
&&((x+LAMBDA)*(x+LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2)
&&((x+LAMBDA)*(x+LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2)) return(1);
else return(0);
break;
}
case D_TRIANGLE:
{
if ((x>-LAMBDA)&&(y>-1.0)&&(LAMBDA*y+x<0.0)) return(1);
else return(0);
break;
}
case D_ANNULUS:
{
l2 = LAMBDA*LAMBDA;
r1 = x*x + y*y;
r2 = (x-MU)*(x-MU) + y*y;
if ((r2 > l2)&&(r1 < 1.0)) return(1);
else return(0);
break;
}
case D_POLYGON:
{
condition = 1;
omega = DPI/((double)NPOLY);
c = cos(omega*0.5);
for (k=0; k<NPOLY; k++)
{
angle = APOLY*PID + (k+0.5)*omega;
condition = condition*(x*cos(angle) + y*sin(angle) < c);
}
return(condition);
break;
}
case D_REULEAUX:
{
condition = 1;
omega2 = PI/((double)NPOLY);
co = cos(omega2);
so = sin(omega2);
if (LAMBDA > 0.0) x2 = co + sqrt(LAMBDA*LAMBDA - so*so);
else x2 = co - sqrt(LAMBDA*LAMBDA - so*so);
for (k=0; k<NPOLY; k++)
{
angle = 2.0*(double)k*omega2 + APOLY*PID;
x1 = x*cos(angle) + y*sin(angle);
y1 = -x*sin(angle) + y*cos(angle);
if (LAMBDA > 0.0) condition = condition*((x1-x2)*(x1-x2) + y1*y1 > LAMBDA*LAMBDA);
else condition = condition*((x1-x2)*(x1-x2) + y1*y1 < LAMBDA*LAMBDA);
}
return(condition);
break;
}
/* D_REULEAUX : distance to all centers of arcs should be larger than LAMBDA */
case D_FLOWER:
{
/* TO DO */
return(1);
break;
}
case D_ALT_REU:
{
condition = 1;
omega2 = PI/((double)NPOLY);
co = cos(omega2);
so = sin(omega2);
x2plus = co + sqrt(LAMBDA*LAMBDA - so*so);
x2minus = co - sqrt(LAMBDA*LAMBDA - so*so);
for (k=0; k<NPOLY; k++)
{
angle = 2.0*(double)k*omega2 + APOLY*PID;
x1 = x*cos(angle) + y*sin(angle);
y1 = -x*sin(angle) + y*cos(angle);
if (k%2==0) condition = condition*((x1-x2plus)*(x1-x2plus) + y1*y1 > LAMBDA*LAMBDA);
else condition = condition*((x1-x2minus)*(x1-x2minus) + y1*y1 < LAMBDA*LAMBDA);
}
return(condition);
break;
}
case D_ANGLE:
{
if (y <= 0.0) return(0);
else if (x*sin(LAMBDA*PI) < -y*cos(LAMBDA*PI)) return(1);
else return(0);
break;
}
case D_LSHAPE:
{
if ((y <= 0.0)&&(x >= -1.0)&&(x <= 1.0)) return(1);
else if ((x >= -1.0)&&(x <= 0.0)) return(1);
else return(0);
break;
}
case D_GENUSN: /* same as polygon */
{
condition = 1;
omega = DPI/((double)NPOLY);
c = cos(omega*0.5);
for (k=0; k<NPOLY; k++)
{
angle = APOLY*PID + (k+0.5)*omega;
condition = condition*(x*cos(angle) + y*sin(angle) < c);
}
return(condition);
break;
}
case D_CIRCLES:
{
condition = 1;
for (k=0; k<ncircles; k++)
{
r2 = (x-circlex[k])*(x-circlex[k]) + (y-circley[k])*(y-circley[k]);
condition = condition*(r2 > circlerad[k]*circlerad[k])*circleactive[k];
}
return(condition);
break;
}
default:
{
printf("Function ij_in_billiard not defined for this billiard \n");
return(1);
}
}
}