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); } }
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); } } }
/// <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); }