public List<PathData> GetPathLeg(PathGraphNode origin, PathGraphNode destination) { return m_slices[origin][destination].Value; }
private List<PathData> GeneratePath(SimplexNoise2D noise, GetHeight getHeightFunction, PathGraphNode origin, PathGraphNode destination) { var originProjection = new Vector2(origin.Position.X, origin.Position.Z); var destinationProjection = new Vector2(destination.Position.X, destination.Position.Z); var gradient = Vector2.Subtract(destinationProjection, originProjection); var distance = gradient.LengthSquared(); gradient.Normalize(); //just checking if we'll get a NaN so the quality oprtator should be fine // ReSharper disable CompareOfFloatsByEqualityOperator var deltaX = gradient.X == 0 ? 0 : 1 / Math.Abs(gradient.X); var deltaZ = gradient.Y == 0 ? 0 : 1 / Math.Abs(gradient.Y); if (deltaX == 0 && deltaZ == 0) { return new List<PathData>(); } var stepX = Math.Sign(gradient.X); var stepZ = Math.Sign(gradient.Y); var maxX = 0.0f; var maxZ = 0.0f; var x = (int)origin.Position.X; var z = (int)origin.Position.Z; var previousHeight = (int)origin.Position.Y; var path = new List<PathData>(); do { var node = BuildPathData(noise, x, z, 0, gradient, getHeightFunction, previousHeight); path.Add(node); previousHeight = (int)node.Position.Y; if (deltaZ == 0 || (deltaX != 0 && maxX < maxZ)) { maxX += deltaX; x += stepX; } else { maxZ += deltaZ; z += stepZ; } } while (Vector2.DistanceSquared(originProjection, new Vector2(x, z)) <= distance); // ReSharper restore CompareOfFloatsByEqualityOperator return path; }
public PathNodeList(PathGraphNode head, GetHeight getHeightFunction) { var noise = new SimplexNoise2D(head.Id); Head = head; var stack = new Stack<PathGraphNode>(); var minPosX = float.MaxValue; var minPosZ = float.MaxValue; var maxPosX = -float.MaxValue; var maxPosZ = -float.MaxValue; m_slices = new Dictionary<PathGraphNode, Dictionary<PathGraphNode, Lazy<List<PathData>>>>(); stack.Push(head); while (stack.Count > 0) { var node = stack.Pop(); var nodePos = node.Position; if (nodePos.X < minPosX) minPosX = nodePos.X; if (nodePos.Z < minPosZ) minPosZ = nodePos.Z; if (nodePos.X > maxPosX) maxPosX = nodePos.X; if (nodePos.Z > maxPosZ) maxPosZ = nodePos.Z; if (node.Edges.Count(val => val.Value > 0) == 0) { continue; } m_slices[node] = new Dictionary<PathGraphNode, Lazy<List<PathData>>>(); foreach (var graphNode in node.Edges) { if (graphNode.Value < 0) { continue; } m_slices[node][graphNode.Key] = new Lazy<List<PathData>>(() => GeneratePath(noise, getHeightFunction, node, graphNode.Key)); stack.Push(graphNode.Key); } } BoundingBox = new BoundingBox(new Vector3(minPosX - 1.5f, 0, minPosZ - 1.5f), new Vector3(maxPosX + 1.5f, 0, maxPosZ + 1.5f)); }
private PathData GetRiverData(int x, int z, PathGraphNode nextNode, PathGraphNode lastNode, PathNodeList path) { var testPoint = new Vector2(x, z); var lastNodePos = new Vector2(lastNode.Position.X, lastNode.Position.Z); var nextNodePos = new Vector2(nextNode.Position.X, nextNode.Position.Z); var distance = MathUtilities.DistanceFromPointToLineSegment(testPoint, lastNodePos, nextNodePos); var pathLeg = path.GetPathLeg(lastNode, nextNode); var distSquared = Vector2.DistanceSquared(lastNodePos, testPoint) - distance*distance; if (distSquared >= 0) { var dist = Math.Sqrt(distSquared); var ratio = dist/Vector2.Distance(lastNodePos, nextNodePos); var sliceIndex = (int) (ratio*pathLeg.Count); if (sliceIndex < pathLeg.Count) { var pathSlice = pathLeg[sliceIndex]; if (distance <= pathSlice.Radius) { return pathSlice; } } } PathData slice = null; foreach (var graphNode in nextNode.Edges) { if (graphNode.Value <= 0) { continue; } var currentSlice = GetRiverData(x, z, graphNode.Key, nextNode, path); if (currentSlice != null && (slice == null || currentSlice.Position.Y < slice.Position.Y)) { slice = currentSlice; } } return slice; }
protected int SortPool(PathGraphNode activeNode, PathGraphNode candidateNode1, PathGraphNode candidateNode2) { var result = (int)(candidateNode1.Position.Y - candidateNode2.Position.Y); if (result == 0) { result = candidateNode1.Edges.Count - candidateNode2.Edges.Count; } if (result == 0) { result = (int)(Vector3.DistanceSquared(candidateNode1.Position, activeNode.Position) - Vector3.DistanceSquared(candidateNode2.Position, activeNode.Position)); } return result; }
protected void InsertNodeIntoMaps(uint nodeId, int x, int z) { var height = m_getHeight(x, z); var node = new PathGraphNode(new Vector3(x, height, z), nodeId); if (height >= RiversStartMinHeight) { node.NodeType = PathNodeType.Source; m_sources.Add(nodeId, node); } else if (height <= RiverEndMaxHeight) { node.NodeType = PathNodeType.Sink; m_sinks.Add(nodeId, node); } else { node.NodeType = PathNodeType.General; m_general.Add(nodeId, node); } }
protected bool FilterPool(PathGraphNode activeNode, PathGraphNode candidateNode) { return activeNode != candidateNode && candidateNode.Position.Y <= activeNode.Position.Y && !activeNode.Edges.ContainsKey(candidateNode) && Vector3.DistanceSquared(candidateNode.Position, activeNode.Position) <= 625; }