PathAStar.cs 12.4 KB
using RCS.Model.Comm;
using RCS.Model.Entity;

namespace RCS.WinClient.Service
{
    public class PathAStar
    {
        List<Base_Point> OpenList = new List<Base_Point>();
        List<Base_Point> CloseList = new List<Base_Point>();
        List<Base_Point> SurPointsList = new List<Base_Point>();

        public const int CONER = 25;
        public const int LINE = 3;
        public const int TOEND = 3;

        /// <summary>
        /// 寻找路径
        /// </summary>
        /// <param name="listApoint">可用的点</param>
        /// <param name="beginPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <param name="agv"></param>
        /// <returns></returns>
        public Base_Point GetPathPoint(List<Base_Point> listApoint, Base_Point beginPoint, Base_Point endPoint, Base_Agv agv, int flag)
        {
            if (beginPoint == null || endPoint == null)
                throw new Exception(" 查找路径失败,起点终点不能为空");

            OpenList.Add(beginPoint);
            if (flag == 1) { CloseList.Clear(); }
            int x = 0;
            while (OpenList.Count != 0)
            {
                x++;
                //按照F值从小到大排序
                //将此点从Open表剔除,并加入Close表中
                OpenList.Sort();
                Base_Point currentPoint = OpenList[0];
                OpenList.RemoveAt(0);
                CloseList.Add(currentPoint);

                //找出它相邻的点
                List<Base_Point> aroundPoints = GetAroundPoint(listApoint, currentPoint);
                if (aroundPoints.Count == 0 && OpenList.Count == 0) return currentPoint;

                foreach (Base_Point judgePoint in aroundPoints)
                {
                    if (OpenList.Contains(judgePoint))
                    {
                        var G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint, beginPoint);
                        if (G <= judgePoint.Value_G)
                        {
                            judgePoint.ParentPoint = currentPoint;
                            judgePoint.Value_G = G;
                            judgePoint.Value_H = CalcH(judgePoint, endPoint);
                            judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        }
                    }
                    else
                    {
                        //如果它们不在开始列表里, 就加入, 并设置父节点,并计算GHF
                        judgePoint.ParentPoint = currentPoint;
                        judgePoint.Value_G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint, beginPoint);
                        judgePoint.Value_H = CalcH(judgePoint, endPoint);
                        judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        OpenList.Add(judgePoint);

                        if (judgePoint.Barcode == endPoint.Barcode)
                            return judgePoint;
                    }
                }
            }
            return OpenList.Last();
        }

        /// <summary>
        /// 寻找四周点
        /// </summary>
        /// <param name="listApoint">可用点集合</param>
        /// <param name="currentPoint"></param>
        /// <returns></returns>
        public List<Base_Point> GetAroundPoint(List<Base_Point> listApoint, Base_Point currentPoint)
        {
            List<Base_Point> listPoint = new List<Base_Point>();

            //找到当前点的X+方向点,判断是否在可用点里面,再判断X+的点是否可走
            Base_Point xPos = currentPoint.XPosPoint;
            if (listApoint.Contains(xPos))
                if (CanReach(xPos, currentPoint, EnumMsg.AgvOri.X正方向))
                    listPoint.Add(xPos);

            Base_Point xNeg = currentPoint.XNegPoint;
            if (listApoint.Contains(xNeg))
                if (CanReach(xNeg, currentPoint, EnumMsg.AgvOri.X负方向))
                    listPoint.Add(xNeg);

            Base_Point yPos = currentPoint.YPosPoint;
            if (listApoint.Contains(yPos))
                if (CanReach(yPos, currentPoint, EnumMsg.AgvOri.Y正方向))
                    listPoint.Add(yPos);

            Base_Point yNeg = currentPoint.YNegPoint;
            if (listApoint.Contains(yNeg))
                if (CanReach(yNeg, currentPoint, EnumMsg.AgvOri.Y负方向))
                    listPoint.Add(yNeg);

            return listPoint;
        }

        /// <summary>
        /// 能否选择此点
        /// </summary>
        /// <param name="judgePoint">待判定的点</param>
        /// <param name="currentPoint"></param>
        /// <param name="flag">待判定点与当前点方向标识</param>
        /// <returns></returns>
        public bool CanReach(Base_Point judgePoint, Base_Point currentPoint, EnumMsg.AgvOri pathDirection)
        {
            if (judgePoint == null)
                return false;

            //关掉的点,排除
            if (CloseList.Exists(a => a.Barcode == judgePoint.Barcode))
                return false;

            switch (pathDirection)
            {
                case EnumMsg.AgvOri.X正方向:
                    //对于X+的四周点,若临时方向存在X-,则不能选择此点
                    if (judgePoint.TmpDirectionList.Exists(a => a.PathDirection == EnumMsg.AgvOri.X负方向))
                        return false;
                    //判断当前点的固定方向是否允许X+方向行走
                    if (!currentPoint.IsXPos)
                        return false;
                    break;
                case EnumMsg.AgvOri.X负方向:
                    if (judgePoint.TmpDirectionList.Exists(a => a.PathDirection == EnumMsg.AgvOri.X正方向))
                        return false;
                    if (!currentPoint.IsXNeg)
                        return false;
                    break;
                case EnumMsg.AgvOri.Y正方向:
                    if (judgePoint.TmpDirectionList.Exists(a => a.PathDirection == EnumMsg.AgvOri.Y负方向))
                        return false;
                    if (!currentPoint.IsYPos)
                        return false;
                    break;
                case EnumMsg.AgvOri.Y负方向:
                    if (judgePoint.TmpDirectionList.Exists(a => a.PathDirection == EnumMsg.AgvOri.Y正方向))
                        return false;
                    if (!currentPoint.IsYNeg)
                        return false;
                    break;
                default:
                    throw new Exception("创建路径失败:找不到此点的方向。");
            }

            return true;
        }

        /// <summary>
        /// 获取从【当前点】到【要判断的点】的行走方向
        /// </summary>
        /// <param name="judgePoint">要判断的点</param>
        /// <param name="currentPoint">当前点</param>
        /// <returns></returns>
        public EnumMsg.AgvOri GetDircition(Base_Point judgePoint, Base_Point currentPoint)
        {
            if (judgePoint.IntX == currentPoint.IntX)
            {
                if (currentPoint.YPosPoint != null && judgePoint.IntY == currentPoint.YPosPoint.IntY)
                    return EnumMsg.AgvOri.Y正方向;
                else if (currentPoint.YNegPoint != null && judgePoint.IntY == currentPoint.YNegPoint.IntY)
                    return EnumMsg.AgvOri.Y负方向;
            }
            if (judgePoint.IntY == currentPoint.IntY)
            {
                if (currentPoint.XPosPoint != null && judgePoint.IntX == currentPoint.XPosPoint.IntX)
                    return EnumMsg.AgvOri.X正方向;
                else if (currentPoint.XNegPoint != null && judgePoint.IntX == currentPoint.XNegPoint.IntX)
                    return EnumMsg.AgvOri.X负方向;
            }

            if (judgePoint.IntY != currentPoint.IntY && judgePoint.IntX != currentPoint.IntX)
            {
                return EnumMsg.AgvOri.斜向;
            }

            throw new Exception("无法找到此两点的路径方向:" + judgePoint.Barcode + "-" + currentPoint.Barcode);
        }

        /// <summary>
        /// G值权重的计算
        /// </summary>
        /// <param name="judgePoint"></param>
        /// <param name="currentPoint"></param>
        /// <returns></returns>
        public double ConditionG(Base_Point judgePoint, Base_Point currentPoint, Base_Point beginPoint)
        {
            double value = LINE;
            Base_Point parentPoint = null;

            if (currentPoint.ParentPoint != null)
            {
                parentPoint = currentPoint.ParentPoint;

                //如果是关键路段,则权重加大
                if (judgePoint.RegionName.Contains("Mutex"))
                    value = 4;
                //如果三点在一个直线上,则等于4,否则等于8
                if (parentPoint.IntX == currentPoint.IntX && judgePoint.IntX == parentPoint.IntX
                    || parentPoint.IntY == currentPoint.IntY && judgePoint.IntY == parentPoint.IntY
                    || judgePoint.ParentPoint == beginPoint)
                    value = LINE;
                else value = CONER;
            }
            //返回值加上将要行走的小车数量
            return value + judgePoint.TmpDirectionList.Count;
        }

        /// <summary>
        /// H值权重的计算
        /// </summary>
        /// <param name="judgePoint"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public double CalcH(Base_Point judgePoint, Base_Point endPoint)
        {
            //查找距离目标点的距离(X+Y)*4
            int dtX = Math.Abs(judgePoint.IntX - endPoint.IntX);
            int dtY = Math.Abs(judgePoint.IntY - endPoint.IntY);
            return (dtX + dtY) * TOEND;
            //return (dtX + dtY) * 0;
        }

        /// <summary>
        /// 寻找路径
        /// </summary>
        /// <param name="listApoint">可用的点</param>
        /// <param name="beginPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <param name="agv"></param>
        /// <returns></returns>
        public Base_Point DemoGetPathPoint(List<Base_Point> listApoint, Base_Point beginPoint, Base_Point endPoint, Base_Agv agv)
        {
            if (beginPoint == null || endPoint == null)
                throw new Exception(" 查找路径失败,起点终点不能为空");

            OpenList.Add(beginPoint);

            int x = 0;
            while (OpenList.Count != 0)
            {
                x++;
                //按照F值从小到大排序
                //将此点从Open表剔除,并加入Close表中
                OpenList.Sort();
                Base_Point currentPoint = OpenList[0];
                OpenList.RemoveAt(0);
                CloseList.Add(currentPoint);

                //找出它相邻的点
                List<Base_Point> aroundPoints = GetAroundPoint(listApoint, currentPoint);

                if (aroundPoints.Count == 0 && OpenList.Count == 0) return currentPoint;

                foreach (Base_Point judgePoint in aroundPoints)
                {
                    if (OpenList.Contains(judgePoint))
                    {
                        var G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint, beginPoint);
                        if (G <= judgePoint.Value_G)
                        {
                            judgePoint.ParentPoint = currentPoint;
                            judgePoint.Value_G = G;
                            judgePoint.Value_H = CalcH(judgePoint, endPoint);
                            judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        }
                    }
                    else
                    {
                        //如果它们不在开始列表里, 就加入, 并设置父节点,并计算GHF
                        judgePoint.ParentPoint = currentPoint;
                        judgePoint.Value_G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint, beginPoint);
                        judgePoint.Value_H = CalcH(judgePoint, endPoint);
                        judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        OpenList.Add(judgePoint);
                        if (judgePoint.Barcode == endPoint.Barcode)
                            return judgePoint;
                    }
                }
            }
            return OpenList.Last();
        }
    }
}