YouTube-simulations/sub_lj_sphere.c
Nils Berglund ab63c4d200
Add files via upload
Main changes: lennardjones, wave_billiard, rde
2025-11-02 19:13:40 +01:00

2172 lines
78 KiB
C

/* 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<n; i++) y *= x;
return(y);
}
double gaussian()
/* returns standard normal random variable, using Box-Mueller algorithm */
{
static double V1, V2, S;
static int phase = 0;
double X;
if (phase == 0)
{
do
{
double U1 = (double)rand() / RAND_MAX;
double U2 = (double)rand() / RAND_MAX;
V1 = 2 * U1 - 1;
V2 = 2 * U2 - 1;
S = V1 * V1 + V2 * V2;
}
while(S >= 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));
}
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<npoly; k++)
{
angle = -apoly*PID + ((double)k+0.5)*omega;
condition = condition*(x*cos(angle) + y*sin(angle) < r*cw);
}
return(condition);
}
double neighbour_color(int nnbg)
{
if (nnbg > 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);
}
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 = (-0.6*tanh(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<particle.hash_nneighb; i++)
{
dx = particle.deltax[i];
dy = particle.deltay[i];
if (BOUNDARY_COND == BC_SPHERE)
{
dist = dist_sphere(particle.xc, particle.yc, particle.xc + dx, particle.yc + dy);
dist *= dist;
}
else dist = dx*dx + dy*dy;
density += 1.0/dist;
}
density -= PARTICLE_DMIN;
// printf("Density = %.3lg\n", density);
hue = ENERGY_HUE_MAX + (ENERGY_HUE_MIN - ENERGY_HUE_MAX)*density/PARTICLE_DMAX;
if (hue > 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<ncircles; i++) if (particle[i].active)
{
compute_particle_colors(particle[i], cluster, plot, rgb, rgbx, rgby, particle);
for (k=0; k<3; k++)
{
particle[i].rgb[k] = rgb[k];
particle[i].rgbx[k] = rgbx[k];
particle[i].rgby[k] = rgby[k];
}
}
}
void compute_background_color(t_particle particle[NMAXCIRCLES], t_obstacle obstacle[NMAXOBSTACLES], int bg_color, t_hashgrid hashgrid[HASHX*HASHY])
/* color background according to particle properties */
{
int i, j, k, n, p, q, m, nnb, number, avrg_fact, obs;
double rgb[3], hue, value, p1, p2, pp1, pp2, oldhue, valx, valy, lum;
static int first = 1, counter = 0;
static double area_factor;
if (first)
{
area_factor = hashgrid[mhash(0,HASHY/2)].area;
first = 0;
}
p1 = 0.75;
p2 = 1.0 - p1;
// pp1 = 0.95;
pp1 = 0.99;
pp2 = 1.0 - pp1;
for (i=0; i<HASHX; i++)
for (j=0; j<HASHY; j++)
{
n = mhash(i, j);
if (first)
{
hashgrid[n].hue1 = 180.0;
hashgrid[n].hue2 = 180.0;
}
/* set two old values for option DOUBLE_MOVIE */
if (DOUBLE_MOVIE)
{
if (counter) oldhue = hashgrid[n].hue1;
else oldhue = hashgrid[n].hue2;
}
else oldhue = hashgrid[n].hue1;
switch (bg_color) {
case (BG_DENSITY):
{
nnb = hashgrid[n].nneighb;
number = 0;
for (q=0; q<nnb; q++)
{
m = hashgrid[n].neighbour[q];
number += hashgrid[m].number;
}
number += hashgrid[n].number;
// hue = 50.0*(double)hashgrid[n].number;
hue = 75.0*(double)number/(double)(nnb + 1);
if (BOUNDARY_COND == BC_SPHERE)
{
hue *= 5.0*area_factor/hashgrid[n].area;
}
hue = p1*oldhue + p2*hue;
rgb[0] = hue/360.0;
rgb[1] = hue/360.0;
rgb[2] = hue/360.0;
break;
}
case (BG_NEIGHBOURS):
{
value = 0.0;
nnb = hashgrid[n].nneighb;
for (q=0; q<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += (double)particle[p].neighb;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += (double)particle[p].neighb;
}
value *= 1.0/(double)(nnb + 1);
hue = neighbour_color((int)(value + 0.5));
hsl_to_rgb(hue, 0.9, 0.5, rgb);
break;
}
case (BG_CHARGE):
{
avrg_fact = 3; /* weight of central cell in hashgrid average */
value = 0.0;
nnb = hashgrid[n].nneighb;
for (q=0; q<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].charge;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += (double)(avrg_fact-1)*particle[p].charge;
}
value *= 1.0/(double)(nnb + avrg_fact);
if (CHARGE_OBSTACLES) value += hashgrid[n].charge;
hue = (-tanh(BG_CHARGE_SLOPE*value)+1.0)*180.0;
hue = p1*oldhue + p2*hue;
hsl_to_rgb_twilight(hue, 0.9, 0.5, rgb);
break;
}
case (BG_EKIN):
{
value = 0.0;
nnb = hashgrid[n].nneighb;
for (q=0; q<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].energy;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += particle[p].energy;
}
value *= 1.0/(double)(nnb + 1);
hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*value/PARTICLE_EMAX;
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].energy;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += particle[p].energy;
}
value *= 1.0/(double)(nnb + 1);
hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*(BG_LOG_EKIN_SHIFT + log(value/PARTICLE_EMAX));
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
if (hashgrid[m].nobs) value += obstacle[hashgrid[m].obstacle].energy;
}
/* hashcell n counts four times */
if (hashgrid[n].nobs) value += 3.0*obstacle[hashgrid[n].obstacle].energy;
value *= 1.0/(double)(nnb + 4);
// if (hashgrid[n].nobs) value += obstacle[hashgrid[n].obstacle].energy;
hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*value/OBSTACLE_EMAX;
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].energy;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += particle[p].energy;
}
value *= 1.0/(double)(nnb + 1);
if (hashgrid[n].nobs) value += obstacle[hashgrid[n].obstacle].energy;
hue = ENERGY_HUE_MIN + (ENERGY_HUE_MAX - ENERGY_HUE_MIN)*value/OBSTACLE_EMAX;
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
if (hashgrid[m].nobs)
{
valx += obstacle[hashgrid[m].obstacle].vx;
valy += obstacle[hashgrid[m].obstacle].vy;
}
}
/* hashcell n counts more */
if (hashgrid[n].nobs)
{
valx += 4.0*obstacle[hashgrid[n].obstacle].vx;
valy += 4.0*obstacle[hashgrid[n].obstacle].vy;
}
valx *= 1.0/(double)(nnb + 4);
valy *= 1.0/(double)(nnb + 4);
hue = argument(valx, valy);
if (hue > 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<nnb; q++)
// {
// m = hashgrid[n].neighbour[q];
// if (hashgrid[m].nobs)
// {
// valx += obstacle[hashgrid[m].obstacle].xc;
// valy += obstacle[hashgrid[m].obstacle].yc;
// }
// }
/* hashcell n counts double */
if (hashgrid[n].nobs)
{
obs = hashgrid[n].obstacle;
valx += obstacle[obs].xc - obstacle[obs].xc0;
valy += obstacle[obs].yc - obstacle[obs].yc0;
}
// valx *= 1.0/(double)(nnb + 1);
// valy *= 1.0/(double)(nnb + 1);
hue = argument(valx, valy);
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += module2(particle[p].fx, particle[p].fy);
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += module2(particle[p].fx, particle[p].fy);
}
value *= BG_FORCE_SLOPE/(double)(nnb + 1);
hue = (1.0 - tanh(value))*360.0;
hue = pp1*oldhue + pp2*hue;
hsl_to_rgb_turbo(hue, 0.9, 0.5, rgb);
break;
}
case (BG_CURRENTX):
{
value = 0.0;
nnb = hashgrid[n].nneighb;
for (q=0; q<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].vx*particle[p].charge;
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += particle[p].vx*particle[p].charge;
}
value *= 1.0/(double)(nnb + 1);
hue = 180.0 + 180.0*value/MAX_CURRENT;
if (hue > 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<nnb; q++)
{
m = hashgrid[n].neighbour[q];
for (k=0; k<hashgrid[m].number; k++)
{
p = hashgrid[m].particles[k];
value += particle[p].angle*particle[p].spin_freq/DPI;
fprintf(lj_log, "value = %.3lg\n", value);
// hue -= (double)((int)hue);
}
}
/* hashcell n counts double */
for (k=0; k<hashgrid[n].number; k++)
{
p = hashgrid[n].particles[k];
value += particle[p].angle*particle[p].spin_freq/DPI;
fprintf(lj_log, "value = %.3lg\n", value);
// hue -= (double)((int)hue);
}
value *= 1.0/(double)(nnb + 1);
fprintf(lj_log, "value = %.3lg\n", value);
// hue = value*particle[n].spin_freq/DPI;
hue = value - (double)((int)value);
fprintf(lj_log, "hue = %.3lg\n", hue);
// angle = PI - angle;
// if (angle < 0.0) angle += DPI;
hue = PARTICLE_HUE_MIN + (PARTICLE_HUE_MAX - PARTICLE_HUE_MIN)*(hue);
hue = p1*oldhue + p2*hue;
hsl_to_rgb_palette(hue, 0.9, 0.5, rgb, COLOR_PALETTE_DIRECTION);
break;
}
}
if (DOUBLE_MOVIE)
{
if (counter) hashgrid[n].hue1 = hue;
else hashgrid[n].hue2 = hue;
}
else hashgrid[n].hue1 = hue;
hashgrid[n].r = rgb[0];
hashgrid[n].g = rgb[1];
hashgrid[n].b = rgb[2];
}
first = 0;
counter = 1 - counter;
}
/* specific routines for lennardjones on a sphere */
int ij_to_sphere(int i, int j, double r, t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE], double xyz[3], int use_wave_radius)
/* convert spherical to rectangular coordinates */
{
double pscal, newr;
static double norm_observer;
static int first = 1;
if (first)
{
norm_observer = sqrt(observer[0]*observer[0] + observer[1]*observer[1] + observer[2]*observer[2]);
first = 0;
}
xyz[0] = wsphere[i*NY_SPHERE+j].x;
xyz[1] = wsphere[i*NY_SPHERE+j].y;
xyz[2] = wsphere[i*NY_SPHERE+j].z;
pscal = xyz[0]*observer[0] + xyz[1]*observer[1] + xyz[2]*observer[2];
newr = wsphere[i*NY_SPHERE+j].radius;
xyz[0] *= newr;
xyz[1] *= newr;
xyz[2] *= newr;
return(pscal/norm_observer > 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 */
{
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);
}
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 + 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<NX_SPHERE; i++)
{
for (j=0; j<NY_SPHERE; j++)
{
wsphere[i*NY_SPHERE+j].phi = (double)i*dphi;
wsphere[i*NY_SPHERE+j].theta = (double)j*dtheta;
wsphere[i*NY_SPHERE+j].cphi = cos(wsphere[i*NY_SPHERE+j].phi);
wsphere[i*NY_SPHERE+j].sphi = sin(wsphere[i*NY_SPHERE+j].phi);
wsphere[i*NY_SPHERE+j].ctheta = cos(wsphere[i*NY_SPHERE+j].theta);
wsphere[i*NY_SPHERE+j].stheta = sin(wsphere[i*NY_SPHERE+j].theta);
wsphere[i*NY_SPHERE+j].x = wsphere[i*NY_SPHERE+j].cphi*wsphere[i*NY_SPHERE+j].stheta;
wsphere[i*NY_SPHERE+j].y = wsphere[i*NY_SPHERE+j].sphi*wsphere[i*NY_SPHERE+j].stheta;
wsphere[i*NY_SPHERE+j].z = -wsphere[i*NY_SPHERE+j].ctheta;
wsphere[i*NY_SPHERE+j].radius = 1.0;
wsphere[i*NY_SPHERE+j].cos_angle_sphere = wsphere[i*NY_SPHERE+j].x*light[0] + wsphere[i*NY_SPHERE+j].y*light[1] + wsphere[i*NY_SPHERE+j].z*light[2];
}
}
}
double test_distance(double phi, double psi, int i, t_particle* particle)
/* determine particle shape */
{
double d, ca, sa, theta;
static double c1, c2, c1inv;
static int first = 1;
if (first)
{
switch (INTERACTION) {
case (I_LJ_DIRECTIONAL):
{
c1 = 2.0/PI;
c2 = 1.0/cos(PI/4.0);
break;
}
case (I_LJ_PENTA):
{
c1 = 5.0/DPI;
c1inv = DPI/5.0;
c2 = 1.0/cos(PI/5.0);
break;
}
}
first = 0;
}
switch (INTERACTION) {
case (I_LJ_DIRECTIONAL):
{
d = dist_point_to_particle_sphere(i, phi, psi, particle, &ca, &sa);
theta = (argument(ca, sa) - particle[i].angle + 2.0*DPI)*c1;
theta -= (double)((int)theta);
theta *= PID;
theta -= 0.5*PID;
return(d*cos(theta)*c2);
}
case (I_LJ_PENTA):
{
d = dist_point_to_particle_sphere(i, phi, psi, particle, &ca, &sa);
theta = (argument(ca, sa) - particle[i].angle + 2.0*DPI)*c1;
theta -= (double)((int)theta);
theta *= c1inv;
theta -= PI/5.0;
return(d*cos(theta)*c2);
}
case (I_LJ_DIPOLE):
{
d = dist_point_to_particle_sphere(i, phi, psi, particle, &ca, &sa);
theta = (argument(ca, sa) - particle[i].angle);
return(2.0*d*(1.0 - 0.5*cos(2.0*theta)));
}
default:
{
if (DRAW_SPIN)
{
d = dist_point_to_particle_sphere(i, phi, psi, particle, &ca, &sa);
theta = (argument(ca, sa) - particle[i].angle);
return(2.0*d*(1.0 - 0.65*cos(theta)));
}
else return(dist_sphere(phi, psi, particle[i].xc, particle[i].yc));
}
}
}
void add_particle_to_sphere(int i, int j, int part, t_particle particle[NMAXCIRCLES], t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE])
/* compute the effect at point (i,j) of adding a particle */
{
int draw_normal_particle = 1;
double x, y, r, dist, ca, sa, x1, y1, x2, y2, d1, d2, r2;
static double dphi, dtheta;
static int first = 1;
if (first)
{
dphi = DPI/(double)NX_SPHERE;
dtheta = PI/(double)NY_SPHERE;
first = 0;
}
x = (double)i*dphi;
y = (double)j*dtheta;
r = 1.2*particle[part].radius;
/* special particle shapes for chemical reactions */
if (REACTION_DIFFUSION)
{
switch(RD_REACTION)
{
case (CHEM_ABC):
{
if (particle[part].type == 3)
{
dist = dist_point_to_particle_sphere(part, x, y, particle, &ca, &sa);
x2 = dist*ca;
y2 = dist*sa;
x1 = 0.35*r*cos(particle[part].angle);
y1 = 0.35*r*sin(particle[part].angle);
d1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
d2 = (x1+x2)*(x1+x2) + (y1+y2)*(y1+y2);
if (d2 < d1) d1 = d2;
r2 = 0.49*r*r;
if (d1 < r2)
{
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 += 1.5*sqrt(r2 - d1);
}
draw_normal_particle = 0;
}
break;
}
case (CHEM_AABAA):
{
if (particle[part].type == 2)
{
dist = dist_point_to_particle_sphere(part, x, y, particle, &ca, &sa);
x2 = dist*ca;
y2 = dist*sa;
x1 = 0.35*r*cos(particle[part].angle);
y1 = 0.35*r*sin(particle[part].angle);
d1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
d2 = (x1+x2)*(x1+x2) + (y1+y2)*(y1+y2);
if (d2 < d1) d1 = d2;
r2 = 0.49*r*r;
if (d1 < r2)
{
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 += 1.5*sqrt(r2 - d1);
}
draw_normal_particle = 0;
}
break;
}
case (CHEM_CATALYTIC_A2D):
{
if (particle[part].type == 3)
{
dist = dist_point_to_particle_sphere(part, x, y, particle, &ca, &sa);
x2 = dist*ca;
y2 = dist*sa;
x1 = 0.5*r*cos(particle[part].angle);
y1 = 0.5*r*sin(particle[part].angle);
d1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
d2 = (x1+x2)*(x1+x2) + (y1+y2)*(y1+y2);
if (d2 < d1) d1 = d2;
r2 = 0.9*r*r;
if (d1 < r2)
{
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 += 1.5*sqrt(r2 - d1);
}
draw_normal_particle = 0;
}
else if (particle[part].type == 4)
{
dist = dist_point_to_particle_sphere(part, x, y, particle, &ca, &sa);
x2 = dist*ca;
y2 = dist*sa;
x1 = 0.4*r*cos(particle[part].angle);
y1 = 0.4*r*sin(particle[part].angle);
d1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
d2 = (x1+x2)*(x1+x2) + (y1+y2)*(y1+y2);
if (d2 < d1) d1 = d2;
r2 = 0.7*r*r;
if (d1 < r2)
{
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 += 1.5*sqrt(r2 - d1);
}
draw_normal_particle = 0;
}
break;
}
}
}
if (draw_normal_particle)
{
dist = test_distance(x, y, part, particle);
if (dist < r)
{
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 += 1.5*sqrt(r*r - dist*dist);
}
}
}
void draw_trajectory_sphere(t_tracer trajectory[TRAJECTORY_LENGTH*N_TRACER_PARTICLES], 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;
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<n_tracers; j++) /*if (particle[tracer_n[j]].active)*/
{
// printf("Drawing tracer %i\n", j);
x1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].xc;
x2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].xc;
y1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].yc;
y2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].yc;
i0 = (int)(x1/dphi);
j0 = (int)(y1/dtheta);
time = traj_length - i;
lum = 0.9 - TRACER_LUM_FACTOR*(double)time/(double)(TRAJECTORY_LENGTH*TRACER_STEPS);
if (lum < 0.0) lum = 0.0;
lum1 = 1.0 - lum;
if ((x2 != x1)||(y2 != y1)) for (p=-1; p<2; p++)
for (q=-1; q<2; q++)
{
i1 = i0 + p;
if (i1 < 0) i1 = NX_SPHERE-1;
if (i1 >= 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 = 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<n_tracers; j++)
{
x1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].xc;
x2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].xc;
y1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].yc;
y2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].yc;
i0 = (int)(x1/dphi);
j0 = (int)(y1/dtheta);
time = traj_position + traj_length - i;
lum = 0.9 - TRACER_LUM_FACTOR*(double)time/(double)(TRAJECTORY_LENGTH*TRACER_STEPS);
if (lum < 0.0) lum = 0.0;
lum1 = 1.0 - lum;
if ((x2 != x1)||(y2 != y1)) for (p=-1; p<2; p++)
for (q=-1; q<2; q++)
{
i1 = i0 + p;
if (i1 < 0) i1 = NX_SPHERE-1;
if (i1 >= 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 = 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<n_tracers; j++)
{
x1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].xc;
x2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].xc;
y1 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i].yc;
y2 = trajectory[j*TRAJECTORY_LENGTH*TRACER_STEPS + i+1].yc;
time = traj_position - i;
lum = 0.9 - TRACER_LUM_FACTOR*(double)time/(double)(TRAJECTORY_LENGTH*TRACER_STEPS);
if (lum < 0.0) lum = 0.0;
lum1 = 1.0 - lum;
if ((x2 != x1)||(y2 != y1)) for (p=-1; p<2; p++)
for (q=-1; q<2; q++)
{
i1 = i0 + p;
if (i1 < 0) i1 = NX_SPHERE-1;
if (i1 >= 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 = 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 init_sphere_radius(t_particle particle[NMAXCIRCLES], t_hashgrid hashgrid[HASHX*HASHY], t_cluster cluster[NMAXCIRCLES], t_tracer trajectory[TRAJECTORY_LENGTH*N_TRACER_PARTICLES], int traj_position, int traj_length, t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE], int *tracer_n, int plot)
/* initialize sphere radius and colors from particles */
{
int i, j, n, m, i0, j0, i1, j1, p, q, part, width, deltai, imin, imax, deltaj, jmin, jmax, cell;
double rgb[3], rgbx[3], rgby[3], dist, d2, radius, r, x, y;
static double dphi, dtheta;
static int first = 1;
if (first)
{
dphi = DPI/(double)NX_SPHERE;
dtheta = PI/(double)NY_SPHERE;
first = 0;
}
/* default radius and color */
#pragma omp parallel for private(i)
for (i=0; i<NX_SPHERE*NY_SPHERE; i++)
{
wsphere[i].radius = 1.0;
if (COLOR_BACKGROUND)
{
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, traj_position, traj_length, particle, cluster, wsphere, tracer_n, plot);
/* draw zero meridian, for debugging */
// for (j=0; j<NY_SPHERE; j++)
// for (i=0; i<20; i++)
// {
// wsphere[i*NY_SPHERE + j].r = 0.5;
// wsphere[i*NY_SPHERE + j].g = 0.5;
// wsphere[i*NY_SPHERE + j].b = 0.5;
// }
/* add particles according to hashgrid */
/* South Pole, q=0 */
m = mhash(0,0);
for (n=0; n<hashgrid[m].number; n++)
{
part = hashgrid[m].particles[n];
if (particle[part].active)
{
deltaj = (int)(2.5*particle[part].radius/dtheta);
j0 = (int)(particle[part].yc/dtheta);
jmax = j0 + deltaj;
#pragma omp parallel for private(i,j,x,y,dist,r)
for (j=0; j<jmax; j++)
for (i=0; i<NX_SPHERE; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
}
}
/* North Pole, q=HASHY-1 */
m = mhash(0,HASHY-1);
for (n=0; n<hashgrid[m].number; n++)
{
part = hashgrid[m].particles[n];
if (particle[part].active)
{
deltaj = (int)(2.5*particle[part].radius/dtheta);
j0 = (int)(particle[part].yc/dtheta);
jmin = j0 - deltaj;
#pragma omp parallel for private(i,j,x,y,dist,r)
for (j=jmin; j<NY_SPHERE; j++)
for (i=0; i<NX_SPHERE; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
}
}
/* bulk */
for (q=1; q<HASHY-1; q++)
{
/* bulk, away from zero meridian */
for (p=1; p<hashx_sphere[q]-1; p++)
{
m = mhash(p,q);
for (n=0; n<hashgrid[m].number; n++)
{
part = hashgrid[m].particles[n];
if (particle[part].active)
{
i0 = (int)(particle[part].xc/dphi);
j0 = (int)(particle[part].yc/dtheta);
deltaj = (int)(2.5*particle[part].radius/dtheta);
jmin = j0 - deltaj;
// if (jmin < 0) jmin = 0;
jmax = j0 + deltaj;
// if (jmax > 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<jmax; j++)
for (i=imin; i<imax; i++)
{
add_particle_to_sphere(i, j, part, particle, wsphere);
}
}
}
}
/* p=0 */
m = mhash(0,q);
for (n=0; n<hashgrid[m].number; n++)
{
part = hashgrid[m].particles[n];
if (particle[part].active)
{
i0 = (int)(particle[part].xc/dphi);
j0 = (int)(particle[part].yc/dtheta);
deltaj = (int)(2.5*particle[part].radius/dtheta);
jmin = j0 - deltaj;
// if (jmin < 0) jmin = 0;
jmax = j0 + deltaj;
// if (jmax > 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<jmax; j++)
{
for (i=0; i<imax; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
for (i=imin; i<NX_SPHERE; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
}
}
}
/* p=hashx_sphere[q]-1 */
m = mhash(hashx_sphere[q]-1,q);
for (n=0; n<hashgrid[m].number; n++)
{
part = hashgrid[m].particles[n];
if (particle[part].active)
{
i0 = (int)(particle[part].xc/dphi);
j0 = (int)(particle[part].yc/dtheta);
deltaj = (int)(2.5*particle[part].radius/dtheta);
jmin = j0 - deltaj;
// if (jmin < 0) jmin = 0;
jmax = j0 + deltaj;
// if (jmax > 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<jmax; j++)
{
for (i=imin; i<NX_SPHERE; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
for (i=0; i<imax; i++)
add_particle_to_sphere(i, j, part, particle, wsphere);
}
}
}
}
}
void compute_light_angle_sphere(t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE])
/* compute sphere shading, adapted from compute_light_angle_sphere_rde() in sub_rde.c */
{
int i, j, iplus, b;
double x, y, z, norm, pscal, deltai[3], deltaj[3], deltar, n[3], r;
static double dphi, dtheta, vshift;
static int first = 1;
if (first)
{
dphi = DPI/(double)NX_SPHERE;
dtheta = PI/(double)NY_SPHERE;
first = 0;
}
#pragma omp parallel for private(i,j,norm,pscal,deltar,deltai,deltaj,n)
for (i=0; i<NX_SPHERE-1; i++)
for (j=0; j<NY_SPHERE-1; j++)
{
/* computation of tangent vectors */
deltar = (wsphere[(i+1)*NY_SPHERE+j].radius - wsphere[i*NY_SPHERE+j].radius)/dphi;
deltai[0] = -wsphere[i*NY_SPHERE+j].radius*wsphere[i*NY_SPHERE+j].sphi;
deltai[0] += deltar*wsphere[i*NY_SPHERE+j].cphi;
deltai[1] = wsphere[i*NY_SPHERE+j].radius*wsphere[i*NY_SPHERE+j].cphi;
deltai[1] += deltar*wsphere[i*NY_SPHERE+j].sphi;
deltai[2] = -deltar*wsphere[i*NY_SPHERE+j].cottheta;
deltar = (wsphere[i*NY_SPHERE+j+1].radius - wsphere[i*NY_SPHERE+j].radius)/dtheta;
deltaj[0] = wsphere[i*NY_SPHERE+j].radius*wsphere[i*NY_SPHERE+j].cphi*wsphere[i*NY_SPHERE+j].ctheta;
deltaj[0] += deltar*wsphere[i*NY_SPHERE+j].cphi*wsphere[i*NY_SPHERE+j].stheta;
deltaj[1] = wsphere[i*NY_SPHERE+j].radius*wsphere[i*NY_SPHERE+j].sphi*wsphere[i*NY_SPHERE+j].ctheta;
deltaj[1] += deltar*wsphere[i*NY_SPHERE+j].sphi*wsphere[i*NY_SPHERE+j].stheta;
deltaj[2] = wsphere[i*NY_SPHERE+j].radius*wsphere[i*NY_SPHERE+j].stheta;
deltaj[2] += -deltar*wsphere[i*NY_SPHERE+j].ctheta;
/* computation of normal vector */
n[0] = deltai[1]*deltaj[2] - deltai[2]*deltaj[1];
n[1] = deltai[2]*deltaj[0] - deltai[0]*deltaj[2];
n[2] = deltai[0]*deltaj[1] - deltai[1]*deltaj[0];
norm = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
pscal = n[0]*light[0] + n[1]*light[1] + n[2]*light[2];
wsphere[i*NY_SPHERE+j].cos_angle = pscal/norm;
}
/* i = NX-1 */
for (j=0; j<NY_SPHERE-1; j++)
{
/* computation of tangent vectors */
deltar = (wsphere[j].radius - wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius)/dphi;
deltai[0] = -wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].sphi;
deltai[0] += deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cphi;
deltai[1] = wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cphi;
deltai[1] += deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].sphi;
deltai[2] = -deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cottheta;
deltar = (wsphere[(NX_SPHERE-1)*NY_SPHERE+j+1].radius - wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius)/dtheta;
deltaj[0] = wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cphi*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].ctheta;
deltaj[0] += deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cphi*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].stheta;
deltaj[1] = wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].sphi*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].ctheta;
deltaj[1] += deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].sphi*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].stheta;
deltaj[2] = wsphere[(NX_SPHERE-1)*NY_SPHERE+j].radius*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].stheta;
deltaj[2] += -deltar*wsphere[(NX_SPHERE-1)*NY_SPHERE+j].ctheta;
/* computation of normal vector */
n[0] = deltai[1]*deltaj[2] - deltai[2]*deltaj[1];
n[1] = deltai[2]*deltaj[0] - deltai[0]*deltaj[2];
n[2] = deltai[0]*deltaj[1] - deltai[1]*deltaj[0];
norm = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
pscal = n[0]*light[0] + n[1]*light[1] + n[2]*light[2];
wsphere[(NX_SPHERE-1)*NY_SPHERE+j].cos_angle = pscal/norm;
}
}
void draw_lj_sphere_ij(int i, int iplus, int j, int jplus, t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE], int fade, double fade_value)
/* draw particles at simulation grid point (i,j) */
{
int k, l, n, m, s, p, q, i1, j1, prev_cell, cell, iplus1, jplus1;
short int draw, drawij;
double xyz[3], ca, rgb[3];
ca = wsphere[i*NY_SPHERE+j].cos_angle;
ca = (ca + 1.0)*0.4 + 0.2;
glColor3f(wsphere[i*NY_SPHERE+j].r*ca, wsphere[i*NY_SPHERE+j].g*ca, wsphere[i*NY_SPHERE+j].b*ca);
glBegin(GL_TRIANGLE_FAN);
drawij = ij_to_sphere(i, j, wsphere[i*NY_SPHERE+j].radius, wsphere, xyz, draw);
if (drawij) draw_vertex_sphere(xyz);
if (ij_to_sphere(iplus, j, wsphere[iplus*NY_SPHERE+j].radius, wsphere, xyz, draw))
draw_vertex_sphere(xyz);
if (ij_to_sphere(iplus, jplus, wsphere[iplus*NY_SPHERE+j+1].radius, wsphere, xyz, draw))
draw_vertex_sphere(xyz);
if (ij_to_sphere(i, jplus, wsphere[i*NY_SPHERE+j+1].radius, wsphere, xyz, draw))
draw_vertex_sphere(xyz);
glEnd ();
}
void draw_lj_sphere_3d(t_lj_sphere wsphere[NX_SPHERE*NY_SPHERE])
/* draw sphere, adapted from draw_wave_sphere_3d_rde() in sub_rde.c */
{
int i, j, imax, imin, jmin, jmax, imid, jmid, fade;
double observer_angle, angle2, observer_latitude, xyz[3], fade_value;
blank();
/* may be defined as parameters later */
fade = 0;
fade_value = 1.0;
observer_angle = argument(observer[0], observer[1]);
if (observer_angle < 0.0) observer_angle += DPI;
angle2 = observer_angle + PI;
if (angle2 > 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<NX_SPHERE-1; 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=0; 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)
{
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<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>=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; i<NX_SPHERE-1; i++)
draw_lj_sphere_ij(i, i+1, NY_SPHERE-3, NY_SPHERE-1, wsphere, fade, fade_value);
draw_lj_sphere_ij(NX_SPHERE-1, 0, NY_SPHERE-3, NY_SPHERE-1, wsphere, fade, fade_value);
}
else
{
if (imin < imax)
{
for (i=imax; i>imid; 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<NX_SPHERE-1; 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=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<imid; 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-1; 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>=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; i<NX_SPHERE-1; i++) for (j=2; j>0; 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]);
}