//$ Copyright 2015-22, Code Respawn Technologies Pvt Ltd - All Rights Reserved $// using System.Collections.Generic; using UnityEngine; namespace DungeonArchitect.Graphs.Layouts { public interface IGraphLayout { void Layout(T[] nodes, IGraphLayoutNodeActions nodeActions); } public interface IGraphLayoutNodeActions { void SetNodePosition(T node, Vector2 position); Vector2 GetNodePosition(T node); T[] GetOutgoingNodes(T node); } public enum GraphLayoutType { Layered, Spring } public class GraphLayoutNode { public T Payload { get; set; } public Vector2 Position { get; set; } public List> Outgoing { get; private set; } public List> Incoming { get; private set; } public GraphLayoutNode(T payload, Vector2 position) { Outgoing = new List>(); Incoming = new List>(); this.Payload = payload; this.Position = position; } } public abstract class GraphLayoutBase : IGraphLayout { public void Layout(T[] nodes, IGraphLayoutNodeActions nodeActions) { if (nodeActions == null || nodes == null) { return; } var nodeToLayoutMap = new Dictionary>(); var layoutNodes = new GraphLayoutNode[nodes.Length]; // Create the nodes for (int i = 0; i < nodes.Length; i++) { var node = nodes[i]; var position = nodeActions.GetNodePosition(node); var layoutNode = new GraphLayoutNode(node, position); layoutNodes[i] = layoutNode; nodeToLayoutMap.Add(node, layoutNode); } // Link the nodes foreach (var node in nodes) { var layoutNode = nodeToLayoutMap[node]; T[] outgoingNodes = nodeActions.GetOutgoingNodes(node); foreach (var outgoingNode in outgoingNodes) { if (!nodeToLayoutMap.ContainsKey(outgoingNode)) continue; var layoutOutgoingNode = nodeToLayoutMap[outgoingNode]; layoutNode.Outgoing.Add(layoutOutgoingNode); layoutOutgoingNode.Incoming.Add(layoutNode); } } LayoutImpl(layoutNodes); foreach (var layoutNode in layoutNodes) { nodeActions.SetNodePosition(layoutNode.Payload, layoutNode.Position); } } protected abstract void LayoutImpl(GraphLayoutNode[] nodes); } }