docs: function intersectionArea(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 containedInCircles(p, circles);
          });
  
          var arcArea = 0, polygonArea = 0, arcs = [], i;
  
          // if we have intersection points that are within all the circles,
          // then figure out the area contained by them
          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 = 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);
              }
              innerPoints.sort(function(a,b) { return b.angle - a.angle;});
  
              // iterate over all points, get arc between the points
              // and update the areas
              var p2 = innerPoints[innerPoints.length - 1];
              for (i = 0; i < innerPoints.length; ++i) {
                  var p1 = innerPoints[i];
  
                  // polygon area updates easily ...
                  polygonArea += (p2.x + p1.x) * (p1.y - p2.y);
  
                  // updating the arc area is a little more involved
                  var midPoint = {x : (p1.x + p2.x) / 2,
                                  y : (p1.y + p2.y) / 2},
                      arc = null;
  
                  for (var j = 0; j < p1.parentIndex.length; ++j) {
                      if (p2.parentIndex.indexOf(p1.parentIndex[j]) > -1) {
                          // figure out the angle halfway between the two points
                          // on the current circle
                          var circle = circles[p1.parentIndex[j]],
                              a1 = Math.atan2(p1.x - circle.x, p1.y - circle.y),
                              a2 = Math.atan2(p2.x - circle.x, p2.y - circle.y);
  
                          var angleDiff = (a2 - a1);
                          if (angleDiff < 0) {
                              angleDiff += 2*Math.PI;
                          }
  
                          // and use that angle to figure out the width of the
                          // arc
                          var a = a2 - angleDiff/2,
                              width = distance(midPoint, {
                                  x : circle.x + circle.radius * Math.sin(a),
                                  y : circle.y + circle.radius * Math.cos(a)
                              });
  
                          // clamp the width to the largest is can actually be
                          // (sometimes slightly overflows because of FP errors)
                          if (width > circle.radius * 2) {
                              width = circle.radius * 2;
                          }
  
                          // pick the circle whose arc has the smallest width
                          if ((arc === null) || (arc.width > width)) {
                              arc = { circle : circle,
                                      width : width,
                                      p1 : p1,
                                      p2 : p2};
                          }
                      }
                  }
  
                  if (arc !== null) {
                      arcs.push(arc);
                      arcArea += circleArea(arc.circle.radius, arc.width);
                      p2 = p1;
                  }
              }
          } else {
              // no intersection points, is either disjoint - or is completely
              // overlapped. figure out which by examining the smallest circle
              var smallest = circles[0];
              for (i = 1; i < circles.length; ++i) {
                  if (circles[i].radius < smallest.radius) {
                      smallest = circles[i];
                  }
              }
  
              // make sure the smallest circle is completely contained in all
              // the other circles
              var disjoint = false;
              for (i = 0; i < circles.length; ++i) {
                  if (distance(circles[i], smallest) > Math.abs(smallest.radius - circles[i].radius)) {
                      disjoint = true;
                      break;
                  }
              }
  
              if (disjoint) {
                  arcArea = polygonArea = 0;
  
              } else {
                  arcArea = smallest.radius * smallest.radius * Math.PI;
                  arcs.push({circle : smallest,
                             p1: { x: smallest.x,        y : smallest.y + smallest.radius},
                             p2: { x: smallest.x - SMALL, y : smallest.y + smallest.radius},
                             width : smallest.radius * 2 });
              }
          }
  
          polygonArea /= 2;
          if (stats) {
              stats.area = arcArea + polygonArea;
              stats.arcArea = arcArea;
              stats.polygonArea = polygonArea;
              stats.arcs = arcs;
              stats.innerPoints = innerPoints;
              stats.intersectionPoints = intersectionPoints;
          }
  
          return arcArea + polygonArea;
      }