Beispiel #1
0
        /// <summary>
        /// Creates a new <see cref="FilteredGraphWrapper"/> that shows the currently visible original nodes.
        /// </summary>
        /// <remarks>
        /// Nodes without currently visible edges are also filtered out.
        /// </remarks>
        private FilteredGraphWrapper CreateFilteredView()
        {
            // create a new FilteredGraphWrapper that filters the original graph and shows only the currently visible nodes
            var filteredGraph = new FilteredGraphWrapper(OriginalGraph,
                                                         node => {
                node = aggregationHelper.GetPlaceholder(node);
                if (!AggregateGraph.Contains(node))
                {
                    return(false);
                }
                // also filter nodes without edges
                return(AggregateGraph.EdgesAt(node).Count(edge => !aggregationHelper.IsHierarchyEdge(edge)) > 0);
            });

            // set the node layouts for a smooth transition
            foreach (var node in filteredGraph.Nodes)
            {
                filteredGraph.SetNodeLayout(node, aggregationHelper.GetPlaceholder(node).Layout.ToRectD());
            }

            // reset any rotated labels
            foreach (var label in filteredGraph.Labels)
            {
                filteredGraph.SetLabelLayoutParameter(label, FreeNodeLabelModel.Instance.CreateDefaultParameter());
            }

            return(filteredGraph);
        }
        private void RegisterAggregationCallbacks()
        {
            Graph.NodeCreated += (sender, args) => {
                if (AggregateGraph.IsAggregationItem(args.Item))
                {
                    // add a label with the number of aggregated items to the new aggregation node
                    Graph.AddLabel(args.Item, AggregateGraph.GetAggregatedItems(args.Item).Count.ToString());
                }
            };

            Graph.EdgeCreated += (sender, args) => {
                var edge = args.Item;
                if (!AggregateGraph.IsAggregationItem(edge))
                {
                    return;
                }

                // add a label with the number of all original aggregated edges represented by the new aggregation edge
                var aggregatedEdgesCount = AggregateGraph.GetAllAggregatedOriginalItems(edge).Count;
                if (aggregatedEdgesCount > 1)
                {
                    Graph.AddLabel(edge, aggregatedEdgesCount.ToString());
                }

                // set the thickness to the number of aggregated edges
                Graph.SetStyle(edge,
                               new PolylineEdgeStyle {
                    Pen = new Pen(Brushes.Gray, 1 + aggregatedEdgesCount)
                });
            };
        }
 /// <summary>
 /// Copies the labels from <paramref name="source"/> to <paramref name="target"/>.
 /// </summary>
 /// <param name="source"></param>
 /// <param name="target"></param>
 private void CopyLabels(INode source, INode target)
 {
     foreach (var label in source.Labels)
     {
         AggregateGraph.AddLabel(target, label.Text, FreeNodeLabelModel.Instance.CreateDefaultParameter(), label.Style);
     }
 }
        /// <summary>
        /// Aggregates the nodes to a new aggregation node.
        /// </summary>
        /// <remarks>
        /// Adds a label with the number of aggregated nodes and adds labels
        /// to all created aggregation edges with the number of replaced original edges.
        /// </remarks>
        private void Aggregate <TKey>(IList <INode> nodes, TKey key, Func <TKey, INodeStyle> styleFactory)
        {
            var size   = Graph.NodeDefaults.Size * (1 + nodes.Count * 0.2);
            var layout = RectD.FromCenter(PointD.Origin, size);

            AggregateGraph.Aggregate(new ListEnumerable <INode>(nodes), layout, styleFactory(key));
        }
