/// <summary> /// switch flips /// </summary> bool RemoveDoublePathCrossings() { bool progress = new PathFixer(metroGraphData, metroGraphData.PointIsAcceptableForEdge).Run(); if (progress) { metroGraphData.Initialize(false); SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings); } return(progress); }
/// <summary> /// unite the nodes that are close to each other /// </summary> bool GlueConflictingNodes() { var circlesHierarchy = GetCirclesHierarchy(); if (circlesHierarchy == null) { return(false); } var gluingMap = new Dictionary <Station, Station>(); var gluedDomain = new Set <Station>(); RectangleNodeUtils.CrossRectangleNodes <Station>(circlesHierarchy, circlesHierarchy, (i, j) => TryToGlueNodes(i, j, gluingMap, gluedDomain)); if (gluingMap.Count == 0) { return(false); } for (int i = 0; i < metroGraphData.Edges.Length; i++) { RegenerateEdge(gluingMap, i); } //can it be more efficient? HashSet <Point> affectedPoints = new HashSet <Point>(); foreach (var s in gluedDomain) { affectedPoints.Add(s.Position); foreach (var neig in s.Neighbors) { if (!neig.IsRealNode) { affectedPoints.Add(neig.Position); } } } //TimeMeasurer.DebugOutput("gluing nodes"); metroGraphData.Initialize(false); SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings, affectedPoints); return(true); }
/// <summary> /// Unbundle unnecessary edges: /// instead of one bundle (a->bcd) we get two bundles (a->b,a->cd) with smaller ink /// </summary> bool UnglueEdgesFromBundleToSaveInk(bool alwaysExecuteSA) { var segsToPolylines = new Dictionary <PointPair, Set <Metroline> >(); ink = metroGraphData.Ink; polylineLength = new Dictionary <Metroline, double>(); //create polylines foreach (var metroline in metroGraphData.Metrolines) { polylineLength[metroline] = metroline.Length; for (var pp = metroline.Polyline.StartPoint; pp.Next != null; pp = pp.Next) { var segment = new PointPair(pp.Point, pp.Next.Point); CollectionUtilities.AddToMap(segsToPolylines, segment, metroline); } } var affectedPoints = new HashSet <Point>(); var progress = false; foreach (var metroline in metroGraphData.Metrolines) { var obstaclesAllowedToIntersect = metroGraphData.PointToStations[metroline.Polyline.Start].EnterableLoosePolylines * metroGraphData.PointToStations[metroline.Polyline.End].EnterableLoosePolylines; if (TrySeparateOnPolyline(metroline, segsToPolylines, affectedPoints, obstaclesAllowedToIntersect)) { progress = true; } } if (progress) //TimeMeasurer.DebugOutput("unbundling"); { metroGraphData.Initialize(false); } if (alwaysExecuteSA || progress) { SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings, alwaysExecuteSA ? null : affectedPoints); } return(progress); }
/// <summary> /// Fix the situation where a station has two neighbors that are almost in the same directions /// </summary> bool GlueCollinearNeighbors(int step) { HashSet <Point> affectedPoints = new HashSet <Point>(); bool progress = false; foreach (var node in metroGraphData.Stations) { if (GlueCollinearNeighbors(node, affectedPoints, step)) { progress = true; } } if (progress) { //TimeMeasurer.DebugOutput("gluing edges"); metroGraphData.Initialize(false); SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings, affectedPoints); } return(progress); }
/// <summary> /// split each edge that is too much constrained by the obstacles /// </summary> bool RelaxConstrainedEdges() { HashSet <Point> affectedPoints = new HashSet <Point>(); bool progress = false; foreach (var edge in metroGraphData.VirtualEdges()) { if (RelaxConstrainedEdge(edge.Item1, edge.Item2, affectedPoints)) { progress = true; } } if (progress) { //TimeMeasurer.DebugOutput("relaxing constrained edges"); metroGraphData.Initialize(false); SimulatedAnnealing.FixRouting(metroGraphData, bundlingSettings, affectedPoints); } return(progress); }