凸多边形Minkowski求和算法

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))
                           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值