Skip to content

Commit

Permalink
circleIntersection -> venn
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Frederickson committed Aug 14, 2014
1 parent d047d0c commit fd7d81c
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 44 deletions.
52 changes: 25 additions & 27 deletions venn.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
}

return venn.bisect(function(distance) {
return circleIntersection.circleOverlap(r1, r2, distance) - overlap;
return venn.circleOverlap(r1, r2, distance) - overlap;
}, 0, r1 + r2);
};

Expand Down Expand Up @@ -177,7 +177,7 @@
var p2 = sets[overlap[k].set],
d2 = distances[setIndex][overlap[k].set];

var extraPoints = circleIntersection.circleCircleIntersection(
var extraPoints = venn.circleCircleIntersection(
{ x: p1.x, y: p1.y, radius: d1},
{ x: p2.x, y: p2.y, radius: d2});

Expand Down Expand Up @@ -238,10 +238,10 @@
if (area.sets.length == 2) {
var left = sets[area.sets[0]],
right = sets[area.sets[1]];
overlap = circleIntersection.circleOverlap(left.radius, right.radius,
circleIntersection.distance(left, right));
overlap = venn.circleOverlap(left.radius, right.radius,
venn.distance(left, right));
} else {
overlap = circleIntersection.intersectionArea(getCircles(area.sets));
overlap = venn.intersectionArea(getCircles(area.sets));
}

output += (overlap - area.size) * (overlap - area.size);
Expand Down Expand Up @@ -470,7 +470,7 @@
/** returns a svg path of the intersection area of a bunch of circles */
venn.intersectionAreaPath = function(circles) {
var stats = {};
circleIntersection.intersectionArea(circles, stats);
venn.intersectionArea(circles, stats);
var arcs = stats.arcs;

if (arcs.length == 0) {
Expand Down Expand Up @@ -557,20 +557,18 @@
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
};
}(window.venn = window.venn || {}));
(function(circleIntersection) {
"use strict";
var SMALL = 1e-10;

/** Returns the intersection area of a bunch of circles (where each circle
is an object having an x,y and radius property) */
circleIntersection.intersectionArea = function(circles, stats) {
venn.intersectionArea = function(circles, stats) {
// get all the intersection points of the circles
var intersectionPoints = getIntersectionPoints(circles);

// filter out points that aren't included in all the circles
var innerPoints = intersectionPoints.filter(function (p) {
return circleIntersection.containedInCircles(p, circles);
return venn.containedInCircles(p, circles);
});

var arcArea = 0, polygonArea = 0, arcs = [], i;
Expand All @@ -580,7 +578,7 @@
if (innerPoints.length > 1) {
// sort the points by angle from the center of the polygon, which lets
// us just iterate over points to get the edges
var center = circleIntersection.getCenter(innerPoints);
var center = venn.getCenter(innerPoints);
for (i = 0; i < innerPoints.length; ++i ) {
var p = innerPoints[i];
p.angle = Math.atan2(p.x - center.x, p.y - center.y);
Expand Down Expand Up @@ -617,7 +615,7 @@
// and use that angle to figure out the width of the
// arc
var a = a2 - angleDiff/2,
width = circleIntersection.distance(midPoint, {
width = venn.distance(midPoint, {
x : circle.x + circle.radius * Math.sin(a),
y : circle.y + circle.radius * Math.cos(a)
});
Expand All @@ -632,7 +630,7 @@
}
}
arcs.push(arc);
arcArea += circleIntersection.circleArea(arc.circle.radius, arc.width);
arcArea += venn.circleArea(arc.circle.radius, arc.width);
p2 = p1;
}
} else {
Expand All @@ -649,7 +647,7 @@
// the other circles
var disjoint = false;
for (i = 0; i < circles.length; ++i) {
if (circleIntersection.distance(circles[i], smallest) > Math.abs(smallest.radius - circles[i].radius)) {
if (venn.distance(circles[i], smallest) > Math.abs(smallest.radius - circles[i].radius)) {
disjoint = true;
break;
}
Expand Down Expand Up @@ -681,9 +679,9 @@
};

/** returns whether a point is contained by all of a list of circles */
circleIntersection.containedInCircles = function(point, circles) {
venn.containedInCircles = function(point, circles) {
for (var i = 0; i < circles.length; ++i) {
if (circleIntersection.distance(point, circles[i]) > circles[i].radius + SMALL) {
if (venn.distance(point, circles[i]) > circles[i].radius + SMALL) {
return false;
}
}
Expand All @@ -695,7 +693,7 @@
var ret = [];
for (var i = 0; i < circles.length; ++i) {
for (var j = i + 1; j < circles.length; ++j) {
var intersect = circleIntersection.circleCircleIntersection(circles[i],
var intersect = venn.circleCircleIntersection(circles[i],
circles[j]);
for (var k = 0; k < intersect.length; ++k) {
var p = intersect[k];
Expand All @@ -707,19 +705,19 @@
return ret;
}

circleIntersection.circleIntegral = function(r, x) {
venn.circleIntegral = function(r, x) {
var y = Math.sqrt(r * r - x * x);
return x * y + r * r * Math.atan2(x, y);
};

/** Returns the area of a circle of radius r - up to width */
circleIntersection.circleArea = function(r, width) {
return circleIntersection.circleIntegral(r, width - r) - circleIntersection.circleIntegral(r, -r);
venn.circleArea = function(r, width) {
return venn.circleIntegral(r, width - r) - venn.circleIntegral(r, -r);
};


/** euclidean distance between two points */
circleIntersection.distance = function(p1, p2) {
venn.distance = function(p1, p2) {
return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) +
(p1.y - p2.y) * (p1.y - p2.y));
};
Expand All @@ -728,7 +726,7 @@
/** Returns the overlap area of two circles of radius r1 and r2 - that
have their centers separated by distance d. Simpler faster
circle intersection for only two circles */
circleIntersection.circleOverlap = function(r1, r2, d) {
venn.circleOverlap = function(r1, r2, d) {
// no overlap
if (d >= r1 + r2) {
return 0;
Expand All @@ -741,16 +739,16 @@

var w1 = r1 - (d * d - r2 * r2 + r1 * r1) / (2 * d),
w2 = r2 - (d * d - r1 * r1 + r2 * r2) / (2 * d);
return circleIntersection.circleArea(r1, w1) + circleIntersection.circleArea(r2, w2);
return venn.circleArea(r1, w1) + venn.circleArea(r2, w2);
};


/** Given two circles (containing a x/y/radius attributes),
returns the intersecting points if possible.
note: doesn't handle cases where there are infinitely many
intersection points (circles are equivalent):, or only one intersection point*/
circleIntersection.circleCircleIntersection = function(p1, p2) {
var d = circleIntersection.distance(p1, p2),
venn.circleCircleIntersection = function(p1, p2) {
var d = venn.distance(p1, p2),
r1 = p1.radius,
r2 = p2.radius;

Expand All @@ -771,7 +769,7 @@
};

/** Returns the center of a bunch of points */
circleIntersection.getCenter = function(points) {
venn.getCenter = function(points) {
var center = { x: 0, y: 0};
for (var i =0; i < points.length; ++i ) {
center.x += points[i].x;
Expand All @@ -781,4 +779,4 @@
center.y /= points.length;
return center;
};
}(window.circleIntersection = window.circleIntersection || {}));
}(window.venn = window.venn || {}));
34 changes: 17 additions & 17 deletions venn_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,36 @@
});

test("circleIntegral", function() {
nearlyEqual(circleIntersection.circleIntegral(10, 0), 0, venn.SMALL,
nearlyEqual(venn.circleIntegral(10, 0), 0, venn.SMALL,
"empty circle test");
nearlyEqual(circleIntersection.circleIntegral(10, 10), Math.PI * 10 * 10 / 2, venn.SMALL,
nearlyEqual(venn.circleIntegral(10, 10), Math.PI * 10 * 10 / 2, venn.SMALL,
"half circle test");
});

test("circleArea", function() {
nearlyEqual(circleIntersection.circleArea(10,0), 0, venn.SMALL, "empty circle test");
nearlyEqual(circleIntersection.circleArea(10, 10), Math.PI*10*10/2, venn.SMALL,
nearlyEqual(venn.circleArea(10,0), 0, venn.SMALL, "empty circle test");
nearlyEqual(venn.circleArea(10, 10), Math.PI*10*10/2, venn.SMALL,
"half circle test");
nearlyEqual(circleIntersection.circleArea(10, 20), Math.PI*10*10, venn.SMALL,
nearlyEqual(venn.circleArea(10, 20), Math.PI*10*10, venn.SMALL,
"full circle test");
});

test("circleOverlap", function() {
nearlyEqual(circleIntersection.circleOverlap(10, 10, 200), 0, venn.SMALL,
nearlyEqual(venn.circleOverlap(10, 10, 200), 0, venn.SMALL,
"nonoverlapping circles test");

nearlyEqual(circleIntersection.circleOverlap(10, 10, 0), Math.PI*10*10, venn.SMALL,
nearlyEqual(venn.circleOverlap(10, 10, 0), Math.PI*10*10, venn.SMALL,
"full overlapping circles test");

nearlyEqual(circleIntersection.circleOverlap(10, 5, 5), Math.PI * 5 * 5, venn.SMALL,
nearlyEqual(venn.circleOverlap(10, 5, 5), Math.PI * 5 * 5, venn.SMALL,
"another fully overlapping circles test");
});

test("distanceFromIntersectArea", function() {
function testDistanceFromIntersectArea(r1, r2, overlap) {
var distance = venn.distanceFromIntersectArea(r1, r2,
overlap);
nearlyEqual(circleIntersection.circleOverlap(r1, r2, distance),
nearlyEqual(venn.circleOverlap(r1, r2, distance),
overlap,
1e-2);
}
Expand Down Expand Up @@ -86,14 +86,14 @@

test("circleCircleIntersection", function() {
var testIntersection = function(p1, p2, msg) {
var points = circleIntersection.circleCircleIntersection(p1, p2);
var points = venn.circleCircleIntersection(p1, p2);
// make sure that points are appropiately spaced
for (var i = 0; i < points.length; i++) {
var point = points[i];
nearlyEqual(circleIntersection.distance(point, p1),
nearlyEqual(venn.distance(point, p1),
p1.radius, venn.SMALL,
msg + ": test distance to p1 for point " + i);
nearlyEqual(circleIntersection.distance(point, p2),
nearlyEqual(venn.distance(point, p2),
p2.radius, venn.SMALL,
msg + ": test distance to p2 for point " + i );
}
Expand All @@ -102,12 +102,12 @@
}

// fully contained
equal(circleIntersection.circleCircleIntersection({x:0, y:3, radius:10},
equal(venn.circleCircleIntersection({x:0, y:3, radius:10},
{x:3, y:0, radius:20}).length,
0, "fully contained test");

// fully disjoint
equal(circleIntersection.circleCircleIntersection({x:0, y:0, radius:10},
equal(venn.circleCircleIntersection({x:0, y:0, radius:10},
{x:21, y:0, radius:10}).length,
0, "fully disjoint test");

Expand Down Expand Up @@ -137,7 +137,7 @@
{"x":0.276, "y":0.723, "radius":1.145},
{"x":0.141, "y":0.585, "radius":0.419}];

var area = circleIntersection.intersectionArea(circles);
var area = venn.intersectionArea(circles);
ok(area == 0);

// no intersection points, but the smallest circle is completely overlapped by each of the others
Expand All @@ -146,7 +146,7 @@
{"x":0.010, "y":0.909,"radius":1.161},
{"x":0.540, "y":0.475,"radius":0.410}];

ok(circles[3].radius * circles[3].radius * Math.PI == circleIntersection.intersectionArea(circles));
ok(circles[3].radius * circles[3].radius * Math.PI == venn.intersectionArea(circles));
});


Expand All @@ -155,7 +155,7 @@
{"x":0.945,"y":0.022,"radius":1.015},
{"x":0.021,"y":0.863,"radius":0.261},
{"x":0.528,"y":0.090,"radius":0.676}],
area = circleIntersection.intersectionArea(circles);
area = venn.intersectionArea(circles);

ok(Math.abs(area - 0.0008914) < 0.0001, area);

Expand Down

0 comments on commit fd7d81c

Please sign in to comment.