Merge pull request #6 from naninunenoy/node

ノードの整列
This commit is contained in:
Nakano Yosuke 2020-11-19 23:56:09 +09:00 committed by GitHub
commit cb49abe84c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 1150 additions and 49 deletions

View File

@ -1,13 +0,0 @@
using System.Collections.Generic;
namespace AsmdefHelper.DependencyGraph.Editor {
public class AsmdefDependency {
public string DependsFrom { get; }
public IEnumerable<string> DependsTo { get; }
public AsmdefDependency(string key, IEnumerable<string> value) {
DependsFrom = key;
DependsTo = value;
}
}
}

View File

@ -13,16 +13,8 @@ namespace AsmdefHelper.DependencyGraph.Editor {
void OnEnable() {
// .asmdefをすべて取得
var asmdefs = CompilationPipeline.GetAssemblies();
var allDependencies = new List<AsmdefDependency>();
foreach (var asmdef in asmdefs) {
allDependencies.Add(
new AsmdefDependency(
asmdef.name,
asmdef.assemblyReferences?.Select(x => x.name) ?? new string[0])
);
}
// viewの作成
var graphView = new AsmdefGraphView(allDependencies) {
var graphView = new AsmdefGraphView(asmdefs) {
style = { flexGrow = 1 }
};
rootVisualElement.Add(graphView);

View File

@ -1,10 +1,17 @@
using System.Collections.Generic;
using System.Linq;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using AsmdefHelper.DependencyGraph.Editor.NodeView;
using UnityEditor.Compilation;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace AsmdefHelper.DependencyGraph.Editor {
public class AsmdefGraphView : GraphView {
public AsmdefGraphView(IEnumerable<AsmdefDependency> asmdefs) : base() {
public sealed class AsmdefGraphView : GraphView {
public AsmdefGraphView(IEnumerable<Assembly> assemblies) {
var assemblyArr = assemblies.ToArray();
// zoom可能に
SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale);
// 背景を黒に
@ -12,24 +19,50 @@ namespace AsmdefHelper.DependencyGraph.Editor {
// ドラッグによる移動可能に
this.AddManipulator(new SelectionDragger());
// ノードの追加
var asmdefNodeDict = new Dictionary<string, AsmdefNode>();
foreach (var asmdef in asmdefs) {
var node = new AsmdefNode(asmdef.DependsFrom);
var asmdefNodeDict = new Dictionary<string, IAsmdefNodeView>();
foreach (var asm in assemblyArr) {
var node = new AsmdefNode(asm.name, contentContainer);
AddElement(node);
asmdefNodeDict.Add(node.title, node);
}
// 依存先にラインを追加
var nodeApapter = new NodeAdapter();
foreach (var asmdef in asmdefs) {
if (!asmdefNodeDict.TryGetValue(asmdef.DependsFrom, out var fromNode)) {
// 依存の整理
var nodeProfiles = assemblyArr
.Select((x, i) => new NodeProfile(new NodeId(i), x.name))
.ToDictionary(x => x.Name);
var dependencies = new List<IDependencyNode>(nodeProfiles.Count);
// 依存先の設定
foreach (var asm in assemblyArr) {
if (nodeProfiles.TryGetValue(asm.name, out var profile)) {
var requireProfiles = asm.assemblyReferences
.Where(x => nodeProfiles.ContainsKey(x.name))
.Select(x => nodeProfiles[x.name]);
var dep = new HashSetDependencyNode(profile);
dep.SetRequireNodes(requireProfiles);
dependencies.Add(dep);
}
}
// 依存元の設定
NodeProcessor.SetBeRequiredNodes(dependencies);
// 依存先にのみラインを追加
foreach (var dep in dependencies) {
if (!asmdefNodeDict.TryGetValue(dep.Profile.Name, out var fromNode)) {
continue;
}
foreach (var dependents in asmdef.DependsTo) {
if (!asmdefNodeDict.TryGetValue(dependents, out var toNode)) {
foreach (var dest in dep.Destinations) {
if (!asmdefNodeDict.TryGetValue(dest.Name, out var toNode)) {
continue;
}
var edge = fromNode.RightPort.ConnectTo(toNode.LeftPort);
contentContainer.Add(edge);// これが無いと線が表示されない
fromNode.RightPort.Connect(toNode.LeftPort);
}
}
// ノードの場所を整列
var sortStrategy = new AlignSortStrategy(AlignParam.Default(), Vector2.zero);
var sortedNode = sortStrategy.Sort(dependencies);
foreach (var node in sortedNode) {
if (asmdefNodeDict.TryGetValue(node.Profile.Name, out var nodeView)) {
nodeView.SetPositionXY(node.Position);
}
}
}

View File

@ -1,20 +1,20 @@
using UnityEditor.Experimental.GraphView;
using AsmdefHelper.DependencyGraph.Editor.NodeView;
using UnityEditor.Experimental.GraphView;
using UnityEngine.UIElements;
namespace AsmdefHelper.DependencyGraph.Editor {
public class AsmdefNode : Node {
public readonly Port LeftPort;
public readonly Port RightPort;
public class AsmdefNode : UiElementsNodeView, IAsmdefNodeView {
public IPort LeftPort { get; }
public IPort RightPort { get; }
public AsmdefNode(string nodeName) {
title = nodeName;
public AsmdefNode(string nodeName, VisualElement parentContentContainer) {
Label = nodeName;
LeftPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(Port));
LeftPort.portName = "Ref By";
outputContainer.Add(LeftPort); // as right side
LeftPort = new GraphViewPort(parentContentContainer, Direction.Input) { Label = "Ref By" };
inputContainer.Add(LeftPort as Port); // as right side
RightPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, typeof(Port));
RightPort.portName = "Ref To";
inputContainer.Add(RightPort); // as left side
RightPort = new GraphViewPort(parentContentContainer, Direction.Output) { Label = "Ref To" };
outputContainer.Add(RightPort as Port); // as left side
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bbaa68e4da2746ed9af5d76e173b5e8c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode {
public class HashSetDependencyNode : IDependencyNode {
public NodeProfile Profile { get; }
public ICollection<NodeProfile> Sources => sources;
public ICollection<NodeProfile> Destinations => destinations;
readonly HashSet<NodeProfile> sources;
readonly HashSet<NodeProfile> destinations;
public HashSetDependencyNode(NodeProfile profile) {
Profile = profile;
sources = new HashSet<NodeProfile>();
destinations = new HashSet<NodeProfile>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3b278ba5cdda49eca5f5aa0b2941713d
timeCreated: 1605450089

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode {
public interface IDependencyNode {
NodeProfile Profile { get; }
ICollection<NodeProfile> Sources { get; }
ICollection<NodeProfile> Destinations { get; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 365c6defe4c649a496963187a24ffca0
timeCreated: 1605449577

View File

@ -0,0 +1,33 @@
using System;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode {
public readonly struct NodeId : IEquatable<NodeId> {
public readonly int value;
public NodeId(int value) => this.value = value;
public bool Equals(NodeId other) {
return value == other.value;
}
public override bool Equals(object obj) {
return obj is NodeId other && Equals(other);
}
public override int GetHashCode() {
return value;
}
public override string ToString() {
return value.ToString();
}
public static bool operator ==(NodeId x, NodeId y) {
return x.Equals(y);
}
public static bool operator !=(NodeId x, NodeId y) {
return !(x == y);
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: de8afe620d6667940a15a8871781c62d
guid: 11a5fcf054a34f8083cdcdb038b4c70c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode {
public static class NodeProcessor {
public static void SetBeRequiredNodes(IEnumerable<IDependencyNode> nodes) {
var array = nodes as IDependencyNode[] ?? nodes.ToArray();
var dict = array.ToDictionary(x => x.Profile.Id);
foreach (var n in array) {
foreach (var d in n.Destinations) {
dict[d.Id].Sources.Add(n.Profile);
}
}
}
public static void SetRequireNodes(this IDependencyNode node, IEnumerable<NodeProfile> requireNodes) {
node.Sources.Clear();
node.Destinations.Clear();
foreach (var d in requireNodes) {
node.Destinations.Add(d);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6febd7e408df42d89d561ffe371c602f
timeCreated: 1605454341

View File

@ -0,0 +1,44 @@
using System;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode {
public class NodeProfile : IEquatable<NodeProfile> {
public NodeId Id { get; }
public string Name { set; get; }
public NodeProfile(NodeId id, string name) {
Id = id;
Name = name;
}
public bool Equals(NodeProfile other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Id.Equals(other.Id) && Name == other.Name;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((NodeProfile) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Id.GetHashCode() * 397) ^ (Name != null ? Name.GetHashCode() : 0);
}
}
public static bool operator ==(NodeProfile x, NodeProfile y) {
return x.Equals(y);
}
public static bool operator !=(NodeProfile x, NodeProfile y) {
return !(x == y);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8cf71e8ce8054c4b95902fcd1bda7010
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7b935eca30945f5bff132d6a7645320
timeCreated: 1605459681

View File

@ -0,0 +1,50 @@
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public struct AlignParam {
public readonly int tryCount;
public readonly float basicDistance;
public readonly float nodeWidth;
public readonly float nodeHeight;
public readonly float relationK;
public readonly float relationNaturalLength;
public readonly float repulsivePower;
public readonly float threshold;
public AlignParam(int tryCount, float basicDistance, float nodeWidth, float nodeHeight,
float relationK, float relationNaturalLength, float repulsivePower, float threshold) {
this.tryCount = tryCount;
this.basicDistance = basicDistance;
this.nodeWidth = nodeWidth;
this.nodeHeight = nodeHeight;
this.relationK = relationK;
this.relationNaturalLength = relationNaturalLength;
this.repulsivePower = repulsivePower;
this.threshold = threshold;
}
public static AlignParam Default() => new AlignParam(1000, 100, 600, 100, -0.01F, 300, 0.01F, 300.0F);
}
public static class AlignParamEx {
public static Vector2 (this AlignParam align, Vector2 target, Vector2 other) {
var k = align.relationK;
var nl = align.relationNaturalLength;
var l = (target - other).magnitude;
var delta = l - nl;
return -(delta * k * (other - target).normalized);
}
public static Vector2 (this AlignParam align, Vector2 target, Vector2 other) {
var l = (other - target).magnitude;
if (l < align.threshold)
{
return -(other - target).normalized * ((align.threshold - l) * align.repulsivePower);
}
return Vector2.zero;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 949ed302d4b143d3b3fea3039ec3f9e9
timeCreated: 1605794098

View File

@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
//https://github.com/TORISOUP/AnimatorControllerLayouter/blob/master/Assets/TORISOUP/AnimatorControllerLayouter/Editor/LayoutHelper.cs
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public class AlignSortStrategy : ISortStrategy {
readonly AlignParam alignParam;
readonly Vector2 originPosition;
public AlignSortStrategy(AlignParam alignParam, Vector2 originPosition) {
this.alignParam = alignParam;
this.originPosition = originPosition;
}
public IEnumerable<SortedNode> Sort(IEnumerable<IDependencyNode> nodes) {
var nodeArr = nodes.ToArray();
var posDict = nodeArr.ToDictionary(x => x.Profile, _ => originPosition);
// まず順番に整列させる
var nodeGrid = new NodeGrid(alignParam.nodeWidth, alignParam.nodeHeight, alignParam.basicDistance, nodeArr.Length);
for (var i = 0; i < nodeArr.Length; i++) {
posDict[nodeArr[i].Profile] += nodeGrid.GridCenterPositions()[i];
}
// ばねによる整列
var tryCount = alignParam.tryCount;
while (tryCount-- > 0) {
foreach (var node in nodeArr) {
var target = posDict[node.Profile];
var force = Vector2.zero;
foreach (var innerNode in nodeArr) {
var other = posDict[innerNode.Profile];
// ばねの計算
if (node.IsConnectedTo(innerNode.Profile)) {
force += alignParam.(target, other);
}
force += alignParam.(target, other);
}
posDict[node.Profile] = target + force * 1.0f;
}
}
return posDict.Select(x => new SortedNode { Profile = x.Key, Position = x.Value });
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5ebdb87d853042fd96657c9f78cec1a9
timeCreated: 1605793928

View File

@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Graphs;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public static class DependencyNodeExtensions {
public static bool IsSourceEmpty(this IDependencyNode node) {
return !node.Sources.Any();
}
public static bool IsDestinationEmpty(this IDependencyNode node) {
return !node.Destinations.Any();
}
public static bool IsEmptyDependency(this IDependencyNode node) {
return node.IsSourceEmpty() && node.IsDestinationEmpty();
}
public static int CountDependencies(this IDependencyNode node) {
return node.Sources.Count + node.Destinations.Count;
}
public static bool ContainsSelfReference(this IDependencyNode node) {
return node.Sources.Any(x => x == node.Profile) ||
node.Destinations.Any(x => x == node.Profile);
}
public static IEnumerable<NodeProfile> ConnectedNodes(this IDependencyNode node) {
return node.Sources.Concat(node.Destinations);
}
public static bool IsConnectedTo(this IDependencyNode node, NodeProfile nodeProfile) {
return node.Sources.Contains(nodeProfile) || node.Destinations.Contains(nodeProfile);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8d0cee1bf7d4c8c47a98a23879a257cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public interface ISortStrategy {
IEnumerable<SortedNode> Sort(IEnumerable<IDependencyNode> nodes);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e2c63741aae4306aa49389ffdcb2e13
timeCreated: 1605459681

View File

@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public class LinerSortStrategy : ISortStrategy {
readonly Vector2 originPosition;
readonly float basicDistance;
readonly float nodeWidth;
readonly float nodeHeight;
public LinerSortStrategy(Vector2 originPosition, float basicDistance, float nodeWidth, float nodeHeight) {
this.originPosition = originPosition;
this.basicDistance = basicDistance;
this.nodeWidth = nodeWidth;
this.nodeHeight = nodeHeight;
}
IEnumerable<SortedNode> ISortStrategy.Sort(IEnumerable<IDependencyNode> nodes) {
var arr = nodes.ToArray();
var posDict = arr
.ToDictionary(x => x.Profile, _ => originPosition);
// 参照元がないNodeを原点に
var left = arr.FirstOrDefault(x => x.IsSourceEmpty());
posDict[left.Profile] = originPosition;
var right = arr.FirstOrDefault(x => x.Profile != left.Profile);
posDict[right.Profile] = new Vector2(nodeWidth / 2.0F + basicDistance, 0.0F) + originPosition;
return posDict.Select(x => new SortedNode { Profile = x.Key, Position = x.Value });
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d00de9a7b3041be922c457f9f53b1c0
timeCreated: 1605459871

View File

@ -0,0 +1,36 @@
using System.Collections.Generic;
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public class NodeGrid {
public readonly float GridWidth;
public readonly float GridHeight;
public readonly float Distance;
readonly int gridSideCount;
public readonly int GridCount;
public NodeGrid(float nodeWidth, float nodeHeight, float nodeDistance, int nodeCount) {
GridWidth = nodeWidth;
GridHeight = nodeHeight;
Distance = nodeDistance;
gridSideCount = SquareValueProvider.ProvideNearestSquareValue(nodeCount);
GridCount = gridSideCount * gridSideCount;
}
public IReadOnlyList<Vector2> GridCenterPositions() {
var grids = new Vector2[GridCount];
var index = 0;
var y = 0.0F;
for (var i = 0; i < gridSideCount; i++) {
var x = 0.0F;
for (var j = 0; j < gridSideCount; j++) {
grids[index] = new Vector2(x, y);
x += (GridWidth/2.0F) + Distance;
index++;
}
y += (GridHeight/2.0F) + Distance;;
}
return grids;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bf9e7d3635b441398a2011b98e35610b
timeCreated: 1605545271

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public class RandomSortStrategy : ISortStrategy {
readonly Vector2 originPosition;
readonly float basicDistance;
readonly float nodeWidth;
readonly float nodeHeight;
public RandomSortStrategy(Vector2 originPosition, float basicDistance, float nodeWidth, float nodeHeight) {
this.originPosition = originPosition;
this.basicDistance = basicDistance;
this.nodeWidth = nodeWidth;
this.nodeHeight = nodeHeight;
}
public IEnumerable<SortedNode> Sort(IEnumerable<IDependencyNode> nodes) {
var nodeArr = nodes
.Select(x => new SortedNode { Profile = x.Profile, Position = originPosition })
.ToArray();
var nodeGrid = new NodeGrid(nodeWidth, nodeHeight, basicDistance, nodeArr.Length);
var positions = nodeGrid.GridCenterPositions();
var indexes = Enumerable.Range(0, positions.Count).ToList();
foreach (var node in nodeArr) {
var randomIndex = indexes[Random.Range(0, indexes.Count)];
node.Position = positions[randomIndex] + originPosition;
indexes.Remove(randomIndex);
}
return nodeArr;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f63fbb77026544bb82b0ddf7e2b507b0
timeCreated: 1605544752

View File

@ -0,0 +1,8 @@
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public class SortedNode {
public NodeProfile Profile { set; get; }
public Vector2 Position { set; get; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c995f86b2ebe4c83ac65ec6727431ddb
timeCreated: 1605459738

View File

@ -0,0 +1,19 @@
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort {
public static class SquareValueProvider {
public static int ProvideNearestSquareValue(int count) {
if (count < 1) return 0;
if (count == 1) return 1;
var value = 1;
while (value < 100) {
var square = value * value;
var nextValue = value + 1;
var nextSquare = nextValue * nextValue;
value = nextValue;
if (square <= count && count <= nextSquare) {
break;
}
}
return value;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b8521b362be64b7eb1bcf8174be0ecf8
timeCreated: 1605545553

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7f68a5c3b1e9b8b4aa69caf9b0838471
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
{
"name": "AsmdefHelper.DependencyGraph.Editor.Tests",
"references": [
"GUID:53e113411e7b0e947975fcd498b539aa"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5b1e278775093cb40af4ebe716362ac9
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,56 @@
using System.Collections;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class DependencyNodeExtensionsTest {
[SetUp]
public void SetUpBeforeEveryTest() {
Nodes.Init();
// [0]--->[1]--->[2]<---[3] [4]
Nodes._0.SetRequireNodes(new[] { Profiles._1 });
Nodes._1.SetRequireNodes(new[] { Profiles._2 });
Nodes._3.SetRequireNodes(new[] { Profiles._2 });
NodeProcessor.SetBeRequiredNodes(new[] { Nodes._0, Nodes._1, Nodes._2, Nodes._3, Nodes._4 });
}
[Test]
public void TestIsSourceEmpty() {
Assert.That(Nodes._0.IsSourceEmpty(), Is.True);
Assert.That(Nodes._1.IsSourceEmpty(), Is.False);
Assert.That(Nodes._2.IsSourceEmpty(), Is.False);
Assert.That(Nodes._3.IsSourceEmpty(), Is.True);
Assert.That(Nodes._4.IsSourceEmpty(), Is.True);
}
[Test]
public void TestIsDestinationEmpty() {
Assert.That(Nodes._0.IsDestinationEmpty(), Is.False);
Assert.That(Nodes._1.IsDestinationEmpty(), Is.False);
Assert.That(Nodes._2.IsDestinationEmpty(), Is.True);
Assert.That(Nodes._3.IsDestinationEmpty(), Is.False);
Assert.That(Nodes._4.IsDestinationEmpty(), Is.True);
}
[Test]
public void TestIsEmptyDependency() {
Assert.That(Nodes._0.IsEmptyDependency(), Is.False);
Assert.That(Nodes._1.IsEmptyDependency(), Is.False);
Assert.That(Nodes._2.IsEmptyDependency(), Is.False);
Assert.That(Nodes._3.IsEmptyDependency(), Is.False);
Assert.That(Nodes._4.IsEmptyDependency(), Is.True);
}
[Test]
public void TestCountDependencies() {
Assert.That(Nodes._0.CountDependencies(), Is.EqualTo(1));
Assert.That(Nodes._1.CountDependencies(), Is.EqualTo(2));
Assert.That(Nodes._2.CountDependencies(), Is.EqualTo(2));
Assert.That(Nodes._3.CountDependencies(), Is.EqualTo(1));
Assert.That(Nodes._4.CountDependencies(), Is.EqualTo(0));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 95cc92d669584f4bacd5faf7b1e78320
timeCreated: 1605543283

View File

@ -0,0 +1,19 @@
using System.Collections;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class HashSetDependencyNodeTest {
[Test]
public void TestHashSetDependencyNode() {
var node = new HashSetDependencyNode(new NodeProfile(new NodeId(1), "node"));
Assert.That(node, Is.InstanceOf<IDependencyNode>());
Assert.That(node.Profile.Id.value, Is.EqualTo(1));
Assert.That(node.Profile.Name, Is.EqualTo("node"));
Assert.That(node.Sources, Is.Empty);
Assert.That(node.Destinations, Is.Empty);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cd573c4b7c3d450da36047e4e1e03824
timeCreated: 1605450304

View File

@ -0,0 +1,42 @@
using System.Collections;
using System.Linq;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class LinerSortStrategyTest {
const float d = 10.0F;
const float w = 10.0F;
const float h = 10.0F;
const float e = 0.0001F;
ISortStrategy sortStrategy;
[SetUp]
public void SetUpBeforeEveryTest() {
Nodes.Init();
sortStrategy = new LinerSortStrategy(Vector2.zero, d, w, h);
}
[Test]
public void TestLinerNodeDependency() {
var nodes = new[] { Nodes._0, Nodes._1 };
// [0]--->[1]
Nodes._0.SetRequireNodes(new[] { Profiles._1});
NodeProcessor.SetBeRequiredNodes(nodes);
var result = sortStrategy.Sort(nodes).ToArray();
var node0 = result.FirstOrDefault(x => x.Profile == Profiles._0);
var node1 = result.FirstOrDefault(x => x.Profile == Profiles._1);
Assert.That(node0, Is.Not.Null);
Assert.That(node0.Position.x, Is.Zero);
Assert.That(node0.Position.y, Is.Zero);
Assert.That(node1, Is.Not.Null);
Assert.That(node1.Position.x, Is.EqualTo(node0.Position.x + d + (w / 2.0F)).Within(e));
Assert.That(node1.Position.y, Is.EqualTo(node0.Position.y).Within(e));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ecac0d687a574143a409b043040ce933
timeCreated: 1605460235

View File

@ -0,0 +1,26 @@
using System.Collections;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class NodeGridTest {
[Test]
public void TestNodeGrid() {
const float e = 0.000001F;
var nodeGrid = new NodeGrid(10.0F, 10.0F, 10.0F, 4);
Assert.That(nodeGrid.GridCount, Is.EqualTo(4));
var grids = nodeGrid.GridCenterPositions();
Assert.That(grids[0].x, Is.EqualTo(0.0F).Within(e));
Assert.That(grids[0].y, Is.EqualTo(0.0F).Within(e));
Assert.That(grids[1].x, Is.EqualTo(15.0F).Within(e));
Assert.That(grids[1].y, Is.EqualTo(0.0F).Within(e));
Assert.That(grids[2].x, Is.EqualTo(0.0F).Within(e));
Assert.That(grids[2].y, Is.EqualTo(15.0F).Within(e));
Assert.That(grids[3].x, Is.EqualTo(15.0F).Within(e));
Assert.That(grids[3].y, Is.EqualTo(15.0F).Within(e));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 43541e9cd66e4df59c2cac11ada769fe
timeCreated: 1605546997

View File

@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class NodeIdTest {
[Test]
public void TestNodeIdValue() {
var nodeId = new NodeId(123);
Assert.That(nodeId.value, Is.EqualTo(123));
}
[Test]
public void TestNodeIdEquals() {
var id1 = new NodeId(111);
var id2 = new NodeId(222);
var id3 = new NodeId(111);
Assert.That(id1, Is.EqualTo(id1));
Assert.That(id1, Is.Not.EqualTo(id2));
Assert.That(id1, Is.EqualTo(id3));
}
[Test]
public void TestNodeIdToString() {
var nodeId = new NodeId(999);
Assert.That(nodeId.ToString(), Is.EqualTo("999"));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 946cb4c27532a5848a9cf8c9dea05df8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,91 @@
using System.Collections;
using System.Linq;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class NodeProcessorTest {
[SetUp]
public void SetUpBeforeEveryTest() {
Nodes.Init();
}
[Test]
public void TestSetRequireNodes() {
var node = new HashSetDependencyNode(new NodeProfile(new NodeId(0), "node0"));
var p1 = new NodeProfile(new NodeId(1), "node1");
var p2 = new NodeProfile(new NodeId(2), "node2");
var p3 = new NodeProfile(new NodeId(3), "node3");
node.Sources.Add(p3);
node.SetRequireNodes(new[] { p1, p2 });
Assert.That(node.Destinations.Count, Is.EqualTo(2));
Assert.That(node.Destinations.Any(x => x.Equals(p1)));
Assert.That(node.Destinations.Any(x => x.Equals(p2)));
Assert.That(node.Sources.Count, Is.Zero);
}
[Test]
public void TestLinerNodeDependency() {
// [0]--->[1]
Nodes._0.SetRequireNodes(new[] { Profiles._1});
NodeProcessor.SetBeRequiredNodes(new[] { Nodes._0, Nodes._1 });
Assert.That(Nodes._1.Sources.Any(x => x.Equals(Profiles._0)));
}
[Test]
public void TestSomeNodeDependency() {
Nodes.SetSomeNodeDependency();
NodeProcessor.SetBeRequiredNodes(Nodes.All);
// 0
Assert.That(Nodes._0.Sources, Is.Empty);
Assert.That(Nodes._0.Destinations.Count, Is.EqualTo(2));
Assert.That(Nodes._0.Destinations.Any(x => x == Profiles._1));
Assert.That(Nodes._0.Destinations.Any(x => x == Profiles._2));
// 1
Assert.That(Nodes._1.Destinations.Count, Is.EqualTo(1));
Assert.That(Nodes._1.Sources.Any(x => x == Profiles._0));
Assert.That(Nodes._1.Destinations.Count, Is.EqualTo(1));
Assert.That(Nodes._1.Destinations.Any(x => x == Profiles._4));
// 2
Assert.That(Nodes._2.Sources.Count, Is.EqualTo(1));
Assert.That(Nodes._2.Sources.Any(x => x == Profiles._0));
Assert.That(Nodes._2.Destinations.Count, Is.EqualTo(2));
Assert.That(Nodes._2.Destinations.Any(x => x == Profiles._3));
Assert.That(Nodes._2.Destinations.Any(x => x == Profiles._4));
// 3
Assert.That(Nodes._3.Sources.Count, Is.EqualTo(2));
Assert.That(Nodes._3.Sources.Any(x => x == Profiles._2));
Assert.That(Nodes._3.Sources.Any(x => x == Profiles._5));
Assert.That(Nodes._3.Destinations, Is.Empty);
// 4
Assert.That(Nodes._4.Sources.Count, Is.EqualTo(2));
Assert.That(Nodes._4.Sources.Any(x => x == Profiles._1));
Assert.That(Nodes._4.Sources.Any(x => x == Profiles._2));
Assert.That(Nodes._4.Destinations.Count, Is.EqualTo(1));
Assert.That(Nodes._4.Destinations.Any(x => x == Profiles._5));
// 5
Assert.That(Nodes._5.Sources.Count, Is.EqualTo(1));
Assert.That(Nodes._5.Sources.Any(x => x == Profiles._4));
Assert.That(Nodes._5.Destinations.Count, Is.EqualTo(2));
Assert.That(Nodes._5.Destinations.Any(x => x == Profiles._3));
Assert.That(Nodes._5.Destinations.Any(x => x == Profiles._6));
// 6
Assert.That(Nodes._6.Sources.Count, Is.EqualTo(1));
Assert.That(Nodes._6.Sources.Any(x => x == Profiles._5));
Assert.That(Nodes._6.Destinations, Is.Empty);
// 7
Assert.That(Nodes._7.Sources, Is.Empty);
Assert.That(Nodes._7.Destinations.Count, Is.EqualTo(1));
Assert.That(Nodes._7.Destinations.Any(x => x == Profiles._8));
// 8
Assert.That(Nodes._8.Sources.Count, Is.EqualTo(1));
Assert.That(Nodes._8.Sources.Any(x => x == Profiles._7));
Assert.That(Nodes._8.Destinations, Is.Empty);
// 9
Assert.That(Nodes._9.Sources, Is.Empty);
Assert.That(Nodes._9.Destinations, Is.Empty);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9e86a8d93f3a4bb5a7c6d81b775efb47
timeCreated: 1605450647

View File

@ -0,0 +1,36 @@
using System.Collections;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class NodeProfileTest {
[Test]
public void TestNodeProfile() {
var nodeProfile = new NodeProfile(new NodeId(123), "testNode");
Assert.That(nodeProfile.Id.value, Is.EqualTo(123));
Assert.That(nodeProfile.Name, Is.EqualTo("testNode"));
}
[Test]
public void TestNodeProfileEquals() {
var profile1 = new NodeProfile(new NodeId(111), "testNode1");
var profile2 = new NodeProfile(new NodeId(222), "testNode1");
var profile3 = new NodeProfile(new NodeId(111), "testNode2");
var profile4 = new NodeProfile(new NodeId(111), "testNode1");
Assert.That(profile1, Is.EqualTo(profile1));
Assert.That(profile1, Is.Not.EqualTo(profile2));
Assert.That(profile1, Is.Not.EqualTo(profile3));
Assert.That(profile1, Is.EqualTo(profile4));
}
[Test]
public void TestNodeProfileName() {
var nodeProfile = new NodeProfile(new NodeId(123), "hoge");
nodeProfile.Name = "testNode";
Assert.That(nodeProfile.Name, Is.EqualTo("testNode"));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6550a73c9df44f0092949ddd3ea5ac06
timeCreated: 1605448488

View File

@ -0,0 +1,71 @@
using System.Collections.Generic;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public static class Ids {
public static readonly NodeId _0 = new NodeId(0);
public static readonly NodeId _1 = new NodeId(1);
public static readonly NodeId _2 = new NodeId(2);
public static readonly NodeId _3 = new NodeId(3);
public static readonly NodeId _4 = new NodeId(4);
public static readonly NodeId _5 = new NodeId(5);
public static readonly NodeId _6 = new NodeId(6);
public static readonly NodeId _7 = new NodeId(7);
public static readonly NodeId _8 = new NodeId(8);
public static readonly NodeId _9 = new NodeId(9);
}
public static class Profiles {
public static readonly NodeProfile _0 = new NodeProfile(Ids._0, "node0");
public static readonly NodeProfile _1 = new NodeProfile(Ids._1, "node1");
public static readonly NodeProfile _2 = new NodeProfile(Ids._2, "node2");
public static readonly NodeProfile _3 = new NodeProfile(Ids._3, "node3");
public static readonly NodeProfile _4 = new NodeProfile(Ids._4, "node4");
public static readonly NodeProfile _5 = new NodeProfile(Ids._5, "node5");
public static readonly NodeProfile _6 = new NodeProfile(Ids._6, "node6");
public static readonly NodeProfile _7 = new NodeProfile(Ids._7, "node7");
public static readonly NodeProfile _8 = new NodeProfile(Ids._8, "node8");
public static readonly NodeProfile _9 = new NodeProfile(Ids._9, "node9");
}
public static class Nodes {
public static readonly IDependencyNode _0 = new HashSetDependencyNode(Profiles._0);
public static readonly IDependencyNode _1 = new HashSetDependencyNode(Profiles._1);
public static readonly IDependencyNode _2 = new HashSetDependencyNode(Profiles._2);
public static readonly IDependencyNode _3 = new HashSetDependencyNode(Profiles._3);
public static readonly IDependencyNode _4 = new HashSetDependencyNode(Profiles._4);
public static readonly IDependencyNode _5 = new HashSetDependencyNode(Profiles._5);
public static readonly IDependencyNode _6 = new HashSetDependencyNode(Profiles._6);
public static readonly IDependencyNode _7 = new HashSetDependencyNode(Profiles._7);
public static readonly IDependencyNode _8 = new HashSetDependencyNode(Profiles._8);
public static readonly IDependencyNode _9 = new HashSetDependencyNode(Profiles._9);
public static readonly IEnumerable<IDependencyNode> All = new[] {
_0, _1, _2, _3, _4, _5, _6, _7, _8, _9
};
public static void Init() {
foreach (var n in All) {
n.Sources.Clear();
n.Destinations.Clear();
}
}
public static void SetSomeNodeDependency() {
/*
* ->[1]-
* [0]-->[2]-->[4]--->[5]--->[6]
*
* V
* [3]<-----------
*
* [7]--->[8] [9]
*
*/
Nodes._0.SetRequireNodes(new[] { Profiles._1, Profiles._2 });
Nodes._1.SetRequireNodes(new[] { Profiles._4 });
Nodes._2.SetRequireNodes(new[] { Profiles._3, Profiles._4 });
Nodes._4.SetRequireNodes(new[] { Profiles._5 });
Nodes._5.SetRequireNodes(new[] { Profiles._3, Profiles._6 });
Nodes._7.SetRequireNodes(new[] { Profiles._8 });
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 55ca469364f847a4827a9f2ed13c7ef4
timeCreated: 1605451653

View File

@ -0,0 +1,34 @@
using System.Collections;
using System.Linq;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class RandomSortStrategyTest {
const float d = 10.0F;
const float w = 10.0F;
const float h = 10.0F;
const float e = 0.0001F;
ISortStrategy sortStrategy;
[SetUp]
public void SetUpBeforeEveryTest() {
Nodes.Init();
sortStrategy = new RandomSortStrategy(Vector2.zero, d, w, h);
}
[Test]
public void TestLinerNodeDependency() {
var result = sortStrategy.Sort(Nodes.All).ToArray();
foreach (var node in result) {
var others = result.Where(x => x.Profile != node.Profile);
foreach (var other in others) {
Assert.That(node.Position, Is.Not.EqualTo(other.Position).Within(e));
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fa8b199e711d454f92390170a758b146
timeCreated: 1605544903

View File

@ -0,0 +1,31 @@
using System;
using System.Collections;
using AsmdefHelper.DependencyGraph.Editor.DependencyNode.Sort;
using NUnit.Framework;
using UnityEditor;
using UnityEngine.TestTools;
namespace AsmdefHelper.DependencyGraph.Editor.DependencyNode.Tests {
public class SquareValueProviderTest {
[Test]
public void TestProvideNearestSquareValue() {
var ans = SquareValueProvider.ProvideNearestSquareValue(0);
Assert.That(ans, Is.EqualTo(0));
ans = SquareValueProvider.ProvideNearestSquareValue(1);
Assert.That(ans, Is.EqualTo(1));
ans = SquareValueProvider.ProvideNearestSquareValue(4);
Assert.That(ans, Is.EqualTo(2));
ans = SquareValueProvider.ProvideNearestSquareValue(8);
Assert.That(ans, Is.EqualTo(3));
ans = SquareValueProvider.ProvideNearestSquareValue(9);
Assert.That(ans, Is.EqualTo(3));
ans = SquareValueProvider.ProvideNearestSquareValue(10);
Assert.That(ans, Is.EqualTo(4));
ans = SquareValueProvider.ProvideNearestSquareValue(10001);
Assert.That(ans, Is.EqualTo(100));
ans = SquareValueProvider.ProvideNearestSquareValue(-1);
Assert.That(ans, Is.EqualTo(0));
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 917495e8285943d4a194235a789c7bc1
timeCreated: 1605545948

View File

@ -0,0 +1,8 @@
using AsmdefHelper.DependencyGraph.Editor.NodeView;
namespace AsmdefHelper.DependencyGraph.Editor {
public interface IAsmdefNodeView : INodeView {
IPort LeftPort { get; }
IPort RightPort { get; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b6072eb937a646a4b9cd860534bd9d43
timeCreated: 1605710938

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 317ec7aeddbdec848819fcfcfcb8becb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,24 @@
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
namespace AsmdefHelper.DependencyGraph.Editor.NodeView {
public class GraphViewPort : Port, IPort {
readonly VisualElement parentContentContainer;
public GraphViewPort(VisualElement contentContainer, Direction directionType) : base(Orientation.Horizontal,
directionType, Capacity.Multi, typeof(Port)) {
parentContentContainer = contentContainer;
}
public string Label { set => portName = value; get => portName; }
public Vector2 Position => new Vector2(GetPosition().x, GetPosition().y);
public void Connect(IPort port) {
if (port is Port graphViewPort) {
parentContentContainer.Add(ConnectTo(graphViewPort));
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 44bf77af3f4d4781a1f63e6227256bec
timeCreated: 1605711889

View File

@ -0,0 +1,5 @@
namespace AsmdefHelper.DependencyGraph.Editor.NodeView {
public interface INodeView : IRect {
string Label { set; get; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 95c599809404452380ee0c65390284e4
timeCreated: 1605457329

View File

@ -0,0 +1,10 @@
using UnityEditor.Experimental.GraphView;
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.NodeView {
public interface IPort {
string Label { set; get; }
Vector2 Position { get; }
void Connect(IPort port);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 21b3446cef7248c8b533162402f8429f
timeCreated: 1605711702

View File

@ -0,0 +1,23 @@
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.NodeView {
public interface IRect {
float PositionX { set; get; }
float PositionY { set; get; }
float Height { get; }
float Width { get; }
}
public static class ViewExtension {
public static Vector2 GetPositionXY(this IRect rect) {
return new Vector2(rect.PositionX, rect.PositionY);
}
public static void SetPositionXY(this IRect rect, Vector2 pos) {
rect.PositionX = pos.x;
rect.PositionY = pos.y;
}
public static Rect AsRect(this IRect rect) {
return new Rect(rect.PositionX, rect.PositionY, rect.Width, rect.Height);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3ba20ae9f4964efaa46e9fd6f83dd819
timeCreated: 1605458617

View File

@ -0,0 +1,26 @@
using UnityEditor.Experimental.GraphView;
using UnityEngine;
namespace AsmdefHelper.DependencyGraph.Editor.NodeView {
public class UiElementsNodeView : Node, INodeView {
public string Label {
get => title;
set => title = value;
}
public float PositionX {
get => transform.position.x;
set => transform.position = new Vector3(value, PositionY, transform.position.z);
}
public float PositionY {
get => transform.position.y;
set => transform.position = new Vector3(PositionX, value, transform.position.z);
}
public float Height => contentRect.height;
public float Width => contentRect.width;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc7014a6a7494dbcbc43466c7dbcdffa
timeCreated: 1605457452

View File

@ -1,7 +1,7 @@
{
"name": "dev.n5y.asmdefhelper",
"displayName": "AsmdefHelper",
"version": "0.2.5",
"version": "0.3.0",
"unity": "2019.3",
"description": "Unity assembly definition utilities.",
"keywords": ["asmdef", "editor"],