void cart_makecart(double *pointx, double *pointy, int npoints, int xsize, int ysize, double blur) { int s,sp; int step; double t,h; double error,dr; double desiredratio; /* Calculate the initial density and velocity for snapshot zero */ cart_density(0.0,0,xsize,ysize); cart_vgrid(0,xsize,ysize); s = 0; /* Now integrate the points in the polygons */ step = 0; t = 0.5*blur*blur; h = INITH; do { /* Do a combined (triple) integration step */ cart_twosteps(pointx,pointy,npoints,t,h,s,xsize,ysize,&error,&dr,&sp); /* Increase the time by 2h and rotate snapshots */ t += 2.0*h; step += 2; s = sp; /* Adjust the time-step. Factor of 2 arises because the target for * the two-step process is twice the target for an individual step */ desiredratio = pow(2*TARGETERROR/error,0.2); if (desiredratio>MAXRATIO) h *= MAXRATIO; else h *= desiredratio; /* If no point moved then we are finished */ } while (dr>0.0); }
void cart_twosteps(double *pointx, double *pointy, int npoints, double t, double h, int s, int xsize, int ysize, double *errorp, double *drp, int *spp) { int s0,s1,s2,s3,s4; int p; double rx1,ry1; double rx2,ry2; double rx3,ry3; double v1x,v1y; double v2x,v2y; double v3x,v3y; double v4x,v4y; double k1x,k1y; double k2x,k2y; double k3x,k3y; double k4x,k4y; double dx1,dy1; double dx2,dy2; double dx12,dy12; double dxtotal,dytotal; double ex,ey; double esq,esqmax; double drsq,drsqmax; s0 = s; s1 = (s+1)%5; s2 = (s+2)%5; s3 = (s+3)%5; s4 = (s+4)%5; /* Calculate the density field for the four new time slices */ cart_density(s0, 0.5*h, s1, xsize, ysize); cart_density(s1, 0.5*h, s2, xsize, ysize); cart_density(s2, 0.5*h, s3, xsize, ysize); cart_density(s3, 0.5*h, s4, xsize, ysize); /* Do all three RK steps for each point in turn */ esqmax = drsqmax = 0.0; for (p=0; p<npoints; p++) { rx1 = pointx[p]; ry1 = pointy[p]; /* Do the big combined (2h) RK step */ cart_velocity(rx1,ry1,s0,xsize,ysize,&v1x,&v1y); k1x = 2*h*v1x; k1y = 2*h*v1y; cart_velocity(rx1+0.5*k1x,ry1+0.5*k1y,s2,xsize,ysize,&v2x,&v2y); k2x = 2*h*v2x; k2y = 2*h*v2y; cart_velocity(rx1+0.5*k2x,ry1+0.5*k2y,s2,xsize,ysize,&v3x,&v3y); k3x = 2*h*v3x; k3y = 2*h*v3y; cart_velocity(rx1+k3x,ry1+k3y,s4,xsize,ysize,&v4x,&v4y); k4x = 2*h*v4x; k4y = 2*h*v4y; dx12 = (k1x+k4x+2.0*(k2x+k3x))/6.0; dy12 = (k1y+k4y+2.0*(k2y+k3y))/6.0; /* Do the first small RK step. No initial call to cart_velocity() is done * because it would be the same as the one above, so there's no need * to do it again */ k1x = h*v1x; k1y = h*v1y; cart_velocity(rx1+0.5*k1x,ry1+0.5*k1y,s1,xsize,ysize,&v2x,&v2y); k2x = h*v2x; k2y = h*v2y; cart_velocity(rx1+0.5*k2x,ry1+0.5*k2y,s1,xsize,ysize,&v3x,&v3y); k3x = h*v3x; k3y = h*v3y; cart_velocity(rx1+k3x,ry1+k3y,s2,xsize,ysize,&v4x,&v4y); k4x = h*v4x; k4y = h*v4y; dx1 = (k1x+k4x+2.0*(k2x+k3x))/6.0; dy1 = (k1y+k4y+2.0*(k2y+k3y))/6.0; /* Do the second small RK step */ rx2 = rx1 + dx1; ry2 = ry1 + dy1; cart_velocity(rx2,ry2,s2,xsize,ysize,&v1x,&v1y); k1x = h*v1x; k1y = h*v1y; cart_velocity(rx2+0.5*k1x,ry2+0.5*k1y,s3,xsize,ysize,&v2x,&v2y); k2x = h*v2x; k2y = h*v2y; cart_velocity(rx2+0.5*k2x,ry2+0.5*k2y,s3,xsize,ysize,&v3x,&v3y); k3x = h*v3x; k3y = h*v3y; cart_velocity(rx2+k3x,ry2+k3y,s4,xsize,ysize,&v4x,&v4y); k4x = h*v4x; k4y = h*v4y; dx2 = (k1x+k4x+2.0*(k2x+k3x))/6.0; dy2 = (k1y+k4y+2.0*(k2y+k3y))/6.0; /* Calculate the (squared) error */ ex = (dx1+dx2-dx12)/15; ey = (dy1+dy2-dy12)/15; esq = ex*ex + ey*ey; if (esq>esqmax) esqmax = esq; /* Update the position of the vertex using the more accurate (two small * steps) result, and deal with the boundary conditions. This code * does 5th-order "local extrapolation" (which just means taking * the estimate of the 5th-order term above and adding it to our * 4th-order result get a result accurate to the next highest order) */ dxtotal = dx1 + dx2 + ex; // Last term is local extrapolation dytotal = dy1 + dy2 + ey; // Last term is local extrapolation drsq = dxtotal*dxtotal + dytotal*dytotal; if (drsq>drsqmax) drsqmax = drsq; rx3 = rx1 + dxtotal; ry3 = ry1 + dytotal; if (rx3<0) rx3 = 0; else if (rx3>xsize) rx3 = xsize; if (ry3<0) ry3 = 0; else if (ry3>ysize) ry3 = ysize; pointx[p] = rx3; pointy[p] = ry3; } *errorp = sqrt(esqmax); *drp = sqrt(drsqmax); *spp = s4; }
/* Function to do the transformation of the given set of points * to the cartogram */ void cart_makecart(double *pointx, double *pointy, int npoints, int xsize, int ysize, double blur) { int i; int s,sp; int step; int done; double t,h; double error,dr; double desiredratio; /* Calculate the initial density and velocity for snapshot zero */ cart_density(0.0,0,xsize,ysize); cart_vgrid(0,xsize,ysize); s = 0; /* Now integrate the points in the polygons */ step = 0; t = 0.5*blur*blur; h = INITH; do { /* Do a combined (triple) integration step */ cart_twosteps(pointx,pointy,npoints,t,h,s,xsize,ysize,&error,&dr,&sp); /* Increase the time by 2h and rotate snapshots */ t += 2.0*h; step += 2; s = sp; /* Adjust the time-step. Factor of 2 arises because the target for * the two-step process is twice the target for an individual step */ desiredratio = pow(2*TARGETERROR/error,0.2); if (desiredratio>MAXRATIO) h *= MAXRATIO; else h *= desiredratio; done = cart_complete(t); #ifdef PERCENT fprintf(stdout,"%i\n",done); #endif #ifndef NOPROGRESS fprintf(stderr," %3i%% |",done); for (i=0; i<done/2; i++) fprintf(stderr,"="); for (i=done/2; i<50; i++) fprintf(stderr," "); fprintf(stderr,"|\r"); #endif /* If no point moved then we are finished */ } while (dr>0.0); #ifdef PERCENT fprintf(stdout,"\n"); #endif #ifndef NOPROGRESS fprintf(stderr," 100%% |==================================================|\n"); #endif }