Пример #1
0
        public List <AStar_PathFinderNode> FindPath(PathPoint start, PathPoint end)
        {
            AStar_PathFinderNode parentNode;
            bool found = false;
            int  gridX = mGrid.GetUpperBound(0);
            int  gridY = mGrid.GetUpperBound(1);

            mStop    = false;
            mStopped = false;
            mOpen.Clear();
            mClose.Clear();

            sbyte[,] direction;
            if (mDiagonals)
            {
                direction = new sbyte[8, 2] {
                    { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 }
                }
            }
            ;
            else
            {
                direction = new sbyte[4, 2] {
                    { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }
                }
            };

            parentNode.G  = 0;
            parentNode.H  = mHEstimate;
            parentNode.F  = parentNode.G + parentNode.H;
            parentNode.X  = start.Z;
            parentNode.Y  = start.Y;
            parentNode.PX = parentNode.X;
            parentNode.PY = parentNode.Y;
            mOpen.Push(parentNode);
            while (mOpen.Count > 0 && !mStop)
            {
                parentNode = mOpen.Pop();

                if (parentNode.X == end.X && parentNode.Y == end.Y)
                {
                    mClose.Add(parentNode);
                    found = true;
                    break;
                }

                if (mClose.Count > mSearchLimit)
                {
                    mStopped = true;
                    return(null);
                }

                if (mPunishChangeDirection)
                {
                    mHoriz = (parentNode.X - parentNode.PX);
                }

                //Lets calculate each successors
                for (int i = 0; i < (mDiagonals ? 8 : 4); i++)
                {
                    AStar_PathFinderNode newNode;
                    newNode.X = parentNode.X + direction[i, 0];
                    newNode.Y = parentNode.Y + direction[i, 1];

                    if (newNode.X < 0 || newNode.Y < 0 || newNode.X >= gridX || newNode.Y >= gridY)
                    {
                        continue;
                    }

                    int newG;
                    if (mHeavyDiagonals && i > 3)
                    {
                        newG = parentNode.G + (int)(mGrid[newNode.X, newNode.Y] * 2.41);
                    }
                    else
                    {
                        newG = parentNode.G + mGrid[newNode.X, newNode.Y];
                    }

                    if (newG == parentNode.G)
                    {
                        //Unbrekeable
                        continue;
                    }

                    if (mPunishChangeDirection)
                    {
                        if ((newNode.X - parentNode.X) != 0)
                        {
                            if (mHoriz == 0)
                            {
                                newG += 20;
                            }
                        }
                        if ((newNode.Y - parentNode.Y) != 0)
                        {
                            if (mHoriz != 0)
                            {
                                newG += 20;
                            }
                        }
                    }

                    int foundInOpenIndex = -1;
                    for (int j = 0; j < mOpen.Count; j++)
                    {
                        if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
                        {
                            foundInOpenIndex = j;
                            break;
                        }
                    }
                    if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
                    {
                        continue;
                    }

                    int foundInCloseIndex = -1;
                    for (int j = 0; j < mClose.Count; j++)
                    {
                        if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
                        {
                            foundInCloseIndex = j;
                            break;
                        }
                    }
                    if (foundInCloseIndex != -1 && (mReopenCloseNodes || mClose[foundInCloseIndex].G <= newG))
                    {
                        continue;
                    }

                    newNode.PX = parentNode.X;
                    newNode.PY = parentNode.Y;
                    newNode.G  = newG;

                    switch (mFormula)
                    {
                    default:
                    case AStar_HeuristicFormula.Manhattan:
                        newNode.H = mHEstimate * (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
                        break;

                    case AStar_HeuristicFormula.MaxDXDY:
                        newNode.H = mHEstimate * (Math.Max(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y)));
                        break;

                    case AStar_HeuristicFormula.DiagonalShortCut:
                        int h_diagonal = Math.Min(Math.Abs(newNode.X - end.X), Math.Abs(newNode.Y - end.Y));
                        int h_straight = (Math.Abs(newNode.X - end.X) + Math.Abs(newNode.Y - end.Y));
                        newNode.H = (mHEstimate * 2) * h_diagonal + mHEstimate * (h_straight - 2 * h_diagonal);
                        break;

                    case AStar_HeuristicFormula.Euclidean:
                        newNode.H = (int)(mHEstimate * Math.Sqrt(Math.Pow((newNode.X - end.X), 2) + Math.Pow((newNode.Y - end.Y), 2)));
                        break;

                    case AStar_HeuristicFormula.EuclideanNoSQR:
                        newNode.H = (int)(mHEstimate * (Math.Pow((newNode.X - end.X), 2) + Math.Pow((newNode.Y - end.Y), 2)));
                        break;

                    case AStar_HeuristicFormula.Custom1:
                        PathPoint dxy        = new PathPoint(Math.Abs(end.X - newNode.X), Math.Abs(end.Y - newNode.Y));
                        int       Orthogonal = Math.Abs(dxy.X - dxy.Y);
                        int       Diagonal   = Math.Abs(((dxy.X + dxy.Y) - Orthogonal) / 2);
                        newNode.H = mHEstimate * (Diagonal + Orthogonal + dxy.X + dxy.Y);
                        break;
                    }
                    if (mTieBreaker)
                    {
                        int dx1   = parentNode.X - end.X;
                        int dy1   = parentNode.Y - end.Y;
                        int dx2   = start.X - end.X;
                        int dy2   = start.Y - end.Y;
                        int cross = Math.Abs(dx1 * dy2 - dx2 * dy1);
                        newNode.H = (int)(newNode.H + cross * 0.001);
                    }
                    newNode.F = newNode.G + newNode.H;

                    //It is faster if we leave the open node in the priority queue
                    //When it is removed, all nodes around will be closed, it will be ignored automatically
                    //if (foundInOpenIndex != -1)
                    //    mOpen.RemoveAt(foundInOpenIndex);

                    //if (foundInOpenIndex == -1)
                    mOpen.Push(newNode);
                }

                mClose.Add(parentNode);
            }

            if (found)
            {
                AStar_PathFinderNode fNode = mClose[mClose.Count - 1];
                for (int i = mClose.Count - 1; i >= 0; i--)
                {
                    if (fNode.PX == mClose[i].X && fNode.PY == mClose[i].Y || i == mClose.Count - 1)
                    {
                        fNode = mClose[i];
                    }
                    else
                    {
                        mClose.RemoveAt(i);
                    }
                }
                mStopped = true;
                return(mClose);
            }
            mStopped = true;
            return(null);
        }
