/// <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); }
/// <summary> /// Gets the descendant <see cref="NodeAggregation.Aggregate"/> with the highest /// <see cref="NodeAggregation.Aggregate.DescendantWeightSum"/>. /// </summary> private static NodeAggregation.Aggregate GetMostImportantDescendant(NodeAggregation.Aggregate aggregate) { while (true) { var maxChild = aggregate.Children.Aggregate((max, child) => child.DescendantWeightSum > max.DescendantWeightSum ? child : max); if (maxChild.Node != null) { return(maxChild); } aggregate = maxChild; } }
public AggregationNodeInfo(NodeAggregation.Aggregate aggregate, bool isAggregated) { this.Aggregate = aggregate; this.IsAggregated = isAggregated; }