Beispiel #5
0
        /// <summary>
        /// Registers a listener to the <see cref="GraphInputMode.ItemClicked"/> event that toggles the aggregation of a node,
        /// runs a layout and sets the current item.
        /// </summary>
        private void InitializeToggleAggregation()
        {
            graphViewerInputMode.ClickableItems = GraphItemTypes.Node;
            graphViewerInputMode.ItemClicked   += async(sender, args) => {
                // prevent default behavior, which would select nodes that are no longer in the graph
                args.Handled = true;

                var node = (INode)args.Item;
                if (!AggregateGraph.IsAggregationItem(node))
                {
                    // is an original node -> only set current item
                    GraphControl.CurrentItem = node;
                    OnInfoPanelPropertiesChanged();
                    return;
                }

                // toggle the aggregation
                var affectedNodes = aggregationHelper.ToggleAggregation(node);

                // set the current item to the new aggregation node (which is the first in the list)
                GraphControl.CurrentItem = affectedNodes[0];

                // notify UI
                OnInfoPanelPropertiesChanged();

                // run layout
                await RunBalloonLayout(affectedNodes);
            };
        }
        /// <summary>
        /// Aggregates the <paramref name="aggregate"/> as well as all its children recursively.
        /// </summary>
        /// <remarks>
        /// Can be used to apply the initial aggregation. If this is not the initial aggregation run, it will reuse existing
        /// aggregation nodes.
        /// </remarks>
        /// <param name="aggregate">The "root" aggregate.</param>
        /// <returns>The aggregation node representing the passed <paramref name="aggregate"/></returns>
        public INode AggregateRecursively(NodeAggregation.Aggregate aggregate)
        {
            if (aggregate.Children.Count == 0)
            {
                return(aggregate.Node);
            }

            PointD originalCenter;

            if (aggregateToNode.TryGetValue(aggregate, out var node))
            {
                originalCenter = node.Layout.GetCenter();
                var aggregationInfo = (AggregationNodeInfo)node.Tag;
                if (aggregationInfo.IsAggregated)
                {
                    return(node);
                }
                else
                {
                    AggregateGraph.Separate(node);
                }
            }
            else
            {
                originalCenter = PointD.Origin;
            }

            var nodesToAggregate = aggregate.Children.Select(AggregateRecursively).ToList();

            if (aggregate.Node != null)
            {
                nodesToAggregate.Add(aggregate.Node);
            }

            var size            = 30 + Math.Sqrt(aggregate.DescendantWeightSum) * 4;
            var layout          = RectD.FromCenter(originalCenter, new SizeD(size, size));
            var aggregationNode =
                AggregateGraph.Aggregate(new ListEnumerable <INode>(nodesToAggregate), layout, AggregationNodeStyle);

            aggregateToNode[aggregate] = aggregationNode;
            aggregationNode.Tag        = new AggregationNodeInfo(aggregate, true);

            if (aggregate.Node != null)
            {
                placeholderMap[aggregate.Node] = aggregationNode;
                CopyLabels(aggregate.Node, aggregationNode);
            }
            else
            {
                var maxChild = GetMostImportantDescendant(aggregate);
                if (maxChild.Node != null && maxChild.Node.Labels.Any())
                {
                    AggregateGraph.AddLabel(aggregationNode, $"({maxChild.Node.Labels[0].Text}, …)",
                                            FreeNodeLabelModel.Instance.CreateDefaultParameter(), DescendantLabelStyle);
                }
            }

            return(aggregationNode);
        }
 private void CreateReplacementEdge(INode sourceNode, INode targetNode, IEdge edge)
 {
     if ((AggregateGraph.IsAggregationItem(sourceNode) || AggregateGraph.IsAggregationItem(targetNode)) &&
         AggregateGraph.GetEdge(sourceNode, targetNode) == null &&
         AggregateGraph.GetEdge(targetNode, sourceNode) == null)
     {
         AggregateGraph.CreateEdge(sourceNode, targetNode, edge.Style);
     }
 }
        /// <summary>
        /// Collects all un-aggregated nodes that match the kind of <paramref name="node"/> by the selector.
        /// </summary>
        private List <INode> CollectNodesOfSameKind <TKey>(INode node, Func <INode, TKey> selector)
        {
            var nodeKind = selector(node);

            return(Graph.Nodes
                   .Where(n => !AggregateGraph.IsAggregationItem(n))
                   .Where(n => selector(n).Equals(nodeKind))
                   .ToList());
        }
 /// <summary>
 /// Returns the <see cref="NodeAggregation.Aggregate"/> for a node.
 /// </summary>
 public NodeAggregation.Aggregate GetAggregateForNode(INode node)
 {
     if (AggregateGraph.IsAggregationItem(node))
     {
         return(((AggregationNodeInfo)node.Tag).Aggregate);
     }
     else
     {
         return(aggregationResult.AggregateMap[node]);
     }
 }
