using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Web;
namespace RT.MvcWeb.Utility
{
public class MinkowskiSum
{
public class Point2D
{
public string name { get; set; }
public double x { get; set; }
public double y { get; set; }
public double deg { get; set; }
public Point2D()
{
name = string.Empty;
x = 0;
y = 0;
deg = 0;
}
public Point2D(string strName)
{
name = strName;
x = 0;
y = 0;
deg = 0;
}
public Point2D(string strName, double dX, double dY)
{
name = strName;
x = dX;
y = dY;
deg = 0;
}
public Point2D(string strName, double dX, double dY, double dDeg)
{
name = strName;
x = dX;
y = dY;
deg = dDeg;
}
public bool Equal(Point2D b)
{
return (x == b.x && y == b.y);
}
public void Offset(double dX, double dY)
{
x += dX;
y += dY;
}
public Point ToPoint()
{
return new Point((int)x, (int)y);
}
public double Angle()
{
return Math.Atan2(y, x);
}
public bool InLine(Line2D line)
{
return InLine(line.pointA, line.pointB);
}
public bool InLineX(Line2D line)
{
return InLineX(line.pointA, line.pointB);
}
public bool InLineR(Line2D line)
{
return InLineR(line.pointA, line.pointB);
}
/// <summary>
/// 判断点在线段p(1,2)内
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public bool InLine(Point2D p1, Point2D p2)
{
if (p1.x == p2.x)
{
if (this.x == p1.x)
return ((this.y - p1.y) * (this.y - p2.y) <= 0);
else
return false;
}
else if (p1.y == p2.y)
{
if (this.y == p1.y)
return ((this.x - p1.x) * (this.x - p2.x) <= 0);
else
return false;
}
else
{
double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
if (xc == this.x)
return ((this.x - p1.x) * (this.x - p2.x) <= 0);
else
return false;
}
}
/// <summary>
/// 判断点在线条经过p1,p2的线上
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public bool InLineX(Point2D p1, Point2D p2)
{
if (p1.x == p2.x)
return (this.x == p1.x);
else if (p1.y == p2.y)
return (this.y == p1.y);
else
{
double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
return (xc == this.x);
}
}
/// <summary>
/// 判断点在线条p(1,2)的右侧延长线上
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public bool InLineR(Point2D p1, Point2D p2)
{
if (p1.x == p2.x)
{
if (this.x == p1.x)
return (p2.y > p1.y && y > p2.y || p2.y < p1.y && y < p2.y);
}
else if (p1.y == p2.y)
{
if (this.y == p1.y)
return (p2.x > p1.x && x > p2.x && p2.x < p1.x && x < p2.x);
}
else
{
double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
if (xc == this.x)
return (p2.x > p1.x && x > p2.x && p2.x < p1.x && x < p2.x);
}
return false;
}
public override string ToString()
{
return string.Format("{0}({1}*{2})+{3}", name, x, y, deg);
}
}
/// <summary>
/// 有向线段(a->b)
/// </summary>
public class Line2D
{
/// <summary>
/// 两线相交的模式
/// </summary>
public enum enumCrossWay
{
enumNone ,
/// <summary>
/// 两线相交第一点
/// </summary>
enumCross1 ,
/// <summary>
/// 两线相交于中间自由点
/// </summary>
enumCrossIn ,
/// <summary>
/// 两线相交于第二点
/// </summary>
enumCross2 ,
/// <summary>
/// 两线平行相交于第一点
/// </summary>
enumMix1 ,
/// <summary>
/// 两线平行相交于中间自由点
/// </summary>
enumMixIn ,
/// <summary>
/// 两线平行相交于第二点
/// </summary>
enumMix2 ,
/// <summary>
/// 两线平行相交于延长线上的任意一点
/// </summary>
enumMixOut
}
public Point2D pointA { get; set; }
public Point2D pointB { get; set; }
public double deg { get; set; }
public Line2D(Point2D a, Point2D b)
{
pointA = a;
pointB = b;
deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
}
public Line2D(Polygon2D p, int nIndex)
{
pointA = p[nIndex % p.Count];
pointB = p[(nIndex + 1) % p.Count];
deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
}
public Line2D(Polygon2D p, int nIndex , Point2D pointStart)
{
pointA = pointStart;
pointB = p[(nIndex + 1) % p.Count];
deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
}
public double GetAngle()
{
return Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
}
/// <summary>
/// 求线段b的拐向
/// </summary>
/// <param name="b"></param>
/// <returns>0~pi:左拐,pi~2pi:右拐</returns>
public double GetOffCourse(Line2D b)
{
double dAngle2 = b.GetAngle();
double dAngle1 = this.GetAngle();
return (dAngle2 - dAngle1 + Math.PI * 2) % (Math.PI * 2);
}
public override string ToString()
{
return string.Format("{0}->{1}", pointA, pointB);
}
#region 两线段相交测试
/// <summary>
/// 搜索与多边形相交点所在的线段
/// </summary>
/// <param name="p"></param>
/// <param name="nStartIndex"></param>
/// <param name="enumWay"></param>
/// <param name="pointCross"></param>
/// <returns></returns>
public int CrossSearch(Polygon2D p, int nStartIndex, out enumCrossWay enumWay, out Point2D pointCross)
{
for (int i = nStartIndex; i < p.Count; i++)
{
Line2D b = new Line2D(p, i);
enumWay = CrossTest(b, out pointCross);
if (enumWay != enumCrossWay.enumNone)
{
if (enumWay == enumCrossWay.enumCross1 ||
enumWay == enumCrossWay.enumCrossIn)
{
if (GetOffCourse(b) < Math.PI)
{
enumWay = enumCrossWay.enumNone;
continue;
}
}
if (enumWay == enumCrossWay.enumCross2)
{
//相交于该线的终点,即相当于下一条线的起点
enumWay = enumCrossWay.enumNone;
}
else if (enumWay == enumCrossWay.enumMixOut)
{
//Line2D b2 = new Line2D(p, i + 1);
//if (GetOffCourse(b2) < Math.PI)
// enumWay = enumCrossWay.enumNone;
//相交于该线的终点,即相当于下一条线的起点
enumWay = enumCrossWay.enumNone;
}
else
return i;
}
}
enumWay = enumCrossWay.enumNone;
pointCross = new Point2D();
return -1;
}
/// <summary>
/// 两线段相交测试
/// </summary>
/// <param name="b"></param>
/// <param name="pointCross"></param>
/// <returns></returns>
public enumCrossWay CrossTest(Line2D b, out Point2D pointCross)
{
double degSub = Math.Abs(this.deg - b.deg);
if (degSub == 0 || degSub == Math.PI)
{
//平行线
if (pointB.InLine(b))
{
pointCross = new Point2D(pointB.name, pointB.x, pointB.y, pointB.deg);
if (pointB.Equal(b.pointB))