public void ISOMLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount, int maxOverlapped) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new ISOMLayoutParameters { Width = 1000, Height = 1000 }; int iteration = 0; var algorithm = new ISOMLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, parameters) { Rand = new Random(123) }; algorithm.IterationEnded += (sender, args) => { Assert.LessOrEqual(args.Iteration, parameters.MaxEpochs); Assert.AreEqual(iteration++, args.Iteration); }; algorithm.ProgressChanged += (sender, percent) => { }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes, true); results.CheckResult(maxCrossCount, maxOverlapped); }
public void SimpleTreeLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new SimpleTreeLayoutParameters { LayerGap = 15, VertexGap = 20 }; foreach (LayoutDirection direction in Enum.GetValues(typeof(LayoutDirection))) { parameters.Direction = direction; foreach (SpanningTreeGeneration treeGen in Enum.GetValues(typeof(SpanningTreeGeneration))) { parameters.SpanningTreeGeneration = treeGen; var algorithm = new SimpleTreeLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, verticesSizes, parameters); LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes); results.CheckResult(maxCrossCount); CheckTreeLayout(algorithm, verticesSizes); } } }
/// <summary> /// Calculates the size of the box layout container. /// </summary> /// <param name="obj">The container to lay out.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="direction">The direction which is being calculated.</param> /// <returns>The minimum and preferred box layout size.</returns> private static LayoutResults Calc(GameObject obj, BoxLayoutParams args, PanelDirection direction) { var transform = obj.AddOrGet <RectTransform>(); int n = transform.childCount; var result = new LayoutResults(direction, n); var components = ListPool <ILayoutElement, BoxLayoutGroup> .Allocate(); for (int i = 0; i < n; i++) { var child = transform.GetChild(i)?.gameObject; if (child != null && child.activeInHierarchy) { // Only on active game objects components.Clear(); child.GetComponents(components); var hc = PUIUtils.GetSize(child, direction, components); if (args.Direction == direction) { result.Accum(hc, args.Spacing); } else { result.Expand(hc); } result.children.Add(hc); } } components.Recycle(); return(result); }
public void KKLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new KKLayoutParameters { Width = 1000, Height = 1000 }; foreach (bool exchange in new[] { true, false }) { parameters.ExchangeVertices = exchange; int iteration = 0; var algorithm = new KKLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, parameters) { Rand = new Random(12345) }; algorithm.IterationEnded += (sender, args) => { Assert.LessOrEqual(args.Iteration, parameters.MaxIterations); Assert.AreEqual(iteration++, args.Iteration); }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes, true); results.CheckResult(maxCrossCount); } }
public void FRLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new BoundedFRLayoutParameters { Width = 1000, Height = 1000 }; foreach (FRCoolingFunction func in Enum.GetValues(typeof(FRCoolingFunction))) { parameters.CoolingFunction = func; int iteration = 0; var algorithm = new FRLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, parameters) { Rand = new Random(12345) }; algorithm.IterationEnded += (sender, args) => { Assert.LessOrEqual(args.Iteration, parameters.MaxIterations); Assert.AreEqual(iteration++, args.Iteration); }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes, true); results.CheckResult(maxCrossCount); } }
public void LinLogLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new LinLogLayoutParameters(); int iteration = 1; var algorithm = new LinLogLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, parameters) { Rand = new Random(12345) }; algorithm.IterationEnded += (sender, args) => { Assert.LessOrEqual(args.Iteration, parameters.MaxIterations); Assert.AreEqual(iteration++, args.Iteration); }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes, true); results.CheckResult(maxCrossCount); }
protected override void OnEnable() { base.OnEnable(); SetDirty(); horizontal = null; vertical = null; }
internal BoxLayoutGroup() { horizontal = null; layoutPriority = 1; parameters = new BoxLayoutParams(); vertical = null; }
public void CalculateLayoutInputVertical() { var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.top + margin.bottom; vertical = Calc(gameObject, parameters, PanelDirection.Vertical); var vTotal = vertical.total; minHeight = vTotal.min + gap; preferredHeight = vTotal.preferred + gap; }
public void CalculateLayoutInputHorizontal() { var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.left + margin.right; horizontal = Calc(gameObject, parameters, PanelDirection.Horizontal); var hTotal = horizontal.total; minWidth = hTotal.min + gap; preferredWidth = hTotal.preferred + gap; }
public void CalculateLayoutInputVertical() { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputVertical for " + gameObject.name); #endif var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.top + margin.bottom; vertical = Calc(gameObject, parameters, PanelDirection.Vertical); var vTotal = vertical.total; minHeight = vTotal.min + gap; preferredHeight = vTotal.preferred + gap; }
public void CalculateLayoutInputHorizontal() { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputHorizontal for " + gameObject.name); #endif var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.left + margin.right; horizontal = Calc(gameObject, parameters, PanelDirection.Horizontal); var hTotal = horizontal.total; minWidth = hTotal.min + gap; preferredWidth = hTotal.preferred + gap; }
public void CircularLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var algorithm = new CircularLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, verticesSizes, new CircularLayoutParameters()); LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes); results.CheckResult(maxCrossCount); CheckCircularLayout(algorithm); }
public void RandomLayoutAlgorithm([NotNull] IVertexAndEdgeListGraph <string, Edge <string> > graph) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var algorithm = new RandomLayoutAlgorithm <string, Edge <string>, IVertexAndEdgeListGraph <string, Edge <string> > >( graph, verticesSizes, null, new RandomLayoutParameters()) { Rand = new Random(12345) }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes, true); results.CheckPositions(); }
/// <summary> /// Lays out components in the box layout container against the layout axis. /// </summary> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="status">The current status of layout.</param> private static void DoLayoutPerp(LayoutResults required, BoxLayoutParams args, LayoutStatus status) { var components = ListPool <ILayoutController, BoxLayoutGroup> .Allocate(); var direction = args.Direction; float size = status.size; foreach (var child in required.children) { var obj = child.source; // Active objects only if (obj != null && obj.activeInHierarchy) { float compSize = size; if (child.flexible <= 0.0f) { // Does not expand to all compSize = Math.Min(compSize, child.preferred); } float offset = (size > compSize) ? GetOffset(args, status.direction, size - compSize) : 0.0f; // Place and size component obj.AddOrGet <RectTransform>().SetInsetAndSizeFromParentEdge(status.edge, offset + status.offset, compSize); // Invoke SetLayout on dependents components.Clear(); obj.GetComponents(components); foreach (var component in components) { if (!PUIUtils.IgnoreLayout(component)) { if (direction == PanelDirection.Horizontal) { component.SetLayoutVertical(); } else // if (direction == PanelDirection.Vertical) { component.SetLayoutHorizontal(); } } } } } components.Recycle(); }
public void RandomLayoutAlgorithm_WithFixedVertices() { IVertexAndEdgeListGraph <string, Edge <string> > graph = GraphFactory.CreateGeneralGraph( 30, 15, 10, false, i => i.ToString(), (s, t) => new Edge <string>(s, t), new Random(123)); string[] vertices = graph.Vertices.ToArray(); string fixedVertexNoPos = vertices[2]; string fixedVertexWithPos = vertices[16]; var fixedVertexPosition = new Point(50.0, 50.0); IDictionary <string, Point> verticesPositions = new Dictionary <string, Point> { [fixedVertexWithPos] = fixedVertexPosition }; IDictionary <string, Size> verticesSizes = GetVerticesSizes(vertices); var verticesTypes = new Dictionary <string, RandomVertexType> { [fixedVertexNoPos] = RandomVertexType.Fixed, [vertices[8]] = RandomVertexType.Free, [fixedVertexWithPos] = RandomVertexType.Fixed }; var algorithm = new RandomLayoutAlgorithm <string, Edge <string>, IVertexAndEdgeListGraph <string, Edge <string> > >( graph, verticesPositions, verticesSizes, verticesTypes, new RandomLayoutParameters()) { Rand = new Random(12345) }; // Run without overlap removal otherwise fixed vertex may change their positions after algorithm run LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes); results.CheckPositions(); Assert.AreEqual(fixedVertexPosition, algorithm.VerticesPositions[fixedVertexWithPos]); }
/// <summary> /// Lays out components in the box layout container. /// </summary> /// <param name="args">The parameters to use for layout.</param> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="size">The total available size in this dimension.</param> private static void DoLayout(BoxLayoutParams args, LayoutResults required, float size) { if (required == null) { throw new ArgumentNullException("required"); } var direction = required.direction; var status = new LayoutStatus(direction, args.Margin ?? new RectOffset(), size); if (args.Direction == direction) { DoLayoutLinear(required, args, status); } else { DoLayoutPerp(required, args, status); } }
public void SugiyamaLayoutAlgorithm( [NotNull] IBidirectionalGraph <string, Edge <string> > graph, int maxCrossCount, int maxOverlapped) { IDictionary <string, Size> verticesSizes = GetVerticesSizes(graph.Vertices); var parameters = new SugiyamaLayoutParameters(); foreach (LayoutDirection direction in Enum.GetValues(typeof(LayoutDirection))) { parameters.Direction = direction; foreach (int mode in new[] { -1, 0, 1, 2, 3 }) { parameters.PositionMode = mode; foreach (bool optimizeWidth in new[] { false, true }) { parameters.OptimizeWidth = optimizeWidth; foreach (bool minimizeEdgeLength in new[] { false, true }) { parameters.MinimizeEdgeLength = minimizeEdgeLength; var algorithm = new SugiyamaLayoutAlgorithm <string, Edge <string>, IBidirectionalGraph <string, Edge <string> > >( graph, verticesSizes, parameters) { Rand = new Random(12345) }; LayoutResults results = ExecuteLayoutAlgorithm(algorithm, verticesSizes); results.CheckResult(maxCrossCount, maxOverlapped); } } } } }
protected static LayoutResults ExecuteLayoutAlgorithm <TVertex, TEdge>( [NotNull] ILayoutAlgorithm <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> > algorithm, [NotNull] IDictionary <TVertex, Size> verticesSizes, bool requireOverlapRemoval = false) where TVertex : class where TEdge : IEdge <TVertex> { var results = new LayoutResults(); Assert.DoesNotThrow(algorithm.Compute); IDictionary <TVertex, Point> verticesPositions = algorithm.VerticesPositions; if (requireOverlapRemoval) { var rectangles = new Dictionary <TVertex, Rect>(); foreach (TVertex vertex in algorithm.VisitedGraph.Vertices) { Point position = algorithm.VerticesPositions[vertex]; Size size = verticesSizes[vertex]; rectangles[vertex] = new Rect( position.X - size.Width * (float)0.5, position.Y - size.Height * (float)0.5, size.Width, size.Height); } var overlapRemoval = new FSAAlgorithm <TVertex>( rectangles, new OverlapRemovalParameters()); Assert.DoesNotThrow(overlapRemoval.Compute); foreach (KeyValuePair <TVertex, Rect> pair in overlapRemoval.Rectangles) { verticesPositions[pair.Key] = new Point( pair.Value.Left + pair.Value.Size.Width * 0.5, pair.Value.Top + pair.Value.Size.Height * 0.5); } } IDictionary <TEdge, Point[]> edgeRoutes = algorithm is IEdgeRoutingAlgorithm <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> > routingAlgorithm ? routingAlgorithm.EdgeRoutes : new Dictionary <TEdge, Point[]>(); // Compute metrics var positionsMetric = new PositionsMetricCalculator <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> >( algorithm.VisitedGraph, verticesPositions, verticesSizes, edgeRoutes); positionsMetric.Calculate(); results.PositionsSet = positionsMetric.PositionsSet; var overlapMetric = new OverlapMetricCalculator <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> >( algorithm.VisitedGraph, verticesPositions, verticesSizes, edgeRoutes); overlapMetric.Calculate(); results.OverlapCount = overlapMetric.OverlapCount; results.OverlappedArea = overlapMetric.OverlappedArea; var areaMetric = new LayoutAreaMetricCalculator <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> >( algorithm.VisitedGraph, verticesPositions, verticesSizes, edgeRoutes); areaMetric.Calculate(); results.TopLeft = areaMetric.TopLeft; results.BottomRight = areaMetric.BottomRight; results.Area = areaMetric.Area; results.Ratio = areaMetric.Ratio; var edgeMetric = new EdgeCrossingCalculator <TVertex, TEdge, IVertexAndEdgeListGraph <TVertex, TEdge> >( algorithm.VisitedGraph, verticesPositions, verticesSizes, edgeRoutes); edgeMetric.Calculate(); results.CrossCount = edgeMetric.CrossCount; results.MaximumEdgeLength = edgeMetric.MaximumEdgeLength; results.MinimumEdgeLength = edgeMetric.MinimumEdgeLength; results.AverageEdgeLength = edgeMetric.AverageEdgeLength; return(results); }
/// <summary> /// Lays out components in the box layout container parallel to the layout axis. /// </summary> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="status">The current status of layout.</param> private static void DoLayoutLinear(LayoutResults required, BoxLayoutParams args, LayoutStatus status) { var total = required.total; var components = ListPool <ILayoutController, BoxLayoutGroup> .Allocate(); var direction = args.Direction; // Determine flex size ratio float size = status.size, prefRatio = 0.0f, minSize = total.min, prefSize = total.preferred, excess = Math.Max(0.0f, size - prefSize), flexTotal = total. flexible, offset = status.offset, spacing = args.Spacing; if (size > minSize && prefSize > minSize) { // Do not divide by 0 prefRatio = Math.Min(1.0f, (size - minSize) / (prefSize - minSize)); } if (excess > 0.0f && flexTotal == 0.0f) { // If no components can be expanded, offset all offset += GetOffset(args, status.direction, excess); } foreach (var child in required.children) { var obj = child.source; // Active objects only if (obj != null && obj.activeInHierarchy) { float compSize = child.min; if (prefRatio > 0.0f) { compSize += (child.preferred - child.min) * prefRatio; } if (excess > 0.0f && flexTotal > 0.0f) { compSize += excess * child.flexible / flexTotal; } // Place and size component obj.AddOrGet <RectTransform>().SetInsetAndSizeFromParentEdge(status.edge, offset, compSize); offset += compSize + ((compSize > 0.0f) ? spacing : 0.0f); // Invoke SetLayout on dependents components.Clear(); obj.GetComponents(components); foreach (var component in components) { if (!PUIUtils.IgnoreLayout(component)) { if (direction == PanelDirection.Horizontal) { component.SetLayoutHorizontal(); } else // if (direction == PanelDirection.Vertical) { component.SetLayoutVertical(); } } } } } components.Recycle(); }