internal static void FixBoundingBox(GeometryGraph component, LayoutAlgorithmSettings settings) { // Pad the graph with margins so the packing will be spaced out. component.Margins = settings.ClusterMargin; component.UpdateBoundingBox(); // Zero the graph component.Translate(-component.BoundingBox.LeftBottom); }
///<summary> ///</summary> ///<param name="geomGraph"></param> static public void ShowGraph(GeometryGraph geomGraph) { var graph = new Graph(); geomGraph.UpdateBoundingBox(); var bb = geomGraph.BoundingBox; bb.Pad(geomGraph.Margins); geomGraph.BoundingBox = bb; BindGeomGraphToDrawingGraph(graph, geomGraph); DisplayGraph(graph, new Form()); }
internal static void PreRunTransform(GeometryGraph geomGraph, PlaneTransformation matrix) { if (matrix.IsIdentity) return; var matrixInverse = matrix.Inverse; foreach (Node n in geomGraph.Nodes) n.Transform(matrixInverse); //calculate new label widths and heights foreach (Edge e in geomGraph.Edges) { if (e.Label != null) { e.OriginalLabelWidth = e.Label.Width; e.OriginalLabelHeight = e.Label.Height; var r = new Rectangle(matrixInverse*new Point(0, 0), matrixInverse*new Point(e.Label.Width, e.Label.Height)); e.Label.Width = r.Width; e.Label.Height = r.Height; } } geomGraph.UpdateBoundingBox(); }
private void DoEdgeRouting(GeometryGraph gg, EdgeRoutingSettings settings, double nodeSeparation) { var mode = settings.EdgeRoutingMode; if (mode == EdgeRoutingMode.SugiyamaSplines) { } else { if (mode == EdgeRoutingMode.Rectilinear || mode == EdgeRoutingMode.RectilinearToCenter) { RectilinearInteractiveEditor.CreatePortsAndRouteEdges( nodeSeparation / 3, nodeSeparation / 3, gg.Nodes, gg.Edges, mode, true); } else if (mode == EdgeRoutingMode.Spline || mode == EdgeRoutingMode.SplineBundling) { /*var coneAngle = Math.PI / 6.0; var nodePadding = nodeSeparation / 3; var loosePadding = SplineRouter.ComputeLooseSplinePadding(nodeSeparation, nodePadding);*/ //if (mode == EdgeRoutingMode.Spline) if (mode == EdgeRoutingMode.Spline) settings.BundlingSettings = null; new SplineRouter(gg, settings).Run(CancelToken); //else //BundledEdgeRouter.RouteEdgesInMetroMapStyle(gg, coneAngle, nodePadding, loosePadding, settings.BundlingSettings); } else if (mode == EdgeRoutingMode.StraightLine) { new StraightLineEdges(gg.Edges, settings.Padding).Run(CancelToken); } // Place labels new EdgeLabelPlacement(gg).Run(CancelToken); if (CancelToken == null || !CancelToken.Canceled) { // foreach (GeometryEdge e in gg.Edges) // TransformUnderlyingPolyline(gg, e, (dg.LayoutAlgorithmSettings as SugiyamaLayoutSettings).Transformation); gg.UpdateBoundingBox(); Dispatcher.BeginInvoke(Invalidate); } } }
static void PostRunTransform(GeometryGraph geometryGraph, SugiyamaLayoutSettings settings) { bool transform = !settings.Transformation.IsIdentity; if (transform) { foreach (Node n in geometryGraph.Nodes) n.Transform(settings.Transformation); foreach (var n in geometryGraph.RootCluster.AllClustersDepthFirst()) { n.Transform(settings.Transformation); n.RectangularBoundary.Rect = n.BoundaryCurve.BoundingBox; } //restore labels widths and heights foreach (Edge e in geometryGraph.Edges) { if (e.Label != null) { e.Label.Width = e.OriginalLabelWidth; e.Label.Height = e.OriginalLabelHeight; } } TransformCurves(geometryGraph, settings); } geometryGraph.UpdateBoundingBox(); }
/// <summary> /// </summary> /// <param name="geometryGraph"></param> /// <param name="layoutSettings"></param> /// <param name="edgesToRoute"></param> public static void RouteAndLabelEdges(GeometryGraph geometryGraph, LayoutAlgorithmSettings layoutSettings, IEnumerable<Edge> edgesToRoute) { //todo: what about parent edges!!!! var filteredEdgesToRoute = edgesToRoute.Where(e => ! e.UnderCollapsedCluster()).ToArray(); var ers = layoutSettings.EdgeRoutingSettings; if (ers.EdgeRoutingMode == EdgeRoutingMode.Rectilinear || ers.EdgeRoutingMode == EdgeRoutingMode.RectilinearToCenter) { RectilinearInteractiveEditor.CreatePortsAndRouteEdges( layoutSettings.NodeSeparation/3, layoutSettings.NodeSeparation/3, geometryGraph.Nodes, edgesToRoute, ers.EdgeRoutingMode, true, ers.UseObstacleRectangles, ers.BendPenalty); } else if (ers.EdgeRoutingMode == EdgeRoutingMode.Spline || ers.EdgeRoutingMode==EdgeRoutingMode.SugiyamaSplines) { new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, null) { ContinueOnOverlaps = true, KeepOriginalSpline = ers.KeepOriginalSpline }.Run(); } else if (ers.EdgeRoutingMode == EdgeRoutingMode.SplineBundling) { var edgeBundlingSettings = ers.BundlingSettings ?? new BundlingSettings(); var bundleRouter = new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, edgeBundlingSettings) { KeepOriginalSpline = ers.KeepOriginalSpline }; bundleRouter.Run(); if (bundleRouter.OverlapsDetected) { new SplineRouter(geometryGraph, filteredEdgesToRoute, ers.Padding, ers.PolylinePadding, ers.ConeAngle, null) { ContinueOnOverlaps = true, KeepOriginalSpline = ers.KeepOriginalSpline }.Run(); } } else if (ers.EdgeRoutingMode == EdgeRoutingMode.StraightLine) { var router = new StraightLineEdges(filteredEdgesToRoute, ers.Padding); router.Run(); } var elb = new EdgeLabelPlacement(geometryGraph.Nodes, filteredEdgesToRoute); elb.Run(); geometryGraph.UpdateBoundingBox(); }
private void LayoutComponent(GeometryGraph component) { if (component.Nodes.Count > 1 || component.RootCluster.Clusters.Any()) { // for small graphs (below 100 nodes) do extra iterations settings.MaxIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation( component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 5, /*maxIterations:*/ 10); settings.MinorIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation(component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 3, /*maxIterations:*/ 20); if (settings.MinConstraintLevel == 0) { // run PivotMDS with a largish Scale so that the layout comes back oversized. // subsequent incremental iterations do a better job of untangling when they're pulling it in // rather than pushing it apart. PivotMDS pivotMDS = new PivotMDS(component) { Scale = 2 }; this.RunChildAlgorithm(pivotMDS, 0.5 / componentCount); } FastIncrementalLayout fil = new FastIncrementalLayout(component, settings, settings.MinConstraintLevel, anyCluster => settings); Debug.Assert(settings.Iterations == 0); foreach (var level in GetConstraintLevels(component)) { if (level > settings.MaxConstraintLevel) { break; } if (level > settings.MinConstraintLevel) { fil.CurrentConstraintLevel = level; } do { fil.Run(); } while (!settings.IsDone); } } // Pad the graph with margins so the packing will be spaced out. component.Margins = settings.NodeSeparation; component.UpdateBoundingBox(); // Zero the graph component.Translate(-component.BoundingBox.LeftBottom); }
internal void LayoutComponent(GeometryGraph component, FastIncrementalLayoutSettings settings) { // for small graphs (below 100 nodes) do extra iterations settings.MaxIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation( component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 3, /*maxIterations:*/ 5); settings.MinorIterations = LayoutAlgorithmHelpers.NegativeLinearInterpolation(component.Nodes.Count, /*lowerThreshold:*/ 50, /*upperThreshold:*/ 500, /*minIterations:*/ 2, /*maxIterations:*/ 10); FastIncrementalLayout fil = new FastIncrementalLayout(component, settings, settings.MinConstraintLevel, anyCluster => settings); Debug.Assert(settings.Iterations == 0); foreach (var level in Enumerable.Range(settings.MinConstraintLevel, settings.MaxConstraintLevel + 1)) { if (level != fil.CurrentConstraintLevel) { fil.CurrentConstraintLevel = level; if (level == 2) { settings.MinorIterations = 1; settings.ApplyForces = false; } } do { fil.Run(); } while (!settings.IsDone); } // Pad the graph with margins so the packing will be spaced out. component.Margins = settings.ClusterMargin; component.UpdateBoundingBox(); }
/// <summary> /// /// </summary> public void IncrementalRun(CancelToken cancelToken, GeometryGraph graph, Func<Cluster, LayoutAlgorithmSettings> clusterSettings) { if (cancelToken != null) { cancelToken.ThrowIfCanceled(); } SetupIncrementalRun(graph, clusterSettings); algorithm.Run(cancelToken); graph.UpdateBoundingBox(); }
/// <summary> /// Run the FastIncrementalLayout instance incrementally /// </summary> public void IncrementalRun(GeometryGraph graph, Func<Cluster, LayoutAlgorithmSettings> clusterSettings) { SetupIncrementalRun(graph, clusterSettings); algorithm.Run(); graph.UpdateBoundingBox(); }
static void FillGraph(Graph graph, DebugCurve[] debugCurves) { var gg = new GeometryGraph { DebugCurves = debugCurves}; gg.Margins = 5; graph.GeometryGraph = gg; gg.UpdateBoundingBox(); }
/// <summary> /// Executes the algorithm. /// </summary> /// <summary> /// Executes the actual algorithm. /// </summary> protected override void RunInternal() { var g = new GeometryGraph(); foreach (var v in graph.Nodes) { Debug.Assert(!(v is Cluster)); var u = new Node(v.BoundaryCurve.Clone()) { UserData = v }; v.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); } double avgLength = 0; foreach (var e in graph.Edges) { avgLength += e.Length; if (e.Source is Cluster || e.Target is Cluster) continue; var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } if (graph.Edges.Count != 0) { avgLength /= graph.Edges.Count; } else { avgLength = 100; } // create edges from the children of each parent cluster to the parent cluster node foreach (var c in graph.RootCluster.AllClustersDepthFirst()) { if (c == graph.RootCluster) continue; var u = new Node(CurveFactory.CreateRectangle(10, 10, new Point())); u.UserData = c; c.AlgorithmData = new PivotMDSNodeWrap(u); g.Nodes.Add(u); foreach (var v in c.Nodes.Concat(from cc in c.Clusters select (Node)cc)) { var vv = v.AlgorithmData as PivotMDSNodeWrap; g.Edges.Add(new Edge(u, vv.node) { Length = avgLength }); } } // create edges between clusters foreach (var e in graph.Edges) { if (e.Source is Cluster || e.Target is Cluster) { var u = e.Source.AlgorithmData as PivotMDSNodeWrap; var v = e.Target.AlgorithmData as PivotMDSNodeWrap; var ee = new Edge(u.node, v.node) { Length = e.Length }; g.Edges.Add(ee); } } // with 0 majorization iterations we just do PivotMDS MdsLayoutSettings settings = new MdsLayoutSettings { ScaleX = this.Scale, ScaleY = this.Scale, IterationsWithMajorization = 0, RemoveOverlaps = false, AdjustScale = false }; MdsGraphLayout mdsLayout = new MdsGraphLayout(settings, g); this.RunChildAlgorithm(mdsLayout, 1.0); g.UpdateBoundingBox(); foreach (var v in graph.Nodes) { var m = v.AlgorithmData as PivotMDSNodeWrap; v.Center = m.node.Center; } }
static void PostRunTransform(GeometryGraph geometryGraph, PlaneTransformation transformation) { bool transform = !transformation.IsIdentity; if (transform) { foreach (Node n in geometryGraph.Nodes) { n.Transform(transformation); } //restore labels widths and heights foreach (Edge e in geometryGraph.Edges) { if (e.Label != null) { e.Label.Width = e.OriginalLabelWidth; e.Label.Height = e.OriginalLabelHeight; } } TransformCurves(geometryGraph, transformation); } geometryGraph.UpdateBoundingBox(); }
public static void Layout(GeometryGraph graph) { foreach (Node n in graph.Nodes) n.BoundaryCurve = CurveFactory.CreateEllipse(20.0, 10.0, new Point()); foreach (Cluster c in graph.RootCluster.AllClustersDepthFirst()) c.BoundaryCurve = c.BoundingBox.Perimeter(); var settings = new FastIncrementalLayoutSettings(); settings.AvoidOverlaps = true; settings.NodeSeparation = 30; settings.RouteEdges = true; LayoutHelpers.CalculateLayout(graph, settings, new CancelToken()); foreach (Cluster c in graph.RootCluster.AllClustersDepthFirst()) c.BoundaryCurve = c.BoundingBox.Perimeter(); var bundlingsettings = new BundlingSettings() { EdgeSeparation = 5, CreateUnderlyingPolyline = true }; var router = new SplineRouter(graph, 10.0, 1.25, Math.PI / 6.0, bundlingsettings); router.Run(); graph.UpdateBoundingBox(); }