/*********************/ /* Graphics routines */ /*********************/ #include "colors_waves.c" int writetiff_new(char *filename, char *description, int x, int y, int width, int height, int compression) { TIFF *file; GLubyte *image, *p; int i; file = TIFFOpen(filename, "w"); if (file == NULL) { return 1; } image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3); /* OpenGL's default 4 byte pack alignment would leave extra bytes at the end of each image row so that each full row contained a number of bytes divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist just to pad the row out to 12 bytes (12 is divisible by 4). To make sure the rows are packed as tight as possible (no row padding), set the pack alignment to 1. */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) width); TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) height); TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(file, TIFFTAG_COMPRESSION, compression); TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(file, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1); TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, description); p = image; for (i = height - 1; i >= 0; i--) { // if (TIFFWriteScanline(file, p, height - i - 1, 0) < 0) if (TIFFWriteScanline(file, p, i, 0) < 0) { free(image); TIFFClose(file); return 1; } p += width * sizeof(GLubyte) * 3; } free(image); /* prenvents RAM consumption*/ TIFFClose(file); return 0; } int writetiff(char *filename, char *description, int x, int y, int width, int height, int compression) { TIFF *file; GLubyte *image, *p; int i; file = TIFFOpen(filename, "w"); if (file == NULL) { return 1; } image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3); /* OpenGL's default 4 byte pack alignment would leave extra bytes at the end of each image row so that each full row contained a number of bytes divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist just to pad the row out to 12 bytes (12 is divisible by 4). To make sure the rows are packed as tight as possible (no row padding), set the pack alignment to 1. */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) width); TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) height); TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(file, TIFFTAG_COMPRESSION, compression); TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(file, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1); TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, description); p = image; for (i = height - 1; i >= 0; i--) { // if (TIFFWriteScanline(file, p, height - i - 1, 0) < 0) if (TIFFWriteScanline(file, p, i, 0) < 0) { free(image); TIFFClose(file); return 1; } p += width * sizeof(GLubyte) * 3; } TIFFClose(file); return 0; } void init() /* initialisation of window */ { glLineWidth(3); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // glOrtho(XMIN, XMAX, YMIN, YMAX , -1.0, 1.0); glOrtho(0.0, NX, 0.0, NY, -1.0, 1.0); } void blank() { 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 test_save_frame() /* some tests with various resolutions */ { static int counter = 0; char *name="wave.", 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, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT, COMPRESSION_LZW); // works for 1080p -> "-50px" // choose one of the following according to the comment beside. // writetiff(n2, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT-40, COMPRESSION_LZW); /* to use with 1080p in drop_billiard.c- probably the best because it's // generating 1080p image, lighter, and then cropping those 40 pixels to // avoid the strange band*/ // writetiff(n2, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT-50, COMPRESSION_LZW); // works for 1080p -> "-50px" band!!! // writetiff(n2, "Wave equation in a planar domain", 0, 0, 1920, 1080-40, COMPRESSION_LZW); //another perfect 1080p from 1440p in setup // writetiff(n2, "Wave equation in a planar domain", -WINWIDTH/8+320, -WINHEIGHT/8+180, WINWIDTH-640, WINHEIGHT-400, COMPRESSION_LZW); // perfect 1040p from 1440p in setup } void test_save_frame_counter(int counter) /* some tests with various resolutions */ /* same as save_frame, but with imposed image number (for option DOUBLE_MOVIE) */ { char *name="wave.", 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, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT, COMPRESSION_LZW); // works for 1080p -> "-50px" // choose one of the following according to the comment beside. // writetiff(n2, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT-40, COMPRESSION_LZW); /* to use with 1080p in drop_billiard.c- probably the best because it's // generating 1080p image, lighter, and then cropping those 40 pixels to // avoid the strange band*/ // writetiff(n2, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT-50, COMPRESSION_LZW); // works for 1080p -> "-50px" band!!! // writetiff(n2, "Wave equation in a planar domain", 0, 0, 1920, 1080-40, COMPRESSION_LZW); //another perfect 1080p from 1440p in setup // writetiff(n2, "BWave equation in a planar domain", -WINWIDTH/8+320, -WINHEIGHT/8+180, WINWIDTH-640, WINHEIGHT-400, COMPRESSION_LZW); // perfect 1040p from 1440p in setup } void save_frame() { static int counter = 0; char *name="wave.", 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, "Wave equation in a planar domain", 0, 0, WINWIDTH, WINHEIGHT, COMPRESSION_LZW); } void save_frame_counter(int counter) /* same as save_frame, but with imposed image number (for option DOUBLE_MOVIE) */ { char *name="wave.", 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, "Wave equation in a planar domain", 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 } } /*********************/ /* 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; } return(alph); } // 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= 1.0) return(0); omega = DPI/((double)polygon.nsides); cw = cos(omega*0.5); for (k=0; k YMIN - MU)) circles[n].active = 1; else circles[n].active = 0; } break; } case (C_RAND_DISPLACED): { ncircles = NGRIDX*NGRIDY; dy = (YMAX - YMIN)/((double)NGRIDY); for (i = 0; i < NGRIDX; i++) for (j = 0; j < NGRIDY; j++) { n = NGRIDY*i + j; circles[n].xc = ((double)(i-NGRIDX/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_PERCOL): { ncircles = NGRIDX*NGRIDY; dy = (YMAX - YMIN)/((double)NGRIDY); for (i = 0; i < NGRIDX; i++) for (j = 0; j < NGRIDY; j++) { n = NGRIDY*i + j; circles[n].xc = ((double)(i-NGRIDX/2) + 0.5)*dy; circles[n].yc = YMIN + ((double)j + 0.5)*dy; circles[n].radius = MU; p = (double)rand()/RAND_MAX; if (p < P_PERCOL) circles[n].active = 1; else circles[n].active = 0; } 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_CLOAK): { ncircles = 200; for (i = 0; i < 40; i++) for (j = 0; j < 5; j++) { n = 5*i + j; phi = (double)i*DPI/40.0; r = LAMBDA*0.5*(1.0 + (double)j/5.0); circles[n].xc = r*cos(phi); circles[n].yc = r*sin(phi); circles[n].radius = MU; circles[n].active = 1; } break; } case (C_CLOAK_A): /* optimized model A1 by C. Jo et al */ { ncircles = 200; ra[0] = 0.0731; sa[0] = 1.115; ra[1] = 0.0768; sa[1] = 1.292; ra[2] = 0.0652; sa[2] = 1.464; ra[3] = 0.056; sa[3] = 1.633; ra[4] = 0.0375; sa[4] = 1.794; for (i = 0; i < 40; i++) for (j = 0; j < 5; j++) { n = 5*i + j; phi = (double)i*DPI/40.0; r = LAMBDA*sa[j]; circles[n].xc = r*cos(phi); circles[n].yc = r*sin(phi); circles[n].radius = LAMBDA*ra[j]; circles[n].active = 1; } break; } case (C_LASER): { ncircles = 17; xx[0] = 0.5*(X_SHOOTER + X_TARGET); xx[1] = LAMBDA - 0.5*(X_TARGET - X_SHOOTER); 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); 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 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, circles[i].xc, circles[i].yc); /* generate new candidates */ naccepted = 0; for (j=0; j= dpoisson*dpoisson); /* new circle is in domain */ far = far*(vabs(x) < LAMBDA)*(y < YMAX)*(y > YMIN); } if (far) /* accept new circle */ { printf("New circle at (%.3f,%.3f) accepted\n", x, y); circles[ncircles].xc = x; circles[ncircles].yc = 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_GOLDEN_MEAN): { ncircles = 300; 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; } /* test for circles that overlap top or bottom boundary */ ncirc0 = ncircles; for (n=0; n < ncirc0; n++) { if (circles[n].yc + circles[n].radius > YMAX) { circles[ncircles].xc = circles[n].xc; circles[ncircles].yc = circles[n].yc - height; circles[ncircles].radius = MU; circles[ncircles].active = 1; ncircles ++; } else if (circles[n].yc - circles[n].radius < YMIN) { circles[ncircles].xc = circles[n].xc; circles[ncircles].yc = circles[n].yc + height; circles[ncircles].radius = MU; circles[ncircles].active = 1; ncircles ++; } } 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<1000; 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 YMIN - MU)) circles[i].active = 1; // printf("i = %i, circlex = %.3lg, circley = %.3lg\n", i, circles[i].xc, circles[i].yc); } break; } case (C_SQUARE_HEX): { ncircles = NGRIDX*(NGRIDY+1); dy = (YMAX - YMIN)/((double)NGRIDY); dx = dy*0.5*sqrt(3.0); for (i = 0; i < NGRIDX; i++) for (j = 0; j < NGRIDY+1; j++) { n = (NGRIDY+1)*i + j; circles[n].xc = ((double)(i-NGRIDX/2) + 0.5)*dy; /* is +0.5 needed? */ circles[n].yc = YMIN + ((double)j - 0.5)*dy; if (((i+NGRIDX)%4 == 2)||((i+NGRIDX)%4 == 3)) circles[n].yc += 0.5*dy; circles[n].radius = MU; /* activate only circles that intersect the domain */ if ((circles[n].yc < YMAX + MU)&&(circles[n].yc > YMIN - MU)) circles[n].active = 1; else circles[n].active = 0; } break; } case (C_RINGS): { ncircles = NGRIDX*NGRIDY; dphi = DPI/((double)NGRIDX); dr = 0.5*LAMBDA/(double)NGRIDY; for (i = 0; i < NGRIDX; i++) for (j = 0; j < NGRIDY; j++) { n = NGRIDY*i + j; phi = (double)i*dphi; r = 0.5*LAMBDA + (double)j*dr; circles[n].xc = r*cos(phi); circles[n].yc = r*sin(phi); circles[n].radius = MU; /* activate only circles that intersect the domain */ if ((circles[n].yc < YMAX + MU)&&(circles[n].yc > YMIN - MU)) circles[n].active = 1; else circles[n].active = 0; } break; } case (C_ONE): { circles[ncircles].xc = 0.0; circles[ncircles].yc = 0.0; circles[ncircles].radius = MU; circles[ncircles].active = 1; ncircles += 1; break; } case (C_TWO): /* used for comparison with cloak */ { circles[ncircles].xc = 0.0; circles[ncircles].yc = 0.0; circles[ncircles].radius = MU; circles[ncircles].active = 2; ncircles += 1; circles[ncircles].xc = 0.0; circles[ncircles].yc = 0.0; circles[ncircles].radius = 2.0*MU; circles[ncircles].active = 1; ncircles += 1; break; } case (C_NOTHING): { ncircles += 0; break; } default: { printf("Function init_circle_config not defined for this pattern \n"); } } } void init_polygon_config(t_polygon polygons[NMAXCIRCLES]) /* initialise the polygon configuration, for billiard shape D_CIRCLES */ /* uses init_circle_config, this is where C++ would be more elegant */ { int i; t_circle circle[NMAXCIRCLES]; init_circle_config(circle); for (i=0; ix = z.x - 2.0*zperp.x; zprime->y = z.y - 2.0*zperp.y; return(1); } int compute_tokarsky_coordinates(double xshift, double yshift, double scaling, t_vertex polyline[NMAXPOLY]) /* compute positions of vertices of tokarsky room */ { int i; double pos[2]; polyline[0].x = 0.0; polyline[0].y = 2.0; polyline[1].x = 1.0; polyline[1].y = 3.0; polyline[2].x = 1.0; polyline[2].y = 4.0; polyline[3].x = 2.0; polyline[3].y = 4.0; polyline[4].x = 2.0; polyline[4].y = 3.0; polyline[5].x = 3.0; polyline[5].y = 3.0; polyline[6].x = 3.0; polyline[6].y = 2.0; polyline[7].x = 5.0; polyline[7].y = 2.0; polyline[8].x = 5.0; polyline[8].y = 3.0; polyline[9].x = 6.0; polyline[9].y = 3.0; polyline[10].x = 6.0; polyline[10].y = 4.0; polyline[11].x = 7.0; polyline[11].y = 3.0; polyline[12].x = 8.0; polyline[12].y = 3.0; polyline[13].x = 8.0; polyline[13].y = 2.0; polyline[14].x = 7.0; polyline[14].y = 2.0; polyline[15].x = 7.0; polyline[15].y = 1.0; polyline[16].x = 6.0; polyline[16].y = 0.0; polyline[17].x = 6.0; polyline[17].y = 1.0; polyline[18].x = 5.0; polyline[18].y = 1.0; polyline[19].x = 4.0; polyline[19].y = 0.0; polyline[20].x = 4.0; polyline[20].y = 1.0; polyline[21].x = 3.0; polyline[21].y = 1.0; polyline[22].x = 2.0; polyline[22].y = 0.0; polyline[23].x = 2.0; polyline[23].y = 1.0; polyline[24].x = 1.0; polyline[24].y = 1.0; polyline[25].x = 1.0; polyline[25].y = 2.0; for (i=0; i<26; i++) { polyline[i].x = (polyline[i].x + xshift)*scaling; polyline[i].y = (polyline[i].y + yshift)*scaling; xy_to_pos(polyline[i].x, polyline[i].y, pos); polyline[i].posi = pos[0]; polyline[i].posj = pos[1]; } return(26); } void compute_isospectral_coordinates(int type, int ishift, double xshift, double yshift, double scaling, t_vertex polyline[NMAXPOLY]) /* compute positions of vertices of isospectral billiards */ /* central triangle has coordinates (0,0), (1,0) and (LAMBDA,MU) fed into affine transformation */ /* defined by (xshift - 0.5), (yshift - 0.25) and scaling*/ { int i; double pos[2]; polyline[ishift].x = (xshift - 0.5)*scaling; polyline[ishift].y = (yshift - 0.25)*scaling; polyline[ishift+1].x = (0.5+xshift)*scaling; polyline[ishift+1].y = (yshift - 0.25)*scaling; polyline[ishift+2].x = (LAMBDA+xshift - 0.5)*scaling; polyline[ishift+2].y = (MU+yshift - 0.25)*scaling; axial_symmetry_tvertex(polyline[ishift], polyline[ishift+2], polyline[ishift+1], &polyline[ishift+3]); axial_symmetry_tvertex(polyline[ishift], polyline[ishift+1], polyline[ishift+2], &polyline[ishift+4]); axial_symmetry_tvertex(polyline[ishift+1], polyline[ishift+2], polyline[ishift], &polyline[ishift+5]); if (type == 0) { axial_symmetry_tvertex(polyline[ishift], polyline[ishift+3], polyline[ishift+2], &polyline[ishift+6]); axial_symmetry_tvertex(polyline[ishift+1], polyline[ishift+4], polyline[ishift], &polyline[ishift+7]); axial_symmetry_tvertex(polyline[ishift+2], polyline[ishift+5], polyline[ishift+1], &polyline[ishift+8]); } else { axial_symmetry_tvertex(polyline[ishift+2], polyline[ishift+3], polyline[ishift], &polyline[ishift+6]); axial_symmetry_tvertex(polyline[ishift], polyline[ishift+4], polyline[ishift+1], &polyline[ishift+7]); axial_symmetry_tvertex(polyline[ishift+1], polyline[ishift+5], polyline[ishift+2], &polyline[ishift+8]); } for (i=ishift; i NMAXPOLY) { printf("NMAXPOLY needs to be increased to %i\n", nsides); nsides = NMAXPOLY; } for (i=0; i DPI) angle -= DPI; while (angle < 0.0) angle += DPI; xy_to_pos(x*MU, y*MU, pos); polyline[i].posi = pos[0]; polyline[i].posj = pos[1]; } return(nsides); } int compute_star_coordinates(t_vertex polyline[NMAXPOLY]) /* compute positions of vertices of star-shaped domain */ { int i; double alpha, r, x, y, pos[2]; alpha = DPI/(double)NPOLY; for (i=0; i= 0.0)&&(v2 >= 0.0)&&(v3 >= 0.0)) return(1); else return(0); } int xy_in_triangle_tvertex(double x, double y, t_vertex z1, t_vertex z2, t_vertex z3) /* returns 1 iff (x,y) is inside the triangle with vertices z1, z2, z3 */ { double v1, v2, v3; /* compute wedge products */ v1 = (z2.x - z1.x)*(y - z1.y) - (z2.y - z1.y)*(x - z1.x); v2 = (z3.x - z2.x)*(y - z2.y) - (z3.y - z2.y)*(x - z2.x); v3 = (z1.x - z3.x)*(y - z3.y) - (z1.y - z3.y)*(x - z3.x); if ((v1 >= 0.0)&&(v2 >= 0.0)&&(v3 >= 0.0)) return(1); else return(0); } int xy_in_billiard(double x, double y) /* returns 1 if (x,y) represents a point in the billiard */ // double x, y; { double l2, r2, r2mu, omega, b, c, angle, z, x1, y1, x2, y2, u, v, u1, v1, dx, dy, width, alpha; int i, j, k, k1, k2, condition = 0, m; static int first = 1, nsides; switch (B_DOMAIN) { case (D_RECTANGLE): { if ((vabs(x) -0.5*LAMBDA)&&(x < 0.5*LAMBDA)&&(y > -1.0)&&(y < 1.0)) return(1); else if (module2(x+0.5*LAMBDA, y) < 1.0) return(1); else if (module2(x-0.5*LAMBDA, y) < 1.0) return(1); else return(0); break; } case (D_SINAI): { if (x*x + y*y > LAMBDA*LAMBDA) return(1); else return(0); break; } case (D_DIAMOND): { l2 = LAMBDA*LAMBDA; r2 = l2 + (LAMBDA-1.0)*(LAMBDA-1.0); if ((x*x + y*y < 1.0)&&((x-LAMBDA)*(x-LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2) &&((x-LAMBDA)*(x-LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2) &&((x+LAMBDA)*(x+LAMBDA) + (y-LAMBDA)*(y-LAMBDA) > r2) &&((x+LAMBDA)*(x+LAMBDA) + (y+LAMBDA)*(y+LAMBDA) > r2)) return(1); else return(0); break; } case (D_TRIANGLE): { if ((x>-LAMBDA)&&(y>-1.0)&&(LAMBDA*y+x<0.0)) return(1); else return(0); break; } case (D_FLAT): { if (y > -LAMBDA) return(1); else return(0); break; } case (D_ANNULUS): { l2 = LAMBDA*LAMBDA; r2 = x*x + y*y; if ((r2 > l2)&&(r2 < 1.0)) return(1); else return(0); } case (D_POLYGON): { condition = 1; omega = DPI/((double)NPOLY); c = cos(omega*0.5); for (k=0; k MU)) return(1); else if ((vabs(y-LAMBDA) < MU)||(vabs(y+LAMBDA) < MU)) return (1); else return(0); } case (D_GRATING): { k1 = -(int)((-YMIN)/LAMBDA); k2 = (int)(YMAX/LAMBDA); condition = 1; for (i=k1; i<= k2; i++) { z = (double)i*LAMBDA; condition = condition*(x*x + (y-z)*(y-z) > MU*MU); } // printf("x = %.3lg, y = %.3lg, k1 = %i, k2 = %i, condition = %i\n", x, y, k1, k2, condition); return(condition); } case (D_EHRENFEST): { return(((x-1.0)*(x-1.0) + y*y < LAMBDA*LAMBDA)||((x+1.0)*(x+1.0) + y*y < LAMBDA*LAMBDA)||((vabs(x) < 1.0)&&(vabs(y) < MU))); } case (D_DISK_GRID): { dy = (YMAX - YMIN)/((double)NGRIDY); for (i = -NGRIDX/2; i < NGRIDX/2; i++) for (j = 0; j < NGRIDY; j++) { x1 = ((double)i + 0.5)*dy; y1 = YMIN + ((double)j + 0.5)*dy; if ((x-x1)*(x-x1) + (y-y1)*(y-y1) < MU*MU) return(0); } return(1); } case (D_DISK_HEX): { dy = (YMAX - YMIN)/((double)NGRIDY); dx = dy*0.5*sqrt(3.0); for (i = -NGRIDX/2; i < NGRIDX/2; i++) for (j = -1; j < NGRIDY; j++) { x1 = ((double)i + 0.5)*dy; y1 = YMIN + ((double)j + 0.5)*dy; if ((i+NGRIDX)%2 == 1) y1 += 0.5*dy; if ((x-x1)*(x-x1) + (y-y1)*(y-y1) < MU*MU) return(0); } return(1); } case (D_PARABOLA): { return(x > 0.25*y*y/LAMBDA - LAMBDA); } case (D_TWO_PARABOLAS): { x1 = 0.25*y*y/MU - MU - LAMBDA; x2 = -x1; width = 0.25*MU; if (width > 0.2) width = 0.2; if (vabs(y) > 1.5*MU) return(1); else if ((x < x1 - width)||(x > x2 + width)) return(1); else if ((x > x1)&&(x < x2)) return(1); else return(0); } case (D_FOUR_PARABOLAS): { x1 = MU + LAMBDA - 0.25*y*y/MU; y1 = MU + LAMBDA - 0.25*x*x/MU; return((vabs(x) < x1)&&(vabs(y) < y1)); } case (D_POLY_PARABOLAS): { condition = 1; omega = DPI/((double)NPOLY); for (k=0; k= LAMBDA) return(0); /* upper and lower ellipse */ else if ((vabs(y) >= MU)&&(x*x/(LAMBDA*LAMBDA) + (y1-MU)*(y1-MU)/((1.0-MU)*(1.0-MU)) >= 1.0)) return(0); /* small ellipses */ else if ((vabs(x) <= c)&&(4.0*(x1-c)*(x1-c)/(MU*MU) + y*y/(MU*MU) <= 1.0)) return(0); /* straight parts */ else if ((vabs(x) >= c)&&(vabs(y) <= width)) return(0); else return(1); } case (D_HYPERBOLA): { b = MU*sqrt(1.0 + x*x/(LAMBDA*LAMBDA - MU*MU)); if (y > 1.02*b) return(1); else if (y < 0.98*b) return (1); else return(0); } case (D_TOKARSKY): { x1 = 4.0 + x/(XMAX - XMIN)*8.4; y1 = 2.0 + y/(XMAX - XMIN)*8.4; if ((x1 <= 0.0)||(x1 >= 8.0)) return(0); else if (x1 < 1.0) { if (y1 <= 2.0) return(0); else if (y1 >= x1 + 2.0) return(0); else return(1); } else if (x1 < 2.0) { if (y1 <= 1.0) return(0); else if (y1 >= 4.0) return(0); else return(1); } else if (x1 < 3.0) { if (y1 <= x1 - 2.0) return(0); else if (y1 >= 3.0) return(0); else return(1); } else if (x1 < 4.0) { if (y1 <= 1.0) return(0); else if (y1 >= 2.0) return(0); else return(1); } else if (x1 < 5.0) { if (y1 <= x1 - 4.0) return(0); else if (y1 >= 2.0) return(0); else return(1); } else if (x1 < 6.0) { if (y1 <= 1.0) return(0); else if (y1 >= 3.0) return(0); else return(1); } else if (x1 < 7.0) { if (y1 <= x1 - 6.0) return(0); else if (y1 >= 10.0 - x1) return(0); else return(1); } else { if (y1 <= 2.0) return(0); else if (y1 >= 3.0) return(0); else return(1); } } case (D_TOKA_PRIME): { // x1 = vabs(x); if (x + MU > 0.0) x1 = x; else x1 = -2.0*MU - x; condition = xy_in_triangle_tvertex(x1, y, polyline[0], polyline[1], polyline[2]); condition += xy_in_triangle_tvertex(x1, y, polyline[0], polyline[2], polyline[3]); condition += xy_in_triangle_tvertex(x1, y, polyline[i], polyline[3], polyline[4]); for (i=3; i<42; i++) condition += xy_in_triangle_tvertex(x1, y, polyline[i], polyline[43], polyline[i+1]); condition += xy_in_triangle_tvertex(x1, y, polyline[42], polyline[43], polyline[3]); return(condition >= 1); } case (D_ISOSPECTRAL): { /* 1st triangle */ condition = xy_in_triangle_tvertex(x, y, polyline[0], polyline[1], polyline[2]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[4], polyline[1]); condition += xy_in_triangle_tvertex(x, y, polyline[1], polyline[5], polyline[2]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[2], polyline[3]); condition += xy_in_triangle_tvertex(x, y, polyline[1], polyline[4], polyline[7]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[5], polyline[8]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[3], polyline[6]); /* 2nd triangle */ condition += xy_in_triangle_tvertex(x, y, polyline[9], polyline[10], polyline[11]); condition += xy_in_triangle_tvertex(x, y, polyline[9], polyline[13], polyline[10]); condition += xy_in_triangle_tvertex(x, y, polyline[10], polyline[14], polyline[11]); condition += xy_in_triangle_tvertex(x, y, polyline[9], polyline[11], polyline[12]); condition += xy_in_triangle_tvertex(x, y, polyline[9], polyline[16], polyline[13]); condition += xy_in_triangle_tvertex(x, y, polyline[10], polyline[17], polyline[14]); condition += xy_in_triangle_tvertex(x, y, polyline[11], polyline[15], polyline[12]); return(condition >= 1); } case (D_HOMOPHONIC): { /* conditions could be summarised in larger triangles, but this is to keep */ /* the option of using triangles with other angles than 30-60-90 */ /* 1st triangle */ condition = xy_in_triangle_tvertex(x, y, polyline[2], polyline[0], polyline[1]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[1], polyline[3]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[21], polyline[1]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[10], polyline[21]); condition += xy_in_triangle_tvertex(x, y, polyline[10], polyline[11], polyline[21]); condition += xy_in_triangle_tvertex(x, y, polyline[11], polyline[13], polyline[21]); condition += xy_in_triangle_tvertex(x, y, polyline[11], polyline[12], polyline[13]); condition += xy_in_triangle_tvertex(x, y, polyline[13], polyline[14], polyline[21]); condition += xy_in_triangle_tvertex(x, y, polyline[14], polyline[20], polyline[21]); condition += xy_in_triangle_tvertex(x, y, polyline[14], polyline[15], polyline[20]); condition += xy_in_triangle_tvertex(x, y, polyline[15], polyline[19], polyline[20]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[4], polyline[5]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[5], polyline[7]); condition += xy_in_triangle_tvertex(x, y, polyline[5], polyline[6], polyline[7]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[7], polyline[8]); condition += xy_in_triangle_tvertex(x, y, polyline[2], polyline[8], polyline[0]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[8], polyline[9]); condition += xy_in_triangle_tvertex(x, y, polyline[0], polyline[9], polyline[10]); condition += xy_in_triangle_tvertex(x, y, polyline[15], polyline[16], polyline[19]); condition += xy_in_triangle_tvertex(x, y, polyline[16], polyline[17], polyline[18]); condition += xy_in_triangle_tvertex(x, y, polyline[16], polyline[18], polyline[19]); /* 2nd triangle */ condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+0], polyline[22+1]); condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+1], polyline[22+3]); condition += xy_in_triangle_tvertex(x, y, polyline[22+0], polyline[22+21], polyline[22+1]); condition += xy_in_triangle_tvertex(x, y, polyline[22+0], polyline[22+10], polyline[22+21]); condition += xy_in_triangle_tvertex(x, y, polyline[22+10], polyline[22+11], polyline[22+21]); condition += xy_in_triangle_tvertex(x, y, polyline[22+11], polyline[22+13], polyline[22+21]); condition += xy_in_triangle_tvertex(x, y, polyline[22+11], polyline[22+12], polyline[22+13]); condition += xy_in_triangle_tvertex(x, y, polyline[22+13], polyline[22+14], polyline[22+21]); condition += xy_in_triangle_tvertex(x, y, polyline[22+14], polyline[22+20], polyline[22+21]); condition += xy_in_triangle_tvertex(x, y, polyline[22+14], polyline[22+15], polyline[22+20]); condition += xy_in_triangle_tvertex(x, y, polyline[22+15], polyline[22+19], polyline[22+20]); condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+3], polyline[22+5]); condition += xy_in_triangle_tvertex(x, y, polyline[22+3], polyline[22+4], polyline[22+5]); condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+5], polyline[22+6]); condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+6], polyline[22+8]); condition += xy_in_triangle_tvertex(x, y, polyline[22+2], polyline[22+8], polyline[22+9]); condition += xy_in_triangle_tvertex(x, y, polyline[22+6], polyline[22+7], polyline[22+8]); condition += xy_in_triangle_tvertex(x, y, polyline[22+11], polyline[22+10], polyline[22+16]); condition += xy_in_triangle_tvertex(x, y, polyline[22+11], polyline[22+16], polyline[22+18]); condition += xy_in_triangle_tvertex(x, y, polyline[22+11], polyline[22+18], polyline[22+12]); condition += xy_in_triangle_tvertex(x, y, polyline[22+16], polyline[22+17], polyline[22+18]); return(condition >= 1); } case (D_CIRCLES): { for (i = 0; i < ncircles; i++) if (circles[i].active) { x1 = circles[i].xc; y1 = circles[i].yc; r2 = circles[i].radius*circles[i].radius; if ((x-x1)*(x-x1) + (y-y1)*(y-y1) < r2) return(0); } return(1); } case (D_CIRCLES_IN_RECT): /* returns 2 inside circles, 0 outside rectangle */ { for (i = 0; i < ncircles; i++) if (circles[i].active) { x1 = circles[i].xc; y1 = circles[i].yc; r2 = circles[i].radius*circles[i].radius; if ((x-x1)*(x-x1) + (y-y1)*(y-y1) < r2) return(2); } if ((vabs(x) >= LAMBDA)||(vabs(y) >= 1.0)) return(0); else return(1); } case (D_POLYGONS): { for (i = 0; i < ncircles; i++) if ((polygons[i].active)&&(in_tpolygon(x, y, polygons[i]))) return(0); return(1); } case (D_VONKOCH): { condition = xy_in_triangle_tvertex(x, y, polyline[0], polyline[npolyline/3], polyline[2*npolyline/3]); m = 1; k = 1; for (i = 0; i < MDEPTH; i++) { m = m*4; for (j = 0; j < npolyline/m; j++) condition += xy_in_triangle_tvertex(x, y, polyline[j*m + k], polyline[j*m + 2*k], polyline[j*m + 3*k]); k = k*4; } return(condition >= 1); } case (D_STAR): { condition = xy_in_triangle_tvertex(x, y, polyline[NPOLY], polyline[NPOLY-1], polyline[0]); for (i = 0; i < NPOLY-1; i++) condition += xy_in_triangle_tvertex(x, y, polyline[NPOLY], polyline[i], polyline[i+1]); return(condition >= 1); } case (D_MENGER): { x1 = 0.5*(x+1.0); y1 = 0.5*(y+1.0); for (k=0; k l2)&&(r2 < 1.0)) return(1); else if (r2mu <= l2) return(2); else return (0); } case (D_MENGER_HEATED): { if ((vabs(x) >= 1.0)||(vabs(y) >= 1.0)) return(0); else { x1 = 0.5*(x+1.0); y1 = 0.5*(y+1.0); for (k=0; k 1.2) return(2); else return(1); } case (D_MANDELBROT_CIRCLE): { u = 0.0; v = 0.0; i = 0; while ((i 1.2) return(2); // else if ((vabs(x) > XMAX - 0.01)||(vabs(y) > YMAX - 0.01)) return(2); else return(1); } case (D_VONKOCH_HEATED): { if (x*x + y*y > LAMBDA*LAMBDA) return(2); x1 = x; y1 = y; condition = xy_in_triangle_tvertex(x1, y1, polyline[0], polyline[npolyline/3], polyline[2*npolyline/3]); m = 1; k = 1; for (i = 0; i < MDEPTH; i++) { m = m*4; for (j = 0; j < npolyline/m; j++) condition += xy_in_triangle_tvertex(x1, y1, polyline[j*m + k], polyline[j*m + 2*k], polyline[j*m + 3*k]); k = k*4; } if (condition > 0) return(0); else return(1); } default: { printf("Function ij_in_billiard not defined for this billiard \n"); return(0); } } } int ij_in_billiard(int i, int j) /* returns 1 if (i,j) represents a point in the billiard */ { double xy[2]; ij_to_xy(i, j, xy); return(xy_in_billiard(xy[0], xy[1])); } void tvertex_lineto(t_vertex z) /* draws boundary segments of isospectral billiard */ { glVertex2d(z.posi, z.posj); } void draw_billiard() /* draws the billiard boundary */ { double x0, x, y, x1, y1, dx, dy, phi, r = 0.01, pos[2], pos1[2], alpha, dphi, omega, z, l, width, a, b, c, ymax; int i, j, k, k1, k2, mr2; static int first = 1, nsides; if (BLACK) glColor3f(1.0, 1.0, 1.0); else glColor3f(0.0, 0.0, 0.0); glLineWidth(BOUNDARY_WIDTH); glEnable(GL_LINE_SMOOTH); switch (B_DOMAIN) { case (D_RECTANGLE): { glBegin(GL_LINE_LOOP); xy_to_pos(LAMBDA, -1.0, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(LAMBDA, 1.0, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-LAMBDA, 1.0, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-LAMBDA, -1.0, pos); glVertex2d(pos[0], pos[1]); 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); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); /* draw foci */ if (FOCI) { glColor3f(0.3, 0.3, 0.3); x0 = sqrt(LAMBDA*LAMBDA-1.0); glLineWidth(2); glEnable(GL_LINE_SMOOTH); 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); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i=0; i<=NSEG; i++) { phi = PID + (double)i*PI/(double)NSEG; x = -0.5*LAMBDA + cos(phi); y = sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd(); break; } case (D_SINAI): { draw_circle(0.0, 0.0, LAMBDA, NSEG); 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); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i=0; i<=NSEG; i++) { phi = alpha - PID + (double)i*dphi; x = -LAMBDA + r*cos(phi); y = LAMBDA + r*sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i=0; i<=NSEG; i++) { phi = alpha + PI + (double)i*dphi; x = LAMBDA + r*cos(phi); y = LAMBDA + r*sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i=0; i<=NSEG; i++) { phi = alpha + PID + (double)i*dphi; x = LAMBDA + r*cos(phi); y = -LAMBDA + r*sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd(); break; } case (D_TRIANGLE): { glBegin(GL_LINE_LOOP); xy_to_pos(-LAMBDA, -1.0, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(LAMBDA, -1.0, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-LAMBDA, 1.0, pos); glVertex2d(pos[0], pos[1]); glEnd(); break; } case (D_FLAT): { glBegin(GL_LINE_LOOP); xy_to_pos(XMIN, -LAMBDA, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(XMAX, -LAMBDA, pos); glVertex2d(pos[0], pos[1]); glEnd(); break; } case (D_ANNULUS): { draw_circle(0.0, 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); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); break; } case (D_YOUNG): { glBegin(GL_LINE_STRIP); xy_to_pos(-MU, YMIN, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-MU, -LAMBDA-MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, -LAMBDA-MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, YMIN, pos); glVertex2d(pos[0], pos[1]); glEnd(); glBegin(GL_LINE_STRIP); xy_to_pos(-MU, YMAX, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-MU, LAMBDA+MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, LAMBDA+MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, YMAX, pos); glVertex2d(pos[0], pos[1]); glEnd(); glBegin(GL_LINE_LOOP); xy_to_pos(-MU, -LAMBDA+MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(-MU, LAMBDA-MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, LAMBDA-MU, pos); glVertex2d(pos[0], pos[1]); xy_to_pos(MU, -LAMBDA+MU, pos); glVertex2d(pos[0], pos[1]); glEnd(); break; } case (D_GRATING): { k1 = -(int)(-YMIN/LAMBDA); k2 = (int)(YMAX/LAMBDA); for (i=k1; i<= k2; i++) { z = (double)i*LAMBDA; draw_circle(0.0, z, MU, NSEG); } break; } case (D_EHRENFEST): { alpha = asin(MU/LAMBDA); x0 = 1.0 - sqrt(LAMBDA*LAMBDA - MU*MU); dphi = 2.0*(PI-alpha)/((double)NSEG); glBegin(GL_LINE_LOOP); for (i=0; i<=NSEG; i++) { phi = -PI + alpha + (double)i*dphi; x = 1.0 + LAMBDA*cos(phi); y = LAMBDA*sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i=0; i<=NSEG; i++) { phi = alpha + (double)i*dphi; x = -1.0 + LAMBDA*cos(phi); y = LAMBDA*sin(phi); xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); break; } case (D_DISK_GRID): { glLineWidth(2); for (i = -NGRIDX/2; i < NGRIDX/2; i++) for (j = 0; j < NGRIDY; j++) { dy = (YMAX - YMIN)/((double)NGRIDY); dx = dy*0.5*sqrt(3.0); x1 = ((double)i + 0.5)*dy; y1 = YMIN + ((double)j + 0.5)*dy; draw_circle(x1, y1, MU, NSEG); } break; } case (D_DISK_HEX): { glLineWidth(2); for (i = -NGRIDX/2; i < NGRIDX/2; i++) for (j = -1; j < NGRIDY; j++) { dy = (YMAX - YMIN)/((double)NGRIDY); x1 = ((double)i + 0.5)*dy; y1 = YMIN + ((double)j + 0.5)*dy; if ((i+NGRIDX)%2 == 1) y1 += 0.5*dy; draw_circle(x1, y1, MU, NSEG); } break; } case (D_PARABOLA): { dy = (YMAX - YMIN)/(double)NSEG; glBegin(GL_LINE_STRIP); for (i = 0; i < NSEG+1; i++) { y = YMIN + dy*(double)i; x = 0.25*y*y/LAMBDA - LAMBDA; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); if (FOCI) { glColor3f(0.3, 0.3, 0.3); draw_circle(0.0, 0.0, r, NSEG); } break; } case (D_TWO_PARABOLAS): { dy = 3.0*MU/(double)NSEG; width = 0.25*MU; if (width > 0.2) width = 0.2; glBegin(GL_LINE_LOOP); for (i = 0; i < NSEG+1; i++) { y = -1.5*MU + dy*(double)i; x = 0.25*y*y/MU - MU - LAMBDA; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i = 0; i < NSEG+1; i++) { y = 1.5*MU - dy*(double)i; x = 0.25*y*y/MU - (MU + width) - LAMBDA; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); glBegin(GL_LINE_LOOP); for (i = 0; i < NSEG+1; i++) { y = -1.5*MU + dy*(double)i; x = LAMBDA + MU - 0.25*y*y/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i = 0; i < NSEG+1; i++) { y = 1.5*MU - dy*(double)i; x = LAMBDA + (MU + width) - 0.25*y*y/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); if (FOCI) { glColor3f(0.3, 0.3, 0.3); draw_circle(-LAMBDA, 0.0, r, NSEG); draw_circle(LAMBDA, 0.0, r, NSEG); } break; } case (D_FOUR_PARABOLAS): { x1 = 2.0*(sqrt(MU*(2.0*MU + LAMBDA)) - MU); dy = 2.0*x1/(double)NSEG; glBegin(GL_LINE_LOOP); for (i = 0; i < NSEG+1; i++) { y = -x1 + dy*(double)i; x = MU + LAMBDA - 0.25*y*y/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i = 0; i < NSEG+1; i++) { x = x1 - dy*(double)i; y = MU + LAMBDA - 0.25*x*x/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i = 0; i < NSEG+1; i++) { y = x1 - dy*(double)i; x = -MU - LAMBDA + 0.25*y*y/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } for (i = 0; i < NSEG+1; i++) { x = -x1 + dy*(double)i; y = -MU - LAMBDA + 0.25*x*x/MU; xy_to_pos(x, y, pos); glVertex2d(pos[0], pos[1]); } glEnd (); if (FOCI) { glColor3f(0.3, 0.3, 0.3); draw_circle(-LAMBDA, 0.0, r, NSEG); draw_circle(LAMBDA, 0.0, r, NSEG); draw_circle(0.0, -LAMBDA, r, NSEG); draw_circle(0.0, LAMBDA, r, NSEG); } break; } case (D_POLY_PARABOLAS): { omega = PI/((double)NPOLY); a = 0.25/MU; b = 1.0/tan(omega); c = LAMBDA + MU; ymax = (-b + sqrt(b*b + 4.0*a*c))/(2.0*a); dy = 2.0*ymax/(double)NSEG; // printf("a = %.3lg, b = %.3lg, ymax = %.3lg\n", a, b,ymax); glBegin(GL_LINE_LOOP); for (k=0; k45; i--) tvertex_lineto(polyline[i]); glEnd(); /* inner lines */ // glLineWidth(BOUNDARY_WIDTH/2); glLineWidth(1); glColor3f(0.75, 0.75, 0.75); glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[3]); tvertex_lineto(polyline[4]); glEnd(); glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[44]); tvertex_lineto(polyline[45]); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[46]); tvertex_lineto(polyline[45]); glEnd(); for (i=3; i<43; i++) { glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[i]); tvertex_lineto(polyline[43]); glEnd(); glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[i+42]); tvertex_lineto(polyline[85]); glEnd(); } break; } case (D_ISOSPECTRAL): { /* 1st triangle */ glBegin(GL_LINE_LOOP); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[4]); tvertex_lineto(polyline[7]); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[5]); tvertex_lineto(polyline[8]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[3]); tvertex_lineto(polyline[6]); glEnd(); /* inner lines */ glBegin(GL_LINE_LOOP); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[0]); tvertex_lineto(polyline[3]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[5]); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[4]); glEnd(); /* 2nd triangle */ glBegin(GL_LINE_LOOP); tvertex_lineto( polyline[9]); tvertex_lineto(polyline[16]); tvertex_lineto(polyline[13]); tvertex_lineto(polyline[10]); tvertex_lineto(polyline[17]); tvertex_lineto(polyline[14]); tvertex_lineto(polyline[11]); tvertex_lineto(polyline[15]); tvertex_lineto(polyline[12]); glEnd(); /* inner lines */ glBegin(GL_LINE_LOOP); tvertex_lineto( polyline[9]); tvertex_lineto(polyline[10]); tvertex_lineto(polyline[11]); tvertex_lineto( polyline[9]); tvertex_lineto(polyline[13]); tvertex_lineto(polyline[10]); tvertex_lineto(polyline[14]); tvertex_lineto(polyline[11]); tvertex_lineto(polyline[12]); glEnd(); break; } case (D_HOMOPHONIC): { /* 1st triangle */ glBegin(GL_LINE_LOOP); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[3]); tvertex_lineto(polyline[4]); tvertex_lineto(polyline[5]); tvertex_lineto(polyline[6]); tvertex_lineto(polyline[8]); tvertex_lineto(polyline[9]); tvertex_lineto(polyline[10]); tvertex_lineto(polyline[12]); tvertex_lineto(polyline[13]); tvertex_lineto(polyline[15]); tvertex_lineto(polyline[16]); tvertex_lineto(polyline[17]); tvertex_lineto(polyline[18]); tvertex_lineto(polyline[20]); glEnd(); /* inner lines */ glLineWidth(BOUNDARY_WIDTH/2); glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[9]); tvertex_lineto(polyline[1]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[5]); tvertex_lineto(polyline[7]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[8]); tvertex_lineto(polyline[21]); tvertex_lineto(polyline[10]); tvertex_lineto(polyline[2]); tvertex_lineto(polyline[21]); tvertex_lineto(polyline[11]); tvertex_lineto(polyline[13]); tvertex_lineto(polyline[21]); tvertex_lineto(polyline[14]); tvertex_lineto(polyline[20]); tvertex_lineto(polyline[15]); tvertex_lineto(polyline[19]); tvertex_lineto(polyline[16]); tvertex_lineto(polyline[18]); glEnd(); /* 2nd triangle */ glLineWidth(BOUNDARY_WIDTH); glBegin(GL_LINE_LOOP); tvertex_lineto(polyline[22+10]); tvertex_lineto(polyline[22+16]); tvertex_lineto(polyline[22+17]); tvertex_lineto(polyline[22+18]); tvertex_lineto(polyline[22+12]); tvertex_lineto(polyline[22+13]); tvertex_lineto(polyline[22+15]); tvertex_lineto(polyline[22+19]); tvertex_lineto(polyline[22+20]); tvertex_lineto(polyline[22+1]); tvertex_lineto(polyline[22+4]); tvertex_lineto(polyline[22+5]); tvertex_lineto(polyline[22+7]); tvertex_lineto(polyline[22+8]); tvertex_lineto(polyline[22+9]); glEnd(); /* inner lines */ glLineWidth(BOUNDARY_WIDTH/2); glBegin(GL_LINE_STRIP); tvertex_lineto(polyline[22+2]); tvertex_lineto(polyline[22+6]); tvertex_lineto(polyline[22+8]); tvertex_lineto(polyline[22+2]); tvertex_lineto(polyline[22+5]); tvertex_lineto(polyline[22+3]); tvertex_lineto(polyline[22+2]); tvertex_lineto(polyline[22+1]); tvertex_lineto(polyline[22+0]); tvertex_lineto(polyline[22+21]); tvertex_lineto(polyline[22+18]); tvertex_lineto(polyline[22+16]); tvertex_lineto(polyline[22+13]); tvertex_lineto(polyline[22+21]); tvertex_lineto(polyline[22+10]); tvertex_lineto(polyline[22+12]); tvertex_lineto(polyline[22+21]); tvertex_lineto(polyline[22+14]); tvertex_lineto(polyline[22+20]); tvertex_lineto(polyline[22+15]); glEnd(); break; } case (D_VONKOCH): { glLineWidth(BOUNDARY_WIDTH/2); glBegin(GL_LINE_LOOP); for (i=0; i 0) { glLineWidth(2); x = 1.0/((double)MRATIO); draw_rectangle(x, x, -x, -x); } /* level 2 */ if (MDEPTH > 1) { glLineWidth(1); mr2 = MRATIO*MRATIO; l = 2.0/((double)mr2); for (i=0; i 2) { glLineWidth(1); l = 2.0/((double)(mr2*MRATIO)); for (i=0; i 0) { glLineWidth(2); x = 1.0/((double)MRATIO); draw_rotated_rectangle(x, x, -x, -x); } /* level 2 */ if (MDEPTH > 1) { glLineWidth(1); mr2 = MRATIO*MRATIO; l = 2.0/((double)mr2); for (i=0; i 2) { glLineWidth(1); l = 2.0/((double)(mr2*MRATIO)); for (i=0; i 0) { glLineWidth(2); x = 1.0/((double)MRATIO); draw_rectangle(x, x, -x, -x); } /* level 2 */ if (MDEPTH > 1) { glLineWidth(1); mr2 = MRATIO*MRATIO; l = 2.0/((double)mr2); for (i=0; i 2) { glLineWidth(1); l = 2.0/((double)(mr2*MRATIO)); for (i=0; i 0) { glLineWidth(2); x = 1.0/((double)MRATIO); draw_rectangle(x, x, -x, -x); } /* level 2 */ if (MDEPTH > 1) { glLineWidth(1); mr2 = MRATIO*MRATIO; l = 2.0/((double)mr2); for (i=0; i 2) { glLineWidth(1); l = 2.0/((double)(mr2*MRATIO)); for (i=0; i= COL_TURBO) color_scheme_asym(COLOR_SCHEME, value, 1.0, 1, rgb); else color_scheme(COLOR_SCHEME, value, 1.0, 1, rgb); break; } case (P_MEAN_ENERGY): { value = dy_e*(double)(j - jmin)*100.0/E_SCALE; if (COLOR_PALETTE >= COL_TURBO) color_scheme_asym(COLOR_SCHEME, value, 1.0, 1, rgb); else color_scheme(COLOR_SCHEME, value, 1.0, 1, rgb); break; } case (P_LOG_ENERGY): { value = LOG_SCALE*log(dy_e*(double)(j - jmin)*100.0/E_SCALE); color_scheme(COLOR_SCHEME, value, 1.0, 1, rgb); break; } case (P_LOG_MEAN_ENERGY): { value = LOG_SCALE*log(dy_e*(double)(j - jmin)*100.0/E_SCALE); color_scheme(COLOR_SCHEME, value, 1.0, 1, rgb); break; } case (P_PHASE): { value = min + 1.0*dy*(double)(j - jmin); color_scheme(COLOR_SCHEME, value, 1.0, 1, rgb); break; } } glColor3f(rgb[0], rgb[1], rgb[2]); if (ROTATE_COLOR_SCHEME) { glVertex2i(j, imin); glVertex2i(j, imax); glVertex2i(j+1, imax); glVertex2i(j+1, imin); } else { glVertex2i(imin, j); glVertex2i(imax, j); glVertex2i(imax, j+1); glVertex2i(imin, j+1); } } glEnd (); glColor3f(1.0, 1.0, 1.0); glLineWidth(BOUNDARY_WIDTH); draw_rectangle(x1, y1, x2, y2); }