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