private static void OptimizeSegment(int startIndex, int endIndex,
                                            StopFunction stopFunction,
                                            IReadOnlyCollection <Point> inputPath,
                                            ICollection <Point> result)
        {
            Point startPoint = inputPath.ElementAt(startIndex);
            Point endPoint   = inputPath.ElementAt(endIndex);

            // if this segment is unblocked, return start + end points
            if (LineRasterizer.IsUnblocked(startPoint, endPoint, stopFunction))
            {
                result.Add(inputPath.ElementAt(startIndex));
                result.Add(inputPath.ElementAt(endIndex));
            }
            else // otherwise subdivide segment in two, and process them
            {
                int halfIndex = startIndex + (endIndex - startIndex) / 2 + 1;
                OptimizeSegment(startIndex, halfIndex - 1, stopFunction, inputPath, result);
                OptimizeSegment(halfIndex, endIndex, stopFunction, inputPath, result);
            }
        }
Пример #2
0
        private static void OptimizeSegment(Int32 startIndex, Int32 endIndex,
                                            StopFunction <Vector2> stopFunction,
                                            List <Vector2> inputPath,
                                            ICollection <Vector2> result)
        {
            Vector2 startPosition = inputPath.ElementAt(startIndex);
            Vector2 endPosition   = inputPath.ElementAt(endIndex);

            // if this segment is unblocked, return start + end points
            if (LineRasterizer.IsUnblocked(startPosition, endPosition, stopFunction))
            {
                result.Add(inputPath.ElementAt(startIndex));
                result.Add(inputPath.ElementAt(endIndex));
            }
            else         // otherwise subdivide segment in two, and process them
            {
                Int32 halfIndex = startIndex + (endIndex - startIndex) / 2 + 1;
                OptimizeSegment(startIndex, halfIndex - 1, stopFunction, inputPath, result);
                OptimizeSegment(halfIndex, endIndex, stopFunction, inputPath, result);
            }
        }
        /// <summary>
        /// This optimization should be used on limited point set (see <see cref="TooMuchPoints"/>).
        /// It searches for unblocked connection from start to end point. The end point is moved,
        /// until the connection is found (at worst the next connection = no optimizaton). If found
        /// the start point is moved to this new point, and end point is reset to end point.
        /// This continues unless we're done.
        /// </summary>
        /// <param name="inputPath">The input path.</param>
        /// <param name="stopFunction">The stop function.</param>
        /// <param name="optimizedPath">The optimized path.</param>
        /// <param name="optimizedPivotPoints">The optimized pivot points.</param>
        protected static void VisibilityOptimization(IReadOnlyCollection <Point> inputPath,
                                                     StopFunction stopFunction,
                                                     out IReadOnlyCollection <Point> optimizedPath,
                                                     out IReadOnlyCollection <Point> optimizedPivotPoints)
        {
            // creates result path
            List <Point> result = new List <Point>();

            // determines master point (one tested from), and last point (to detect cycle end)
            int   masterIndex = 0;
            int   lastIndex   = inputPath.Count - 1;
            Point masterPoint = inputPath.ElementAt(masterIndex);

            // adds first point
            result.Add(masterPoint);

            do // performs optimization loop
            {
                // starts at last points and work its way to the start point
                for (int index = Math.Min(OptimizationStep, lastIndex); index >= 0; index--)
                {
                    int   referenceIndex = Math.Min(masterIndex + index, lastIndex);
                    Point referencePoint = inputPath.ElementAt(referenceIndex);

                    // if reference point is visible from master point (or next, which is assumed as visible) reference point becomes master
                    if (referenceIndex == masterIndex + 1 || LineRasterizer.IsUnblocked(masterPoint, referencePoint, stopFunction))
                    {
                        // switches reference point as master, adding master to an optimized path
                        masterPoint = inputPath.ElementAt(referenceIndex);
                        masterIndex = referenceIndex;
                        result.Add(masterPoint);
                        break;
                    }
                }
            } while (masterIndex < lastIndex); // if we're on the last point -> terminate

            // returns the optimized path
            optimizedPath        = result;
            optimizedPivotPoints = result;
        }
        protected void AddRectangleToCache(Rectangle rectangle)
        {
            // set bits to each point inside the rectangle
            if (AreHollowAreasMinimized)
            {
                int offset = GetOffset(rectangle.Left, rectangle.Top);

                for (int y = 0; y < rectangle.Height; y++)
                {
                    for (int x = 0; x < rectangle.Width; x++)
                    {
                        Cache.Set(offset + x, true);
                    }

                    offset += Width;
                }
            }
            else // set bits of hollow rectangle only
            {
                // sides (top/right/bottom/left)
                foreach (Point point in LineRasterizer.EnumerateHorizontalLine(rectangle.Left, rectangle.Right - 2, rectangle.Top))
                {
                    SetCacheBit(point.X, point.Y);
                }
                foreach (Point point in LineRasterizer.EnumerateVerticalLine(rectangle.Right - 1, rectangle.Top, rectangle.Bottom - 2))
                {
                    SetCacheBit(point.X, point.Y);
                }
                foreach (Point point in LineRasterizer.EnumerateHorizontalLine(rectangle.Left + 1, rectangle.Right - 1, rectangle.Bottom - 1))
                {
                    SetCacheBit(point.X, point.Y);
                }
                foreach (Point point in LineRasterizer.EnumerateVerticalLine(rectangle.Left, rectangle.Top + 1, rectangle.Bottom - 1))
                {
                    SetCacheBit(point.X, point.Y);
                }
            }
        }
