PathAStar.cs 12 KB
using XingYe_ACS.BaseStruct;
using XingYe_ACS.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XingYe_ACS.Business
{
    public class PathAStar
    {
        List<Point> OpenList = new List<Point>();
        List<Point> CloseList = new List<Point>();
        List<Point> SurPointsList = new List<Point>();

        public const int CONER = 10;
        public const int LINE = 4;
        public const int TOEND = 4;

        /// <summary>
        /// 寻找路径
        /// </summary>
        /// <param name="listApoint">可用的点</param>
        /// <param name="beginPoint">起点</param>
        /// <param name="endPoint">终点</param>
        /// <param name="agv"></param>
        /// <returns></returns>
        public Point GetPathPoint(List<Point> listApoint, Point beginPoint, Point endPoint, 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();
                Point currentPoint = OpenList[0];
                OpenList.RemoveAt(0);
                CloseList.Add(currentPoint);

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

                foreach (Point judgePoint in aroundPoints)
                {
                    if (OpenList.Contains(judgePoint))
                    {
                        var G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint);
                        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);
                        judgePoint.Value_H = CalcH(judgePoint, endPoint);
                        judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        OpenList.Add(judgePoint);

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

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

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

            Point xNeg = currentPoint.xNegPoint;
            if (listApoint.Contains(xNeg))
                if (CanReach(xNeg, currentPoint, EnumMsg.OriType.X负方向))
                    listPoint.Add(xNeg);

            Point yPos = currentPoint.yPosPoint;
            if (listApoint.Contains(yPos))
                if (CanReach(yPos, currentPoint, EnumMsg.OriType.Y正方向))
                    listPoint.Add(yPos);

            Point yNeg = currentPoint.yNegPoint;
            if (listApoint.Contains(yNeg))
                if (CanReach(yNeg, currentPoint, EnumMsg.OriType.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(Point judgePoint, Point currentPoint, EnumMsg.OriType pathDirection)
        {
            if (judgePoint == null)
                return false;

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

            switch (pathDirection)
            {
                case EnumMsg.OriType.X正方向:
                    //对于X+的四周点,若临时方向存在X-,则不能选择此点
                    if (judgePoint.tmpDirectionList.Exists(a => a.pathDirection == EnumMsg.OriType.X负方向))
                        return false;
                    //判断当前点的固定方向是否允许X+方向行走
                    if (!currentPoint.isXPos)
                        return false;
                    break;
                case EnumMsg.OriType.X负方向:
                    if (judgePoint.tmpDirectionList.Exists(a => a.pathDirection == EnumMsg.OriType.X正方向))
                        return false;
                    if (!currentPoint.isXNeg)
                        return false;
                    break;
                case EnumMsg.OriType.Y正方向:
                    if (judgePoint.tmpDirectionList.Exists(a => a.pathDirection == EnumMsg.OriType.Y负方向))
                        return false;
                    if (!currentPoint.isYPos)
                        return false;
                    break;
                case EnumMsg.OriType.Y负方向:
                    if (judgePoint.tmpDirectionList.Exists(a => a.pathDirection == EnumMsg.OriType.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.OriType GetDircition(Point judgePoint, Point currentPoint)
        {
            if (judgePoint.intX == currentPoint.intX)
            {
                if (currentPoint.yPosPoint != null && judgePoint.intY == currentPoint.yPosPoint.intY)
                    return EnumMsg.OriType.Y正方向;
                else if (currentPoint.yNegPoint != null && judgePoint.intY == currentPoint.yNegPoint.intY)
                    return EnumMsg.OriType.Y负方向;
            }
            if (judgePoint.intY == currentPoint.intY)
            {
                if (currentPoint.xPosPoint != null && judgePoint.intX == currentPoint.xPosPoint.intX)
                    return EnumMsg.OriType.X正方向;
                else if (currentPoint.xNegPoint != null && judgePoint.intX == currentPoint.xNegPoint.intX)
                    return EnumMsg.OriType.X负方向;
            }
            throw new Exception("无法找到此两点的路径方向:" + judgePoint.strBarcode + "-" + currentPoint.strBarcode);
        }

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

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

                //如果是关键路段,则权重加大
                if (judgePoint.strRegionName.Contains("Mutex"))
                    value = 4;
                //如果三点在一个直线上,则等于4,否则等于8
                if ((parentPoint.intX == currentPoint.intX && judgePoint.intX == parentPoint.intX)
                   || (parentPoint.intY == currentPoint.intY && judgePoint.intY == parentPoint.intY))
                    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(Point judgePoint, 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 Point DemoGetPathPoint(List<Point> listApoint, Point beginPoint, Point endPoint, 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();
                Point currentPoint = OpenList[0];
                OpenList.RemoveAt(0);
                CloseList.Add(currentPoint);

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

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

                foreach (Point judgePoint in aroundPoints)
                {
                    if (OpenList.Contains(judgePoint))
                    {
                        var G = currentPoint.Value_G + ConditionG(judgePoint, currentPoint);
                        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);
                        judgePoint.Value_H = CalcH(judgePoint, endPoint);
                        judgePoint.Value_F = judgePoint.Value_G + judgePoint.Value_H;
                        OpenList.Add(judgePoint);
                        if (judgePoint.strBarcode == endPoint.strBarcode)
                            return judgePoint;
                    }
                }
            }
            return OpenList.Last();
        }
    }
}