remove old projekt
parent
678ca8e251
commit
287877c107
|
@ -1,128 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Roy_T.AStar.Collections
|
||||
{
|
||||
// C# Adaptation of a min heap built for C++ by Robin Thomas
|
||||
// Original source code at: https://github.com/robin-thomas/min-heap
|
||||
|
||||
internal sealed class MinHeap<T>
|
||||
where T : IComparable<T>
|
||||
{
|
||||
private readonly List<T> Items;
|
||||
|
||||
public MinHeap()
|
||||
{
|
||||
this.Items = new List<T>();
|
||||
}
|
||||
|
||||
public int Count => this.Items.Count;
|
||||
|
||||
public T Peek() => this.Items[0];
|
||||
|
||||
public void Insert(T item)
|
||||
{
|
||||
this.Items.Add(item);
|
||||
this.SortItem(item);
|
||||
}
|
||||
|
||||
public T Extract()
|
||||
{
|
||||
var node = this.Items[0];
|
||||
|
||||
this.ReplaceFirstItemWithLastItem();
|
||||
this.Heapify(0);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public void Remove(T item)
|
||||
{
|
||||
if (this.Count < 2)
|
||||
{
|
||||
this.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = this.Items.IndexOf(item);
|
||||
if (index >= 0)
|
||||
{
|
||||
this.Items[index] = this.Items[this.Items.Count - 1];
|
||||
this.Items.RemoveAt(this.Items.Count - 1);
|
||||
|
||||
this.Heapify(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => this.Items.Clear();
|
||||
|
||||
private void ReplaceFirstItemWithLastItem()
|
||||
{
|
||||
this.Items[0] = this.Items[this.Items.Count - 1];
|
||||
this.Items.RemoveAt(this.Items.Count - 1);
|
||||
}
|
||||
|
||||
private void SortItem(T item)
|
||||
{
|
||||
var index = this.Items.Count - 1;
|
||||
|
||||
while (HasParent(index))
|
||||
{
|
||||
var parentIndex = GetParentIndex(index);
|
||||
if (ItemAIsSmallerThanItemB(item, this.Items[parentIndex]))
|
||||
{
|
||||
this.Items[index] = this.Items[parentIndex];
|
||||
index = parentIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.Items[index] = item;
|
||||
}
|
||||
|
||||
private void Heapify(int startIndex)
|
||||
{
|
||||
var bestIndex = startIndex;
|
||||
|
||||
if (this.HasLeftChild(startIndex))
|
||||
{
|
||||
var leftChildIndex = GetLeftChildIndex(startIndex);
|
||||
if (ItemAIsSmallerThanItemB(this.Items[leftChildIndex], this.Items[bestIndex]))
|
||||
{
|
||||
bestIndex = leftChildIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.HasRightChild(startIndex))
|
||||
{
|
||||
var rightChildIndex = GetRightChildIndex(startIndex);
|
||||
if (ItemAIsSmallerThanItemB(this.Items[rightChildIndex], this.Items[bestIndex]))
|
||||
{
|
||||
bestIndex = rightChildIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIndex != startIndex)
|
||||
{
|
||||
var temp = this.Items[bestIndex];
|
||||
this.Items[bestIndex] = this.Items[startIndex];
|
||||
this.Items[startIndex] = temp;
|
||||
this.Heapify(bestIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ItemAIsSmallerThanItemB(T a, T b) => a.CompareTo(b) < 0;
|
||||
|
||||
private static bool HasParent(int index) => index > 0;
|
||||
private bool HasLeftChild(int index) => GetLeftChildIndex(index) < this.Items.Count;
|
||||
private bool HasRightChild(int index) => GetRightChildIndex(index) < this.Items.Count;
|
||||
|
||||
private static int GetParentIndex(int i) => (i - 1) / 2;
|
||||
private static int GetLeftChildIndex(int i) => (2 * i) + 1;
|
||||
private static int GetRightChildIndex(int i) => (2 * i) + 2;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Graphs
|
||||
{
|
||||
public sealed class Edge : IEdge
|
||||
{
|
||||
private Velocity traversalVelocity;
|
||||
|
||||
public Edge(INode start, INode end, Velocity traversalVelocity)
|
||||
{
|
||||
this.Start = start;
|
||||
this.End = end;
|
||||
|
||||
this.Distance = Distance.BeweenPositions(start.Position, end.Position);
|
||||
this.TraversalVelocity = traversalVelocity;
|
||||
}
|
||||
|
||||
public Velocity TraversalVelocity
|
||||
{
|
||||
get => this.traversalVelocity;
|
||||
set
|
||||
{
|
||||
this.traversalVelocity = value;
|
||||
this.TraversalDuration = this.Distance / value;
|
||||
}
|
||||
}
|
||||
|
||||
public Duration TraversalDuration { get; private set; }
|
||||
|
||||
public Distance Distance { get; }
|
||||
|
||||
public INode Start { get; }
|
||||
public INode End { get; }
|
||||
|
||||
public override string ToString() => $"{this.Start} -> {this.End} @ {this.TraversalVelocity}";
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Graphs
|
||||
{
|
||||
public interface IEdge
|
||||
{
|
||||
Velocity TraversalVelocity { get; set; }
|
||||
Duration TraversalDuration { get; }
|
||||
Distance Distance { get; }
|
||||
INode Start { get; }
|
||||
INode End { get; }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Graphs
|
||||
{
|
||||
public interface INode
|
||||
{
|
||||
Position Position { get; }
|
||||
IList<IEdge> Incoming { get; }
|
||||
IList<IEdge> Outgoing { get; }
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Graphs
|
||||
{
|
||||
public sealed class Node : INode
|
||||
{
|
||||
public Node(Position position)
|
||||
{
|
||||
this.Incoming = new List<IEdge>(0);
|
||||
this.Outgoing = new List<IEdge>(0);
|
||||
|
||||
this.Position = position;
|
||||
}
|
||||
|
||||
public IList<IEdge> Incoming { get; }
|
||||
public IList<IEdge> Outgoing { get; }
|
||||
|
||||
public Position Position { get; }
|
||||
|
||||
internal void Connect(INode node, Velocity traversalVelocity)
|
||||
{
|
||||
var edge = new Edge(this, node, traversalVelocity);
|
||||
this.Outgoing.Add(edge);
|
||||
node.Incoming.Add(edge);
|
||||
}
|
||||
|
||||
internal void Disconnect(INode node)
|
||||
{
|
||||
for (var i = this.Outgoing.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var edge = this.Outgoing[i];
|
||||
if (edge.End == node)
|
||||
{
|
||||
this.Outgoing.Remove(edge);
|
||||
node.Incoming.Remove(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => this.Position.ToString();
|
||||
}
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Roy_T.AStar.Graphs;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Grids
|
||||
{
|
||||
public sealed class Grid
|
||||
{
|
||||
private readonly Node[,] Nodes;
|
||||
|
||||
public static Grid CreateGridWithLateralConnections(GridSize gridSize, Size cellSize, Velocity traversalVelocity)
|
||||
{
|
||||
CheckArguments(gridSize, cellSize, traversalVelocity);
|
||||
|
||||
var grid = new Grid(gridSize, cellSize);
|
||||
|
||||
grid.CreateLateralConnections(traversalVelocity);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public static Grid CreateGridWithDiagonalConnections(GridSize gridSize, Size cellSize, Velocity traversalVelocity)
|
||||
{
|
||||
CheckArguments(gridSize, cellSize, traversalVelocity);
|
||||
|
||||
var grid = new Grid(gridSize, cellSize);
|
||||
|
||||
grid.CreateDiagonalConnections(traversalVelocity);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
public static Grid CreateGridWithLateralAndDiagonalConnections(GridSize gridSize, Size cellSize, Velocity traversalVelocity)
|
||||
{
|
||||
CheckArguments(gridSize, cellSize, traversalVelocity);
|
||||
|
||||
var grid = new Grid(gridSize, cellSize);
|
||||
|
||||
grid.CreateDiagonalConnections(traversalVelocity);
|
||||
grid.CreateLateralConnections(traversalVelocity);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private static void CheckArguments(GridSize gridSize, Size cellSize, Velocity defaultSpeed)
|
||||
{
|
||||
if (gridSize.Columns < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(gridSize), $"Argument {nameof(gridSize.Columns)} is {gridSize.Columns} but should be >= 1");
|
||||
}
|
||||
|
||||
if (gridSize.Rows < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(gridSize), $"Argument {nameof(gridSize.Rows)} is {gridSize.Rows} but should be >= 1");
|
||||
}
|
||||
|
||||
if (cellSize.Width <= Distance.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(cellSize), $"Argument {nameof(cellSize.Width)} is {cellSize.Width} but should be > {Distance.Zero}");
|
||||
}
|
||||
|
||||
if (cellSize.Height <= Distance.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(cellSize), $"Argument {nameof(cellSize.Height)} is {cellSize.Height} but should be > {Distance.Zero}");
|
||||
}
|
||||
|
||||
if (defaultSpeed.MetersPerSecond <= 0.0f)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(defaultSpeed), $"Argument {nameof(defaultSpeed)} is {defaultSpeed} but should be > 0.0 m/s");
|
||||
}
|
||||
}
|
||||
|
||||
private Grid(GridSize gridSize, Size cellSize)
|
||||
{
|
||||
this.GridSize = gridSize;
|
||||
this.Nodes = new Node[gridSize.Columns, gridSize.Rows];
|
||||
|
||||
this.CreateNodes(cellSize);
|
||||
}
|
||||
|
||||
private void CreateNodes(Size cellSize)
|
||||
{
|
||||
for (var x = 0; x < this.Columns; x++)
|
||||
{
|
||||
for (var y = 0; y < this.Rows; y++)
|
||||
{
|
||||
this.Nodes[x, y] = new Node(Position.FromOffset(cellSize.Width * x, cellSize.Height * y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateLateralConnections(Velocity defaultSpeed)
|
||||
{
|
||||
for (var x = 0; x < this.Columns; x++)
|
||||
{
|
||||
for (var y = 0; y < this.Rows; y++)
|
||||
{
|
||||
var node = this.Nodes[x, y];
|
||||
|
||||
if (x < this.Columns - 1)
|
||||
{
|
||||
var eastNode = this.Nodes[x + 1, y];
|
||||
node.Connect(eastNode, defaultSpeed);
|
||||
eastNode.Connect(node, defaultSpeed);
|
||||
}
|
||||
|
||||
if (y < this.Rows - 1)
|
||||
{
|
||||
var southNode = this.Nodes[x, y + 1];
|
||||
node.Connect(southNode, defaultSpeed);
|
||||
southNode.Connect(node, defaultSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateDiagonalConnections(Velocity defaultSpeed)
|
||||
{
|
||||
for (var x = 0; x < this.Columns; x++)
|
||||
{
|
||||
for (var y = 0; y < this.Rows; y++)
|
||||
{
|
||||
var node = this.Nodes[x, y];
|
||||
|
||||
if (x < this.Columns - 1 && y < this.Rows - 1)
|
||||
{
|
||||
var southEastNode = this.Nodes[x + 1, y + 1];
|
||||
node.Connect(southEastNode, defaultSpeed);
|
||||
southEastNode.Connect(node, defaultSpeed);
|
||||
}
|
||||
|
||||
if (x > 0 && y < this.Rows - 1)
|
||||
{
|
||||
var southWestNode = this.Nodes[x - 1, y + 1];
|
||||
node.Connect(southWestNode, defaultSpeed);
|
||||
southWestNode.Connect(node, defaultSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GridSize GridSize { get; }
|
||||
|
||||
public int Columns => this.GridSize.Columns;
|
||||
|
||||
public int Rows => this.GridSize.Rows;
|
||||
|
||||
public INode GetNode(GridPosition position) => this.Nodes[position.X, position.Y];
|
||||
|
||||
public IReadOnlyList<INode> GetAllNodes()
|
||||
{
|
||||
var list = new List<INode>(this.Columns * this.Rows);
|
||||
|
||||
for (var x = 0; x < this.Columns; x++)
|
||||
{
|
||||
for (var y = 0; y < this.Rows; y++)
|
||||
{
|
||||
list.Add(this.Nodes[x, y]);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public void DisconnectNode(GridPosition position)
|
||||
{
|
||||
var node = this.Nodes[position.X, position.Y];
|
||||
|
||||
foreach (var outgoingEdge in node.Outgoing)
|
||||
{
|
||||
var opposite = outgoingEdge.End;
|
||||
opposite.Incoming.Remove(outgoingEdge);
|
||||
}
|
||||
|
||||
node.Outgoing.Clear();
|
||||
|
||||
foreach (var incomingEdge in node.Incoming)
|
||||
{
|
||||
var opposite = incomingEdge.Start;
|
||||
opposite.Outgoing.Remove(incomingEdge);
|
||||
}
|
||||
|
||||
node.Incoming.Clear();
|
||||
}
|
||||
|
||||
public void RemoveDiagonalConnectionsIntersectingWithNode(GridPosition position)
|
||||
{
|
||||
var left = new GridPosition(position.X - 1, position.Y);
|
||||
var top = new GridPosition(position.X, position.Y - 1);
|
||||
var right = new GridPosition(position.X + 1, position.Y);
|
||||
var bottom = new GridPosition(position.X, position.Y + 1);
|
||||
|
||||
if (this.IsInsideGrid(left) && this.IsInsideGrid(top))
|
||||
{
|
||||
this.RemoveEdge(left, top);
|
||||
this.RemoveEdge(top, left);
|
||||
}
|
||||
|
||||
if (this.IsInsideGrid(top) && this.IsInsideGrid(right))
|
||||
{
|
||||
this.RemoveEdge(top, right);
|
||||
this.RemoveEdge(right, top);
|
||||
}
|
||||
|
||||
if (this.IsInsideGrid(right) && this.IsInsideGrid(bottom))
|
||||
{
|
||||
this.RemoveEdge(right, bottom);
|
||||
this.RemoveEdge(bottom, right);
|
||||
}
|
||||
|
||||
if (this.IsInsideGrid(bottom) && this.IsInsideGrid(left))
|
||||
{
|
||||
this.RemoveEdge(bottom, left);
|
||||
this.RemoveEdge(left, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveEdge(GridPosition from, GridPosition to)
|
||||
{
|
||||
var fromNode = this.Nodes[from.X, from.Y];
|
||||
var toNode = this.Nodes[to.X, to.Y];
|
||||
|
||||
fromNode.Disconnect(toNode);
|
||||
}
|
||||
|
||||
private bool IsInsideGrid(GridPosition position) => position.X >= 0 && position.X < this.Columns && position.Y >= 0 && position.Y < this.Rows;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Roy_T.AStar.Graphs;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Paths
|
||||
{
|
||||
public sealed class Path
|
||||
{
|
||||
public Path(PathType type, IReadOnlyList<IEdge> edges)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Edges = edges;
|
||||
|
||||
for (var i = 0; i < this.Edges.Count; i++)
|
||||
{
|
||||
this.Duration += this.Edges[i].TraversalDuration;
|
||||
this.Distance += this.Edges[i].Distance;
|
||||
}
|
||||
}
|
||||
|
||||
public PathType Type { get; }
|
||||
|
||||
public Duration Duration { get; }
|
||||
|
||||
public IReadOnlyList<IEdge> Edges { get; }
|
||||
public Distance Distance { get; }
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Roy_T.AStar.Collections;
|
||||
using Roy_T.AStar.Graphs;
|
||||
using Roy_T.AStar.Grids;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Paths
|
||||
{
|
||||
public sealed class PathFinder
|
||||
{
|
||||
private readonly MinHeap<PathFinderNode> Interesting;
|
||||
private readonly Dictionary<INode, PathFinderNode> Nodes;
|
||||
private readonly PathReconstructor PathReconstructor;
|
||||
|
||||
private PathFinderNode NodeClosestToGoal;
|
||||
|
||||
public PathFinder()
|
||||
{
|
||||
this.Interesting = new MinHeap<PathFinderNode>();
|
||||
this.Nodes = new Dictionary<INode, PathFinderNode>();
|
||||
this.PathReconstructor = new PathReconstructor();
|
||||
}
|
||||
|
||||
public Path FindPath(GridPosition start, GridPosition end, Grid grid)
|
||||
{
|
||||
var startNode = grid.GetNode(start);
|
||||
var endNode = grid.GetNode(end);
|
||||
|
||||
var maximumVelocity = grid.GetAllNodes().SelectMany(n => n.Outgoing).Select(e => e.TraversalVelocity).Max();
|
||||
|
||||
return this.FindPath(startNode, endNode, maximumVelocity);
|
||||
}
|
||||
|
||||
public Path FindPath(GridPosition start, GridPosition end, Grid grid, Velocity maximumVelocity)
|
||||
{
|
||||
var startNode = grid.GetNode(start);
|
||||
var endNode = grid.GetNode(end);
|
||||
|
||||
return this.FindPath(startNode, endNode, maximumVelocity);
|
||||
}
|
||||
|
||||
public Path FindPath(INode start, INode goal, Velocity maximumVelocity)
|
||||
{
|
||||
this.ResetState();
|
||||
this.AddFirstNode(start, goal, maximumVelocity);
|
||||
|
||||
while (this.Interesting.Count > 0)
|
||||
{
|
||||
var current = this.Interesting.Extract();
|
||||
if (GoalReached(goal, current))
|
||||
{
|
||||
return this.PathReconstructor.ConstructPathTo(current.Node, goal);
|
||||
}
|
||||
|
||||
this.UpdateNodeClosestToGoal(current);
|
||||
|
||||
foreach (var edge in current.Node.Outgoing)
|
||||
{
|
||||
var oppositeNode = edge.End;
|
||||
var costSoFar = current.DurationSoFar + edge.TraversalDuration;
|
||||
|
||||
if (this.Nodes.TryGetValue(oppositeNode, out var node))
|
||||
{
|
||||
this.UpdateExistingNode(goal, maximumVelocity, current, edge, oppositeNode, costSoFar, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.InsertNode(oppositeNode, edge, goal, costSoFar, maximumVelocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.PathReconstructor.ConstructPathTo(this.NodeClosestToGoal.Node, goal);
|
||||
}
|
||||
|
||||
private void ResetState()
|
||||
{
|
||||
this.Interesting.Clear();
|
||||
this.Nodes.Clear();
|
||||
this.PathReconstructor.Clear();
|
||||
this.NodeClosestToGoal = null;
|
||||
}
|
||||
|
||||
private void AddFirstNode(INode start, INode goal, Velocity maximumVelocity)
|
||||
{
|
||||
var head = new PathFinderNode(start, Duration.Zero, ExpectedDuration(start, goal, maximumVelocity));
|
||||
this.Interesting.Insert(head);
|
||||
this.Nodes.Add(head.Node, head);
|
||||
this.NodeClosestToGoal = head;
|
||||
}
|
||||
|
||||
private static bool GoalReached(INode goal, PathFinderNode current) => current.Node == goal;
|
||||
|
||||
private void UpdateNodeClosestToGoal(PathFinderNode current)
|
||||
{
|
||||
if (current.ExpectedRemainingTime < this.NodeClosestToGoal.ExpectedRemainingTime)
|
||||
{
|
||||
this.NodeClosestToGoal = current;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateExistingNode(INode goal, Velocity maximumVelocity, PathFinderNode current, IEdge edge, INode oppositeNode, Duration costSoFar, PathFinderNode node)
|
||||
{
|
||||
if (node.DurationSoFar > costSoFar)
|
||||
{
|
||||
this.Interesting.Remove(node);
|
||||
this.InsertNode(oppositeNode, edge, goal, costSoFar, maximumVelocity);
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertNode(INode current, IEdge via, INode goal, Duration costSoFar, Velocity maximumVelocity)
|
||||
{
|
||||
this.PathReconstructor.SetCameFrom(current, via);
|
||||
|
||||
var node = new PathFinderNode(current, costSoFar, ExpectedDuration(current, goal, maximumVelocity));
|
||||
this.Interesting.Insert(node);
|
||||
this.Nodes[current] = node;
|
||||
}
|
||||
|
||||
public static Duration ExpectedDuration(INode a, INode b, Velocity maximumVelocity)
|
||||
=> Distance.BeweenPositions(a.Position, b.Position) / maximumVelocity;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using System;
|
||||
using Roy_T.AStar.Graphs;
|
||||
using Roy_T.AStar.Primitives;
|
||||
|
||||
namespace Roy_T.AStar.Paths
|
||||
{
|
||||
internal sealed class PathFinderNode : IComparable<PathFinderNode>
|
||||
{
|
||||
public PathFinderNode(INode node, Duration durationSoFar, Duration expectedRemainingTime)
|
||||
{
|
||||
this.Node = node;
|
||||
this.DurationSoFar = durationSoFar;
|
||||
this.ExpectedRemainingTime = expectedRemainingTime;
|
||||
this.ExpectedTotalTime = this.DurationSoFar + this.ExpectedRemainingTime;
|
||||
}
|
||||
|
||||
public INode Node { get; }
|
||||
public Duration DurationSoFar { get; }
|
||||
public Duration ExpectedRemainingTime { get; }
|
||||
public Duration ExpectedTotalTime { get; }
|
||||
|
||||
public int CompareTo(PathFinderNode other) => this.ExpectedTotalTime.CompareTo(other.ExpectedTotalTime);
|
||||
public override string ToString() => $"📍{{{this.Node.Position.X}, {this.Node.Position.Y}}}, ⏱~{this.ExpectedTotalTime}";
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Roy_T.AStar.Graphs;
|
||||
|
||||
namespace Roy_T.AStar.Paths
|
||||
{
|
||||
internal sealed class PathReconstructor
|
||||
{
|
||||
private readonly Dictionary<INode, IEdge> CameFrom;
|
||||
|
||||
public PathReconstructor()
|
||||
{
|
||||
this.CameFrom = new Dictionary<INode, IEdge>();
|
||||
}
|
||||
|
||||
public void SetCameFrom(INode node, IEdge via)
|
||||
=> this.CameFrom[node] = via;
|
||||
|
||||
public Path ConstructPathTo(INode node, INode goal)
|
||||
{
|
||||
var current = node;
|
||||
var edges = new List<IEdge>();
|
||||
|
||||
while (this.CameFrom.TryGetValue(current, out var via))
|
||||
{
|
||||
edges.Add(via);
|
||||
current = via.Start;
|
||||
}
|
||||
|
||||
edges.Reverse();
|
||||
|
||||
var type = node == goal ? PathType.Complete : PathType.ClosestApproach;
|
||||
return new Path(type, edges);
|
||||
}
|
||||
|
||||
public void Clear() => this.CameFrom.Clear();
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Roy_T.AStar.Paths
|
||||
{
|
||||
public enum PathType
|
||||
{
|
||||
Complete,
|
||||
ClosestApproach
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct Distance : IComparable<Distance>, IEquatable<Distance>
|
||||
{
|
||||
public static Distance Zero => new Distance(0);
|
||||
|
||||
private Distance(float meters)
|
||||
{
|
||||
this.Meters = meters;
|
||||
}
|
||||
|
||||
public float Meters { get; }
|
||||
|
||||
public static Distance FromMeters(float meters) => new Distance(meters);
|
||||
|
||||
public static Distance BeweenPositions(Position a, Position b)
|
||||
{
|
||||
var sX = a.X;
|
||||
var sY = a.Y;
|
||||
var eX = b.X;
|
||||
var eY = b.Y;
|
||||
|
||||
var d0 = (eX - sX) * (eX - sX);
|
||||
var d1 = (eY - sY) * (eY - sY);
|
||||
|
||||
return FromMeters((float)Math.Sqrt(d0 + d1));
|
||||
}
|
||||
|
||||
public static Distance operator +(Distance a, Distance b)
|
||||
=> new Distance(a.Meters + b.Meters);
|
||||
|
||||
public static Distance operator -(Distance a, Distance b)
|
||||
=> new Distance(a.Meters - b.Meters);
|
||||
|
||||
public static Distance operator *(Distance a, float b)
|
||||
=> new Distance(a.Meters * b);
|
||||
|
||||
public static Distance operator /(Distance a, float b)
|
||||
=> new Distance(a.Meters / b);
|
||||
|
||||
public static bool operator >(Distance a, Distance b)
|
||||
=> a.Meters > b.Meters;
|
||||
|
||||
public static bool operator <(Distance a, Distance b)
|
||||
=> a.Meters < b.Meters;
|
||||
|
||||
public static bool operator >=(Distance a, Distance b)
|
||||
=> a.Meters >= b.Meters;
|
||||
|
||||
public static bool operator <=(Distance a, Distance b)
|
||||
=> a.Meters <= b.Meters;
|
||||
|
||||
public static bool operator ==(Distance a, Distance b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(Distance a, Distance b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public static Duration operator /(Distance distance, Velocity velocity)
|
||||
=> Duration.FromSeconds(distance.Meters / velocity.MetersPerSecond);
|
||||
|
||||
public override string ToString() => $"{this.Meters:F2}m";
|
||||
|
||||
public override bool Equals(object obj) => obj is Distance distance && this.Equals(distance);
|
||||
public bool Equals(Distance other) => this.Meters == other.Meters;
|
||||
|
||||
public int CompareTo(Distance other) => this.Meters.CompareTo(other.Meters);
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.Meters.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct Duration : IComparable<Duration>, IEquatable<Duration>
|
||||
{
|
||||
public static Duration Zero => new Duration(0);
|
||||
|
||||
private Duration(float seconds)
|
||||
{
|
||||
this.Seconds = seconds;
|
||||
}
|
||||
|
||||
public float Seconds { get; }
|
||||
|
||||
public static Duration FromSeconds(float seconds) => new Duration(seconds);
|
||||
|
||||
public static Duration operator +(Duration a, Duration b)
|
||||
=> new Duration(a.Seconds + b.Seconds);
|
||||
|
||||
public static Duration operator -(Duration a, Duration b)
|
||||
=> new Duration(a.Seconds - b.Seconds);
|
||||
|
||||
public static bool operator >(Duration a, Duration b)
|
||||
=> a.Seconds > b.Seconds;
|
||||
|
||||
public static bool operator <(Duration a, Duration b)
|
||||
=> a.Seconds < b.Seconds;
|
||||
|
||||
public static bool operator >=(Duration a, Duration b)
|
||||
=> a.Seconds >= b.Seconds;
|
||||
|
||||
public static bool operator <=(Duration a, Duration b)
|
||||
=> a.Seconds <= b.Seconds;
|
||||
|
||||
public static bool operator ==(Duration a, Duration b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(Duration a, Duration b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"{this.Seconds:F2}s";
|
||||
|
||||
public override bool Equals(object obj) => obj is Duration duration && this.Equals(duration);
|
||||
|
||||
public bool Equals(Duration other) => this.Seconds == other.Seconds;
|
||||
|
||||
public int CompareTo(Duration other) => this.Seconds.CompareTo(other.Seconds);
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.Seconds.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct GridPosition : IEquatable<GridPosition>
|
||||
{
|
||||
public static GridPosition Zero => new GridPosition(0, 0);
|
||||
|
||||
public GridPosition(int x, int y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
|
||||
public static bool operator ==(GridPosition a, GridPosition b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(GridPosition a, GridPosition b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"({this.X}, {this.Y})";
|
||||
|
||||
public override bool Equals(object obj) => obj is GridPosition GridPosition && this.Equals(GridPosition);
|
||||
|
||||
public bool Equals(GridPosition other) => this.X == other.X && this.Y == other.Y;
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.X + this.Y;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct GridSize : IEquatable<GridSize>
|
||||
{
|
||||
public GridSize(int columns, int rows)
|
||||
{
|
||||
this.Columns = columns;
|
||||
this.Rows = rows;
|
||||
}
|
||||
|
||||
public int Columns { get; }
|
||||
public int Rows { get; }
|
||||
|
||||
public static bool operator ==(GridSize a, GridSize b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(GridSize a, GridSize b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"(columns: {this.Columns}, rows: {this.Rows})";
|
||||
|
||||
public override bool Equals(object obj) => obj is GridSize GridSize && this.Equals(GridSize);
|
||||
|
||||
public bool Equals(GridSize other) => this.Columns == other.Columns && this.Rows == other.Rows;
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.Columns.GetHashCode() + this.Rows.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct Position : IEquatable<Position>
|
||||
{
|
||||
public static Position Zero => new Position(0, 0);
|
||||
|
||||
public Position(float x, float y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public static Position FromOffset(Distance xDistanceFromOrigin, Distance yDistanceFromOrigin)
|
||||
=> new Position(xDistanceFromOrigin.Meters, yDistanceFromOrigin.Meters);
|
||||
|
||||
public float X { get; }
|
||||
public float Y { get; }
|
||||
|
||||
public static bool operator ==(Position a, Position b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(Position a, Position b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"({this.X:F2}, {this.Y:F2})";
|
||||
|
||||
public override bool Equals(object obj) => obj is Position position && this.Equals(position);
|
||||
|
||||
public bool Equals(Position other) => this.X == other.X && this.Y == other.Y;
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.X.GetHashCode() + this.Y.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct Size : IEquatable<Size>
|
||||
{
|
||||
public Size(Distance width, Distance height)
|
||||
{
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
|
||||
public Distance Width { get; }
|
||||
public Distance Height { get; }
|
||||
|
||||
public static bool operator ==(Size a, Size b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(Size a, Size b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"(width: {this.Width}, height: {this.Height})";
|
||||
|
||||
public override bool Equals(object obj) => obj is Size Size && this.Equals(Size);
|
||||
|
||||
public bool Equals(Size other) => this.Width == other.Width && this.Height == other.Height;
|
||||
|
||||
public override int GetHashCode() => -1609761766 + this.Width.GetHashCode() + this.Height.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Roy_T.AStar.Primitives
|
||||
{
|
||||
public struct Velocity : IComparable<Velocity>, IEquatable<Velocity>
|
||||
{
|
||||
private Velocity(float metersPerSecond)
|
||||
{
|
||||
this.MetersPerSecond = metersPerSecond;
|
||||
}
|
||||
|
||||
public float MetersPerSecond { get; }
|
||||
|
||||
public float KilometersPerHour => this.MetersPerSecond * 3.6f;
|
||||
|
||||
|
||||
public static Velocity FromMetersPerSecond(float metersPerSecond)
|
||||
=> new Velocity(metersPerSecond);
|
||||
|
||||
public static Velocity FromKilometersPerHour(float kilometersPerHour)
|
||||
=> new Velocity(kilometersPerHour / 3.6f);
|
||||
|
||||
public static Velocity operator +(Velocity a, Velocity b)
|
||||
=> new Velocity(a.MetersPerSecond + b.MetersPerSecond);
|
||||
|
||||
public static Velocity operator -(Velocity a, Velocity b)
|
||||
=> new Velocity(a.MetersPerSecond - b.MetersPerSecond);
|
||||
|
||||
public static bool operator >(Velocity a, Velocity b)
|
||||
=> a.MetersPerSecond > b.MetersPerSecond;
|
||||
|
||||
public static bool operator <(Velocity a, Velocity b)
|
||||
=> a.MetersPerSecond < b.MetersPerSecond;
|
||||
|
||||
public static bool operator >=(Velocity a, Velocity b)
|
||||
=> a.MetersPerSecond >= b.MetersPerSecond;
|
||||
|
||||
public static bool operator <=(Velocity a, Velocity b)
|
||||
=> a.MetersPerSecond <= b.MetersPerSecond;
|
||||
|
||||
public static bool operator ==(Velocity a, Velocity b)
|
||||
=> a.Equals(b);
|
||||
|
||||
public static bool operator !=(Velocity a, Velocity b)
|
||||
=> !a.Equals(b);
|
||||
|
||||
public override string ToString() => $"{this.MetersPerSecond:F2} m/s";
|
||||
|
||||
public override bool Equals(object obj) => obj is Velocity velocity && this.MetersPerSecond == velocity.MetersPerSecond;
|
||||
|
||||
public bool Equals(Velocity other) => this.MetersPerSecond == other.MetersPerSecond;
|
||||
|
||||
public int CompareTo(Velocity other) => this.MetersPerSecond.CompareTo(other.MetersPerSecond);
|
||||
|
||||
public override int GetHashCode() => -1419927970 + this.MetersPerSecond.GetHashCode();
|
||||
}
|
||||
}
|
|
@ -1,507 +0,0 @@
|
|||
using log4net;
|
||||
using Mono.Addins;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Region.CoreModules.World.LegacyMap;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.ScriptEngine.Interfaces;
|
||||
using OpenSim.Region.ScriptEngine.Shared.Api;
|
||||
using Roy_T.AStar.Graphs;
|
||||
using Roy_T.AStar.Grids;
|
||||
using Roy_T.AStar.Paths;
|
||||
using Roy_T.AStar.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
|
||||
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
|
||||
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
|
||||
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
|
||||
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
|
||||
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
|
||||
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
|
||||
|
||||
[assembly: Addin("BasicPathFindingModule", "0.1")]
|
||||
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
namespace OpenSim.Modules.PathFinding
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicPathFindingModule")]
|
||||
|
||||
public class BasicPathFindingModule : INonSharedRegionModule
|
||||
{
|
||||
#region Region Module
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private Scene m_scene = null;
|
||||
private IConfig m_config = null;
|
||||
private bool m_enabled = true;
|
||||
private IScriptModuleComms m_scriptModule;
|
||||
|
||||
private List<Environment> m_environments = new List<Environment>();
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "BasicPathFindingModule"; }
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_config = source.Configs["XEngine"];
|
||||
|
||||
if (m_config != null)
|
||||
{
|
||||
m_enabled = m_config.GetBoolean("EnablePathFinding", m_enabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.Error("[" + Name + "]: Cant find config.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("[" + Name + "]: initialization error: {0}", e.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_enabled)
|
||||
{
|
||||
m_log.Info("[" + Name + "]: module is enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.Info("[" + Name + "]: module is disabled");
|
||||
}
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
if (m_enabled)
|
||||
{
|
||||
m_log.Info("[" + Name + "]: Load region " + scene.Name);
|
||||
|
||||
m_scene = scene;
|
||||
m_scriptModule = m_scene.RequestModuleInterface<IScriptModuleComms>();
|
||||
if (m_scriptModule == null)
|
||||
{
|
||||
m_log.ErrorFormat("[" + Name + "]: Failed to load IScriptModuleComms!");
|
||||
m_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osGeneratePathEnv");
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osKeepAlivePathEnv");
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osSetPathPositionData");
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osSetPathLineData");
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osGeneratePath");
|
||||
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osGetSearchableObjectList");
|
||||
|
||||
m_scriptModule.RegisterScriptInvocation(this, "osGenerateDebugImage");
|
||||
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_SUCCESSFUL", 19850);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_NOT_FOUND", 19851);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_OUT_OF_RANGE", 19852);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_NOT_IN_LINE", 19853);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_START_OR_END_UNKNOWN", 19854);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_TARGET_NOT_REACHABLE", 19855);
|
||||
m_scriptModule.RegisterConstant("PATH_ENV_ERR_UNKNOWN", 19860);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.WarnFormat("[" + Name + "]: script method registration failed; {0}", e.Message);
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
m_log.Info("[" + Name + "]: Region loading done!");
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Asyn Funktions
|
||||
|
||||
private void generatePathEnvironment(ScriptRequestData requestData)
|
||||
{
|
||||
lock(m_environments)
|
||||
{
|
||||
try
|
||||
{
|
||||
UUID _envID = UUID.Random();
|
||||
Environment _newEnv = new Environment(_envID.ToString(), (int)m_scene.RegionInfo.RegionSizeX);
|
||||
|
||||
m_environments.Add(_newEnv);
|
||||
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, _envID.ToString(), requestData.RequestID.ToString());
|
||||
}
|
||||
catch (Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void keepAlivePathEnv(ScriptRequestData requestData)
|
||||
{
|
||||
lock (m_environments)
|
||||
{
|
||||
try
|
||||
{
|
||||
Environment _env = m_environments.Find(X => X.ID == requestData.EnvironmentID);
|
||||
|
||||
if (_env != null)
|
||||
{
|
||||
_env.LastTimeUsed = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, "", requestData.RequestID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19851, "", requestData.RequestID.ToString());
|
||||
}
|
||||
catch (Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setPositionData(ScriptRequestData requestData, Vector3 position, int walkable, int isTarget, int isStart)
|
||||
{
|
||||
lock(m_environments)
|
||||
{
|
||||
try
|
||||
{
|
||||
Environment _env = m_environments.Find(X => X.ID == requestData.EnvironmentID);
|
||||
|
||||
if (_env != null)
|
||||
{
|
||||
PathNode _node = _env.Nodes.Find(X => X.PositionX == (int)position.X && X.PositionY == (int)position.Y);
|
||||
|
||||
if (_node == null)
|
||||
{
|
||||
_node = new PathNode((int)position.X, (int)position.Y, false);
|
||||
_env.Nodes.Add(_node);
|
||||
}
|
||||
|
||||
if (walkable == 1)
|
||||
_node.Walkable = true;
|
||||
|
||||
if (walkable == 0)
|
||||
_node.Walkable = false;
|
||||
|
||||
if (isTarget == 1)
|
||||
_env.Target = _node;
|
||||
|
||||
if (isStart == 1)
|
||||
_env.Start = _node;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19851, "", requestData.RequestID.ToString());
|
||||
}
|
||||
catch (Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setLineData(ScriptRequestData requestData, Vector3 start, Vector3 target, int walkable)
|
||||
{
|
||||
lock(m_environments)
|
||||
{
|
||||
try
|
||||
{
|
||||
Environment _env = m_environments.Find(X => X.ID == requestData.EnvironmentID);
|
||||
|
||||
if (_env != null)
|
||||
{
|
||||
if ((int)start.X == (int)target.X || (int)start.Y == (int)target.Y)
|
||||
{
|
||||
if ((int)start.X == (int)target.X && (int)start.Y == (int)target.Y)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, "", requestData.RequestID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 _PointA = new Vector3(0, 0, 0);
|
||||
Vector3 _PointB = new Vector3(0, 0, 0);
|
||||
|
||||
if ((int)start.X != (int)target.X)
|
||||
{
|
||||
if ((int)start.X < (int)target.X)
|
||||
{
|
||||
_PointA = start;
|
||||
_PointB = target;
|
||||
}
|
||||
|
||||
if ((int)start.X > (int)target.X)
|
||||
{
|
||||
_PointA = target;
|
||||
_PointB = start;
|
||||
}
|
||||
|
||||
while ((int)_PointA.X <= (int)_PointB.X)
|
||||
{
|
||||
setPositionData(requestData, _PointA, walkable, 0, 0);
|
||||
_PointA.X = (int)_PointA.X + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((int)start.Y != (int)target.Y)
|
||||
{
|
||||
if ((int)start.Y < (int)target.Y)
|
||||
{
|
||||
_PointA = start;
|
||||
_PointB = target;
|
||||
}
|
||||
|
||||
if ((int)start.Y > (int)target.Y)
|
||||
{
|
||||
_PointA = target;
|
||||
_PointB = start;
|
||||
}
|
||||
|
||||
while ((int)_PointA.Y <= (int)_PointB.Y)
|
||||
{
|
||||
setPositionData(requestData, _PointA, walkable, 0, 0);
|
||||
_PointA.Y = (int)_PointA.Y + 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, "", requestData.RequestID.ToString());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19853, "", requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19851, "", requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generatePath(ScriptRequestData requestData)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (m_environments)
|
||||
{
|
||||
Environment _env = m_environments.Find(X => X.ID == requestData.EnvironmentID);
|
||||
|
||||
if (_env.Start != null && _env.Target != null)
|
||||
{
|
||||
if (_env.Start.PositionX == _env.Target.PositionX && _env.Start.PositionY == _env.Target.PositionY)
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, "", requestData.RequestID.ToString());
|
||||
|
||||
GridSize _pathFindingGridSize = new GridSize(_env.Size, _env.Size);
|
||||
Roy_T.AStar.Primitives.Size _pathFindingCellSize = new Roy_T.AStar.Primitives.Size(Distance.FromMeters(1), Distance.FromMeters(1));
|
||||
Velocity _pathFindingVelocity = Velocity.FromKilometersPerHour(11.5f);
|
||||
|
||||
Grid _pathFindingGrid = Grid.CreateGridWithLateralAndDiagonalConnections(_pathFindingGridSize, _pathFindingCellSize, _pathFindingVelocity);
|
||||
|
||||
foreach (INode _thisNode in _pathFindingGrid.GetAllNodes())
|
||||
{
|
||||
PathNode _node = _env.Nodes.Find(X => X.PositionX == (int)_thisNode.Position.X && X.PositionY == (int)_thisNode.Position.Y);
|
||||
|
||||
if (_node == null)
|
||||
{
|
||||
_pathFindingGrid.DisconnectNode(new GridPosition((int)_thisNode.Position.X, (int)_thisNode.Position.Y));
|
||||
_pathFindingGrid.RemoveDiagonalConnectionsIntersectingWithNode(new GridPosition((int)_thisNode.Position.X, (int)_thisNode.Position.Y));
|
||||
}
|
||||
}
|
||||
|
||||
PathFinder pathFinder = new PathFinder();
|
||||
Path _pathFindingPath = pathFinder.FindPath(new GridPosition(_env.Start.PositionX, _env.Start.PositionY), new GridPosition(_env.Target.PositionX, _env.Target.PositionY), _pathFindingGrid);
|
||||
|
||||
String _pathString = "";
|
||||
int lastX = 0;
|
||||
int lastY = 0;
|
||||
|
||||
foreach (var _thisEdge in _pathFindingPath.Edges)
|
||||
{
|
||||
if (lastX != (int)_thisEdge.End.Position.X && lastY != (int)_thisEdge.End.Position.Y)
|
||||
{
|
||||
_pathString += "<" + _thisEdge.End.Position.X + ", " + _thisEdge.End.Position.Y + ", 0>;";
|
||||
|
||||
lastX = (int)_thisEdge.End.Position.X;
|
||||
lastY = (int)_thisEdge.End.Position.Y;
|
||||
}
|
||||
}
|
||||
|
||||
_pathString += "<" + _pathFindingPath.Edges[_pathFindingPath.Edges.Count - 1].End.Position.X + ", " + _pathFindingPath.Edges[_pathFindingPath.Edges.Count - 1].End.Position.Y + ", 0>;";
|
||||
|
||||
|
||||
if (_pathFindingPath.Type == PathType.Complete)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, _pathString, requestData.RequestID.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19855, _pathString, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19854, "", requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}catch(Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDebugImage(ScriptRequestData requestData)
|
||||
{
|
||||
lock(m_environments)
|
||||
{
|
||||
try
|
||||
{
|
||||
Environment _env = m_environments.Find(X => X.ID == requestData.EnvironmentID);
|
||||
|
||||
if (_env != null)
|
||||
{
|
||||
Bitmap _bitmap = new Bitmap(_env.Size, _env.Size);
|
||||
|
||||
foreach (PathNode thisNode in _env.Nodes)
|
||||
{
|
||||
if (thisNode.Walkable)
|
||||
_bitmap.SetPixel(thisNode.PositionX, thisNode.PositionY, Color.Green);
|
||||
|
||||
if (!thisNode.Walkable)
|
||||
_bitmap.SetPixel(thisNode.PositionX, thisNode.PositionY, Color.Black);
|
||||
}
|
||||
|
||||
_bitmap.Save(requestData.EnvironmentID + ".png");
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19850, requestData.EnvironmentID + ".png", requestData.RequestID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19851, "", requestData.RequestID.ToString());
|
||||
}
|
||||
catch (Exception _error)
|
||||
{
|
||||
m_scriptModule.DispatchReply(requestData.ScriptID, 19860, _error.Message, requestData.RequestID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Script Funktions
|
||||
|
||||
[ScriptInvocation]
|
||||
public string osGeneratePathEnv(UUID hostID, UUID scriptID)
|
||||
{
|
||||
UUID requestKey = UUID.Random();
|
||||
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { generatePathEnvironment(new ScriptRequestData(hostID, scriptID, null, requestKey)); })).Start();
|
||||
|
||||
return requestKey.ToString();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public string osKeepAlivePathEnv(UUID hostID, UUID scriptID, String environmentID)
|
||||
{
|
||||
UUID requestKey = UUID.Random();
|
||||
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { keepAlivePathEnv(new ScriptRequestData(hostID, scriptID, environmentID, requestKey)); })).Start();
|
||||
|
||||
return requestKey.ToString();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public void osSetPathPositionData(UUID hostID, UUID scriptID, String environmentID, Vector3 position, int walkable, int isTarget, int isStart)
|
||||
{
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { setPositionData(new ScriptRequestData(hostID, scriptID, environmentID), position, walkable, isTarget, isStart); })).Start();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public void osSetPathLineData(UUID hostID, UUID scriptID, String environmentID, Vector3 start, Vector3 target, int walkable)
|
||||
{
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { setLineData(new ScriptRequestData(hostID, scriptID, environmentID), start, target, walkable); })).Start();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public string osGeneratePath(UUID hostID, UUID scriptID, String environmentID)
|
||||
{
|
||||
UUID requestKey = UUID.Random();
|
||||
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { generatePath(new ScriptRequestData(hostID, scriptID, environmentID, requestKey)); })).Start();
|
||||
|
||||
return requestKey.ToString();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public string osGenerateDebugImage(UUID hostID, UUID scriptID, String environmentID)
|
||||
{
|
||||
UUID requestKey = UUID.Random();
|
||||
|
||||
SceneObjectGroup _host = m_scene.GetSceneObjectGroup(hostID);
|
||||
(new Thread(delegate () { generateDebugImage(new ScriptRequestData(hostID, scriptID, environmentID, requestKey)); })).Start();
|
||||
|
||||
return requestKey.ToString();
|
||||
}
|
||||
|
||||
[ScriptInvocation]
|
||||
public object[] osGetSearchableObjectList(UUID hostID, UUID scriptID, String searchString)
|
||||
{
|
||||
List<object> returnList = new List<object>();
|
||||
|
||||
foreach (SceneObjectGroup thisGroup in m_scene.GetSceneObjectGroups())
|
||||
{
|
||||
if(thisGroup.Name == searchString)
|
||||
returnList.Add(thisGroup.UUID);
|
||||
}
|
||||
|
||||
return returnList.ToArray();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
using OpenMetaverse;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenSim.Modules.PathFinding
|
||||
{
|
||||
class Environment
|
||||
{
|
||||
public String ID = null;
|
||||
|
||||
public int Size = 0;
|
||||
public int LastTimeUsed = 0;
|
||||
|
||||
public PathNode Start = null;
|
||||
public PathNode Target = null;
|
||||
|
||||
private List<PathNode> m_nodes = new List<PathNode>();
|
||||
public List<PathNode> Nodes
|
||||
{
|
||||
get
|
||||
{
|
||||
LastTimeUsed = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
return m_nodes;
|
||||
}
|
||||
set
|
||||
{
|
||||
LastTimeUsed = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
m_nodes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Environment(String envID, int size)
|
||||
{
|
||||
ID = envID;
|
||||
|
||||
Size = size;
|
||||
|
||||
LastTimeUsed = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenSim.Modules.PathFinding
|
||||
{
|
||||
class PathNode
|
||||
{
|
||||
public int PositionX = 0;
|
||||
public int PositionY = 0;
|
||||
|
||||
public bool Walkable = false;
|
||||
|
||||
public int f_cost = 99999;
|
||||
|
||||
public PathNode Parent = null;
|
||||
|
||||
public PathNode(int positionX, int positionY)
|
||||
{
|
||||
PositionX = positionX;
|
||||
PositionY = positionY;
|
||||
}
|
||||
|
||||
public PathNode(int positionX, int positionY, bool isWalkable)
|
||||
{
|
||||
PositionX = positionX;
|
||||
PositionY = positionY;
|
||||
|
||||
Walkable = isWalkable;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
using OpenMetaverse;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenSim.Modules.PathFinding
|
||||
{
|
||||
public class ScriptRequestData
|
||||
{
|
||||
public UUID HostID = UUID.Zero;
|
||||
public UUID ScriptID = UUID.Zero;
|
||||
public String EnvironmentID = null;
|
||||
public UUID RequestID = UUID.Zero;
|
||||
|
||||
public ScriptRequestData(UUID host, UUID script)
|
||||
{
|
||||
HostID = host;
|
||||
ScriptID = script;
|
||||
}
|
||||
|
||||
public ScriptRequestData(UUID host, UUID script, String envID)
|
||||
{
|
||||
HostID = host;
|
||||
ScriptID = script;
|
||||
EnvironmentID = envID;
|
||||
}
|
||||
|
||||
public ScriptRequestData(UUID host, UUID script, String envID, UUID requestID)
|
||||
{
|
||||
HostID = host;
|
||||
ScriptID = script;
|
||||
EnvironmentID = envID;
|
||||
RequestID = requestID;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue