diff --git a/Assets/SEE/Controls/Actions/ContextMenuAction.cs b/Assets/SEE/Controls/Actions/ContextMenuAction.cs index 43069152c9..e1b0b39587 100644 --- a/Assets/SEE/Controls/Actions/ContextMenuAction.cs +++ b/Assets/SEE/Controls/Actions/ContextMenuAction.cs @@ -348,6 +348,8 @@ IEnumerable options _ => throw new ArgumentOutOfRangeException() }); + // We want to empower the user to load the implementation and architecture, separately. + // This method loads only the implementation. void LoadImplementation() { LoadReflexionDataProperty dialog = new(); @@ -355,6 +357,7 @@ void LoadImplementation() WaitForInputAsync(dialog).Forget(); } + // This method loads only the architecture. void LoadArchitecture() { LoadReflexionDataProperty dialog = new(); @@ -366,17 +369,17 @@ async UniTask WaitForInputAsync(LoadReflexionDataProperty dialog) { await UniTask.WaitWhile(dialog.WaitForInputOrCancel); SEEReflexionCity city = graphElement.GameObject().ContainingCity(); - if (dialog.TryGetImplementationDataPaths(out DataPath implGXL, out DataPath projectFolder)) + if (dialog.TryGetImplementationDataPaths(out DataPath implDataPath, out DataPath projectFolder)) { - city.LoadAndDrawSubgraphAsync(implGXL, projectFolder).Forget(); - new LoadPartOfReflexionCityNetAction(city.transform.parent.name, false, implGXL, projectFolder).Execute(); + city.LoadAndDrawSubgraphAsync(implDataPath, projectFolder).Forget(); + new LoadPartOfReflexionCityNetAction(city.transform.parent.name, false, implDataPath, projectFolder).Execute(); } - if (dialog.TryGetArchitectureDataPath(out DataPath archGXL)) + if (dialog.TryGetArchitectureDataPath(out DataPath archDataPath)) { - city.LoadAndDrawSubgraphAsync(archGXL).Forget(); - new LoadPartOfReflexionCityNetAction(city.transform.parent.name, true, archGXL).Execute(); + city.LoadAndDrawSubgraphAsync(archDataPath).Forget(); + new LoadPartOfReflexionCityNetAction(city.transform.parent.name, true, archDataPath).Execute(); } } } diff --git a/Assets/SEE/Controls/Actions/ShuffleAction.cs b/Assets/SEE/Controls/Actions/ShuffleAction.cs index 4b30192c70..67e4f25c35 100644 --- a/Assets/SEE/Controls/Actions/ShuffleAction.cs +++ b/Assets/SEE/Controls/Actions/ShuffleAction.cs @@ -116,7 +116,7 @@ private void Update() // The node operator that is going to be used to move the city-root node nodeOperator = cityRootNode.gameObject.NodeOperator(); - // Where exactly have we hit the plane containing cideRootNode (if at all)? + // Where exactly have we hit the plane containing cityRootNode (if at all)? if (Raycasting.RaycastPlane(new UnityEngine.Plane(Vector3.up, cityRootNode.position), out Vector3 cityPlaneHitPoint)) { gizmo.gameObject.SetActive(true); diff --git a/Assets/SEE/DataModel/DG/IO/GXLParser.cs b/Assets/SEE/DataModel/DG/IO/GXLParser.cs index 5d5e01bdff..a2d76f440a 100644 --- a/Assets/SEE/DataModel/DG/IO/GXLParser.cs +++ b/Assets/SEE/DataModel/DG/IO/GXLParser.cs @@ -174,8 +174,11 @@ private void EnsureExpectedEndTag() /// /// Stream containing GXL data that shall be processed /// Name of the GXL data stream. Only used for display purposes in log messages + /// to report progress /// token with which the loading can be cancelled - public virtual async UniTask LoadAsync(Stream gxl, string name, CancellationToken token = default) + public virtual async UniTask LoadAsync(Stream gxl, string name, + Action changePercentage = null, + CancellationToken token = default) { Name = name; @@ -194,6 +197,8 @@ public virtual async UniTask LoadAsync(Stream gxl, string name, CancellationToke // Defined only at the EndElement, e.g. here. string lastText = string.Empty; + bool firstEdgeRead = false; + try { await UniTask.SwitchToThreadPool(); @@ -237,6 +242,11 @@ public virtual async UniTask LoadAsync(Stream gxl, string name, CancellationToke StartNode(); break; case State.InEdge: + if (!firstEdgeRead) + { + firstEdgeRead = true; + changePercentage?.Invoke(0.5f); + } StartEdge(); break; case State.InType: @@ -402,6 +412,7 @@ public virtual async UniTask LoadAsync(Stream gxl, string name, CancellationToke { Reader.Close(); await UniTask.SwitchToMainThread(); + changePercentage?.Invoke(1.0f); } if (Context.Count > 0) diff --git a/Assets/SEE/DataModel/DG/IO/GraphReader.cs b/Assets/SEE/DataModel/DG/IO/GraphReader.cs index f9de5c09ef..0d6aeb9374 100644 --- a/Assets/SEE/DataModel/DG/IO/GraphReader.cs +++ b/Assets/SEE/DataModel/DG/IO/GraphReader.cs @@ -47,13 +47,16 @@ public GraphReader(HashSet hierarchicalEdgeTypes, string basePath, strin /// path of the GXL data /// edge types forming the node hierarchy /// the base path of the graph + /// to report progress /// token with which the loading can be cancelled /// logger to log the output /// loaded graph - public static async UniTask LoadAsync(DataPath path, HashSet hierarchicalEdgeTypes, string basePath, CancellationToken token = default, Utils.ILogger logger = null) + public static async UniTask LoadAsync(DataPath path, HashSet hierarchicalEdgeTypes, string basePath, + Action changePercentage = null, CancellationToken token = default, + Utils.ILogger logger = null) { GraphReader graphReader = new(hierarchicalEdgeTypes, basePath, logger: logger); - await graphReader.LoadAsync(await path.LoadAsync(), path.Path, token); + await graphReader.LoadAsync(await path.LoadAsync(), path.Path, changePercentage, token); return graphReader.GetGraph(); } @@ -75,10 +78,13 @@ public static async UniTask LoadAsync(DataPath path, HashSet hier /// /// Stream containing GXL data that shall be processed /// Name of the GXL data stream. Only used for display purposes in log messages + /// to report progress /// token with which the loading can be cancelled - public override async UniTask LoadAsync(Stream gxl, string name = "[unknown]", CancellationToken token = default) + public override async UniTask LoadAsync(Stream gxl, string name = "[unknown]", + Action changePercentage = null, + CancellationToken token = default) { - await base.LoadAsync(gxl, name, token); + await base.LoadAsync(gxl, name, changePercentage, token); graph.BasePath = basePath; if (!string.IsNullOrWhiteSpace(rootName)) { diff --git a/Assets/SEE/DataModel/DG/Node.cs b/Assets/SEE/DataModel/DG/Node.cs index e6aa018052..781b8a33a2 100644 --- a/Assets/SEE/DataModel/DG/Node.cs +++ b/Assets/SEE/DataModel/DG/Node.cs @@ -1,7 +1,6 @@ using SEE.Tools.ReflexionAnalysis; using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; namespace SEE.DataModel.DG diff --git a/Assets/SEE/Game/City/AbstractSEECity.cs b/Assets/SEE/Game/City/AbstractSEECity.cs index 6845ac3ffd..db755cfde5 100644 --- a/Assets/SEE/Game/City/AbstractSEECity.cs +++ b/Assets/SEE/Game/City/AbstractSEECity.cs @@ -4,7 +4,6 @@ using Sirenix.Serialization; using SEE.DataModel.DG; using SEE.GO; -using SEE.Layout.NodeLayouts.Cose; using SEE.Utils; using Sirenix.OdinInspector; using UnityEngine; @@ -264,13 +263,6 @@ public ColorRange GetColorForMetric(string metricName) [Tooltip("Settings for the selection of edges."), TabGroup(EdgeFoldoutGroup), RuntimeTab(EdgeFoldoutGroup)] public EdgeSelectionAttributes EdgeSelectionSettings = new(); - /// - /// The cose graph settings. - /// - [HideInInspector] - [Obsolete] - public CoseGraphAttributes CoseGraphSettings = new(); // FIXME put into CitySettings.cs - /// /// The metrics for the visualization of erosions. /// @@ -697,50 +689,6 @@ protected static void DumpNodeMetrics(ICollection graphs) } } - /// - /// Saves all data needed for the listing of the dirs in gui in cosegraphSettings - /// - /// - [Obsolete] - public void SetupCompoundSpringEmbedder(Graph graph) - { - if (NodeLayoutSettings.Kind == NodeLayoutKind.CompoundSpringEmbedder) - { - Dictionary dirs = CoseGraphSettings.ListInnerNodeToggle; - // the new directories - Dictionary dirsLocal = new(); - - Dictionary dirsLayout = new(); - Dictionary dirsShape = new(); - - foreach (Node node in graph.Nodes()) - { - if (!node.IsLeaf()) - { - dirsShape.Add(node.ID, NodeTypes[node.Type].Shape); - dirsLocal.Add(node.ID, false); - dirsLayout.Add(node.ID, NodeLayoutSettings.Kind); - } - } - - // if the key isn't in the old dictionaries - //dirsLocal = dirsLocal.Where(i => !dirs.ContainsKey(i.Key)).ToDictionary(i => i.Key, i => i.Value); - - bool diff1 = dirs.Keys.Except(dirsLocal.Keys).Any(); - bool diff2 = dirsLocal.Keys.Except(dirs.Keys).Any(); - - if (dirs.Count != dirsLocal.Count || diff1 || diff2) - { - CoseGraphSettings.InnerNodeShape = dirsShape; - CoseGraphSettings.InnerNodeLayout = dirsLayout; - CoseGraphSettings.ListInnerNodeToggle = dirsLocal; - } - - CoseGraphSettings.LoadedForNodeTypes = NodeTypes.Where(type => type.Value.IsRelevant) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value.IsRelevant); - } - } - /// /// Adds the initial root node type to the . /// By default it is assigned the royal blue color and is false. diff --git a/Assets/SEE/Game/City/AbstractSEECityExtension.cs b/Assets/SEE/Game/City/AbstractSEECityExtension.cs deleted file mode 100644 index 5b69c2ac0a..0000000000 --- a/Assets/SEE/Game/City/AbstractSEECityExtension.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -namespace SEE.Game.City -{ - /// - /// Class with properties for a nodelayout. - /// - public class NodelayoutModel - { - /// - /// true if the nodelayout only visualize leaf nodes - /// - public readonly bool OnlyLeaves; - - /// - /// true if the nodelayout can handle sublayouts - /// - public readonly bool CanApplySublayouts; - - /// - /// true if the inner nodes enclose the leaf nodes - /// - public readonly bool InnerNodesEncloseLeafNodes; - - /// - /// true if the layout is a circular layout - /// - public readonly bool IsCircular; - - /// - /// true if the layout displays the hierarchie of the graph - /// - public readonly bool IsHierarchical; - - /// - /// constructor - /// - /// true if the nodelayout only visualize leaf nodes - /// true if the nodelayout can handle sublayouts - /// true if the inner nodes enclose the leaf nodes - /// true if the layout is a circular layout - /// true if the layout displays the hierarchie of the graph - public NodelayoutModel(bool onlyLeaves, bool canApplySublayouts, bool innerNodesEncloseLeafNodes, bool isCircular, bool isHierarchical) - { - this.OnlyLeaves = onlyLeaves; - this.CanApplySublayouts = canApplySublayouts; - this.InnerNodesEncloseLeafNodes = innerNodesEncloseLeafNodes; - this.IsCircular = isCircular; - IsHierarchical = isHierarchical; - } - } - - /// - /// class with properties for inner node kind - /// - public class InnerNodeKindsModel - { - /// - /// true if the inner node kind has a circluar shape - /// - public readonly bool IsCircular; - - /// - /// true if the inner node kind has a rectangular shape - /// - public readonly bool IsRectangular; - - /// - /// constructor - /// - /// true if the inner node kind has a circluar shape - /// true if the inner node kind has a rectangular shape - public InnerNodeKindsModel(bool isCircular, bool isRectangular) - { - this.IsCircular = isCircular; - this.IsRectangular = isRectangular; - } - } - - /// - /// Extension class for abstractSeeCity - /// - public static class AbstractSEECityExtension - { - /// - /// Returns a model for the given nodelayout - /// - /// the nodelayout - /// the model - public static NodelayoutModel GetModel(this NodeLayoutKind nodeLayout) - { - switch (nodeLayout) - { - case NodeLayoutKind.CompoundSpringEmbedder: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: true, innerNodesEncloseLeafNodes: true, isCircular: false, isHierarchical: true); - case NodeLayoutKind.EvoStreets: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: false, isCircular: false, isHierarchical: true); - case NodeLayoutKind.Balloon: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: true, isHierarchical: true); - case NodeLayoutKind.RectanglePacking: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: false, isHierarchical: true); - case NodeLayoutKind.Treemap: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: false, isHierarchical: true); - case NodeLayoutKind.IncrementalTreeMap: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: false, isHierarchical: true); - case NodeLayoutKind.CirclePacking: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: true, isHierarchical: true); - case NodeLayoutKind.Manhattan: - return new NodelayoutModel(onlyLeaves: true, canApplySublayouts: false, innerNodesEncloseLeafNodes: false, isCircular: false, isHierarchical: false); - default: - return new NodelayoutModel(onlyLeaves: false, canApplySublayouts: false, innerNodesEncloseLeafNodes: true, isCircular: false, isHierarchical: true); - } - } - - /// - /// Returns the possible inner node kinds for a layout - /// - /// the nodelayout - /// the inner node kinds - public static List GetInnerNodeKinds(this NodeLayoutKind nodeLayout) - { - List values = Enum.GetValues(typeof(NodeShapes)).Cast().ToList(); - List list = new List(); - - list = nodeLayout.GetModel().IsCircular ? values.Where(kind => kind.GetModel().IsCircular).ToList() : values.Where(kind => kind.GetModel().IsRectangular).ToList(); - list.OrderBy(kind => kind.ToString()); - return list; - } - - /// - /// Returns all nodelayout wich are possible sublayouts for the given nodelayout - /// - /// the given nodelayout - /// a list of possible sublayout - public static List GetPossibleSublayouts(this NodeLayoutKind nodeLayout) - { - List values = Enum.GetValues(typeof(NodeLayoutKind)).Cast().ToList(); - values.Remove(NodeLayoutKind.FromFile); - - if (nodeLayout == NodeLayoutKind.EvoStreets) - { - return values.Where(layout => !layout.GetModel().IsCircular).ToList(); - } - - return values; //nodeLayout.IsCircular() ? values.Where(layout => layout.IsCircular()).ToList() : values.Where(layout => !layout.IsCircular()).ToList(); - } - - /// - /// Returns the model for a node shape. - /// - /// the node shape - /// the innernodeKindModel - public static InnerNodeKindsModel GetModel(this NodeShapes shape) - { - switch (shape) - { - case NodeShapes.Blocks: - return new InnerNodeKindsModel(isCircular: false, isRectangular: true); - case NodeShapes.Cylinders: - return new InnerNodeKindsModel(isCircular: true, isRectangular: false); - case NodeShapes.Spiders: - return new InnerNodeKindsModel(isCircular: true, isRectangular: false); - case NodeShapes.Polygons: - return new InnerNodeKindsModel(isCircular: true, isRectangular: false); - case NodeShapes.Bars: - return new InnerNodeKindsModel(isCircular: true, isRectangular: false); - default: - throw new NotImplementedException($"Unexpected case {shape}"); - } - } - } -} - - diff --git a/Assets/SEE/Game/City/AbstractSEECityExtension.cs.meta b/Assets/SEE/Game/City/AbstractSEECityExtension.cs.meta deleted file mode 100644 index 5d9fe9cbe2..0000000000 --- a/Assets/SEE/Game/City/AbstractSEECityExtension.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 621ba49b55c556a488ac17930f2177e0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Game/City/AbstractSEECityIO.cs b/Assets/SEE/Game/City/AbstractSEECityIO.cs index 8eed383df9..5a082d516c 100644 --- a/Assets/SEE/Game/City/AbstractSEECityIO.cs +++ b/Assets/SEE/Game/City/AbstractSEECityIO.cs @@ -23,10 +23,6 @@ public partial class AbstractSEECity /// private const string nodeTypesLabel = "NodeTypes"; /// - /// Label in the configuration file for . - /// - private const string coseGraphSettingsLabel = "CoseGraph"; - /// /// Label in the configuration file for . /// private const string erosionSettingsLabel = "ErosionIssues"; @@ -123,7 +119,6 @@ protected virtual void Save(ConfigWriter writer) NodeLayoutSettings.Save(writer, nodeLayoutSettingsLabel); EdgeLayoutSettings.Save(writer, edgeLayoutSettingsLabel); EdgeSelectionSettings.Save(writer, edgeSelectionSettingsLabel); - CoseGraphSettings.Save(writer, coseGraphSettingsLabel); MarkerAttributes.Save(writer, markerAttributesLabel); } @@ -152,7 +147,6 @@ protected virtual void Restore(Dictionary attributes) NodeLayoutSettings.Restore(attributes, nodeLayoutSettingsLabel); EdgeLayoutSettings.Restore(attributes, edgeLayoutSettingsLabel); EdgeSelectionSettings.Restore(attributes, edgeSelectionSettingsLabel); - CoseGraphSettings.Restore(attributes, coseGraphSettingsLabel); MarkerAttributes.Restore(attributes, markerAttributesLabel); } } diff --git a/Assets/SEE/Game/City/NodeLayoutAttributes.cs b/Assets/SEE/Game/City/NodeLayoutAttributes.cs index 5b149ce61e..d005bede2e 100644 --- a/Assets/SEE/Game/City/NodeLayoutAttributes.cs +++ b/Assets/SEE/Game/City/NodeLayoutAttributes.cs @@ -5,6 +5,7 @@ using SEE.Utils.Config; using SEE.Utils.Paths; using UnityEngine; +using Sirenix.OdinInspector; namespace SEE.Game.City { @@ -18,14 +19,31 @@ public class NodeLayoutAttributes : LayoutSettings /// How to layout the nodes. /// [Tooltip("How to layout the nodes.")] - public NodeLayoutKind Kind = NodeLayoutKind.Balloon; + public NodeLayoutKind Kind = NodeLayoutKind.Treemap; /// - /// Settings for the . + /// Settings for the . /// [Tooltip("Settings for the IncrementalTreeMap layout. Used only for this kind of layout.")] + [ShowIf("@this.Kind == NodeLayoutKind.IncrementalTreeMap")] public IncrementalTreeMapAttributes IncrementalTreeMap = new(); + /// + /// The sublayout for the architecture. + /// + /// Relevant only for the reflexion layout. + [Tooltip("Layout for the architecture. Used only for the reflexion layout.")] + [ShowIf("@this.Kind == NodeLayoutKind.Reflexion")] + public NodeLayoutKind Architecture = NodeLayoutKind.Treemap; + + /// + /// The sublayout for the implementation. + /// + /// Relevant only for the reflexion layout. + [Tooltip("Layout for the implementation. Used only for the reflexion layout.")] + [ShowIf("@this.Kind == NodeLayoutKind.Reflexion")] + public NodeLayoutKind Implementation = NodeLayoutKind.Treemap; + /// /// The path for the layout file containing the node layout information. /// If the file extension is , the layout is expected @@ -40,11 +58,70 @@ public class NodeLayoutAttributes : LayoutSettings "This information is used only if 'From File' is selected as node layout.")] public DataPath LayoutPath = new(); + /// + /// The path to the layout file containing the node layout information for the architecture. + /// + /// Relevant only for the reflexion layout. + [OdinSerialize] + [Tooltip("The path to the layout file containing the node layout information for the architecture. " + + "If the file extension is GVL, the layout is expected to be stored in Axivion's Gravis layout (GVL) with 2D co-ordinates. " + + "Otherwise the layout format SDL is expected, which saves all three dimensions of a node. " + + "This information is used only if 'From File' is selected as node layout.")] + [ShowIf("@this.Kind == NodeLayoutKind.Reflexion")] + public DataPath ArchitectureLayoutPath = new(); + + /// + /// The proportion of space allocated for the architecture. + /// This number relates to the longer edge of the available rectangle. + /// + /// Relevant only for the reflexion layout. + [Tooltip("The proportion of space allocated for the architecture. This number relates to the longer edge of the available rectangle.")] + [ShowIf("@this.Kind == NodeLayoutKind.Reflexion")] + [Range(0f, 1f)] + public float ArchitectureLayoutProportion = 0.6f; + + #region Config I/O + + /// + /// Configuration label for . + /// + private const string nodeLayoutLabel = "NodeLayout"; + /// + /// Configuration label for . + /// + private const string layoutPathLabel = "LayoutPath"; + /// + /// Configuration label for . + /// + private const string incrementalTreeMapLabel = "IncrementalTreeMap"; + /// + /// Configuration label for . + /// + private const string architectureLayoutLabel = "ArchitectureLayout"; + /// + /// Configuration label for . + /// + private const string implementationLayoutLabel = "ImplementationLayout"; + /// + /// Configuration label for . + /// + private const string architectureLayoutPathLabel = "ArchitectureLayoutPath"; + /// + /// Configuration label for . + /// + private const string architectureLayoutProportionLabel = "ArchitectureLayoutProportion"; + public override void Save(ConfigWriter writer, string label) { writer.BeginGroup(label); writer.Save(Kind.ToString(), nodeLayoutLabel); LayoutPath.Save(writer, layoutPathLabel); + // Reflexion layout settings. + writer.Save(Implementation.ToString(), implementationLayoutLabel); + writer.Save(Architecture.ToString(), architectureLayoutLabel); + ArchitectureLayoutPath.Save(writer, architectureLayoutPathLabel); + writer.Save(ArchitectureLayoutProportion, architectureLayoutProportionLabel); + // IncrementalTreeMap layout settings. IncrementalTreeMap.Save(writer, incrementalTreeMapLabel); writer.EndGroup(); } @@ -57,21 +134,15 @@ public override void Restore(Dictionary attributes, string label ConfigIO.RestoreEnum(values, nodeLayoutLabel, ref Kind); LayoutPath.Restore(values, layoutPathLabel); + // Reflexion layout settings. + ConfigIO.RestoreEnum(values, implementationLayoutLabel, ref Implementation); + ConfigIO.RestoreEnum(values, architectureLayoutLabel, ref Architecture); + ArchitectureLayoutPath.Restore(values, architectureLayoutPathLabel); + ConfigIO.Restore(values, architectureLayoutProportionLabel, ref ArchitectureLayoutProportion); + // IncrementalTreeMap layout settings. IncrementalTreeMap.Restore(values, incrementalTreeMapLabel); } } - - /// - /// Configuration label for . - /// - private const string layoutPathLabel = "LayoutPath"; - /// - /// Configuration label for . - /// - private const string incrementalTreeMapLabel = "IncrementalTreeMap"; - /// - /// Configuration label for . - /// - private const string nodeLayoutLabel = "NodeLayout"; + #endregion Config I/O } } diff --git a/Assets/SEE/Game/City/NodeLayoutKind.cs b/Assets/SEE/Game/City/NodeLayoutKind.cs index 8244fc1c79..10da945043 100644 --- a/Assets/SEE/Game/City/NodeLayoutKind.cs +++ b/Assets/SEE/Game/City/NodeLayoutKind.cs @@ -10,8 +10,7 @@ public enum NodeLayoutKind : byte RectanglePacking, Treemap, CirclePacking, - Manhattan, - CompoundSpringEmbedder, + Reflexion, IncrementalTreeMap, FromFile } diff --git a/Assets/SEE/Game/City/SEECity.cs b/Assets/SEE/Game/City/SEECity.cs index e56367c751..b4f43f2aaf 100644 --- a/Assets/SEE/Game/City/SEECity.cs +++ b/Assets/SEE/Game/City/SEECity.cs @@ -120,7 +120,7 @@ protected override void ProjectPathChanged() /// /// True if the pipeline of is still running. /// - private bool IsPipelineRunning; + protected bool IsPipelineRunning; /// /// The graph to be visualized. It may be a subgraph of the loaded graph @@ -145,7 +145,6 @@ protected Graph VisualizedSubGraph else if (visualizedSubGraph == null) { visualizedSubGraph = RelevantGraph(LoadedGraph); - SetupCompoundSpringEmbedder(visualizedSubGraph); } return visualizedSubGraph; } @@ -390,7 +389,7 @@ public virtual void SaveData() /// /// Returns whether the graph has been loaded. /// - private bool IsGraphLoaded => loadedGraph != null; + protected bool IsGraphLoaded => loadedGraph != null; /// /// Draws the graph. @@ -404,62 +403,59 @@ public virtual void DrawGraph() { if (IsPipelineRunning) { - ShowNotification.Error("SEECity", "Graph provider pipeline is still running"); + ShowNotification.Error("Graph Drawing", "Graph provider pipeline is still running."); return; } - - if (LoadedGraph == null) + if (LoadedGraph != null) { - Debug.LogError("No graph loaded.\n"); + DrawGraphAsync(VisualizedSubGraph).Forget(); } else { - Graph theVisualizedSubGraph = VisualizedSubGraph; - if (ReferenceEquals(theVisualizedSubGraph, null)) - { - Debug.LogError("No graph loaded.\n"); - } - else - { - DrawAsync(theVisualizedSubGraph).Forget(); - } + ShowNotification.Error("Graph Drawing", "No graph loaded."); } + } - return; - - async UniTaskVoid DrawAsync(Graph subGraph) + /// + /// Draws . + /// Precondition: The and its metrics have been loaded. + /// + /// graph to be drawn + protected async UniTaskVoid DrawGraphAsync(Graph graph) + { + GraphRenderer renderer = new(this, graph); + try { - graphRenderer = new GraphRenderer(this, subGraph); - // We assume here that this SEECity instance was added to a game object as - // a component. The inherited attribute gameObject identifies this game object. - try + using (LoadingSpinner.ShowDeterminate($"Drawing city \"{gameObject.name}\"", out Action updateProgress)) { - using (LoadingSpinner.ShowDeterminate($"Drawing city \"{gameObject.name}\"", out Action updateProgress)) + void ReportProgress(float x) { - void ReportProgress(float x) - { - ProgressBar = x; - updateProgress(x); - } - - await graphRenderer.DrawGraphAsync(subGraph, gameObject, ReportProgress, cancellationTokenSource.Token); + ProgressBar = x; + updateProgress(x); } - } - catch (OperationCanceledException) - { - ShowNotification.Warn("Drawing cancelled", "Drawing was cancelled.\n", log: true); - throw; - } - // If we're in editmode, InitializeAfterDrawn() will be called by Start() once the - // game starts. Otherwise, in playmode, we have to call it ourselves. - if (Application.isPlaying) - { - InitializeAfterDrawn(); + await renderer.DrawGraphAsync(graph, gameObject, ReportProgress, cancellationTokenSource.Token); } } + catch (OperationCanceledException) + { + ShowNotification.Warn("Drawing cancelled", "Drawing was cancelled.\n", log: true); + throw; + } + + // If we're in editmode, InitializeAfterDrawn() will be called by Start() once the + // game starts. Otherwise, in playmode, we have to call it ourselves. + if (Application.isPlaying) + { + InitializeAfterDrawn(); + } } + /// + /// True if the graph has been drawn (and of course loaded). + /// + protected bool IsGraphDrawn => IsGraphLoaded && gameObject.IsCodeCityDrawn(); + /// /// Re-draws the graph without deleting the underlying loaded graph. /// Only the game objects generated for the nodes and edges are deleted first @@ -469,7 +465,7 @@ void ReportProgress(float x) [Button(ButtonSizes.Small, Name = "Re-Draw Data")] [ButtonGroup(DataButtonsGroup), RuntimeButton(DataButtonsGroup, "Re-Draw Data")] [PropertyOrder(DataButtonsGroupOrderDraw)] - [EnableIf(nameof(IsGraphLoaded))] + [EnableIf(nameof(IsGraphDrawn))] public void ReDrawGraph() { if (LoadedGraph == null) @@ -519,21 +515,6 @@ public void SaveLayout() } } - /// - /// Reads the a saved layout of the city from a file named . - /// The format of the written file depends upon the file extension. If the extension - /// is it is expected to be in the GVL format; otherwise - /// the file is assumed to be in the SLD format. - /// - [Button(ButtonSizes.Small)] - [ButtonGroup(DataButtonsGroup), RuntimeButton(DataButtonsGroup, "Load Layout")] - [PropertyOrder(DataButtonsGroupOrderLoadLayout)] - public void LoadLayout() - { - ICollection gameNodes = AllNodeDescendants(gameObject); - graphRenderer.LoadLayout(gameNodes, gameObject.transform.position.y); - } - /// /// This method will cancel any running graph provider pipeline and delete the currently /// loaded graph. diff --git a/Assets/SEE/Game/City/SEECityEvolution.cs b/Assets/SEE/Game/City/SEECityEvolution.cs index 3c79cc0e37..db776db4da 100644 --- a/Assets/SEE/Game/City/SEECityEvolution.cs +++ b/Assets/SEE/Game/City/SEECityEvolution.cs @@ -317,9 +317,7 @@ private void DrawGraphs(IList graphs) // there may now be multiple roots again. relevantGraph.AddSingleRoot(out Node _, name: "ROOT", type: Graph.UnknownType); } - graphs[i] = relevantGraph; - SetupCompoundSpringEmbedder(graphs[i]); } } diff --git a/Assets/SEE/Game/City/SEECityRandom.cs b/Assets/SEE/Game/City/SEECityRandom.cs index 92c4d31080..cfffc821df 100644 --- a/Assets/SEE/Game/City/SEECityRandom.cs +++ b/Assets/SEE/Game/City/SEECityRandom.cs @@ -3,7 +3,6 @@ using System.Linq; using Cysharp.Threading.Tasks; using SEE.DataModel.DG; -using SEE.GO; using SEE.Tools.RandomGraphs; using SEE.Utils.Config; using Sirenix.OdinInspector; @@ -103,97 +102,6 @@ public override UniTask LoadDataAsync() return UniTask.CompletedTask; } - /// - /// Adds clone edges for nodes whose Euclidean distance is below a threshold. - /// - /// Note: This method was used for our VISSOFT 2022 publication and should be - /// removed when the research for it is done. - /// - [Button(ButtonSizes.Small)] - [ButtonGroup(DataButtonsGroup)] - [PropertyOrder(DataButtonsGroupOrderLoad)] - [Obsolete("Remove after VISSOFT publication")] - private void AddCloneEdges() - { - float threshold = 2.75f; - - // FIXME: To be removed after the VISSOFT paper submission. - if (LoadedGraph != null) - { - ISet metrics = LoadedGraph.AllNumericNodeAttributes(); - ZScoreScale zscore = new ZScoreScale(new List { LoadedGraph }, metrics, true); - IList nodes = LoadedGraph.Nodes(); - int numberOfEdgesAdded = 0; - int numberOfComparisons = 0; - float minimumDistance = float.MaxValue; - int numberOfClones = 0; - int numberOfLeaves = 0; - - for (int i = 0; i < nodes.Count; i++) - { - if (nodes[i].IsLeaf()) - { - numberOfLeaves++; - bool isClone = false; - for (int j = i + 1; j < nodes.Count; j++) - { - if (nodes[j].IsLeaf()) - { - numberOfComparisons++; - float distance = Distance(metrics, zscore, nodes[i], nodes[j]); - if (distance < minimumDistance) - { - minimumDistance = distance; - } - if (distance <= threshold) - { - //Debug.Log($"Distance({nodes[i].ID}, {nodes[j].ID}) = {distance} <= {threshold}: {distance <= threshold}.\n"); - Debug.Log($"{nodes[i].ID};{nodes[j].ID};{distance}\n"); - LoadedGraph.AddEdge(new Edge(nodes[i], nodes[j], "clone-" + distance)); - numberOfEdgesAdded++; - isClone = true; - } - } - } - if (isClone) - { - numberOfClones++; - } - } - } - Debug.Log($"Added {numberOfEdgesAdded} clone edges for {numberOfComparisons} comparisons. Minimum distance = {minimumDistance}.\n"); - Debug.Log($"Clone rate {numberOfClones}/{numberOfLeaves} = {(float)numberOfClones / numberOfLeaves}.\n"); - } - - float Distance(ISet metrics, ZScoreScale zscore, Node left, Node right) - { - return Euclidean(GetMetrics(metrics, zscore, left), GetMetrics(metrics, zscore, right)); - } - - float[] GetMetrics(ISet metrics, ZScoreScale zscore, Node node) - { - float[] result = new float[metrics.Count]; - int i = 0; - foreach (string metric in metrics) - { - result[i] = zscore.GetMetricValue(node, metric); - i++; - } - return result; - } - - float Euclidean(float[] leftVector, float[] rightVector) - { - float result = 0; - for (int i = 0; i < leftVector.Length; i++) - { - float diff = leftVector[i] - rightVector[i]; - result += diff * diff; - } - return Mathf.Sqrt(result); - } - } - //---------------------------------------------------------------------------- // Input/output of configuration attributes //---------------------------------------------------------------------------- diff --git a/Assets/SEE/Game/City/SEEReflexionCity.cs b/Assets/SEE/Game/City/SEEReflexionCity.cs index f2a85a229a..162fcf6780 100644 --- a/Assets/SEE/Game/City/SEEReflexionCity.cs +++ b/Assets/SEE/Game/City/SEEReflexionCity.cs @@ -7,10 +7,10 @@ using SEE.UI; using Sirenix.OdinInspector; using UnityEngine; -using SEE.GraphProviders; -using SEE.Utils.Paths; using SEE.Game.CityRendering; using MoreLinq; +using SEE.GraphProviders; +using SEE.Utils.Paths; using SEE.Utils; namespace SEE.Game.City @@ -98,6 +98,7 @@ protected override void InitializeAfterDrawn() } } + #region SEEReflexionCity creation during in play mode /// /// Loads the initial reflexion city. /// @@ -191,14 +192,14 @@ private void SetInitialType(VisualNodeAttributes type, Color color) /// Returns the of this city. /// /// The if it exists, otherwise null. - public ReflexionGraphProvider GetReflexionGraphProvider() + private ReflexionGraphProvider GetReflexionGraphProvider() { ReflexionGraphProvider provider = null; DataProvider.Pipeline.ForEach(p => { - if (p is ReflexionGraphProvider) + if (p is ReflexionGraphProvider pAsReflexionGraphProvider) { - provider = (ReflexionGraphProvider)p; + provider = pAsReflexionGraphProvider; } }); return provider; @@ -214,6 +215,9 @@ public ReflexionGraphProvider GetReflexionGraphProvider() /// Nothing, it is an asynchronous method that needs to wait. public async UniTask LoadAndDrawSubgraphAsync(DataPath path, DataPath projectFolder = null) { + // FIXME (#825): This code should be moved to ReflexionGraph. It updates a subgraph. + // Clearly, what this update requires is an implementation detail of ReflexionGraph. + (Graph graph, GraphRenderer renderer) = await LoadGraphAsync(path, projectFolder == null); if (projectFolder != null) { @@ -228,7 +232,7 @@ public async UniTask LoadAndDrawSubgraphAsync(DataPath path, DataPath projectFol Node root = ReflexionGraph.GetNode(projectFolder == null? ReflexionGraph.ArchitectureRoot.ID : ReflexionGraph.ImplementationRoot.ID); // Draws the graph. - await renderer.DrawGraphAsync(graph, root.GameObject(), loadReflexionFiles: true); + await renderer.DrawGraphAsync(graph, root.GameObject(), doNotAddUniqueRoot: true); // Adds the graph to the existing reflexion graph. graph.Nodes().ForEach(node => { @@ -311,5 +315,7 @@ void AddMissingNodeTypes(Graph graph, GraphRenderer renderer) } } } + + #endregion SEEReflexionCity creation during in play mode } } diff --git a/Assets/SEE/Game/CityRendering/AbstractLayoutNode.cs b/Assets/SEE/Game/CityRendering/AbstractLayoutNode.cs index 8dcc11e059..48831825d2 100644 --- a/Assets/SEE/Game/CityRendering/AbstractLayoutNode.cs +++ b/Assets/SEE/Game/CityRendering/AbstractLayoutNode.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using SEE.DataModel.DG; +using SEE.DataModel.DG; using SEE.Layout; using UnityEngine; @@ -27,169 +26,34 @@ public abstract class AbstractLayoutNode : ILayoutNode public Node ItsNode => Node; /// - /// Constructor setting the graph corresponding to this layout node - /// and the mapping. The mapping maps all graph nodes to be - /// laid out onto their corresponding layout node and is shared among all layout nodes. - /// The given will be added to . + /// See . /// - /// graph node corresponding to this layout node - /// the mapping of graph nodes onto LayoutNodes this node should be added to - protected AbstractLayoutNode(Node node, IDictionary toLayoutNode) - { - Node = node; - ToLayoutNode = toLayoutNode; - ToLayoutNode[node] = this; - } + public override string ID => Node.ID; /// - /// The tree level of the node. Roots have level 0, for all other nodes the level is the - /// distance to its root. + /// Constructor setting the graph corresponding to this layout node. /// - private int level; - - /// - /// The tree level of the node. Roots have level 0, for all other nodes the level is the - /// distance to its root. - /// - public int Level + /// graph node corresponding to this layout node + protected AbstractLayoutNode(Node node) { - get => level; - set => level = value; + Node = node; } /// - /// The mapping from graph nodes onto layout nodes. Every layout node created by any of the - /// constructors of this class or one of its subclasses will be added to it. All layout nodes - /// given to the layout will refer to the same mapping, i.e., is the - /// same for all. The mapping will be gathered by the constructor. - /// - protected readonly IDictionary ToLayoutNode; - - /// - /// Whether this node represents a leaf. - /// - /// true if this node represents a leaf - public bool IsLeaf => Node.IsLeaf(); - - /// - /// A unique ID for a node: the ID of the graph node underlying this layout node. - /// - /// unique ID for this node - public string ID => Node.ID; - - /// - /// The parent of this node. May be null if it has none. - /// - /// Note: Parent may be null even if the underlying graph node actually has a - /// parent in the graph, yet that parent was never passed to any of the - /// constructors of this class. For instance, non-hierarchical layouts will - /// receive only leaf nodes, i.e., their parents will not be passed to the - /// layout, in which case Parent will be null. + /// Implementation of . /// - public ILayoutNode Parent + /// Name of a node type + /// True if this node has a type with the given . + public override bool HasType(string typeName) { - get - { - if (Node.Parent == null) - { - // The node does not have a parent in the original graph. - return null; - } - else if (ToLayoutNode.TryGetValue(Node.Parent, out ILayoutNode result)) - { - // The node has a parent in the original graph and that parent was passed to the layout. - return result; - } - else - { - // The node has a parent in the original graph, but it was not passed to the layout. - return null; - } - } + return Node.Type == typeName; } /// - /// The set of children of this node. Note: For nodes for which IsLeaf - /// is true, the empty list will be returned. - /// - /// Note: If a child of the node in the underlying graph, has no - /// corresponding layout node (), it will be ignored silently. - /// This is useful in situation where only a subset of nodes is to be considered for a layout. + /// Human-readable representation of this layout node for debugging purposes. /// - /// children of this node - public ICollection Children() - { - IList result; - if (!IsLeaf) - { - IList children = Node.Children(); - result = new List(children.Count); - foreach (Node node in children) - { - if (ToLayoutNode.TryGetValue(node, out ILayoutNode layoutNode)) - { - result.Add(layoutNode); - } - //else - //{ - // Debug.LogError($"Child {node.ID} of {ID} has no corresponding layout node.\n"); - //} - } - } - else - { - result = new List(); - } - return result; - } - - public void SetOrigin() - { - CenterPosition = relativePosition + sublayoutRoot.CenterPosition; - } - - public void SetRelative(ILayoutNode node) - { - relativePosition.x -= node.CenterPosition.x; - relativePosition.z -= node.CenterPosition.z; - sublayoutRoot = node; - } - - public ICollection Successors - { - get - { - ICollection successors = new List(); - foreach (Edge edge in Node.Outgoings) - { - successors.Add(ToLayoutNode[edge.Target]); - } - return successors; - } - } - - // Features defined by LayoutNode that must be implemented by subclasses. - public abstract Vector3 LocalScale { get; set; } - public abstract Vector3 AbsoluteScale { get; } - - public abstract void ScaleBy(float factor); - public abstract Vector3 CenterPosition { get; set; } - public abstract float Rotation { get; set; } - public abstract Vector3 Roof { get; } - public abstract Vector3 Ground { get; } - - private Vector3 relativePosition; - private bool isSublayoutNode; - private bool isSublayoutRoot; - private Sublayout sublayout; - private ILayoutNode sublayoutRoot; - - public Vector3 RelativePosition { get => relativePosition; set => relativePosition = value; } - public bool IsSublayoutNode { get => isSublayoutNode; set => isSublayoutNode = value; } - public bool IsSublayoutRoot { get => isSublayoutRoot; set => isSublayoutRoot = value; } - public Sublayout Sublayout { get => sublayout; set => sublayout = value; } - public ILayoutNode SublayoutRoot { get => sublayoutRoot; set => sublayoutRoot = value; } - + /// combination of , , + /// and public override string ToString() { string result = base.ToString(); @@ -197,6 +61,5 @@ public override string ToString() + " Parent=" + (Parent != null ? Parent.ID : ""); return result; } - } } diff --git a/Assets/SEE/Game/CityRendering/EdgeRenderer.cs b/Assets/SEE/Game/CityRendering/EdgeRenderer.cs index 1e089ca039..3164181a78 100644 --- a/Assets/SEE/Game/CityRendering/EdgeRenderer.cs +++ b/Assets/SEE/Game/CityRendering/EdgeRenderer.cs @@ -68,11 +68,8 @@ public IDictionary> LayoutEdges(ICollection toLayoutNode = new Dictionary(); - // One layout game node for each game node. - ICollection layoutNodes = ToLayoutNodes(gameNodes, go => new LayoutGameNode(toLayoutNode, go)); + IDictionary layoutNodes = ToLayoutNodes(gameNodes); // Now we have all nodes (game nodes and layout nodes). Next we gather the layout edges. @@ -82,13 +79,13 @@ public IDictionary> LayoutEdges(ICollection(toLayoutNode[edge.Source], toLayoutNode[edge.Target], edge)); + layoutEdges.Add(new LayoutGraphEdge(layoutNodes[edge.Source], layoutNodes[edge.Target], edge)); } } // All (graph/layout) nodes and edges are known. // We can now calculate the edge layout. - GetEdgeLayout().Create(layoutNodes, layoutEdges); + GetEdgeLayout().Create(layoutNodes.Values, layoutEdges); // Finally, we can prepare the result. IDictionary> result = new Dictionary>(layoutEdges.Count); @@ -134,15 +131,14 @@ private GameObject DrawEdge(Edge edge, GameObject from, GameObject to, bool addT // We add the ascendants of the source and target nodes in case the edge layout is hierarchical. AddAscendants(from, gameNodes); AddAscendants(to, gameNodes); - Dictionary nodeToLayoutNode = new(); // The layout nodes corresponding to those game nodes. - ICollection layoutNodes = ToLayoutNodes(gameNodes, go => new LayoutGameNode(nodeToLayoutNode, go)); + IDictionary layoutNodes = ToLayoutNodes(gameNodes); LayoutGameNode fromLayoutNode = null; // layout node in layoutNodes corresponding to source node LayoutGameNode toLayoutNode = null; // layout node in layoutNodes corresponding to target node // We need fromLayoutNode and toLayoutNode to create a single layout edge to be passed // to the edge layouter. - foreach (LayoutGameNode layoutNode in layoutNodes) + foreach (LayoutGameNode layoutNode in layoutNodes.Values) { if (layoutNode.ItsNode == edge.Source) { @@ -163,7 +159,7 @@ private GameObject DrawEdge(Edge edge, GameObject from, GameObject to, bool addT { new(fromLayoutNode, toLayoutNode, edge) }; // Calculate the edge layout (for the single edge only). - GameObject resultingEdge = EdgeLayout(layoutNodes, layoutEdges, addToGraphElementIDMap).Single(); + GameObject resultingEdge = EdgeLayout(layoutNodes.Values, layoutEdges, addToGraphElementIDMap).Single(); // The edge becomes a child of the root node of the game-node hierarchy GameObject codeCity = SceneQueries.GetCodeCity(from.transform).gameObject; @@ -280,8 +276,8 @@ public ICollection EdgeLayout(ICollection gameNodes, GameObject parent, bool addToGraphElementIDMap) { - ICollection layoutNodes = ToLayoutNodes(gameNodes); - ICollection result = EdgeLayout(layoutNodes, ConnectingEdges(layoutNodes), addToGraphElementIDMap); + IDictionary layoutNodes = ToLayoutNodes(gameNodes); + ICollection result = EdgeLayout(layoutNodes.Values, ConnectingEdges(layoutNodes.Values), addToGraphElementIDMap); AddToParent(result, parent); return result; } @@ -319,7 +315,7 @@ private async UniTask> EdgeLayoutAsync(ICollectionnodes whose connecting edges are to be laid out /// laid out edges public ICollection> LayoutEdges(ICollection layoutNodes) - where T : AbstractLayoutNode, IHierarchyNode + where T : AbstractLayoutNode { if (layoutNodes == null || layoutNodes.Count == 0) { @@ -354,7 +350,7 @@ private async UniTask> EdgeLayoutAsync(ICollection bool addToGraphElementIDMap, Action updateProgress = null, CancellationToken token = default) - where T : LayoutGameNode, IHierarchyNode + where T : LayoutGameNode { IEdgeLayout layout = GetEdgeLayout(); if (layout == null) @@ -396,7 +392,7 @@ private async UniTask> EdgeLayoutAsync(ICollection private ICollection EdgeLayout(ICollection gameNodes, ICollection> layoutEdges, bool addToGraphElementIDMap) - where T : LayoutGameNode, IHierarchyNode + where T : LayoutGameNode { IEdgeLayout layout = GetEdgeLayout(); EdgeFactory edgeFactory = new(layout, Settings.EdgeLayoutSettings.EdgeWidth); diff --git a/Assets/SEE/Game/CityRendering/GraphRenderer.cs b/Assets/SEE/Game/CityRendering/GraphRenderer.cs index 19f9bb735f..7e779e7adc 100644 --- a/Assets/SEE/Game/CityRendering/GraphRenderer.cs +++ b/Assets/SEE/Game/CityRendering/GraphRenderer.cs @@ -1,3 +1,7 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; using Cysharp.Threading.Tasks; using SEE.DataModel.DG; using SEE.Game.City; @@ -7,12 +11,7 @@ using SEE.GO.NodeFactories; using SEE.Layout; using SEE.Layout.NodeLayouts; -using SEE.Layout.NodeLayouts.Cose; using SEE.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; using UnityEngine; using Plane = SEE.GO.Plane; @@ -195,11 +194,6 @@ public void AddNewNodeType(string nodeType) /// private const float levelDistance = 0.001f; - /// - /// the ground level of the nodes - /// - private const float groundLevel = 0.0f; - /// /// The graphs to be rendered. /// @@ -213,24 +207,19 @@ public void AddNewNodeType(string nodeType) /// /// A mapping of the name of node types of onto the factories creating those nodes. /// - private readonly Dictionary nodeTypeToFactory = new Dictionary(); + private readonly Dictionary nodeTypeToFactory = new(); /// /// A mapping of the name of node types of onto the /// s creating the antennas of those nodes. /// - private readonly Dictionary nodeTypeToAntennaDectorator = new Dictionary(); + private readonly Dictionary nodeTypeToAntennaDectorator = new(); /// /// The scale used to normalize the metrics determining the lengths of the blocks. /// private IScale scaler; - /// - /// A mapping from Node to ILayoutNode. - /// - private readonly Dictionary toLayoutNode = new Dictionary(); - /// /// True if edges are to be actually drawn, that is, if the user has selected an /// edge layout different from . @@ -262,7 +251,7 @@ public void SetScaler(ICollection graphs) } /// - /// Returns a mapping of each graph Node onto its containing GameNode for every + /// Returns a mapping of each graph node onto its containing GameNode for every /// element in . /// /// @@ -280,58 +269,68 @@ private static Dictionary NodeToGameNodeMap(IEnumerable gameNodes /// /// Draws the nodes and edges of the graph and their decorations by applying the layouts according /// to the user's choice in the settings. - /// - /// the graph to be drawn; it should be one initially passed to the constructor - /// every game object drawn for this graph will be added to this parent + /// + /// If the has multiple roots, a unique root will be added to + /// whose immediate children are all previous root nodes and a game object will be created for this new root. + /// This, however, can be avoided by passing true to . + /// + /// The game objects representing the nodes will be children of , while + /// the game objects drawn for edges will always be children of the unique root game object representing + /// the code city as a whole. + /// + /// the graph to be drawn; it should be one initially passed to the constructor since + /// the node-type factories and the like are set up by the constructor + /// every game object drawn will be become an immediate child to this parent /// action to be called with the progress of the operation /// cancellation token with which to cancel the operation + /// if true, no artificial unique root node will be added if there are multiple root + /// nodes in public async UniTask DrawGraphAsync(Graph graph, GameObject parent, Action updateProgress = null, - CancellationToken token = default, bool loadReflexionFiles = false) + CancellationToken token = default, bool doNotAddUniqueRoot = false) { - // all nodes of the graph - IList nodes = graph.Nodes(); - if (nodes.Count == 0) + if (graph.NodeCount == 0) { Debug.LogWarning("The graph has no nodes.\n"); return; } - IDictionary nodeMap = await DrawNodesAsync(nodes, x => updateProgress?.Invoke(x * 0.5f), token); - // the layout to be applied - NodeLayout nodeLayout = GetLayout(parent); + // all nodes of the graph + IDictionary nodeMap = await DrawNodesAsync(graph.Nodes(), x => updateProgress?.Invoke(x * 0.5f), token); // If we have multiple roots, we need to add a unique one. - if (!loadReflexionFiles) + if (!doNotAddUniqueRoot) { AddGameRootNodeIfNecessary(graph, nodeMap); } // The representation of the nodes for the layout. - ICollection gameNodes = ToLayoutNodes(nodeMap.Values); + IDictionary gameNodes = ToLayoutNodes(nodeMap.Values); // 1) Calculate the layout. Performance p = Performance.Begin($"Node layout {Settings.NodeLayoutSettings.Kind} for {gameNodes.Count} nodes"); + // the layout to be applied + NodeLayout nodeLayout = GetLayout(); // Equivalent to gameNodes but as an ICollection instead of ICollection // (GameNode implements ILayoutNode). - ICollection layoutNodes = gameNodes.Cast().ToList(); + ICollection layoutNodes = gameNodes.Values.Cast().ToList(); // 2) Apply the calculated layout to the game objects. - nodeLayout.Apply(layoutNodes); + { + Vector3 position = parent.transform.position; + position.y += parent.transform.lossyScale.y / 2.0f + levelDistance; + NodeLayout.Apply(nodeLayout.Create(layoutNodes, position, new Vector2(parent.transform.lossyScale.x, parent.transform.lossyScale.z))); + } p.End(); Debug.Log($"Built \"{Settings.NodeLayoutSettings.Kind}\" node layout for {gameNodes.Count} nodes in {p.GetElapsedTime()} [h:m:s:ms].\n"); - // Fit layoutNodes into parent. - Fit(parent, layoutNodes); - Stack(parent, layoutNodes); - CreateGameNodeHierarchy(nodeMap, parent); // Create the laid out edges; they will be children of the unique root game node // representing the node hierarchy. This way the edges can be moved along with // the nodes. - GameObject rootGameNode = RootGameNode(loadReflexionFiles? parent.ContainingCity().gameObject : parent); + GameObject rootGameNode = RootGameNode(parent); try { - await EdgeLayoutAsync(gameNodes, rootGameNode, true, x => updateProgress?.Invoke(0.5f + x * 0.5f), token); + await EdgeLayoutAsync(gameNodes.Values, rootGameNode, true, x => updateProgress?.Invoke(0.5f + x * 0.5f), token); } catch (OperationCanceledException) { @@ -382,16 +381,6 @@ void AddGameRootNodeIfNecessary(Graph graph, IDictionary nodeM } } - /// - /// The are put just above the w.r.t. the y axis. - /// - /// plane upon which should be stacked - /// the layout nodes to be stacked - public static void Stack(GameObject plane, IEnumerable layoutNodes) - { - NodeLayout.Stack(layoutNodes, plane.transform.position.y + plane.transform.lossyScale.y / 2.0f + levelDistance); - } - /// /// Adds light to simulate an emissive effect. The new light object will be added to /// above its center such that it covers all . @@ -419,17 +408,6 @@ private void AddLight(ICollection gameObjects, GameObject parent) light.intensity = 1.0f; } - /// - /// Scales and moves the so that they fit into the . - /// - /// the parent in which to fit the - /// the nodes to be fitted into the - public static void Fit(GameObject parent, IEnumerable layoutNodes) - { - NodeLayout.Scale(layoutNodes, parent.transform.lossyScale.x, parent.transform.lossyScale.z); - NodeLayout.MoveTo(layoutNodes, parent.transform.position); - } - /// /// Creates the same nesting of all game nodes in as in /// the graph node hierarchy. Every root node in the graph node hierarchy will become @@ -458,31 +436,72 @@ public static void CreateGameNodeHierarchy(IDictionary nodeMap } /// - /// Returns the node layouter according to the settings. The node layouter will - /// place the nodes at ground level 0. This method just returns the layouter, - /// it does not actually calculate the layout. + /// Returns the node layouter according to the settings. This method just returns + /// the layouter; it does not actually calculate the layout. + /// + /// node layout selected + public NodeLayout GetLayout() => GetLayout(Settings.NodeLayoutSettings.Kind); + + /// + /// Returns the node layouter according to . This method + /// just returns the layouter; it does not actually calculate the layout. /// - /// the parent in which to fit the nodes + /// the kind of the node layout requested /// node layout selected - public NodeLayout GetLayout(GameObject parent) => - Settings.NodeLayoutSettings.Kind switch - { - NodeLayoutKind.Manhattan => new ManhattanLayout(groundLevel), - NodeLayoutKind.RectanglePacking => new RectanglePackingNodeLayout(groundLevel), - NodeLayoutKind.EvoStreets => new EvoStreetsNodeLayout(groundLevel), - NodeLayoutKind.Treemap => new TreemapLayout(groundLevel, parent.transform.lossyScale.x, parent.transform.lossyScale.z), - NodeLayoutKind.IncrementalTreeMap => new IncrementalTreeMapLayout( - groundLevel, - parent.transform.lossyScale.x, - parent.transform.lossyScale.z, - Settings.NodeLayoutSettings.IncrementalTreeMap), - NodeLayoutKind.Balloon => new BalloonNodeLayout(groundLevel), - NodeLayoutKind.CirclePacking => new CirclePackingNodeLayout(groundLevel), - NodeLayoutKind.CompoundSpringEmbedder => new CoseLayout(groundLevel, Settings), - NodeLayoutKind.FromFile => new LoadedNodeLayout(groundLevel, Settings.NodeLayoutSettings.LayoutPath.Path), - _ => throw new Exception("Unhandled node layout " + Settings.NodeLayoutSettings.Kind) + private NodeLayout GetLayout(NodeLayoutKind kind) => + kind switch + { + NodeLayoutKind.Reflexion => new ReflexionLayout(Settings.NodeLayoutSettings.ArchitectureLayoutProportion, + GetImplementationLayout(Settings.NodeLayoutSettings), + GetArchitectureLayout(Settings.NodeLayoutSettings)), + NodeLayoutKind.RectanglePacking => new RectanglePackingNodeLayout(), + NodeLayoutKind.EvoStreets => new EvoStreetsNodeLayout(), + NodeLayoutKind.Treemap => new TreemapLayout(), + NodeLayoutKind.IncrementalTreeMap => new IncrementalTreeMapLayout(Settings.NodeLayoutSettings.IncrementalTreeMap), + NodeLayoutKind.Balloon => new BalloonNodeLayout(), + NodeLayoutKind.CirclePacking => new CirclePackingNodeLayout(), + NodeLayoutKind.FromFile => new LoadedNodeLayout(Settings.NodeLayoutSettings.LayoutPath.Path), + _ => throw new Exception("Unhandled node layout " + kind) }; + /// + /// Returns the node layouter for drawing the implementation according to . + /// + /// the settings for the implementation layout + /// layouter for implementation + /// thrown if called for + private NodeLayout GetImplementationLayout(NodeLayoutAttributes nodeLayoutSettings) + { + if (nodeLayoutSettings.Implementation == NodeLayoutKind.FromFile) + { + return new LoadedNodeLayout(nodeLayoutSettings.LayoutPath.Path); + } + if (nodeLayoutSettings.Implementation == NodeLayoutKind.Reflexion) + { + throw new Exception("Reflexion layout cannot be used as an implementation layout."); + } + return GetLayout(nodeLayoutSettings.Implementation); + } + + /// + /// Returns the node layouter for drawing the architecture according to . + /// + /// the settings for the architecture layout + /// layouter for architecture + /// thrown if called for + private NodeLayout GetArchitectureLayout(NodeLayoutAttributes nodeLayoutSettings) + { + if (nodeLayoutSettings.Architecture == NodeLayoutKind.FromFile) + { + return new LoadedNodeLayout(nodeLayoutSettings.ArchitectureLayoutPath.Path); + } + if (nodeLayoutSettings.Architecture == NodeLayoutKind.Reflexion) + { + throw new Exception("Reflexion layout cannot be used as an architecture layout."); + } + return GetLayout(nodeLayoutSettings.Architecture); + } + /// /// Adds as a child to , /// maintaining the world position of . @@ -508,29 +527,35 @@ private static void AddToParent(ICollection children, GameObject par } /// - /// Transforms the given to a collection of LayoutNodes. - /// Sets the node levels of all . - /// - /// collection of game objects created to represent inner nodes or leaf nodes of a graph - /// collection of LayoutNodes representing the information of for layouting - private ICollection ToLayoutNodes(ICollection gameObjects) - { - return ToLayoutNodes(gameObjects, go => new LayoutGameNode(toLayoutNode, go)); - } - - /// - /// Transforms the given to a collection of s. - /// Sets the node levels of all . + /// Returns a mapping of all graph nodes associated with any of the given + /// onto newly created s. /// /// collection of game objects created to represent inner nodes or leaf nodes of a graph - /// delegate that returns a new layout node for each - /// collection of LayoutNodes representing the information of for layouting - private static ICollection ToLayoutNodes - (ICollection gameNodes, - Func newLayoutNode) where T : class, ILayoutNode + /// mapping of graph nodes onto newly created s + private static IDictionary ToLayoutNodes + (ICollection gameNodes) { - ICollection result = gameNodes.Select(newLayoutNode).ToList(); - LayoutNodes.SetLevels(result); + Dictionary result = new(); + foreach (GameObject gameNode in gameNodes) + { + if (gameNode.TryGetNode(out Node node)) + { + result[node] = new LayoutGameNode(gameNode); + } + } + foreach (var item in result) + { + Node parent = item.Key; + LayoutGameNode parentGameNode = item.Value; + foreach (Node child in parent.Children()) + { + if (result.TryGetValue(child, out LayoutGameNode childGameNode)) + { + parentGameNode.AddChild(childGameNode); + } + } + } + LayoutNodes.SetLevels(result.Values); return result; } @@ -544,16 +569,6 @@ private static IEnumerable FindInnerNodes(IEnumerable ga return gameNodes.Where(o => !o.IsLeaf()); } - /// - /// Returns only the leaf nodes in gameNodes as a list. - /// - /// - /// the leaf nodes in gameNodes as a list - private static IEnumerable FindLeafNodes(IEnumerable gameNodes) - { - return gameNodes.Where(o => o.IsLeaf()); - } - /// /// Draws the nodes of the graph and returns a mapping of each graph node onto its corresponding game object. /// @@ -655,7 +670,7 @@ public static void ComputeBoundingBox(ICollection layoutNodes, out foreach (ILayoutNode layoutNode in layoutNodes) { - Vector3 extent = layoutNode.LocalScale / 2.0f; + Vector3 extent = layoutNode.AbsoluteScale / 2.0f; // Note: position denotes the center of the object Vector3 position = layoutNode.CenterPosition; { @@ -694,33 +709,26 @@ public static void ComputeBoundingBox(ICollection layoutNodes, out } /// - /// Returns the child object of tagged by Tags.Node. - /// If there is no such child or if there are more than one, an exception will - /// be thrown. + /// Returns the first immediate child object of the code-city object containing + /// and tagged by . /// - /// game object representing a code city - /// child object of tagged by Tags.Node - public static GameObject RootGameNode(GameObject codeCity) + /// game object representing a node in a code city or a code city as a whole + /// first immediate child object of the code-city object containing + /// and tagged by + /// thrown if is not contained in + /// a code city or if that code city has no child tagged by + /// The code-city object is obtained via + private static GameObject RootGameNode(GameObject gameNode) { - GameObject result = null; - foreach (Transform child in codeCity.transform) + Transform codeCity = SceneQueries.GetCodeCity(gameNode.transform); + if (codeCity == null) { - if (child.CompareTag(Tags.Node)) - { - if (result == null) - { - result = child.gameObject; - } - else - { - throw new Exception($"Code city {codeCity.name} has multiple children tagged by {Tags.Node}" - + $": {result.name} and {child.name}"); - } - } + throw new Exception($"Game node {gameNode.name} is not contained in a code city."); } + GameObject result = SceneQueries.GetCityRootNode(codeCity.gameObject); if (result == null) { - throw new Exception($"Code city {codeCity.name} has no child tagged by {Tags.Node}"); + throw new Exception($"Code city {codeCity.name} has no child tagged by {Tags.Node}."); } return result; } diff --git a/Assets/SEE/Game/CityRendering/LayoutGameNode.cs b/Assets/SEE/Game/CityRendering/LayoutGameNode.cs index 6ca1f5ce0b..242bd4afda 100644 --- a/Assets/SEE/Game/CityRendering/LayoutGameNode.cs +++ b/Assets/SEE/Game/CityRendering/LayoutGameNode.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using SEE.DataModel.DG; -using SEE.GO; +using SEE.GO; using SEE.Layout; using UnityEngine; @@ -15,13 +13,11 @@ public class LayoutGameNode : AbstractLayoutNode /// /// Constructor. /// - /// the mapping of graph nodes onto s - /// this node should be added to /// the game object this layout node represents - public LayoutGameNode(IDictionary toLayoutNode, GameObject gameObject) - : base(gameObject.GetComponent().Value, toLayoutNode) + public LayoutGameNode(GameObject gameObject) + : base(gameObject.GetComponent().Value) { - this.GameObject = gameObject; + GameObject = gameObject; } /// @@ -34,13 +30,13 @@ public GameObject GetGameObject() } /// - /// The local scale of this node. + /// See . /// - public override Vector3 LocalScale + public override Vector3 AbsoluteScale { get { - return GameObject.transform.localScale; + return GameObject.transform.lossyScale; } set { @@ -49,32 +45,14 @@ public override Vector3 LocalScale } /// - /// The absolute scale of a node in world co-ordinates. - /// - /// Note: This value may be meaningful only if the node is not skewed. + /// . /// - public override Vector3 AbsoluteScale + public override void ScaleXZBy(float factor) { - get => GameObject.transform.lossyScale; - } - - /// - /// Scales this node by the given : its current - /// Scale is multiplied by . If the object - /// contains a line, the line width is multiplied by , too. - /// - /// factor by which to mulitply the scale - public override void ScaleBy(float factor) - { - LineRenderer renderer = GameObject.GetComponent(); - if (renderer != null) - { - // This object is drawn by a line. The width of the line must - // be adjusted. - renderer.startWidth *= factor; - renderer.endWidth *= factor; - } - LocalScale *= factor; + Vector3 result = AbsoluteScale; + result.x *= factor; + result.z *= factor; + AbsoluteScale = result; } /// @@ -92,6 +70,9 @@ public override Vector3 CenterPosition } } + /// + /// See . + /// public override float Rotation { get => GameObject.transform.eulerAngles.y; @@ -100,7 +81,7 @@ public override float Rotation /// - /// X-Z center position of the roof of the node in world space. + /// See . /// public override Vector3 Roof { @@ -111,7 +92,7 @@ public override Vector3 Roof } /// - /// X-Z center position of the ground of the node in world space. + /// See . /// public override Vector3 Ground { diff --git a/Assets/SEE/Game/CityRendering/LayoutGraphNode.cs b/Assets/SEE/Game/CityRendering/LayoutGraphNode.cs index 5970eb03fc..29d41f9e35 100644 --- a/Assets/SEE/Game/CityRendering/LayoutGraphNode.cs +++ b/Assets/SEE/Game/CityRendering/LayoutGraphNode.cs @@ -1,6 +1,4 @@ using SEE.DataModel.DG; -using SEE.Layout; -using System.Collections.Generic; using UnityEngine; namespace SEE.Game.CityRendering @@ -14,15 +12,11 @@ namespace SEE.Game.CityRendering public class LayoutGraphNode : AbstractLayoutNode { /// - /// Constructor setting the graph corresponding to this layout node - /// and the mapping. The mapping maps all graph nodes to be - /// laid out onto their corresponding layout node and is shared among all layout nodes. - /// The given will be added to . + /// Constructor setting the graph corresponding to this layout node. /// /// graph node corresponding to this layout node - /// the mapping of graph nodes onto LayoutNodes this node should be added to - public LayoutGraphNode(Node node, Dictionary toLayoutNode) - : base(node, toLayoutNode) + public LayoutGraphNode(Node node) + : base(node) { } /// @@ -34,27 +28,19 @@ public LayoutGraphNode(Node node, Dictionary toLayoutNode) /// /// . /// - public override Vector3 LocalScale - { - get => scale; - set => scale = value; - } - - /// - /// . - /// public override Vector3 AbsoluteScale { get => scale; + set => scale = value; } /// - /// . + /// . /// - /// factor by which to scale the node - public override void ScaleBy(float factor) + public override void ScaleXZBy(float factor) { - scale *= factor; + scale.x *= factor; + scale.z *= factor; } /// diff --git a/Assets/SEE/Game/CityRendering/NodeRenderer.cs b/Assets/SEE/Game/CityRendering/NodeRenderer.cs index 0d5c26b80b..f85635e64f 100644 --- a/Assets/SEE/Game/CityRendering/NodeRenderer.cs +++ b/Assets/SEE/Game/CityRendering/NodeRenderer.cs @@ -396,75 +396,6 @@ public void AdjustScaleOfLeaf(GameObject gameNode) } } - /// - /// Loads and applies a layout stored in . - /// - /// the nodes to be laid out - /// ground level where the lowest node will be placed (y axis) - internal void LoadLayout(ICollection gameNodes, float groundLevel) - { - if (Application.isPlaying) - { - // The LayoutGraphNode, unlike LayoutGameNode, does not change the underlying game object - // representing a node, hence, we have no unwanted side effects when calling the Layout. - ICollection layoutNodes = ToAbstractLayoutNodes(gameNodes); - LoadedNodeLayout layout = new(groundLevel, Settings.NodeLayoutSettings.LayoutPath.Path); - foreach (KeyValuePair item in layout.Layout(layoutNodes)) - { - GameObject node = GraphElementIDMap.Find(item.Key.ID); - if (node != null) - { - NodeTransform nodeTransform = item.Value; - NodeOperator nodeOperator = node.NodeOperator(); - // nodeTransform.position.y relates to the ground of the node; - // the node operator's y co-ordinate is meant to be the center - nodeTransform.Position.y += nodeTransform.Scale.y / 2; - //Debug.Log($"{node.name} [{node.transform.position}, {node.transform.lossyScale}] => [{nodeTransform.position}), ({nodeTransform.scale}]\n"); - nodeOperator.MoveTo(nodeTransform.Position); - // FIXME: Scaling doesn't work yet; likely because nodeTransform.scale is world space - // but the node operator expects local scale. - //nodeOperator.ScaleTo(nodeTransform.scale, animationDuration); - } - } - } - else - { - throw new NotImplementedException("Loading a layout is currently supported only in play mode." - + " In the editor, use 'Draw Data' instead"); - } - } - - /// - /// Yields the collection of LayoutNodes corresponding to the given . - /// Each LayoutNode has the position, scale, and rotation of the game node. The graph node - /// attached to the game node is passed on to the LayoutNode so that the graph node data is - /// available to the node layout (e.g., Parent or Children). - /// Sets also the node levels of all resulting LayoutNodes. - /// - /// collection of game objects created to represent inner nodes or leaf nodes of a graph - /// collection of LayoutNodes representing the information of for layouting - public static ICollection ToAbstractLayoutNodes(ICollection gameNodes) - { - IList result = new List(); - Dictionary toLayoutNode = new(); - - foreach (GameObject gameObject in gameNodes) - { - Node node = gameObject.GetComponent().Value; - LayoutGraphNode layoutNode = new(node, toLayoutNode) - { - // We must transfer the scale from gameObject to layoutNode. - // but the layout needs the game object's scale. - // Rotation and CenterPosition are all zero. They will be computed by the layout, - // Note: LayoutGraphNode does not make a distinction between local and absolute scale. - LocalScale = gameObject.transform.lossyScale - }; - result.Add(layoutNode); - } - LayoutNodes.SetLevels(result); - return result; - } - /// /// Returns the scale of the given as requested by the user's /// settings, i.e., what the use specified for the width, height, and depth of a node. diff --git a/Assets/SEE/Game/Evolution/EvolutionRenderer.cs b/Assets/SEE/Game/Evolution/EvolutionRenderer.cs index 37ac5d5f76..af84ad028a 100644 --- a/Assets/SEE/Game/Evolution/EvolutionRenderer.cs +++ b/Assets/SEE/Game/Evolution/EvolutionRenderer.cs @@ -193,12 +193,6 @@ public float AnimationLagFactor /// private static readonly EdgeEqualityComparer edgeEqualityComparer = new(); - /// - /// If true, inner nodes should not be rendered. This will be true if a non-hierarchical - /// layout is applied. - /// - private bool ignoreInnerNodes = true; - #region User Messages /// diff --git a/Assets/SEE/Game/Evolution/EvolutionRendererAdjust.cs b/Assets/SEE/Game/Evolution/EvolutionRendererAdjust.cs index 73ced3e21c..ddd02b6763 100644 --- a/Assets/SEE/Game/Evolution/EvolutionRendererAdjust.cs +++ b/Assets/SEE/Game/Evolution/EvolutionRendererAdjust.cs @@ -69,8 +69,8 @@ void ScaleTo(GameObject gameNode, ILayoutNode layoutNode) // hence, the two spaces may be different. // We may need to transform layoutNode.LocalScale from world space to local space. Vector3 localScale = gameNode.transform.parent == null ? - layoutNode.LocalScale - : gameNode.transform.parent.InverseTransformVector(layoutNode.LocalScale); + layoutNode.AbsoluteScale + : gameNode.transform.parent.InverseTransformVector(layoutNode.AbsoluteScale); gameNode.NodeOperator() .ScaleTo(localScale, AnimationLagFactor, updateEdges: false) diff --git a/Assets/SEE/Game/Evolution/EvolutionRendererLayout.cs b/Assets/SEE/Game/Evolution/EvolutionRendererLayout.cs index 4940dff026..8ad8b88bea 100644 --- a/Assets/SEE/Game/Evolution/EvolutionRendererLayout.cs +++ b/Assets/SEE/Game/Evolution/EvolutionRendererLayout.cs @@ -1,5 +1,6 @@ using SEE.DataModel.DG; using SEE.Game.CityRendering; +using SEE.GO; using SEE.Layout; using SEE.Layout.NodeLayouts; using SEE.Utils; @@ -84,11 +85,10 @@ private void CalculateLayout(Graph graph) List gameObjects = new(); // The layout to be applied. - NodeLayout nodeLayout = Renderer.GetLayout(gameObject); + NodeLayout nodeLayout = Renderer.GetLayout(); // Gather all nodes for the layout. - ignoreInnerNodes = !nodeLayout.IsHierarchical(); - foreach (Node node in graph.Nodes().Where(node => !ignoreInnerNodes || node.IsLeaf())) + foreach (Node node in graph.Nodes()) { // All layouts (flat and hierarchical ones) must be able to handle leaves; // hence, leaves can be added at any rate. For a hierarchical layout, we @@ -114,15 +114,11 @@ private void CalculateLayout(Graph graph) iNodeLayout.OldLayout = iOldLayout; } - // Calculate and apply the node layout - ICollection layoutNodes = GraphRenderer.ToAbstractLayoutNodes(gameObjects); - // Note: Apply applies its results only on the layoutNodes but not on the game objects - // these layoutNodes represent. Here, we leave the game objects untouched. The layout - // must be later applied when we render a city. Here, we only store the layout for later use. - nodeLayout.Apply(layoutNodes); + // Calculate and apply the node layout. + ICollection layoutNodes = ToAbstractLayoutNodes(gameObjects); + NodeLayout.Apply(nodeLayout.Create(layoutNodes, gameObject.transform.position, + new Vector2(gameObject.transform.lossyScale.x, gameObject.transform.lossyScale.z))); oldLayout = nodeLayout; - GraphRenderer.Fit(gameObject, layoutNodes); - GraphRenderer.Stack(gameObject, layoutNodes); if (edgesAreDrawn) { @@ -145,6 +141,37 @@ private void CalculateLayout(Graph graph) // the layout for every graph in the graph series for later use. } + /// + /// Yields the collection of s corresponding to the given . + /// Each has the position, scale, and rotation of the game node. The graph node + /// attached to the game node is passed on to the so that the graph node data is + /// available to the node layout (e.g., Parent or Children). + /// Sets also the node levels of all resulting . + /// + /// collection of game objects created to represent inner nodes or leaf nodes of a graph + /// collection of s representing the information + /// of for layouting + private static ICollection ToAbstractLayoutNodes(ICollection gameNodes) + { + IList result = new List(); + + foreach (GameObject gameObject in gameNodes) + { + Node node = gameObject.GetComponent().Value; + LayoutGraphNode layoutNode = new(node) + { + // We must transfer the scale from gameObject to layoutNode. + // but the layout needs the game object's scale. + // Rotation and CenterPosition are all zero. They will be computed by the layout, + // Note: LayoutGraphNode does not make a distinction between local and absolute scale. + AbsoluteScale = gameObject.transform.lossyScale + }; + result.Add(layoutNode); + } + LayoutNodes.SetLevels(result); + return result; + } + /// /// Returns a mapping of graph-node IDs onto their corresponding . /// diff --git a/Assets/SEE/Game/SceneQueries.cs b/Assets/SEE/Game/SceneQueries.cs index f16f9707bf..9b223302cc 100644 --- a/Assets/SEE/Game/SceneQueries.cs +++ b/Assets/SEE/Game/SceneQueries.cs @@ -135,7 +135,7 @@ public static HashSet GetGraphs(IEnumerable gameNodes) /// If is a node representing a code city, /// the result is considered the root of the graph. /// - /// object representing a code city (generally tagged by Tags.CodeCity) + /// object representing a code city (tagged by ) /// game object representing the root of the graph or null if there is none public static GameObject GetCityRootNode(GameObject codeCity) { @@ -152,16 +152,19 @@ public static GameObject GetCityRootNode(GameObject codeCity) /// /// Returns the farthest ancestor in the game-object hierarchy that is tagged by /// . + /// If has no parent or if its parent is not tagged by + /// , will be returned. /// /// The child transform, to find the root for. /// The root transform of given child, so the highest transform with the tag /// . - /// thrown if is null + /// thrown if + /// is null public static Transform GetCityRootTransformUpwards(Transform cityChildTransform) { if (cityChildTransform == null) { - throw new ArgumentNullException(); + throw new ArgumentNullException(nameof(cityChildTransform)); } Transform result = cityChildTransform; while (result.parent != null && result.parent.CompareTag(Tags.Node)) @@ -176,10 +179,12 @@ public static Transform GetCityRootTransformUpwards(Transform cityChildTransform /// represents a code city, that is, is tagged by . /// This ancestor is assumed to carry the settings (layout information etc.). /// If none can be found, null will be returned. + /// If is tagged by , + /// it will be returned. /// /// transform at which to start the search /// closest ancestor transform in the game-object hierarchy tagged by - /// Tags.CodeCity or null + /// or null public static Transform GetCodeCity(Transform transform) { Transform result = transform; diff --git a/Assets/SEE/GameObjects/Factories/EdgeFactory.cs b/Assets/SEE/GameObjects/Factories/EdgeFactory.cs index 09dca111af..69c91304c4 100644 --- a/Assets/SEE/GameObjects/Factories/EdgeFactory.cs +++ b/Assets/SEE/GameObjects/Factories/EdgeFactory.cs @@ -78,7 +78,7 @@ private static GameObject NewGameEdge(LayoutGraphEdge layoutGraphEdge) whe /// the layout edges for which to create game objects /// game objects representing the public IEnumerable DrawEdges(IEnumerable nodes, ICollection> edges) - where T : LayoutGameNode, IHierarchyNode + where T : LayoutGameNode { if (edges.Count == 0) { diff --git a/Assets/SEE/GraphProviders/GXLGraphProvider.cs b/Assets/SEE/GraphProviders/GXLGraphProvider.cs index 2c6c0d6655..4176dbd87e 100644 --- a/Assets/SEE/GraphProviders/GXLGraphProvider.cs +++ b/Assets/SEE/GraphProviders/GXLGraphProvider.cs @@ -27,7 +27,7 @@ public class GXLSingleGraphProvider : FileBasedSingleGraphProvider /// input graph (currently ignored) /// where the /// and will be retrieved - /// this parameter is currently ignored + /// to report progress /// this parameter is currently ignored /// loaded graph /// thrown in case @@ -39,7 +39,7 @@ public override async UniTask ProvideAsync(Graph graph, AbstractSEECity c CancellationToken token = default) { CheckArguments(city); - return await GraphReader.LoadAsync(Path, city.HierarchicalEdges, city.SourceCodeDirectory.Path, token); + return await GraphReader.LoadAsync(Path, city.HierarchicalEdges, city.SourceCodeDirectory.Path, changePercentage, token); } public override SingleGraphProviderKind GetKind() diff --git a/Assets/SEE/GraphProviders/ReflexionGraphProvider.cs b/Assets/SEE/GraphProviders/ReflexionGraphProvider.cs index 624663dca1..84a2a227d8 100644 --- a/Assets/SEE/GraphProviders/ReflexionGraphProvider.cs +++ b/Assets/SEE/GraphProviders/ReflexionGraphProvider.cs @@ -113,13 +113,12 @@ public Graph ProvideInitial(string cityName, AbstractSEECity city, { throw new ArgumentNullException(nameof(city)); } - string graphSuffix = $" ({cityName})"; - CityName += graphSuffix; - Graph architectureGraph = new("", $"Compiler{graphSuffix}"); + CityName = cityName; + Graph architectureGraph = new("", $"Architecture {cityName}"); changePercentage?.Invoke(0.33f); - Graph implementationGraph = new("", $"Files{graphSuffix}"); + Graph implementationGraph = new("", $"Implementation {cityName}"); changePercentage?.Invoke(0.66f); - Graph mappingGraph = new("", $"EmptyMapping{graphSuffix}"); + Graph mappingGraph = new("", $"Mapping {cityName}"); changePercentage?.Invoke(1.0f); return new ReflexionGraph(implementationGraph, architectureGraph, mappingGraph, CityName); } diff --git a/Assets/SEE/Layout/EdgeLayouts/BundledEdgeLayout.cs b/Assets/SEE/Layout/EdgeLayouts/BundledEdgeLayout.cs index a79ce7144b..4f2ae111d9 100644 --- a/Assets/SEE/Layout/EdgeLayouts/BundledEdgeLayout.cs +++ b/Assets/SEE/Layout/EdgeLayouts/BundledEdgeLayout.cs @@ -76,7 +76,7 @@ public override void Create(IEnumerable nodes, IEnumerable> IList layoutNodes = nodes.ToList(); if (layoutEdges.Count > 0) { - ICollection roots = GetRoots(layoutNodes).ToList(); + ICollection roots = LayoutNodes.GetRoots(layoutNodes).ToList(); Assert.IsTrue(roots.Any()); maxLevel = GetMaxLevel(roots, -1); @@ -112,17 +112,6 @@ private static int GetMaxLevel(IEnumerable nodes, int currentLevel) where return nodes.Select(node => GetMaxLevel(node.Children(), currentLevel + 1)).Prepend(max).Max(); } - /// - /// Yields all nodes in that do not have a parent, - /// i.e., are root nodes. - /// - /// list of nodes - /// all root nodes in - private static ICollection GetRoots(IEnumerable layoutNodes) where T : ILayoutNode - { - return layoutNodes.Where(layoutNode => layoutNode.Parent == null).ToList(); - } - /// /// Returns the path from to in the /// node hierarchy including the child and the ancestor. @@ -184,17 +173,16 @@ private static ILayoutNode[] Ancestors(ILayoutNode child, ILayoutNode ancestor) /// ending node /// to retrieve the lowest common ancestor of source and target /// points to draw a spline between source and target - private TinySpline.BSpline CreateSpline(T source, T target, LCAFinder lcaFinder) - where T : ILayoutNode, IHierarchyNode + private TinySpline.BSpline CreateSpline(ILayoutNode source, ILayoutNode target, LCAFinder lcaFinder) { - EqualityComparer comparer = EqualityComparer.Default; + EqualityComparer comparer = EqualityComparer.Default; if (comparer.Equals(source, target)) { return SelfLoop(source, EdgesAboveBlocks, levelDistance); } // Lowest common ancestor - T lca = lcaFinder.LCA(source, target); + ILayoutNode lca = lcaFinder.LCA(source, target); if (lca == null) { // This should never occur if we have a single root node, but may happen if diff --git a/Assets/SEE/Layout/EdgeLayouts/IEdgeLayout.cs b/Assets/SEE/Layout/EdgeLayouts/IEdgeLayout.cs index d73d8a5275..beaa679623 100644 --- a/Assets/SEE/Layout/EdgeLayouts/IEdgeLayout.cs +++ b/Assets/SEE/Layout/EdgeLayouts/IEdgeLayout.cs @@ -38,7 +38,7 @@ public string Name /// ancestors of any nodes whose edges are to be drawn /// edges for which to add way points public abstract void Create(IEnumerable nodes, IEnumerable> edges) - where T : ILayoutNode, IHierarchyNode; + where T : ILayoutNode; /// /// Orientation of the edges; diff --git a/Assets/SEE/Layout/IGameNode.cs b/Assets/SEE/Layout/IGameNode.cs new file mode 100644 index 0000000000..e1df5844ec --- /dev/null +++ b/Assets/SEE/Layout/IGameNode.cs @@ -0,0 +1,56 @@ +using UnityEngine; + +namespace SEE.Layout +{ + /// + /// Defines properties and methods for all nodes to be laid out regarding rendering. + /// + public interface IGameNode + { + /// + /// A unique ID for a node. + /// + string ID { get; } + + /// + /// True if this node has a type with the given . + /// + /// Name of a node type + /// True if this node has a type with the given . + bool HasType(string typeName); + + /// + /// The absolute scale of a node in world co-ordinates. + /// + /// Note: This value may be meaningful only if the node is not skewed. + /// + Vector3 AbsoluteScale { get; set; } + + /// + /// Scales the width (x) and depth (z) of the node by the given . + /// The height will be maintained. + /// + /// factory by which to scale the width and depth of the node + void ScaleXZBy(float factor); + + /// + /// Center position of a node in world space. + /// + Vector3 CenterPosition { get; set; } + + /// + /// Rotation around the y axis in degrees. + /// + float Rotation { get; set; } + + /// + /// X-Z center position of the roof of the node in world space. + /// + Vector3 Roof { get; } + + /// + /// X-Z center position of the ground of the node in world space. + /// + Vector3 Ground { get; } + } +} diff --git a/Assets/SEE/Layout/IGameNode.cs.meta b/Assets/SEE/Layout/IGameNode.cs.meta new file mode 100644 index 0000000000..36d78d56ff --- /dev/null +++ b/Assets/SEE/Layout/IGameNode.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7c4e4297cfd3d8b4d9d82d9ddf22e1d2 \ No newline at end of file diff --git a/Assets/SEE/Layout/IHierarchyNode.cs b/Assets/SEE/Layout/IHierarchyNode.cs index eeb8c9f3bc..ffe3ff91e7 100644 --- a/Assets/SEE/Layout/IHierarchyNode.cs +++ b/Assets/SEE/Layout/IHierarchyNode.cs @@ -5,7 +5,7 @@ namespace SEE.Layout /// /// Defines the interface of nodes in a node hierarchy. /// - /// + /// The type of the node in the hierarchy (parent and children). public interface IHierarchyNode { /// @@ -28,6 +28,19 @@ public interface IHierarchyNode /// bool IsLeaf { get; } + /// + /// Adds given to the list of children of this node. + /// + /// child to be added + void AddChild(T child); + + /// + /// Removes given from the list of children of this node. + /// + /// child to be removed + /// in case is not a child + void RemoveChild(T child); + /// /// The set of children of this node. Note: Even nodes for which IsLeaf /// returns true, may still have children. Layouts may refuse to layout diff --git a/Assets/SEE/Layout/ILayoutNode.cs b/Assets/SEE/Layout/ILayoutNode.cs index d5ae774571..6e38ae4b9d 100644 --- a/Assets/SEE/Layout/ILayoutNode.cs +++ b/Assets/SEE/Layout/ILayoutNode.cs @@ -1,112 +1,94 @@ using System.Collections.Generic; -using System.Linq; using UnityEngine; namespace SEE.Layout { - public interface IGameNode + /// + /// Defines the methods for all nodes to be laid out. + /// + public abstract class ILayoutNode : IGameNode, IHierarchyNode { /// - /// A unique ID for a node. + /// See . /// - string ID { get; } + public abstract string ID { get; } /// - /// The local scale of a node (i.e., scale relative to its parent). + /// See . /// - Vector3 LocalScale { get; set; } - + public abstract Vector3 AbsoluteScale { get; set; } /// - /// The absolute scale of a node in world co-ordinates. - /// - /// Note: This value may be meaningful only if the node is not skewed. + /// See . /// - Vector3 AbsoluteScale { get; } - + public abstract Vector3 CenterPosition { get; set; } /// - /// Scales the node by the given . + /// See . /// - /// factory by which to scale the node - void ScaleBy(float factor); - + public abstract float Rotation { get; set; } /// - /// Center position of a node in world space. + /// See . /// - Vector3 CenterPosition { get; set; } - + public abstract Vector3 Roof { get; } /// - /// Rotation around the y axis in degrees. + /// See . /// - float Rotation { get; set; } - + public abstract Vector3 Ground { get; } /// - /// X-Z center position of the roof of the node in world space. + /// See . /// - Vector3 Roof { get; } - + public abstract bool HasType(string typeName); /// - /// X-Z center position of the ground of the node in world space. + /// See . /// - Vector3 Ground { get; } - } + public abstract void ScaleXZBy(float factor); - public interface IGraphNode - { /// - /// The set of immediate successors of this node. + /// See . /// - ICollection Successors { get; } - } + public ILayoutNode Parent { get; protected set; } - public interface ISublayoutNode - { /// - /// the relative position from a sublayoutNode to its sublayoutRoot node + /// See . /// - Vector3 RelativePosition { get; set; } + public int Level { get; set; } = 0; /// - /// true if node is a sublayouNode + /// List of children of this node. /// - bool IsSublayoutNode { get; set; } + private readonly List children = new(); /// - /// true if node is a root node of a sublayout + /// See . /// - bool IsSublayoutRoot { get; set; } + public bool IsLeaf => children.Count == 0; /// - /// if the node is a sublayout root, this is the sublayout + /// See . /// - Sublayout Sublayout { get; set; } + public ICollection Children() + { + return children; + } /// - /// the sublayout root node + /// See . /// - T SublayoutRoot { get; set; } - - void SetOrigin(); - - void SetRelative(T node); - } - - /// - /// Defines the methods for all nodes to be laid out. - /// - public interface ILayoutNode : IGameNode, IGraphNode, IHierarchyNode, ISublayoutNode - { - } + public void AddChild(ILayoutNode child) + { + children.Add(child); + child.Parent = this; + } - public static class ILayoutNodeHierarchy - { /// - /// Returns all nodes in that do not have a parent. + /// See . /// - /// nodes to be queried - /// all root nodes in - public static ICollection Roots(ICollection layoutNodes) + public void RemoveChild(ILayoutNode child) { - return layoutNodes.Where(node => node.Parent == null).ToList(); + if (!children.Remove(child)) + { + throw new System.Exception("Child not found."); + } + child.Parent = null; } } -} \ No newline at end of file +} diff --git a/Assets/SEE/Layout/ILayoutNodeHierarchy.cs b/Assets/SEE/Layout/ILayoutNodeHierarchy.cs new file mode 100644 index 0000000000..bac0c5043e --- /dev/null +++ b/Assets/SEE/Layout/ILayoutNodeHierarchy.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; + +namespace SEE.Layout +{ + /// + /// Utility methods for hierarchies. + /// + public static class ILayoutNodeHierarchy + { + /// + /// Returns all nodes in that do not have a parent. + /// + /// nodes to be queried + /// all root nodes in + public static ICollection Roots(ICollection layoutNodes) + { + return layoutNodes.Where(node => node.Parent == null).ToList(); + } + + /// + /// Returns all transitive descendants of including . + /// + /// the root of the hierarchy + /// all transitive descendants of including + public static ICollection DescendantsOf(ILayoutNode parent) + { + List descendants = new(); + + DFS(parent); + + return descendants; + + void DFS(ILayoutNode node) + { + descendants.Add(node); + foreach (ILayoutNode child in node.Children()) + { + DFS(child); + } + } + } + } +} diff --git a/Assets/SEE/Layout/ILayoutNodeHierarchy.cs.meta b/Assets/SEE/Layout/ILayoutNodeHierarchy.cs.meta new file mode 100644 index 0000000000..ef5fe92c6e --- /dev/null +++ b/Assets/SEE/Layout/ILayoutNodeHierarchy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7e7f0f2952d785948868ab6e8609dbfc \ No newline at end of file diff --git a/Assets/SEE/Layout/IO/GVLReader.cs b/Assets/SEE/Layout/IO/GVLReader.cs index 6f042216a3..2a12d1cfba 100644 --- a/Assets/SEE/Layout/IO/GVLReader.cs +++ b/Assets/SEE/Layout/IO/GVLReader.cs @@ -30,14 +30,14 @@ public class GVLReader /// logger used to emit errors, warnings, etc. public GVLReader(string filename, ICollection gameNodes, float groundLevel = 0, SEE.Utils.ILogger logger = null) { - this.Filename = filename; - this.Logger = logger; + Filename = filename; + Logger = logger; this.groundLevel = groundLevel; Reader = new XmlTextReader(filename) { WhitespaceHandling = WhitespaceHandling.None }; - this.GameNodes = ToMap(gameNodes); + GameNodes = ToMap(gameNodes); // The CS (icon size) values of the nested nodes. The icon size // of a node N is the CS value of its immediate parent node. // Root nodes do not have a parent, but will try to access the CS @@ -80,7 +80,7 @@ private static Dictionary ToMap(ICollection gameNo /// layout data of their containing node. ParentNode stores the necessary /// information obtained for a parent and requested by its children. /// - protected struct ParentNode + protected readonly struct ParentNode { /// /// The icon size attribute of the parent. This value specifies the @@ -101,8 +101,8 @@ protected struct ParentNode /// parent game node public ParentNode(float cs, IGameNode gameNode) { - this.CS = cs; - this.GameNode = gameNode; + CS = cs; + GameNode = gameNode; } } @@ -578,7 +578,7 @@ protected virtual void StartNode() // Although we assign the local scale here, the node is not yet contained in any // other node, in which case local scale and world-space scale are the same. // Nodes will be nested later by the client of this layout. - gameNode.LocalScale = scale; + gameNode.AbsoluteScale = scale; gameNode.CenterPosition = position; } diff --git a/Assets/SEE/Layout/IO/SLDReader.cs b/Assets/SEE/Layout/IO/SLDReader.cs index ea5d27b197..8009aca3aa 100644 --- a/Assets/SEE/Layout/IO/SLDReader.cs +++ b/Assets/SEE/Layout/IO/SLDReader.cs @@ -73,7 +73,7 @@ public static void Read(string filename, IEnumerable gameNodes) node.CenterPosition = position; node.Rotation = eulerAngles.y; - node.LocalScale = scale; + node.AbsoluteScale = scale; } else { diff --git a/Assets/SEE/Layout/LayoutNodes.cs b/Assets/SEE/Layout/LayoutNodes.cs index baf7bed1ec..e4c70c1a05 100644 --- a/Assets/SEE/Layout/LayoutNodes.cs +++ b/Assets/SEE/Layout/LayoutNodes.cs @@ -14,7 +14,7 @@ public static class LayoutNodes /// /// nodes whose level is to be set public static void SetLevels(ICollection layoutNodes) - where T : class, ILayoutNode + where T : ILayoutNode { foreach (T root in GetRoots(layoutNodes)) { diff --git a/Assets/SEE/Layout/LayoutVertex.cs b/Assets/SEE/Layout/LayoutVertex.cs index 370f66bb41..4b13319bac 100644 --- a/Assets/SEE/Layout/LayoutVertex.cs +++ b/Assets/SEE/Layout/LayoutVertex.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using UnityEngine; +using UnityEngine; namespace SEE.Layout { @@ -16,8 +14,8 @@ public class LayoutVertex : ILayoutNode /// the unique ID of the node (a number to be converted into a string) public LayoutVertex(Vector3 initialSize, int index) { - scale = initialSize; - id = index.ToString(); + AbsoluteScale = initialSize; + this.id = index.ToString(); } /// @@ -26,7 +24,7 @@ public LayoutVertex(Vector3 initialSize, int index) /// unique ID of the node public LayoutVertex(string id) { - scale = Vector3.zero; + AbsoluteScale = Vector3.zero; this.id = id; } @@ -36,146 +34,64 @@ public LayoutVertex(string id) private readonly string id; /// - /// Immediate ancestor of the node. May be null, if the node is a root. + /// . /// - public ILayoutNode Parent { get; private set; } + public override string ID => id; - /// - /// The level of the node in the node hierarchy, that is, the number - /// of ancestors. A root has level 0. - /// - public int Level { get; set; } = 0; - - /// - /// Immediate children of the node. - /// - private readonly List children = new(); - - /// - /// Immediate children of the node. - /// - public ICollection Children() - { - return children; - } + #region IGameNode /// - /// Adds given to the children of this node. + /// Implementation of . /// - /// child node - public void AddChild(LayoutVertex node) + /// ignored + /// always false + public override bool HasType(string typeName) { - children.Add(node); - node.Parent = this; + return false; } /// - /// The local scale of the node, that is, the size of the node - /// relative to its parent. If size is Vector3.one, the node is - /// as large as its parent. + /// . /// - private Vector3 scale; + public override Vector3 AbsoluteScale { set; get; } /// - /// The local scale of the node, that is, the size of the node - /// relative to its parent. If size is Vector3.one, the node is - /// as large as its parent. + /// . /// - public Vector3 LocalScale + public override void ScaleXZBy(float factor) { - get => scale; - set => scale = value; - } - - /// - /// Increases the size of this node by the given factor. - /// - /// factor by which to multiply this node's scale - public void ScaleBy(float factor) - { - scale *= factor; - } - - public void SetOrigin() - { - throw new NotImplementedException(); - } - - public void SetRelative(ILayoutNode node) - { - throw new NotImplementedException(); + Vector3 result = AbsoluteScale; + result.x *= factor; + result.z *= factor; + AbsoluteScale = result; } /// /// The center position of the node. /// - private Vector3 centerPosition; - - /// - /// The center position of the node. - /// - public Vector3 CenterPosition - { - get => centerPosition; - set => centerPosition = value; - } + public override Vector3 CenterPosition { set; get; } /// /// The X-Z center position of the node's roof. /// - public Vector3 Roof + public override Vector3 Roof { - get => centerPosition + 0.5f * scale.y * Vector3.up; + get => CenterPosition + 0.5f * AbsoluteScale.y * Vector3.up; } /// /// The X-Z center position of the node's ground. /// - public Vector3 Ground + public override Vector3 Ground { - get => centerPosition - 0.5f * scale.y * Vector3.up; + get => CenterPosition - 0.5f * AbsoluteScale.y * Vector3.up; } - /// - /// True if this node is a leaf, that is, has no children. - /// - public bool IsLeaf => children.Count == 0; - - /// - /// The unique ID of this node. - /// - public string ID { get => id; } - - /// - /// The rotation of the node along the y axis in degrees. - /// - private float rotation; - /// /// The rotation of the node along the y axis in degrees. /// - public float Rotation - { - get => rotation; - set => rotation = value; - } - - /// - /// The set of successor nodes. - /// - public ICollection Successors => new List(); - - /// - /// The scale of the node in world space, i.e., in absolute Unity units - /// independent of its parent. - /// - public Vector3 AbsoluteScale => scale; + public override float Rotation { set; get; } - public Vector3 RelativePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public bool IsSublayoutNode { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public bool IsSublayoutRoot { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public Sublayout Sublayout { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public ILayoutNode SublayoutRoot { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public GameObject GameObject => throw new NotImplementedException(); + #endregion IGameNode } -} \ No newline at end of file +} diff --git a/Assets/SEE/Layout/NodeLayouts/BalloonNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/BalloonNodeLayout.cs index d081823a02..12a4fab17f 100644 --- a/Assets/SEE/Layout/NodeLayouts/BalloonNodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/BalloonNodeLayout.cs @@ -1,6 +1,4 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; -using System; +using System; using System.Collections.Generic; using UnityEngine; @@ -12,15 +10,9 @@ namespace SEE.Layout.NodeLayouts /// Published in: Proceeding INFOVIS '98 Proceedings of the 1998 IEEE Symposium on /// Information Visualization, Pages 19-25. /// - public class BalloonNodeLayout : HierarchicalNodeLayout + public class BalloonNodeLayout : NodeLayout { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public BalloonNodeLayout(float groundLevel) - : base(groundLevel) + static BalloonNodeLayout() { Name = "Balloon"; } @@ -28,7 +20,7 @@ public BalloonNodeLayout(float groundLevel) /// /// Information about a node necessary to draw it. /// - private struct NodeInfo + private readonly struct NodeInfo { public readonly float Radius; public readonly float OuterRadius; @@ -36,23 +28,30 @@ private struct NodeInfo public NodeInfo(float radius, float outerRadius, float referenceLengthChildren) { - this.Radius = radius; - this.OuterRadius = outerRadius; - this.ReferenceLengthChildren = referenceLengthChildren; + Radius = radius; + OuterRadius = outerRadius; + ReferenceLengthChildren = referenceLengthChildren; } } /// /// A mapping of nodes onto their circle data. /// - private readonly Dictionary nodeInfos = new Dictionary(); + private readonly Dictionary nodeInfos = new(); /// /// The node layout we compute as a result. /// private Dictionary layoutResult; - public override Dictionary Layout(IEnumerable gameNodes) + /// + /// See . + /// + /// thrown if there is no root in + protected override Dictionary Layout + (IEnumerable gameNodes, + Vector3 centerPosition, + Vector2 rectangle) { // puts the outermost circles of the roots next to each other; // later we might use a circle-packing algorithm instead, @@ -65,7 +64,7 @@ public override Dictionary Layout(IEnumerable 1 or d equals NaN. - double alpha = 2 * System.Math.Asin(childOuterRadius / (2 * parentInnerRadius)); + double alpha = 2 * Math.Asin(childOuterRadius / (2 * parentInnerRadius)); if (accummulatedAlpha > 0.0) { @@ -345,9 +341,9 @@ private void DrawCircles(ILayoutNode node, Vector3 position) } // Convert polar coordinate back to cartesian coordinate. Vector3 childCenter; - childCenter.x = position.x + (float)(parentInnerRadius * System.Math.Cos(accummulatedAlpha)); - childCenter.y = GroundLevel; - childCenter.z = position.z + (float)(parentInnerRadius * System.Math.Sin(accummulatedAlpha)); + childCenter.x = position.x + (float)(parentInnerRadius * Math.Cos(accummulatedAlpha)); + childCenter.y = position.y; + childCenter.z = position.z + (float)(parentInnerRadius * Math.Sin(accummulatedAlpha)); DrawCircles(child, childCenter); @@ -357,15 +353,5 @@ private void DrawCircles(ILayoutNode node, Vector3 position) } } } - - public override Dictionary Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts) - { - throw new NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } } diff --git a/Assets/SEE/Layout/NodeLayouts/CirclePackingNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/CirclePackingNodeLayout.cs index ddcfe0e2c0..33fb66f30e 100644 --- a/Assets/SEE/Layout/NodeLayouts/CirclePackingNodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/CirclePackingNodeLayout.cs @@ -1,6 +1,4 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.CirclePacking; -using SEE.Layout.NodeLayouts.Cose; +using SEE.Layout.NodeLayouts.CirclePacking; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -11,15 +9,9 @@ namespace SEE.Layout.NodeLayouts /// This layout packs circles closely together as a set of nested circles to decrease /// the total area of city. /// - public class CirclePackingNodeLayout : HierarchicalNodeLayout + public class CirclePackingNodeLayout : NodeLayout { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public CirclePackingNodeLayout(float groundLevel) - : base(groundLevel) + static CirclePackingNodeLayout() { Name = "Circle Packing"; } @@ -29,7 +21,15 @@ public CirclePackingNodeLayout(float groundLevel) /// private Dictionary layoutResult; - public override Dictionary Layout(IEnumerable layoutNodes) + /// + /// See . + /// + /// thrown if there is no root in + /// or if there is more than one root + protected override Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) { layoutResult = new Dictionary(); @@ -47,9 +47,9 @@ public override Dictionary Layout(IEnumerable Layout(IEnumerable /// "Globalizes" the layout. Initially, the position of children are assumed to be - /// relative to their parent, where the parent has position Vector3.zero. This - /// function adjusts the co-ordinates of all nodes to the world's co-ordinates. - /// We also adjust the ground level of each inner node by its level lift. + /// relative to their parent, where the parent has position (0, 0). This + /// function adjusts the X/Z co-ordinates of all nodes to the world's co-ordinates. /// /// the layout to be adjusted /// the position of the parent of all children /// the children to be laid out private static void MakeGlobal (Dictionary layoutResult, - Vector3 position, + Vector2 position, ICollection children) { foreach (ILayoutNode child in children) { NodeTransform childTransform = layoutResult[child]; - if (!child.IsLeaf) - { - // The inner nodes will be slightly lifted along the y axis according to their - // tree depth so that they can be stacked visually (level 0 is at the bottom). - position.y += LevelLift(child); - } - childTransform.Position += position; + Vector2 childPosition = new Vector2(childTransform.X, childTransform.Z) + position; + childTransform.MoveTo(childPosition.x, childPosition.y); layoutResult[child] = childTransform; - MakeGlobal(layoutResult, childTransform.Position, child.Children()); + MakeGlobal(layoutResult, childPosition, child.Children()); } } @@ -103,7 +97,7 @@ private float PlaceNodes(ILayoutNode parent) } else { - List circles = new List(children.Count); + List circles = new(children.Count); int i = 0; foreach (ILayoutNode child in children) @@ -132,7 +126,7 @@ private float PlaceNodes(ILayoutNode parent) // Note: The position of the transform is currently only local, relative to the zero center // within the parent node. The co-ordinates will later be adjusted to the world scope. layoutResult[circle.GameObject] - = new NodeTransform(new Vector3(circle.Center.x, GroundLevel, circle.Center.y), + = new NodeTransform(circle.Center.x, circle.Center.y, GetScale(circle.GameObject, circle.Radius)); } return outOuterRadius; @@ -151,8 +145,8 @@ private float PlaceNodes(ILayoutNode parent) /// the scale of private static Vector3 GetScale(ILayoutNode node, float radius) { - return node.IsLeaf ? node.LocalScale - : new Vector3(2 * radius, node.LocalScale.y, 2 * radius); + return node.IsLeaf ? node.AbsoluteScale + : new Vector3(2 * radius, node.AbsoluteScale.y, 2 * radius); } /// @@ -164,18 +158,8 @@ private static Vector3 GetScale(ILayoutNode node, float radius) /// radius of the minimal circle containing the given block private static float LeafRadius(ILayoutNode block) { - Vector3 extent = block.LocalScale / 2.0f; + Vector3 extent = block.AbsoluteScale / 2.0f; return Mathf.Sqrt(extent.x * extent.x + extent.z * extent.z); } - - public override Dictionary Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts) - { - throw new System.NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } } diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs deleted file mode 100644 index 7c10880ef1..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System.Collections.Generic; -using SEE.Game.City; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public abstract class AbstractSublayoutNode - { - /// - /// the root node - /// - public T Node { get; } - - /// - /// A List with removed children - /// - public List RemovedChildren { get; set; } - - /// - /// nodes of the sublayout - /// - public List Nodes { get; set; } - - /// - /// the kind of the inner nodes - /// - public NodeShapes InnerNodeKind { get; } - - /// - /// the node Layout - /// - public NodeLayoutKind NodeLayout { get; } - - /// - /// constructor - /// - /// the root node - /// the kind of the inner nodes - /// the node Layout - public AbstractSublayoutNode(T node, NodeShapes innerNodeKinds, NodeLayoutKind nodeLayouts) - { - Node = node; - InnerNodeKind = innerNodeKinds; - NodeLayout = nodeLayouts; - Nodes = new List(); - RemovedChildren = new List(); - } - } - -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs.meta deleted file mode 100644 index 646da13daf..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/AbstractSublayoutNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a0e2d6bfc011157498f650879f2febeb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs b/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs deleted file mode 100644 index f07a74c9b0..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs +++ /dev/null @@ -1,9 +0,0 @@ -/// -/// SEE.Layout.NodeLayouts.Cose provides a composite layout and -/// force-directed layouts. A composite layout is a layout -/// where one specify another layout for particular subtrees -/// of the node hierarchy. -/// -namespace SEE.Layout.NodeLayouts.Cose -{ -} \ No newline at end of file diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs.meta deleted file mode 100644 index cebe05569c..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/Cose.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ada1f109a6d6b9a439f2a5b5ba8b84a7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs deleted file mode 100644 index 085cbd2a84..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseCoarsenEdge : CoseEdge - { - /// - /// constructor for an edge of a coarsen graph - /// - /// the source node - /// the target node - public CoseCoarsenEdge(CoseNode source, CoseNode target) : base(source, target) - { - } - - /// - /// constructor - /// - public CoseCoarsenEdge() : base(null, null) - { - - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs.meta deleted file mode 100644 index a28dfb5def..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenEdge.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d8ba01e8d58a3054c90a3f106fbacd11 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs deleted file mode 100644 index b256e23a73..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseCoarsenGraph : CoseGraph - { - /// - /// the layout - /// - private readonly CoseLayout layout; - - /// - /// constructor - /// - /// the parent node - /// the graphmanager for this graph - public CoseCoarsenGraph(CoseNode parent, CoseGraphManager graphManager) : base(parent, graphManager) - { - } - - /// - /// constructor - /// - /// the layout - public CoseCoarsenGraph(CoseLayout layout) : base(null, layout.GraphManager) - { - this.layout = layout; - } - - /// - /// Coarsen this graph - /// - public void Coarsen() - { - UnmatchAll(); - - CoseCoarsenNode node1; - CoseCoarsenNode node2; - - if (Nodes.Count > 0) - { - while (!((CoseCoarsenNode)Nodes[0]).Matched) - { - node1 = (CoseCoarsenNode)Nodes[0]; - node2 = node1.GetMatching(); - - Contract(node1, node2); - } - - foreach (CoseCoarsenNode node in Nodes) - { - CoseNode newNode = layout.NewNode(); - newNode.LayoutValues.Pred1 = node.Node1.Reference; - node.Node1.Reference.LayoutValues.Next = newNode; - - if (node.Node2 != null) - { - newNode.LayoutValues.Pred2 = node.Node2.Reference; - node.Node2.Reference.LayoutValues.Next = newNode; - } - - node.Reference = newNode; - } - } - } - - /// - /// unmatches all nodes of this graph - /// - private void UnmatchAll() - { - foreach (CoseCoarsenNode node in Nodes) - { - node.Matched = false; - } - } - - /// - /// Creates a matching node for the two given nodes - /// - /// the first node - /// the second node - private void Contract(CoseCoarsenNode node1, CoseCoarsenNode node2) - { - CoseCoarsenNode node3 = new CoseCoarsenNode(); - AddNode(node3); - node3.Node1 = node1; - - foreach (CoseCoarsenNode node in node1.GetNeighborsList()) - { - if (node != node3) - { - Add(new CoseCoarsenEdge(), node3, node); - } - } - node3.Weight = node1.Weight; - - Remove(node1); - - if (node2 != null) - { - node3.Node2 = node2; - - foreach (CoseCoarsenNode node in node2.GetNeighborsList()) - { - if (node != node3) - { - Add(new CoseCoarsenEdge(), node3, node); - } - } - node3.Weight += node2.Weight; - - Remove(node2); - } - - node3.Matched = true; - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs.meta deleted file mode 100644 index a520e92210..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenGraph.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d8280768662e83b4c9e152691c5a3f3a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs deleted file mode 100644 index fa896ac353..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseCoarsenNode : CoseNode - { - /// - /// the reference node - /// - private CoseNode reference; - - /// - /// indicates whether the node was matched with another node - /// - private bool matched; - - /// - /// the weight of the node - /// - private int weight; - - /// - /// the first node of the matching - /// - private CoseCoarsenNode node1; - - /// - /// the second node of the matching - /// - private CoseCoarsenNode node2; - - public CoseNode Reference { get => reference; set => reference = value; } - public bool Matched { get => matched; set => matched = value; } - public int Weight { get => weight; set => weight = value; } - public CoseCoarsenNode Node1 { get => node1; set => node1 = value; } - public CoseCoarsenNode Node2 { get => node2; set => node2 = value; } - - /// - /// constructor, inital weight of a coarsenNode is 1 - /// - /// the original node - /// the current graphmanager - public CoseCoarsenNode(ILayoutNode node, CoseGraphManager graphManager) : base(node, graphManager) - { - weight = 1; - } - - /// - /// constructor - /// - public CoseCoarsenNode() : base(null, null) - { - } - - /// - /// Calculates the best node for a matching - /// - /// neighbour node with the smallest weight - public CoseCoarsenNode GetMatching() - { - CoseCoarsenNode minWeighted = null; - int minWeight = int.MaxValue; - - foreach (CoseCoarsenNode node in GetNeighborsList()) - { - if (!node.Matched && node != this && (node.Weight < minWeight)) - { - minWeighted = node; - minWeight = node.Weight; - } - } - return minWeighted; - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs.meta deleted file mode 100644 index 38aaecc119..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseCoarsenNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 45bffee726827c14e906dae189f1a9ab -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs deleted file mode 100644 index 5465d4f5f1..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseEdge - { - /// - /// Indicates whether the edge is an intergraph edge - /// - private bool isInterGraph; - - /// - /// the length of the edge - /// - private float length = 0.0f; - - /// - /// the length of the edge in x direction - /// - private float lengthX = 0.0f; - - /// - /// the length of the edge in y direction - /// - private float lengthY = 0.0f; - - /// - /// Indicates whether source and target node are overlapping - /// - private bool isOverlappingSourceAndTarget; - - /// - /// the lowest common ancestor of the traget and source node - /// - private CoseGraph lowestCommonAncestor; - - /// - /// the lowest common ancestor of the source node - /// - private CoseNode sourceInLca; - - /// - /// the lowest common ancestor of the target node - /// - private CoseNode targetInLca; - - /// - /// The source node - /// - private CoseNode source; - - /// - /// the target Node - /// - private CoseNode target; - - /// - /// the ideal edge length of the edge - /// - private float idealEdgeLength = CoseLayoutSettings.EdgeLength; - - /// - /// True if edge is between two graphs. - /// - public bool IsInterGraph { get => isInterGraph; set => isInterGraph = value; } - public float LengthX { get => lengthX; set => lengthX = value; } - public float LengthY { get => lengthY; set => lengthY = value; } - public bool IsOverlappingSourceAndTarget { get => isOverlappingSourceAndTarget; set => isOverlappingSourceAndTarget = value; } - public CoseGraph LowestCommonAncestor { get => lowestCommonAncestor; set => lowestCommonAncestor = value; } - public CoseNode SourceInLca { get => sourceInLca; set => sourceInLca = value; } - public CoseNode TargetInLca { get => targetInLca; set => targetInLca = value; } - public CoseNode Source { get => source; set => source = value; } - public CoseNode Target { get => target; set => target = value; } - public float IdealEdgeLength { get => idealEdgeLength; set => idealEdgeLength = value; } - public float Length { get => length; set => length = value; } - - /// - /// Constructor - /// - /// the source node of the edge - /// the target node of the edge - public CoseEdge(CoseNode source, CoseNode target) - { - this.source = source; - this.target = target; - } - - /// - /// Returns the other end of the edge if in this graph - /// - /// the node on the one end - /// the corresponding graph - /// - public CoseNode GetOtherEndInGraph(CoseNode node, CoseGraph graph) - { - CoseNode otherEnd = GetOtherEnd(node); - CoseGraph root = graph.GraphManager.RootGraph; - - while (true) - { - if (otherEnd.Owner == graph) - { - return otherEnd; - } - - if (otherEnd.Owner == root) - { - break; - } - - otherEnd = otherEnd.Owner.Parent; - } - return null; - } - - /// - /// Returns the other end node of the edge - /// - /// - /// the other end node of this edge - public CoseNode GetOtherEnd(CoseNode node) - { - if (node.Equals(source)) - { - return target; - } - else if (node.Equals(target)) - { - return source; - } - else - { - throw new System.Exception("Node is not incident"); - } - } - - /// - /// Calculates and sets the current length of the edge if all nodes have the same size - /// - public void UpdateLengthSimple() - { - lengthX = target.GetCenterX() - source.GetCenterX(); - lengthY = target.GetCenterY() - source.GetCenterY(); - - if (Mathf.Abs(lengthX) < 1.0) - { - lengthX = CoseHelper.Sign(lengthX); - } - - if (Mathf.Abs(lengthY) < 1.0) - { - lengthY = CoseHelper.Sign(lengthY); - } - - length = Mathf.Sqrt(lengthX * lengthX + lengthY * lengthY); - } - - /// - /// updates the legth of the edge (different node sizes) - /// - public void UpdateLenght() - { - double[] clipPointCoordinates = new double[4]; - Tuple result = CoseGeometry.GetIntersection(CoseHelper.NewRect(target.Scale, target.CenterPosition), CoseHelper.NewRect(source.Scale, source.CenterPosition), clipPointCoordinates); - isOverlappingSourceAndTarget = result.Item1; - clipPointCoordinates = result.Item2; - - if (!isOverlappingSourceAndTarget) - { - lengthX = (float)clipPointCoordinates[0] - (float)clipPointCoordinates[2]; - lengthY = (float)clipPointCoordinates[1] - (float)clipPointCoordinates[3]; - - if (Mathf.Abs(lengthX) < 1.0) - { - lengthX = CoseHelper.Sign(lengthX); - } - - if (Mathf.Abs(lengthY) < 1.0) - { - lengthY = CoseHelper.Sign(lengthY); - } - - length = Mathf.Sqrt(lengthX * lengthX + lengthY * lengthY); - } - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs.meta deleted file mode 100644 index feae051c4c..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseEdge.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 939e2b53f574b334aa75787ab75669f2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs deleted file mode 100644 index e29658f735..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public static class CoseGeometry - { - /// - /// Calculates the amount of intersection between two rectangles - /// - /// the first rectangle - /// the second rectangle - /// the result values - /// a tuple(intersect, result), intersect indictates if they intersect and result contains the resulting values - public static Tuple GetIntersection(Rect rectA, Rect rectB, double[] result) - { - //result[0-1] will contain clipPoint of rectA, result[2-3] will contain clipPoint of rectB - - double p1x = rectA.center.x; - double p1y = rectA.center.y; - double p2x = rectB.center.x; - double p2y = rectB.center.y; - - //if two rectangles intersect, then clipping points are centers - if (rectA.Overlaps(rectB)) - { - result[0] = p1x; - result[1] = p1y; - result[2] = p2x; - result[3] = p2y; - return new Tuple(true, result); - } - - //variables for rectA - double topLeftAx = rectA.x; - double topLeftAy = rectA.y; - double topRightAx = rectA.x + rectA.width; - double bottomLeftAx = rectA.x; - double bottomLeftAy = rectA.y + rectA.height; - double bottomRightAx = rectA.x + rectA.width; - double halfWidthA = rectA.width / 2; - double halfHeightA = rectA.height / 2; - - //variables for rectB - double topLeftBx = rectB.x; - double topLeftBy = rectB.y; - double topRightBx = rectB.x + rectB.width; - double bottomLeftBx = rectB.x; - double bottomLeftBy = rectB.y + rectB.height; - double bottomRightBx = rectB.x + rectB.width; - double halfWidthB = rectB.width / 2; - double halfHeightB = rectB.height / 2; - - //flag whether clipping points are found - bool clipPointAFound = false; - bool clipPointBFound = false; - - - // line is vertical - if (p1x == p2x) - { - if (p1y > p2y) - { - result[0] = p1x; - result[1] = topLeftAy; - result[2] = p2x; - result[3] = bottomLeftBy; - return new Tuple(false, result); - } - else if (p1y < p2y) - { - result[0] = p1x; - result[1] = bottomLeftAy; - result[2] = p2x; - result[3] = topLeftBy; - return new Tuple(false, result); - } - else - { - //not line, return null; - } - } - // line is horizontal - else if (p1y == p2y) - { - if (p1x > p2x) - { - result[0] = topLeftAx; - result[1] = p1y; - result[2] = topRightBx; - result[3] = p2y; - return new Tuple(false, result); - } - else if (p1x < p2x) - { - result[0] = topRightAx; - result[1] = p1y; - result[2] = topLeftBx; - result[3] = p2y; - return new Tuple(false, result); - } - else - { - //not valid line, return null; - } - } - else - { - //slopes of rectA's and rectB's diagonals - double slopeA = rectA.height / rectA.width; - double slopeB = rectB.height / rectB.width; - - //slope of line between center of rectA and center of rectB - double slopePrime = (p2y - p1y) / (p2x - p1x); - int cardinalDirectionA; - int cardinalDirectionB; - double tempPointAx; - double tempPointAy; - double tempPointBx; - double tempPointBy; - - //determine whether clipping point is the corner of nodeA - if ((-slopeA) == slopePrime) - { - if (p1x > p2x) - { - result[0] = bottomLeftAx; - result[1] = bottomLeftAy; - clipPointAFound = true; - } - else - { - result[0] = topRightAx; - result[1] = topLeftAy; - clipPointAFound = true; - } - } - else if (slopeA == slopePrime) - { - if (p1x > p2x) - { - result[0] = topLeftAx; - result[1] = topLeftAy; - clipPointAFound = true; - } - else - { - result[0] = bottomRightAx; - result[1] = bottomLeftAy; - clipPointAFound = true; - } - } - - //determine whether clipping point is the corner of nodeB - if ((-slopeB) == slopePrime) - { - if (p2x > p1x) - { - result[2] = bottomLeftBx; - result[3] = bottomLeftBy; - clipPointBFound = true; - } - else - { - result[2] = topRightBx; - result[3] = topLeftBy; - clipPointBFound = true; - } - } - else if (slopeB == slopePrime) - { - if (p2x > p1x) - { - result[2] = topLeftBx; - result[3] = topLeftBy; - clipPointBFound = true; - } - else - { - result[2] = bottomRightBx; - result[3] = bottomLeftBy; - clipPointBFound = true; - } - } - - //if both clipping points are corners - if (clipPointAFound && clipPointBFound) - { - return new Tuple(false, result); - } - - //determine Cardinal Direction of rectangles - if (p1x > p2x) - { - if (p1y > p2y) - { - cardinalDirectionA = GetCardinalDirection(slopeA, slopePrime, 4); - cardinalDirectionB = GetCardinalDirection(slopeB, slopePrime, 2); - } - else - { - cardinalDirectionA = GetCardinalDirection(-slopeA, slopePrime, 3); - cardinalDirectionB = GetCardinalDirection(-slopeB, slopePrime, 1); - } - } - else - { - if (p1y > p2y) - { - cardinalDirectionA = GetCardinalDirection(-slopeA, slopePrime, 1); - cardinalDirectionB = GetCardinalDirection(-slopeB, slopePrime, 3); - } - else - { - cardinalDirectionA = GetCardinalDirection(slopeA, slopePrime, 2); - cardinalDirectionB = GetCardinalDirection(slopeB, slopePrime, 4); - } - } - //calculate clipping Point if it is not found before - if (!clipPointAFound) - { - switch (cardinalDirectionA) - { - case 1: - tempPointAy = topLeftAy; - tempPointAx = p1x + (-halfHeightA) / slopePrime; - result[0] = tempPointAx; - result[1] = tempPointAy; - break; - case 2: - tempPointAx = bottomRightAx; - tempPointAy = p1y + halfWidthA * slopePrime; - result[0] = tempPointAx; - result[1] = tempPointAy; - break; - case 3: - tempPointAy = bottomLeftAy; - tempPointAx = p1x + halfHeightA / slopePrime; - result[0] = tempPointAx; - result[1] = tempPointAy; - break; - case 4: - tempPointAx = bottomLeftAx; - tempPointAy = p1y + (-halfWidthA) * slopePrime; - result[0] = tempPointAx; - result[1] = tempPointAy; - break; - } - } - if (!clipPointBFound) - { - switch (cardinalDirectionB) - { - case 1: - tempPointBy = topLeftBy; - tempPointBx = p2x + (-halfHeightB) / slopePrime; - result[2] = tempPointBx; - result[3] = tempPointBy; - break; - case 2: - tempPointBx = bottomRightBx; - tempPointBy = p2y + halfWidthB * slopePrime; - result[2] = tempPointBx; - result[3] = tempPointBy; - break; - case 3: - tempPointBy = bottomLeftBy; - tempPointBx = p2x + halfHeightB / slopePrime; - result[2] = tempPointBx; - result[3] = tempPointBy; - break; - case 4: - tempPointBx = bottomLeftBx; - tempPointBy = p2y + (-halfWidthB) * slopePrime; - result[2] = tempPointBx; - result[3] = tempPointBy; - break; - } - } - - } - - return new Tuple(false, result); - } - - private static int GetCardinalDirection(double slope, double slopePrime, int line) - { - if (slope > slopePrime) - { - return line; - } - else - { - return 1 + (line % 4); - } - } - - /// - /// Calculates in which direction two rectangles overlap - /// - /// the first rectangle - /// the second rectangle - /// the directions, -1 = left/top, 1 = right/bottom - private static void DecideDirectionsForOverlappingNodes(Rect rectA, Rect rectB, double[] directions) - { - if (rectA.center.x < rectB.center.x) - { - directions[0] = -1; - } - else - { - directions[0] = 1; - } - - if (rectA.center.y < rectB.center.y) - { - directions[1] = -1; - } - else - { - directions[1] = 1; - } - } - - /// - /// calculates the separation amount between two given rectangles - /// - /// the first rectangle - /// the second rectangle - /// the amount of overlapping - /// the separation buffer - public static void CalcSeparationAmount(Rect rectA, Rect rectB, double[] overlapAmount, double separationBuffer) - { - //Rect rectA = _rectA; - if (!rectA.Overlaps(rectB)) - { - throw new System.Exception("Needs overlap"); - } - - double[] directions = new double[2]; - - DecideDirectionsForOverlappingNodes(rectA, rectB, directions); - - overlapAmount[0] = Mathf.Min(rectA.xMax, rectB.xMax) - - Mathf.Max(rectA.x, rectB.x); - overlapAmount[1] = Mathf.Min(rectA.yMax, rectB.yMax) - - Mathf.Max(rectA.y, rectB.y); - - // update the overlapping amounts for the following cases: - - if ((rectA.x <= rectB.x) && (rectA.xMax >= rectB.xMax)) - // Case x.1: - // - // rectA - // | | - // | _________ | - // | | | | - // | ________ | _______ | ______ | - // | | - // | | - // rectB - { - overlapAmount[0] += Mathf.Min((rectB.x - rectA.x), - (rectA.xMax - rectB.xMax)); - } - else if ((rectB.x <= rectA.x) && (rectB.xMax >= rectA.xMax)) - // Case x.2: - // * - // rectB - // | | - // | _________ | - // | | | | - // |________|_______|______| - // | | - // | | - // rectA - { - overlapAmount[0] += Mathf.Min((rectA.x - rectB.x), - (rectB.xMax - rectA.xMax)); - } - - if ((rectA.y <= rectB.y) && (rectA.yMax >= rectB.yMax)) - // Case y.1: - // ________ rectA - // | - // | - // ______|____ rectB - // | | - // | | - // ______|____| - // | - // | - // | ________ - // - { - overlapAmount[1] += Mathf.Min((rectB.y - rectA.y), - (rectA.yMax - rectB.yMax)); - } - else if ((rectB.y <= rectA.y) && (rectB.yMax >= rectA.yMax)) - // Case y.2: - // ________ rectB - // | - // | - // ______|____ rectA - // | | - // | | - // ______|____| - // | - // | - // |________ - // - { - overlapAmount[1] += Mathf.Min((rectA.y - rectB.y), - (rectB.yMax - rectA.yMax)); - } - - // find slope of the line passes two centers - double slope = - Mathf.Abs((rectB.center.y - rectA.center.y) / - (rectB.center.x - rectA.center.x)); - - // if centers are overlapped - if ((rectB.center.y == rectA.center.y) && - (rectB.center.x == rectA.center.x)) - { - // assume the slope is 1 (45 degree) - slope = 1.0; - } - - // change y - double moveByY = slope * overlapAmount[0]; - // change x - double moveByX = overlapAmount[1] / slope; - - // now we have two pairs: - // 1) overlapAmount[0], moveByY - // 2) moveByX, overlapAmount[1] - - // use pair no:1 - if (overlapAmount[0] < moveByX) - { - moveByX = overlapAmount[0]; - } - // use pair no:2 - else - { - moveByY = overlapAmount[1]; - } - - // return half the amount so that if each rectangle is moved by these - // amounts in opposite directions, overlap will be resolved - - overlapAmount[0] = -1 * directions[0] * ((moveByX / 2) + separationBuffer); - overlapAmount[1] = -1 * directions[1] * ((moveByY / 2) + separationBuffer); - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs.meta deleted file mode 100644 index e6a0292507..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGeometry.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f5a82d3509d363c42973adf61257d0c3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs deleted file mode 100644 index 6db5d7a507..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseGraph - { - /// - /// the parent of the graph - /// - private CoseNode parent; - - /// - /// the graphmanager of the current CoseLayout - /// - private CoseGraphManager graphManager; - - /// - /// the nodes contained by this graph - /// - private List nodes = new List(); - - /// - /// edges of this graph - /// - private List edges = new List(); - - /// - /// the left front corner of the graph - /// - private Vector2 leftFrontCorner; - - /// - /// the right back corner of this graph - /// - private Vector2 rightBackCorner; - - /// - /// the scale of this graph - /// - private Vector3 scale; - - /// the centerPosition of this graph - private Vector3 centerPosition; - - /// - /// the extend of this graph - /// - public Vector3 Extend - { - get => scale / 2; - } - - /// - /// the estimated size of this graph - /// - private double estimatedSize = Mathf.NegativeInfinity; - - /// - /// the margin around this graph - /// - private readonly float defaultMargin = CoseLayoutSettings.GraphMargin; - - /// - /// Indicates if the graph is connected - /// - private bool isConnected = false; - - /// - /// the original node - /// - private ILayoutNode graphObject; - - /// - /// Indicates if this graph is a sublayout - /// - private bool isSubLayout = false; - - public ILayoutNode GraphObject { get => graphObject; set => graphObject = value; } - public CoseGraphManager GraphManager { get => graphManager; set => graphManager = value; } - public CoseNode Parent { get => parent; set => parent = value; } - public List Nodes { get => nodes; set => nodes = value; } - public bool IsConnected { get => isConnected; set => isConnected = value; } - public List Edges { get => edges; set => edges = value; } - public double EstimatedSize { get => estimatedSize; set => estimatedSize = value; } - public bool IsSubLayout { get => isSubLayout; set => isSubLayout = value; } - public Vector3 Scale { get => scale; set => scale = value; } - public Vector3 CenterPosition { get => centerPosition; set => centerPosition = value; } - public Vector2 LeftFrontCorner { get => leftFrontCorner; set => leftFrontCorner = value; } - public Vector2 RightBackCorner { get => rightBackCorner; set => rightBackCorner = value; } - - /// - /// constructor - /// - /// the parent node - /// the graphmanager for this graph - public CoseGraph(CoseNode parent, CoseGraphManager graphManager) - { - this.parent = parent; - this.graphManager = graphManager; - } - - /// - /// update the bounds of this graph - /// - /// if true the update of the bounds is performed recursively - public void UpdateBounds(bool recursive) - { - if (parent.SublayoutValues.IsSubLayoutNode) - { - LeftFrontCorner = parent.GetLeftFrontCorner(); - RightBackCorner = parent.GetRightBackCorner(); - - UpdateBounding(); - - foreach (CoseNode cNode in nodes) - { - if (recursive && cNode.Child != null) - { - cNode.UpdateBounds(); - } - else - { - cNode.SetOrigin(); - } - } - return; - } - - Vector2 leftLowerCorner = new Vector2(Mathf.Infinity, Mathf.NegativeInfinity); - Vector2 rightUpperCorner = new Vector2(Mathf.NegativeInfinity, Mathf.Infinity); - - Vector2 leftLowerCornerNode; - Vector2 rightUpperCornerNode; - - foreach (CoseNode cNode in nodes) - { - - if (recursive && cNode.Child != null) - { - cNode.UpdateBounds(); - } - - leftLowerCornerNode = cNode.GetLeftFrontCorner(); - rightUpperCornerNode = cNode.GetRightBackCorner(); - - if (leftLowerCorner.x > leftLowerCornerNode.x) - { - leftLowerCorner.x = leftLowerCornerNode.x; - } - - if (rightUpperCorner.x < rightUpperCornerNode.x) - { - rightUpperCorner.x = rightUpperCornerNode.x; - } - - if (rightUpperCorner.y > rightUpperCornerNode.y) - { - rightUpperCorner.y = rightUpperCornerNode.y; - } - - if (leftLowerCorner.y < leftLowerCornerNode.y) - { - leftLowerCorner.y = leftLowerCornerNode.y; - } - } - - if (leftLowerCorner.x == Mathf.Infinity) - { - leftFrontCorner = parent.GetLeftFrontCorner(); - rightBackCorner = parent.GetRightBackCorner(); - } - - leftFrontCorner.x = leftLowerCorner.x - defaultMargin; - leftFrontCorner.y = leftLowerCorner.y + defaultMargin; - - rightBackCorner.x = rightUpperCorner.x + defaultMargin; - rightBackCorner.y = rightUpperCorner.y - defaultMargin; - - UpdateBounding(); - } - - /// - /// Adds the given displacment values to the graphs position - /// - /// displacement x direction - /// displacement z direction - public void SetXZDisplacementBoundingRect(float dx, float dz) - { - centerPosition.x += dx; - centerPosition.z += dz; - } - - /// - /// updates the bounds of the boundingrectanle - /// - public void UpdateBounding() - { - scale.x = RightBackCorner.x - LeftFrontCorner.x; - scale.z = LeftFrontCorner.y - RightBackCorner.y; - centerPosition.x = LeftFrontCorner.x + Extend.x; - centerPosition.z = RightBackCorner.y + Extend.z; - } - - /// - /// Updates and calculates if the graph is connected - /// - public void UpdateConnected() - { - if (nodes.Count == 0) - { - isConnected = true; - return; - } - - HashSet visited = new HashSet(); - - CoseNode current = nodes[0]; - - List neighborEdges; - CoseNode currentNeighbor; - - LinkedList toBeVisited = new LinkedList(current.WithChildren()); - - while (toBeVisited.Count != 0) - { - current = toBeVisited.First.Value; - toBeVisited.RemoveFirst(); - visited.Add(current); - - neighborEdges = current.Edges; - - foreach (CoseEdge edge in neighborEdges) - { - currentNeighbor = edge.GetOtherEndInGraph(current, this); - - if (currentNeighbor != null && !visited.Contains(currentNeighbor)) - { - foreach (CoseNode toAdd in currentNeighbor.WithChildren()) - { - toBeVisited.AddLast(toAdd); - } - } - } - } - - isConnected = false; - - if (visited.Count >= nodes.Count) - { - int noOfVisitedInThisGraph = 0; - - foreach (CoseNode visitedNode in visited) - { - if (visitedNode.Owner == this) - { - noOfVisitedInThisGraph++; - } - } - - if (noOfVisitedInThisGraph == nodes.Count) - { - isConnected = true; - } - } - } - - /// - /// Adds an edge to this graph - /// - /// the new edge - /// the source node - /// the target node - /// the new edge - public CoseEdge Add(CoseEdge newEdge, CoseNode sourceNode, CoseNode targetNode) - { - if (!nodes.Contains(sourceNode) || !nodes.Contains(targetNode)) - { - throw new System.Exception("Source or Traget not in Graph"); - } - - if (sourceNode.Owner != targetNode.Owner || sourceNode.Owner != this) - { - throw new System.Exception("Both owners must be in this graph"); - } - - newEdge.Source = sourceNode; - newEdge.Target = targetNode; - newEdge.IsInterGraph = false; - edges.Add(newEdge); - sourceNode.Edges.Add(newEdge); - - if (targetNode != sourceNode) - { - targetNode.Edges.Add(newEdge); - } - return newEdge; - } - - /// - /// Adds a new node to this graph - /// - /// the new node - public void AddNode(CoseNode node) - { - if (graphManager == null) - { - throw new System.Exception("Graph has no graph manager"); - } - if (nodes.Contains(node)) - { - throw new System.Exception("Node is already in graph"); - } - - node.Owner = this; - nodes.Add(node); - } - - /// - /// calculates the estimated size of this graph - /// - /// the estimated size - public double CalcEstimatedSize() - { - double size = 0; - - foreach (CoseNode node in nodes) - { - size += node.CalcEstimatedSize(); - } - - if (size == 0) - { - estimatedSize = CoseLayoutSettings.EmptyCompoundSize; - } - else - { - estimatedSize = size / Math.Sqrt(nodes.Count); - } - - return estimatedSize; - } - - /// - /// Calculates the inclusion tree depth of this graph - /// - /// the inclusion tree depth - public int GetInclusionTreeDepth() - { - if (this == graphManager.RootGraph) - { - return 1; - } - else - { - return parent.InclusionTreeDepth; - } - } - - /// - /// Removes a given node from this graph - /// - /// the node to remove - public void Remove(CoseNode node) - { - if (node == null) - { - throw new System.Exception("node is null"); - } - if (node.Owner == null || node.Owner != this) - { - throw new System.Exception("owner graph is invalid"); - } - if (graphManager == null) - { - throw new System.Exception("Owner graph manager is invalid"); - } - - List edgesToBeRemoved = new List(); - edgesToBeRemoved.AddRange(node.Edges); - - foreach (CoseEdge edge in edgesToBeRemoved) - { - if (edge.IsInterGraph) - { - graphManager.Remove(edge); - } - else - { - edge.Source.Owner.Remove(edge); - } - } - - if (!nodes.Contains(node)) - { - throw new System.Exception("node is not in owner node list"); - } - nodes.Remove(node); - } - - /// - /// Removes a given edge from this graph - /// - /// the edge to remove from this graph - public void Remove(CoseEdge edge) - { - if (edge == null) - { - throw new System.Exception("Edge is null"); - } - if (edge.Source == null || edge.Target == null) - { - throw new System.Exception("source or target is null"); - } - if (edge.Source.Owner == null || edge.Target.Owner == null) - { - throw new System.Exception("source or target owner is null"); - } - if (!edge.Source.Edges.Contains(edge) || !edge.Target.Edges.Contains(edge)) - { - throw new System.Exception("source or target doesnt know this edge"); - } - - edge.Source.Edges.Remove(edge); - - if (edge.Target != edge.Source) - { - edge.Target.Edges.Remove(edge); - } - - if (!edge.Source.Owner.Edges.Contains(edge)) - { - throw new System.Exception("not in owner graph managers edge list"); - } - - edge.Source.Owner.Edges.Remove(edge); - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs.meta deleted file mode 100644 index e75647ea6b..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraph.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f40715947ead7544782b5ac97646fb54 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs deleted file mode 100644 index 41a81ddd92..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System.Collections.Generic; -using SEE.Game.City; -using SEE.Utils.Config; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// This class holds all attributes for the COSE layout - /// - public class CoseGraphAttributes - { - /// - /// The ideal length of the edge - /// - public int EdgeLength = CoseLayoutSettings.EdgeLength; - - /// - /// If true the edge length is calculated with the feature "use smart ideal edge calculation" - /// - public bool UseSmartIdealEdgeCalculation = CoseLayoutSettings.UseSmartIdealEdgeCalculation; - - /// - /// If true the feature "use smart multilevel calculation" is used, the edge length adjusts for each level - /// - public bool UseSmartMultilevelScaling = CoseLayoutSettings.UseSmartMultilevelCalculation; - - /// - /// the factor by which the edge length of intergraph edges is enlarged - /// - public float PerLevelIdealEdgeLengthFactor = CoseLayoutSettings.PerLevelIdealEdgeLengthFactor; - - /// - /// if true the feature "smart repulsion range calculation" is used (Grid variant) - /// - public bool UseSmartRepulsionRangeCalculation = CoseLayoutSettings.UseSmartRepulsionRangeCalculation; - - /// - /// the strength of the gravity (root graph) - /// - public float GravityStrength = CoseLayoutSettings.GravityStrength; - - /// - /// strength of the gravity in compound nodes (not root graph) - /// - public float CompoundGravityStrength = CoseLayoutSettings.CompoundGravityStrength; - - /// - /// the repulsion strength - /// - public float RepulsionStrength = CoseLayoutSettings.RepulsionStrength; - - /// - /// if true the feature: multilevel scaling is used - /// - public bool MultiLevelScaling = CoseLayoutSettings.MultilevelScaling; - - /// - /// key: inner-node ids, value: bool, if true the inner node is layouted by a sublayout - /// - public Dictionary ListInnerNodeToggle = new Dictionary(); - - /// - /// key: inner-node ids, value: the nodelayout - /// - public Dictionary InnerNodeLayout = new Dictionary(); - - /// - /// key: inner-node ids, value: the inner node kind - /// - public Dictionary InnerNodeShape = new Dictionary(); - - /// - /// the nodetypes - /// - public Dictionary LoadedForNodeTypes = new Dictionary(); - - /// - /// is true the parameter edgeLength and repulsion strength are calculated automatically - /// - public bool UseCalculationParameter = true; - - /// - /// is true the parameter edgeLength and repulsion strength are calculated automatically and are iteratily changed till a goog layout is found - /// - public bool UseIterativeCalculation = false; - - private const string edgeLengthLabel = "EdgeLength"; - private const string useSmartIdealEdgeCalculationLabel = "UseSmartIdealEdgeCalculation"; - private const string useSmartMultilevelScalingLabel = "UseSmartMultilevelScaling"; - private const string perLevelIdealEdgeLengthFactorLabel = "PerLevelIdealEdgeLengthFactor"; - private const string useSmartRepulsionRangeCalculationLabel = "UseSmartRepulsionRangeCalculation"; - private const string gravityStrengthLabel = "GravityStrength"; - private const string compoundGravityStrengthLabel = "CompoundGravityStrength"; - private const string repulsionStrengthLabel = "RepulsionStrength"; - private const string multiLevelScalingLabel = "MultiLevelScaling"; - private const string listInnerNodeToggleLabel = "ListInnerNodeToggle"; - private const string innerNodeLayoutLabel = "InnerNodeLayout"; - private const string innerNodeShapeLabel = "InnerNodeShape"; - private const string loadedForNodeTypesLabel = "LoadedForNodeTypes"; - private const string useCalculationParameterLabel = "UseCalculationParameter"; - private const string useIterativeCalculationLabel = "UseIterativeCalculation"; - - internal void Save(ConfigWriter writer, string label) - { - writer.BeginGroup(label); - writer.Save(EdgeLength, edgeLengthLabel); - writer.Save(UseSmartIdealEdgeCalculation, useSmartIdealEdgeCalculationLabel); - writer.Save(UseSmartMultilevelScaling, useSmartMultilevelScalingLabel); - writer.Save(PerLevelIdealEdgeLengthFactor, perLevelIdealEdgeLengthFactorLabel); - writer.Save(UseSmartRepulsionRangeCalculation, useSmartRepulsionRangeCalculationLabel); - writer.Save(GravityStrength, gravityStrengthLabel); - writer.Save(CompoundGravityStrength, compoundGravityStrengthLabel); - writer.Save(RepulsionStrength, repulsionStrengthLabel); - writer.Save(MultiLevelScaling, multiLevelScalingLabel); - writer.Save(ListInnerNodeToggle, listInnerNodeToggleLabel); - writer.SaveAsStrings(InnerNodeLayout, innerNodeLayoutLabel); // saves enums as strings - writer.SaveAsStrings(InnerNodeShape, innerNodeShapeLabel); // saves enums as strings - writer.Save(LoadedForNodeTypes, loadedForNodeTypesLabel); - writer.Save(UseCalculationParameter, useCalculationParameterLabel); - writer.Save(UseIterativeCalculation, useIterativeCalculationLabel); - writer.EndGroup(); - } - - internal void Restore(Dictionary attributes, string label) - { - if (attributes.TryGetValue(label, out object dictionary)) - { - Dictionary values = dictionary as Dictionary; - { - ConfigIO.Restore(values, edgeLengthLabel, ref EdgeLength); - ConfigIO.Restore(values, useSmartMultilevelScalingLabel, ref UseSmartMultilevelScaling); - ConfigIO.Restore(values, useSmartIdealEdgeCalculationLabel, ref UseSmartIdealEdgeCalculation); - ConfigIO.Restore(values, perLevelIdealEdgeLengthFactorLabel, ref PerLevelIdealEdgeLengthFactor); - ConfigIO.Restore(values, useSmartRepulsionRangeCalculationLabel, ref UseSmartRepulsionRangeCalculation); - ConfigIO.Restore(values, gravityStrengthLabel, ref GravityStrength); - ConfigIO.Restore(values, compoundGravityStrengthLabel, ref CompoundGravityStrength); - ConfigIO.Restore(values, repulsionStrengthLabel, ref RepulsionStrength); - ConfigIO.Restore(values, multiLevelScalingLabel, ref MultiLevelScaling); - ConfigIO.Restore(values, listInnerNodeToggleLabel, ref ListInnerNodeToggle); - ConfigIO.RestoreEnumDict(values, innerNodeLayoutLabel, ref InnerNodeLayout); - ConfigIO.RestoreEnumDict(values, innerNodeShapeLabel, ref InnerNodeShape); - ConfigIO.Restore(values, loadedForNodeTypesLabel, ref LoadedForNodeTypes); - ConfigIO.Restore(values, useCalculationParameterLabel, ref UseCalculationParameter); - ConfigIO.Restore(values, useIterativeCalculationLabel, ref UseIterativeCalculation); - } - } - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs.meta deleted file mode 100644 index 3d4240e901..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphAttributes.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3c9d0e311c1564d4a908ea05e0480b80 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs deleted file mode 100644 index c1f9da562d..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System.Collections.Generic; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseGraphManager - { - /// - /// the layout - /// - private CoseLayout layout; - - /// - /// all graphs - /// - private List graphs; - - /// - /// all intergraph edges - /// - private List edges; - - /// - /// all nodes - /// - private List allNodes; - - /// - /// all edges - /// - private List allEdges; - - /// - /// the root graph - /// - private CoseGraph rootGraph; - - /// - /// nodes to which gravitation is applied to - /// - private List nodesToApplyGravitation; - - public List Graphs { get => graphs; set => graphs = value; } - public List Edges { get => edges; set => edges = value; } - public List AllNodes { get => allNodes; set => allNodes = value; } - public List AllEdges { get => allEdges; set => allEdges = value; } - public CoseGraph RootGraph { get => rootGraph; set => rootGraph = value; } - public List NodesToApplyGravitation { get => nodesToApplyGravitation; set => nodesToApplyGravitation = value; } - public CoseLayout Layout { get => layout; set => layout = value; } - - /// - /// constructor - /// - /// the layout - public CoseGraphManager(CoseLayout layout) - { - this.layout = layout; - Init(); - } - - /// - /// initalizes the graph manager - /// - private void Init() - { - graphs = new List(); - edges = new List(); - allNodes = null; - allEdges = null; - nodesToApplyGravitation = null; - rootGraph = null; - } - - /// - /// Adds the root graph to this graph manager - /// - /// - public CoseGraph AddRootGraph() - { - rootGraph = Add(new CoseGraph(null, this), new CoseNode(null, this)); - rootGraph.GraphManager = this; - return rootGraph; - } - - /// - /// Sets this graph to root graph - /// - /// the graph - public void SetRootGraph(CoseGraph graph) - { - if (graph.GraphManager != this) - { - throw new System.Exception("Root not in this graph manager"); - } - - rootGraph = graph; - - if (graph.Parent == null) - { - graph.Parent = layout.NewNode(); - } - } - - /// - /// Adds a graph to this graphManager - /// - /// the new graph - /// the parent node of the graph - /// the graph - public CoseGraph Add(CoseGraph newGraph, CoseNode parent) - { - if (newGraph == null || parent == null) - { - throw new System.Exception("Parameter is null"); - } - if (graphs.Contains(newGraph)) - { - throw new System.Exception("Graph is already in GraphManager"); - } - - graphs.Add(newGraph); - - if (newGraph.Parent != null || parent.Child != null) - { - throw new System.Exception("Elements already having this parameter"); - } - - newGraph.Parent = parent; - parent.Child = newGraph; - - return newGraph; - } - - /// - /// Adds an edge to this graphManager - /// - /// the new edge - /// the source of this edge - /// the target of the edge - /// the new edge - public CoseEdge Add(CoseEdge newEdge, CoseNode cSource, CoseNode cTarget) - { - CoseGraph sourceGraph = cSource.Owner; - CoseGraph targetGraph = cTarget.Owner; - - if (sourceGraph == null || sourceGraph.GraphManager != this) - { - throw new System.Exception("Source not in this graph manager"); - } - - if (targetGraph == null || targetGraph.GraphManager != this) - { - throw new System.Exception("Target not in this graph manager"); - } - - if (sourceGraph == targetGraph) - { - newEdge.IsInterGraph = false; - newEdge = sourceGraph.Add(newEdge, cSource, cTarget); - - if (newEdge.Source == null || newEdge.Target == null) - { - Debug.Log("stop"); - } - return newEdge; - } - else - { - newEdge.IsInterGraph = true; - newEdge.Source = cSource; - newEdge.Target = cTarget; - - if (edges.Contains(newEdge)) - { - throw new System.Exception("Edge already in inter-graph list"); - } - edges.Add(newEdge); - - if (newEdge.Source == null || newEdge.Target == null) - { - throw new System.Exception("Edge source or traget is null"); - } - - if (newEdge.Source.Edges.Contains(newEdge) || newEdge.Target.Edges.Contains(newEdge)) - { - throw new System.Exception("Edge is already in source or target edge list"); - - } - newEdge.Source.Edges.Add(newEdge); - newEdge.Target.Edges.Add(newEdge); - - if (newEdge.Source == null || newEdge.Target == null) - { - Debug.Log("stop"); - } - return newEdge; - } - } - - /// - /// Updates the bounds of this graph, recursively, starting with the root graph - /// - public void UpdateBounds() - { - rootGraph.UpdateBounds(true); - } - - /// - /// Returns all nodes of the graphManager - /// - /// all nodes of the graphManager - public List GetAllNodes() - { - if (allNodes == null) - { - List nodeList = new List(); - - foreach (CoseGraph graph in graphs) - { - nodeList.AddRange(graph.Nodes); - } - allNodes = nodeList; - } - - return allNodes; - } - - /// - /// Calculates the inclusion tree depth for all nodes - /// - public void CalcInclusionTreeDepths() - { - CalcInclusionTreeDepth(RootGraph, 1); - } - - - /// - /// Calculates the inclusion tree depth for all nodes for a given graph - /// - /// the graph - /// depth of the current graph - private void CalcInclusionTreeDepth(CoseGraph graph, int depth) - { - graph.Nodes.ForEach(node => - { - node.InclusionTreeDepth = depth; - - if (node.Child != null) - { - CalcInclusionTreeDepth(node.Child, depth + 1); - } - }); - } - - - /// - /// calculates all lowest common anchestors for all edges - /// - public void CalcLowestCommonAncestors() - { - CoseNode sourceNode; - CoseNode targetNode; - CoseGraph sourceAnchestorGraph; - CoseGraph targetAnchestorGraph; - - foreach (CoseEdge edge in GetAllEdges()) - { - sourceNode = edge.Source; - targetNode = edge.Target; - edge.LowestCommonAncestor = null; - edge.SourceInLca = sourceNode; - edge.TargetInLca = targetNode; - - if (sourceNode == targetNode) - { - edge.LowestCommonAncestor = sourceNode.Owner; - continue; - } - - sourceAnchestorGraph = sourceNode.Owner; - - while (edge.LowestCommonAncestor == null) - { - edge.TargetInLca = targetNode; - targetAnchestorGraph = targetNode.Owner; - - while (edge.LowestCommonAncestor == null) - { - if (targetAnchestorGraph == sourceAnchestorGraph) - { - edge.LowestCommonAncestor = targetAnchestorGraph; - break; - } - - if (targetAnchestorGraph == rootGraph) - { - break; - } - - if (edge.LowestCommonAncestor != null) - { - throw new System.Exception("lowest anchestor should be null"); - } - edge.TargetInLca = targetAnchestorGraph.Parent; - targetAnchestorGraph = edge.TargetInLca.Owner; - } - - if (sourceAnchestorGraph == rootGraph) - { - break; - } - - if (edge.LowestCommonAncestor == null) - { - edge.SourceInLca = sourceAnchestorGraph.Parent; - sourceAnchestorGraph = edge.SourceInLca.Owner; - } - } - - if (edge.LowestCommonAncestor == null) - { - throw new System.Exception("lowest common anchestor not allowed to be null"); - } - } - } - - /// - /// Returns all edges of the graphManager - /// - /// all edges - public List GetAllEdges() - { - if (allEdges == null) - { - List edgeList = new List(); - - foreach (CoseGraph graph in graphs) - { - edgeList.AddRange(graph.Edges); - } - - edgeList.AddRange(edges); - - allEdges = edgeList; - } - - return allEdges; - } - - /// - /// Creates all coarsen graphs for the multilevel scaling - /// - /// a list of coarsen graphManager - public List CoarsenGraph() - { - List gmList = new List(); - int prevNodeCount; - int currNodeCount; - - gmList.Add(this); - - CoseCoarsenGraph g = new CoseCoarsenGraph(layout); - - ConvertToCoarseningGraph(rootGraph, g); - - currNodeCount = g.Nodes.Count; - - CoseGraphManager lastM; - CoseGraphManager newM; - - do - { - prevNodeCount = currNodeCount; - g.Coarsen(); - - lastM = gmList[gmList.Count - 1]; - newM = Coarsen(lastM); - - gmList.Add(newM); - currNodeCount = g.Nodes.Count; - - } while ((prevNodeCount != currNodeCount) && currNodeCount > 1); - - layout.GraphManager = this; - - gmList.RemoveAt(gmList.Count - 1); - - return gmList; - } - - /// - /// Coarsen a graph manager (once) - /// - /// - /// a new graph manager - private CoseGraphManager Coarsen(CoseGraphManager lastM) - { - CoseGraphManager newM = new CoseGraphManager(lastM.Layout); - - newM.Layout.GraphManager = newM; - newM.AddRootGraph(); - - newM.RootGraph.GraphObject = lastM.RootGraph.GraphObject; - - CoarsenNodes(lastM.RootGraph, newM.RootGraph); - - lastM.Layout.GraphManager = lastM; - - AddEdges(lastM, newM); - - return newM; - } - - /// - /// Adds all edges from one graphManager to another graphManager - /// - /// the "old" graphManager - /// the new graphManager - private static void AddEdges(CoseGraphManager lastM, CoseGraphManager newM) - { - foreach (CoseEdge edge in lastM.GetAllEdges()) - { - if (edge.IsInterGraph || edge.Source.Child != null || edge.Target != null) - { - if (!edge.Source.LayoutValues.Next.GetNeighborsList().Contains(edge.Target.LayoutValues.Next)) - { - newM.Add(new CoseEdge(null, null), edge.Source.LayoutValues.Next, edge.Target.LayoutValues.Next); - } - } - else - { - if (edge.Source.LayoutValues.Next != edge.Target.LayoutValues.Next) - { - if (!edge.Source.LayoutValues.Next.GetNeighborsList().Contains(edge.Target.LayoutValues.Next)) - { - newM.Add(new CoseEdge(null, null), edge.Source.LayoutValues.Next, edge.Target.LayoutValues.Next); - } - } - } - } - } - - /// - /// Coarsen the nodes of a given graph to a more coarser graph (once) - /// - /// the uncoarsen graph - /// the coarser graph - private void CoarsenNodes(CoseGraph graph, CoseGraph coarserGraph) - { - foreach (CoseNode node in graph.Nodes) - { - if (node.Child != null) - { - node.LayoutValues.Next = coarserGraph.GraphManager.Layout.NewNode(); - coarserGraph.GraphManager.Add(coarserGraph.GraphManager.Layout.NewGraph(), node.LayoutValues.Next); - node.LayoutValues.Next.LayoutValues.Pred1 = node; - coarserGraph.AddNode(node.LayoutValues.Next); - - CoarsenNodes(node.Child, node.LayoutValues.Next.Child); - } - else - { - if (!node.LayoutValues.Next.LayoutValues.IsProcessed) - { - coarserGraph.AddNode(node.LayoutValues.Next); - node.LayoutValues.Next.LayoutValues.IsProcessed = true; - } - } - - node.LayoutValues.Next.SetLocation(node.CenterPosition.x, node.CenterPosition.z); - node.LayoutValues.Next.SetHeight(node.Scale.z); - node.LayoutValues.Next.SetWidth(node.Scale.x); - } - } - - /// - /// Converts a graph to a coarsengraph - /// - /// the original graph - /// the coarsen graph - private void ConvertToCoarseningGraph(CoseGraph coseGraph, CoseCoarsenGraph graph) - { - Dictionary dict = new Dictionary(); - - foreach (CoseNode node in coseGraph.Nodes) - { - if (node.Child != null) - { - ConvertToCoarseningGraph(node.Child, graph); - } - else - { - CoseCoarsenNode coarsenNode = new CoseCoarsenNode(); - coarsenNode.Reference = node; - dict.Add(node, coarsenNode); - graph.AddNode(coarsenNode); - } - } - - foreach (CoseEdge edge in coseGraph.Edges) - { - if (edge.Source.Child == null && edge.Target.Child == null) - { - graph.Add(new CoseCoarsenEdge(), dict[edge.Source], dict[edge.Target]); - } - } - } - - /// - /// Removes an edge from its graphManager - /// - /// the edge to remove - public void Remove(CoseEdge edge) - { - if (edge == null) - { - throw new System.Exception("Edge is null"); - } - if (!edge.IsInterGraph) - { - throw new System.Exception("Edge is not an intergraph edge"); - } - if (edge.Source == null || edge.Target == null) - { - throw new System.Exception("source or target is null"); - } - if (!edge.Source.Edges.Contains(edge) || !edge.Target.Edges.Contains(edge)) - { - throw new System.Exception("source or target doesnt know this edge"); - } - - edge.Source.Edges.Remove(edge); - edge.Target.Edges.Remove(edge); - - if (edge.Source.Owner == null || edge.Source.Owner.GraphManager == null) - { - throw new System.Exception("Edge owner or edge owner graphmanager is null"); - } - if (!edge.Source.Owner.GraphManager.Edges.Contains(edge)) - { - throw new System.Exception("not in owner graph managers edge list"); - } - - edge.Source.Owner.GraphManager.Edges.Remove(edge); - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs.meta deleted file mode 100644 index 6a97082814..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseGraphManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 041d44b1f0bbe4e479c1dd1796a84648 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs deleted file mode 100644 index 16b22f5f5a..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using SEE.Game.City; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// Helper functions - /// - public class CoseHelper - { - /// - /// checks if the node with the given id is a sublayout root node - /// - /// all sublayout nodes - /// the id - /// true if the node with the given id is a sublayout root node - public static SublayoutNode CheckIfNodeIsSublayouRoot(ICollection sublayoutNodes, string id) - { - foreach (SublayoutNode subLayoutNode in sublayoutNodes) - { - if (subLayoutNode.Node.ID == id) - { - return subLayoutNode; - } - } - return null; - } - - /// - /// checks if the node with the given id is a sublayout root node - /// - /// all sublayout nodes - /// the id - /// true if the node with the given id is a sublayout root node - public static SublayoutLayoutNode CheckIfNodeIsSublayouRoot(ICollection sublayoutNodes, string id) - { - foreach (SublayoutLayoutNode subLayoutNode in sublayoutNodes) - { - if (subLayoutNode.Node.ID == id) - { - return subLayoutNode; - } - } - return null; - } - - /// - /// Returns a new Rect with the given scale and center position - /// - /// the scale - /// the center postion - /// a new rect - public static Rect NewRect(Vector3 scale, Vector3 center) - { - return new Rect - { - x = center.x - scale.x / 2, - y = center.z - scale.z / 2, - width = scale.x, - height = scale.z - }; - } - - /// - /// Sign function - /// - /// the value - /// the sign of the given value - public static int Sign(float value) - { - if (value > 0) - { - return 1; - } - else if (value < 0) - { - return -1; - } - else - { - return 0; - } - } - - /// - /// return a NodeLayout of the given nodeLayout type - /// - /// the node layout - /// the groundlevel - /// the leafNode unit - /// the abstract see city settings - /// a node layout object - public static NodeLayout GetNodelayout(NodeLayoutKind nodeLayout, float groundLevel, AbstractSEECity settings) - { - switch (nodeLayout) - { - case NodeLayoutKind.Manhattan: - return new ManhattanLayout(groundLevel); - case NodeLayoutKind.RectanglePacking: - return new RectanglePackingNodeLayout(groundLevel); - case NodeLayoutKind.EvoStreets: - return new EvoStreetsNodeLayout(groundLevel); - case NodeLayoutKind.Treemap: - return new TreemapLayout(groundLevel, 1000.0f, 1000.0f); - case NodeLayoutKind.IncrementalTreeMap: - return new IncrementalTreeMapLayout( - groundLevel, - 1000.0f, - 1000.0f, - settings.NodeLayoutSettings.IncrementalTreeMap); - case NodeLayoutKind.Balloon: - return new BalloonNodeLayout(groundLevel); - case NodeLayoutKind.CirclePacking: - return new CirclePackingNodeLayout(groundLevel); - case NodeLayoutKind.CompoundSpringEmbedder: - return new CoseLayout(groundLevel, settings); - default: - throw new Exception("Unhandled node layout " + nodeLayout); - } - } - - /// - /// Calculates a good edge length for the given number of nodes and maximal depth - /// - /// the number of nodes - /// the maximal depth - /// edge length - public static int GetGoodEgdeLength(int countNodes, int maxDepth, int leafNodesCount, int countEdges) - { - float constant = -5.055f; - float countNodesConstant = 0.206f; - float countMaxDepthConstant = 2.279f; - float edgeDensityConstant = -57.829f; - - float edgeDensity; - - if (leafNodesCount == 0 || countEdges == 0) - { - edgeDensity = 0; - } - else - { - float leafNodeCountMinus = leafNodesCount > 1 ? leafNodesCount - 1 : 1; - edgeDensity = countEdges / (leafNodesCount * leafNodeCountMinus); - } - - float edgeLength = countNodesConstant * countNodes + countMaxDepthConstant * maxDepth + edgeDensityConstant * edgeDensity + constant; - return Math.Max((int)Math.Ceiling(edgeLength), 2); - } - - /// - /// Calculates a good repulsion strength for the given number of edges and maximal depth - /// - /// the number of nodes - /// the maximal depth - /// repulsion strength - public static int GetGoodRepulsionRange(int maxDepth, int leafNodesCount, int countEdges) - { - float constant = -1.995f; - float countMaxDepthConstant = 1.107f; - float countNodesConstant = 0.209f; - - float edgeDensityConstant = 91.799f; - - float edgeDensity; - - if (leafNodesCount == 0 || countEdges == 0) - { - edgeDensity = 0; - } - else - { - float leafNodeCountMinus = leafNodesCount > 1 ? leafNodesCount - 1 : 1; - edgeDensity = countEdges / (leafNodesCount * leafNodeCountMinus); - } - - - float repulsionStrength = countMaxDepthConstant * maxDepth + leafNodesCount * countNodesConstant + edgeDensity * edgeDensityConstant + constant; - return Math.Max((int)Math.Ceiling(repulsionStrength), 2); - } - - /// - /// Returns the layout node with the given ID - /// - /// the ID - /// layout node with the given ID - public static ILayoutNode GetLayoutNodeFromLinkname(String id, ICollection layoutNodes) - { - List nodes = layoutNodes.Where(layoutNode => layoutNode.ID == id).ToList(); - - if (nodes.Count > 1) - { - throw new System.Exception("Linkname should be unique"); - } - else if (nodes.Count == 0) - { - throw new System.Exception("No node exists with this linkname"); - } - - return nodes.First(); - } - - } -} - - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs.meta deleted file mode 100644 index e17abf85e1..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseHelper.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ee1c067618120d34aac85cafcfd3cc23 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs deleted file mode 100644 index 2e0b07600c..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs +++ /dev/null @@ -1,1328 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using SEE.DataModel.DG; -using SEE.Game.City; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - internal class IterationConstraint - { - /// - /// the start value - /// - public int Start; - - /// - /// the end value - /// - public int End; - - /// - /// The value by which the parameter value is increased within each iteration - /// - public int IterationStep; - - /// - /// constructor - /// - /// the start value - /// the end value - /// The value by which the parameter value is increased within each iteration - public IterationConstraint(int start, int end, int iterationStep) - { - this.Start = start; - this.End = end; - this.IterationStep = iterationStep; - } - } - - public class CoseLayout : NodeLayout - { - /// - /// the Graphmanager of the layout - /// - private CoseGraphManager graphManager; - - /// - /// collection with all Edge Objects - /// - private ICollection edges = new List(); - - /// - /// Mapping from Node to CoseNode - /// - private readonly Dictionary nodeToCoseNode; - - /// - /// Layout Settings (idealEdgeLength etc.) - /// - private CoseLayoutSettings coseLayoutSettings; - - /// - /// Grid for smart repulsion range calculation - /// - private List[,] grid; - - /// - /// All sublayouts (choosed by the user via GUI) - /// - private List sublayoutNodes = new List(); - - /// - /// Collection with all layoutNodes - /// - private List layoutNodes; - - /// - /// The node layout we compute as a result. - /// - private Dictionary layoutResult; - - /// - /// A list with all graph managers (used for multilevel scaling) - /// - private List gmList; - - /// - /// the abstarct see city settings - /// - private readonly AbstractSEECity settings; - - public CoseGraphManager GraphManager { get => graphManager; set => graphManager = value; } - public CoseLayoutSettings CoseLayoutSettings { get => coseLayoutSettings; set => coseLayoutSettings = value; } - public List SublayoutNodes { get => sublayoutNodes; set => sublayoutNodes = value; } - - /// - /// Constructor - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - /// Graph Settings - public CoseLayout(float groundLevel, AbstractSEECity settings) : base(groundLevel) - { - Name = "Compound Spring Embedder Layout"; - nodeToCoseNode = new Dictionary(); - this.settings = settings; - SetupGraphSettings(settings.CoseGraphSettings); - } - - /// - /// Computes the Layout - /// - /// the nodes to layout - /// the edges of the graph - /// the sublayouts - /// - public override Dictionary Layout(ICollection layoutNodes, ICollection edges, ICollection coseSublayoutNodes) - { - this.edges = edges; - SublayoutNodes = coseSublayoutNodes.ToList(); - - layoutResult = new Dictionary(); - this.layoutNodes = layoutNodes.ToList(); - - ICollection roots = LayoutNodes.GetRoots(layoutNodes); - if (roots.Count == 0) - { - throw new System.Exception("Graph has no root node."); - } - else if (roots.Count > 1) - { - throw new System.Exception("Graph has more than one root node."); - } - - ILayoutNode root = roots.FirstOrDefault(); - - if (CoseLayoutSettings.AutomaticParameterCalculation || CoseLayoutSettings.IterativParameterCalculation) - { - GetGoodParameter(); - } - - PlaceNodes(root); - SetCalculatedLayoutPositionToNodes(); - - if (CoseLayoutSettings.IterativParameterCalculation) - { - CalculateParameterAutomatically(); - } - - return layoutResult; - } - - public override Dictionary Layout(IEnumerable gameNodes) - { - throw new NotImplementedException(); - } - - /// - /// Sets the calulated position and scale from the coseNodes to NodeTransfrom - /// - public void SetCalculatedLayoutPositionToNodes() - { - Vector3 relativePositionRootGraph = graphManager.RootGraph.CenterPosition; - graphManager.RootGraph.CenterPosition = new Vector3(0.0f, GroundLevel, 0.0f); - - PlacePositionNodes(graphManager.RootGraph, relativePositionRootGraph); - - foreach (CoseGraph graph in graphManager.Graphs) - { - - Vector3 position = graph != graphManager.RootGraph ? new Vector3(graph.CenterPosition.x - relativePositionRootGraph.x, graph.CenterPosition.y, graph.CenterPosition.z - relativePositionRootGraph.z) : new Vector3(graph.CenterPosition.x, graph.CenterPosition.y, graph.CenterPosition.z); - - - float width = graph.Scale.x; - float height = graph.Scale.z; - - - if (graph.Parent != null && graph.Parent.NodeObject != null && SublayoutNodes.Count() > 0) - { - SublayoutLayoutNode sublayoutNode = CoseHelper.CheckIfNodeIsSublayouRoot(SublayoutNodes, graph.Parent.NodeObject.ID); - - if (sublayoutNode != null && sublayoutNode.NodeLayout == NodeLayoutKind.EvoStreets) - { - width = graph.Parent.SublayoutValues.Sublayout.RootNodeRealScale.x; - height = graph.Parent.SublayoutValues.Sublayout.RootNodeRealScale.z; - position -= graph.Parent.SublayoutValues.Sublayout.LayoutOffset; - } - } - - if (graph != graphManager.RootGraph) - { - position.y += LevelLift(graph.Parent.NodeObject); - } - - bool applyRotation = true; - - foreach (SublayoutLayoutNode node in SublayoutNodes) - { - if (node.Nodes.Contains(graph.GraphObject) && !node.Node.IsSublayoutRoot) - { - applyRotation = false; - break; - } - } - - if (graph.GraphObject != null) - { - float rotation = applyRotation ? graph.GraphObject.Rotation : 0.0f; - layoutResult[graph.GraphObject] = new NodeTransform(position, new Vector3(width, graph.GraphObject.LocalScale.y, height), rotation); - } - - } - } - - /// - /// Resets the node position and rotation to inital - /// - public void Reset() - { - foreach (ILayoutNode layoutNode in layoutNodes) - { - layoutNode.CenterPosition = new Vector3(0, GroundLevel, 0); - layoutNode.Rotation = 0.0f; - } - } - - /// - /// calculates edgeLength and repulsionStrength - /// - public void GetGoodParameter() - { - int countNode = layoutNodes.Where(node => !node.IsSublayoutNode || node.IsSublayoutRoot).ToList().Count; - int countMax = CountDepthMax(layoutNodes); - - int leafNodesCount = layoutNodes.Where(node => node.IsLeaf && (!node.IsSublayoutNode || node.IsSublayoutRoot)).ToList().Count; - - int edgesCount = edges.Where(edge => edge.Source.Children().Count > 0 && edge.Target.Children().Count > 0).ToList().Count; - - int edgeLength = CoseHelper.GetGoodEgdeLength(countNode, countMax, leafNodesCount, edgesCount); - int repulsionStrength = CoseHelper.GetGoodRepulsionRange(countMax, countNode, edgesCount); - - settings.CoseGraphSettings.RepulsionStrength = repulsionStrength; - settings.CoseGraphSettings.EdgeLength = edgeLength; - - CoseLayoutSettings.EdgeLength = edgeLength; - CoseLayoutSettings.RepulsionStrength = repulsionStrength; - } - - /// - /// Calculates the values for edgelength and repuslionforce iterativaly by increasing the values each iteration until a "good" layout is found - /// - private void CalculateParameterAutomatically() - { - int currentEdgeLength = CoseLayoutSettings.EdgeLength; - int currentRepulsionStrength = (int)CoseLayoutSettings.RepulsionStrength; - - IterationConstraint edgeLengthConstraint = new IterationConstraint(start: currentEdgeLength, end: currentEdgeLength + 15, iterationStep: 5); - IterationConstraint repulsionRangeConstraint = new IterationConstraint(start: currentRepulsionStrength, end: currentRepulsionStrength + 15, iterationStep: 5); - - ApplyLayout(); - Measurements measurements = new Measurements(layoutNodes: layoutNodes, edges: edges.ToList()); - - while (measurements.OverlappingGameNodes > 0) - { - int nextRep = currentRepulsionStrength + repulsionRangeConstraint.IterationStep; - if (nextRep <= repulsionRangeConstraint.End) - { - currentRepulsionStrength = nextRep; - } - else - { - int nextEdgeLength = currentEdgeLength + edgeLengthConstraint.IterationStep; - - if (nextEdgeLength <= edgeLengthConstraint.End) - { - currentEdgeLength = nextEdgeLength; - currentRepulsionStrength = repulsionRangeConstraint.Start; - } - else - { - break; - } - } - - Reset(); - CalculateLayout(edgeLength: currentEdgeLength, repulsionStrength: currentRepulsionStrength); - ApplyLayout(); - measurements = new Measurements(layoutNodes: layoutNodes, edges: edges.ToList()); - } - Reset(); - } - - /// - /// Applies the caluclated positions to the layout nodes - /// - private void ApplyLayout() - { - foreach (KeyValuePair entry in layoutResult) - { - ILayoutNode node = entry.Key; - NodeTransform transform = entry.Value; - Vector3 position = transform.Position; - position.y += transform.Scale.y / 2.0f; - node.CenterPosition = position; - node.LocalScale = transform.Scale; - node.Rotation = transform.Rotation; - } - } - - /// - /// Calculates the layout with the given edgeLength and repuslionStrength - /// - /// the edgelength - /// the repulsionStrength - private void CalculateLayout(int edgeLength, int repulsionStrength) - { - CoseLayoutSettings.EdgeLength = edgeLength; - CoseLayoutSettings.RepulsionStrength = repulsionStrength; - settings.CoseGraphSettings.EdgeLength = edgeLength; - settings.CoseGraphSettings.RepulsionStrength = repulsionStrength; - - StartLayoutProzess(); - SetCalculatedLayoutPositionToNodes(); - } - - /// - /// Calculates the maximal depth of all nodes in . - /// - /// the layout nodes - /// maximal depth of given - private static int CountDepthMax(ICollection layoutNodes) - { - int depth = 0; - foreach (ILayoutNode node in layoutNodes) - { - if (node.IsLeaf) - { - if (depth < node.Level) - { - depth = node.Level; - } - } - } - - return depth; - } - - /// - /// Setup function for the CoseGraphSettings - /// Values for Graph Layout Settings and Setup for Layouts - /// - /// Graph Settings, choosed by user - private void SetupGraphSettings(CoseGraphAttributes settings) - { - CoseLayoutSettings.EdgeLength = settings.EdgeLength; - CoseLayoutSettings.UseSmartIdealEdgeCalculation = settings.UseSmartIdealEdgeCalculation; - CoseLayoutSettings.PerLevelIdealEdgeLengthFactor = settings.PerLevelIdealEdgeLengthFactor; - CoseLayoutSettings.UseSmartRepulsionRangeCalculation = settings.UseSmartRepulsionRangeCalculation; - CoseLayoutSettings.GravityStrength = settings.GravityStrength; - CoseLayoutSettings.CompoundGravityStrength = settings.CompoundGravityStrength; - CoseLayoutSettings.RepulsionStrength = settings.RepulsionStrength; - CoseLayoutSettings.MultilevelScaling = settings.MultiLevelScaling; - CoseLayoutSettings.UseSmartMultilevelCalculation = settings.UseSmartMultilevelScaling; - CoseLayoutSettings.AutomaticParameterCalculation = settings.UseCalculationParameter; - CoseLayoutSettings.IterativParameterCalculation = settings.UseIterativeCalculation; - - coseLayoutSettings = new CoseLayoutSettings(); - - } - - /// - /// places the original node objects to the calculated positions - /// and applys relativ position of the root graph to all nodes - /// - /// the root graph - /// the relative postion of the root graph. - private void PlacePositionNodes(CoseGraph root, Vector3 relativePositionRootGraph) - { - foreach (CoseNode node in root.Nodes) - { - if (node.IsLeaf()) - { - ILayoutNode nNode = node.NodeObject; - - bool applyRotation = true; - - foreach (SublayoutLayoutNode sublayoutNode in SublayoutNodes) - { - if (sublayoutNode.Nodes.Contains(node.NodeObject) && !sublayoutNode.Node.IsSublayoutRoot) - { - applyRotation = false; - break; - } - } - - float rotation = applyRotation ? node.NodeObject.Rotation : 0.0f; - - Vector3 position = new Vector3(node.CenterPosition.x - relativePositionRootGraph.x, node.CenterPosition.y, node.CenterPosition.z - relativePositionRootGraph.z); - NodeTransform transform = new NodeTransform(position, node.NodeObject.LocalScale, rotation); - layoutResult[nNode] = transform; - } - - if (node.Child != null) - { - PlacePositionNodes(node.Child, relativePositionRootGraph); - } - } - } - - /// - /// Places the Nodes - /// - /// Root Node - private void PlaceNodes(ILayoutNode root) - { - CreateTopology(root); - CalculateSubLayouts(); - - if (SublayoutNodes.Count > 0 && CoseHelper.CheckIfNodeIsSublayouRoot(SublayoutNodes, graphManager.RootGraph.Nodes.First().NodeObject.ID) != null) - { - graphManager.UpdateBounds(); - } - else - { - StartLayoutProzess(); - } - } - - /// - /// Starts the layout process - /// - private void StartLayoutProzess() - { - if (CoseLayoutSettings.MultilevelScaling) - { - CoseLayoutSettings.Incremental = false; - MultiLevelScaling(); - } - else - { - CoseLayoutSettings.Incremental = true; - ClassicLayout(); - } - } - - /// - /// Starts the layout process of a classic layout - /// - private void ClassicLayout() - { - CalculateNodesToApplyGravityTo(); - CalcNoOfChildrenForAllNodes(); - graphManager.CalcLowestCommonAncestors(); - graphManager.CalcInclusionTreeDepths(); - graphManager.RootGraph.CalcEstimatedSize(); - CalcIdealEdgeLength(); - InitSpringEmbedder(); - RunSpringEmbedder(); - } - - /// - /// Calculates the number of children of every node - /// - private void CalcNoOfChildrenForAllNodes() - { - graphManager.GetAllNodes().ForEach(node => node.NoOfChildren = node.CalcNumberOfChildren()); - } - - /// - /// Starts the layout process of a multi level scaling layout - /// - private void MultiLevelScaling() - { - CoseGraphManager gm = graphManager; - gmList = gm.CoarsenGraph(); - - coseLayoutSettings.NoOfLevels = gmList.Count - 1; - coseLayoutSettings.Level = coseLayoutSettings.NoOfLevels; - - Dictionary edgeLengths = new Dictionary(); - - if (CoseLayoutSettings.UseSmartMultilevelCalculation) - { - int originalEdgeLength = CoseLayoutSettings.EdgeLength; - - edgeLengths.Add(0, originalEdgeLength); - - // we dont have to look at the original graph - for (int i = 1; i < gmList.Count; i++) - { - int k = edgeLengths[i - 1]; - double fac = Math.Sqrt(4.0 / 7); - int newEdgeLength = (int)(fac * k); - newEdgeLength = Math.Max(newEdgeLength, 1); - Debug.Log(""); - edgeLengths.Add(i, newEdgeLength); - } - } - - while (coseLayoutSettings.Level >= 0) - { - graphManager = gmList[coseLayoutSettings.Level]; - - if (CoseLayoutSettings.UseSmartMultilevelCalculation) - { - CoseLayoutSettings.EdgeLength = edgeLengths[coseLayoutSettings.Level]; - } - - ClassicLayout(); - CoseLayoutSettings.Incremental = true; - - if (coseLayoutSettings.Level >= 1) - { - Uncoarsen(); - } - - coseLayoutSettings.TotalIterations = 0; - coseLayoutSettings.Coolingcycle = 0; - coseLayoutSettings.Level--; - } - - CoseLayoutSettings.Incremental = false; - } - - /// - /// uncoarsen all nodes from the layouts graph manager - /// - private void Uncoarsen() - { - foreach (CoseNode node in graphManager.GetAllNodes()) - { - node.LayoutValues.Pred1.SetLocation(node.CenterPosition.x, node.CenterPosition.z); - if (node.LayoutValues.Pred2 != null) - { - node.LayoutValues.Pred2.SetLocation(node.CenterPosition.x + CoseLayoutSettings.EdgeLength, node.CenterPosition.z + CoseLayoutSettings.EdgeLength); - } - } - } - - /// - /// calculates the sublayouts - /// - private void CalculateSubLayouts() - { - foreach (CoseNode node in graphManager.GetAllNodes()) - { - SetSublayoutValuesToNode(node: node); - } - } - - /// - /// Set sublayout values from the nodeobject of this node to the layoutValues of this node - /// - /// a cose node - private void SetSublayoutValuesToNode(CoseNode node) - { - node.SublayoutValues.IsSubLayoutNode = node.NodeObject.IsSublayoutNode; - node.SublayoutValues.IsSubLayoutRoot = node.NodeObject.IsSublayoutRoot; - node.SublayoutValues.Sublayout = node.NodeObject.Sublayout; - if (node.NodeObject.SublayoutRoot != null) - { - node.SublayoutValues.SubLayoutRoot = nodeToCoseNode[node.NodeObject.SublayoutRoot]; - } - - if (node.SublayoutValues.IsSubLayoutNode) - { - node.SublayoutValues.RelativeScale = new Vector3(node.NodeObject.LocalScale.x, node.NodeObject.LocalScale.y, node.NodeObject.LocalScale.z); - node.SublayoutValues.RelativeCenterPosition = new Vector3(node.NodeObject.CenterPosition.x, node.NodeObject.CenterPosition.y, node.NodeObject.CenterPosition.z); - - node.Scale = new Vector3(node.NodeObject.LocalScale.x, node.NodeObject.LocalScale.y, node.NodeObject.LocalScale.z); - node.CenterPosition = new Vector3(node.NodeObject.CenterPosition.x, node.NodeObject.CenterPosition.y, node.NodeObject.CenterPosition.z); - - if (!node.SublayoutValues.IsSubLayoutRoot) - { - node.SetPositionRelativ(node.SublayoutValues.SubLayoutRoot); - - if (node.Child != null) - { - node.Child.LeftFrontCorner = node.GetLeftFrontCorner(); - node.Child.RightBackCorner = node.GetRightBackCorner(); - node.Child.UpdateBounding(); - } - } - } - } - - /// - /// Runs the spring embedder - /// - private void RunSpringEmbedder() - { - graphManager.UpdateBounds(); - do - { - coseLayoutSettings.TotalIterations++; - if (coseLayoutSettings.TotalIterations % CoseLayoutSettings.ConvergenceCheckPeriode == 0) - { - if (IsConverged()) - { - break; - } - coseLayoutSettings.Coolingcycle++; - - // based on www.btluke.com/simanf1.html, schedule 3 - coseLayoutSettings.CoolingFactor = Mathf.Max(coseLayoutSettings.InitialCoolingFactor - Mathf.Pow(coseLayoutSettings.Coolingcycle, Mathf.Log(100 * (coseLayoutSettings.InitialCoolingFactor - coseLayoutSettings.FinalTemperature)) / Mathf.Log(coseLayoutSettings.MaxCoolingCycle)) / 100, coseLayoutSettings.FinalTemperature); - //Debug.LogFormat("cooling factor: {0}\n", coseLayoutSettings.CoolingFactor); - } - - coseLayoutSettings.TotalDisplacement = 0; - CalcSpringForces(); - CalcRepulsionForces(); - CalcGravitationalForces(); - MoveNodes(); - graphManager.UpdateBounds(); - ResetForces(); - - } while (coseLayoutSettings.TotalIterations < coseLayoutSettings.MaxIterations); - graphManager.UpdateBounds(); - } - - /// - /// Calculates the spring forces for all edges - /// - private void CalcSpringForces() - { - List edges = GetAllEdges(); - - foreach (CoseEdge edge in edges) - { - CalcSpringForce(edge, edge.IdealEdgeLength); - } - } - - /// - /// Calculates the spring force for one edge - /// - /// the edge - /// the ideal edge length of this edge - private static void CalcSpringForce(CoseEdge edge, float idealEdgeLength) - { - CoseNode source = edge.Source; - CoseNode target = edge.Target; - - float length; - float springForce; - float springForceX; - float springForceY; - - if (CoseLayoutSettings.UniformLeafNodeSize && source.Child == null && target.Child == null) - { - edge.UpdateLengthSimple(); - } - else - { - edge.UpdateLenght(); - - if (edge.IsOverlappingSourceAndTarget) - { - return; - } - } - - length = edge.Length; - - float dl = length - idealEdgeLength; - - if (length == 0.0) - { - length = 0.1f; - } - - if (dl == 0.0) - { - springForceX = 0; - springForceY = 0; - } - else - { - springForce = CoseLayoutSettings.SpringStrength * dl; - springForceX = springForce * (edge.LengthX / length); - springForceY = springForce * (edge.LengthY / length); - } - - if (float.IsNaN(springForceX)) - { - Debug.Log(""); - } - - source.LayoutValues.SpringForceX += springForceX; - source.LayoutValues.SpringForceY += springForceY; - target.LayoutValues.SpringForceX -= springForceX; - target.LayoutValues.SpringForceY -= springForceY; - } - - /// - /// Returns all edges of this layout - /// - /// - private List GetAllEdges() - { - return graphManager.GetAllEdges(); - } - - /// - /// calculates the repuslion forces for all nodes - /// - private void CalcRepulsionForces() - { - int i; - int j; - List nodes = GetAllNodes(); - HashSet processedNodeSet; - - if (CoseLayoutSettings.UseSmartRepulsionRangeCalculation) - { - if ((coseLayoutSettings.TotalIterations % CoseLayoutSettings.GridCalculationCheckPeriode) == 1) - { - grid = CalcGrid(graphManager.RootGraph); - - foreach (CoseNode node in nodes) - { - AddNodeToGrid(node, graphManager.RootGraph.LeftFrontCorner.x, graphManager.RootGraph.RightBackCorner.y); - } - } - - processedNodeSet = new HashSet(); - - foreach (CoseNode node in nodes) - { - CalculateRepulsionForceForNode(node, processedNodeSet); - processedNodeSet.Add(node); - } - } - else - { - for (i = 0; i < nodes.Count; i++) - { - CoseNode nodeA = nodes[i]; - - for (j = i + 1; j < nodes.Count; j++) - { - CoseNode nodeB = nodes[j]; - - if (nodeA.Owner != nodeB.Owner) - { - continue; - } - - CalcRepulsionForce(nodeA, nodeB); - } - } - } - } - - /// - /// Calculates the repulsion force for one node - /// - /// the node - /// a set of nodes that have already been processed (repulsion forces already have been calcualted) - private void CalculateRepulsionForceForNode(CoseNode nodeA, HashSet processedNodeSet) - { - int i; - int j; - - if (coseLayoutSettings.TotalIterations % CoseLayoutSettings.GridCalculationCheckPeriode == 1) - { - HashSet surrounding = new HashSet(); - - for (i = (nodeA.LayoutValues.StartX - 1); i < (nodeA.LayoutValues.FinishX + 2); i++) - { - for (j = (nodeA.LayoutValues.StartY - 1); j < (nodeA.LayoutValues.FinishY + 2); j++) - { - - if (!((i < 0) || (j < 0) || (i >= grid.GetLength(0)) || (j >= grid.GetLength(1)))) - { - List list = grid[i, j]; - - for (int k = 0; k < list.Count; k++) - { - CoseNode nodeB = list[k]; - - if ((nodeA.Owner != nodeB.Owner) || (nodeA == nodeB)) - { - continue; - } - - if (!processedNodeSet.Contains(nodeB) && !surrounding.Contains(nodeB)) - { - double distanceX = Mathf.Abs(nodeA.GetCenterX() - nodeB.GetCenterX()) - ((nodeA.Scale.x / 2) + (nodeB.Scale.x / 2)); - double distanceY = Mathf.Abs(nodeA.GetCenterY() - nodeB.GetCenterY()) - ((nodeA.Scale.z / 2) + (nodeB.Scale.z / 2)); - if ((distanceX <= coseLayoutSettings.RepulsionRange) && (distanceY <= coseLayoutSettings.RepulsionRange)) - { - surrounding.Add(nodeB); - } - } - } - } - } - } - nodeA.Surrounding = surrounding.ToList(); - } - - foreach (CoseNode node in nodeA.Surrounding) - { - CalcRepulsionForce(nodeA, node); - } - } - - /// - /// Calculates the repulsion force between two nodes - /// - /// the first node - /// the second node - private static void CalcRepulsionForce(CoseNode nodeA, CoseNode nodeB) - { - double[] overlapAmount = new double[2]; - double[] clipPoints = new double[4]; - float distanceX; - float distanceY; - float distanceSquared; - float distance; - float repulsionForce; - float repulsionForceX; - float repulsionForceY; - - if (nodeA.CalcOverlap(nodeB, overlapAmount)) - { - repulsionForceX = 2 * (float)overlapAmount[0]; - repulsionForceY = 2 * (float)overlapAmount[1]; - - float childrenConstant = nodeA.NoOfChildren * nodeB.NoOfChildren / (float)(nodeA.NoOfChildren + nodeB.NoOfChildren); - - nodeA.LayoutValues.RepulsionForceX -= childrenConstant * repulsionForceX; - nodeA.LayoutValues.RepulsionForceY -= childrenConstant * repulsionForceY; - - nodeB.LayoutValues.RepulsionForceX += childrenConstant * repulsionForceX; - nodeB.LayoutValues.RepulsionForceY += childrenConstant * repulsionForceY; - } - else - { - if (CoseLayoutSettings.UniformLeafNodeSize && nodeA.Child == null && nodeB.Child == null) - { - distanceX = nodeB.CenterPosition.x - nodeA.CenterPosition.x; - distanceY = nodeB.CenterPosition.z - nodeA.CenterPosition.z; - } - else - { - clipPoints = nodeA.CalcIntersection(nodeB, clipPoints); - - distanceX = (float)clipPoints[2] - (float)clipPoints[0]; - distanceY = (float)clipPoints[3] - (float)clipPoints[1]; - } - - if (Mathf.Abs(distanceX) < CoseLayoutSettings.MinRepulsionDistance) - { - distanceX = Mathf.Sign(distanceX) * CoseLayoutSettings.MinRepulsionDistance; - } - - if (Mathf.Abs(distanceY) < CoseLayoutSettings.MinRepulsionDistance) - { - distanceY = Mathf.Sign(distanceY) * CoseLayoutSettings.MinRepulsionDistance; - } - - distanceSquared = (distanceX * distanceX) + (distanceY * distanceY); - distance = Mathf.Sqrt((float)distanceSquared); - - repulsionForce = CoseLayoutSettings.RepulsionStrength * nodeA.NoOfChildren * nodeB.NoOfChildren / distanceSquared; - - repulsionForceX = repulsionForce * distanceX / distance; - repulsionForceY = repulsionForce * distanceY / distance; - - nodeA.LayoutValues.RepulsionForceX -= repulsionForceX; - nodeA.LayoutValues.RepulsionForceY -= repulsionForceY; - - nodeB.LayoutValues.RepulsionForceX += repulsionForceX; - nodeB.LayoutValues.RepulsionForceY += repulsionForceY; - } - - if (float.IsNaN(nodeA.LayoutValues.RepulsionForceX)) - { - Debug.Log(""); - } - } - - /// - /// Adds a node to the grid (multi level scaling) - /// - /// the node - /// the left position - /// the top position - private void AddNodeToGrid(CoseNode v, double left, double top) - { - int startX = (int)Math.Floor((v.GetLeftFrontCorner().x - left) / coseLayoutSettings.RepulsionRange); - int finishX = (int)Math.Floor((v.Scale.x + v.GetLeftFrontCorner().x - left) / coseLayoutSettings.RepulsionRange); - int startY = (int)Math.Floor((v.GetRightBackCorner().y - top) / coseLayoutSettings.RepulsionRange); - int finishY = (int)Math.Floor((v.Scale.z + v.GetRightBackCorner().y - top) / coseLayoutSettings.RepulsionRange); - - for (int i = startX; i <= finishX; i++) - { - for (int j = startY; j <= finishY; j++) - { - grid[i, j].Add(v); - v.SetGridCoordinates(startX, finishX, startY, finishY); - } - } - } - - /// - /// calculates the grid for multi level scaling - /// - /// the graph to calcualte the grid for - /// the grid - private List[,] CalcGrid(CoseGraph graph) - { - int i; - int j; - - List[,] collect; - - int sizeX = (int)Mathf.Ceil((float)((graph.RightBackCorner.x - graph.LeftFrontCorner.x) / coseLayoutSettings.RepulsionRange)); - int sizeY = (int)Mathf.Ceil((float)((graph.LeftFrontCorner.y - graph.RightBackCorner.y) / coseLayoutSettings.RepulsionRange)); - - collect = new List[sizeX, sizeY]; - - for (i = 0; i < sizeX; i++) - { - for (j = 0; j < sizeY; j++) - { - collect[i, j] = new List(); - } - } - return collect; - } - - /// - /// Calculates the gravitational forces for a node - /// - /// - private void CalcGravitationalForce(CoseNode node) - { - if (node.LayoutValues.GravitationForceX != 0 && node.LayoutValues.GravitationForceY != 0) - { - throw new System.Exception("gravitational force needs to be 0.0"); - } - CoseGraph ownerGraph; - float ownerCenterX; - float ownerCenterY; - float distanceX; - float distanceY; - float absDistanceX; - float absDistanceY; - int estimatedSize; - - ownerGraph = node.Owner; - ownerCenterX = ownerGraph.CenterPosition.x; - ownerCenterY = ownerGraph.CenterPosition.z; - distanceX = node.GetCenterX() - ownerCenterX; - distanceY = node.GetCenterY() - ownerCenterY; - absDistanceX = Mathf.Abs(distanceX) + node.Scale.x / 2; - absDistanceY = Mathf.Abs(distanceY) + node.Scale.z / 2; - - if (node.Owner == graphManager.RootGraph) - { - estimatedSize = (int)(ownerGraph.EstimatedSize * CoseLayoutSettings.GravityRangeFactor); - - if (absDistanceX > estimatedSize || absDistanceY > estimatedSize) - { - node.LayoutValues.GravitationForceX = -CoseLayoutSettings.GravityStrength * distanceX; - node.LayoutValues.GravitationForceY = -CoseLayoutSettings.GravityStrength * distanceY; - } - } - else - { - estimatedSize = (int)(ownerGraph.EstimatedSize * CoseLayoutSettings.CompoundGravityRangeFactor); - - if (absDistanceX > estimatedSize || absDistanceY > estimatedSize) - { - node.LayoutValues.GravitationForceX = -CoseLayoutSettings.GravityStrength * distanceX * CoseLayoutSettings.CompoundGravityStrength; - node.LayoutValues.GravitationForceY = -CoseLayoutSettings.GravityStrength * distanceY * CoseLayoutSettings.CompoundGravityStrength; - } - } - } - - /// - /// Calculates the gravitational forces for all nodes of this layout - /// - private void CalcGravitationalForces() - { - List nodes = graphManager.NodesToApplyGravitation; - - foreach (CoseNode node in nodes) - { - CalcGravitationalForce(node); - } - } - - /// - /// Move all nodes - /// - private void MoveNodes() - { - List nodes = GetAllNodes(); - foreach (CoseNode node in nodes) - { - if (!node.SublayoutValues.IsSubLayoutNode || node.SublayoutValues.IsSubLayoutRoot) - { - node.Move(); - } - } - } - - /// - /// Resets all forces acting on the nodes of this layout - /// - private void ResetForces() - { - List nodes = GetAllNodes(); - foreach (CoseNode node in nodes) - { - node.Reset(); - } - } - - /// - /// This methode inspects whether the graph has reached to a minima. It returns true if the layout seems to be oscillating as well. - /// - /// - private bool IsConverged() - { - bool converged; - bool oscilating = false; - - if (coseLayoutSettings.TotalIterations > coseLayoutSettings.MaxIterations / 3) - { - oscilating = Math.Abs(coseLayoutSettings.TotalDisplacement - coseLayoutSettings.OldTotalDisplacement) < 2; - } - converged = coseLayoutSettings.TotalDisplacement < (decimal)coseLayoutSettings.TotalDisplacementThreshold; - coseLayoutSettings.OldTotalDisplacement = coseLayoutSettings.TotalDisplacement; - return converged || oscilating; - } - - /// - /// Initalizes the spring embedder - /// - private void InitSpringEmbedder() - { - if (CoseLayoutSettings.Incremental) - { - coseLayoutSettings.CoolingFactor = 0.8f; - coseLayoutSettings.InitialCoolingFactor = 0.8f; - coseLayoutSettings.MaxNodeDisplacement = CoseLayoutSettings.MaxNodeDisplacementIncremental; - } - else - { - coseLayoutSettings.CoolingFactor = 1.0f; - coseLayoutSettings.InitialCoolingFactor = 1.0f; - coseLayoutSettings.MaxNodeDisplacement = CoseLayoutSettings.MaxNodeDisplacement; - } - - coseLayoutSettings.MaxIterations = Math.Max(GetAllNodes().Count * 5, coseLayoutSettings.MaxIterations); - coseLayoutSettings.TotalDisplacementThreshold = coseLayoutSettings.DisplacementThresholdPerNode * GetAllNodes().Count; - coseLayoutSettings.RepulsionRange = CalcRepulsionRange(); - } - - /// - /// Calculates the repulsion range - /// - /// - private double CalcRepulsionRange() - { - double repulsionRange = (2 * (coseLayoutSettings.Level + 1) * CoseLayoutSettings.EdgeLength); - return repulsionRange; - - } - - /// - /// Calculates the ideal edge length for each edge - /// - private void CalcIdealEdgeLength() - { - int lcaDepth; - CoseNode source; - CoseNode target; - - foreach (CoseEdge edge in graphManager.GetAllEdges()) - { - edge.IdealEdgeLength = CoseLayoutSettings.EdgeLength; - - if (edge.IsInterGraph) - { - source = edge.Source; - target = edge.Target; - - - - if (CoseLayoutSettings.UseSmartIdealEdgeCalculation) - { - int sizeOfSourceInLca = (int)Math.Round(edge.SourceInLca.EstimatedSize); - int sizeOfTargetInLca = (int)Math.Round(edge.TargetInLca.EstimatedSize); - - edge.IdealEdgeLength += sizeOfSourceInLca + sizeOfTargetInLca - 2 * CoseLayoutSettings.SimpleNodeSize; - } - - lcaDepth = edge.LowestCommonAncestor.GetInclusionTreeDepth(); - - edge.IdealEdgeLength += CoseLayoutSettings.EdgeLength * CoseLayoutSettings.PerLevelIdealEdgeLengthFactor * (source.InclusionTreeDepth + target.InclusionTreeDepth - 2 * lcaDepth); - } - } - } - - /// - /// Indicates whether the edge is allowed in coselayout or not. - /// All Edge between predecessors and successors in the same hierarchie (inclusion branch) are not allowed in the cose layout - /// - /// the edge to check - /// is Allowed in layout - private bool ExcludeEdgesInSameHierarchie(Edge edge) - { - // Kanten zwischen Vorgängern und Nachfolgern in der gleichen Hierarchie werden vom Layout ausgeschlossen - - ILayoutNode sourceNode = layoutNodes.Where(node => node.ID == edge.Source.ID).First(); - ILayoutNode targetNode = layoutNodes.Where(node => node.ID == edge.Target.ID).First(); - - if (sourceNode.Level == targetNode.Level) - { - return true; - } - - ILayoutNode startNode = sourceNode.Level <= targetNode.Level ? sourceNode : targetNode; - - return CheckChildrenForHierachie(targetNode, startNode.Children()); - } - - /// - /// Check whether the node is with one of the given nodes in the same hierarchy - /// - /// - /// - /// - private bool CheckChildrenForHierachie(ILayoutNode node, ICollection children) - { - foreach (ILayoutNode child in children) - { - if (node.ID == child.ID) - { - return false; - } - - if (!CheckChildrenForHierachie(node, child.Children())) - { - return false; - } - } - - return true; - } - - /// - /// Calculates the Topology for the given graph structure - /// - /// root of the graph - private void CreateTopology(ILayoutNode root) - { - graphManager = new CoseGraphManager(this); - graphManager.AddRootGraph(); - CreateNode(root, null); - - foreach (Edge edge in edges) - { - if (ExcludeEdgesInSameHierarchie(edge) && (edge.Source.ID != edge.Target.ID)) - { - CreateEdge(edge); - } - } - graphManager.UpdateBounds(); - } - - /// - /// Creates a new node from a ILayoutNode - /// - /// the original node - /// the parent node - private void CreateNode(ILayoutNode node, CoseNode parent) - { - CoseNode cNode = NewNode(node); - CoseGraph rootGraph = graphManager.RootGraph; - - nodeToCoseNode.Add(node, cNode); - - if (parent != null) - { - //CoseNode cParent = nodeToCoseNode[parent]; - if (parent.Child == null) - { - throw new System.Exception("Parent Node doesnt have a child graph"); - } - parent.Child.AddNode(cNode); - } - else - { - rootGraph.AddNode(cNode); - } - - // inital position - cNode.SetLocation(node.CenterPosition.x, node.CenterPosition.z); - - if (!node.IsLeaf) - { - CoseGraph graph = new CoseGraph(null, graphManager); - graph.GraphObject = node; - graphManager.Add(graph, cNode); - - foreach (ILayoutNode child in cNode.NodeObject.Children()) - { - CreateNode(child, cNode); - } - - cNode.UpdateBounds(); - } - else - { - Vector3 size = node.LocalScale; - cNode.SetWidth(size.x); - cNode.SetHeight(size.z); - } - } - - /// - /// Creates a new graph - /// - /// the new graph - public CoseGraph NewGraph() - { - return new CoseGraph(null, graphManager); - } - - /// - /// Creates a new node from a ILayoutNode - /// - /// a ILayoutNode - /// the new node - private CoseNode NewNode(ILayoutNode node) - { - return new CoseNode(node, graphManager); - } - - /// - /// Creates a new cose edge - /// - /// the new edge - private void CreateEdge(Edge edge) - { - CoseEdge cEdge = new CoseEdge(nodeToCoseNode[CoseHelper.GetLayoutNodeFromLinkname(edge.Source.ID, layoutNodes)], - nodeToCoseNode[CoseHelper.GetLayoutNodeFromLinkname(edge.Target.ID, layoutNodes)]); - - graphManager.Add(cEdge, cEdge.Source, cEdge.Target); - } - - /// - /// - finds a list of nodes for which gravitation should be applied - /// - for connected graphs(root graph or compound/ children graphs) there is no need to apply gravitation - /// - each graph/ children node is marked as connected or not - /// - private void CalculateNodesToApplyGravityTo() - { - List listNodes = new List(); - - foreach (CoseGraph graph in graphManager.Graphs) - { - graph.UpdateConnected(); - - if (!graph.IsConnected) - { - listNodes.AddRange(graph.Nodes); - } - } - - graphManager.NodesToApplyGravitation = listNodes; - } - - /// - /// Creates a new node - /// - /// the new node - public CoseNode NewNode() - { - return new CoseNode(null, graphManager); - } - - /// - /// Returns all nodes of this layout - /// - /// all nodes - private List GetAllNodes() - { - return graphManager.GetAllNodes(); - } - - public override bool IsHierarchical() - { - return true; - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return true; - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs.meta deleted file mode 100644 index b5b82349be..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b83f7438b6b200647bbe1d4a9e51700e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs deleted file mode 100644 index e6714f1c1e..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseLayoutSettings - { - /// - /// the margin of a graph - /// - public static float GraphMargin = 0.5f; - - /// - /// the margin of a compound node - /// - public static int CompoundNodeMargin = 1; - - /// - /// the empty compound node size - /// - public static int EmptyCompoundSize = 5; - - /// - /// the ideal edge length - /// - public static int EdgeLength = 20; - - /// - /// indicates whether to use the smart edge length calculation during the layout process - /// - public static bool UseSmartIdealEdgeCalculation = false; - - /// - /// true if smart multilevel calculation is used - /// - public static bool UseSmartMultilevelCalculation = false; - - /// - /// the simple node size - /// - public static int SimpleNodeSize = 1; - - /// - /// the factor by which the edge length increases with every level of the edges source/target node - /// - public static float PerLevelIdealEdgeLengthFactor = 0.1f; - - /// - /// Indicates whether the layout process is incrementally calculated - /// - public static bool Incremental = true; - - /// - /// the maximum value of the displacement of a node when the layout process is incrementally calculated - /// - public static float MaxNodeDisplacementIncremental = 50.0f; - - /// - /// the maximum value of the displacement of a node when the layout process is not incrementally calculated - /// - //public static double MaxNodeDisplacement = 100.0 * 3; - - /// - /// the check period - /// - public static int ConvergenceCheckPeriode = 100; - - /// - /// Indicates whether all node have the same size - /// - public static bool UniformLeafNodeSize = false; - - /// - /// the strength of a spring - /// - public static float SpringStrength = 0.45f; - - /// - /// Indicates whether smart repulsion range calculation is used - /// - public static bool UseSmartRepulsionRangeCalculation = false; - - /// - /// the check period interval for the grid calculation (multilevel scaling) - /// - public static int GridCalculationCheckPeriode = 10; - - /// - /// the minimal distance for applying the repulsion strength - /// - public static float MinRepulsionDistance = EdgeLength / 10; - - /// - /// the repulsion strength - /// - public static float RepulsionStrength = 50; - - /// - /// the gravity range factor - /// - public static float GravityRangeFactor = 2.0f; - - /// - /// the strength of the global gravity - /// - public static float GravityStrength = 0.8f; - - /// - /// the compound gravity range factor - /// - public static float CompoundGravityRangeFactor = 1.5f; - - /// - /// the strength of the gravity in a compound node - /// - public static float CompoundGravityStrength = 1.5f; - - /// - /// Indicates whether multilevel scaling is used - /// - public static bool MultilevelScaling = false; - - /// - /// the cooling adjuster - /// - public static int CoolingAdjuster = 1; - - /// - /// true if the parameter edgeLength/repulsionStrength should be calculated automatically - /// - public static bool AutomaticParameterCalculation = true; - - /// - /// true if the layout process continues until a "good" layout is found - /// - public static bool IterativParameterCalculation = false; - - /// - /// the cooling factor - /// - private float coolingFactor; - - /// - /// the initial cooling factor - /// - private float initialCoolingFactor; - - /// - /// the amount of cooling cycles - /// - private float coolingcycle; - - /// - /// The final temperature - /// - private float finalTemperature; - - /// - /// the maximum number of cooling cycles - /// - private int maxCoolingCycle; - - /// - /// the maximal displacement for a node - /// - private double maxNodeDisplacement; - - /// - /// maximum number of iterations - /// - private int maxIterations; - - /// - /// the total displacement threshold - /// - private double totalDisplacementThreshold; - - /// - /// the repulsion range - /// - private double repulsionRange; - - /// - /// the displacement threshold per node - /// - private double displacementThresholdPerNode; - - /// - /// the amount of iterations done - /// - private double totalIterations; - - /// - /// the amount of the displacement done - /// - private decimal totalDisplacement; - - /// - /// the old amount of the displacement done - /// - private decimal oldTotalDisplacement; - - /// - /// current level (multilevel scaling) - /// - private int level; - - /// - /// number of levels - /// - private int noOfLevels; - - public CoseLayoutSettings() - { - coolingFactor = 1.0f; - initialCoolingFactor = 1.0f; - coolingcycle = 0; - finalTemperature = 0; - maxIterations = 4000; - finalTemperature = ConvergenceCheckPeriode / maxIterations; - maxCoolingCycle = maxIterations / ConvergenceCheckPeriode; - displacementThresholdPerNode = (3.0 * EdgeLength) / 100; - totalIterations = 0; - totalDisplacement = 0.0m; - oldTotalDisplacement = 0.0m; - level = 0; - } - - public float InitialCoolingFactor { get => initialCoolingFactor; set => initialCoolingFactor = value; } - public float Coolingcycle { get => coolingcycle; set => coolingcycle = value; } - public float FinalTemperature { get => finalTemperature; set => finalTemperature = value; } - public int MaxCoolingCycle { get => maxCoolingCycle; set => maxCoolingCycle = value; } - public int MaxIterations { get => maxIterations; set => maxIterations = value; } - public double TotalDisplacementThreshold { get => totalDisplacementThreshold; set => totalDisplacementThreshold = value; } - public double RepulsionRange { get => repulsionRange; set => repulsionRange = value; } - public double DisplacementThresholdPerNode { get => displacementThresholdPerNode; set => displacementThresholdPerNode = value; } - public double TotalIterations { get => totalIterations; set => totalIterations = value; } - public decimal OldTotalDisplacement { get => oldTotalDisplacement; set => oldTotalDisplacement = value; } - public int Level { get => level; set => level = value; } - public float CoolingFactor { get => coolingFactor; set => coolingFactor = value; } - public double MaxNodeDisplacement { get => maxNodeDisplacement; set => maxNodeDisplacement = value; } - public decimal TotalDisplacement { get => totalDisplacement; set => totalDisplacement = value; } - public int NoOfLevels { get => noOfLevels; set => noOfLevels = value; } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs.meta deleted file mode 100644 index bf7c0ffbbe..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseLayoutSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 0b42958ec05a39d49be4dbc1870cda84 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs deleted file mode 100644 index aa8e253fec..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs +++ /dev/null @@ -1,622 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseNode - { - /// - /// The GraphManager of the current CoseLayout - /// - private CoseGraphManager graphManager; - - /// - /// The original node - /// - private ILayoutNode nodeObject; - - /// - /// indicates whether this node is connected/ parent graph is connected - /// - private bool isConnected = true; - - /// - /// The child graph/ graph neasted inside the node - /// - private CoseGraph child; - - /// - /// The graph to with the node belongs to - /// - private CoseGraph owner; - - /// - /// The incoming/ outgoing edges - /// - private List edges = new List(); - - /// - /// the scale of this node - /// - private Vector3 scale; - - /// - /// the centerPosition of this node - /// - private Vector3 centerPosition; - - /// - /// the extend of this node - /// - public Vector3 Extend - { - get => scale / 2; - } - - /// - /// the sublayout values - /// - private CoseNodeSublayoutValues sublayoutValues = new CoseNodeSublayoutValues(); - - /// - /// The estimated size of the node - /// - private double estimatedSize = Mathf.NegativeInfinity; - - /// - /// the layout value - /// - private CoseNodeLayoutValues layoutValues = new CoseNodeLayoutValues(); - - /// - /// A list of nodes that surround the node - /// - private List surrounding = new List(); - - /// - /// the number of children - /// - private int noOfChildren; - - /// - /// the inclusion tree depth - /// - private int inclusionTreeDepth = int.MaxValue; - - public int NoOfChildren { get => noOfChildren; set => noOfChildren = value; } - public List Surrounding { get => surrounding; set => surrounding = value; } - public CoseNodeLayoutValues LayoutValues { get => layoutValues; set => layoutValues = value; } - public double EstimatedSize { get => estimatedSize; set => estimatedSize = value; } - public CoseNodeSublayoutValues SublayoutValues { get => sublayoutValues; set => sublayoutValues = value; } - public List Edges { get => edges; set => edges = value; } - public CoseGraph Owner { get => owner; set => owner = value; } - public CoseGraph Child { get => child; set => child = value; } - public bool IsConnected { get => isConnected; set => isConnected = value; } - public ILayoutNode NodeObject { get => nodeObject; set => nodeObject = value; } - public CoseGraphManager GraphManager { get => graphManager; set => graphManager = value; } - public int InclusionTreeDepth { get => inclusionTreeDepth; set => inclusionTreeDepth = value; } - public Vector3 Scale { get => scale; set => scale = value; } - public Vector3 CenterPosition { get => centerPosition; set => centerPosition = value; } - - /// - /// Constructor - /// - /// the original node - /// the graphmanager - public CoseNode(ILayoutNode node, CoseGraphManager graphManager) - { - nodeObject = node; - this.graphManager = graphManager; - } - - /// - /// calculates if this node overlaps with the given node - /// - /// the second node - /// the amount of how much is nodes overlap - /// - public bool CalcOverlap(CoseNode nodeB, double[] overlapAmount) - { - Vector3 center = CenterPosition; - if (center == nodeB.CenterPosition) - { - center = new Vector3(center.x, center.y, center.z + 0.001f); - } - - centerPosition = center; - - Rect rectA = CoseHelper.NewRect(Scale, centerPosition); - Rect rectB = CoseHelper.NewRect(nodeB.Scale, nodeB.CenterPosition); - - if (rectA.Overlaps(rectB)) - { - CoseGeometry.CalcSeparationAmount(rectA, rectB, overlapAmount, CoseLayoutSettings.EdgeLength / 2.0); - return true; - } - else - { - return false; - } - } - - /// - /// calculates the amout of intersection - /// - /// the second node - /// the clip points of the nodes - /// - public double[] CalcIntersection(CoseNode nodeB, double[] clipPoints) - { - Tuple result = CoseGeometry.GetIntersection(CoseHelper.NewRect(scale, centerPosition), CoseHelper.NewRect(nodeB.scale, nodeB.centerPosition), clipPoints); - return result.Item2; - } - - /// - /// Returns a list with this nodes and its children nodes - /// - /// if tue the owner nodes are also added - /// a list with this nodes and its children nodes - public List WithChildren(bool withOwner = true) - { - List withNeighbors = new List(); - - if (withOwner) - { - withNeighbors.Add(this); - } - - if (child != null) - { - foreach (CoseNode childN in child.Nodes) - { - withNeighbors.AddRange(childN.WithChildren()); - } - } - - return withNeighbors; - } - - /// - /// Moves the node according to the forces - /// - public void Move() - { - CoseLayout layout = graphManager.Layout; - double maxNodeDisplacement = layout.CoseLayoutSettings.CoolingFactor * layout.CoseLayoutSettings.MaxNodeDisplacement; - - layoutValues.DisplacementX = layout.CoseLayoutSettings.CoolingFactor * (layoutValues.SpringForceX + layoutValues.RepulsionForceX + layoutValues.GravitationForceX) / noOfChildren; - layoutValues.DisplacementY = layout.CoseLayoutSettings.CoolingFactor * (layoutValues.SpringForceY + layoutValues.RepulsionForceY + layoutValues.GravitationForceY) / noOfChildren; - - if (Math.Abs(layoutValues.DisplacementX) > maxNodeDisplacement) - { - layoutValues.DisplacementX = (float)maxNodeDisplacement * CoseHelper.Sign(layoutValues.DisplacementX); - } - - if (Math.Abs(layoutValues.DisplacementY) > maxNodeDisplacement) - { - layoutValues.DisplacementY = (float)maxNodeDisplacement * CoseHelper.Sign(layoutValues.DisplacementY); - } - - if (child == null && !sublayoutValues.IsSubLayoutNode) - { - MoveBy(layoutValues.DisplacementX, layoutValues.DisplacementY); - } - else if (child.Nodes.Count == 0 && !sublayoutValues.IsSubLayoutNode) - { - MoveBy(layoutValues.DisplacementX, layoutValues.DisplacementY); - } - else - { - if (!sublayoutValues.IsSubLayoutNode && !sublayoutValues.IsSubLayoutRoot) - { - PropogateDisplacementToChildren(layoutValues.DisplacementX, layoutValues.DisplacementY); - } - else - { - if (sublayoutValues.IsSubLayoutRoot) - { - MoveBy(layoutValues.DisplacementX, layoutValues.DisplacementY); - } - } - - } - - layout.CoseLayoutSettings.TotalDisplacement += (decimal)(Math.Abs(layoutValues.DisplacementX) + Math.Abs(layoutValues.DisplacementY)); - } - - /// - /// Propogates the displacement of the sublayout root to the sublayout children - /// - /// the displacement of the x direction - /// the displacement of the y direction - public void PropogateDisplacementToSublayoutChildren(float dx, float dy) - { - MoveBy(dx, dy); - - if (child != null) - { - child.SetXZDisplacementBoundingRect(dx, dy); - - foreach (CoseNode node in child.Nodes) - { - node.PropogateDisplacementToSublayoutChildren(dx, dy); - } - } - } - - /// - /// Propgates the displacement of this node to its children - /// - /// the displacement of the x direction - /// the displacement of the y direction - public void PropogateDisplacementToChildren(float dx, float dy) - { - foreach (CoseNode node in child.Nodes) - { - if (node.Child == null) - { - node.MoveBy(dx, dy); - node.LayoutValues.DisplacementX += dx; - node.LayoutValues.DisplacementY += dy; - } - else - { - node.PropogateDisplacementToChildren(dx, dy); - } - } - } - - /// - /// Changes the position of the nodes according to the given displacement values - /// - /// the displacement of the x direction - /// the displacement of the z direction - public void MoveBy(double dx, double dz) - { - centerPosition.x += (float)dx; - centerPosition.z += (float)dz; - } - - /// - /// Resets the forces that act on this node - /// - public void Reset() - { - layoutValues.SpringForceX = 0; - layoutValues.SpringForceY = 0; - layoutValues.RepulsionForceX = 0; - layoutValues.RepulsionForceY = 0; - layoutValues.GravitationForceX = 0; - layoutValues.GravitationForceY = 0; - layoutValues.DisplacementX = 0; - layoutValues.DisplacementY = 0; - } - - /// - /// Positions the node relative to the given node - /// - /// the node - public void SetPositionRelativ(CoseNode origin) - { - sublayoutValues.SetLocationRelative(sublayoutValues.RelativeCenterPosition.x - origin.centerPosition.x, sublayoutValues.RelativeCenterPosition.z - origin.centerPosition.z); - sublayoutValues.SubLayoutRoot = origin; - } - - /// - /// Sets the position independent to its sublayout root - /// - public void SetOrigin() - { - centerPosition.x = sublayoutValues.RelativeCenterPosition.x + sublayoutValues.SubLayoutRoot.centerPosition.x; - centerPosition.z = sublayoutValues.RelativeCenterPosition.z + sublayoutValues.SubLayoutRoot.centerPosition.z; - SetWidth(sublayoutValues.RelativeScale.x); - SetHeight(sublayoutValues.RelativeScale.z); - } - - /// - /// Set the node to the given position and scale - /// - /// the new position - /// the new scale - public void SetPositionScale(Vector3 position, Vector3 scale) - { - SetWidth(scale.x); - SetHeight(scale.z); - - sublayoutValues.UpdateRelativeBounding(scale: scale, position: position); - UpdateBounding(position: position, scale: scale); - - if (child != null) - { - child.LeftFrontCorner = GetLeftFrontCorner(); - child.RightBackCorner = GetRightBackCorner(); - child.UpdateBounding(); - } - } - - /// - /// Return wheather the node is a leaf node - /// - /// true if the node is a leaf node - public bool IsLeaf() - { - return child == null || child.Nodes.Count == 0; - } - - /// - /// Calculates the number of children - /// - /// the number of children - public int CalcNumberOfChildren() - { - int noOfChildren = 0; - - if (child == null) - { - noOfChildren = 1; - } - else - { - foreach (CoseNode child in child.Nodes) - { - noOfChildren += child.CalcNumberOfChildren(); - } - } - - if (noOfChildren == 0) - { - noOfChildren = 1; - } - - return noOfChildren; - } - - - /// - /// Sets the node to the given center Location - /// - /// x position - /// z position - public void SetLocation(float x, float z) - { - centerPosition.x = x; - centerPosition.z = z; - } - - /// - /// Updates the bounds of this node according to the bounds of its neasted graph - /// - public void UpdateBounds() - { - if (child == null) - { - throw new System.Exception("Child Graph is null"); - } - - if (sublayoutValues.IsSubLayoutRoot) - { - SetWidth(sublayoutValues.RelativeScale.x); - SetHeight(sublayoutValues.RelativeScale.z); - child.UpdateBounds(true); - // rect.x/ rect.y müssen nicht gesetzt werden, da der Knoten seine Größe kennt und nicht abhängig von Child knoten ist - return; - } - - if (sublayoutValues.IsSubLayoutNode) // durch das vorherige return werden die root knoten ausgeschlossen - { - // diese knoten haben relativ positionen zu subLayoutRoot, d.h. diese müssen wieder auf origin gesetzt werden, - // damit das von anderen richtig berechnet werden kann - - // set position to origin by using the relativ values - centerPosition.x = sublayoutValues.RelativeCenterPosition.x + sublayoutValues.SubLayoutRoot.centerPosition.x; - centerPosition.z = sublayoutValues.RelativeCenterPosition.z + sublayoutValues.SubLayoutRoot.centerPosition.z; - SetWidth(sublayoutValues.RelativeScale.x); - SetHeight(sublayoutValues.RelativeScale.z); - child.UpdateBounds(true); - return; - } - - if (child.Nodes.Count != 0) - { - child.UpdateBounds(true); - - centerPosition.x = child.LeftFrontCorner.x + child.Extend.x; - centerPosition.z = child.RightBackCorner.y + child.Extend.z; - - SetWidth(child.Scale.x + CoseLayoutSettings.CompoundNodeMargin + CoseLayoutSettings.CompoundNodeMargin); - SetHeight(child.Scale.z + CoseLayoutSettings.CompoundNodeMargin + CoseLayoutSettings.CompoundNodeMargin); - } - } - - /// - /// Sets the grid start/ end coorinates for this node - /// - /// start x - /// finish x - /// start y - /// finish y - public void SetGridCoordinates(int startX, int finishX, int startY, int finishY) - { - layoutValues.StartX = startX; - layoutValues.FinishX = finishX; - layoutValues.StartY = startY; - layoutValues.FinishY = finishY; - } - - /// - /// Calculates the estimated size of this node - /// - /// - public double CalcEstimatedSize() - { - if (child == null) - { - estimatedSize = (scale.x + scale.z) / 2; - return estimatedSize; - } - else - { - estimatedSize = child.CalcEstimatedSize(); - scale.x = (float)estimatedSize; - scale.z = (float)estimatedSize; - return estimatedSize; - } - } - - /// - /// Returns a list with all neighbour nodes - /// - /// the neighbour nodes - public HashSet GetNeighborsList() - { - HashSet neighbors = new HashSet(); - - foreach (CoseEdge edge in edges) - { - if (edge.Source.Equals(this)) - { - neighbors.Add(edge.Target); - } - else - { - if (!edge.Target.Equals(this)) - { - throw new System.Exception("Incorrect Incidency"); - } - neighbors.Add(edge.Source); - } - } - - return neighbors; - } - - /// - /// updates the bounding rect of the node - /// - /// the center position - /// the scale - public void UpdateBounding(Vector2 position, Vector2 scale) - { - this.scale = scale; - centerPosition = position; - } - - /// - /// Returns the center of x postion - /// - /// center x postion - public float GetCenterX() - { - return centerPosition.x; - } - - /// - /// Returns the center of y postion - /// - /// center y postion - public float GetCenterY() - { - return centerPosition.z; - } - - /// - /// Sets the height of the bouding rect - /// - /// the height - public void SetHeight(double height) - { - scale.z = (float)height; - } - - /// - /// Sets the width of the bouding rect - /// - /// the width - public void SetWidth(double width) - { - scale.x = (float)width; - } - - /// - /// Returns the left postion of the bounding rect - /// - /// the left position - public float GetLeft() - { - return centerPosition.x - Scale.x / 2; - } - - /// - /// Returns the left front corner of this node as a 2D Vector - /// - /// left front corner - public Vector2 GetLeftFrontCorner() - { - Vector2 leftLowerCorner = new Vector2() - { - x = centerPosition.x - Extend.x, - y = centerPosition.z + Extend.z - }; - return leftLowerCorner; - } - - /// - /// Returns the right back corner of this node as a 2D Vector - /// - /// right back corner - public Vector2 GetRightBackCorner() - { - Vector2 rightBackCorner = new Vector2() - { - x = centerPosition.x + Extend.x, - y = centerPosition.z - Extend.z - }; - return rightBackCorner; - } - - /// - /// Returns the right postion of the bounding rect - /// - /// the right position - public float GetRight() - { - return centerPosition.x + Scale.x / 2; - } - - /// - /// Returns the top postion of the bounding rect - /// - /// the top position - public float GetTop() - { - return centerPosition.z - Scale.z / 2; - } - - /// - /// Returns the bottom postion of the bounding rect - /// - /// the bottom position - public float GetBottom() - { - return centerPosition.z + Scale.z / 2; - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs.meta deleted file mode 100644 index 8c3764d1d1..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c973d493541cc714a8316722d34a4e32 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs deleted file mode 100644 index 225ccd434b..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseNodeLayoutValues - { - /// - /// the spring force for the x direction - /// - private float springForceX = 0.0f; - - /// - /// the spring force for the y direction - /// - private float springForceY = 0.0f; - - /// - /// the repulsion force for the x direction - /// - private float repulsionForceX = 0.0f; - - /// - /// the repulsion force for the y direction - /// - private float repulsionForceY = 0.0f; - - /// - /// the gravitation force for the x direction - /// - private float gravitationForceX = 0.0f; - - /// - /// the gravitation force for the y direction - /// - private float gravitationForceY = 0.0f; - - /// - /// the displacement for the x direction - /// - private float displacementX = 0.0f; - - /// - /// the displacement for the y direction - /// - private float displacementY = 0.0f; - - /// - /// The first grid coorinate for the x axis - /// - private int startX = 0; - - /// - /// The first grid coorinate for the y axis - /// - private int startY = 0; - - /// - /// The last grid coorinate for the x axis - /// - private int finishX = 0; - - /// - /// The last grid coorinate for the y axis - /// - private int finishY = 0; - - /// - /// the first predecessor node for the matching (multilevel scaling) - /// - private CoseNode pred1; - - /// - /// the second predecessor node for the matching (multilevel scaling) - /// - private CoseNode pred2; - - /// - /// The next node for the matching (multilevel scaling) - /// - private CoseNode next; - - /// - /// Indicates whether the node was processed in the multilevel scaling process - /// - private bool isProcessed; - - public float SpringForceX { get => springForceX; set => springForceX = value; } - public float SpringForceY { get => springForceY; set => springForceY = value; } - public float RepulsionForceX { get => repulsionForceX; set => repulsionForceX = value; } - public float RepulsionForceY { get => repulsionForceY; set => repulsionForceY = value; } - public float GravitationForceX { get => gravitationForceX; set => gravitationForceX = value; } - public float GravitationForceY { get => gravitationForceY; set => gravitationForceY = value; } - public float DisplacementX { get => displacementX; set => displacementX = value; } - public float DisplacementY { get => displacementY; set => displacementY = value; } - public int StartX { get => startX; set => startX = value; } - public int StartY { get => startY; set => startY = value; } - public int FinishX { get => finishX; set => finishX = value; } - public int FinishY { get => finishY; set => finishY = value; } - public CoseNode Pred1 { get => pred1; set => pred1 = value; } - public CoseNode Pred2 { get => pred2; set => pred2 = value; } - public CoseNode Next { get => next; set => next = value; } - public bool IsProcessed { get => isProcessed; set => isProcessed = value; } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs.meta deleted file mode 100644 index 7a5798a4f9..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeLayoutValues.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7591af180734970418b7b1bd38fe0cbd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs deleted file mode 100644 index af7657c438..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - public class CoseNodeSublayoutValues - { - /// - /// the scale of the calculated sublayout. If the node layout is not enclosing all its childnodes, - /// the position and scale of the root node will be adaped. - /// - private Vector3 relativeScale; - - /// - /// the centerposition of the calculated sublayout. If the node layout is not enclosing all - /// its childnodes, the position and scale of the root node will be adaped. - /// - private Vector3 relativeCenterPosition; - - /// - /// Indicates whether the node is a sublayout root - /// - private bool isSubLayoutRoot = false; - - /// - /// Indicates whether the node is a sublayout node - /// - private bool isSubLayoutNode = false; - - /// - /// The root node of the sublayout the node is part of - /// - private CoseNode subLayoutRoot = null; - - /// - /// is the node is sublayoutRoot, the sublayout if this node - /// - private Sublayout sublayout; - - public bool IsSubLayoutRoot { get => isSubLayoutRoot; set => isSubLayoutRoot = value; } - public bool IsSubLayoutNode { get => isSubLayoutNode; set => isSubLayoutNode = value; } - public CoseNode SubLayoutRoot { get => subLayoutRoot; set => subLayoutRoot = value; } - public Sublayout Sublayout { get => sublayout; set => sublayout = value; } - public Vector3 RelativeScale { get => relativeScale; set => relativeScale = value; } - public Vector3 RelativeCenterPosition { get => relativeCenterPosition; set => relativeCenterPosition = value; } - - /// - /// Set the given x/ z position the the relative centerPosition - /// - /// x value - /// z value - public void SetLocationRelative(float x, float z) - { - relativeCenterPosition.x = x; - relativeCenterPosition.z = z; - } - - /// - /// updates the relative bounding rect - /// - /// the scale - /// the centerPosition - public void UpdateRelativeBounding(Vector3 scale, Vector3 position) - { - relativeScale = scale; - relativeCenterPosition = position; - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs.meta deleted file mode 100644 index 3b42a0d0db..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/CoseNodeSublayoutValues.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7ca3c304d9d894b408b9281a09f41fb1 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs deleted file mode 100644 index b7ce61313a..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System.Collections.Generic; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// ILayoutNode for the caluclation of the sublayouts - /// - public class LayoutSublayoutNode : ILayoutNode - { - /// - /// the scale - /// - public Vector3 LocalScale { get => node.LocalScale; set => node.LocalScale = value; } - - /// - /// the center position - /// - public Vector3 CenterPosition { get => node.CenterPosition; set => node.CenterPosition = value; } - - /// - /// the rotation - /// - public float Rotation { get => node.Rotation; set => node.Rotation = value; } - - /// - /// the level - /// - public int Level { get => node.Level; set => node.Level = value; } - - /// - /// the id - /// - public string ID => node.ID; - - /// - /// roof vector - /// - public Vector3 Roof => node.Roof; - - /// - /// ground vector - /// - public Vector3 Ground => node.Ground; - - /// - /// collection of successor nodes - /// - public ICollection Successors => GetSuccessors(); - - /// - /// the parent node - /// - public ILayoutNode Parent => GetParent(); - - /// - /// true if node is a leaf node - /// - public bool IsLeaf => isLeaf; - - /// - /// Returns all Children of a node - /// - /// - public ICollection Children() - { - return GetChildren(); - } - - /// - /// the underlying ILayoutNode - /// - public ILayoutNode Node => node; - - /// - /// the relative position of this node to its sublayout root - /// - public Vector3 RelativePosition { get; set; } - - /// - /// true if node is a sublayout node - /// - public bool IsSublayoutNode { get => false; set => value = false; } - - /// - /// the if node is a sublayout root node - /// - public bool IsSublayoutRoot { get => false; set => value = false; } - - /// - /// the sublayout of this node - /// - public Sublayout Sublayout { get; set; } - - /// - /// if node is a sublayoutNode this property holds the sublayout root node - /// - public ILayoutNode SublayoutRoot { get; set; } - - public Vector3 AbsoluteScale => throw new System.NotImplementedException(); - - /// - /// the child nodes - /// - private ICollection children; - - /// - /// true if node is a leaf node - /// - private readonly bool isLeaf; - - /// - /// the underlying iLayoutnode - /// - private readonly ILayoutNode node; - - /// - /// the parent node - /// - private ILayoutNode parent; - - /// - /// the successor nodes - /// - private ICollection successors; - - /// - /// holding the child nodes temporary - /// - private readonly ICollection temporaryChildren; - - /// - /// holding the parent node temporary - /// - private readonly ILayoutNode temporaryParent; - - /// - /// a dictinary holding a mapping from the underlying IlayoutNode to a CoseSublayoutNode - /// - private readonly Dictionary iLayoutToCoseSublayoutNode; - - public LayoutSublayoutNode(ILayoutNode node, ICollection children, bool isLeaf, ILayoutNode parent, Vector3 localScale, Dictionary iLayoutToCoseSublayoutNode) - { - this.node = node; - this.isLeaf = isLeaf; - temporaryChildren = children; - temporaryParent = parent; - node.LocalScale = localScale; - this.iLayoutToCoseSublayoutNode = iLayoutToCoseSublayoutNode; - iLayoutToCoseSublayoutNode[node] = this; - } - - public LayoutSublayoutNode(ILayoutNode node, Dictionary iLayoutToCoseSublayoutNode) - { - this.node = node; - isLeaf = node.IsLeaf; - temporaryChildren = node.Children(); - temporaryParent = node.Parent; - node.LocalScale = node.LocalScale; - this.iLayoutToCoseSublayoutNode = iLayoutToCoseSublayoutNode; - iLayoutToCoseSublayoutNode[node] = this; - } - - private ILayoutNode GetParent() - { - if (parent == null && temporaryParent != null) - { - if (iLayoutToCoseSublayoutNode.ContainsKey(temporaryParent)) - { - parent = iLayoutToCoseSublayoutNode[temporaryParent]; - } - } - return parent; - } - - private ICollection GetSuccessors() - { - if (successors == null) - { - ICollection succesorsCollection = new List(); - foreach (ILayoutNode successor in node.Successors) - { - if (iLayoutToCoseSublayoutNode.ContainsKey(successor)) - { - succesorsCollection.Add(iLayoutToCoseSublayoutNode[successor]); - } - } - successors = succesorsCollection; - } - return successors; - } - - private ICollection GetChildren() - { - if (children == null) - { - List childrenList = new List(); - - foreach (ILayoutNode child in temporaryChildren) - { - if (iLayoutToCoseSublayoutNode.ContainsKey(child)) - { - childrenList.Add(iLayoutToCoseSublayoutNode[child]); - } - } - children = childrenList; - } - return children; - } - - public void SetOrigin() - { - throw new System.NotImplementedException(); - } - - public void SetRelative(ILayoutNode node) - { - throw new System.NotImplementedException(); - } - - public void ScaleBy(float factor) - { - throw new System.NotImplementedException(); - } - } -} - diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs.meta deleted file mode 100644 index 8fa466268c..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/LayoutSublayoutNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d6746e95235bc734fb45486608813235 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/License.txt b/Assets/SEE/Layout/NodeLayouts/Cose/License.txt deleted file mode 100644 index 131610a226..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/License.txt +++ /dev/null @@ -1,16 +0,0 @@ -MIT License - -Copyright (c) 2019 iVis-at-Bilkent - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE -OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs b/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs deleted file mode 100644 index a239c38241..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs +++ /dev/null @@ -1,608 +0,0 @@ -using SEE.DataModel.DG; -using SEE.Layout.Utils; -using SEE.Utils; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// FIXME: This should be moved to a more specific namespace. - /// - public class EdgesMeasurements - { - /// - /// The maximum length of an edge - /// - public readonly float LengthMax; - - /// - /// The minimum length of an edge - /// - public readonly float LengthMin; - - /// - /// The total length of all edges - /// - public readonly float LengthTotal; - - /// - /// The maximum length of an edge in relation to the area (height + width / 2) - /// - public readonly float LengthMaxArea; - - /// - /// The minimum length of an edge in relation to the area (height + width / 2) - /// - public readonly float LengthMinArea; - - /// - /// The total length of all edges in relation to the area (height + width / 2) - /// - public readonly float LengthTotalArea; - - /// - /// The average length of an edge - /// - public readonly float LengthAverage; - - /// - /// The average length of an edge in relation to the area (height + width / 2) - /// - public readonly float LengthAverageArea; - - /// - /// The variance length of any edge - /// - public readonly float LengthVariance; - - /// - /// The standart deviation of any edge length - /// - public readonly float LengthStandardDeviation; - - /// - /// The variance length of any edge in relation to the area (height + width / 2) - /// - public readonly float LengthVarianceArea; - - /// - /// The standart deviation of any edge length in relation to the area (height + width / 2) - /// - public readonly float LengthStandardDeviationArea; - - /// - /// class holding all measurements value of the edges - /// - /// the length of the longest edge - /// the length of the shortest edge - /// the total length of all edges - /// the length of the longest edge in relation to the area - /// The minimum length of an edge in relation to the area (height + width / 2) - /// The total length of all edges in relation to the area (height + width / 2) - /// The average length of an edge - /// The variance length of any edge - /// The variance length of any edge in relation to the area (height + width / 2) - /// The average length of an edge in relation to the area (height + width / 2) - /// The standart deviation of any edge length in relation to the area (height + width / 2) - /// The variance length of any edge in relation to the area (height + width / 2) - public EdgesMeasurements(float lengthMax, float lengthMin, float lengthTotal, float lengthMaxArea, float lengthMinArea, float lengthTotalArea, float lengthAverage, float lengthAverageArea, float lengthVariance, float lengthStandardDeviation, float lengthVarianceArea, float lengthStandardDeviationArea) - { - this.LengthMax = lengthMax; - this.LengthMin = lengthMin; - this.LengthTotal = lengthTotal; - this.LengthMaxArea = lengthMaxArea; - this.LengthMinArea = lengthMinArea; - this.LengthTotalArea = lengthTotalArea; - this.LengthAverage = lengthAverage; - this.LengthAverageArea = lengthAverageArea; - this.LengthVariance = lengthVariance; - this.LengthStandardDeviation = lengthStandardDeviation; - this.LengthVarianceArea = lengthVarianceArea; - this.LengthStandardDeviationArea = lengthStandardDeviationArea; - } - } - - public class Measurements - { - /// - /// all edges - /// - private readonly IList edges; - - /// - /// width of this graph visualisation - /// - private readonly float width = 0.0f; - - /// - /// height of this graph visualisation - /// - private readonly float height = 0.0f; - - /// - /// Dictonary with nodes and corresonding gameobjects - /// - private readonly ICollection layoutNodes; - - /// - /// a dictionary containing all measurements with the according values - /// - private SortedDictionary measurementsDict = new(); - - /// - /// the performance of the layout of the nodes - /// - private readonly Performance nodePerformance = null; - - public EdgesMeasurements EdgesMeasurements - { - get => MeasurementsEdges(); - } - - public int OverlappingGameNodes - { - get => CalcOverlappingGameNodes(); - } - - public float Area - { - get => MeasurementsArea(); - } - - public int EdgeCrossings - { - get => MeasureEdgeCrossing(); - } - - public string NodesPerformance - { - get => GetNodesPerformance(); - } - - public double NodePerformanceInMilliSeconds - { - get => GetNodePerformanceInMilliseconds(); - } - - /// - /// The constructor which will also always calculate the length of the edges. - /// - /// the graph displayed by the layout - /// 2D co-ordinate of the left front corner - /// 2D co-ordinate of the right back corner - /// the layoutNodes - /// nodes performance - public Measurements(ICollection layoutNodes, Graph graph, - Vector2 leftFrontCorner, Vector2 rightBackCorner, - Performance performance = null) - { - width = Distance(leftFrontCorner.x, rightBackCorner.x); - height = Distance(leftFrontCorner.y, rightBackCorner.y); - this.layoutNodes = new List(layoutNodes); - edges = graph.ConnectingEdges(layoutNodes); - nodePerformance = performance; - EdgeDistCalculation(graph, layoutNodes); - } - - /// - /// constructor - /// - /// the layout nodes - /// edges - public Measurements(ICollection layoutNodes, List edges) - { - this.layoutNodes = new List(layoutNodes); - this.edges = edges; - } - - private Dictionary edgeLengths; - - /// - /// Calculates the distance for each edge - /// - /// the layoutnodes - /// the graph - private void EdgeDistCalculation(Graph graph, ICollection layoutNodes) - { - edgeLengths = new Dictionary(); - foreach (Edge edge in graph.Edges()) - { - Vector3 sourcePosition = layoutNodes.Where(node => node.ID == edge.Source.ID).First().CenterPosition; - Vector3 targetPosition = layoutNodes.Where(node => node.ID == edge.Target.ID).First().CenterPosition; - edgeLengths[edge] = Vector3.Distance(sourcePosition, targetPosition); - } - } - - /// - /// Gets the time needed for calculating the node layout to the measurements - /// - public string GetNodesPerformance() - { - if (nodePerformance != null) - { - return nodePerformance.GetElapsedTime(); - } - return ""; - } - - /// - /// Gets the time needed gfor the calculation of the node layout - /// - /// time in milliseconds - public double GetNodePerformanceInMilliseconds() - { - if (nodePerformance != null) - { - return nodePerformance.GetTimeInMilliSeconds(); - } - return 0.0; - } - - /// - /// Transforms all measurements to a string dictinary containing the measurements with it values - /// - /// string dictinary with measurements - public SortedDictionary ToStringDictionary(bool calcualteNew = false) - { - if (!calcualteNew && measurementsDict.Count > 0) - { - return measurementsDict; - } - - EdgesMeasurements edgeMeasure = EdgesMeasurements; - SortedDictionary measurements = new SortedDictionary - { - { "Area", Math.Round (Area, 2).ToString() }, - { "Nodes overlapping", OverlappingGameNodes.ToString() }, - { "Number of edge crossings", EdgeCrossings.ToString() }, - { "Straight Edge length max", Math.Round(edgeMeasure.LengthMax, 2).ToString() }, - { "Straight Edge length min", Math.Round(edgeMeasure.LengthMin, 2).ToString() }, - { "Straight Edge length total", Math.Round(edgeMeasure.LengthTotal, 2).ToString() }, - { "Straight Edge length max (area)", Math.Round(edgeMeasure.LengthMaxArea, 2).ToString() }, - { "Straight Edge length min (area)", Math.Round(edgeMeasure.LengthMinArea, 2).ToString() }, - { "Straight Edge length total (area)", Math.Round(edgeMeasure.LengthTotalArea, 2).ToString() }, - { "Straight Edge length average", Math.Round(edgeMeasure.LengthAverage, 2).ToString() }, - { "Straight Edge length average (area)", Math.Round(edgeMeasure.LengthAverageArea, 2).ToString() }, - { "Straight Edge length variance", Math.Round(edgeMeasure.LengthVariance, 2).ToString() }, - { "Straight Edge length standard deviation", Math.Round(edgeMeasure.LengthStandardDeviation, 2).ToString() }, - { "Straight Edge length variance (area)", Math.Round(edgeMeasure.LengthVarianceArea, 2).ToString() }, - { "Straight Edge length standard deviation (area)", Math.Round(edgeMeasure.LengthStandardDeviationArea, 2).ToString() }, - }; - - string nodePerformance = NodesPerformance; - if (nodePerformance.Length > 0) - { - measurements.Add("Time for node layout", nodePerformance); - } - - measurementsDict = measurements; - return measurementsDict; - } - - /// - /// Measures the number of edge crossings - /// - private int MeasureEdgeCrossing() - { - List edgesToIterate = new List(); - edgesToIterate.AddRange(edges); - int totalCrossings = 0; - - foreach (Edge edge in edges) - { - edgesToIterate.Remove(edge); - - foreach (Edge edge2 in edgesToIterate) - { - - Vector3 sourcePosition = CoseHelper.GetLayoutNodeFromLinkname(edge.Source.ID, layoutNodes).CenterPosition; - Vector3 targetPosition = CoseHelper.GetLayoutNodeFromLinkname(edge.Target.ID, layoutNodes).CenterPosition; - Vector3 sourcePosition2 = CoseHelper.GetLayoutNodeFromLinkname(edge2.Source.ID, layoutNodes).CenterPosition; - Vector3 targetPosition2 = CoseHelper.GetLayoutNodeFromLinkname(edge2.Target.ID, layoutNodes).CenterPosition; - bool doIntersect = FasterLineSegmentIntersection(new Vector2(sourcePosition.x, sourcePosition.z), - new Vector2(targetPosition.x, targetPosition.z), - new Vector2(sourcePosition2.x, sourcePosition2.z), - new Vector2(targetPosition2.x, targetPosition2.z), false); - if (doIntersect) - { - totalCrossings++; - } - } - } - return totalCrossings; - } - - /// - /// Calculates whether two lines intersect. - /// Algorithm: https://www.habrador.com/tutorials/math/5-line-line-intersection/ - /// http://inis.jinr.ru/sl/vol1/CMC/Graphics_Gems_3,ed_D.Kirk.pdf - /// https://forum.unity.com/threads/line-intersection.17384/ - /// - /// 2D coordinate of start position of line 1 - /// 2D coordinate of end position of line 1 - /// 2D coordinate of start position of line 2 - /// 2D coordinate of end position of line 2 - /// - /// true if the lines intersect - private static bool FasterLineSegmentIntersection(Vector2 l1P1, Vector2 l1P2, Vector2 l2P1, Vector2 l2P2, bool shouldIncludeEndPoints) - { - //To avoid floating point precision issues we can add a small value - - float epsilon = 0.00001f; - - bool isIntersecting = false; - - float denominator = (l2P2.y - l2P1.y) * (l1P2.x - l1P1.x) - (l2P2.x - l2P1.x) * (l1P2.y - l1P1.y); - - //Make sure the denominator is > 0, if not the lines are parallel - if (denominator != 0f) - { - float uA = ((l2P2.x - l2P1.x) * (l1P1.y - l2P1.y) - (l2P2.y - l2P1.y) * (l1P1.x - l2P1.x)) / denominator; - float uB = ((l1P2.x - l1P1.x) * (l1P1.y - l2P1.y) - (l1P2.y - l1P1.y) * (l1P1.x - l2P1.x)) / denominator; - - //Are the line segments intersecting if the end points are the same - if (shouldIncludeEndPoints) - { - //Is intersecting if u_a and u_b are between 0 and 1 or exactly 0 or 1 - if (uA >= 0f + epsilon && uA <= 1f - epsilon && uB >= 0f + epsilon && uB <= 1f - epsilon) - { - isIntersecting = true; - } - } - else - { - //Is intersecting if u_a and u_b are between 0 and 1 - if (uA > 0f + epsilon && uA < 1f - epsilon && uB > 0f + epsilon && uB < 1f - epsilon) - { - isIntersecting = true; - } - } - } - - return isIntersecting; - } - - /// - /// calculates measurements for edges, e.g. maximal edge length - /// - private EdgesMeasurements MeasurementsEdges() - { - float minDistEdge = 0; - float maxDistEdge = 0; - float totalDist = 0; - float relationMinDistEdge; - float relationMaxDistEdge; - float relationTotalDist; - float relationAvgDist; - float averageDistEdge = 0; - float varianceDistEdge = 0; - float relativeVarianceDistEdge = 0; - float standardDeviation; - float relativeStandardDeviation; - - if (edges.Count > 0) - { - minDistEdge = edgeLengths[edges[0]]; - maxDistEdge = edgeLengths[edges[0]]; - } - - foreach (Edge edge in edges) - { - float length = edgeLengths[edge]; - totalDist += length; - - if (length < minDistEdge) - { - minDistEdge = length; - } - - if (length > maxDistEdge) - { - maxDistEdge = length; - } - } - - float areaLength = (height + width) / 2; - relationMaxDistEdge = maxDistEdge / areaLength; - relationMinDistEdge = minDistEdge / areaLength; - relationTotalDist = totalDist / areaLength; - - if (edges.Count > 0) - { - averageDistEdge = totalDist / edges.Count; - float variance = 0f; - - foreach (Edge edge in edges) - { - float length = edgeLengths[edge]; - variance += (length - averageDistEdge) * (length - averageDistEdge); - } - if (edges.Count == 1) - { - varianceDistEdge = 0; - } - else - { - varianceDistEdge = variance / (edges.Count - 1); - } - } - standardDeviation = Mathf.Sqrt(varianceDistEdge); - - relationAvgDist = averageDistEdge / areaLength; - if (edges.Count > 0) - { - float varianceRelative = 0f; - - foreach (Edge edge in edges) - { - float edgeDistRelative = edgeLengths[edge] / areaLength; - varianceRelative += (edgeDistRelative - relationAvgDist) * (edgeDistRelative - relationAvgDist); - } - if (edges.Count == 1) - { - relativeVarianceDistEdge = 0; - } - else - { - relativeVarianceDistEdge = varianceRelative / (edges.Count - 1); - } - } - relativeStandardDeviation = Mathf.Sqrt(relativeVarianceDistEdge); - - return new EdgesMeasurements(lengthMax: maxDistEdge, - lengthMin: minDistEdge, - lengthTotal: totalDist, - lengthMaxArea: relationMaxDistEdge, - lengthMinArea: relationMinDistEdge, - lengthTotalArea: relationTotalDist, - lengthAverage: averageDistEdge, - lengthAverageArea: relationAvgDist, - lengthVariance: varianceDistEdge, - lengthStandardDeviation: standardDeviation, - lengthVarianceArea: relativeVarianceDistEdge, - lengthStandardDeviationArea: relativeStandardDeviation); - } - - /// - /// calculates measurement for the area - /// - private float MeasurementsArea() - { - return height * width; - } - - /// - /// calcuates the distance between 2 points - /// - /// 2d coordinate - /// 2d coordinate - /// the distance - private static float Distance(float v0, float v1) - { - if (v1 <= v0) - { - Debug.AssertFormat(v1 > v0, "v1 > v0 expected. Actual v0 = {0}, v1 = {1}.\n", v0, v1); - throw new Exception("v1 > v0 expected"); - } - else - { - if (v0 < 0.0f) - { - return v1 + Math.Abs(v0); - } - else - { - return v1 - v0; - } - } - } - - /// - /// Returns the amount of overlapping of nodes - /// - /// the overlapping amount - private int CalcOverlappingGameNodes() - { - int overlapAmount = 0; - - List nodesToIterate = new List(); - nodesToIterate.AddRange(layoutNodes); - - foreach (ILayoutNode node in layoutNodes) - { - nodesToIterate.Remove(node); - - foreach (ILayoutNode node2 in nodesToIterate) - { - bool doOverlap = CheckOverlapping(node, node2); - bool inSameHierarchie = CheckIfInHierarchie(node, node2); - if (CheckOverlapping(node, node2) && !CheckIfInHierarchie(node, node2)) - { - overlapAmount++; - } - } - } - - return overlapAmount; - } - - /// - /// checks wheather two nodes are in the same inclusion tree branch - /// - /// first node - /// second node - /// - private bool CheckIfInHierarchie(ILayoutNode node1, ILayoutNode node2) - { - if (node1.Level == node2.Level || node1.Equals(node2)) - { - return false; - } - - ILayoutNode startNode = node1.Level <= node2.Level ? node1 : node2; - ILayoutNode childNode = node1.Level <= node2.Level ? node2 : node1; - - return CheckIfChild(startNode.Children(), childNode); - } - - /// - /// checks if a node is a children of a list of nodes - /// - /// list of nodes - /// the node - /// - private bool CheckIfChild(ICollection children, ILayoutNode node2) - { - foreach (ILayoutNode childNode in children) - { - if (childNode.Equals(node2)) - { - return true; - } - else - { - if (CheckIfChild(childNode.Children(), node2)) - { - return true; - } - } - } - - return false; - } - - /// - /// checks if two nodes overlap - /// - /// the first node - /// the second node - /// - private static bool CheckOverlapping(ILayoutNode node1, ILayoutNode node2) - { - Bounds bounds1 = new Bounds(node1.CenterPosition, node1.LocalScale); - Bounds bounds2 = new Bounds(node2.CenterPosition, node2.LocalScale); - - bool intersect = IntersectBounds(bounds1, bounds2); - - return intersect; - } - - /// - /// checks if two bounds intersect - /// - /// the first bound - /// the second bound - /// - private static bool IntersectBounds(Bounds bounds1, Bounds bounds2) - { - return !(bounds2.min.x > bounds1.max.x || - bounds2.max.x < bounds1.min.x || - bounds2.min.z > bounds1.max.z || - bounds2.max.z < bounds1.min.z); - - } - } -} \ No newline at end of file diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs.meta deleted file mode 100644 index 0ca169d78c..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/Measurements.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5611edeb8b5367942850cfe45a5bbbfb -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs deleted file mode 100644 index d576373d67..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using SEE.Game.City; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// A class for holding properties for a sublayout - /// - public class SublayoutLayoutNode : AbstractSublayoutNode - { - /// - /// constructor - /// - /// the root node - /// to inner node kind - /// the nodelayout of this sublayout - public SublayoutLayoutNode(ILayoutNode node, NodeShapes innerNodeKinds, NodeLayoutKind nodeLayouts) : base(node, innerNodeKinds, nodeLayouts) - { - node.IsSublayoutRoot = true; - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs.meta deleted file mode 100644 index 23d046bdf2..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutLayoutNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 172aee806d5a9f7489366795ef36e97c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs b/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs deleted file mode 100644 index a500d2af74..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using SEE.DataModel.DG; -using SEE.Game.City; - -namespace SEE.Layout.NodeLayouts.Cose -{ - /// - /// A class for holding properties for a sublayout - /// - public class SublayoutNode : AbstractSublayoutNode - { - /// - /// constructor - /// - /// the root node - /// to inner node kind - /// the nodelayout of this sublayout - public SublayoutNode(Node node, NodeShapes innerNodeKinds, NodeLayoutKind nodeLayouts) : base(node, innerNodeKinds, nodeLayouts) - { - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs.meta b/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs.meta deleted file mode 100644 index abdc1bb9d3..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/Cose/SublayoutNode.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 75f4cd9729c32464b8be4b1dea575062 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/EvoStreets/ENode.cs b/Assets/SEE/Layout/NodeLayouts/EvoStreets/ENode.cs index 59cd851558..738993a03e 100644 --- a/Assets/SEE/Layout/NodeLayouts/EvoStreets/ENode.cs +++ b/Assets/SEE/Layout/NodeLayouts/EvoStreets/ENode.cs @@ -107,7 +107,7 @@ internal struct Rectangle /// The rectangle as a human-readable string. /// /// rectangle as a human-readable string - public override string ToString() + public override readonly string ToString() { return $"[center={Center}, width={Width:F4}, depth={Depth:F4}]"; } @@ -208,10 +208,9 @@ public float Length(Orientation orientation) /// /// Adds the layout information of this to the . /// - /// the y co-ordinate of the ground of this node to be added to /// layout where to add the layout information /// the height of an inner node (depicted as street) - public abstract void ToLayout(ref Dictionary layoutResult, float groundLevel, float streetHeight); + public abstract void ToLayout(ref Dictionary layoutResult, float streetHeight); /// /// Prints this node with an indentation proportional to its . Can be used for debugging. @@ -298,12 +297,11 @@ public override void SetLocation(Orientation orientation, Location centerLocatio /// Adds the layout information of this to the . /// . /// - /// the y co-ordinate of the ground of this node to be added to /// layout where to add the layout information /// will be ignored - public override void ToLayout(ref Dictionary layoutResult, float groundLevel, float streetHeight) + public override void ToLayout(ref Dictionary layoutResult, float streetHeight) { - layoutResult[GraphNode] = new NodeTransform(new Vector3(Rectangle.Center.X, groundLevel, Rectangle.Center.Y), + layoutResult[GraphNode] = new NodeTransform(Rectangle.Center.X, Rectangle.Center.Y, new Vector3 (Rectangle.Width, GraphNode.AbsoluteScale.y, Rectangle.Depth), 0); } @@ -347,7 +345,7 @@ public override void Print() /// /// The children of this inner node in the hierarchy. /// - private readonly List children = new List(); + private readonly List children = new(); /// /// This is the rectangle for the street itself representing the inner node. @@ -562,18 +560,17 @@ public override void SetLocation(Orientation orientation, Location centerLocatio /// node. The attribute is just the area enclosing this street and all /// representations of the descendants of this node. /// - /// the y co-ordinate of the ground of this node to be added to /// layout where to add the layout information /// the height of an inner node (depicted as street) - public override void ToLayout(ref Dictionary layoutResult, float groundLevel, float streetHeight) + public override void ToLayout(ref Dictionary layoutResult, float streetHeight) { layoutResult[GraphNode] - = new NodeTransform(new Vector3(street.Center.X, groundLevel, street.Center.Y), + = new NodeTransform(street.Center.X, street.Center.Y, new Vector3(street.Width, streetHeight, street.Depth), 0); foreach (ENode child in children) { - child.ToLayout(ref layoutResult, groundLevel, streetHeight); + child.ToLayout(ref layoutResult, streetHeight); } } } diff --git a/Assets/SEE/Layout/NodeLayouts/EvoStreetsNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/EvoStreetsNodeLayout.cs index 6d646a2a1a..3a78b51112 100644 --- a/Assets/SEE/Layout/NodeLayouts/EvoStreetsNodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/EvoStreetsNodeLayout.cs @@ -1,22 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; using SEE.Layout.NodeLayouts.EvoStreets; using UnityEngine; namespace SEE.Layout.NodeLayouts { - public class EvoStreetsNodeLayout : HierarchicalNodeLayout + /// + /// Lays out nodes in a tree hierarchy in a street-like manner (EvoStreets + /// according to Frank Steinbrückner). + /// + public class EvoStreetsNodeLayout : NodeLayout { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public EvoStreetsNodeLayout(float groundLevel) - : base(groundLevel) + static EvoStreetsNodeLayout() { Name = "EvoStreets"; } @@ -40,20 +36,28 @@ public EvoStreetsNodeLayout(float groundLevel) /// private readonly float streetHeight = 0.0001f; - public override Dictionary Layout(IEnumerable gameNodes) + /// + /// See . + /// + /// thrown if there is no or more than one root in + /// + protected override Dictionary Layout + (IEnumerable gameNodes, + Vector3 centerPosition, + Vector2 rectangle) { IList layoutNodes = gameNodes.ToList(); if (layoutNodes.Count == 0) { - throw new Exception("No nodes to be laid out."); + return new Dictionary(); } if (layoutNodes.Count == 1) { ILayoutNode singleNode = layoutNodes.First(); - Dictionary layoutResult = new Dictionary + Dictionary layoutResult = new() { - [singleNode] = new NodeTransform(Vector3.zero, singleNode.LocalScale) + [singleNode] = new NodeTransform(0, 0, singleNode.AbsoluteScale) }; return layoutResult; } @@ -80,8 +84,8 @@ public override Dictionary Layout(IEnumerable layoutResult = new Dictionary(); - rootNode.ToLayout(ref layoutResult, GroundLevel, streetHeight); + Dictionary layoutResult = new(); + rootNode.ToLayout(ref layoutResult, streetHeight); return layoutResult; } } @@ -129,16 +133,5 @@ private static ENode GenerateHierarchy(ILayoutNode root, int depth = 0) } return result; } - - public override Dictionary Layout(ICollection layoutNodes, ICollection edges, - ICollection sublayouts) - { - throw new NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } -} \ No newline at end of file +} diff --git a/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs deleted file mode 100644 index 7453b39a58..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace SEE.Layout.NodeLayouts -{ - /// - /// The abstract super class of all non-hierarchical (flat) node layouts. - /// - public abstract class FlatNodeLayout : NodeLayout - { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public FlatNodeLayout(float groundLevel) - : base(groundLevel) - { - } - - /// - /// Always false because non-hierarchical layouts can handle only leaves. - /// - /// always false - public override bool IsHierarchical() - { - return false; - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs.meta b/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs.meta deleted file mode 100644 index bcffae18df..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/FlatNodeLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8b085be28ad87fc4081c2d477ea44f39 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs deleted file mode 100644 index f9459a332b..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections.Generic; - -namespace SEE.Layout.NodeLayouts -{ - /// - /// The abstract super class of all hierarchical node layouts. - /// - public abstract class HierarchicalNodeLayout : NodeLayout - { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public HierarchicalNodeLayout(float groundLevel) - : base(groundLevel) - { - } - - /// - /// Always true because hierarchical layouts can handle both inner nodes and leaves. - /// - /// always true - public override bool IsHierarchical() - { - return true; - } - - /// - /// The roots of the subtrees of the original graph that are to be laid out. - /// A node is considered a root if it has either no parent in the original - /// graph or its parent is not contained in the set of nodes to be laid out. - /// - protected IList Roots; - - /// - /// Returns the maximal depth of the forest with the given root nodes. - /// If roots.Count == 0, 0 is the maximal depth. If there is at least - /// one root, the minimum value of the maximal depth is 1. - /// - /// set of root tree nodes of the forest - /// maximal depth of the forest - protected static int MaxDepth(List roots) - { - int result = 0; - foreach (ILayoutNode root in roots) - { - int depth = MaxDepth(root); - if (depth > result) - { - result = depth; - } - } - return result; - } - - /// - /// Returns the maximal depth of the tree rooted by given node. The depth of - /// a tree with only one node is 1. - /// - /// root node of the tree - /// maximal depth of the tree - protected static int MaxDepth(ILayoutNode node) - { - int result = 0; - foreach (ILayoutNode child in node.Children()) - { - int depth = MaxDepth(child); - if (depth > result) - { - result = depth; - } - } - return result + 1; - } - } -} diff --git a/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs.meta b/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs.meta deleted file mode 100644 index eda0880090..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/HierarchicalNodeLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e69bc58071bdb2042bd9eae237a5a19f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/IncrementalTreeMapLayout.cs b/Assets/SEE/Layout/NodeLayouts/IncrementalTreeMapLayout.cs index 8f12922c01..7f2241dcd3 100644 --- a/Assets/SEE/Layout/NodeLayouts/IncrementalTreeMapLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/IncrementalTreeMapLayout.cs @@ -1,5 +1,3 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; using SEE.Layout.NodeLayouts.IncrementalTreeMap; using System; using System.Collections.Generic; @@ -17,42 +15,27 @@ namespace SEE.Layout.NodeLayouts /// that can guarantee stability in the layouts over the series of graphs in the evolution /// while not neglecting the aspect of visual quality either. /// - public class IncrementalTreeMapLayout : HierarchicalNodeLayout, IIncrementalNodeLayout + public class IncrementalTreeMapLayout : NodeLayout, IIncrementalNodeLayout { /// /// Constructor. /// - /// the y co-ordinate setting the ground level - /// width of the rectangle in which to place all nodes in Unity units - /// width of the rectangle in which to place all nodes in Unity units /// the settings for the layout - public IncrementalTreeMapLayout(float groundLevel, - float width, - float depth, - IncrementalTreeMapAttributes settings) - : base(groundLevel) + public IncrementalTreeMapLayout(IncrementalTreeMapAttributes settings) { - Name = "IncrementalTreeMap"; - this.width = width; - this.depth = depth; this.settings = settings; } + static IncrementalTreeMapLayout() + { + Name = "IncrementalTreeMap"; + } + /// /// The adjustable parameters for the layout. /// private readonly IncrementalTreeMapAttributes settings; - /// - /// The width of the rectangle in which to place all nodes in Unity units. - /// - private readonly float width; - - /// - /// The depth of the rectangle in which to place all nodes in Unity units. - /// - private readonly float depth; - /// /// The node layout we compute as a result. /// @@ -84,17 +67,21 @@ public IIncrementalNodeLayout OldLayout { if (value is IncrementalTreeMapLayout layout) { - this.oldLayout = layout; + oldLayout = layout; } else { throw new ArgumentException( - "Predecessor of IncrementalTreeMapLayout was not a IncrementalTreeMapLayout."); + $"Predecessor of {nameof(IncrementalTreeMapLayout)} was not an {nameof(IncrementalTreeMapLayout)}."); } } } - public override Dictionary Layout(IEnumerable layoutNodes) + /// + /// See . + /// + /// thrown if is empty. + protected override Dictionary Layout(IEnumerable layoutNodes, Vector3 centerPosition, Vector2 rectangle) { List layoutNodesList = layoutNodes.ToList(); if (!layoutNodesList.Any()) @@ -102,10 +89,9 @@ public override Dictionary Layout(IEnumerable Layout(IEnumerable. /// Fills the and the . /// - private void InitNodes() + /// the rectangle size in which to fit the node + private void InitNodes(Vector2 rectangle) { float totalSize = Roots.Sum(InitNode); // adjust the absolute size to the rectangle of the layout - float adjustFactor = (width * depth) / totalSize; + float adjustFactor = (rectangle.x * rectangle.y) / totalSize; foreach (Node node in nodeMap.Values) { node.DesiredSize *= adjustFactor; @@ -127,8 +114,8 @@ private void InitNodes() } /// - /// Creates a for the given - /// and continues recursively with the children of the ILayoutNode . + /// Creates a for the given + /// and continues recursively with the children of . /// Extends both and by the node. /// /// node of the layout @@ -141,8 +128,8 @@ private float InitNode(ILayoutNode node) if (node.IsLeaf) { - // x and z lengths may differ; we need to consider the larger value - float size = Mathf.Max(node.LocalScale.x, node.LocalScale.z); + // x and z lengths may differ; we need to consider the larger value. + float size = Mathf.Max(node.AbsoluteScale.x, node.AbsoluteScale.z); newNode.DesiredSize = size; return size; } @@ -157,11 +144,12 @@ private float InitNode(ILayoutNode node) /// /// Calculates the layout for so that they fit in . /// Works recursively on the children of each sibling. - /// Adds the actual layout to + /// Adds the actual layout to . /// /// nodes with same parent (or roots) /// area to place siblings - private void CalculateLayout(ICollection siblings, Rectangle rectangle) + /// the y-coordindate of the ground where all nodes will be placed + private void CalculateLayout(ICollection siblings, Rectangle rectangle, float groundLevel) { List nodes = siblings.Select(n => nodeMap[n.ID]).ToList(); // check if the old layout can be used to lay out siblings. @@ -176,7 +164,7 @@ private void CalculateLayout(ICollection siblings, Rectangle rectan ApplyIncrementalLayout(nodes, rectangle); } - AddToLayout(nodes); + AddToLayout(nodes, groundLevel); foreach (ILayoutNode node in siblings) { @@ -187,7 +175,7 @@ private void CalculateLayout(ICollection siblings, Rectangle rectan } Rectangle childRectangle = nodeMap[node.ID].Rectangle; - CalculateLayout(children, childRectangle); + CalculateLayout(children, childRectangle, groundLevel); } } @@ -321,7 +309,8 @@ private int NumberOfOccurrencesInOldGraph(IEnumerable nodes) /// Applies padding to the result. /// /// nodes with calculated layout - private void AddToLayout(IEnumerable nodes) + /// The y-coordindate of the ground where all nodes will be placed. + private void AddToLayout(IEnumerable nodes, float groundLevel) { foreach (Node node in nodes) { @@ -335,31 +324,15 @@ private void AddToLayout(IEnumerable nodes) absolutePadding = 0; } - Vector3 position = new Vector3( - (float)(rectangle.X + rectangle.Width / 2.0d), - GroundLevel, - (float)(rectangle.Z + rectangle.Depth / 2.0d)); Vector3 scale = new Vector3( (float)(rectangle.Width - absolutePadding), - layoutNode.LocalScale.y, + layoutNode.AbsoluteScale.y, (float)(rectangle.Depth - absolutePadding)); - layoutResult[layoutNode] = new NodeTransform(position, scale); + layoutResult[layoutNode] = new NodeTransform((float)(rectangle.X + rectangle.Width / 2.0d), + (float)(rectangle.Z + rectangle.Depth / 2.0d), + scale); } } - - public override Dictionary Layout - (ICollection layoutNodes, ICollection edges, - ICollection sublayouts) - { - // Must not be implemented because UsesEdgesAndSublayoutNodes() returns false - // and this method should never be called. - throw new NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } } diff --git a/Assets/SEE/Layout/NodeLayouts/LoadedNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/LoadedNodeLayout.cs index 39584fb5ae..5c4e7692de 100644 --- a/Assets/SEE/Layout/NodeLayouts/LoadedNodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/LoadedNodeLayout.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using SEE.DataModel.DG; using SEE.Layout.IO; -using SEE.Layout.NodeLayouts.Cose; using SEE.Utils; using UnityEngine; @@ -13,42 +11,47 @@ namespace SEE.Layout.NodeLayouts /// /// A layout that is read from a layout file. /// - public class LoadedNodeLayout : HierarchicalNodeLayout + public class LoadedNodeLayout : NodeLayout { /// /// Constructor. /// /// the y co-ordinate setting the ground level; all nodes will be /// placed on this level - /// the name of file from which to read the layout information - public LoadedNodeLayout(float groundLevel, string filename) - : base(groundLevel) + public LoadedNodeLayout(string filename) { - Name = "Loaded Layout"; this.filename = filename; } + static LoadedNodeLayout() + { + Name = "Loaded Layout"; + } + /// /// The name of the layout file from which to read the layout information. /// private readonly string filename; /// - /// See . - /// Note: The layout may not only be returned but also applied depending on the implementation - /// of . + /// See . /// - /// nodes to be laid out - /// resulting layout - public override Dictionary Layout(IEnumerable layoutNodes) + /// thrown if the file extension of + /// is not known or if the file could not be loaded + protected override Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) { Dictionary result = new(); if (File.Exists(filename)) { + // Where to add the loaded node layout. IList layoutNodeList = layoutNodes.ToList(); + // Load the layout from the file. if (Filenames.HasExtension(filename, Filenames.GVLExtension)) { - new GVLReader(filename, layoutNodeList.Cast().ToList(), GroundLevel, new SEELogger()); + new GVLReader(filename, layoutNodeList.Cast().ToList(), groundLevel, new SEELogger()); // The elements in layoutNodeList will be stacked onto each other starting at groundLevel. } else if (Filenames.HasExtension(filename, Filenames.SLDExtension)) @@ -64,29 +67,14 @@ public override Dictionary Layout(IEnumerable Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts) - { - throw new NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } } diff --git a/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs b/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs deleted file mode 100644 index b1a87808b5..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs +++ /dev/null @@ -1,91 +0,0 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace SEE.Layout.NodeLayouts -{ - /// - /// Calculates a simple grid layout for leaf nodes (only). The order is - /// alphabetic with respect to the ID of the nodes. - /// - public class ManhattanLayout : FlatNodeLayout - { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - /// the factor to be multiplied with the default distance between buildings; - /// if game objects are 'naturally' larger, the distances between them should be larger, too. - public ManhattanLayout(float groundLevel) - : base(groundLevel) - { - Name = "Manhattan"; - } - - /// - /// The factor to be multiplied with the default distance between buildings. - /// If game objects are 'naturally' larger, the distances between them should be larger, too. - /// - private readonly float unit; - - public override Dictionary Layout(IEnumerable gameNodes) - { - Dictionary result = new Dictionary(); - - // Simple grid layout with the same number of blocks in each row (roughly). - IList layoutNodes = gameNodes.ToList(); - int numberOfBuildingsPerRow = (int)Mathf.Sqrt(layoutNodes.Count); - int column = 0; - int row = 1; - float distanceBetweenBuildings = unit * 3.0f; - float maxZ = 0.0f; // maximal depth of a building in a row - float positionX = 0.0f; // co-ordinate in a column of the grid - float positionZ = 0.0f; // co-ordinate in a row of the grid - // Note: (position.X, position.Y) is the left lower corner of the game object in the X,Z plane - - // Draw all nodes in a grid in ascending alphabetic order of their ID. - foreach (ILayoutNode gameNode in layoutNodes.OrderBy(gameObject => gameObject.ID)) - { - column++; - if (column > numberOfBuildingsPerRow) - { - // exceeded length of the square => start a new row - row++; - column = 1; - positionZ += maxZ + distanceBetweenBuildings; - maxZ = 0.0f; - positionX = 0.0f; - } - Vector3 size = gameNode.LocalScale; - if (size.z > maxZ) - { - maxZ = size.z; - } - - // center position of the block to be placed - positionX += size.x / 2.0f; - // The x,z position in a NodeTransform is the center of a GameObject, whereas - // (position.X, position.Y) is the left lower corner of the game object in the X,Z plane. - // We want all GameObjects be placed at the same ground level 0. - // We maintain the original scaleof the gameNode. - result[gameNode] = new NodeTransform(new Vector3(positionX, GroundLevel, positionZ + size.z / 2.0f), size); - // right border position of the block to be placed + space in between buildings - positionX += size.x / 2.0f + distanceBetweenBuildings; - } - return result; - } - - public override Dictionary Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts) - { - throw new System.NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } - } -} \ No newline at end of file diff --git a/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs.meta b/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs.meta deleted file mode 100644 index abc86cebd0..0000000000 --- a/Assets/SEE/Layout/NodeLayouts/ManhattanLayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: cb4dcca55f39e744da791f93c2af2d68 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/NodeLayouts/NodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/NodeLayout.cs index bc1fa4124d..0afd7f28e9 100644 --- a/Assets/SEE/Layout/NodeLayouts/NodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/NodeLayout.cs @@ -1,6 +1,4 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -12,330 +10,415 @@ namespace SEE.Layout.NodeLayouts public abstract class NodeLayout { /// - /// Constructor. + /// The unique name of a layout. Must be set by all concrete subclasses. /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - public NodeLayout(float groundLevel) - { - this.GroundLevel = groundLevel; - } - - /// - /// The unique name of a layout. Must be set by all concrete subclasses. - /// - public string Name + public static string Name { get; protected set; } = string.Empty; /// - /// The y co-ordinate of the ground where blocks are placed. + /// Yields the layout for all given . + /// For every node n in : result[n] is the node transform, + /// i.e., the game object's position, scale, and rotation. It is this node transform + /// that is calculated by this method. + /// + /// The nodes will be placed into a rectangle whose width is the + /// x co-ordindate of and whose depth is the y co-ordinate + /// of . + /// + /// The center of that rectangle is given by . /// - protected readonly float GroundLevel; + /// set of layout nodes for which to compute the layout + /// The center of the rectangle in worldspace. + /// The size of the rectangle within all nodes will be placed. + /// node layout + public virtual Dictionary Create + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) + { + if (!layoutNodes.Any()) + { + return new(); + } + Dictionary layout = Layout(layoutNodes, centerPosition, rectangle); + // nodes will have random positions at this point; leaves will have their three dimensions set. - /// - /// If inner nodes are represented as visible objects covering their total area - /// and the visualizations of those inner nodes are stacked in a hierarchical layout, - /// their visualizations should not be on the same level; otherwise they will hide - /// each other. For this reason, every inner node will be slightly lifted along the - /// y axis according to its tree depth so that inner nodes are stacked visually - /// (level 0 is at the bottom). The value levelIncreaseForInnerNodes is the - /// height factor for each level. It will be multiplied by the level to obtain - /// an inner node's y co-ordinate. - /// - protected const float LevelIncreaseForInnerNodes = 0.015f; + // We now move and scale the layout such that it fits into the rectangle at centerPosition. + // We need to compute the bounding box; we cannot simply use the bounding of the root note. + // That would be possible only for layouts which express containment as spatial enclosing. + // Yet, for EvoStreets this does not hold. + Box box = Bounding3DBox(layout.Values); + MoveTo(layout.Values, centerPosition, box); + float scaleFactor = Mathf.Min(rectangle.x / box.Width, rectangle.y / box.Depth); + // Note: Scaling may not be needed for some layouts because they already scale the nodes + // so that they fit into rectangle (e.g., tree map). + // The box is now at centerPosition. + ScaleXZ(layout.Values, scaleFactor, new Vector2(centerPosition.x, centerPosition.z)); - /// - /// Returns the lift for an innner node as a product of its tree level - /// and levelIncreaseForInnerNodes. This value is intended to be added - /// to the ground level to define the y co-ordindate of an inner node - /// where visualizations of inner nodes can be stacked and would possibly - /// hide each other if they were all at the same height. - /// - /// an inner node to be lifted - /// lift for an innner node - protected static float LevelLift(ILayoutNode node) - { - return node.Level * LevelIncreaseForInnerNodes; + // MoveTo and ScaleXZ affect only the scales and X/Z positions of the nodes. + // The y co-ordinates are not changed and are still the ones set by the caller. + // We need to stack the nodes on top of each other. + Stack(layout, centerPosition.y); + return layout; } /// /// Yields the layout for all given . /// For every node n in : result[n] is the node transform, - /// i.e., the game object's position, scale, and rotation. + /// i.e., the game object's position, scale, and rotation. It is this node transform + /// that is calculated by this method. /// - /// IMPORTANT NOTE: The y co-ordinate of the position in NodeTransform will - /// be interpreted as the ground position of the game object (unlike in Unity - /// where it is the center height). + /// The nodes will be placed into a rectangle whose width is the + /// x co-ordindate of and whose depth is the y co-ordinate + /// of . /// /// set of layout nodes for which to compute the layout + /// The center of the rectangle in worldspace. + /// The size of the rectangle within all nodes will be placed. /// node layout - /// - public abstract Dictionary Layout(IEnumerable layoutNodes); + protected abstract Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle); /// - /// Yields the layout for all given . - /// For every node n in : result[n] is the node transform, - /// i.e., the game object's position, scale, and rotation. - /// - /// contains all edges of the overlying graph and contains all sublayouts + /// Applies the values to its corresponding . /// - /// - /// - /// - /// - public abstract Dictionary Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts); + /// the calculated layout to be applied + public static void Apply(Dictionary layout) where T : ILayoutNode + { + foreach (KeyValuePair entry in layout) + { + T node = entry.Key; + NodeTransform transform = entry.Value; + node.CenterPosition = transform.CenterPosition; + node.AbsoluteScale = transform.Scale; + node.Rotation = transform.Rotation; + } + } /// - /// Adds the given to every node position in the given . + /// Creates cubes for each node in the layout and places them at the calculated positions. + /// This method can be used for debugging to show intermediate results of the layouting + /// process. /// - /// node layout to be adjusted - /// offset to be added - /// where has been added to each position - public static Dictionary Move(Dictionary layout, Vector3 offset) + /// layout to be shown + /// a prefix to be prepanded to the gameObject name + static void Draw(Dictionary layout, string prefix) { - Dictionary result = new Dictionary(); foreach (KeyValuePair entry in layout) { + ILayoutNode node = entry.Key; NodeTransform transform = entry.Value; - transform.Position += offset; - result[entry.Key] = transform; + GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); + go.name = prefix + "+" + node.ID; + go.transform.position = transform.CenterPosition; + go.transform.localScale = transform.Scale; } - return result; } /// - /// Adds the given to every node in . + /// The y co-ordinate of the ground level where all nodes will be placed initially + /// by calling . /// - /// layout nodes to be adjusted - /// offset to be added - public static void MoveTo(IEnumerable layoutNodes, Vector3 target) + protected const float groundLevel = 0.0f; + + #region Modifiers + + /// + /// A 3D box enclosing all nodes. + /// + /// the left front lower corner + /// the right back upper corner + record Box(Vector3 LeftFrontCorner, Vector3 RightBackCorner) { - IList layoutList = layoutNodes.ToList(); - Bounding3DBox(layoutList.ToList(), out Vector3 left, out Vector3 right); - // The center of the bounding 3D box enclosing all layoutNodes - Vector3 centerPosition = (right + left) / 2.0f; - Vector3 offset = target - centerPosition; - // It is assumed that target.y is the lowest point of the city. - offset.y = target.y; - foreach (ILayoutNode layoutNode in layoutList) - { - layoutNode.CenterPosition += offset; - } + /// + /// The center of the box. + /// + /// The center of the box is the midpoint of the line segment connecting its + /// left front corner and its right back corner. The coordinates of the center + /// can be calculated using the midpoint formula. + public Vector3 Center => (LeftFrontCorner + RightBackCorner) / 2.0f; + + /// + /// The height of the box. + /// + public float Height => RightBackCorner.y - LeftFrontCorner.y; + /// + /// The width of the box. + /// + public float Width => RightBackCorner.x - LeftFrontCorner.x; + /// + /// The depth of the box. + /// + public float Depth => RightBackCorner.z - LeftFrontCorner.z; } /// - /// Scales all nodes in so that they fit into + /// Scales the width and depth of all nodes in so that they fit into /// a rectangled defined by and . - /// The aspect ratio of every node is maintained. + /// The aspect ratio of every node is maintained. Only the NodeTransforms (values of the + /// dictionary) are affected. /// - /// layout nodes to be scaled + /// layout nodes to be scaled /// the absolute width (x axis) the required space for the laid out nodes must have /// the absolute depth (z axis) the required space for the laid out nodes must have /// the factor by which the scale of edge node was multiplied - public static float Scale(IEnumerable layoutNodes, float width, float depth) + private static float ScaleXZ(ICollection layout, float scaleFactor, Vector2 centerPosition) { - IList layoutNodeList = layoutNodes.ToList(); - Bounding3DBox(layoutNodeList, out Vector3 leftFrontCorner, out Vector3 rightBackCorner); - // The actual occupied space is a rectangle defined by leftFrontCorner and rightBackCorner. - - float actualWidth = rightBackCorner.x - leftFrontCorner.x; - float actualDepth = rightBackCorner.z - leftFrontCorner.z; - - float scaleFactor = Mathf.Min(width / actualWidth, depth / actualDepth); - foreach (ILayoutNode layoutNode in layoutNodeList) + foreach (NodeTransform nodeTransform in layout) { - layoutNode.ScaleBy(scaleFactor); - // The x/z co-ordinates must be adjusted after scaling - Vector3 newPosition = layoutNode.CenterPosition * scaleFactor; - layoutNode.CenterPosition = newPosition; + nodeTransform.ScaleXZBy(scaleFactor, centerPosition); } return scaleFactor; } /// - /// Stacks all onto each other with + /// Moves all nodes in together to the X/Z plane defined + /// by . + /// More precisely, the bounding enclosing all nodes in will be + /// translated (moved such that there is no change in size or shape) to a new location + /// such that the ground center of the bounding box at the new location is . + /// + /// layout to be moved + /// worldspace center point where to move the + /// bounding box enclosing all nodes in + private static void MoveTo(ICollection layout, Vector3 targetGroundCenter, Box box) + { + // centerPosition is the worldspace center of the bounding 3D box (cube) enclosing all layoutNodes. + Vector3 centerPosition = box.Center; + // Note that centerPosition relates to the center of the bounding box, while + // targetGroundCenter is the ground center of the target bounding box. + // Hence, we need to adjust the y co-ordinate of centerPosition. + centerPosition.y -= box.Height / 2.0f; + // The offest is the vector from the current center of the bounding box to the + // target center point and needs to be added to all nodes. + Vector3 offset = targetGroundCenter - centerPosition; + // It is assumed that target.y is the lowest point of the city. FIXME???? + foreach (NodeTransform nodeTransform in layout) + { + nodeTransform.TranslateBy(offset); + } + } + + /// + /// Stacks all nodes in the onto each other with /// in between parent and children (children are on top of their parent) where the initial /// y co-ordinate ground position of the roof nodes is specified by . - /// The x and z co-ordinates of the are not changed. + /// The x and z co-ordinates of the nodes are not changed. /// - /// the nodes to be stacked onto each other + /// layout whose nodes are to be stacked onto each other /// target y co-ordinate ground position of the layout nodes /// the y distance between parents and their children - public static void Stack(IEnumerable layoutNodes, float groundLevel, float levelDelta = 0.001f) + private static void Stack(Dictionary layout, float groundLevel, float levelDelta = 0.001f) { // position all root nodes at groundLevel - foreach (ILayoutNode layoutNode in layoutNodes) + foreach (ILayoutNode root in layout.Keys) { - if (layoutNode.Parent == null) + if (root.Parent == null) { - float newRoofY = PutOn(layoutNode, groundLevel); + float newRoofY = PutOn(layout[root], groundLevel) + levelDelta; // Continue with the children - foreach (ILayoutNode child in layoutNode.Children()) + foreach (ILayoutNode child in root.Children()) { - Stack(child, newRoofY + levelDelta, levelDelta); + Stack(child, newRoofY); } } } - } + return; - /// - /// Positions the ground of on - /// and then stacks its children onto with - /// space along the y axis in between. Recurses to its children. Children are put on top of - /// . - /// the node to be positioned - /// the target y co-ordinate ground position of - /// the y distance between and its children - private static void Stack(ILayoutNode layoutNode, float groundLevel, float levelDelta) - { - float newRoofY = PutOn(layoutNode, groundLevel); - foreach (ILayoutNode child in layoutNode.Children()) + void Stack(ILayoutNode layoutNode, float level) + { + float newRoofY = PutOn(layout[layoutNode], level) + levelDelta; + foreach (ILayoutNode child in layoutNode.Children()) + { + Stack(child, newRoofY); + } + } + + static float PutOn(NodeTransform nodeTransform, float level) { - Stack(child, newRoofY + levelDelta, levelDelta); + nodeTransform.LiftGroundTo(level); + return nodeTransform.Roof; } } /// - /// Puts the ground of on (y axis). + /// Returns the bounding 3D box enclosing all given . /// - /// the layout node to be positioned - /// the y-coordinate of the ground of to be positioned - /// the y co-ordinate of the roof of the after it was moved along the y-axis - private static float PutOn(ILayoutNode layoutNode, float groundLevel) + /// the list of layout node transforms that are enclosed in the resulting bounding 3D box + private static Box Bounding3DBox(IEnumerable nodeTransforms) { - Vector3 centerPosition = layoutNode.CenterPosition; - float yExtent = layoutNode.AbsoluteScale.y / 2.0f; - centerPosition.y = groundLevel + yExtent; - layoutNode.CenterPosition = centerPosition; - return centerPosition.y + yExtent; - } + Vector3 left = new(Mathf.Infinity, Mathf.Infinity, Mathf.Infinity); + Vector3 right = new(Mathf.NegativeInfinity, Mathf.NegativeInfinity, Mathf.NegativeInfinity); - /// - /// Returns the bounding 3D box enclosing all given . - /// - /// the list of layout nodes that are enclosed in the resulting bounding 3D box - /// the left lower front corner of the bounding box - /// the right upper back corner of the bounding box - private static void Bounding3DBox(ICollection layoutNodes, out Vector3 left, out Vector3 right) - { - if (layoutNodes.Count == 0) - { - left = Vector3.zero; - right = Vector3.zero; - } - else + foreach (NodeTransform node in nodeTransforms) { - left = new Vector3(Mathf.Infinity, Mathf.Infinity, Mathf.Infinity); - right = new Vector3(Mathf.NegativeInfinity, Mathf.NegativeInfinity, Mathf.NegativeInfinity); - - foreach (ILayoutNode go in layoutNodes) + Vector3 extent = node.Scale / 2.0f; + // Note: position denotes the center of the *ground* of the object; + // this has consequences on the interpretation of the y co-ordinate. + Vector3 position = node.CenterPosition; { - Vector3 extent = go.AbsoluteScale / 2.0f; - // Note: position denotes the center of the object - Vector3 position = go.CenterPosition; + // left x co-ordinate of node + float x = position.x - extent.x; + if (x < left.x) { - // left x co-ordinate of go - float x = position.x - extent.x; - if (x < left.x) - { - left.x = x; - } + left.x = x; } - { // right x co-ordinate of go - float x = position.x + extent.x; - if (x > right.x) - { - right.x = x; - } + } + { // right x co-ordinate of node + float x = position.x + extent.x; + if (x > right.x) + { + right.x = x; } + } + { + // lower y co-ordinate of node + float y = position.y - extent.y; + if (y < left.y) { - // lower y co-ordinate of go - float y = position.y - extent.y; - if (y < left.y) - { - left.y = y; - } + left.y = y; } + } + { + // upper y co-ordinate of node + float y = position.y + extent.y; + if (y > right.y) { - // upper y co-ordinate of go - float y = position.y + extent.y; - if (y > right.y) - { - right.y = y; - } + right.y = y; } + } + { + // front z co-ordinate of node + float z = position.z - extent.z; + if (z < left.z) { - // front z co-ordinate of go - float z = position.z - extent.z; - if (z < left.z) - { - left.z = z; - } + left.z = z; } + } + { + // back z co-ordinate of node + float z = position.z + extent.z; + if (z > right.z) { - // back z co-ordinate of go - float z = position.z + extent.z; - if (z > right.z) - { - right.z = z; - } + right.z = z; } } } + return new Box(left, right); } + #endregion Modifiers + #region Hierarchy /// - /// If true, the layout can handle both inner nodes and leaves; otherwise - /// only leaves. + /// The roots of the subtrees of the original graph that are to be laid out. + /// A node is considered a root if it has either no parent in the original + /// graph or its parent is not contained in the set of nodes to be laid out. /// - /// whether the layout can handle hierarchical graphs - public abstract bool IsHierarchical(); + protected IList Roots; /// - /// If true, the layout needs the edges to calculate the Layout + /// Returns the maximal depth of the forest with the given root nodes. + /// If roots.Count == 0, 0 is the maximal depth. If there is at least + /// one root, the minimum value of the maximal depth is 1. /// - /// - public abstract bool UsesEdgesAndSublayoutNodes(); + /// set of root tree nodes of the forest + /// maximal depth of the forest + protected static int MaxDepth(List roots) + { + int result = 0; + foreach (ILayoutNode root in roots) + { + int depth = MaxDepth(root); + if (depth > result) + { + result = depth; + } + } + return result; + } /// - /// Calculates and applies the layout to the given . + /// Returns the maximal depth of the tree rooted by given node. The depth of + /// a tree with only one node is 1. /// - /// nodes for which to apply the layout - public void Apply(IEnumerable layoutNodes) + /// root node of the tree + /// maximal depth of the tree + protected static int MaxDepth(ILayoutNode node) { - ApplyLayoutNodeTransform(Layout(layoutNodes)); + int result = 0; + foreach (ILayoutNode child in node.Children()) + { + int depth = MaxDepth(child); + if (depth > result) + { + result = depth; + } + } + return result + 1; } + #endregion Hierarchy + + #region Padding + /// + /// Some padding will be added between nodes. That padding depends upon the minimum + /// of the width and depth of a node, multiplied by this factor. + /// + private const float paddingFactor = 0.05f; + /// - /// Calculates and applies the layout to the given . + /// The minimal padding between nodes in absolute (world space) terms. /// - /// nodes for which to apply the layout - /// edges of the underlying graph - /// the sublayouts for the layout - public void Apply(ICollection layoutNodes, ICollection edges, ICollection sublayouts) + private const float minimimalAbsolutePadding = 0.01f; + + /// + /// The maximal padding between nodes in absolute (world space) terms. + /// + private const float maximalAbsolutePadding = 0.1f; + + /// + /// Returns the padding to be added around a node to separate it visually + /// from its neigboaring nodes. + /// + /// The resulting padding will clamped into + /// and . + /// + /// The actual padding added between two neighboaring nodes + /// may be double this value if padding was added for both nodes. + /// the width of the node + /// the depth of the node + /// padding to be added + protected static float Padding(float width, float depth) { - ApplyLayoutNodeTransform(Layout(layoutNodes, edges, sublayouts)); + return Mathf.Clamp(Mathf.Min(width, depth) * paddingFactor, minimimalAbsolutePadding, maximalAbsolutePadding); } /// - /// Applies the values to its corresponding . + /// The inverse function of . It returns + /// the padding that was added to a node to obtain an area with + /// and . This padding needs to removed + /// from this area to get the original node area before padding was added. + /// + /// Let o = (w, d) be the original area and p = Padding(w, d). + /// Let n = (w+p, d+p) be the area where padding p was added. + /// Let p' = ReversePadding(w+p, d+p). Then (w+p-p', d+p-p') = (w, p). + /// + /// The resulting padding will clamped into + /// and . /// - /// the calculated layout to be applied - private static void ApplyLayoutNodeTransform(Dictionary layout) where T : ILayoutNode + /// the width of the node after padding was added + /// the depth of the node after padding was added + /// padding to be added + protected static float ReversePadding(float widthWithPadding, float depthWithPadding) { - foreach (KeyValuePair entry in layout) - { - T node = entry.Key; - NodeTransform transform = entry.Value; - // y co-ordinate of transform.position refers to the ground - Vector3 position = transform.Position; - position.y += transform.Scale.y / 2.0f; - node.CenterPosition = position; - node.LocalScale = transform.Scale; - node.Rotation = transform.Rotation; - } + float min = Mathf.Min(widthWithPadding, depthWithPadding); + return Mathf.Clamp((min * paddingFactor)/(1 + paddingFactor), minimimalAbsolutePadding, maximalAbsolutePadding); } + + #endregion Padding } } diff --git a/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PNode.cs b/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PNode.cs index bd8323d6f0..bb4d5d86e5 100644 --- a/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PNode.cs +++ b/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PNode.cs @@ -10,7 +10,7 @@ public class PNode /// /// A node is aware of its assigned space rectangle. /// - public PRectangle Rectangle = new PRectangle(); + public PRectangle Rectangle = new(); /// /// Whether the rectangle is occupied. diff --git a/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PTree.cs b/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PTree.cs index 5f43d3d3e9..f82dd47b34 100644 --- a/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PTree.cs +++ b/Assets/SEE/Layout/NodeLayouts/RectanglePacking/PTree.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using UnityEngine; namespace SEE.Layout.NodeLayouts.RectanglePacking @@ -84,11 +85,11 @@ public PNode Split(PNode node, Vector2 size) // so that it is actually not split, but it is not free. if (!FreeLeaves.Remove(node)) { - throw new System.Exception("Node to be split is not a free leaf."); + throw new Exception("Node to be split is not a free leaf."); } else if (size.x > node.Rectangle.Size.x || size.y > node.Rectangle.Size.y) { - throw new System.Exception("Requested size does not fit into this rectangle."); + throw new Exception("Requested size does not fit into this rectangle."); } else if (size.x == node.Rectangle.Size.x) { @@ -141,7 +142,7 @@ public PNode Split(PNode node, Vector2 size) node.Right = new(); node.Right.Rectangle = new PRectangle(new Vector2(node.Rectangle.Position.x, node.Rectangle.Position.y + size.y), - new Vector2(node.Rectangle.Size.x, node.Rectangle.Size.y - size.y)); + new Vector2(node.Rectangle.Size.x, node.Rectangle.Size.y - size.y)); FreeLeaves.Add(node.Right); // The upper enclosed rectangle is split again. Its left rectangle will be the rectangle @@ -192,5 +193,42 @@ public IList GetSufficientlyLargeLeaves(Vector2 size) } return result; } + + /// + /// Prints the tree to the console. Can be used for debugging. + /// + public void Print() + { + Print(Root, "", true); + } + + /// + /// Prints the tree rooted by to the console. Can be used for debugging. + /// + /// the root of the tree to be printed + /// indentation before the node is printed + /// whether this is the last node to be printed + private void Print(PNode node, string indent, bool last) + { + if (node == null) + { + return; + } + string output = indent; + if (last) + { + output += "└─"; + indent += " "; + } + else + { + output += "├─"; + indent += "| "; + } + Debug.Log(output + " " + node + "\n"); + + Print(node.Left, indent, false); + Print(node.Right, indent, true); + } } } diff --git a/Assets/SEE/Layout/NodeLayouts/RectanglePackingNodeLayout.cs b/Assets/SEE/Layout/NodeLayouts/RectanglePackingNodeLayout.cs index 4836f1ac84..23300641d4 100644 --- a/Assets/SEE/Layout/NodeLayouts/RectanglePackingNodeLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/RectanglePackingNodeLayout.cs @@ -1,6 +1,4 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; -using SEE.Layout.NodeLayouts.RectanglePacking; +using SEE.Layout.NodeLayouts.RectanglePacking; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -9,36 +7,26 @@ namespace SEE.Layout.NodeLayouts { /// /// This layout packs rectangles closely together as a set of nested packed rectangles to decrease - /// the total area of city. + /// the total area of city. The algorithm is based on the dissertation of Richard Wettel + /// "Software Systems as Cities" (2010); see page 35. + /// https://www.inf.usi.ch/lanza/Downloads/PhD/Wett2010b.pdf /// - public class RectanglePackingNodeLayout : HierarchicalNodeLayout + public class RectanglePackingNodeLayout : NodeLayout { - /// - /// Constructor. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - /// the unit for blocks; will be used to adjust the padding - /// the padding to be added between neighboring nodes; - /// the actual value used is padding * leafNodeFactory.Unit() - public RectanglePackingNodeLayout(float groundLevel, float padding = 1.0f) - : base(groundLevel) + static RectanglePackingNodeLayout() { Name = "Rectangle Packing"; - this.padding = padding; } /// - /// The padding between neighboring rectangles. - /// - private readonly float padding; - - /// - /// Yields a layout of as a set of nested packed rectangles. + /// See . /// - /// nodes to be laid out - /// retangle packing layout - public override Dictionary Layout(IEnumerable layoutNodes) + /// thrown if there is more than one root in + /// + protected override Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) { Dictionary layoutResult = new(); @@ -46,7 +34,7 @@ public override Dictionary Layout(IEnumerable Layout(IEnumerable().ToList()); - RemovePadding(layoutResult, padding); + Pack(layoutResult, layoutNodeList.Cast().ToList(), groundLevel); + RemovePadding(layoutResult); return layoutResult; } } @@ -89,11 +78,10 @@ public override Dictionary Layout(IEnumerable Layout(IEnumerable - /// Adjusts the layout so that all rectangles are truly nested. Also lifts the inner - /// nodes a bit along the y axis so that are stacked. This may be necessary for - /// space filling inner nodes such as cubes. It is not needed for lines, however. + /// Adjusts the layout so that all rectangles are truly nested. This is necessary + /// because the origin of the rectangle packing layout is different from the + /// Unity's co-ordinate system. The rectangle packing layout's origin is upper left + /// and grows to the right and *down*, while the X/Z plane in unity grows to the + /// right and *up*. /// /// the layout to be adjusted /// the parent node whose children are to be adjusted @@ -114,51 +104,41 @@ private static void MakeContained ILayoutNode parent) { NodeTransform parentTransform = layout[parent]; - Vector3 parentCenterPosition = parentTransform.Position; Vector3 parentExtent = parentTransform.Scale / 2.0f; // The x co-ordinate of the left lower corner of the parent. - float xCorner = parentCenterPosition.x - parentExtent.x; + float xCorner = parentTransform.X - parentExtent.x; // The z co-ordinate of the left lower corner of the parent. - float zCorner = parentCenterPosition.z - parentExtent.z; + float zCorner = parentTransform.Z - parentExtent.z; foreach (ILayoutNode child in parent.Children()) { - NodeTransform childTransform = layout[child]; - Vector3 newChildPosition = childTransform.Position; - newChildPosition.x += xCorner; - newChildPosition.z += zCorner; - if (!child.IsLeaf) - { - // The inner nodes will be slightly lifted along the y axis according to their - // tree depth so that they can be stacked visually (level 0 is at the bottom). - newChildPosition.y += LevelLift(child); - } - layout[child] = new NodeTransform(newChildPosition, childTransform.Scale, childTransform.Rotation); + layout[child].MoveBy(xCorner, zCorner); MakeContained(layout, child); } } /// - /// Removes the for all NodeTransforms in . + /// Removes the added padding for all NodeTransforms in . /// - /// layout containing the NodeTransform.scale to be adjusted - /// padding to be removed - private static void RemovePadding(Dictionary layout, float padding) + /// layout containing the NodeTransform.Scale to be adjusted + private static void RemovePadding(Dictionary layout) { - ICollection keys = new List(layout.Keys); + // We use a copy of the keys because we will modify layout during the iteration. + ICollection layoutNodes = new List(layout.Keys); - foreach (ILayoutNode key in keys) + foreach (ILayoutNode layoutNode in layoutNodes) { - NodeTransform value = layout[key]; - Vector3 scale = value.Scale; - scale.x -= 2.0f * padding; - scale.z -= 2.0f * padding; - // Since we removed the padding, we need to adjust the position, too, - // to center the node within the assigned rectangle. - Vector3 position = value.Position; - position.x += padding; - position.z += padding; - layout[key] = new NodeTransform(position, scale); + // We added padding to both inner nodes and leaves, but we want to + // the restore the original size of the leaves only. + if (layoutNode.IsLeaf) + { + NodeTransform value = layout[layoutNode]; + Vector3 scale = value.Scale; + float reversePadding = ReversePadding(scale.x, scale.z); + // We shrink the scale, but the position remains the same since + // value.Position denotes the center point. + layout[layoutNode].ExpandBy(-reversePadding, -reversePadding); + } } } @@ -169,15 +149,16 @@ private static void RemovePadding(Dictionary layout, /// /// the current layout; will be updated /// node to be laid out (includings all its descendants) + /// The y-coordindate of the ground where all nodes will be placed. /// the width and depth of the area covered by the rectangle for - private Vector2 PlaceNodes(Dictionary layout, ILayoutNode node) + private Vector2 PlaceNodes(Dictionary layout, ILayoutNode node, float groundLevel) { if (node.IsLeaf) { // Leaves maintain their scale, which was already set initially. The position will // be adjusted later at a higher level of the node hierarchy when Pack() is // applied to this leaf and all its siblings. - return new Vector2(node.LocalScale.x, node.LocalScale.z); + return new Vector2(node.AbsoluteScale.x, node.AbsoluteScale.z); } else { @@ -189,7 +170,7 @@ private Vector2 PlaceNodes(Dictionary layout, ILayou { if (!child.IsLeaf) { - Vector2 childArea = PlaceNodes(layout, child); + Vector2 childArea = PlaceNodes(layout, child, groundLevel); // childArea is the ground area size required for this inner node. // The position of this inner node in layout will be below in the call to Pack(). // The position is relative to the parent of this inner node. @@ -197,22 +178,23 @@ private Vector2 PlaceNodes(Dictionary layout, ILayou // Note: We have already added padding to leaf nodes, but this one here is an // inner node. Nevertheless, we do not add padding here, because padding is already // included in the returned childArea. - layout[child] = new NodeTransform(Vector3.zero, - new Vector3(childArea.x, GroundLevel, childArea.y)); + layout[child] = new NodeTransform(0, 0, + new Vector3(childArea.x, child.AbsoluteScale.y, childArea.y)); } } // The scales of all children of the node have now been set. Now // let's pack those children. if (children.Count > 0) { - Vector2 area = Pack(layout, children.Cast().ToList()); - return new Vector2(area.x + 2.0f * padding, area.y + 2.0f * padding); + Vector2 area = Pack(layout, children.Cast().ToList(), groundLevel); + float padding = Padding(area.x, area.y); + return new Vector2(area.x + padding, area.y + padding); } else { // Can we ever arrive here? That would mean that node is not a leaf // and does not have children. - return new Vector2(node.LocalScale.x, node.LocalScale.z); + return new Vector2(node.AbsoluteScale.x, node.AbsoluteScale.z); } } } @@ -282,9 +264,10 @@ private static Vector2 Sum(List nodes, Dictionarythe current layout (positions of /// will be updated /// the nodes to be laid out + /// The y-coordindate of the ground where all nodes will be placed. /// the width (x) and depth (y) of the outer rectangle in which all /// were placed - private Vector2 Pack(Dictionary layout, List nodes) + private Vector2 Pack(Dictionary layout, List nodes, float groundLevel) { // To increase the efficiency of the space usage, we order the elements by one of the sizes. // Elements must be sorted by size, descending @@ -297,7 +280,7 @@ private Vector2 Pack(Dictionary layout, List layout, List preservers = new Dictionary(); + Dictionary preservers = new(); // All nodes in pnodes that do not preserve the size of coverec. - // The value is the aspect ratio of coverec if the node were used to - // place el. - Dictionary expanders = new Dictionary(); + // The value is the absolute difference of the aspect ratio of coverec from 1 + // (1 being the perfect ratio) if the node were used to place el. + Dictionary expanders = new(); foreach (ILayoutNode el in nodes) { @@ -329,7 +312,7 @@ private Vector2 Pack(Dictionary layout, List layout, List layout, List layout, List Layout(ICollection layoutNodes, ICollection edges, ICollection sublayouts) - { - throw new System.NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } -} \ No newline at end of file +} diff --git a/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs b/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs new file mode 100644 index 0000000000..7f201bba74 --- /dev/null +++ b/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs @@ -0,0 +1,330 @@ +using SEE.Tools.ReflexionAnalysis; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace SEE.Layout.NodeLayouts +{ + /// + /// A layout for the reflexion analysis of a code city where there are two sublayouts, + /// one for the architecture and one for the implementation. + /// + public class ReflexionLayout : NodeLayout + { + /// + /// Constructor. + /// + /// the proportion of the longer edge of the available space that + /// is occupied by the architecture; must be in [0, 1] + /// the layout to applied to the implementation nodes; + /// if none is given will be used + /// the layout to applied to the architecture nodes; + /// if none is given will be used + /// thrown if is not in [0, 1] + public ReflexionLayout(float architectureProportion, NodeLayout implementationLayout = null, NodeLayout architectureLayout = null) + { + if (architectureProportion < 0 || architectureProportion > 1) + { + throw new ArgumentException("Architecture proportion must be in [0, 1]."); + } + this.architectureProportion = architectureProportion; + this.implementationLayout = implementationLayout ?? new TreemapLayout(); + this.architectureLayout = architectureLayout ?? new TreemapLayout(); + } + + static ReflexionLayout() + { + Name = "Reflexion"; + } + + /// + /// The proportion of the longer edge of the available space that is occupied by + /// the architecture; must be in [0, 1]. + /// + private readonly float architectureProportion; + /// + /// The layout to applied to the implementation nodes. + /// + private readonly NodeLayout implementationLayout; + /// + /// The layout to applied to the architecture nodes. + /// + private readonly NodeLayout architectureLayout; + + /// + /// See . + /// + /// Preconditions: + /// There must be only one root node that has exactly two children. One of them is the architecture + /// and the other is the implementation. The architecture node has the node type + /// and the implementation node has the node type + /// . + /// + /// thrown in case the preconditions are not met + protected override Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) + { + // There should be one root that has exactly two children. One of them is the architecture + // and the other is the implementation. + IList roots = LayoutNodes.GetRoots(layoutNodes); + if (roots.Count == 0) + { + // Nothing to be laid out. + return new Dictionary(); + } + if (roots.Count > 1) + { + throw new ArgumentException("Graph has more than one root node."); + } + ICollection children = roots[0].Children(); + if (children.Count != 2) + { + throw new ArgumentException("Root node has not exactly two children."); + } + ILayoutNode architectureRoot = null; + ILayoutNode implementationRoot = null; + + // We cannot use indexing, hence, we need to iterate over the children. + foreach (ILayoutNode child in children) + { + if (child.HasType(ReflexionGraph.ArchitectureType)) + { + architectureRoot = child; + } + else if (child.HasType(ReflexionGraph.ImplementationType)) + { + implementationRoot = child; + } + else + { + throw new ArgumentException("Root node has a child that is neither architecture nor implementation."); + } + } + if (architectureRoot == null) + { + throw new ArgumentException("Root node has no architecture child."); + } + if (implementationRoot == null) + { + throw new ArgumentException("Root node has no implementation child."); + } + if (architectureRoot == implementationRoot) + { + throw new ArgumentException("Root node has the two children that are both architecture or implementation, respectively."); + } + + Split(centerPosition, rectangle.x, rectangle.y, architectureProportion, out Area implementionArea, out Area architectureArea); + + // We will temporarily remove the architecture and implementation nodes as children from the root node + // because the sublayouts would be unable to detect a root. + roots[0].RemoveChild(architectureRoot); + roots[0].RemoveChild(implementationRoot); + + // Laying out the implementation. + ICollection implementationNodes = ILayoutNodeHierarchy.DescendantsOf(implementationRoot); + Dictionary result + = implementationLayout.Create(implementationNodes, + implementionArea.Position, + new Vector2(implementionArea.Width, implementionArea.Depth)); + + // Laying out the architecture. + ICollection architectureNodes = ILayoutNodeHierarchy.DescendantsOf(architectureRoot); + + Union(result, architectureLayout.Create(architectureNodes, + architectureArea.Position, + new Vector2(architectureArea.Width, architectureArea.Depth))); + + // Adding the architecture and implementation nodes back as children to the root node. + roots[0].AddChild(architectureRoot); + roots[0].AddChild(implementationRoot); + + // The root node was not laid out by the sublayouts, hence, we need to add it manually, + // occupying the complete available space. + result[roots[0]] = new NodeTransform(centerPosition.x, centerPosition.z, new Vector3(rectangle.x, roots[0].AbsoluteScale.y, rectangle.y)); + return result; + + // Adds the layout to the result. + static void Union(Dictionary result, Dictionary layout) + { + foreach (KeyValuePair entry in layout) + { + result[entry.Key] = entry.Value; + } + } + } + + /// + /// Represents a plane in 3D space where to draw a code city for reflexion analysis, + /// that is, an area for the implementation city or the architecture city. + /// + struct Area + { + /// + /// Constructor. + /// + /// The center point of the area in world space. + /// The width of the area in world space. + /// The depth of the area in world space. + internal Area(Vector3 position, float width, float depth) + { + Position = position; + Width = width; + Depth = depth; + } + /// + /// The center point of the area in world space. + /// + internal Vector3 Position; + /// + /// The width of the area in world space. + /// + internal float Width; + /// + /// The depth of the area in world space. + /// + internal float Depth; + + /// + /// Draws a cube representing the area. Can be used for debugging. + /// + /// the name of the created cube + internal readonly void Draw(string name) + { + GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); + go.name = name; + go.transform.position = Position; + go.transform.localScale = new Vector3(Width, 0.01f, Depth); + } + } + + /// + /// Splits the available rectangle for the code city into two areas - one for the + /// implementation and one for the architecture - along the longer edge of the + /// rectangle in the proportion of . + /// + /// The rectangle is specified by its center position , + /// and its and . + /// + /// The area of the implementation is returned in + /// and the area of the architecture in . + /// + /// The edge length of is the length of the longer edge + /// of the rectangle multiplied by . + /// + /// and together + /// occupy exactly the space of the rectangle. + /// + /// is assumed to be in [0, 1]. If + /// is 0 or less, the implementation takes + /// all the space and the architecture area sits at the end of the longer edge of the + /// implementation with zero scale. If + /// is 1 or greater, the architecture takes all the space and the implementation area sits at the + /// begin of the longer edge of the architecture with zero scale. + /// + /// the center position of the rectangle in which to place + /// the implementation and architecture + /// the width of the rectangle in which to place them + /// the depth of the rectangle in which to place them + /// the proportion of the longer edge of the available + /// space that should be allocated for the architecture; must be in [0, 1] + /// the resulting area of the implementation + /// the resulting area of the architecture + private static void Split(Vector3 centerPosition, + float width, + float depth, + float architectureLayoutProportion, + out Area implementionArea, + out Area architectureArea) + { + bool xIsLongerEdge = width >= depth; + + if (architectureLayoutProportion <= 0) + { + // the implemenation takes all the available space + implementionArea = new(centerPosition, width, depth); + // the architecture sits at the end of the longer edge of the implementation with zero space + Vector3 architecturePos = implementionArea.Position; + if (xIsLongerEdge) + { + architecturePos.x = implementionArea.Position.x + implementionArea.Width / 2; + } + else + { + architecturePos.z = implementionArea.Position.z + implementionArea.Depth / 2; + } + architectureArea = new(architecturePos, 0, 0); + } + else if (architectureLayoutProportion >= 1) + { + // the architecture takes all the available space + architectureArea = new(centerPosition, width, depth); + // the implementation sits at the begin of the longer edge of the architecture with zero space + Vector3 implementationPos = architectureArea.Position; + if (xIsLongerEdge) + { + implementationPos.x = architectureArea.Position.x - architectureArea.Width / 2; + } + else + { + implementationPos.z = architectureArea.Position.z - architectureArea.Depth / 2; + } + implementionArea = new(implementationPos, 0, 0); + } + else + { + if (xIsLongerEdge) + { + // The reference point from which to start laying out the areas. + Vector3 referencePoint = centerPosition; + // The mid point of the left edge of the code city. + referencePoint.x -= width / 2; + + // The implementationArea. + { + float length = width * (float)(1 - architectureLayoutProportion); + Vector3 position = referencePoint; + position.x += length / 2; + implementionArea = new(position, length, depth); + // Move the reference point to the right end of the implementation area. + referencePoint.x += length; + } + + // The architectureArea. + { + float length = width * architectureLayoutProportion; + Vector3 position = referencePoint; + position.x += length / 2; + architectureArea = new(position, length, depth); + } + } + else + { + // The reference point from which to start laying out the areas. + Vector3 referencePoint = centerPosition; + // The mid point of the lower edge of the code city. + referencePoint.z -= depth / 2; + + // The implementationArea. + { + float length = depth * (float)(1 - architectureLayoutProportion); + Vector3 position = referencePoint; + position.z += length / 2; + implementionArea = new(position, width, length); + // Move the reference point to the lower end of the implementation area. + referencePoint.z += length; + } + + // The architectureArea. + { + float length = depth * architectureLayoutProportion; + Vector3 position = referencePoint; + position.z += length / 2; + architectureArea = new(position, width, length); + } + } + } + } + } +} diff --git a/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs.meta b/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs.meta new file mode 100644 index 0000000000..34d43841db --- /dev/null +++ b/Assets/SEE/Layout/NodeLayouts/ReflexionLayout.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0c410f9e69518c445a112dbd68f1b77f \ No newline at end of file diff --git a/Assets/SEE/Layout/NodeLayouts/TreeMap/RectangleTiling.cs b/Assets/SEE/Layout/NodeLayouts/TreeMap/RectangleTiling.cs index caadc18a67..cfa9c7c975 100644 --- a/Assets/SEE/Layout/NodeLayouts/TreeMap/RectangleTiling.cs +++ b/Assets/SEE/Layout/NodeLayouts/TreeMap/RectangleTiling.cs @@ -3,6 +3,9 @@ namespace SEE.Layout.NodeLayouts.TreeMap { + /// + /// Implements the tiling of rectangles for a tree map layout. + /// internal class RectangleTiling { /// @@ -12,17 +15,36 @@ internal class RectangleTiling /// public class Rectangle { + /// + /// Constructor. + /// + /// X co-ordinate at corner + /// Z co-ordinate at corner + /// width of the rectangle + /// depth (breadth) of the rectangle public Rectangle(float x, float z, float width, float depth) { - this.X = x; - this.Z = z; - this.Width = width; - this.Depth = depth; + X = x; + Z = z; + Width = width; + Depth = depth; } - public float X; // x co-ordinate at corner - public float Z; // z co-ordinate at corner - public float Width; // width - public float Depth; // depth (breadth) + /// + /// X co-ordinate at corner. + /// + public float X; + /// + /// Z co-ordinate at corner. + /// + public float Z; + /// + /// Width of the rectangle. + /// + public float Width; + /// + /// Depth (breadth) of the rectangle. + /// + public float Depth; } /// @@ -30,17 +52,29 @@ public Rectangle(float x, float z, float width, float depth) /// public class NodeSize { + /// + /// Constructor. + /// + /// layout node this node size corresponds to + /// size of the node public NodeSize(ILayoutNode gameNode, float size) { - this.GameNode = gameNode; - this.Size = size; + GameNode = gameNode; + Size = size; } + /// + /// The layout node this node size corresponds to. + /// public ILayoutNode GameNode; + /// + /// The size of the node. + /// public float Size; } /// - /// Adds padding to the rectangle. + /// Adds padding to the rectangle to all sides, that is, the width + /// and depth are increased by twice the . /// /// rectangle for which to add padding /// the absolute padding to be added in between diff --git a/Assets/SEE/Layout/NodeLayouts/TreemapLayout.cs b/Assets/SEE/Layout/NodeLayouts/TreemapLayout.cs index ec87028fad..6869ae7f04 100644 --- a/Assets/SEE/Layout/NodeLayouts/TreemapLayout.cs +++ b/Assets/SEE/Layout/NodeLayouts/TreemapLayout.cs @@ -1,6 +1,4 @@ -using SEE.DataModel.DG; -using SEE.Layout.NodeLayouts.Cose; -using SEE.Layout.NodeLayouts.TreeMap; +using SEE.Layout.NodeLayouts.TreeMap; using System; using System.Collections.Generic; using System.Linq; @@ -14,49 +12,25 @@ namespace SEE.Layout.NodeLayouts /// described by Bruls, Huizing, van Wijk, "Squarified Treemaps". /// pp. 33-42, Eurographics / IEEE VGTC Symposium on Visualization, 2000. /// - public class TreemapLayout : HierarchicalNodeLayout + public class TreemapLayout : NodeLayout { - /// - /// Constructor. The width and depth are assumed to be in Unity units. - /// - /// the y co-ordinate setting the ground level; all nodes will be - /// placed on this level - /// width of the rectangle in which to place all nodes in Unity units - /// width of the rectangle in which to place all nodes in Unity units - public TreemapLayout(float groundLevel, - float width, - float depth) - : base(groundLevel) + static TreemapLayout() { Name = "Treemap"; - this.width = width; - this.depth = depth; } - /// - /// The width of the rectangle in which to place all nodes in Unity units. - /// - private readonly float width; - - /// - /// The depth of the rectangle in which to place all nodes in Unity units. - /// - private readonly float depth; - /// /// The node layout we compute as a result. /// private Dictionary layoutResult; /// - /// Return a treemap layout where are all nodes are fit into a given rectangle - /// with the width and depth passed to the constructor. The width and depth of - /// the original layout nodes will be scaled to fit into the rectangle, but - /// the height will remain the same as in the input. + /// See . /// - /// nodes to be laid out - /// treemap layout scaled in x and z axes - public override Dictionary Layout(IEnumerable layoutNodes) + protected override Dictionary Layout + (IEnumerable layoutNodes, + Vector3 centerPosition, + Vector2 rectangle) { layoutResult = new Dictionary(); @@ -64,7 +38,7 @@ public override Dictionary Layout(IEnumerable enumerator = layoutNodeList.GetEnumerator(); @@ -72,9 +46,9 @@ public override Dictionary Layout(IEnumerable Layout(IEnumerable Layout(IEnumerable - private void CalculateLayout() + private void CalculateLayout(Vector2 rectangle) { /// Our "logical" rectangle in which to put the whole treemap is assumed to have its /// center at Vector3.zero here. @@ -109,14 +83,14 @@ private void CalculateLayout() if (Roots.Count == 1) { ILayoutNode root = Roots[0]; - Assert.AreEqual(root.AbsoluteScale, root.LocalScale); - layoutResult[root] = new NodeTransform(Vector3.zero, - new Vector3(width, root.LocalScale.y, depth)); - CalculateLayout(root.Children(), x: -width / 2.0f, z: -depth / 2.0f, width, depth); + Assert.AreEqual(root.AbsoluteScale, root.AbsoluteScale); + layoutResult[root] = new NodeTransform(0, 0, + new Vector3(rectangle.x, root.AbsoluteScale.y, rectangle.y)); + CalculateLayout(root.Children(), x: -rectangle.x / 2.0f, z: -rectangle.y / 2.0f, rectangle.x, rectangle.y); } else { - CalculateLayout(Roots, x: -width / 2.0f, z: -depth / 2.0f, width, depth); + CalculateLayout(Roots, x: -rectangle.x / 2.0f, z: -rectangle.y / 2.0f, rectangle.x, rectangle.y); } } @@ -145,45 +119,17 @@ private void CalculateLayout(ICollection siblings, float x, float z { // Note: nodeTransform.position is the center position, while // CalculateLayout assumes co-ordinates x and z as the left front corner - Assert.AreEqual(node.AbsoluteScale, node.LocalScale); + Assert.AreEqual(node.AbsoluteScale, node.AbsoluteScale); NodeTransform nodeTransform = layoutResult[node]; CalculateLayout(children, - nodeTransform.Position.x - nodeTransform.Scale.x / 2.0f, - nodeTransform.Position.z - nodeTransform.Scale.z / 2.0f, + nodeTransform.X - nodeTransform.Scale.x / 2.0f, + nodeTransform.Z - nodeTransform.Scale.z / 2.0f, nodeTransform.Scale.x, nodeTransform.Scale.z); } } } - /// - /// Some padding will be added between nodes. That padding depends upon the minimum - /// of the width and depth of a node, multiplied by this factor. - /// - private const float paddingFactor = 0.05f; - - /// - /// The minimal padding between nodes in absolute (world space) terms. - /// - private const float minimimalAbsolutePadding = 0.01f; - - /// - /// The maximal padding between nodes in absolute (world space) terms. - /// - private const float maximalAbsolutePadding = 0.1f; - - /// - /// Returns the padding to be added between neighboring nodes (on a per node basis, - /// i.e., the actual padding is the sum of the padding of two neighboring nodes). - /// - /// the width of the node - /// the depth of the node - /// padding to be added - private static float Padding(float width, float depth) - { - return Mathf.Clamp(Mathf.Min(width, depth) * paddingFactor, minimimalAbsolutePadding, maximalAbsolutePadding); - } - /// /// Calculates the size of all nodes. The size of a leaf is the maximum of /// its width and depth. The size of an inner node is the sum of the sizes @@ -206,8 +152,7 @@ private float CalculateSize() /// /// The size metric of each node. The area of the rectangle is proportional to a node's size. /// - private readonly Dictionary sizes - = new Dictionary(); + private readonly Dictionary sizes = new(); /// /// Calculates the size of node and all its descendants. The size of a leaf @@ -223,7 +168,7 @@ private float CalculateSize(ILayoutNode node) if (node.IsLeaf) { // a leaf - Vector3 size = node.LocalScale; + Vector3 size = node.AbsoluteScale; // x and z lengths may differ; we need to consider the larger value float result = Mathf.Max(size.x, size.z); sizes[node] = new RectangleTiling.NodeSize(node, result); @@ -249,7 +194,7 @@ private float CalculateSize(ILayoutNode node) /// list of node area sizes private List GetSizes(ICollection nodes) { - List result = new List(); + List result = new(); foreach (ILayoutNode node in nodes) { result.Add(sizes[node]); @@ -278,24 +223,10 @@ private void AddToLayout foreach (RectangleTiling.Rectangle rect in rects) { ILayoutNode o = nodes[i].GameNode; - Vector3 position = new Vector3(rect.X + rect.Width / 2.0f, GroundLevel, rect.Z + rect.Depth / 2.0f); - Vector3 scale = new Vector3(rect.Width, o.LocalScale.y, rect.Depth); - Assert.AreEqual(o.AbsoluteScale, o.LocalScale, $"{o.ID}: {o.AbsoluteScale} != {o.LocalScale}"); - layoutResult[o] = new NodeTransform(position, scale); + Vector3 scale = new(rect.Width, o.AbsoluteScale.y, rect.Depth); + layoutResult[o] = new NodeTransform(rect.X + rect.Width / 2.0f, rect.Z + rect.Depth / 2.0f, scale); i++; } } - - public override Dictionary Layout - (ICollection layoutNodes, ICollection edges, - ICollection sublayouts) - { - throw new NotImplementedException(); - } - - public override bool UsesEdgesAndSublayoutNodes() - { - return false; - } } } diff --git a/Assets/SEE/Layout/NodeTransform.cs b/Assets/SEE/Layout/NodeTransform.cs index 3f728041b8..3cbdd983eb 100644 --- a/Assets/SEE/Layout/NodeTransform.cs +++ b/Assets/SEE/Layout/NodeTransform.cs @@ -1,55 +1,84 @@ -using UnityEngine; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using UnityEngine; namespace SEE.Layout { /// /// The position, scaling, and rotation of a node game object as determined by a node layout. - /// The y co-ordinate of the position will be interpreted as the ground position of - /// the game object (unlike in Unity where it is the center height). /// - /// Note: Structs are value types and are copied on assignment. - public struct NodeTransform + public class NodeTransform { /// /// Constructor setting the position and scale. The rotation will be 0 degrees. - /// The y co-ordinate of the position will be interpreted as the ground position of - /// the game object (unlike in Unity where it is the center height). + /// The y co-ordinate will be calculated such that the ground of the object is 0. /// - /// position in the scene; y co-ordinate denotes the ground - /// the scale of the object + /// worldspace x center position + /// worldspace z center position + /// the absolute scale of the object + public NodeTransform(float x, float z, Vector3 scale) + { + centerPosition = new Vector3(x, scale.y, z); + Scale = scale; + Rotation = 0.0f; + } + + /// + /// Constructor setting the position, scale, and rotation. + /// The y co-ordinate will be calculated such that the ground of the object is 0. + /// + /// worldspace x center position + /// worldspace z center position + /// the absolute scale of the object + /// rotation of the object around the y axis in degree + public NodeTransform(float x, float z, Vector3 scale, float rotation) + { + centerPosition = new Vector3(x, scale.y, z); + Scale = scale; + Rotation = rotation; + } + + /// + /// Constructor setting the position, scale, and rotation. + /// The position will be exactly as given by , + /// that is, no adjustment will be made to the y co-ordinate. + /// The rotation will be 0 degrees. + /// + /// worldspace center position + /// the absolute scale of the object public NodeTransform(Vector3 position, Vector3 scale) { - this.Position = position; - this.Scale = scale; + centerPosition = position; + Scale = scale; Rotation = 0.0f; } /// /// Constructor setting the position, scale, and rotation. - /// The y co-ordinate of the position will be interpreted as the ground position of - /// the game object (unlike in Unity where it is the center height). The x and z - /// co-ordinate refer to the center of an object in the x/z plane (ground). + /// The position will be exactly as given by , + /// that is, no adjustment will be made to the y co-ordinate. + /// The rotation will be degrees. /// - /// position in the scene; y co-ordinate denotes the ground - /// the scale of the object + /// worldspace center position + /// the absolute scale of the object /// rotation of the object around the y axis in degree public NodeTransform(Vector3 position, Vector3 scale, float rotation) { - this.Position = position; - this.Scale = scale; - this.Rotation = rotation; + centerPosition = position; + Scale = scale; + Rotation = rotation; } /// - /// The position in the scene. - /// - /// IMPORTANT NOTE: The y co-ordinate will be interpreted as the ground position of - /// the game object (unlike in Unity where it is the center height). The x and z - /// co-ordinate refer to the center of an object in the x/z plane (ground). + /// The worldspace position along the x axis. /// - public Vector3 Position; + public float X => centerPosition.x; /// - /// The scale (width, height, depth) of the game object. + /// The worldspace position along the z axis. + /// + public float Z => centerPosition.z; + + /// + /// The absolute scale (width, height, depth) of the game object. /// public Vector3 Scale; /// @@ -58,9 +87,108 @@ public NodeTransform(Vector3 position, Vector3 scale, float rotation) /// public float Rotation; + /// + /// The roof (y axis) of this node transform. + /// + public float Roof => centerPosition.y + Scale.y / 2.0f; + + /// + /// The worldspace center position of the node. + /// + /// We keep this a separate field declaration (not using a + /// default property for ) to be able + /// to modify the co-ordinates individually. + private Vector3 centerPosition; + + /// + /// The worldspace center position of the node. + /// + public Vector3 CenterPosition => centerPosition; + + /// + /// Scales the width (x) and depth (z) by the given . + /// The height will be maintained. + /// + /// factory by which to scale the width and depth of the node + public void ScaleXZBy(float factor) + { + Scale.x *= factor; + Scale.z *= factor; + } + + public void ScaleXZBy(float factor, Vector2 relativeTo) + { + Vector2 newPosition = relativeTo + factor * (new Vector2(X, Z) - relativeTo); + centerPosition.x = newPosition.x; + centerPosition.z = newPosition.y; + ScaleXZBy(factor); + } + + /// + /// Translate (moves) this transform by given . + /// + /// the relative offset by which to move + internal void TranslateBy(Vector3 offset) + { + centerPosition += offset; + } + + /// + /// Lifts this transform along the y axis such that the ground of the object is at the + /// given level. + /// + /// the absolute worldspace y co-ordindate of the ground where to lift + internal void LiftGroundTo(float ground) + { + centerPosition.y = ground + Scale.y / 2.0f; + } + + /// + /// Moves this transform to the given and co-ordinates. + /// The y co-ordinate will be maintained. + /// + /// target x co-ordinate + /// target z co-ordinate + internal void MoveTo(float x, float z) + { + centerPosition.x = x; + centerPosition.z = z; + } + + /// + /// Moves this transform by the given along the + /// x axis and along the y axis. Equivalent to + /// MoveTo(X + xOffset, Z + zOffset). + /// + /// to be added to + /// to be added to + internal void MoveBy(float xOffset, float zOffset) + { + centerPosition.x += xOffset; + centerPosition.z += zOffset; + } + + /// + /// Expands the scale of this transform by the given along the + /// x axis and by along the y axis. Equivalent to + /// Scale.x += xOffset and Scale.z += zOffset. The offsets can be negative, in + /// which case the node is actually shrunk. + /// + /// to be added to + /// to be added to + internal void ExpandBy(float xOffset, float zOffset) + { + Scale.x += xOffset; + Scale.z += zOffset; + } + + /// + /// Human readable string representation of this node transform for debugging. + /// + /// string representation of this node transform public override string ToString() { - return "position=" + Position.ToString() + " scale=" + Scale.ToString(); + return "position=" + centerPosition.ToString() + " scale=" + Scale.ToString() + " rotation=" + Rotation; } } } diff --git a/Assets/SEE/Layout/Sublayout.cs b/Assets/SEE/Layout/Sublayout.cs deleted file mode 100644 index 93eb10b91d..0000000000 --- a/Assets/SEE/Layout/Sublayout.cs +++ /dev/null @@ -1,326 +0,0 @@ -// Copyright 2020 Nina Unterberg -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -// associated documentation files (the "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or substantial -// portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -// THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -using System.Collections.Generic; -using SEE.DataModel.DG; -using SEE.Game.City; -using SEE.GO; -using SEE.Layout.NodeLayouts; -using SEE.Layout.NodeLayouts.Cose; -using SEE.Layout.Utils; -using UnityEngine; - -namespace SEE.Layout -{ - public class Sublayout - { - /// - /// the layout of the sublayout - /// - private readonly NodeLayoutKind nodeLayout; - - /// - /// a map from every sublayout node to the corresponding gameobject - /// - private readonly ICollection sublayoutNodes; - - /// - /// the y co-ordinate setting the ground level; all nodes will be placed on this level - /// - private readonly float groundLevel; - - /// - /// the scale of the calculated layout - /// - private Vector3 layoutScale; - - /// - /// the layout offset - /// - private Vector3 layoutOffset; - - /// - /// the "real" scale of the root node (is needed, if the nodelayout doenst enclose the inner nodes) - /// - private Vector3 rootNodeRealScale; - - /// - /// the sublayout node - /// - private readonly SublayoutLayoutNode sublayout; - - /// - /// the graph - /// - private readonly Graph graph; - - /// - /// A Mapping from ILayoutNodes to ILayoutSublayoutNodes - /// - private readonly Dictionary iLayoutToCoseSublayoutNode = new(); - - /// - /// abstract see city settings - /// - public AbstractSEECity Settings; - - /// - /// the edges of the sublayout - /// - private readonly ICollection edges = new List(); - - public Vector3 LayoutScale { get => layoutScale; set => layoutScale = value; } - - public Vector3 RootNodeRealScale { get => rootNodeRealScale; set => rootNodeRealScale = value; } - - public Vector3 LayoutOffset { get => layoutOffset; set => layoutOffset = value; } - - /// - /// constructor - /// - /// the sublayout node - /// the groundlevel for the nodes - /// the underlying graph - /// abstract see city settings - public Sublayout(SublayoutLayoutNode sublayout, float groundLevel, Graph graph, AbstractSEECity settings) - { - nodeLayout = sublayout.NodeLayout; - this.groundLevel = groundLevel; - this.sublayout = sublayout; - this.graph = graph; - this.Settings = settings; - - if (sublayout.Node.Children().Count > 0) - { - sublayoutNodes = CalculateNodesForSublayout(); - - foreach (ILayoutNode layoutNode in sublayoutNodes) - { - ILayoutNode sublayoutNode = (layoutNode as LayoutSublayoutNode).Node; - sublayoutNode.IsSublayoutNode = true; - } - } - - edges = graph.ConnectingEdges(sublayoutNodes); - sublayout.Node.Sublayout = this; - } - - - /// - /// Calculates all nodes needed for a sublayout with this graphs parent node as the sublayouts root node - /// - /// a collection with ILayoutSublayoutNodes - public ICollection CalculateNodesForSublayout() - { - List nodesForLayout = new List(sublayout.Nodes); - nodesForLayout.Remove(sublayout.Node); - ICollection sublayoutNodes = ConvertToCoseSublayoutNodes(nodesForLayout); - - if (sublayout.NodeLayout.GetModel().OnlyLeaves) - { - return sublayoutNodes; - } - else - { - sublayoutNodes.Add(new LayoutSublayoutNode(sublayout.Node, iLayoutToCoseSublayoutNode)); - - // bei einem subsubLayout wird der root wieder hinzugefügt - foreach (ILayoutNode node in sublayout.RemovedChildren) - { - if (node.IsSublayoutRoot) - { - sublayoutNodes.Add(new LayoutSublayoutNode(node, new List(), true, node.Parent, node.Sublayout.layoutScale, iLayoutToCoseSublayoutNode)); - } - } - } - return sublayoutNodes; - } - - /// - /// Converts a layoutNode to a layout node used for the sublayout calculation - /// - /// - /// a collection with ILayoutSublayoutNodes - private ICollection ConvertToCoseSublayoutNodes(List layoutNodes) - { - List sublayoutNodes = new List(); - layoutNodes.ForEach(layoutNode => - { - sublayoutNodes.Add(new LayoutSublayoutNode(layoutNode, iLayoutToCoseSublayoutNode)); - }); - - return sublayoutNodes; - } - - /// - /// Calculates and sets the nodes positions - /// - public void Layout() - { - Dictionary layout = CalculateSublayout(); - - //root.NodeObject.Parent = parentNodeObject; - - foreach (ILayoutNode layoutNode in layout.Keys) - { - ILayoutNode sublayoutNode = (layoutNode as LayoutSublayoutNode).Node; - NodeTransform transform = layout[layoutNode]; - - Vector3 position = transform.Position; - Vector3 scale = transform.Scale; - - sublayoutNode.RelativePosition = position; - sublayoutNode.CenterPosition = position; - sublayoutNode.LocalScale = scale; - sublayoutNode.Rotation = transform.Rotation; - - if (sublayoutNode.IsSublayoutRoot) - { - if (sublayoutNode == sublayout.Node) - { - LayoutScale = scale; - } - else - { - foreach (ILayoutNode subNode in sublayoutNode.Sublayout.sublayoutNodes) - { - ILayoutNode subSubNode = (subNode as LayoutSublayoutNode).Node; - - subSubNode.Rotation = sublayoutNode.Rotation; - - if (subSubNode != sublayoutNode) - { - subSubNode.SetOrigin(); - subSubNode.RelativePosition = subSubNode.CenterPosition; - - sublayoutNodes.Add(new LayoutSublayoutNode(subSubNode, iLayoutToCoseSublayoutNode)); - - } - } - sublayoutNode.IsSublayoutRoot = false; - } - } - } - - if (!sublayout.NodeLayout.GetModel().InnerNodesEncloseLeafNodes) - { - Vector2 leftLowerCorner = new Vector2(Mathf.Infinity, Mathf.NegativeInfinity); - Vector2 rightUpperCorner = new Vector2(Mathf.NegativeInfinity, Mathf.Infinity); - - Vector2 leftLowerCornerNode; - Vector2 rightUpperCornerNode; - - foreach (ILayoutNode layoutNode in sublayoutNodes) - { - ILayoutNode sublayoutNode = (layoutNode as LayoutSublayoutNode).Node; - - leftLowerCornerNode = new Vector2() - { - x = sublayoutNode.CenterPosition.x - sublayoutNode.LocalScale.x / 2, - y = sublayoutNode.CenterPosition.z + sublayoutNode.LocalScale.z / 2, - }; - - rightUpperCornerNode = new Vector2() - { - x = sublayoutNode.CenterPosition.x + sublayoutNode.LocalScale.x / 2, - y = sublayoutNode.CenterPosition.z - sublayoutNode.LocalScale.z / 2, - }; - - - if (leftLowerCorner.x > leftLowerCornerNode.x) - { - leftLowerCorner.x = leftLowerCornerNode.x; - } - - if (rightUpperCorner.x < rightUpperCornerNode.x) - { - rightUpperCorner.x = rightUpperCornerNode.x; - } - - if (rightUpperCorner.y > rightUpperCornerNode.y) - { - rightUpperCorner.y = rightUpperCornerNode.y; - } - - if (leftLowerCorner.y < leftLowerCornerNode.y) - { - leftLowerCorner.y = leftLowerCornerNode.y; - } - } - - Vector3 scale = new Vector3 - { - x = rightUpperCorner.x - leftLowerCorner.x, - z = leftLowerCorner.y - rightUpperCorner.y - }; - - Vector3 position = new Vector3 - { - x = leftLowerCorner.x + scale.x / 2, - z = rightUpperCorner.y + scale.z / 2 - }; - - LayoutScale = scale; - - if (!nodeLayout.GetModel().OnlyLeaves) - { - rootNodeRealScale = sublayout.Node.LocalScale; - LayoutOffset = position - sublayout.Node.CenterPosition; - } - - sublayout.Node.LocalScale = scale; - sublayout.Node.CenterPosition = position; - sublayout.Node.IsSublayoutNode = true; - } - - SetCoseNodeToLayoutPosition(); - } - - /// - /// sets the sublayout node position relativ to its root node - /// - private void SetCoseNodeToLayoutPosition() - { - List nodes = new List(sublayout.Nodes); - nodes.AddRange(sublayout.RemovedChildren); - nodes.Remove(sublayout.Node); - - nodes.ForEach(node => - { - node.SetRelative(sublayout.Node); - }); - } - - /// - /// Calculates the sublayout positions - /// - /// a mapping from iLayoutNode to the calcualted nodeTransform - private Dictionary CalculateSublayout() - { - NodeLayout layout = CoseHelper.GetNodelayout(nodeLayout, groundLevel, Settings); - if (layout.UsesEdgesAndSublayoutNodes()) - { - return layout.Layout(sublayoutNodes, edges, new List()); - } - else - { - return layout.Layout(sublayoutNodes); - } - } - } -} - diff --git a/Assets/SEE/Layout/Sublayout.cs.meta b/Assets/SEE/Layout/Sublayout.cs.meta deleted file mode 100644 index 9d8bcc9d83..0000000000 --- a/Assets/SEE/Layout/Sublayout.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 57f6c07d967c7b0479c35a65a89021ea -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/SEE/Layout/Utils/LCAFinder.cs b/Assets/SEE/Layout/Utils/LCAFinder.cs index ba50fedaa6..f5561b47a9 100644 --- a/Assets/SEE/Layout/Utils/LCAFinder.cs +++ b/Assets/SEE/Layout/Utils/LCAFinder.cs @@ -1,32 +1,64 @@ using System; using System.Collections.Generic; -using UnityEngine; - namespace SEE.Layout.Utils { /// /// Computes the lowest common ancestors (LCA) in a rooted tree or a forest based on - /// the algorithm by Berkman, Omer and Vishkin, Uzi(1993), "Recursive Star-Tree + /// the algorithm by Berkman, Omer and Vishkin, Uzi (1993), "Recursive Star-Tree /// Parallel Data Structure", SIAM Journal on Computing, 22 (2): 221–242. /// public class LCAFinder where HNode : IHierarchyNode { + /// + /// The maximum depth of the tree. + /// private uint maxLevel; + /// + /// Mapping of nodes onto their tree index. + /// private Dictionary nodeMap; + + /// + /// The list of nodes in the tree. + /// private HNode[] indexList; + /// + /// The Euler tour through the tree. + /// private int[] eulerTour; + /// + /// The length of the Euler tour. + /// private int tourLength; + /// + /// The component number of each node in the Euler tour. + /// private int numberComponent; + /// + /// The tree number of each node in the Euler tour. + /// private int[] tree; + /// + /// The level of each node in the Euler tour. + /// private int[] level; + /// + /// The representative of each node in the Euler tour. + /// private int[] representative; - private int[,] rmq; // two-dimensional array + /// + /// The two-dimensional Range Minimum Query (RMQ) data structure. + /// + private int[,] rmq; + /// + /// The logarithm base 2 of the length of the Euler tour. + /// private int[] log2; /// @@ -38,10 +70,12 @@ public LCAFinder(HNode root) { if (root == null) { - throw new System.ArgumentNullException("Root must not be null."); + throw new ArgumentNullException("Root must not be null."); } - ICollection roots = new List(); - roots.Add(root); + ICollection roots = new List + { + root + }; Run(roots); } @@ -51,86 +85,23 @@ public LCAFinder(HNode root) /// has at most one parent). /// /// roots of the forest + /// thrown if is empty public LCAFinder(ICollection roots) { if (roots.Count == 0) { - throw new System.Exception("Empty set of roots given."); + throw new Exception("Empty set of roots given."); } Run(roots); } - private void CheckTree(ICollection roots) - { - HashSet visited = new HashSet(); - foreach (HNode root in roots) - { - CheckTree(root, visited); - } - } - - private void CheckTree(HNode node, HashSet visited) - { - if (visited.Contains(node)) - { - // node was already visited - throw new Exception("Input is not a tree. Node " + node + " can be reached more than once."); - } - else - { - visited.Add(node); - HNode parent = node.Parent; - // We should have visited the parent already in this pre-order depth-first traversal. - if (parent != null && !visited.Contains(parent)) - { - throw new Exception("Parent in tree is inconsistent. Violating node: " + parent); - } - foreach (HNode child in node.Children()) - { - // Does child also believe it is a child of node? - if (!ReferenceEquals(child.Parent, node)) - { - throw new Exception("Parenting in tree is inconsistent: Child " + child + " is not a child of node " + parent); - } - CheckTree(child, visited); - } - } - } - - /// - /// Yields the floor of the binary logarithm of n. - /// - /// the input number - /// floor of the binary logarithm - private static uint Log2(uint n) - { - n |= (n >> 1); - n |= (n >> 2); - n |= (n >> 4); - n |= (n >> 8); - n |= (n >> 16); - - return (uint)(NumBitsSet(n) - 1); - } - - private static int NumBitsSet(uint x) - { - x -= ((x >> 1) & 0x55555555); - x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); - x = (((x >> 4) + x) & 0x0f0f0f0f); - x += (x >> 8); - x += (x >> 16); - - return (int)(x & 0x0000003f); - } - /// /// Runs the preprocessing step to find the LCA in O(|V| log(|V|)) time and space. /// - /// roots of the forest + /// roots of the forest private void Run(ICollection roots) { - CheckTree(roots); + // CheckTree(roots); int numberOfNodes = MapAllNodes(roots); maxLevel = 1 + Log2((uint)numberOfNodes); DetermineEulerTours(roots, numberOfNodes); @@ -139,10 +110,11 @@ private void Run(ICollection roots) /// /// Creates the mapping of nodes onto integers and the index list. /// + /// roots of the forest private int MapAllNodes(ICollection roots) { ICollection allNodes = AllNodes(roots); - NodeToIntegerMap nodeToIntegerMapping = new NodeToIntegerMap(allNodes); + NodeToIntegerMap nodeToIntegerMapping = new(allNodes); nodeMap = nodeToIntegerMapping.NodeMap(); indexList = nodeToIntegerMapping.IndexList(); return allNodes.Count; @@ -155,8 +127,8 @@ private int MapAllNodes(ICollection roots) /// and their transitive descendants private static ICollection AllNodes(ICollection roots) { - List result = new List(roots); - Queue todos = new Queue(roots); + List result = new(roots); + Queue todos = new(roots); while (todos.Count > 0) { HNode node = todos.Dequeue(); @@ -178,9 +150,9 @@ private static ICollection AllNodes(ICollection roots) private void DepthFirstTraversal(int n, int level) { // List of nodes already visited - HashSet visited = new HashSet(); + HashSet visited = new(); - Stack> stack = new Stack>(); + Stack> stack = new(); stack.Push(Pair.Of(n, level)); while (stack.Count > 0) @@ -220,7 +192,7 @@ private void DepthFirstTraversal(int n, int level) } /// - /// Determines the RMQ. See the paper. + /// Determines the Range Minimum Query (RMQ). See the paper. /// private void DetermineRMQ() { @@ -257,8 +229,11 @@ private void DetermineRMQ() /// /// Determines the Euler tours for all subtrees rooted by any of the given roots. - /// Computes eulerTour, level, and representative. + /// Computes , , , + /// , and . /// + /// list of root nodes + /// number of nodes in the forest private void DetermineEulerTours(ICollection roots, int numberOfNodes) { eulerTour = new int[2 * numberOfNodes]; @@ -279,8 +254,7 @@ private void DetermineEulerTours(ICollection roots, int numberOfNodes) } else { - Debug.LogError("LCSFinder: multiple roots in the same tree.\n"); - throw new System.Exception("LCSFinder: multiple roots in the same tree."); + throw new Exception("LCSFinder: multiple roots in the same tree."); } } @@ -308,16 +282,16 @@ private void DetermineEulerTours(ICollection roots, int numberOfNodes) /// /// first node /// second - /// + /// lowest common ancestor public HNode LCA(HNode nodeA, HNode nodeB) { if (!nodeMap.TryGetValue(nodeA, out int indexOfA)) { - throw new System.Exception("invalid vertex: " + nodeA); + throw new Exception("invalid vertex: " + nodeA); } if (!nodeMap.TryGetValue(nodeB, out int indexOfB)) { - throw new System.Exception("invalid vertex: " + nodeB); + throw new Exception("invalid vertex: " + nodeB); } // Check if a == b because lca(a, a) == a if (nodeA.Equals(nodeB)) @@ -328,16 +302,14 @@ public HNode LCA(HNode nodeA, HNode nodeB) // If a and b are in different components, they do not have an LCA if (tree[indexOfA] != tree[indexOfB] || tree[indexOfA] == 0) { - return default(HNode); + return default; } indexOfA = representative[indexOfA]; indexOfB = representative[indexOfB]; if (indexOfA > indexOfB) { - int swap = indexOfA; - indexOfA = indexOfB; - indexOfB = swap; + (indexOfB, indexOfA) = (indexOfA, indexOfB); } int l = log2[indexOfB - indexOfA + 1]; @@ -358,12 +330,12 @@ public HNode LCA(HNode nodeA, HNode nodeB) private class NodeToIntegerMap { /// - /// The mapping from nodes onto integers, i.e., the inverse of indexList. + /// The mapping from nodes onto integers, i.e., the inverse of . /// private readonly Dictionary nodeMap; /// - /// The mapping from integers onto nodes, i.e., the inverse of nodeMap. + /// The mapping from integers onto nodes, i.e., the inverse of . /// private readonly HNode[] indexList; @@ -386,7 +358,7 @@ public NodeToIntegerMap(ICollection nodes) } /// - /// Yields the mapping from nodes onto integers, i.e., the inverse of indexList. + /// Yields the mapping from nodes onto integers, i.e., the inverse of . /// /// a mapping from nodes onto integers public Dictionary NodeMap() @@ -395,7 +367,7 @@ public Dictionary NodeMap() } /// - /// Yields the mapping from integers onto nodes, i.e., the inverse of nodeMap. + /// Yields the mapping from integers onto nodes, i.e., the inverse of . /// /// mapping from integers onto nodes public HNode[] IndexList() @@ -403,5 +375,85 @@ public HNode[] IndexList() return indexList; } } + + #region Utils + /// + /// Yields the floor of the binary logarithm of n. + /// + /// the input number + /// floor of the binary logarithm + private static uint Log2(uint n) + { + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + + return (uint)(NumBitsSet(n) - 1); + } + + /// + /// Returns the number of 1 bits in integer . + /// + /// the integer whose 1 bits should be counted + /// number of 1 bits in integer + private static int NumBitsSet(uint x) + { + x -= ((x >> 1) & 0x55555555); + x = (((x >> 2) & 0x33333333) + (x & 0x33333333)); + x = (((x >> 4) + x) & 0x0f0f0f0f); + x += (x >> 8); + x += (x >> 16); + + return (int)(x & 0x0000003f); + } + #endregion Utils + + #region Debugging + /// + /// Checks if all trees rooted by a root listed in are valid trees + /// (nodes can be reached only once) and whether the parent-child information is consistent. + /// + /// This method can be used for debugging. + private static void CheckTree(ICollection roots) + { + HashSet visited = new(); + foreach (HNode root in roots) + { + CheckTree(root, visited); + } + + return; + + static void CheckTree(HNode node, HashSet visited) + { + if (visited.Contains(node)) + { + // node was already visited + throw new Exception("Input is not a tree. Node " + node + " can be reached more than once."); + } + else + { + visited.Add(node); + HNode parent = node.Parent; + // We should have visited the parent already in this pre-order depth-first traversal. + if (parent != null && !visited.Contains(parent)) + { + throw new Exception("Parent in tree is inconsistent. Violating node: " + parent); + } + foreach (HNode child in node.Children()) + { + // Does child also believe it is a child of node? + if (!ReferenceEquals(child.Parent, node)) + { + throw new Exception("Parenting in tree is inconsistent: Child " + child + " is not a child of node " + parent); + } + CheckTree(child, visited); + } + } + } + } + #endregion Debugging } } diff --git a/Assets/SEE/Net/Dashboard/DashboardRetriever.cs b/Assets/SEE/Net/Dashboard/DashboardRetriever.cs index 8913e37ec1..f69ac076fa 100644 --- a/Assets/SEE/Net/Dashboard/DashboardRetriever.cs +++ b/Assets/SEE/Net/Dashboard/DashboardRetriever.cs @@ -172,7 +172,7 @@ private async UniTask GetAtPathAsync(string path, Dictionary /// Initializes the video manager by obtaining a token and setting up the camera dropdown. + /// If this code is executed in an environment different from , + /// the object will be disabled. /// private void Start() { + // FIXME (#826): Rather than trying to obtain the token on Start, we should rather try that only + // if the user explicitly demands it (starts the face cam). Otherwise we might annoy + // the user with a failing request to the token server that is not needed. if (SceneSettings.InputType == PlayerInputType.DesktopPlayer) { SetupCameraDropdown(); @@ -294,7 +299,7 @@ private IEnumerator JoinRoom(string token) /// Coroutine to handle the asynchronous publishing process. private IEnumerator PublishVideo() { - if (room == null) + if (room == null || !room.IsConnected) { ShowNotification.Error("Livekit", "Not connected."); yield break; diff --git a/Assets/SEE/Tools/ReflexionAnalysis/Incremental.cs b/Assets/SEE/Tools/ReflexionAnalysis/Incremental.cs index 4970e85673..1e73051700 100644 --- a/Assets/SEE/Tools/ReflexionAnalysis/Incremental.cs +++ b/Assets/SEE/Tools/ReflexionAnalysis/Incremental.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Runtime.CompilerServices; using JetBrains.Annotations; -using SEE.DataModel; using SEE.DataModel.DG; using UnityEngine.Assertions; using static SEE.Tools.ReflexionAnalysis.ReflexionSubgraphs; diff --git a/Assets/SEE/Tools/ReflexionAnalysis/ReflexionGraph.cs b/Assets/SEE/Tools/ReflexionAnalysis/ReflexionGraph.cs index d6f4dd9816..547f38829f 100644 --- a/Assets/SEE/Tools/ReflexionAnalysis/ReflexionGraph.cs +++ b/Assets/SEE/Tools/ReflexionAnalysis/ReflexionGraph.cs @@ -222,9 +222,12 @@ IEnumerable EdgeIntersection(Graph aGraph, Graph anotherGraph) /// Disassembles the given into implementation, architecture, and mapping graphs, /// and returns them in this order. /// + /// The three resulting graphs are new graphs, that is, the nodes and edges are copies; they are not + /// shared with the disassembled graph. Graph elements in the resulting subgraphs can be mapped onto their + /// original corresponding graph elements in this graph by way of their ID. + /// /// Pre-condition: The given graph must have been assembled by . /// - /// Graph generated by /// 3-tuple consisting of (implementation, architecture, mapping) graph public (Graph implementation, Graph architecture, Graph mapping) Disassemble() { diff --git a/Assets/SEE/UI/RuntimeConfigMenu/RuntimeTabMenu.cs b/Assets/SEE/UI/RuntimeConfigMenu/RuntimeTabMenu.cs index 4a527fcb2f..23a8b5be91 100644 --- a/Assets/SEE/UI/RuntimeConfigMenu/RuntimeTabMenu.cs +++ b/Assets/SEE/UI/RuntimeConfigMenu/RuntimeTabMenu.cs @@ -12,7 +12,6 @@ using SEE.Game.City; using SEE.UI.Menu; using SEE.GO; -using SEE.Layout.NodeLayouts.Cose; using SEE.Net.Actions.RuntimeConfig; using SEE.Utils; using SimpleFileBrowser; @@ -626,7 +625,6 @@ private void CreateSetting(Func getter, string settingName, GameObject p // confirmed types where the nested fields should be edited case ColorRange: case ColorProperty: - case CoseGraphAttributes: case VisualNodeAttributes: case NodeLayoutAttributes: case EdgeLayoutAttributes: diff --git a/Assets/SEEPlayModeTests/TestKeywordInput.cs b/Assets/SEEPlayModeTests/TestKeywordInput.cs index 52c38c2896..29d43ccef3 100644 --- a/Assets/SEEPlayModeTests/TestKeywordInput.cs +++ b/Assets/SEEPlayModeTests/TestKeywordInput.cs @@ -35,7 +35,7 @@ public IEnumerator TestDialog() { LogAssert.ignoreFailingMessages = true; - KeywordInput input = new KeywordInput(keywords); + KeywordInput input = new(keywords); input.Register(OnPhraseRecognized); input.Start(); @@ -53,7 +53,7 @@ public IEnumerator TestDialog() private void OnPhraseRecognized(PhraseRecognizedEventArgs args) { // General information on what was recognized. - StringBuilder builder = new StringBuilder(); + StringBuilder builder = new(); builder.AppendFormat("{0} ({1}){2}", args.text, args.confidence, Environment.NewLine); builder.AppendFormat("\tTimestamp: {0}{1}", args.phraseStartTime, Environment.NewLine); builder.AppendFormat("\tDuration: {0} seconds{1}", args.phraseDuration.TotalSeconds, Environment.NewLine); diff --git a/Assets/SEEPlayModeTests/TestSEEGame.cs b/Assets/SEEPlayModeTests/TestSEEGame.cs index 3de76b0f6d..33c40b0569 100644 --- a/Assets/SEEPlayModeTests/TestSEEGame.cs +++ b/Assets/SEEPlayModeTests/TestSEEGame.cs @@ -175,7 +175,7 @@ private static void PressButton(string buttonPath) // Make sure the object is really holding a button. Assert.That(buttonObject.TryGetComponent(out Button _)); // Press the button. - ExecuteEvents.Execute(buttonObject.gameObject, new BaseEventData(EventSystem.current), ExecuteEvents.submitHandler); + ExecuteEvents.Execute(buttonObject, new BaseEventData(EventSystem.current), ExecuteEvents.submitHandler); } } } diff --git a/Assets/SEETests/TestConfigIO.cs b/Assets/SEETests/TestConfigIO.cs index 22248c5868..54c6a85238 100644 --- a/Assets/SEETests/TestConfigIO.cs +++ b/Assets/SEETests/TestConfigIO.cs @@ -1,14 +1,11 @@ using System.Collections.Generic; using System.IO; using NUnit.Framework; -using SEE.DataModel.DG; using SEE.Game; using SEE.Game.City; using SEE.GraphProviders; -using SEE.Layout.NodeLayouts.Cose; using SEE.Tools.RandomGraphs; using SEE.Utils.Config; -using SEE.Utils.Paths; using UnityEngine; namespace SEE.Utils @@ -701,7 +698,6 @@ private static void AbstractSEECityAttributesAreEqual(AbstractSEECity expected, AreEqualEdgeLayoutSettings(expected.EdgeLayoutSettings, actual.EdgeLayoutSettings); AreEqualEdgeSelectionSettings(expected.EdgeSelectionSettings, actual.EdgeSelectionSettings); AreEqualErosionSettings(expected.ErosionSettings, actual.ErosionSettings); - AreEqualCoseGraphSettings(expected.CoseGraphSettings, actual.CoseGraphSettings); AreEqual(expected.MarkerAttributes, actual.MarkerAttributes); } @@ -887,7 +883,6 @@ private static void WipeOutAbstractSEECityAttributes(AbstractSEECity city) WipeOutEdgeLayoutSettings(city); WipeOutEdgeSelectionSettings(city.EdgeSelectionSettings); WipeOutErosionSettings(city); - WipeOutCoseGraphSettings(city); WipeOutMarkerAttributes(city.MarkerAttributes); } @@ -907,52 +902,12 @@ private static void WipeOutMetricToColor(AbstractSEECity city) /// the city whose attributes are to be re-assigned private static void WipeOutNodeTypes(AbstractSEECity city) { - foreach (var settings in city.NodeTypes.Values) + foreach (VisualNodeAttributes settings in city.NodeTypes.Values) { WipeOutNodeSettings(settings); } } - private static void WipeOutCoseGraphSettings(AbstractSEECity city) - { - // CoseGraphSettings - city.CoseGraphSettings.EdgeLength++; - city.CoseGraphSettings.UseSmartIdealEdgeCalculation = !city.CoseGraphSettings.UseSmartIdealEdgeCalculation; - city.CoseGraphSettings.UseSmartMultilevelScaling = !city.CoseGraphSettings.UseSmartMultilevelScaling; - city.CoseGraphSettings.PerLevelIdealEdgeLengthFactor++; - city.CoseGraphSettings.UseSmartRepulsionRangeCalculation = !city.CoseGraphSettings.UseSmartRepulsionRangeCalculation; - city.CoseGraphSettings.GravityStrength++; - city.CoseGraphSettings.CompoundGravityStrength++; - city.CoseGraphSettings.RepulsionStrength++; - city.CoseGraphSettings.MultiLevelScaling = !city.CoseGraphSettings.MultiLevelScaling; - city.CoseGraphSettings.ListInnerNodeToggle = new Dictionary() { { "ID1", true }, { "ID2", false } }; - city.CoseGraphSettings.InnerNodeLayout = new Dictionary() { { "ID1", NodeLayoutKind.Manhattan }, { "ID2", NodeLayoutKind.Balloon } }; - city.CoseGraphSettings.InnerNodeShape = new Dictionary() { { "ID1", NodeShapes.Blocks }, { "ID2", NodeShapes.Cylinders } }; - city.CoseGraphSettings.LoadedForNodeTypes = new Dictionary() { { "ID1", false }, { "ID2", true } }; - city.CoseGraphSettings.UseCalculationParameter = !city.CoseGraphSettings.UseCalculationParameter; - city.CoseGraphSettings.UseIterativeCalculation = !city.CoseGraphSettings.UseIterativeCalculation; - } - - private static void AreEqualCoseGraphSettings(CoseGraphAttributes expected, CoseGraphAttributes actual) - { - // CoseGraphSettings - Assert.AreEqual(expected.EdgeLength, actual.EdgeLength); - Assert.AreEqual(expected.UseSmartIdealEdgeCalculation, actual.UseSmartIdealEdgeCalculation); - Assert.AreEqual(expected.UseSmartMultilevelScaling, actual.UseSmartMultilevelScaling); - Assert.AreEqual(expected.PerLevelIdealEdgeLengthFactor, actual.PerLevelIdealEdgeLengthFactor); - Assert.AreEqual(expected.UseSmartRepulsionRangeCalculation, actual.UseSmartRepulsionRangeCalculation); - Assert.AreEqual(expected.GravityStrength, actual.GravityStrength); - Assert.AreEqual(expected.CompoundGravityStrength, actual.CompoundGravityStrength); - Assert.AreEqual(expected.RepulsionStrength, actual.RepulsionStrength); - Assert.AreEqual(expected.MultiLevelScaling, actual.MultiLevelScaling); - CollectionAssert.AreEquivalent(expected.ListInnerNodeToggle, actual.ListInnerNodeToggle); - CollectionAssert.AreEquivalent(expected.InnerNodeLayout, actual.InnerNodeLayout); - CollectionAssert.AreEquivalent(expected.InnerNodeShape, actual.InnerNodeShape); - CollectionAssert.AreEquivalent(expected.LoadedForNodeTypes, actual.LoadedForNodeTypes); - Assert.AreEqual(expected.UseCalculationParameter, actual.UseCalculationParameter); - Assert.AreEqual(expected.UseIterativeCalculation, actual.UseIterativeCalculation); - } - private static void WipeOutErosionSettings(AbstractSEECity city) { city.ErosionSettings.ShowInnerErosions = !city.ErosionSettings.ShowInnerErosions; @@ -1043,7 +998,7 @@ private static void AreEqualEdgeSelectionSettings(EdgeSelectionAttributes expect private static void WipeOutNodeLayoutSettings(AbstractSEECity city) { - city.NodeLayoutSettings.Kind = NodeLayoutKind.CompoundSpringEmbedder; + city.NodeLayoutSettings.Kind = NodeLayoutKind.Balloon; city.NodeLayoutSettings.LayoutPath.Path = "no path found"; } diff --git a/Assets/SEETests/TestDashboard.cs b/Assets/SEETests/TestDashboard.cs index eee9ae13ff..eaae982c1c 100644 --- a/Assets/SEETests/TestDashboard.cs +++ b/Assets/SEETests/TestDashboard.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using SEE.Net.Dashboard.Model.Issues; using SEE.Net.Dashboard.Model.Metric; +using SEE.Utils; using UnityEngine; using UnityEngine.TestTools; @@ -20,11 +21,31 @@ public class TestDashboard * properties has to be created, because the currently existing SEE project is too dynamic to reliably test. */ + /// + /// The maximal amount of time to wait for a response from the dashboard. + /// + private const float timeout = 2f; + + /// + /// The game object holding a component, + /// which is used to retrieve data from the dashboard. This object will + /// be created and destroyed for each test. + /// + private GameObject retrieverObject; + [SetUp] public void SetUp() { - GameObject retrieverObject = new("Retriever"); - retrieverObject.AddComponent(); + retrieverObject = new("Retriever"); + DashboardRetriever retriever = retrieverObject.AddComponent(); + // Set timeout to 2 seconds to speed up tests. + retriever.TimeoutSeconds = timeout; + } + + [TearDown] + public void TearDown() + { + Destroyer.Destroy(retrieverObject); } [UnityTest] diff --git a/Assets/SEETests/TestLCAFinder.cs b/Assets/SEETests/TestLCAFinder.cs index 7ea4716afc..e1c443917e 100644 --- a/Assets/SEETests/TestLCAFinder.cs +++ b/Assets/SEETests/TestLCAFinder.cs @@ -28,9 +28,8 @@ private LNode NewVertex(string name = "") private class LNode : IHierarchyNode { - private LNode parent; + public LNode Parent { private set; get; } - public LNode Parent => parent; private int level; @@ -59,9 +58,15 @@ public ICollection Children() public void AddChild(LNode child) { - child.parent = this; + child.Parent = this; children.Add(child); } + + public void RemoveChild(LNode child) + { + children.Remove(child); + child.Parent = null; + } } [SetUp] @@ -110,7 +115,7 @@ public void TestSimple() public void TestChain() { // root - // | + // | // a // | // b @@ -142,7 +147,7 @@ public void TestMultiLevel() // a b c // /\ | /\ // a1 a2 b1 c1 c2 - // /\ + // /\ // c11 c12 LNode root = NewVertex("root"); @@ -189,7 +194,7 @@ public void TestForrest() // a b c // /\ | /\ // a1 a2 b1 c1 c2 - // /\ + // /\ // c11 c12 LNode r1 = NewVertex("r1"); diff --git a/Assets/SEETests/TestLayoutIO.cs b/Assets/SEETests/TestLayoutIO.cs index 2b877bed13..2fadbc326c 100644 --- a/Assets/SEETests/TestLayoutIO.cs +++ b/Assets/SEETests/TestLayoutIO.cs @@ -43,7 +43,7 @@ public void TestGVLWriteRead() ClearLayout(gameObjects, yIsStored); // Read the saved layout. - Dictionary readLayout = new LoadedNodeLayout(0, filename).Layout(gameObjects); + Dictionary readLayout = new LoadedNodeLayout(filename).Create(gameObjects, Vector3.zero, Vector2.one); //Dump(readLayout, 10); Assert.AreEqual(savedLayout.Count, readLayout.Count); // no gameObject added or removed @@ -63,7 +63,6 @@ public void TestGVLWriteRead() [Test] public void TestSLDWriteRead() { - float groundLevel = -1; // SLD contains the height (y co-ordinate). bool yIsStored = true; string filename = Path.GetTempFileName() + Filenames.SLDExtension; @@ -73,7 +72,7 @@ public void TestSLDWriteRead() ICollection layoutNodes = NodeCreator.CreateNodes(howManyRootNodes: 9, howDeeplyNested: 0); CalculateLayout(layoutNodes, - out Dictionary _, + out _, out Dictionary layoutMap); //Dump(layoutMap, 10, "Created layout (y relates to the ground)"); @@ -82,15 +81,14 @@ public void TestSLDWriteRead() { ICollection gameObjects = ToGameNodes(layoutMap); IO.SLDWriter.Save(filename, gameObjects); - //Dump(gameObjects, 10, "Saved layout (y relates to the center)"); + //Dump(gameObjects, 10, "Saved layout"); } ClearLayout(layoutNodes, yIsStored); // Read the saved layout. - // Note: groundLevel will be ignored when the layout was stored in SLD. - Dictionary readLayout = new LoadedNodeLayout(groundLevel, filename).Layout(layoutNodes); - //Dump(readLayout, 10, "Read layout (y relates to the ground)"); + Dictionary readLayout = new LoadedNodeLayout(filename).Create(layoutNodes, Vector3.zero, Vector2.one); + //Dump(readLayout, 10, "Read layout"); Assert.AreEqual(layoutMap.Count, readLayout.Count); // no gameObject added or removed // Now layoutMap and readLayout should be the same including @@ -102,6 +100,7 @@ public void TestSLDWriteRead() FileIO.DeleteIfExists(filename); } + // Returns a list of new game objects whose position and scale are retrieved from the given layoutNodes. static ICollection ToGameNodes(Dictionary layoutNodes) { ICollection result = new List(layoutNodes.Count); @@ -110,11 +109,7 @@ static ICollection ToGameNodes(Dictionary lay GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); go.name = layoutNode.Key; go.transform.localScale = layoutNode.Value.Scale; - // position.y of a NodeTransform relates to the ground, while a - // game objects position.y relates to the center; we need to lift it - Vector3 position = layoutNode.Value.Position; - position.y += go.transform.localScale.y / 2; - go.transform.position = position; + go.transform.position = layoutNode.Value.CenterPosition; result.Add(go); } return result; @@ -139,13 +134,13 @@ private static void ClearLayout(ICollection gameObjects, bool yIsSt { if (yIsStored) { - layoutNode.LocalScale = Vector3.zero; + layoutNode.AbsoluteScale = Vector3.zero; layoutNode.CenterPosition = Vector3.zero; } else { - layoutNode.LocalScale = new Vector3(0.0f, layoutNode.LocalScale.y, 0.0f); - layoutNode.CenterPosition = new Vector3(0.0f, layoutNode.LocalScale.y, 0.0f); + layoutNode.AbsoluteScale = new Vector3(0.0f, layoutNode.AbsoluteScale.y, 0.0f); + layoutNode.CenterPosition = new Vector3(0.0f, layoutNode.AbsoluteScale.y, 0.0f); } } } @@ -175,12 +170,12 @@ private static void LayoutsAreEqual(Dictionary readL Assert.That(readTransform.Scale.y, Is.EqualTo(savedTransform.Scale.y).Within(floatTolerance)); } Assert.That(readTransform.Scale.z, Is.EqualTo(savedTransform.Scale.z).Within(floatTolerance)); - Assert.That(readTransform.Position.x, Is.EqualTo(savedTransform.Position.x).Within(floatTolerance)); + Assert.That(readTransform.X, Is.EqualTo(savedTransform.X).Within(floatTolerance)); if (compareY) { - Assert.That(readTransform.Position.y, Is.EqualTo(savedTransform.Position.y).Within(floatTolerance)); + Assert.That(readTransform.CenterPosition.y, Is.EqualTo(savedTransform.CenterPosition.y).Within(floatTolerance)); } - Assert.That(readTransform.Position.z, Is.EqualTo(savedTransform.Position.z).Within(floatTolerance)); + Assert.That(readTransform.Z, Is.EqualTo(savedTransform.Z).Within(floatTolerance)); Assert.AreEqual(savedTransform.Rotation, readTransform.Rotation); } } @@ -199,8 +194,7 @@ private static void CalculateLayout out Dictionary layoutMap) { // Layout the nodes. - RectanglePackingNodeLayout packer = new(0.0f, 1.0f); - savedLayout = packer.Layout(gameObjects); + savedLayout = new RectanglePackingNodeLayout().Create(gameObjects, Vector3.zero, Vector2.one); // Apply the layout. layoutMap = new Dictionary(savedLayout.Count); @@ -208,12 +202,9 @@ private static void CalculateLayout { ILayoutNode node = entry.Key; NodeTransform transform = entry.Value; - node.LocalScale = transform.Scale; - Vector3 position = transform.Position; - // from ground to center position along the y axis - position.y += transform.Scale.y / 2.0f; - node.CenterPosition = position; - layoutMap[node.ID] = new NodeTransform(node.CenterPosition, node.LocalScale, node.Rotation); + node.AbsoluteScale = transform.Scale; + node.CenterPosition = transform.CenterPosition; + layoutMap[node.ID] = new NodeTransform(node.CenterPosition, node.AbsoluteScale, node.Rotation); } } @@ -328,8 +319,8 @@ private static void TestWriteReadLayout(string fileExtension) Assert.Fail("Untested layout format"); } // Read the saved layout. - LoadedNodeLayout loadedNodeLayout = new(0, filename); - Dictionary readLayout = loadedNodeLayout.Layout(new List()); + LoadedNodeLayout loadedNodeLayout = new(filename); + Dictionary readLayout = loadedNodeLayout.Create(new List(), Vector3.zero, Vector2.one); Assert.AreEqual(0, readLayout.Count); } finally diff --git a/Assets/SEETests/TestRectanglePacker.cs b/Assets/SEETests/TestRectanglePacker.cs index e324c8e7a3..5c9c4198dc 100644 --- a/Assets/SEETests/TestRectanglePacker.cs +++ b/Assets/SEETests/TestRectanglePacker.cs @@ -51,7 +51,7 @@ private static bool EqualLists(IList left, IList right) [Test] public void TestSplit() { - Vector2 totalSize = new Vector2(14, 12); + Vector2 totalSize = new(14, 12); PTree tree = new(Vector2.zero, totalSize); PNode A = tree.Root; @@ -60,7 +60,7 @@ public void TestSplit() Assert.That(A.Rectangle.Size, Is.EqualTo(totalSize)); // First split - Vector2 EL1size = new Vector2(8, 6); + Vector2 EL1size = new(8, 6); PNode result = tree.Split(A, EL1size); PNode B = A.Left; @@ -193,8 +193,6 @@ public void TestSplit() Assert.That(Fright.Rectangle.Size, Is.EqualTo(new Vector2(F.Rectangle.Size.x, F.Rectangle.Size.y - Fleft.Rectangle.Size.y))); Assert.That(EqualLists(tree.FreeLeaves, new List() { K, H, Fright }), Is.True); - - // Debug.Log(A.ToString() + "\n"); } /// @@ -205,9 +203,9 @@ public void TestLayout() { ICollection gameObjects = NodeCreator.CreateNodes(); - RectanglePackingNodeLayout packer = new RectanglePackingNodeLayout(0.0f, 1.0f); + RectanglePackingNodeLayout packer = new(); - Dictionary layout = packer.Layout(gameObjects); + Dictionary layout = packer.Create(gameObjects, Vector3.zero, Vector2.one); } } } diff --git a/Assets/Scenes/SEENewWorld.unity b/Assets/Scenes/SEENewWorld.unity index a8df404b18..819c6a3953 100644 --- a/Assets/Scenes/SEENewWorld.unity +++ b/Assets/Scenes/SEENewWorld.unity @@ -1626,133 +1626,30 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings - Entry: 7 - Data: 32|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle - Entry: 7 - Data: 33|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 7 - Data: 34|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib - - Name: - Entry: 8 - Data: - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 35|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 34 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 36|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 34 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 37|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 34 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - Name: DataProvider Entry: 7 - Data: 38|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + Data: 32|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 39|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + Data: 33|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 40|SEE.GraphProviders.AllGitBranchesSingleGraphProvider, SEE + Data: 34|SEE.GraphProviders.AllGitBranchesSingleGraphProvider, SEE - Name: PathGlobbing Entry: 7 - Data: 41|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, + Data: 35|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, mscorlib]], mscorlib - Name: comparer - Entry: 9 - Data: 34 + Entry: 7 + Data: 36|System.Collections.Generic.GenericEqualityComparer`1[[System.String, + mscorlib]], mscorlib + - Name: + Entry: 8 + Data: - Name: Entry: 12 Data: 1 @@ -1826,10 +1723,17 @@ MonoBehaviour: pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 LayoutPath: Root: 2 RelativePath: AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 0 AnimationKind: 2 @@ -2501,6 +2405,118 @@ Transform: type: 3} m_PrefabInstance: {fileID: 461318614} m_PrefabAsset: {fileID: 0} +--- !u!1001 &229995737 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_RootOrder + value: 141 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalPosition.x + value: -30.14087 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalPosition.y + value: 0.4470662 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalPosition.z + value: 9.369 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -4216859302048453862, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -927199367670048503, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_Name + value: Desk01 + objectReference: {fileID: 0} + - target: {fileID: -927199367670048503, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 100000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_Name + value: CloneCity + objectReference: {fileID: 0} + - target: {fileID: 100000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_StaticEditorFlags + value: 4294967295 + objectReference: {fileID: 0} + - target: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_RootOrder + value: 16 + objectReference: {fileID: 0} + - target: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_LocalPosition.x + value: 2.3 + objectReference: {fileID: 0} + - target: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_LocalPosition.z + value: -12.603 + objectReference: {fileID: 0} + - target: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: + - targetCorrespondingSourceObject: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + insertIndex: -1 + addedObject: {fileID: 407024183} + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 616cd0a1c5e06384e8441efb4837d445, type: 3} +--- !u!4 &229995738 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 400000, guid: 616cd0a1c5e06384e8441efb4837d445, + type: 3} + m_PrefabInstance: {fileID: 229995737} + m_PrefabAsset: {fileID: 0} --- !u!1001 &236072121 PrefabInstance: m_ObjectHideFlags: 0 @@ -4237,165 +4253,58 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings + - Name: DataProvider Entry: 7 - Data: 68|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle + Data: 68|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + - Name: Pipeline Entry: 7 - Data: 69|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer + Data: 69|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + SEE]], mscorlib + - Name: + Entry: 12 + Data: 2 + - Name: Entry: 7 - Data: 70|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib + Data: 70|SEE.GraphProviders.GXLSingleGraphProvider, SEE + - Name: Path + Entry: 7 + Data: 71|SEE.Utils.Paths.DataPath, SEE + - Name: Root + Entry: 3 + Data: 3 + - Name: RelativePath + Entry: 1 + Data: /JLGExample/CodeFacts.gxl.xz + - Name: AbsolutePath + Entry: 1 + Data: - Name: Entry: 8 Data: - Name: - Entry: 12 - Data: 0 + Entry: 8 + Data: - Name: - Entry: 13 + Entry: 7 + Data: 72|SEE.GraphProviders.JaCoCoGraphProvider, SEE + - Name: Path + Entry: 7 + Data: 73|SEE.Utils.Paths.DataPath, SEE + - Name: Root + Entry: 3 + Data: 3 + - Name: RelativePath + Entry: 1 + Data: /JLGExample/jacoco.xml + - Name: AbsolutePath + Entry: 1 Data: - Name: Entry: 8 Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 71|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 72|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 73|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - - Name: DataProvider - Entry: 7 - Data: 74|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - - Name: Pipeline - Entry: 7 - Data: 75|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, - SEE]], mscorlib - - Name: - Entry: 12 - Data: 2 - - Name: - Entry: 7 - Data: 76|SEE.GraphProviders.GXLSingleGraphProvider, SEE - - Name: Path - Entry: 7 - Data: 77|SEE.Utils.Paths.DataPath, SEE - - Name: Root - Entry: 3 - Data: 3 - - Name: RelativePath - Entry: 1 - Data: /JLGExample/CodeFacts.gxl.xz - - Name: AbsolutePath - Entry: 1 - Data: - - Name: - Entry: 8 - Data: - - Name: - Entry: 8 - Data: - - Name: - Entry: 7 - Data: 78|SEE.GraphProviders.JaCoCoGraphProvider, SEE - - Name: Path - Entry: 7 - Data: 79|SEE.Utils.Paths.DataPath, SEE - - Name: Root - Entry: 3 - Data: 3 - - Name: RelativePath - Entry: 1 - Data: /JLGExample/jacoco.xml - - Name: AbsolutePath - Entry: 1 - Data: - - Name: - Entry: 8 - Data: - - Name: - Entry: 8 - Data: + Entry: 8 + Data: - Name: Entry: 13 Data: @@ -4433,10 +4342,17 @@ MonoBehaviour: pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 LayoutPath: Root: 2 RelativePath: AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 0 AnimationKind: 2 @@ -7931,129 +7847,22 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings - Entry: 7 - Data: 110|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle - Entry: 7 - Data: 111|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 7 - Data: 112|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib - - Name: - Entry: 8 - Data: - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 113|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 112 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 114|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 112 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 115|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 112 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - Name: DataProvider Entry: 7 - Data: 116|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + Data: 110|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 117|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + Data: 111|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 118|SEE.GraphProviders.GXLSingleGraphProvider, SEE + Data: 112|SEE.GraphProviders.GXLSingleGraphProvider, SEE - Name: Path Entry: 7 - Data: 119|SEE.Utils.Paths.DataPath, SEE + Data: 113|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -8106,10 +7915,17 @@ MonoBehaviour: pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 LayoutPath: Root: 2 RelativePath: AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 0 AnimationKind: 0 @@ -9482,6 +9298,824 @@ PrefabInstance: m_AddedGameObjects: [] m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 9ae402f151ff86c41be9bfccb69a6cc4, type: 3} +--- !u!1 &407024182 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 407024183} + - component: {fileID: 407024189} + - component: {fileID: 407024188} + - component: {fileID: 407024187} + - component: {fileID: 407024186} + - component: {fileID: 407024185} + - component: {fileID: 407024184} + m_Layer: 0 + m_Name: CloneCity + m_TagString: Code City + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &407024183 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + serializedVersion: 2 + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 45.8, z: 0} + m_LocalScale: {x: 147.20435, y: 0.00018599132, z: 321.01263} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 229995738} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &407024184 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 253abae38e5d8014abb73913836a3d5f, type: 3} + m_Name: + m_EditorClassIdentifier: + serializationData: + SerializedFormat: 2 + SerializedBytes: + ReferencedUnityObjects: [] + SerializedBytesString: + Prefab: {fileID: 0} + PrefabModificationsReferencedUnityObjects: [] + PrefabModifications: [] + SerializationNodes: + - Name: HierarchicalEdges + Entry: 7 + Data: 0|System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core + - Name: + Entry: 12 + Data: 4 + - Name: + Entry: 1 + Data: Enclosing + - Name: + Entry: 1 + Data: Belongs_To + - Name: + Entry: 1 + Data: Part_Of + - Name: + Entry: 1 + Data: Defined_In + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: HiddenEdges + Entry: 7 + Data: 1|System.Collections.Generic.HashSet`1[[System.String, mscorlib]], System.Core + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: NodeTypes + Entry: 7 + Data: 2|SEE.Game.City.NodeTypeVisualsMap, SEE + - Name: map + Entry: 7 + Data: 3|SEE.Game.City.VisualNodeAttributesMapping, SEE + - Name: comparer + Entry: 7 + Data: 4|System.Collections.Generic.GenericEqualityComparer`1[[System.String, + mscorlib]], mscorlib + - Name: + Entry: 8 + Data: + - Name: + Entry: 12 + Data: 3 + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: ROOT + - Name: $v + Entry: 7 + Data: 5|SEE.Game.City.VisualNodeAttributes, SEE + - Name: IsRelevant + Entry: 5 + Data: true + - Name: Shape + Entry: 3 + Data: 0 + - Name: MetricToLength + Entry: 7 + Data: 6|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 3 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: ColorProperty + Entry: 7 + Data: 7|SEE.Game.City.ColorProperty, SEE + - Name: Property + Entry: 3 + Data: 0 + - Name: TypeColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 0.3412 + - Name: + Entry: 4 + Data: 0.7216 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: ByLevel + Entry: 5 + Data: true + - Name: ColorMetric + Entry: 1 + Data: + - Name: + Entry: 8 + Data: + - Name: MinimalBlockLength + Entry: 4 + Data: 0.001 + - Name: MaximalBlockLength + Entry: 4 + Data: 1 + - Name: AntennaSettings + Entry: 7 + Data: 8|SEE.Game.City.AntennaAttributes, SEE + - Name: AntennaSections + Entry: 7 + Data: 9|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: LabelSettings + Entry: 7 + Data: 10|SEE.Game.LabelAttributes, SEE + - Name: Show + Entry: 5 + Data: true + - Name: Distance + Entry: 4 + Data: 0.2 + - Name: FontSize + Entry: 4 + Data: 0.4 + - Name: AnimationFactor + Entry: 4 + Data: 0.5 + - Name: LabelAlpha + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: OutlineWidth + Entry: 4 + Data: 1 + - Name: ShowNames + Entry: 5 + Data: false + - Name: AllowManualResize + Entry: 5 + Data: false + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: File + - Name: $v + Entry: 7 + Data: 11|SEE.Game.City.VisualNodeAttributes, SEE + - Name: IsRelevant + Entry: 5 + Data: true + - Name: Shape + Entry: 3 + Data: 1 + - Name: MetricToLength + Entry: 7 + Data: 12|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 3 + - Name: + Entry: 1 + Data: Metric.Number_of_Tokens + - Name: + Entry: 1 + Data: Metric.LOC + - Name: + Entry: 1 + Data: Metric.Number_of_Tokens + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: ColorProperty + Entry: 7 + Data: 13|SEE.Game.City.ColorProperty, SEE + - Name: Property + Entry: 3 + Data: 1 + - Name: TypeColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: ByLevel + Entry: 5 + Data: true + - Name: ColorMetric + Entry: 1 + Data: Metric.Clone_Rate + - Name: + Entry: 8 + Data: + - Name: MinimalBlockLength + Entry: 4 + Data: 0.001 + - Name: MaximalBlockLength + Entry: 4 + Data: 1 + - Name: AntennaSettings + Entry: 7 + Data: 14|SEE.Game.City.AntennaAttributes, SEE + - Name: AntennaSections + Entry: 7 + Data: 15|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: LabelSettings + Entry: 7 + Data: 16|SEE.Game.LabelAttributes, SEE + - Name: Show + Entry: 5 + Data: true + - Name: Distance + Entry: 4 + Data: 0.2 + - Name: FontSize + Entry: 4 + Data: 0.4 + - Name: AnimationFactor + Entry: 4 + Data: 0.5 + - Name: LabelAlpha + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: OutlineWidth + Entry: 4 + Data: 1 + - Name: ShowNames + Entry: 5 + Data: false + - Name: AllowManualResize + Entry: 5 + Data: false + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 7 + Data: + - Name: $k + Entry: 1 + Data: Directory + - Name: $v + Entry: 7 + Data: 17|SEE.Game.City.VisualNodeAttributes, SEE + - Name: IsRelevant + Entry: 5 + Data: true + - Name: Shape + Entry: 3 + Data: 1 + - Name: MetricToLength + Entry: 7 + Data: 18|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 3 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 1 + Data: 0.001 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: ColorProperty + Entry: 7 + Data: 19|SEE.Game.City.ColorProperty, SEE + - Name: Property + Entry: 3 + Data: 0 + - Name: TypeColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 0.4339623 + - Name: + Entry: 4 + Data: 0.419633329 + - Name: + Entry: 4 + Data: 0.419633329 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: ByLevel + Entry: 5 + Data: true + - Name: ColorMetric + Entry: 1 + Data: + - Name: + Entry: 8 + Data: + - Name: MinimalBlockLength + Entry: 4 + Data: 0.001 + - Name: MaximalBlockLength + Entry: 4 + Data: 1 + - Name: AntennaSettings + Entry: 7 + Data: 20|SEE.Game.City.AntennaAttributes, SEE + - Name: AntennaSections + Entry: 7 + Data: 21|System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: LabelSettings + Entry: 7 + Data: 22|SEE.Game.LabelAttributes, SEE + - Name: Show + Entry: 5 + Data: true + - Name: Distance + Entry: 4 + Data: 0.2 + - Name: FontSize + Entry: 4 + Data: 0.4 + - Name: AnimationFactor + Entry: 4 + Data: 0.5 + - Name: LabelAlpha + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: OutlineWidth + Entry: 4 + Data: 1 + - Name: ShowNames + Entry: 5 + Data: false + - Name: AllowManualResize + Entry: 5 + Data: false + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: MarkerAttributes + Entry: 7 + Data: 23|SEE.Game.City.MarkerAttributes, SEE + - Name: MarkerHeight + Entry: 4 + Data: 0.2 + - Name: MarkerWidth + Entry: 4 + Data: 0.01 + - Name: AdditionBeamColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: ChangeBeamColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 4 + Data: 0.921568632 + - Name: + Entry: 4 + Data: 0.0156862754 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: DeletionBeamColor + Entry: 7 + Data: UnityEngine.Color, UnityEngine.CoreModule + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 0 + - Name: + Entry: 4 + Data: 1 + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: MetricToColor + Entry: 7 + Data: 24|SEE.Game.City.ColorMap, SEE + - Name: map + Entry: 7 + Data: 25|SEE.Game.City.ColorRangeMapping, SEE + - Name: comparer + Entry: 9 + Data: 4 + - Name: + Entry: 12 + Data: 0 + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: DataProvider + Entry: 7 + Data: 26|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + - Name: Pipeline + Entry: 7 + Data: 27|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + SEE]], mscorlib + - Name: + Entry: 12 + Data: 1 + - Name: + Entry: 7 + Data: 28|SEE.GraphProviders.GXLSingleGraphProvider, SEE + - Name: Path + Entry: 7 + Data: 29|SEE.Utils.Paths.DataPath, SEE + - Name: Root + Entry: 3 + Data: 3 + - Name: RelativePath + Entry: 1 + Data: /net/CodeFacts.gxl.xz + - Name: AbsolutePath + Entry: 1 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 13 + Data: + - Name: + Entry: 8 + Data: + - Name: + Entry: 8 + Data: + LODCulling: 0.001 + ConfigurationPath: + Root: 3 + RelativePath: /net/net.cfg + AbsolutePath: + sourceCodeDirectory: + Root: 2 + RelativePath: + AbsolutePath: + SolutionPath: + Root: 2 + RelativePath: + AbsolutePath: + IgnoreSelfLoopsInLifting: 0 + MaximalAntennaSegmentHeight: 0.5 + AntennaWidth: 0.1 + BaseAnimationDuration: 1 + ProgressBar: 0 + ZScoreScale: 0 + ScaleOnlyLeafMetrics: 1 + NodeLayoutSettings: + Kind: 4 + IncrementalTreeMap: + LocalMovesDepth: 3 + LocalMovesBranchingLimit: 4 + pNorm: 1 + PaddingMm: 5 + GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 + LayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 + EdgeLayoutSettings: + Kind: 3 + AnimationKind: 2 + AnimateInnerEdges: 1 + AnimateTransitiveSourceEdges: 0 + AnimateTransitiveTargetEdges: 0 + EdgeWidth: 0.01 + EdgesAboveBlocks: 1 + Tension: 0.85 + EdgeSelectionSettings: + TubularSegments: 50 + Radius: 0.005 + RadialSegments: 8 + AreSelectable: 1 + ErosionSettings: + ShowInnerErosions: 0 + ShowLeafErosions: 0 + ErosionScalingFactor: 1.5 + ShowDashboardIssuesInCodeWindow: 0 + ArchitectureIssue: Metric.Architecture_Violations + CloneIssue: Metric.Clone + CycleIssue: Metric.Cycle + DeadCodeIssue: Metric.Dead_Code + MetricIssue: Metric.Metric + StyleIssue: Metric.Style + UniversalIssue: Metric.Universal + LspHint: Metric.LSP_Hint + LspInfo: Metric.LSP_Info + LspWarning: Metric.LSP_Warning + LspError: Metric.LSP_Error + ArchitectureIssueSum: Metric.Architecture_Violations_SUM + CloneIssueSum: Metric.Clone_SUM + CycleIssueSum: Metric.Cycle_SUM + DeadCodeIssueSum: Metric.Dead_Code_SUM + MetricIssueSum: Metric.Metric_SUM + StyleIssueSum: Metric.Style_SUM + UniversalIssueSum: Metric.Universal_SUM + BoardSettings: + LoadBoardOnStartup: 0 + BoardPath: + Root: 2 + RelativePath: + AbsolutePath: +--- !u!114 &407024185 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37219dcb41cd2df49bc7987f17f6fff9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &407024186 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7623b0249cfceff40b25a7b4ea3b89f4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &407024187 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2e5d4facdf0010e4898868f60a952c2b, type: 3} + m_Name: + m_EditorClassIdentifier: + HeightOffset: 0.0010616779 +--- !u!65 &407024188 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &407024189 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 407024182} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 800ec33a9c0fe564b9b72cdd97dc8d9e, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!1001 &409247203 PrefabInstance: m_ObjectHideFlags: 0 @@ -13235,129 +13869,22 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings - Entry: 7 - Data: 122|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle - Entry: 7 - Data: 123|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 7 - Data: 124|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib - - Name: - Entry: 8 - Data: - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 125|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 124 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 126|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 124 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 127|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 124 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - Name: DataProvider Entry: 7 - Data: 128|SEE.GraphProviders.MultiGraphPipelineProvider, SEE + Data: 122|SEE.GraphProviders.MultiGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 129|System.Collections.Generic.List`1[[SEE.GraphProviders.MultiGraphProvider, + Data: 123|System.Collections.Generic.List`1[[SEE.GraphProviders.MultiGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 130|SEE.GraphProviders.GXLEvolutionGraphProvider, SEE + Data: 124|SEE.GraphProviders.GXLEvolutionGraphProvider, SEE - Name: GXLDirectory Entry: 7 - Data: 131|SEE.Utils.Paths.DataPath, SEE + Data: 125|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -13413,10 +13940,17 @@ MonoBehaviour: pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 LayoutPath: Root: 2 RelativePath: AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 3 AnimationKind: 0 @@ -19855,129 +20389,22 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings - Entry: 7 - Data: 68|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle - Entry: 7 - Data: 69|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 7 - Data: 70|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib - - Name: - Entry: 8 - Data: - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 71|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 72|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 73|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 70 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - Name: DataProvider Entry: 7 - Data: 74|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + Data: 68|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 75|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + Data: 69|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 3 - Name: Entry: 7 - Data: 76|SEE.GraphProviders.GXLSingleGraphProvider, SEE + Data: 70|SEE.GraphProviders.GXLSingleGraphProvider, SEE - Name: Path Entry: 7 - Data: 77|SEE.Utils.Paths.DataPath, SEE + Data: 71|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -19995,23 +20422,23 @@ MonoBehaviour: Data: - Name: Entry: 7 - Data: 78|SEE.GraphProviders.MergeDiffGraphProvider, SEE + Data: 72|SEE.GraphProviders.MergeDiffGraphProvider, SEE - Name: OldGraph Entry: 7 - Data: 79|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + Data: 73|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 80|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + Data: 74|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 81|SEE.GraphProviders.GXLSingleGraphProvider, SEE + Data: 75|SEE.GraphProviders.GXLSingleGraphProvider, SEE - Name: Path Entry: 7 - Data: 82|SEE.Utils.Paths.DataPath, SEE + Data: 76|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -20041,10 +20468,10 @@ MonoBehaviour: Data: - Name: Entry: 7 - Data: 83|SEE.GraphProviders.JaCoCoGraphProvider, SEE + Data: 77|SEE.GraphProviders.JaCoCoGraphProvider, SEE - Name: Path Entry: 7 - Data: 84|SEE.Utils.Paths.DataPath, SEE + Data: 78|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -20097,10 +20524,17 @@ MonoBehaviour: pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 3 + Implementation: 3 LayoutPath: Root: 2 RelativePath: AbsolutePath: + ArchitectureLayoutPath: + Root: 2 + RelativePath: + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 0 AnimationKind: 2 @@ -24370,7 +24804,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 400000, guid: d61f1d3b65d8de342b340e6a67b1e19f, type: 3} propertyPath: m_LocalPosition.z - value: -12.25 + value: -16.333 objectReference: {fileID: 0} - target: {fileID: 400000, guid: d61f1d3b65d8de342b340e6a67b1e19f, type: 3} propertyPath: m_LocalRotation.x @@ -27415,8 +27849,8 @@ Transform: m_GameObject: {fileID: 2147363512} serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 45.8, z: 0} - m_LocalScale: {x: 147.20435, y: 0.00018599132, z: 321.01263} + m_LocalPosition: {x: 0, y: 45.799995, z: 0} + m_LocalScale: {x: 147.20435, y: 0.00018599132, z: 321.0126} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1462978786} @@ -29375,129 +29809,22 @@ MonoBehaviour: - Name: Entry: 8 Data: - - Name: CoseGraphSettings - Entry: 7 - Data: 86|SEE.Layout.NodeLayouts.Cose.CoseGraphAttributes, SEE - - Name: EdgeLength - Entry: 3 - Data: 20 - - Name: UseSmartIdealEdgeCalculation - Entry: 5 - Data: false - - Name: UseSmartMultilevelScaling - Entry: 5 - Data: false - - Name: PerLevelIdealEdgeLengthFactor - Entry: 4 - Data: 0.1 - - Name: UseSmartRepulsionRangeCalculation - Entry: 5 - Data: false - - Name: GravityStrength - Entry: 4 - Data: 0.8 - - Name: CompoundGravityStrength - Entry: 4 - Data: 1.5 - - Name: RepulsionStrength - Entry: 4 - Data: 50 - - Name: MultiLevelScaling - Entry: 5 - Data: false - - Name: ListInnerNodeToggle - Entry: 7 - Data: 87|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 7 - Data: 88|System.Collections.Generic.GenericEqualityComparer`1[[System.String, - mscorlib]], mscorlib - - Name: - Entry: 8 - Data: - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeLayout - Entry: 7 - Data: 89|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeLayoutKind, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 88 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: InnerNodeShape - Entry: 7 - Data: 90|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SEE.Game.City.NodeShapes, - SEE]], mscorlib - - Name: comparer - Entry: 9 - Data: 88 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: LoadedForNodeTypes - Entry: 7 - Data: 91|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Boolean, - mscorlib]], mscorlib - - Name: comparer - Entry: 9 - Data: 88 - - Name: - Entry: 12 - Data: 0 - - Name: - Entry: 13 - Data: - - Name: - Entry: 8 - Data: - - Name: UseCalculationParameter - Entry: 5 - Data: true - - Name: UseIterativeCalculation - Entry: 5 - Data: false - - Name: - Entry: 8 - Data: - Name: DataProvider Entry: 7 - Data: 92|SEE.GraphProviders.SingleGraphPipelineProvider, SEE + Data: 86|SEE.GraphProviders.SingleGraphPipelineProvider, SEE - Name: Pipeline Entry: 7 - Data: 93|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, + Data: 87|System.Collections.Generic.List`1[[SEE.GraphProviders.SingleGraphProvider, SEE]], mscorlib - Name: Entry: 12 Data: 1 - Name: Entry: 7 - Data: 94|SEE.GraphProviders.ReflexionGraphProvider, SEE + Data: 88|SEE.GraphProviders.ReflexionGraphProvider, SEE - Name: Architecture Entry: 7 - Data: 95|SEE.Utils.Paths.DataPath, SEE + Data: 89|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -29512,7 +29839,7 @@ MonoBehaviour: Data: - Name: Implementation Entry: 7 - Data: 96|SEE.Utils.Paths.DataPath, SEE + Data: 90|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -29527,7 +29854,7 @@ MonoBehaviour: Data: - Name: Mapping Entry: 7 - Data: 97|SEE.Utils.Paths.DataPath, SEE + Data: 91|SEE.Utils.Paths.DataPath, SEE - Name: Root Entry: 3 Data: 3 @@ -29576,17 +29903,24 @@ MonoBehaviour: ZScoreScale: 0 ScaleOnlyLeafMetrics: 1 NodeLayoutSettings: - Kind: 8 + Kind: 5 IncrementalTreeMap: LocalMovesDepth: 3 LocalMovesBranchingLimit: 4 pNorm: 1 PaddingMm: 5 GradientDescentPrecision: -4 + Architecture: 7 + Implementation: 3 LayoutPath: Root: 3 RelativePath: /reflexion/compiler/Layout.sld AbsolutePath: + ArchitectureLayoutPath: + Root: 3 + RelativePath: /reflexion/compiler/ArchitectureLayout.sld + AbsolutePath: + ArchitectureLayoutProportion: 0.6 EdgeLayoutSettings: Kind: 3 AnimationKind: 0 @@ -29666,7 +30000,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 2e5d4facdf0010e4898868f60a952c2b, type: 3} m_Name: m_EditorClassIdentifier: - HeightOffset: 0.0015002489 + HeightOffset: 0.0015009642 --- !u!65 &2147363518 BoxCollider: m_ObjectHideFlags: 0 @@ -30484,3 +30818,4 @@ SceneRoots: - {fileID: 1706202779} - {fileID: 1301391584} - {fileID: 1450271878} + - {fileID: 229995737} diff --git a/Assets/StreamingAssets/net/net.cfg b/Assets/StreamingAssets/net/net.cfg new file mode 100644 index 0000000000..45ad49fafe --- /dev/null +++ b/Assets/StreamingAssets/net/net.cfg @@ -0,0 +1,249 @@ +ConfigPath : { + Root : "StreamingAssets"; + RelativePath : "/net/net.cfg"; + AbsolutePath : ""; +}; +ProjectPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +SolutionPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +LODCulling : 0.00100000; +HierarchicalEdges : [ + "Enclosing"; + "Belongs_To"; + "Part_Of"; + "Defined_In"; +]; +HiddenEdges : [ +]; +NodeTypes : [ + { + nodeType : "ROOT"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.00000000; + Green : 0.34120000; + Blue : 0.72160000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "File"; + visualNodeAttributes : { + Shape : "Cylinders"; + IsRelevant : True; + MetricToLength : [ + "Metric.Number_of_Tokens"; + "Metric.LOC"; + "Metric.Number_of_Tokens"; + ]; + ColorProperty : { + Property : "Metric"; + TypeColor : { + Red : 1.00000000; + Green : 1.00000000; + Blue : 1.00000000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : "Metric.Clone_Rate"; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "Directory"; + visualNodeAttributes : { + Shape : "Cylinders"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.43396230; + Green : 0.41963330; + Blue : 0.41963330; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; +]; +IgnoreSelfLoopsInLifting : False; +MaximalAntennaSegmentHeight : 0.50000000; +AntennaWidth : 0.10000000; +BaseAnimationDuration : 1.00000000; +MetricToColor : [ +]; +ZScoreScale : False; +ScaleOnlyLeafMetrics : True; +ErosionIssues : { + ShowInnerErosions : False; + ShowLeafErosions : False; + ShowDashboardIssuesInCodeWindow : False; + ErosionScalingFactor : 1.50000000; + StyleIssue : "Metric.Style"; + UniversalIssue : "Metric.Universal"; + MetricIssue : "Metric.Metric"; + Dead_CodeIssue : "Metric.Dead_Code"; + CycleIssue : "Metric.Cycle"; + CloneIssue : "Metric.Clone"; + ArchitectureIssue : "Metric.Architecture_Violations"; + LspHint : "Metric.LSP_Hint"; + LspInfo : "Metric.LSP_Info"; + LspWarning : "Metric.LSP_Warning"; + LspError : "Metric.LSP_Error"; + StyleIssue_SUM : "Metric.Style_SUM"; + UniversalIssue_SUM : "Metric.Universal_SUM"; + MetricIssue_SUM : "Metric.Metric_SUM"; + Dead_CodeIssue_SUM : "Metric.Dead_Code_SUM"; + CycleIssue_SUM : "Metric.Cycle_SUM"; + CloneIssue_SUM : "Metric.Clone_SUM"; + ArchitectureIssue_SUM : "Metric.Architecture_Violations_SUM"; +}; +BoardSettings : { + LoadBoardOnStartup : False; + BoardPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; +}; +NodeLayout : { + NodeLayout : "CirclePacking"; + LayoutPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; + IncrementalTreeMap : { + LocalMovesDepth : 3; + LocalMovesBranchingLimit : 4; + PNorm : "P2Euclidean"; + GradientDescentPrecision : -4; + Padding : 5.00000000; + }; +}; +EdgeLayout : { + EdgeLayout : "Bundling"; + AnimationKind : "None"; + AnimateInnerEdges : True; + AnimateTransitiveSourceEdges : False; + AnimateTransitiveTargetEdges : False; + EdgeWidth : 0.01000000; + EdgesAboveBlocks : True; + Tension : 0.85000000; +}; +EdgeSelection : { + TubularSegments : 50; + Radius : 0.00500000; + RadialSegments : 8; + AreSelectable : True; +}; +Markers : { + MarkerHeight : 0.20000000; + MarkerWidth : 0.01000000; + AdditionBeamColor : { + Red : 0.00000000; + Green : 1.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; + ChangeBeamColor : { + Red : 1.00000000; + Green : 0.92156860; + Blue : 0.01568628; + Alpha : 1.00000000; + }; + DeletionBeamColor : { + Red : 0.00000000; + Green : 0.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; +}; +data : { + kind : "SinglePipeline"; + pipeline : [ + { + kind : "GXL"; + path : { + Root : "StreamingAssets"; + RelativePath : "/net/CodeFacts.gxl.xz"; + AbsolutePath : ""; + }; + }; + ]; +}; diff --git a/Assets/SEE/Layout/NodeLayouts/Cose.meta b/Assets/StreamingAssets/net/net.cfg.meta similarity index 67% rename from Assets/SEE/Layout/NodeLayouts/Cose.meta rename to Assets/StreamingAssets/net/net.cfg.meta index 7860e3e58e..b7ef72ce87 100644 --- a/Assets/SEE/Layout/NodeLayouts/Cose.meta +++ b/Assets/StreamingAssets/net/net.cfg.meta @@ -1,6 +1,5 @@ fileFormatVersion: 2 -guid: 29e9382f4d496594c96109159d4136ff -folderAsset: yes +guid: 664ba65ff6f8ab1418dd4bfd96ec0ec5 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld b/Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld new file mode 100644 index 0000000000..67384ee818 --- /dev/null +++ b/Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld @@ -0,0 +1,6 @@ +CompilerArch#ROOT;-1.68;0.9085671;-7.648314;0;0;0;1.473884;0.001;1.785303 +Main;-1.310055;0.9105672;-8.303521;0;0;0;0.6816972;0.001;0.4337917 +FrontEnd;-1.674104;0.9105672;-7.857195;0;0;0;1.410934;0.001;0.4106197 +MiddleEnd;-1.674104;0.9105672;-7.419796;0;0;0;1.410934;0.001;0.4106197 +BackEnd;-1.674104;0.9105672;-6.985967;0;0;0;1.410934;0.001;0.4106197 +Common;-2.039628;0.9105672;-8.303521;0;0;0;0.6816972;0.001;0.4337917 diff --git a/Assets/SEE/Layout/NodeLayouts/Cose/License.txt.meta b/Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld.meta similarity index 62% rename from Assets/SEE/Layout/NodeLayouts/Cose/License.txt.meta rename to Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld.meta index 494f093824..6ec12924c4 100644 --- a/Assets/SEE/Layout/NodeLayouts/Cose/License.txt.meta +++ b/Assets/StreamingAssets/reflexion/compiler/ArchitectureLayout.sld.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 9729121824427a74186cfa3582dcbceb -TextScriptImporter: +guid: 5e13974d9dc3a4349a604533d55c1329 +DefaultImporter: externalObjects: {} userData: assetBundleName: diff --git a/Assets/StreamingAssets/reflexion/compiler/Reflexion.cfg b/Assets/StreamingAssets/reflexion/compiler/Reflexion.cfg index 362ddfc8e6..b57d19c23f 100644 --- a/Assets/StreamingAssets/reflexion/compiler/Reflexion.cfg +++ b/Assets/StreamingAssets/reflexion/compiler/Reflexion.cfg @@ -413,6 +413,123 @@ NodeTypes : [ AllowManualResize : False; }; }; + { + nodeType : "ROOT"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.00000000; + Green : 0.34120000; + Blue : 0.72160000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "ARCHITECTURE"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 1.00000000; + Green : 0.75690000; + Blue : 0.02750000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : True; + }; + }; + { + nodeType : "IMPLEMENTATION"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.39220000; + Green : 0.78430000; + Blue : 0.39220000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : True; + }; + }; ]; IgnoreSelfLoopsInLifting : False; MaximalAntennaSegmentHeight : 0.10000000; @@ -491,12 +608,20 @@ BoardSettings : { }; }; NodeLayout : { - NodeLayout : "FromFile"; + NodeLayout : "Reflexion"; LayoutPath : { Root : "StreamingAssets"; RelativePath : "/reflexion/compiler/Layout.sld"; AbsolutePath : ""; }; + ImplementationLayout : "Treemap"; + ArchitectureLayout : "FromFile"; + ArchitectureLayoutPath : { + Root : "StreamingAssets"; + RelativePath : "/reflexion/compiler/ArchitectureLayout.sld"; + AbsolutePath : ""; + }; + ArchitectureLayoutProportion : 0.60000000; IncrementalTreeMap : { LocalMovesDepth : 3; LocalMovesBranchingLimit : 4; @@ -521,27 +646,6 @@ EdgeSelection : { RadialSegments : 8; AreSelectable : True; }; -CoseGraph : { - EdgeLength : 20; - UseSmartIdealEdgeCalculation : False; - UseSmartMultilevelScaling : False; - PerLevelIdealEdgeLengthFactor : 0.10000000; - UseSmartRepulsionRangeCalculation : False; - GravityStrength : 0.80000000; - CompoundGravityStrength : 1.50000000; - RepulsionStrength : 50.00000000; - MultiLevelScaling : False; - ListInnerNodeToggle : [ - ]; - InnerNodeLayout : [ - ]; - InnerNodeShape : [ - ]; - LoadedForNodeTypes : [ - ]; - UseCalculationParameter : True; - UseIterativeCalculation : False; -}; Markers : { MarkerHeight : 0.20000000; MarkerWidth : 0.01000000; diff --git a/Data/GXL/test-layouts/Nested.gxl b/Data/GXL/test-layouts/Nested.gxl new file mode 100644 index 0000000000..30c491ae05 --- /dev/null +++ b/Data/GXL/test-layouts/Nested.gxl @@ -0,0 +1,195 @@ + + + + + + + + 4 + + + 4 + + + 1 + + + EL4 + + + EL4 + + + + + + 5 + + + 3 + + + 1 + + + EL3 + + + EL3 + + + + + + 7 + + + 3 + + + 1 + + + EL2 + + + EL2 + + + + + + 8 + + + 6 + + + 1 + + + EL1 + + + EL1 + + + + + + D1 + + + D1 + + + + + + D2 + + + D2 + + + + + + D2A + + + D2A + + + + + + D2B + + + D2B + + + + + + D2AF1 + + + D2AF1 + + + 8 + + + 6 + + + 1 + + + + + + D2AF2 + + + D2AF2 + + + 8 + + + 6 + + + 1 + + + + + + D2BF1 + + + D2BF1 + + + 8 + + + 6 + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Data/GXL/test-layouts/Wettel-circular.cfg b/Data/GXL/test-layouts/Wettel-circular.cfg new file mode 100644 index 0000000000..e5b527e0ae --- /dev/null +++ b/Data/GXL/test-layouts/Wettel-circular.cfg @@ -0,0 +1,249 @@ +ConfigPath : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/Wettel-circular.cfg"; + AbsolutePath : ""; +}; +ProjectPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +SolutionPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +LODCulling : 0.00100000; +HierarchicalEdges : [ + "Enclosing"; + "Belongs_To"; + "Part_Of"; + "Defined_In"; +]; +HiddenEdges : [ +]; +NodeTypes : [ + { + nodeType : "ROOT"; + visualNodeAttributes : { + Shape : "Cylinders"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.00000000; + Green : 0.34120000; + Blue : 0.72160000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "Directory"; + visualNodeAttributes : { + Shape : "Cylinders"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.06608222; + Green : 0.93396230; + Blue : 0.14479780; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "File"; + visualNodeAttributes : { + Shape : "Cylinders"; + IsRelevant : True; + MetricToLength : [ + "Metric.Width"; + "Metric.Height"; + "Metric.Depth"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.97169810; + Green : 0.03208439; + Blue : 0.17481420; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; +]; +IgnoreSelfLoopsInLifting : False; +MaximalAntennaSegmentHeight : 0.50000000; +AntennaWidth : 0.10000000; +BaseAnimationDuration : 1.00000000; +MetricToColor : [ +]; +ZScoreScale : False; +ScaleOnlyLeafMetrics : True; +ErosionIssues : { + ShowInnerErosions : False; + ShowLeafErosions : False; + ShowDashboardIssuesInCodeWindow : False; + ErosionScalingFactor : 1.50000000; + StyleIssue : "Metric.Style"; + UniversalIssue : "Metric.Universal"; + MetricIssue : "Metric.Metric"; + Dead_CodeIssue : "Metric.Dead_Code"; + CycleIssue : "Metric.Cycle"; + CloneIssue : "Metric.Clone"; + ArchitectureIssue : "Metric.Architecture_Violations"; + LspHint : "Metric.LSP_Hint"; + LspInfo : "Metric.LSP_Info"; + LspWarning : "Metric.LSP_Warning"; + LspError : "Metric.LSP_Error"; + StyleIssue_SUM : "Metric.Style_SUM"; + UniversalIssue_SUM : "Metric.Universal_SUM"; + MetricIssue_SUM : "Metric.Metric_SUM"; + Dead_CodeIssue_SUM : "Metric.Dead_Code_SUM"; + CycleIssue_SUM : "Metric.Cycle_SUM"; + CloneIssue_SUM : "Metric.Clone_SUM"; + ArchitectureIssue_SUM : "Metric.Architecture_Violations_SUM"; +}; +BoardSettings : { + LoadBoardOnStartup : False; + BoardPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; +}; +NodeLayout : { + NodeLayout : "CirclePacking"; + LayoutPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; + IncrementalTreeMap : { + LocalMovesDepth : 3; + LocalMovesBranchingLimit : 4; + PNorm : "P2Euclidean"; + GradientDescentPrecision : -4; + Padding : 5.00000000; + }; +}; +EdgeLayout : { + EdgeLayout : "Bundling"; + AnimationKind : "None"; + AnimateInnerEdges : True; + AnimateTransitiveSourceEdges : False; + AnimateTransitiveTargetEdges : False; + EdgeWidth : 0.01000000; + EdgesAboveBlocks : True; + Tension : 0.85000000; +}; +EdgeSelection : { + TubularSegments : 50; + Radius : 0.00500000; + RadialSegments : 8; + AreSelectable : True; +}; +Markers : { + MarkerHeight : 0.20000000; + MarkerWidth : 0.01000000; + AdditionBeamColor : { + Red : 0.00000000; + Green : 1.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; + ChangeBeamColor : { + Red : 1.00000000; + Green : 0.92156860; + Blue : 0.01568628; + Alpha : 1.00000000; + }; + DeletionBeamColor : { + Red : 0.00000000; + Green : 0.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; +}; +data : { + kind : "SinglePipeline"; + pipeline : [ + { + kind : "GXL"; + path : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/Nested.gxl"; + AbsolutePath : ""; + }; + }; + ]; +}; diff --git a/Data/GXL/test-layouts/Wettel.cfg b/Data/GXL/test-layouts/Wettel.cfg new file mode 100644 index 0000000000..c92193816d --- /dev/null +++ b/Data/GXL/test-layouts/Wettel.cfg @@ -0,0 +1,249 @@ +ConfigPath : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/Wettel.cfg"; + AbsolutePath : ""; +}; +ProjectPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +SolutionPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +LODCulling : 0.00100000; +HierarchicalEdges : [ + "Enclosing"; + "Belongs_To"; + "Part_Of"; + "Defined_In"; +]; +HiddenEdges : [ +]; +NodeTypes : [ + { + nodeType : "ROOT"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.00000000; + Green : 0.34120000; + Blue : 0.72160000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "Directory"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 1.00000000; + Green : 1.00000000; + Blue : 1.00000000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "File"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "Metric.Width"; + "Metric.Height"; + "Metric.Depth"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 1.00000000; + Green : 1.00000000; + Blue : 1.00000000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; +]; +IgnoreSelfLoopsInLifting : False; +MaximalAntennaSegmentHeight : 0.50000000; +AntennaWidth : 0.10000000; +BaseAnimationDuration : 1.00000000; +MetricToColor : [ +]; +ZScoreScale : False; +ScaleOnlyLeafMetrics : True; +ErosionIssues : { + ShowInnerErosions : False; + ShowLeafErosions : False; + ShowDashboardIssuesInCodeWindow : False; + ErosionScalingFactor : 1.50000000; + StyleIssue : "Metric.Style"; + UniversalIssue : "Metric.Universal"; + MetricIssue : "Metric.Metric"; + Dead_CodeIssue : "Metric.Dead_Code"; + CycleIssue : "Metric.Cycle"; + CloneIssue : "Metric.Clone"; + ArchitectureIssue : "Metric.Architecture_Violations"; + LspHint : "Metric.LSP_Hint"; + LspInfo : "Metric.LSP_Info"; + LspWarning : "Metric.LSP_Warning"; + LspError : "Metric.LSP_Error"; + StyleIssue_SUM : "Metric.Style_SUM"; + UniversalIssue_SUM : "Metric.Universal_SUM"; + MetricIssue_SUM : "Metric.Metric_SUM"; + Dead_CodeIssue_SUM : "Metric.Dead_Code_SUM"; + CycleIssue_SUM : "Metric.Cycle_SUM"; + CloneIssue_SUM : "Metric.Clone_SUM"; + ArchitectureIssue_SUM : "Metric.Architecture_Violations_SUM"; +}; +BoardSettings : { + LoadBoardOnStartup : False; + BoardPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; +}; +NodeLayout : { + NodeLayout : "RectanglePacking"; + LayoutPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; + IncrementalTreeMap : { + LocalMovesDepth : 3; + LocalMovesBranchingLimit : 4; + PNorm : "P2Euclidean"; + GradientDescentPrecision : -4; + Padding : 5.00000000; + }; +}; +EdgeLayout : { + EdgeLayout : "Bundling"; + AnimationKind : "None"; + AnimateInnerEdges : True; + AnimateTransitiveSourceEdges : False; + AnimateTransitiveTargetEdges : False; + EdgeWidth : 0.01000000; + EdgesAboveBlocks : True; + Tension : 0.85000000; +}; +EdgeSelection : { + TubularSegments : 50; + Radius : 0.00500000; + RadialSegments : 8; + AreSelectable : True; +}; +Markers : { + MarkerHeight : 0.20000000; + MarkerWidth : 0.01000000; + AdditionBeamColor : { + Red : 0.00000000; + Green : 1.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; + ChangeBeamColor : { + Red : 1.00000000; + Green : 0.92156860; + Blue : 0.01568628; + Alpha : 1.00000000; + }; + DeletionBeamColor : { + Red : 0.00000000; + Green : 0.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; +}; +data : { + kind : "SinglePipeline"; + pipeline : [ + { + kind : "GXL"; + path : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/Nested.gxl"; + AbsolutePath : ""; + }; + }; + ]; +}; diff --git a/Data/GXL/test-layouts/Wettel.gxl b/Data/GXL/test-layouts/Wettel.gxl new file mode 100644 index 0000000000..e9aba0af9e --- /dev/null +++ b/Data/GXL/test-layouts/Wettel.gxl @@ -0,0 +1,99 @@ + + + + + + + + D1 + + + D1 + + + + + + 8 + + + 6 + + + 1 + + + EL1 + + + EL1 + + + + + + EL2 + + + EL2 + + + 7 + + + 3 + + + 2 + + + + + + EL3 + + + EL3 + + + 5 + + + 3 + + + 3 + + + + + + EL4 + + + EL4 + + + 4 + + + 4 + + + 4 + + + + + + + + + + + + + + + + diff --git a/Data/GXL/test-layouts/test-layouts.cfg b/Data/GXL/test-layouts/test-layouts.cfg new file mode 100644 index 0000000000..9215861be9 --- /dev/null +++ b/Data/GXL/test-layouts/test-layouts.cfg @@ -0,0 +1,249 @@ +ConfigPath : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/test-layouts.cfg"; + AbsolutePath : ""; +}; +ProjectPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +SolutionPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; +}; +LODCulling : 0.00100000; +HierarchicalEdges : [ + "Enclosing"; + "Belongs_To"; + "Part_Of"; + "Defined_In"; +]; +HiddenEdges : [ +]; +NodeTypes : [ + { + nodeType : "ROOT"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.00000000; + Green : 0.34120000; + Blue : 0.72160000; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "Directory"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "0.001"; + "0.001"; + "0.001"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.04889644; + Green : 0.97169810; + Blue : 0.04125132; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; + { + nodeType : "File"; + visualNodeAttributes : { + Shape : "Blocks"; + IsRelevant : True; + MetricToLength : [ + "Metric.Width"; + "Metric.Height"; + "Metric.Depth"; + ]; + ColorProperty : { + Property : "Type"; + TypeColor : { + Red : 0.96226420; + Green : 0.03177289; + Blue : 0.03177289; + Alpha : 1.00000000; + }; + ByLevel : True; + ColorMetric : ""; + }; + MinimalBlockLength : 0.00100000; + MaximalBlockLength : 1.00000000; + LabelSettings : { + Show : True; + Distance : 0.20000000; + FontSize : 0.40000000; + AnimationDuration : 0.50000000; + LabelAlpha : 1.00000000; + }; + AntennnaSettings : { + AntennaSections : [ + ]; + }; + OutlineWidth : 1.00000000; + ShowNames : False; + AllowManualResize : False; + }; + }; +]; +IgnoreSelfLoopsInLifting : False; +MaximalAntennaSegmentHeight : 0.50000000; +AntennaWidth : 0.10000000; +BaseAnimationDuration : 1.00000000; +MetricToColor : [ +]; +ZScoreScale : False; +ScaleOnlyLeafMetrics : True; +ErosionIssues : { + ShowInnerErosions : False; + ShowLeafErosions : False; + ShowDashboardIssuesInCodeWindow : False; + ErosionScalingFactor : 1.50000000; + StyleIssue : "Metric.Style"; + UniversalIssue : "Metric.Universal"; + MetricIssue : "Metric.Metric"; + Dead_CodeIssue : "Metric.Dead_Code"; + CycleIssue : "Metric.Cycle"; + CloneIssue : "Metric.Clone"; + ArchitectureIssue : "Metric.Architecture_Violations"; + LspHint : "Metric.LSP_Hint"; + LspInfo : "Metric.LSP_Info"; + LspWarning : "Metric.LSP_Warning"; + LspError : "Metric.LSP_Error"; + StyleIssue_SUM : "Metric.Style_SUM"; + UniversalIssue_SUM : "Metric.Universal_SUM"; + MetricIssue_SUM : "Metric.Metric_SUM"; + Dead_CodeIssue_SUM : "Metric.Dead_Code_SUM"; + CycleIssue_SUM : "Metric.Cycle_SUM"; + CloneIssue_SUM : "Metric.Clone_SUM"; + ArchitectureIssue_SUM : "Metric.Architecture_Violations_SUM"; +}; +BoardSettings : { + LoadBoardOnStartup : False; + BoardPath : { + Root : "AssetsFolder"; + RelativePath : ""; + AbsolutePath : ""; + }; +}; +NodeLayout : { + NodeLayout : "RectanglePacking"; + LayoutPath : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/saved-modified-rectangle-packing.sld"; + AbsolutePath : ""; + }; + IncrementalTreeMap : { + LocalMovesDepth : 3; + LocalMovesBranchingLimit : 4; + PNorm : "P2Euclidean"; + GradientDescentPrecision : -4; + Padding : 5.00000000; + }; +}; +EdgeLayout : { + EdgeLayout : "Bundling"; + AnimationKind : "None"; + AnimateInnerEdges : True; + AnimateTransitiveSourceEdges : False; + AnimateTransitiveTargetEdges : False; + EdgeWidth : 0.01000000; + EdgesAboveBlocks : True; + Tension : 0.85000000; +}; +EdgeSelection : { + TubularSegments : 50; + Radius : 0.00500000; + RadialSegments : 8; + AreSelectable : True; +}; +Markers : { + MarkerHeight : 0.20000000; + MarkerWidth : 0.01000000; + AdditionBeamColor : { + Red : 0.00000000; + Green : 1.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; + ChangeBeamColor : { + Red : 1.00000000; + Green : 0.92156860; + Blue : 0.01568628; + Alpha : 1.00000000; + }; + DeletionBeamColor : { + Red : 0.00000000; + Green : 0.00000000; + Blue : 0.00000000; + Alpha : 1.00000000; + }; +}; +data : { + kind : "SinglePipeline"; + pipeline : [ + { + kind : "GXL"; + path : { + Root : "ProjectFolder"; + RelativePath : "/Data/GXL/test-layouts/Wettel.gxl"; + AbsolutePath : ""; + }; + }; + ]; +}; diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 7c88263265..0132e0d739 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,3 @@ m_EditorVersion: 6000.0.34f1 m_EditorVersionWithRevision: 6000.0.34f1 (5ab2d9ed9190) +