Beispiel #10
0
        /// <summary>
        /// Runs the smart <see cref="NodeAggregation"/> algorithm with the settings from the properties panel.
        /// </summary>
        private async void RunButtonClick(object sender, RoutedEventArgs e)
        {
            SetUiEnabled(false);
            GraphControl.Graph = new DefaultGraph();
            AggregateGraph.Dispose();
            await RunAggregationAndReplaceGraph(OriginalGraph);

            SetUiEnabled(true);

            OnInfoPanelPropertiesChanged();
        }
 /// <summary>
 /// Separates all <paramref name="nodes"/> and runs the layout afterwards.
 /// </summary>
 private void Separate(IEnumerable <INode> nodes)
 {
     foreach (var child in nodes)
     {
         if (AggregateGraph.IsAggregationItem(child))
         {
             AggregateGraph.Separate(child);
         }
     }
     RunLayout();
 }
        /// <summary>
        /// Aggregates all nodes of the original graph by the selector and runs the layout.
        /// </summary>
        /// <remarks>
        /// Before aggregating the nodes, all existing aggregations are
        /// <see cref="AggregateGraphWrapper.SeparateAll">separated</see>.
        /// </remarks>
        private void AggregateAll <TKey>(Func <INode, TKey> selector, Func <TKey, INodeStyle> styleFactory)
        {
            AggregateGraph.SeparateAll();

            foreach (var grouping in Graph.Nodes.GroupBy(selector).ToList())
            {
                Aggregate(grouping.ToList(), grouping.Key, styleFactory);
            }

            RunLayout();
        }
        /// <summary>
        /// Separates an aggregated aggregation node and replaces it by a new aggregation node.
        /// </summary>
        /// <remarks>
        /// Creates hierarchy edges between the new aggregation node and its children.
        /// </remarks>
        /// <param name="node">The node.</param>
        /// <returns>The nodes affected by this operation. The created aggregation node is always the first item.</returns>
        public IListEnumerable <INode> Separate(INode node)
        {
            var aggregationInfo = (AggregationNodeInfo)node.Tag;
            var aggregate       = aggregationInfo.Aggregate;
            var aggregatedItems = AggregateGraph.GetAggregatedItems(node)
                                  .Where(n => n != aggregate.Node)
                                  .Cast <INode>().ToList();

            AggregateGraph.Separate(node);

            var nodesToAggregate = aggregate.Node != null
          ? new ListEnumerable <INode>(new List <INode> {
                aggregate.Node
            })
          : ListEnumerable <INode> .Empty;
            var aggregationNode = AggregateGraph.Aggregate(nodesToAggregate, node.Layout.ToRectD(), AggregationNodeStyle);

            foreach (var child in aggregatedItems)
            {
                AggregateGraph.CreateEdge(aggregationNode, child, HierarchyEdgeStyle, true);
                AggregateGraph.SetNodeLayout(child,
                                             RectD.FromCenter(aggregationNode.Layout.GetCenter(), child.Layout.ToSizeD()));
                ReplaceEdges(child);
            }

            aggregationInfo.IsAggregated = false;
            aggregateToNode[aggregate]   = aggregationNode;
            aggregationNode.Tag          = aggregationInfo;

            var affectedNodes = new List <INode> {
                aggregationNode
            };

            affectedNodes.AddRange(aggregatedItems);

            if (aggregate.Parent != null && aggregateToNode.TryGetValue(aggregate.Parent, out var parentNode))
            {
                AggregateGraph.CreateEdge(parentNode, aggregationNode, HierarchyEdgeStyle, true);
                affectedNodes.Add(parentNode);
            }

            if (aggregate.Node != null)
            {
                placeholderMap[aggregate.Node] = aggregationNode;
                CopyLabels(aggregate.Node, aggregationNode);
                ReplaceEdges(aggregationNode);
            }

            return(new ListEnumerable <INode>(affectedNodes));
        }
        /// <summary>
        /// Replaces original edges adjacent to a placeholder node with aggregation edges when source and target are
        /// currently visible.
        /// </summary>
        private void ReplaceEdges(INode node)
        {
            INode originalNode;

            if (node.Tag is AggregationNodeInfo aggregationInfo)
            {
                originalNode = aggregationInfo.Aggregate.Node;
            }
            else
            {
                originalNode = node;
            }

            if (originalNode == null)
            {
                return;
            }

            foreach (var edge in AggregateGraph.WrappedGraph.EdgesAt(originalNode).ToList())
            {
                if (edge.TargetPort.Owner == originalNode)
                {
                    var sourceNode = (INode)edge.SourcePort.Owner;
                    if (AggregateGraph.Contains(sourceNode))
                    {
                        CreateReplacementEdge(sourceNode, node, edge);
                    }
                    else if (placeholderMap.TryGetValue(sourceNode, out var placeholderSource) &&
                             AggregateGraph.Contains(placeholderSource))
                    {
                        CreateReplacementEdge(placeholderSource, node, edge);
                    }
                }
                else
                {
                    var targetNode = (INode)edge.TargetPort.Owner;
                    if (AggregateGraph.Contains(targetNode))
                    {
                        CreateReplacementEdge(node, targetNode, edge);
                    }
                    else if (placeholderMap.TryGetValue(targetNode, out var placeholderTarget) &&
                             AggregateGraph.Contains(placeholderTarget))
                    {
                        CreateReplacementEdge(node, placeholderTarget, edge);
                    }
                }
            }
        }
        /// <summary>
        /// For all passed nodes, aggregates all nodes that match the given node by the selector.
        /// </summary>
        /// <remarks>
        /// After the aggregation a layout calculation is run.
        /// </remarks>
        private void AggregateSame <TKey>(IList <INode> nodes, Func <INode, TKey> selector, Func <TKey, INodeStyle> styleFactory)
        {
            // get one representative of each kind of node (determined by the selector) ignoring aggregation nodes
            IList <INode> distinctNodes = nodes.Where(n => !AggregateGraph.IsAggregationItem(n))
                                          .GroupBy(selector)
                                          .Select(g => g.First())
                                          .ToList();

            foreach (var node in distinctNodes)
            {
                // aggregate all nodes of the same kind as the representing node
                var nodesOfSameKind = CollectNodesOfSameKind(node, selector);
                Aggregate(nodesOfSameKind, selector(node), styleFactory);
            }
            RunLayout();
        }
        /// <summary>
        /// Replaces a separated node and its hierarchy children with a new aggregation node.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns>The nodes affected by this operation. The created aggregation node is always the first item.</returns>
        public IListEnumerable <INode> Aggregate(INode node)
        {
            var aggregationInfo = (AggregationNodeInfo)node.Tag;
            var aggregate       = aggregationInfo.Aggregate;
            var aggregationNode = AggregateRecursively(aggregate);

            var affectedNodes = new List <INode> {
                aggregationNode
            };

            if (aggregate.Parent != null && aggregateToNode.TryGetValue(aggregate.Parent, out var parentNode))
            {
                AggregateGraph.CreateEdge(parentNode, aggregationNode, HierarchyEdgeStyle, true);
                affectedNodes.Add(parentNode);
            }

            if (aggregate.Node != null)
            {
                ReplaceEdges(aggregationNode);
            }

            return(new ListEnumerable <INode>(affectedNodes));
        }
        public static void Generate(string dlcName, Manifest.Manifest manifest, AggregateGraph.AggregateGraph aggregateGraph, Stream outStream)
        {
            var game = new Game();
            game.Entities = new List<Entity>();
            var ent = new Entity() { Id = IdGenerator.Guid().ToString().Replace("-", ""), Name = "SoundScene0", Iterations = 1, ModelName = "SoundScene", Properties = new List<Property>() { CreateMultiItemProperty("SoundBanks", new string[1] { aggregateGraph.SoundBank.Name + ".bnk" }) } };
            game.Entities.Add(ent);
            foreach (var x in manifest.Entries)
            {
                var entry = x.Value["Attributes"];
                var entity = new Entity();
                bool isVocal = entry.ArrangementName == "Vocals";
                bool isBass = entry.ArrangementName == "Bass";

                entity.Id = entry.PersistentID.ToLower();
                entity.Name = String.Format("GRSong_Asset_{0}_{1}", dlcName, entry.ArrangementName);
                entity.ModelName = "GRSong_Asset";
                entity.Iterations = 46;
                game.Entities.Add(entity);
                var properties = new List<Property>();
                var addProperty = new Action<string, object>((a, b) => properties.Add(CreateProperty(a, b.ToString())));

                if (isBass || isVocal)
                    addProperty("BinaryVersion", entry.BinaryVersion);

                addProperty("SongKey", entry.SongKey);
                addProperty("SongAsset", entry.SongAsset);
                addProperty("SongXml", entry.SongXml);
                addProperty("ForceUseXML", entry.ForceUseXML);
                addProperty("Shipping", entry.Shipping);
                addProperty("DisplayName", entry.DisplayName);

                addProperty("SongEvent", entry.SongEvent);

                if (isVocal)
                    addProperty("InputEvent", entry.InputEvent);

                addProperty("ArrangementName", entry.ArrangementName);
                addProperty("RepresentativeArrangement", entry.RepresentativeArrangement);

                if (!isVocal && !String.IsNullOrEmpty(entry.VocalsAssetId))
                {
                    addProperty("VocalsAssetId", entry.VocalsAssetId.Split(new string[1] { "|" }, StringSplitOptions.RemoveEmptyEntries)[0]);

                    var dynVisDen = new List<object>();
                    foreach (var y in entry.DynamicVisualDensity)
                        dynVisDen.Add(y);
                    properties.Add(CreateMultiItemProperty("DynamicVisualDensity", dynVisDen));
                }

                addProperty("ArtistName", entry.ArtistName);
                addProperty("ArtistNameSort", entry.ArtistNameSort);
                addProperty("SongName", entry.SongName);
                addProperty("SongNameSort", entry.SongNameSort);
                addProperty("AlbumName", entry.AlbumName);
                addProperty("AlbumNameSort", entry.AlbumNameSort);
                addProperty("SongYear", entry.SongYear);

                if (!isVocal) {
                    addProperty("RelativeDifficulty", entry.RelativeDifficulty);
                    addProperty("AverageTempo", entry.AverageTempo);//fix this

                    addProperty("NonStandardChords", true);//fix this
                    addProperty("DoubleStops", entry.DoubleStops);
                    addProperty("PowerChords", entry.PowerChords);
                    addProperty("OpenChords", entry.OpenChords);
                    addProperty("BarChords", entry.BarChords);
                    addProperty("Sustain", entry.Sustain);
                    addProperty("Bends", entry.Bends);
                    addProperty("Slides", entry.Slides);
                    addProperty("HOPOs", entry.HOPOs);
                    addProperty("PalmMutes", entry.PalmMutes);
                    addProperty("Vibrato", entry.Vibrato);

                    addProperty("MasterID_Xbox360", entry.MasterID_Xbox360);
                    addProperty("EffectChainName", entry.EffectChainName);
                    addProperty("CrowdTempo", "Fast");//fix this
                }

                addProperty("AlbumArt", entry.AlbumArt);

                entity.Properties = properties;
            }
            game.Serialize(outStream);
        }
        /// <summary>
        /// Fills the context menu with menu items based on the clicked node.
        /// </summary>
        private void OnPopulateItemContextMenu(object sender, PopulateItemContextMenuEventArgs <IModelItem> e)
        {
            // first update the selection
            INode node = e.Item as INode;

            // if the cursor is over a node select it, else clear selection
            UpdateSelection(node);

            // Create the context menu items
            var selectedNodes = graphControl.Selection.SelectedNodes;

            if (selectedNodes.Count > 0)
            {
                // only allow aggregation operations on nodes that are not aggregation nodes already
                var aggregateAllowed = selectedNodes.Any(n => !AggregateGraph.IsAggregationItem(n));

                var aggregateByShape =
                    new ToolStripMenuItem("Aggregate Nodes with Same Shape")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByShape.Click += (o, args) => AggregateSame(selectedNodes.ToList(), ShapeSelector,
                                                                     ShapeStyle);
                e.Menu.Items.Add(aggregateByShape);

                var aggregateByColor =
                    new ToolStripMenuItem("Aggregate Nodes with Same Color")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByColor.Click += (o, args) => AggregateSame(selectedNodes.ToList(), ColorSelector, ColorStyle);
                e.Menu.Items.Add(aggregateByColor);

                var aggregateByShapeAndColor =
                    new ToolStripMenuItem("Aggregate Nodes with Same Shape and Color")
                {
                    Enabled = aggregateAllowed
                };
                aggregateByShapeAndColor.Click += (o, args) =>
                                                  AggregateSame(selectedNodes.ToList(), ShapeAndColorSelector, ShapeAndColorStyle);
                e.Menu.Items.Add(aggregateByShapeAndColor);

                var separateAllowed = selectedNodes.Any(n => AggregateGraph.IsAggregationItem(n));
                var separate        = new ToolStripMenuItem("Separate")
                {
                    Enabled = separateAllowed
                };
                separate.Click += (o, args) => Separate(selectedNodes.ToList());
                e.Menu.Items.Add(separate);
            }
            else
            {
                var aggregateByShape = new ToolStripMenuItem("Aggregate All Nodes by Shape");
                aggregateByShape.Click += (o, args) => AggregateAll(ShapeSelector, ShapeStyle);
                e.Menu.Items.Add(aggregateByShape);

                var aggregateByColor = new ToolStripMenuItem("Aggregate All Nodes by Color");
                aggregateByColor.Click += (o, args) => AggregateAll(ColorSelector, ColorStyle);
                e.Menu.Items.Add(aggregateByColor);

                var aggregateByShapeAndColor = new ToolStripMenuItem("Aggregate All Nodes by Shape and Color");
                aggregateByShapeAndColor.Click += (o, args) => AggregateAll(ShapeAndColorSelector, ShapeAndColorStyle);
                e.Menu.Items.Add(aggregateByShapeAndColor);

                var separateAllowed = Graph.Nodes.Any(n => AggregateGraph.IsAggregationItem(n));
                var separateAll     = new ToolStripMenuItem("Separate All")
                {
                    Enabled = separateAllowed
                };
                separateAll.Click += (o, args) => {
                    AggregateGraph.SeparateAll();
                    RunLayout();
                };
                e.Menu.Items.Add(separateAll);
            }

            e.ShowMenu = true;
            e.Handled  = true;
        }
 public bool IsOriginalNodeOrPlaceHolder(INode node)
 {
     return(!AggregateGraph.IsAggregationItem(node) || ((AggregationNodeInfo)node.Tag).Aggregate.Node != null);
 }