Пример #2
0
        /// <summary>
        /// plan a safe route through the terrain, using the given start and end locations
        /// </summary>
        /// <param name="start_x_mm">starting x coordinate in mm</param>
        /// <param name="start_y_mm">starting y coordinate in mm</param>
        /// <param name="finish_x_mm">finishing x coordinate in mm</param>
        /// <param name="finish_y_mm">finishing y coordinate in mm</param>
        /// <returns>the path positions in millimetres</returns>
        public List <float> CreatePlan(float start_x_mm, float start_y_mm,
                                       float finish_x_mm, float finish_y_mm)
        {
            // get the dimension of the occupancy grid
            int dimension = navigable_space.GetLength(0);

            // calculate the start and end points on the safe navigation grid
            // which may differ from the original grid size due to the power of 2 constraint
            PathPoint PathStart = new PathPoint((int)((start_x_mm - OccupancyGridCentre_x_mm) / cellSize_mm) + (dimension / 2) + safety_offset,
                                                (int)((start_y_mm - OccupancyGridCentre_y_mm) / cellSize_mm) + (dimension / 2) + safety_offset);
            PathPoint PathEnd = new PathPoint((int)((finish_x_mm - OccupancyGridCentre_x_mm) / cellSize_mm) + (dimension / 2) + safety_offset,
                                              (int)((finish_y_mm - OccupancyGridCentre_y_mm) / cellSize_mm) + (dimension / 2) + safety_offset);

            // calculate a path, if one exists
            List <AStar_PathFinderNode> path = pathfinder.FindPath(PathStart, PathEnd);

            // convert the path into millimetres and store it in an array list
            List <float> result = new List <float>();

            if (path != null)
            {
                for (int i = 0; i < path.Count; i++)
                {
                    AStar_PathFinderNode node = path[i];
                    float x = (float)((((node.X - safety_offset) - (dimension / 2)) * cellSize_mm) + OccupancyGridCentre_x_mm);
                    float y = (float)((((node.Y - safety_offset) - (dimension / 2)) * cellSize_mm) + OccupancyGridCentre_y_mm);
                    result.Add(x);
                    result.Add(y);
                }

                if (pathSmoothing)
                {
                    ArrayList spline_x = new ArrayList();
                    ArrayList spline_y = new ArrayList();
                    float[]   pts      = new float[4 * 2];

                    int interval = 8;
                    for (int i = 0; i < result.Count; i += interval * 2)
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            int idx = i - (2 * interval * 2) + (j * interval * 2);
                            if (idx < 0)
                            {
                                idx = 0;
                            }
                            if (idx >= result.Count - 1)
                            {
                                idx = result.Count - 2;
                            }
                            pts[j * 2]       = (float)result[idx];
                            pts[(j * 2) + 1] = (float)result[idx + 1];
                        }

                        double temp     = Math.Sqrt(Math.Pow(pts[2 * 2] - pts[1 * 2], 2F) + Math.Pow(pts[(2 * 2) + 1] - pts[(1 * 2) + 1], 2F));
                        int    interpol = System.Convert.ToInt32(temp);

                        SplinePoint(pts, interpol, spline_x, spline_y);
                    }

                    if (spline_x.Count > 1)
                    {
                        List <float> smoothed_result = new List <float>();
                        smoothed_result.Add((float)result[0]);
                        smoothed_result.Add((float)result[1]);
                        for (int i = 1; i < spline_x.Count; i++)
                        {
                            float x = Convert.ToSingle((double)spline_x[i]);
                            float y = Convert.ToSingle((double)spline_y[i]);
                            smoothed_result.Add(x);
                            smoothed_result.Add(y);
                        }
                        smoothed_result.Add((float)result[result.Count - 2]);
                        smoothed_result.Add((float)result[result.Count - 1]);
                        result = smoothed_result;
                    }
                }
            }
            return(result);
        }