From 1c6e7bde4656701c70451a111d29765a424c3cba Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 13 Sep 2022 21:29:02 +0200 Subject: [PATCH] Added extension to organize node-graphs --- .../Artemis.Core.csproj.DotSettings | 1 + .../Extensions/NodeExtension.cs | 26 ++++++ .../Extensions/NodeScriptExtension.cs | 88 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/Artemis.Core/VisualScripting/Extensions/NodeExtension.cs create mode 100644 src/Artemis.Core/VisualScripting/Extensions/NodeScriptExtension.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj.DotSettings b/src/Artemis.Core/Artemis.Core.csproj.DotSettings index a18836e5e..d42d584d5 100644 --- a/src/Artemis.Core/Artemis.Core.csproj.DotSettings +++ b/src/Artemis.Core/Artemis.Core.csproj.DotSettings @@ -93,4 +93,5 @@ True True True + True True \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Extensions/NodeExtension.cs b/src/Artemis.Core/VisualScripting/Extensions/NodeExtension.cs new file mode 100644 index 000000000..5c187a4c8 --- /dev/null +++ b/src/Artemis.Core/VisualScripting/Extensions/NodeExtension.cs @@ -0,0 +1,26 @@ +using System; +using System.Linq; + +namespace Artemis.Core; + +public static class NodeExtension +{ + #region Methods + + public static double EstimateHeight(this INode node) + { + const double PIN_HEIGHT = 26; + const double TITLE_HEIGHT = 46; + + int inputPinCount = node.Pins.Count(x => x.Direction == PinDirection.Input) + + node.PinCollections.Where(x => x.Direction == PinDirection.Input).Sum(x => x.Count() + 1); + int outputPinCount = node.Pins.Count(x => x.Direction == PinDirection.Output) + + node.PinCollections.Where(x => x.Direction == PinDirection.Output).Sum(x => x.Count() + 1); + + return TITLE_HEIGHT + (Math.Max(inputPinCount, outputPinCount) * PIN_HEIGHT); + } + + public static double EstimateWidth(this INode node) => 120; // DarthAffe 13.09.2022: For now just assume they are all the same size + + #endregion +} \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Extensions/NodeScriptExtension.cs b/src/Artemis.Core/VisualScripting/Extensions/NodeScriptExtension.cs new file mode 100644 index 000000000..f0961dfb6 --- /dev/null +++ b/src/Artemis.Core/VisualScripting/Extensions/NodeScriptExtension.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Core; + +public static class NodeScriptExtension +{ + #region Methods + + public static void Organize(this NodeScript nodeScript) + { + const double SPACING_HORIZONTAL = 160; + const double SPACING_VERTICAL = 20; + + Dictionary levels = nodeScript.Nodes.ToDictionary(node => node, _ => -1); + + List currentLevelNodes = nodeScript.Nodes.Where(x => x.IsExitNode).ToList(); + foreach (INode currentLevelNode in currentLevelNodes) + levels[currentLevelNode] = 0; // DarthAffe 13.09.2022: Init-exit nodes as zero + + int currentLevel = 1; + while (currentLevelNodes.Count > 0) + { + List nextLevelNodes = currentLevelNodes.SelectMany(node => node.Pins + .Where(x => x.Direction == PinDirection.Input) + .SelectMany(x => x.ConnectedTo) + .Select(x => x.Node) + .Concat(node.PinCollections + .Where(x => x.Direction == PinDirection.Input) + .SelectMany(x => x) + .SelectMany(x => x.ConnectedTo) + .Select(x => x.Node))) + .Distinct() + .ToList(); + + foreach (INode nextLevelNode in nextLevelNodes) + if (currentLevel > levels[nextLevelNode]) + levels[nextLevelNode] = currentLevel; + + currentLevelNodes = nextLevelNodes; + currentLevel++; + } + + void LayoutLevel(IList nodes, double posX, double posY) + { + foreach (INode node in nodes) + { + node.X = posX; + node.Y = posY; + + posY += SPACING_VERTICAL + node.EstimateHeight(); + } + } + + List? unusedNodes = null; + double unusedPosY = 0; + double level0Width = 0; + + double positionX = 0; + foreach (IGrouping levelGroup in levels.GroupBy(x => x.Value, x => x.Key).OrderBy(x => x.Key)) + { + List nodes = levelGroup.ToList(); + double levelHeight = nodes.Sum(x => x.EstimateHeight()) + ((nodes.Count - 1) * SPACING_VERTICAL); + double levelWidth = nodes.Max(x => x.EstimateWidth()); + double positionY = -(levelHeight / 2.0); + + if (levelGroup.Key == -1) + { + unusedNodes = nodes; + unusedPosY = positionY; + } + else + { + if (levelGroup.Key == 0) + level0Width = levelWidth; + + LayoutLevel(nodes, positionX, positionY); + + positionX -= SPACING_HORIZONTAL + levelWidth; + } + } + + if (unusedNodes != null) + LayoutLevel(unusedNodes, level0Width + (SPACING_HORIZONTAL / 2.0), unusedPosY); + } + + #endregion +} \ No newline at end of file