Пример #5
0
        /// <summary>
        /// See <see cref="BasePathfinder.OnTryFindPath"/> for more details.
        /// </summary>
        protected override bool OnTryFindPath(Point startPoint, Point endPoint,
                                              StopFunction stopFunction,
                                              out IReadOnlyCollection <Point> path,
                                              out IReadOnlyCollection <Point> pivotPoints,
                                              bool optimize = true)
        {
            // prepares main parameters
            bool         result    = false;
            List <Point> pointList = new List <Point>();

            // detects all the path segments that are passable
            IReadOnlyList <PathSegment> segments = LineRasterizer.ScanPathSegments(startPoint, endPoint, stopFunction);
            int  segmentIndex = 0;
            bool running      = true;

            while (running)
            {
                // gets this segment
                PathSegment segment        = segments[segmentIndex];
                Point       collisionPoint = segment.LastPoint;

                // adds already found points to a final path
                pointList.Add(segment.FirstPoint);
                pointList.Add(segment.LastPoint);

                // we have arrived at destination, we're done here
                if (collisionPoint == endPoint)
                {
                    result = true;
                    break;
                }

                // cirumvents the obstacle from both sides
                EvasionObstacleInfo obstacleInfo;

                // tries to circumvent the obstacle from both sides (left/right) to determine which on is shorter
                if (TryScanObstacle(collisionPoint, segment.Direction, stopFunction, segments, segmentIndex, out obstacleInfo))
                {
                    // adds better route points to our result structures, advances to the latest segment
                    segmentIndex += obstacleInfo.SegmentIndex + 1;

                    // determines left/right side paths step counts
                    int leftPathStepCount  = obstacleInfo.LeftStepCount;
                    int rightPathStepCount = obstacleInfo.TotalStepCount - leftPathStepCount;

                    // determines short path
                    IEnumerable <Point> shorterPath = leftPathStepCount < rightPathStepCount?
                                                      obstacleInfo.PivotPoints.Take(obstacleInfo.LefPointCount) :
                                                          obstacleInfo.PivotPoints.Skip(obstacleInfo.LefPointCount).Reverse();

                    // adds this path to overall path
                    pointList.AddRange(shorterPath);
                }
                else // path not found
                {
                    running = false;
                }
            }

            // returns the found path
            pivotPoints = pointList;
            path        = pointList;
            return(result);
        }