Skip to content

Commit

Permalink
optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
Calvin Metcalf committed May 16, 2013
1 parent f758edd commit b6238aa
Showing 1 changed file with 71 additions and 55 deletions.
126 changes: 71 additions & 55 deletions cartogram.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,25 @@
topology = copy(topology);

// objects are projected into screen coordinates
var projectGeometry = projector(projection);

// project the arcs into screen space
var tf = transformer(topology.transform),
projectedArcs = topology.arcs.map(function(arc) {
var x = 0, y = 0;
return arc.map(function(coord) {
coord[0] = (x += coord[0]);
coord[1] = (y += coord[1]);
return projection(tf(coord));
});
});
var tf = transformer(topology.transform),x,y,len1,i1,out1,len2=topology.arcs.length,i2=0,
projectedArcs = new Array(len2);
while(i2<len2){
x = 0;
y = 0;
len1 = topology.arcs[i2].length;
i1 = 0;
out1 = new Array(len1);
while(i1<len1){
topology.arcs[i2][i1][0] = (x += topology.arcs[i2][i1][0]);
topology.arcs[i2][i1][1] = (y += topology.arcs[i2][i1][1]);
out1[i1] = projection(tf(topology.arcs[i2][i1]));
i1++;
}
projectedArcs[i2++]=out1;

}

// path with identity projection
var path = d3.geo.path()
Expand All @@ -68,20 +75,21 @@
return objects;
}

var i = 0,
targetSizeError = 1;
var i = 0;
while (i++ < iterations) {
var areas = objects.map(path.area),
totalArea = d3.sum(areas),
sizeErrors = [],
var areas = objects.map(path.area);
var totalArea = d3.sum(areas),
sizeErrorsTot =0,
sizeErrorsNum=0,
meta = objects.map(function(o, j) {
var area = Math.abs(areas[j]), // XXX: why do we have negative areas?
v = +values[j],
desired = totalArea * v / totalValue,
radius = Math.sqrt(area / Math.PI),
mass = Math.sqrt(desired / Math.PI) - radius,
sizeError = Math.max(area, desired) / Math.min(area, desired);
sizeErrors.push(sizeError);
sizeErrorsTot+=sizeError;
sizeErrorsNum++;
// console.log(o.id, "@", j, "area:", area, "value:", v, "->", desired, radius, mass, sizeError);
return {
id: o.id,
Expand All @@ -95,51 +103,49 @@
};
});

var sizeError = d3.mean(sizeErrors),
var sizeError = sizeErrorsTot/sizeErrorsNum,
forceReductionFactor = 1 / (1 + sizeError);

// console.log("meta:", meta);
// console.log(" total area:", totalArea);
// console.log(" force reduction factor:", forceReductionFactor, "mean error:", sizeError);

projectedArcs.forEach(function(arc) {
arc.forEach(function(coord) {
// create an array of vectors: [x, y]
var vectors = meta.map(function(d) {
var centroid = d.centroid,
mass = d.mass,
radius = d.radius,
theta = angle(centroid, coord),
dist = distance(centroid, coord),
Fij = (dist > radius)
? mass * radius / dist
: mass *
(Math.pow(dist, 2) / Math.pow(radius, 2)) *
(4 - 3 * dist / radius);
return [
Fij * Math.cos(theta),
Fij * Math.sin(theta)
];
});

// using Fij and angles, calculate vector sum
var delta = vectors.reduce(function(a, b) {
return [
a[0] + b[0],
a[1] + b[1]
];
}, [0, 0]);

delta[0] *= forceReductionFactor;
delta[1] *= forceReductionFactor;

coord[0] += delta[0];
coord[1] += delta[1];
});
});
var len1,i1,delta,len2=projectedArcs.length,i2=0,delta,len3,i3,centroid,mass,radius,rSquared,dx,dy,distSquared,dist,Fij;
while(i2<len2){
len1=projectedArcs[i2].length;
i1=0;
while(i1<len1){
// create an array of vectors: [x, y]
delta = [0,0];
len3 = meta.length;
i3=0;
while(i3<len3) {
centroid = meta[i3].centroid;
mass = meta[i3].mass;
radius = meta[i3].radius;
rSquared = (radius*radius);
dx = projectedArcs[i2][i1][0] - centroid[0];
dy = projectedArcs[i2][i1][1] - centroid[1];
distSquared = dx * dx + dy * dy;
dist=Math.sqrt(distSquared);
Fij = (dist > radius)
? mass * radius / dist
: mass *
(distSquared / rSquared) *
(4 - 3 * dist / radius);
delta[0]+=(Fij * cosArctan(dy,dx));
delta[1]+=(Fij * sinArctan(dy,dx));
i3++;
}
projectedArcs[i2][i1][0] += (delta[0]*forceReductionFactor);
projectedArcs[i2][i1][1] += (delta[1]*forceReductionFactor);
i1++;
}
i2++;
}

// break if we hit the target size error
if (sizeError <= targetSizeError) break;
if (sizeError <= 1) break;
}

return {
Expand Down Expand Up @@ -265,7 +271,18 @@
return types[geom.type](geom.coordinates);
};
}

function cosArctan(dx,dy){
var div = dx/dy;
return (dy>0)?
(1/Math.sqrt(1+(div*div))):
(-1/Math.sqrt(1+(div*div)));
}
function sinArctan(dx,dy){
var div = dx/dy;
return (dy>0)?
(div/Math.sqrt(1+(div*div))):
(-div/Math.sqrt(1+(div*div)));
}
function copy(o) {
return (o instanceof Array)
? o.map(copy)
Expand Down Expand Up @@ -304,7 +321,6 @@
o.coordinates = geometryType[o.type](o.arcs);
return o;
}

var geometryType = {
LineString: line,
MultiLineString: polygon,
Expand Down

0 comments on commit b6238aa

Please sign in to comment.