/* some graphic routines moved here from su_lj.c */ #include "colors_waves.c" 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); } /*********************/ /* some basic math */ /*********************/ double vabs(double x) /* absolute value */ { double res; if (x<0.0) res = -x; else res = x; return(res); } double ipow(double x, int n) { double y; int i; y = x; for (i=1; i= 1 || S == 0); X = V1 * sqrt(-2 * log(S) / S); } else X = V2 * sqrt(-2 * log(S) / S); phase = 1 - phase; return X; } 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); } double dist_sphere(double phi1, double theta1, double phi2, double theta2) /* returns angle between points given in spherical coordinates */ { double dist; dist = sin(theta1)*sin(theta2)*cos(phi1 - phi2); dist += cos(theta1)*cos(theta2); return(acos(dist)); } void compute_midpoint_sphere(double phi1, double theta1, double phi2, double theta2, double *phi, double *theta) /* compute midpoint between two points on the sphere */ { double x1, y1, z1, x2, y2, z2, x3, y3, z3, r; x1 = cos(phi1)*sin(theta1); y1 = sin(phi1)*sin(theta1); z1 = -cos(theta1); x2 = cos(phi2)*sin(theta2); y2 = sin(phi2)*sin(theta2); z2 = -cos(theta2); x3 = x1 + x2; y3 = y1 + y2; z3 = z1 + z2; r = sqrt(x3*x3 + y3*y3 + z3*z3); *theta = acos(-z3/r); *phi = argument(x3, y3); if (*phi < 0.0) *phi += DPI; } void compute_convex_combination_sphere(double phi1, double theta1, double phi2, double theta2, double *phia, double *thetaa, double *phib, double *thetab, double lambda) /* compute convex combination of two points on the sphere */ { double x1, y1, z1, x2, y2, z2, x3, y3, z3, r, lam1; lam1 = 1.0 - lambda; x1 = cos(phi1)*sin(theta1); y1 = sin(phi1)*sin(theta1); z1 = -cos(theta1); x2 = cos(phi2)*sin(theta2); y2 = sin(phi2)*sin(theta2); z2 = -cos(theta2); x3 = lambda*x1 + lam1*x2; y3 = lambda*y1 + lam1*y2; z3 = lambda*z1 + lam1*z2; r = sqrt(x3*x3 + y3*y3 + z3*z3); *thetaa = acos(-z3/r); *phia = argument(x3, y3); if (*phia < 0.0) *phia += DPI; x3 = lam1*x1 + lambda*x2; y3 = lam1*y1 + lambda*y2; z3 = lam1*z1 + lambda*z2; r = sqrt(x3*x3 + y3*y3 + z3*z3); *thetab = acos(-z3/r); *phib = argument(x3, y3); if (*phib < 0.0) *phib += DPI; } 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 radius 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 7) nnbg = 7; switch(nnbg){ case (7): return(340.0); case (6): return(310.0); case (5): return(260.0); case (4): return(200.0); case (3): return(140.0); case (2): return(100.0); case (1): return(70.0); default: return(30.0); } } double partner_color(int np) { switch(np){ case (0): return(340.0); case (1): return(260.0); case (2): return(210.0); case (3): return(140.0); case (4): return(70.0); default: return(20.0); // case (0): return(70.0); // case (1): return(200.0); // case (2): return(280.0); // case (3): return(140.0); // case (4): return(320.0); // default: return(20.0); } } double type_hue(int type) { int hue; double t2; static double b, hmax; static int first = 1; if (first) { hmax = 360.0; b = 16.0*(hmax - HUE_TYPE3); first = 0; } // if ((RD_REACTION == CHEM_CATALYTIC_A2D)&&(type == 4)) return(HUE_TYPE3); if ((RD_REACTION == CHEM_ABDACBE)&&(type == 4)) return(HUE_TYPE3); if ((RD_REACTION == CHEM_ABDACBE)&&(type == 5)) return(280.0); switch (type) { case (0): return(HUE_TYPE0); case (1): return(HUE_TYPE1); case (2): return(HUE_TYPE2); case (3): return(HUE_TYPE3); case (4): return(HUE_TYPE4); case (5): return(HUE_TYPE5); case (6): return(HUE_TYPE6); case (7): { if (RD_REACTION == CHEM_BZ) return(HUE_TYPE2); else return(HUE_TYPE7); } case (8): return(HUE_TYPE8); default: { if (RD_REACTION == CHEM_BZ) { if (type == 7) return(HUE_TYPE2); if (type == 8) type = 5; } else if ((RD_REACTION == CHEM_BRUSSELATOR)&&(type >= 5)) return(70.0); t2 = (double)(type*type); hue = (hmax*t2 - b)/t2; return(hue); } } } void compute_particle_colors(t_particle particle, t_cluster cluster[NMAXCIRCLES], int plot, double rgb[3], double rgbx[3], double rgby[3], t_particle other_particle[NMAXCIRCLES]) { double ej, angle, hue, huex, huey, lum, x, y, ccluster, xg, yg, vx, vy, amoment, dist, density, dx, dy; int i, k, p, q, cl, mol[2], mass[2]; switch (plot) { case (P_KINETIC): { ej = particle.energy; if (ej > 0.0) { hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*ej/PARTICLE_EMAX; if (hue > ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; } break; } case (P_NEIGHBOURS): { hue = neighbour_color(particle.neighb); break; } case (P_BONDS): { hue = neighbour_color(particle.neighb); break; } case (P_ANGLE): { angle = particle.angle; hue = angle*particle.spin_freq/DPI; hue -= (double)((int)hue); huex = (DPI - angle)*particle.spin_freq/DPI; huex -= (double)((int)huex); angle = PI - angle; if (angle < 0.0) angle += DPI; huey = angle*particle.spin_freq/DPI; huey -= (double)((int)huey); hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(hue); huex = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(huex); huey = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(huey); break; } case (P_TYPE): { hue = type_hue(particle.type); break; } case (P_DIRECTION): { hue = argument(particle.vx, particle.vy); if (hue > DPI) hue -= DPI; if (hue < 0.0) hue += DPI; hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(hue)/DPI; break; } case (P_DIRECT_ENERGY): { hue = argument(particle.vx, particle.vy); if (hue > DPI) hue -= DPI; if (hue < 0.0) hue += DPI; hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(hue)/DPI; if (particle.energy < 0.1*PARTICLE_EMAX) lum = 10.0*particle.energy/PARTICLE_EMAX; else lum = 1.0; break; } case (P_ANGULAR_SPEED): { hue = 160.0*(1.0 + tanh(SLOPE*particle.omega)); // printf("omega = %.3lg, hue = %.3lg\n", particle[j].omega, hue); break; } case (P_DIFF_NEIGHB): { hue = (double)(particle.diff_neighb+1)/(double)(particle.neighb+1); // hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*hue; // hue = 180.0*(1.0 + hue); hue = 20.0 + 320.0*hue; break; } case (P_THERMOSTAT): { if (particle.thermostat) hue = 30.0; else hue = 270.0; break; } case (P_INITIAL_POS): { hue = particle.color_hue; break; } case (P_NUMBER): { hue = particle.color_hue; break; } case (P_EMEAN): { ej = particle.emean; if (ej > 0.0) { hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*ej/PARTICLE_EMAX; if (hue > ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; } break; } case (P_EMEAN_DENSITY): { ej = particle.emean; cl = particle.cluster; ej *= PARTICLE_MASS/cluster[cl].mass; if (ej > 0.0) { hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*ej/PARTICLE_EMAX; if (hue > ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; } break; } case (P_LOG_EMEAN): { ej = particle.emean; if (ej > 0.0) { ej = log(ej/PARTICLE_EMIN)/log(PARTICLE_EMAX/PARTICLE_EMIN); if (ej < 0.0) ej = 0.0; else if (ej > 1.0) ej = 1.0; hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*ej; // if (hue > ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; // if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; } break; } case (P_DIRECT_EMEAN): { hue = particle.dirmean + COLOR_HUESHIFT*PI; // printf("dirmean = %.3lg\n", particle.dirmean); if (hue > DPI) hue -= DPI; if (hue < 0.0) hue += DPI; hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(hue)/DPI; ej = particle.emean; if (ej < 0.5*PARTICLE_EMAX) lum = 2.0*ej/PARTICLE_EMAX; else lum = 1.0; break; } case (P_NOPARTICLE): { hue = 0.0; lum = 1.0; break; } case (P_NPARTNERS): { hue = partner_color(particle.npartners); break; } case (P_CHARGE): { hue = (-CHARGE_HUE_RANGE*tanh(BG_CHARGE_SLOPE*particle.charge)+1.0)*180.0; break; } case (P_MOL_ANGLE): { p = particle.p0; q = particle.p1; x = other_particle[q].xc - other_particle[p].xc; y = other_particle[q].yc - other_particle[p].yc; /* deal with periodic boundary conditions */ if (x > 0.5*(XMAX - XMIN)) x -= (XMAX - XMIN); else if (x < 0.5*(XMIN - XMAX)) x += (XMAX - XMIN); if (y > 0.5*(YMAX - YMIN)) y -= (YMAX - YMIN); else if (y < 0.5*(YMIN - YMAX)) y += (YMAX - YMIN); angle = (argument(x, y) + COLOR_HUESHIFT*PI)*MOL_ANGLE_FACTOR; // printf("Particle p = %i, mol_angle = %i\n", p, particle.mol_angle); // angle = argument(x, y)*(double)particle.mol_angle; // angle = argument(x, y)*(double)(other_particle[particle.p0].npartners); while (angle > DPI) angle -= DPI; while (angle < 0.0) angle += DPI; hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(angle)/DPI; break; } case (P_CLUSTER): { // cluster = (double)(particle.cluster)/(double)(ncircles); ccluster = (double)(particle.cluster_color)/(double)(ncircles); ccluster -= (double)((int)ccluster); hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*ccluster; break; } case (P_CLUSTER_SIZE): { // cluster = (double)(particle.cluster)/(double)(ncircles); ccluster = 1.0 - 5.0/((double)particle.cluster_size + 4.0); hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*ccluster; break; } case (P_CLUSTER_SELECTED): { cl = particle.cluster; if (cluster[cl].selected) hue = COLOR_HUE_CLUSTER_SELECTED; else hue = COLOR_HUE_CLUSTER_NOT_SELECTED; break; } case (P_COLLISION): { hue = (double)particle.collision; if (hue > 0.0) hue = atan(0.25*(0.03*hue + 1.0))/PID; // { // hue += 10.0; // hue *= 1.0/(40.0 + hue); // } hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*hue; break; } case (P_RADIUS): { // hue = atan(5.0*(particle.radius/MU - 0.75))/PID; hue = (particle.radius/MU - RANDOM_RADIUS_MIN)/RANDOM_RADIUS_RANGE; // hue = 0.5*(hue + 1.0); hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*hue; break; } case (P_MOL_ANG_MOMENTUM): { /* move this computation to evolve_clusters? */ mol[0] = other_particle[particle.p0].cluster; mol[1] = other_particle[particle.p1].cluster; mass[0] = 1.0/cluster[mol[0]].mass_inv; mass[1] = 1.0/cluster[mol[1]].mass_inv; xg = mass[0]*cluster[mol[0]].xg + mass[1]*cluster[mol[1]].xg; yg = mass[0]*cluster[mol[0]].yg + mass[1]*cluster[mol[1]].yg; amoment = 0.999*cluster[mol[0]].lmean; for (i=0; i<2; i++) { q = mol[i]; x = cluster[q].xg - xg; y = cluster[q].yg - yg; if (x > 0.5*(XMAX - XMIN)) x -= (XMAX - XMIN); else if (x < 0.5*(XMIN - XMAX)) x += (XMAX - XMIN); if (y > 0.5*(YMAX - YMIN)) y -= (YMAX - YMIN); else if (y < 0.5*(YMIN - YMAX)) y += (YMAX - YMIN); vx = cluster[q].vx; vy = cluster[q].vy; amoment += 0.001*(x*vy - y*vx)*mass[i]; // printf("(x,y) = (%.3lg, %.3lg), (vx, vy) = (%.3lg, %.3lg)\n", x, y, vx, vy); } for (i=0; i<2; i++) cluster[mol[i]].lmean = amoment; // printf("cluster %i: p0 = %i, p1 = %i, L = %.3lg\n", cl, particle.p0, particle.p1, amoment); hue = 180.0*(1.0 + tanh(cluster[mol[0]].lmean/PARTICLE_LMAX)); // printf("L/LMAX = %.3lg, hue = %.3lg\n", amoment/PARTICLE_LMAX, hue); break; } case (P_DENSITY): { density = 0.0; for (i=0; i ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; break; } } switch (plot) { case (P_KINETIC): { // hsl_to_rgb_turbo(hue, 0.9, 0.5, rgb); // hsl_to_rgb_turbo(hue, 0.9, 0.5, rgbx); // hsl_to_rgb_turbo(hue, 0.9, 0.5, rgby); hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_EKIN); break; } case (P_BONDS): { hsl_to_rgb_turbo(hue, 0.9, 0.5, rgb); hsl_to_rgb_turbo(hue, 0.9, 0.5, rgbx); hsl_to_rgb_turbo(hue, 0.9, 0.5, rgby); break; } case (P_DIRECTION): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_DIRECTION); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_DIRECTION); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_DIRECTION); break; } case (P_ANGLE): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_ANGLE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_ANGLE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_ANGLE); break; } case (P_DIRECT_ENERGY): { hsl_to_rgb_twilight(hue, 0.9, 0.5, rgb); hsl_to_rgb_twilight(hue, 0.9, 0.5, rgbx); hsl_to_rgb_twilight(hue, 0.9, 0.5, rgby); for (i=0; i<3; i++) { rgb[i] *= lum; rgbx[i] *= lum; rgby[i] *= lum; } break; } case (P_DIFF_NEIGHB): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_DIFFNEIGH); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_DIFFNEIGH); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_DIFFNEIGH); // hsl_to_rgb_twilight(hue, 0.9, 0.5, rgb); // hsl_to_rgb_twilight(hue, 0.9, 0.5, rgbx); // hsl_to_rgb_twilight(hue, 0.9, 0.5, rgby); break; } case (P_INITIAL_POS): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_INITIAL_POS); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_INITIAL_POS); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_INITIAL_POS); break; } case (P_EMEAN): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_EKIN); break; } case (P_LOG_EMEAN): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_EKIN); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_EKIN); break; } case (P_DIRECT_EMEAN): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_DIRECTION); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_DIRECTION); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_DIRECTION); for (i=0; i<3; i++) { rgb[i] *= lum; rgbx[i] *= lum; rgby[i] *= lum; } break; } case (P_CHARGE): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_CHARGE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_CHARGE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_CHARGE); break; } case (P_MOL_ANGLE): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_ANGLE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_ANGLE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_ANGLE); break; } case (P_CLUSTER): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_CLUSTER); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_CLUSTER); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_CLUSTER); break; } case (P_CLUSTER_SIZE): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_CLUSTER_SIZE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_CLUSTER_SIZE); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_CLUSTER_SIZE); break; } case (P_CLUSTER_SELECTED): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_CLUSTER_SELECTED); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_CLUSTER_SELECTED); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_CLUSTER_SELECTED); break; } case (P_MOL_ANG_MOMENTUM): { hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_ANGULAR_MOMENTUM); hsl_to_rgb_palette(hue, 0.9, 0.5, rgbx, COLOR_PALETTE_ANGULAR_MOMENTUM); hsl_to_rgb_palette(hue, 0.9, 0.5, rgby, COLOR_PALETTE_ANGULAR_MOMENTUM); break; } default: { hsl_to_rgb(hue, 0.9, 0.5, rgb); hsl_to_rgb(hue, 0.9, 0.5, rgbx); hsl_to_rgb(hue, 0.9, 0.5, rgby); } } } void compute_all_particle_colors(t_particle particle[NMAXCIRCLES], t_cluster cluster[NMAXCIRCLES], int plot) /* compute the colors of all particles */ { int i, k; double rgb[3], rgbx[3], rgby[3]; for (i=0; i ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; hue = p1*oldhue + p2*hue; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); break; } case (BG_LOG_EKIN): { value = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; hue = p1*oldhue + p2*hue; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); break; } case (BG_EOBSTACLES): { value = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; hue = p1*oldhue + p2*hue; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); break; } case (BG_EKIN_OBSTACLES): { value = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q ENERGY_HUE_MIN) hue = ENERGY_HUE_MIN; if (hue < ENERGY_HUE_MAX) hue = ENERGY_HUE_MAX; hue = p1*oldhue + p2*hue; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_EKIN); break; } case (BG_DIR_OBSTACLES): { valx = 0.0; valy = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q DPI) hue -= DPI; if (hue < 0.0) hue += DPI; hue = pp1*oldhue + pp2*hue; lum = module2(valx, valy)/OBSTACLE_VMAX; if (lum > 1.0) lum = 1.0; hsl_to_rgb_palette(hue*360.0/DPI, 0.9, 0.5*lum, rgb, COLOR_PALETTE_DIRECTION); break; } case (BG_POS_OBSTACLES): { valx = 0.0; valy = 0.0; nnb = hashgrid[n].nneighb; // for (q=0; q DPI) hue -= DPI; if (hue < 0.0) hue += DPI; hue = pp1*oldhue + pp2*hue; lum = module2(valx, valy); if (lum > 1.0) lum = 1.0; // lum = 1.0; hsl_to_rgb_palette(hue*360.0/DPI, 0.9, 0.5*lum, rgb, COLOR_PALETTE_DIRECTION); break; } case (BG_FORCE): { value = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q 360.0) hue = 360.0; if (hue < 0.0) hue = 0.0; hue = p1*oldhue + p2*hue; hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_CURRENT); break; } case (BG_DIRECTION): { value = 0.0; nnb = hashgrid[n].nneighb; for (q=0; q COS_VISIBLE); } double distance_sphere(int i, int k, t_particle* particle, double *ca, double *sa) /* compute distance and direction on sphere */ { double x0, y0, z0, x1, y1, z1, x2, y2, z2, cp1, sp1, ct1, st1, cp2, sp2, ct2, st2; double cthat, sphat, cphat, dist, r, reg = 0.001; double xx0, yy0, zz0; cp1 = cos(particle[i].xc); sp1 = sin(particle[i].xc); ct1 = cos(particle[i].yc); st1 = sin(particle[i].yc); cp2 = cos(particle[k].xc); sp2 = sin(particle[k].xc); ct2 = cos(particle[k].yc); st2 = sin(particle[k].yc); x0 = cp2*st2; y0 = sp2*st2; z0 = -ct2; /* apply first rotation to particle k */ x1 = cp1*x0 + sp1*y0; y1 = -sp1*x0 + cp1*y0; /* apply second rotation to particle k */ x2 = -ct1*x1 - st1*z0; z2 = st1*x1 - ct1*z0; /* vector giving direction */ cthat = -z2; r = 1.0/sqrt(y1*y1+x2*x2); sphat = y1*r; cphat = x2*r; /* angle of vector */ *ca = -cthat*sphat; *sa = cthat*cphat; dist = acos(z2); return(dist); } double dist_point_to_particle_sphere(int i, double phi, double psi, t_particle* particle, double *ca, double *sa) /* compute distance and direction between point and particle on sphere */ /* same as distance_sphere but for a general point */ { double x0, y0, z0, x1, y1, z1, x2, y2, z2, cp1, sp1, ct1, st1, cp2, sp2, ct2, st2; double cthat, sphat, cphat, dist, r, reg = 0.001; double xx0, yy0, zz0; cp1 = cos(particle[i].xc); sp1 = sin(particle[i].xc); ct1 = cos(particle[i].yc); st1 = sin(particle[i].yc); cp2 = cos(phi); sp2 = sin(phi); ct2 = cos(psi); st2 = sin(psi); x0 = cp2*st2; y0 = sp2*st2; z0 = -ct2; /* apply first rotation to particle k */ x1 = cp1*x0 + sp1*y0; y1 = -sp1*x0 + cp1*y0; /* apply second rotation to particle k */ x2 = -ct1*x1 - st1*z0; z2 = st1*x1 - ct1*z0; /* vector giving direction */ cthat = -z2; r = 1.0/sqrt(y1*y1+x2*x2); sphat = y1*r; cphat = x2*r; /* angle of vector */ *ca = -cthat*sphat; *sa = cthat*cphat; dist = acos(z2); return(dist); } void init_3d() /* initialisation of window */ { double width, height; width = 2.0*(WINWIDTH/1760.0); height = WINHEIGHT/990.0; glLineWidth(3); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // glOrtho(-2.0, 2.0, -1.0, 1.0 , -1.0, 1.0); glOrtho(-width, width, -height, height, -1.0, 1.0); } void xyz_to_xy(double x, double y, double z, double xy_out[2]) { int i; double s, t, xinter[3]; static double n2, m2, d, sm2, sn2, v[3], h[2], plane_ratio = 0.5; static int first = 1; if ((first)||(reset_view)) { m2 = observer[0]*observer[0] + observer[1]*observer[1]; n2 = m2 + observer[2]*observer[2]; d = plane_ratio*n2; sm2 = sqrt(m2); sn2 = sqrt(n2); h[0] = observer[1]/sm2; h[1] = -observer[0]/sm2; v[0] = -observer[0]*observer[2]/(sn2*sm2); v[1] = -observer[1]*observer[2]/(sn2*sm2); v[2] = m2/(sn2*sm2); first = 0; } if (z > ZMAX_FACTOR*n2) z = ZMAX_FACTOR*n2; z *= Z_SCALING_FACTOR; s = observer[0]*x + observer[1]*y + observer[2]*z; t = (d - s)/(n2 - s); xinter[0] = t*observer[0] + (1.0-t)*x; xinter[1] = t*observer[1] + (1.0-t)*y; xinter[2] = t*observer[2] + (1.0-t)*z; xy_out[0] = XSHIFT_3D + FLIPX*XY_SCALING_FACTOR*(xinter[0]*h[0] + xinter[1]*h[1]); xy_out[1] = YSHIFT_3D + XY_SCALING_FACTOR*(xinter[0]*v[0] + xinter[1]*v[1] + xinter[2]*v[2]); } void draw_vertex_sphere(double xyz[3]) { double xy_screen[2]; xyz_to_xy(xyz[0], xyz[1], xyz[2], xy_screen); glVertex2d(xy_screen[0], xy_screen[1]); } void init_lj_sphere(t_lj_sphere *wsphere) /* initialize sphere data, taken from sub_sphere.c */ { int i, j; double dphi, dtheta, theta0, xy[2], phishift, reg_cot; printf("Initializing wsphere\n"); dphi = DPI/(double)(NX_SPHERE-1); dtheta = PI/(double)(NY_SPHERE); #pragma omp parallel for private(i,j) for (i=0; i 2) { omega = DPI/(double)(particle[part].type - 2); for (k=0; k wsphere[i*NY_SPHERE+j].radius)&&(!wsphere[i*NY_SPHERE+j].locked)) { wsphere[i*NY_SPHERE+j].r = particle[part].rgb[0]; wsphere[i*NY_SPHERE+j].g = particle[part].rgb[1]; wsphere[i*NY_SPHERE+j].b = particle[part].rgb[2]; wsphere[i*NY_SPHERE+j].radius = h; } } } } draw_normal_particle = 0; break; } } } if (draw_normal_particle) { dist = test_distance(x, y, part, particle); if (dist < r) { h = 1.0 + 1.5*sqrt(r*r - dist*dist); if ((h > wsphere[i*NY_SPHERE+j].radius)&&(!wsphere[i*NY_SPHERE+j].locked)) { wsphere[i*NY_SPHERE+j].r = particle[part].rgb[0]; wsphere[i*NY_SPHERE+j].g = particle[part].rgb[1]; wsphere[i*NY_SPHERE+j].b = particle[part].rgb[2]; wsphere[i*NY_SPHERE+j].radius = h; } } } } void draw_trajectory_sphere(t_tracer trajectory[TRAJECTORY_LENGTH*N_TRACER_PARTICLES], t_hashgrid hashgrid[HASHX*HASHY], int traj_position, int traj_length, t_particle *particle, t_cluster *cluster, t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE], int *tracer_n, int plot) /* draw tracer particle trajectory */ { int i, j, i0, j0, time, p, q, width, imin, cell, i1, j1; double x1, x2, y1, y2, rgb[3], rgbx[3], rgby[3], radius, lum, lum1, rgb_bg[3]; static double dphi, dtheta; static int first = 1; if (first) { dphi = DPI/(double)NX_SPHERE; dtheta = PI/(double)NY_SPHERE; first = 0; } if (traj_length < TRAJECTORY_DRAW_LENGTH) imin = 0; else imin = traj_length - TRAJECTORY_DRAW_LENGTH; if (traj_position < imin) traj_position = imin; if (traj_length < TRAJECTORY_LENGTH*TRACER_STEPS) for (i=imin; i < traj_length-1; i++) for (j=0; j= NX_SPHERE) i1 = 0; j1 = j0 + q; if (j1 < 0) j1 = 0; if (j1 >= NY_SPHERE) j1 = NY_SPHERE-1; cell = i1*NY_SPHERE+j1; if (!wsphere[cell].locked) { if (COLOR_BACKGROUND) { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1*rgb_bg[0]; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1*rgb_bg[1]; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1*rgb_bg[2]; } else { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1; } } } } else { for (i = traj_position + 1; i < traj_length-1; i++) for (j=0; j= NX_SPHERE) i1 = 0; j1 = j0 + q; if (j1 < 0) j1 = 0; if (j1 >= NY_SPHERE) j1 = NY_SPHERE-1; cell = i1*NY_SPHERE+j1; if (!wsphere[cell].locked) { if (COLOR_BACKGROUND) { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1*rgb_bg[0]; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1*rgb_bg[1]; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1*rgb_bg[2]; } else { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1; } } } } for (i=imin; i < traj_position-1; i++) for (j=0; j= NX_SPHERE) i1 = 0; j1 = j0 + q; if (j1 < 0) j1 = 0; if (j1 >= NY_SPHERE) j1 = NY_SPHERE-1; cell = i1*NY_SPHERE+j1; if (!wsphere[cell].locked) { if (COLOR_BACKGROUND) { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1*rgb_bg[0]; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1*rgb_bg[1]; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1*rgb_bg[2]; } else { wsphere[cell].r = particle[tracer_n[j]].rgb[0]*lum + lum1; wsphere[cell].g = particle[tracer_n[j]].rgb[1]*lum + lum1; wsphere[cell].b = particle[tracer_n[j]].rgb[2]*lum + lum1; } } } } } } void draw_segments_sphere(t_segment segment[NMAXSEGMENTS], t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE]) /* draw the repelling segments on the sphere */ { int s, i, cell, npoints, i0, j0, i1, j1, p, q; double x1, y1, x2, y2, x, y, dt, length; static double dphi, dtheta; static int first = 1; if (first) { dphi = DPI/(double)NX_SPHERE; dtheta = PI/(double)NY_SPHERE; first = 0; } for (s=0; s= NX_SPHERE) i1 = 0; j1 = j0 + q; if (j1 < 0) j1 = 0; if (j1 >= NY_SPHERE) j1 = NY_SPHERE-1; cell = i1*NY_SPHERE+j1; wsphere[cell].r = 0.0; wsphere[cell].g = 0.0; wsphere[cell].b = 0.0; wsphere[cell].radius += 0.005; } } } } void draw_absorbers_sphere(t_absorber absorber[NMAX_ABSORBERS], t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE]) /* draw the absorbing discs on the sphere */ { int i, j, n, cell; double x, y, dist; static double dphi, dtheta; static int first = 1; if (first) { dphi = DPI/(double)NX_SPHERE; dtheta = PI/(double)NY_SPHERE; first = 0; } for (i=0; i 0)) { cell = hash_cell(wsphere[i].phi, wsphere[i].theta); wsphere[i].r = hashgrid[cell].r; wsphere[i].g = hashgrid[cell].g; wsphere[i].b = hashgrid[cell].b; } else { wsphere[i].r = 1.0; wsphere[i].g = 1.0; wsphere[i].b = 1.0; } } /* add tracer trajectories */ if (TRACER_PARTICLE) draw_trajectory_sphere(trajectory, hashgrid, traj_position, traj_length, particle, cluster, wsphere, tracer_n, plot); if (ADD_FIXED_SEGMENTS) draw_segments_sphere(segment, wsphere); // if (ADD_ABSORBERS) // draw_absorbers_sphere(absorber, wsphere); /* draw zero meridian, for debugging */ // for (j=0; j NY_SPHERE-1) jmax = NY_SPHERE-1; deltai = (int)(2.5*particle[part].radius/(dphi*sin(particle[part].yc + 0.001))); imin = i0 - deltai; // if (imin < 0) imin = 0; imax = i0 + deltai; // if (imax > NX_SPHERE-1) imax = NX_SPHERE-1; #pragma omp parallel for private(i,j,x,y,dist,r) for (j=jmin; j NY_SPHERE-1) jmax = NY_SPHERE-1; deltai = (int)(2.5*particle[part].radius/(dphi*sin(particle[part].yc + 0.001))); imin = NX_SPHERE + i0 - deltai; imax = i0 + deltai; #pragma omp parallel for private(i,j,x,y,dist,r) for (j=jmin; j NY_SPHERE-1) jmax = NY_SPHERE-1; deltai = (int)(2.5*particle[part].radius/(dphi*sin(particle[part].yc + 0.001))); imin = i0 - deltai; imax = i0 + deltai - NX_SPHERE; #pragma omp parallel for private(i,j,x,y,dist,r) for (j=jmin; j DPI) angle2 -= DPI; observer_latitude = asin(observer[2]/module2(observer[0], observer[1])); imin = (int)(observer_angle*(double)NX_SPHERE/DPI); imax = (int)(angle2*(double)NX_SPHERE/DPI); if (imin >= NX_SPHERE-1) imin = NX_SPHERE-2; if (imax >= NX_SPHERE-1) imax = NX_SPHERE-2; jmax = NY_SPHERE; jmin = 0; jmid = (int)((double)NY_SPHERE*(observer_latitude + PID)/PI); imid = (imin + imax)/2; printf("Angle = %.5lg, angle2 = %.5lg, imin = %i, imax = %i\n", observer_angle, angle2, imin, imax); if (observer[2] > 0.0) { if (imin < imax) { for (i=imax; i>imid; i--) { for (j=jmin; j<=jmax; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imid; i>imin; i--) { for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imax+1; i=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } if (imin >= 1) { for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(imin-1, imin, j, j+1, wsphere, fade, fade_value); } } else { for (i=imax; i=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imax-1; i>=0; i--) { for (j=jmin; j<=jmax; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (j=jmin; j<=jmax; j++) { draw_lj_sphere_ij(NX_SPHERE-1, 0, j, j+1, wsphere, fade, fade_value); draw_lj_sphere_ij(0, 1, j, j+1, wsphere, fade, fade_value); } for (i=NX_SPHERE-2; i>=imin; i--) { for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } if (imin >= 1) { /* experimental */ for (j=jmid/3; j<=jmid; j++) draw_lj_sphere_ij(imin-1, imin, j, j+1, wsphere, fade, fade_value); for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(imin-1, imin, j, j+1, wsphere, fade, fade_value); } } /* North pole */ for (i=0; iimid; i--) { for (j=jmax; j>=jmin; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imid; i>imin; i--) { for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imax+1; i=jmin; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (j=jmax; j>=jmin; j--) draw_lj_sphere_ij(NX_SPHERE-1, 0, j, j+1, wsphere, fade, fade_value); for (i=0; i<=imin; i++) { for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } /* TEST */ for (j=jmin; j<=jmid; j++) for (i=-1; i<2; i++) if ((imin+i >= 0)&&(imin+i+1 < NX_SPHERE)) draw_lj_sphere_ij(imin+i, imin+i+1, j, j+1, wsphere, fade, fade_value); for (j=jmax; j>=jmid; j--) for (i=-1; i<2; i++) if ((imin+i >= 0)&&(imin+i+1 < NX_SPHERE)) draw_lj_sphere_ij(imin+i, imin+i+1, j, j+1, wsphere, fade, fade_value); } else { for (i=imax; i=jmin; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imid; i=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=imax-1; i>=0; i--) { for (j=jmax; j>=jmin; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (j=jmax; j>=jmin; j--) draw_lj_sphere_ij(NX_SPHERE-1, 0, j, j+1, wsphere, fade, fade_value); for (i=NX_SPHERE-2; i>=imin; i--) { for (j=jmax; j>=jmid; j--) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(i, i+1, j, j+1, wsphere, fade, fade_value); } for (i=0; i<2; i++) if (imin >= i) { for (j=2*jmax/3; j>=jmid; j--) draw_lj_sphere_ij(imin-i, imin-i+1, j, j+1, wsphere, fade, fade_value); for (j=jmin; j<=jmid; j++) draw_lj_sphere_ij(imin-i, imin-i+1, j, j+1, wsphere, fade, fade_value); } /* TEST */ for (j=jmin; j<=jmid; j++) for (i=-1; i<2; i++) if ((imin+i >= 0)&&(imin+i+1 < NX_SPHERE)) draw_lj_sphere_ij(imin+i, imin+i+1, j, j+1, wsphere, fade, fade_value); for (j=jmax; j>=jmid; j--) for (i=-1; i<2; i++) if ((imin+i >= 0)&&(imin+i+1 < NX_SPHERE)) draw_lj_sphere_ij(imin+i, imin+i+1, j, j+1, wsphere, fade, fade_value); } /* South pole */ for (i=0; i0; j--) draw_lj_sphere_ij(i, i+1, j-1, j, wsphere, fade, fade_value); for (j=2; j>0; j--) draw_lj_sphere_ij(NX_SPHERE-1, 0, j-1, j, wsphere, fade, fade_value); } } void viewpoint_schedule(int i) /* change position of observer */ { int j; double angle, ca, sa, r1, interpolate, rho; static double observer_initial[3], r, ratio, rho0, zmax; static int first = 1; if (first) { for (j=0; j<3; j++) observer_initial[j] = observer[j]; r1 = observer[0]*observer[0] + observer[1]*observer[1]; r = sqrt(r1 + observer[2]*observer[2]); ratio = r/sqrt(r1); rho0 = module2(observer[0], observer[1]); if (vabs(rho0) < 0.001) rho0 = 0.001; zmax = r*sin(MAX_LATITUDE*PI/180.0); first = 0; } interpolate = (double)i/(double)NSTEPS; angle = (ROTATE_ANGLE*DPI/360.0)*interpolate; // printf("i = %i, interpolate = %.3lg, angle = %.3lg\n", i, interpolate, angle); ca = cos(angle); sa = sin(angle); switch (VIEWPOINT_TRAJ) { case (VP_HORIZONTAL): { observer[0] = ca*observer_initial[0] - sa*observer_initial[1]; observer[1] = sa*observer_initial[0] + ca*observer_initial[1]; break; } case (VP_ORBIT): { observer[0] = ca*observer_initial[0] - sa*observer_initial[1]*ratio; observer[1] = ca*observer_initial[1] + sa*observer_initial[0]*ratio; observer[2] = ca*observer_initial[2]; break; } case (VP_ORBIT2): { observer[0] = ca*observer_initial[0] - sa*observer_initial[1]*ratio; observer[1] = ca*observer_initial[1] + sa*observer_initial[0]*ratio; observer[2] = sa*zmax; break; } case (VP_POLAR): { rho = -sa*observer_initial[2] + ca*rho0; observer[0] = observer_initial[0]*rho/rho0; observer[1] = observer_initial[1]*rho/rho0; observer[2] = ca*observer_initial[2] + sa*rho0; break; } } printf("Angle %.3lg, Observer position (%.3lg, %.3lg, %.3lg)\n", angle, observer[0], observer[1], observer[2]); }