/*最小平移向量对象:
    @axis:指示方向的单位向量
    @overlap:表示两图形在该方向上发生重叠的部分所占据的长度
*/
var MinimumTranslationVector = function (axis, overlap) {
   this.axis = axis;
   this.overlap = overlap;
};

/*重构后的separationOnAxes()方法,separationOnAxes方法返回的是阴影是否重叠。而下面的方法还能算出MTV,它会记录下受测图形重叠部分长度最小的轴,如果未发生碰撞则不会返回特殊MTV值(axis=undefined, overlap=0)*/
  minimumTranslationVector: function (axes, shape, displacement) {
      return getMTV(this, shape, displacement, axes);//返回MinimumTranslationVector对象
   }
   
/*与附录中Shape不同的地方*/
function polygonCollidesWithPolygon (p1, p2, displacement) { // displacement for p1
   var mtv1 = p1.minimumTranslationVector(p1.getAxes(), p2, displacement),
       mtv2 = p1.minimumTranslationVector(p2.getAxes(), p2, displacement);

   if (mtv1.overlap === 0 || mtv2.overlap === 0)
      return { axis: undefined, overlap: 0 };
   else
      return mtv1.overlap < mtv2.overlap ? mtv1 : mtv2;
};

// ..............................................................
// Check to see if a circle collides with another circle
// ..............................................................

function circleCollidesWithCircle (c1, c2) {
   var distance = Math.sqrt( Math.pow(c2.x - c1.x, 2) +
                             Math.pow(c2.y - c1.y, 2)),
       overlap = Math.abs(c1.radius + c2.radius) - distance;

   return overlap < 0 ?
      new MinimumTranslationVector(undefined, 0) :
      new MinimumTranslationVector(undefined, overlap);
};

// ..............................................................
// Get the polygon's point that's closest to the circle
// ..............................................................

function getPolygonPointClosestToCircle(polygon, circle) {
   var min = BIG_NUMBER,
       length,
       testPoint,
       closestPoint;
   
   for (var i=0; i < polygon.points.length; ++i) {
      testPoint = polygon.points[i];
      length = Math.sqrt(Math.pow(testPoint.x - circle.x, 2), 
                         Math.pow(testPoint.y - circle.y, 2));
      if (length < min) {
         min = length;
         closestPoint = testPoint;
      }
   }

   return closestPoint;
};

// ..............................................................
// Get the circle's axis (circle's don't have an axis, so this
// method manufactures one)
// ..............................................................

function getCircleAxis(circle, polygon, closestPoint) {
   var v1 = new Vector(new Point(circle.x, circle.y)),
       v2 = new Vector(new Point(closestPoint.x, closestPoint.y)),
       surfaceVector = v1.subtract(v2);

   return surfaceVector.normalize();
};

// ..............................................................
// Tests to see if a polygon collides with a circle
// ..............................................................

function polygonCollidesWithCircle (polygon, circle, displacement) {
   var axes = polygon.getAxes(),
       closestPoint = getPolygonPointClosestToCircle(polygon, circle);

   axes.push(getCircleAxis(circle, polygon, closestPoint));

   return polygon.minimumTranslationVector(axes, circle, displacement);
};

// ..............................................................
// Given two shapes, and a set of axes, returns the minimum
// translation vector.
// ..............................................................


function getMTV(shape1, shape2, displacement, axes) {
   var minimumOverlap = BIG_NUMBER,
       overlap,
       axisWithSmallestOverlap,
       mtv;

   for (var i=0; i < axes.length; ++i) {
      axis = axes[i];
      projection1 = shape1.project(axis);
      projection2 = shape2.project(axis);
      overlap = projection1.getOverlap(projection2);

      if (overlap === 0) {
         return new MinimumTranslationVector(undefined, 0);
      }
      else {
         if (overlap < minimumOverlap) {
            minimumOverlap = overlap;
            axisWithSmallestOverlap = axis;    
         }
      }
   }
   mtv = new MinimumTranslationVector(axisWithSmallestOverlap,
                                     minimumOverlap);
   return mtv;
};


// Constants.....................................................

var BIG_NUMBER = 1000000;