/// <summary> /// apply a number of heuristics to improve current routing /// </summary> internal static void FixRouting(MetroGraphData metroGraphData, BundlingSettings bundlingSettings) { // #if DEBUG && TEST_MSAGL // Debug.Assert(metroGraphData.looseIntersections.HubPositionsAreOK()); // #endif //TimeMeasurer.DebugOutput("Initial cost = " + CostCalculator.Cost(metroGraphData, bundlingSettings)); //TimeMeasurer.DebugOutput("Initial cost of forces: " + CostCalculator.CostOfForces(metroGraphData, bundlingSettings)); var adjuster = new NodePositionsAdjuster(metroGraphData, bundlingSettings); adjuster.GlueConflictingNodes(); adjuster.UnglueEdgesFromBundleToSaveInk(true); var step = 0; int MaxSteps = 10; while (++step < MaxSteps) { /*#if DEBUG && TEST_MSAGL * Debug.Assert(metroGraphData.looseIntersections.HubPositionsAreOK()); #endif*/ //heuristics to improve routing bool progress = adjuster.GlueConflictingNodes(); progress |= adjuster.RelaxConstrainedEdges(); progress |= (step <= 3 && adjuster.UnglueEdgesFromBundleToSaveInk(false)); progress |= adjuster.GlueCollinearNeighbors(step); progress |= (step == 3 && adjuster.RemoveDoublePathCrossings()); if (!progress) { break; } } //one SA has to be executed with bundle forces metroGraphData.cdtIntersections.ComputeForcesForBundles = true; adjuster.RemoveDoublePathCrossings(); adjuster.UnglueEdgesFromBundleToSaveInk(true); while (adjuster.GlueConflictingNodes()) { } metroGraphData.Initialize(true); //this time initialize the tight enterables also // HubDebugger.ShowHubs(metroGraphData, bundlingSettings); //TimeMeasurer.DebugOutput("NodePositionsAdjuster stopped after " + step + " steps"); //HubDebugger.ShowHubs(metroGraphData, bundlingSettings, true); //TimeMeasurer.DebugOutput("Final cost: " + CostCalculator.Cost(metroGraphData, bundlingSettings)); //TimeMeasurer.DebugOutput("Final cost of forces: " + CostCalculator.CostOfForces(metroGraphData, bundlingSettings)); }
/// <summary> /// apply a number of heuristics to improve current routing /// </summary> internal static void FixRouting(MetroGraphData metroGraphData, BundlingSettings bundlingSettings) { #if DEBUG && TEST_MSAGL Debug.Assert(metroGraphData.looseIntersections.HubPositionsAreOK()); #endif //TimeMeasurer.DebugOutput("Initial cost = " + CostCalculator.Cost(metroGraphData, bundlingSettings)); //TimeMeasurer.DebugOutput("Initial cost of forces: " + CostCalculator.CostOfForces(metroGraphData, bundlingSettings)); var adjuster = new NodePositionsAdjuster(metroGraphData, bundlingSettings); adjuster.GlueConflictingNodes(); adjuster.UnglueEdgesFromBundleToSaveInk(true); var step = 0; int MaxSteps = 10; while (++step < MaxSteps) { /*#if DEBUG && TEST_MSAGL Debug.Assert(metroGraphData.looseIntersections.HubPositionsAreOK()); #endif*/ //heuristics to improve routing bool progress = adjuster.GlueConflictingNodes(); progress |= adjuster.RelaxConstrainedEdges(); progress |= (step <= 3 && adjuster.UnglueEdgesFromBundleToSaveInk(false)); progress |= adjuster.GlueCollinearNeighbors(step); progress |= (step == 3 && adjuster.RemoveDoublePathCrossings()); if (!progress) break; } //one SA has to be executed with bundle forces metroGraphData.cdtIntersections.ComputeForcesForBundles = true; adjuster.RemoveDoublePathCrossings(); adjuster.UnglueEdgesFromBundleToSaveInk(true); while (adjuster.GlueConflictingNodes()) { } metroGraphData.Initialize(true); //this time initialize the tight enterables also // HubDebugger.ShowHubs(metroGraphData, bundlingSettings); //TimeMeasurer.DebugOutput("NodePositionsAdjuster stopped after " + step + " steps"); //HubDebugger.ShowHubs(metroGraphData, bundlingSettings, true); //TimeMeasurer.DebugOutput("Final cost: " + CostCalculator.Cost(metroGraphData, bundlingSettings)); //TimeMeasurer.DebugOutput("Final cost of forces: " + CostCalculator.CostOfForces(metroGraphData, bundlingSettings)); }
/// <summary> /// edge routing with Ordered Bundles: /// 1. route edges with bundling /// 2. nudge bundles and hubs /// 3. order paths /// </summary> protected override void RunInternal() { //TimeMeasurer.DebugOutput("edge bundling started"); if (ThereAreOverlaps(TightHierarchy)) { /* * LayoutAlgorithmSettings.ShowDebugCurves( * TightHierarchy.GetAllLeaves().Select(p => new DebugCurve(100, 1, "black", p)).ToArray());*/ Status = BundlingStatus.Overlaps; TimeMeasurer.DebugOutput("overlaps in edge bundling"); return; } FixLocationsForHookAnywherePorts(geometryGraph.Edges); if (!RoutePathsWithSteinerDijkstra()) { Status = BundlingStatus.EdgeSeparationIsTooLarge; return; } FixChildParentEdges(); if (!bundlingSettings.StopAfterShortestPaths) { var metroGraphData = new MetroGraphData(regularEdges.Select(e => e.EdgeGeometry).ToArray(), LooseHierarchy, TightHierarchy, bundlingSettings, shortestPathRouter.Cdt, EdgeLooseEnterable, EdgeTightEnterable, loosePolylineOfPort); NodePositionsAdjuster.FixRouting(metroGraphData, bundlingSettings); new EdgeNudger(metroGraphData, bundlingSettings).Run(); //TimeMeasurer.DebugOutput("edge bundling ended"); } RouteSelfEdges(); FixArrowheads(); }