PageRenderTime 41ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/GraphLayout/Test/MSAGLTests/SplineRouterTests.cs

https://gitlab.com/hoseinyeganloo/automatic-graph-layout
C# | 338 lines | 284 code | 36 blank | 18 comment | 23 complexity | 4fd304d9cbad9323bce314e890088e89 MD5 | raw file
  1. //-----------------------------------------------------------------------
  2. // <copyright file="SplineRouterTests.cs" company="Microsoft">
  3. // (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //-----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Linq;
  11. #if GDI_DEBUG_VIEWER
  12. using Microsoft.Msagl.GraphViewerGdi;
  13. #endif
  14. using Microsoft.Msagl.Core;
  15. using Microsoft.Msagl.Core.DataStructures;
  16. using Microsoft.Msagl.Core.Geometry;
  17. using Microsoft.Msagl.Core.Geometry.Curves;
  18. using Microsoft.Msagl.Core.Layout;
  19. using Microsoft.Msagl.Core.Routing;
  20. using Microsoft.Msagl.DebugHelpers.Persistence;
  21. using Microsoft.Msagl.Layout.Incremental;
  22. using Microsoft.Msagl.Layout.Initial;
  23. using Microsoft.Msagl.Routing;
  24. using Microsoft.Msagl.Routing.Rectilinear;
  25. using Microsoft.Msagl.Routing.Spline.Bundling;
  26. using Microsoft.VisualStudio.TestTools.UnitTesting;
  27. namespace Microsoft.Msagl.UnitTests
  28. {
  29. /// <summary>
  30. /// Test class for methods inside EdgeRouterHelper
  31. /// </summary>
  32. [TestClass]
  33. [DeploymentItem(@"Resources\MSAGLGeometryGraphs")]
  34. public class SplineRouterTests : MsaglTestBase
  35. {
  36. [TestMethod]
  37. [Description("Verifies that RouteEdges calls progress changed.")]
  38. public void RouteEdges_CallsProgress()
  39. {
  40. //DisplayGeometryGraph.SetShowFunctions();
  41. GeometryGraph graph = GraphGenerator.GenerateTree(10);
  42. double ratioComplete = 0;
  43. EventHandler<ProgressChangedEventArgs> handler = (s, e) => ratioComplete = e.RatioComplete;
  44. SplineRouter splineRouter = null;
  45. try
  46. {
  47. splineRouter = new SplineRouter(graph, 10, 1, Math.PI / 6, null);
  48. splineRouter.ProgressChanged += handler;
  49. splineRouter.Run();
  50. // DisplayGeometryGraph.ShowGraph(graph);
  51. }
  52. finally
  53. {
  54. splineRouter.ProgressChanged -= handler;
  55. }
  56. Assert.AreEqual(1, ratioComplete, "RouteEdges did not complete");
  57. }
  58. [TestMethod]
  59. [WorkItem(571435)]
  60. [Description("Runs spline routing on a relatively small graph that has caused problems in the past.")]
  61. public void RouteEdges_SplineRoutingRegressionBug20110127()
  62. {
  63. double tightPadding = 1;
  64. double loosePadding = 20;
  65. double coneAngle = Math.PI / 6;
  66. GeometryGraph graph = LoadGraph("RoutingRegressionBug20110127.msagl.geom");
  67. SplineRouter splineRouter = new SplineRouter(graph, tightPadding, loosePadding, coneAngle, null);
  68. splineRouter.Run();
  69. //DisplayGeometryGraph.ShowGraph(graph);
  70. CheckEdgesForOverlapWithNodes(tightPadding, graph);
  71. }
  72. [TestMethod]
  73. [WorkItem(446802)]
  74. [TestCategory("LayoutPerfTest")]
  75. [TestCategory("NonRollingBuildTest")]
  76. [Timeout(30 * 1000)]
  77. [Description("Simple timed test of routing with 20 degree cones over a large graph")]
  78. public void RouteEdges_SplineRouting1138Bus()
  79. {
  80. var g = LoadGraph("GeometryGraph_1138bus.msagl.geom");
  81. var sw = new Stopwatch();
  82. sw.Start();
  83. var loosePadding = SplineRouter.ComputeLooseSplinePadding(10, 2);
  84. SplineRouter splineRouter = new SplineRouter(g, 2, loosePadding, Math.PI / 6, null);
  85. splineRouter.Run();
  86. sw.Stop();
  87. System.Console.WriteLine("Edge routing took: {0} seconds.", sw.ElapsedMilliseconds / 1000.0);
  88. }
  89. [TestMethod]
  90. [WorkItem(448382)]
  91. [WorkItem(446802)]
  92. [TestCategory("LayoutPerfTest")]
  93. [TestCategory("NonRollingBuildTest")]
  94. // [Timeout(30 * 1000)]
  95. [Description("Simple timed test of routing with 20 degree cones over a large graph")]
  96. public void RouteEdges_Nodes50()
  97. {
  98. var g = LoadGraph("nodes50.msagl.geom");
  99. var sw = new Stopwatch();
  100. sw.Start();
  101. const double TightPadding = 2.0;
  102. var loosePadding = SplineRouter.ComputeLooseSplinePadding(10, TightPadding);
  103. SplineRouter splineRouter = new SplineRouter(g, TightPadding, loosePadding, Math.PI / 6, null);
  104. splineRouter.Run();
  105. sw.Stop();
  106. Console.WriteLine("Edge routing took: {0} seconds.", sw.ElapsedMilliseconds / 1000.0);
  107. CheckEdgesForOverlapWithNodes(TightPadding, g);
  108. }
  109. private static void CheckEdgesForOverlapWithNodes(double tightPadding, GeometryGraph graph)
  110. {
  111. #if GDI_DEBUG_VIEWER
  112. if (!DontShowTheDebugViewer())
  113. {
  114. DisplayGeometryGraph.SetShowFunctions();
  115. }
  116. #endif
  117. foreach (var e in graph.Edges.Where(e=>!MultiEdge(e)))//avoid checking multi-edges since they routed as bundles and can slightly go over the nodes
  118. {
  119. Assert.IsNotNull(e.EdgeGeometry, "EdgeGeometry is null");
  120. Assert.IsNotNull(e.EdgeGeometry.Curve, "EdgeGeometry.Curve is null");
  121. foreach (var v in graph.Nodes)
  122. {
  123. if (v == e.Source || v == e.Target)
  124. {
  125. continue;
  126. }
  127. var box = v.BoundingBox;
  128. var poly = InteractiveObstacleCalculator.CreatePaddedPolyline(Curve.PolylineAroundClosedCurve(v.BoundaryCurve), tightPadding / 2);
  129. bool overlaps = CurveOverlapsBox(e.EdgeGeometry.Curve, ref box, poly);
  130. #if GDI_DEBUG_VIEWER
  131. //uncomment to see the graph and the overlaps
  132. if (overlaps && !DontShowTheDebugViewer())
  133. {
  134. LayoutAlgorithmSettings.ShowGraph(graph);
  135. LayoutAlgorithmSettings.Show(poly, e.Curve);
  136. }
  137. #endif
  138. Assert.IsFalse(overlaps);
  139. }
  140. }
  141. }
  142. static bool CurveOverlapsBox(ICurve curve, ref Rectangle box, Polyline boxPolyline) {
  143. // if the curve bounding box doesn't intersect the invalidated region then no overlap!
  144. if (!box.Intersects(curve.BoundingBox)) {
  145. return false;
  146. }
  147. // if either end of the curve is inside the box then there is definitely overlap!
  148. if (box.Contains(curve.Start) || box.Contains(curve.End)) {
  149. return true;
  150. }
  151. // we have already determined that the curve is close but not fully contained so now we
  152. // need to check for a more expensive intersection
  153. return Curve.CurveCurveIntersectionOne(boxPolyline, curve, false) != null;
  154. }
  155. private static bool MultiEdge(Edge edge)
  156. {
  157. return edge.Source.OutEdges.Where(e => e.Target == edge.Target && e != edge).Any() || edge.Source.InEdges.Where(e => e.Source == edge.Target && e != edge).Any();
  158. }
  159. [TestMethod]
  160. [WorkItem(446802)]
  161. [TestCategory("LayoutPerfTest")]
  162. [TestCategory("NonRollingBuildTest")]
  163. [Timeout(20000000)]
  164. [Description("Simple timed test of routing with 20 degree cones over a small complete graph")]
  165. public void SplineRoutingSmallCompleteGraph()
  166. {
  167. //DisplayGeometryGraph.SetShowFunctions();
  168. var g = LoadGraph("K20.msagl.geom");
  169. var sw = new Stopwatch();
  170. sw.Start();
  171. var loosePadding = SplineRouter.ComputeLooseSplinePadding(10, 2);
  172. SplineRouter splineRouter = new SplineRouter(g, 2, loosePadding, Math.PI / 6, null);
  173. splineRouter.Run();
  174. sw.Stop();
  175. TestContext.WriteLine("Edge routing took: {0} seconds.", sw.ElapsedMilliseconds / 1000.0);
  176. }
  177. [TestMethod]
  178. [Description("the run does not stop")]
  179. public void BundlingBug1GeomGraph() {
  180. #if DEBUG && TEST_MSAGL
  181. DisplayGeometryGraph.SetShowFunctions();
  182. #endif
  183. var graph = GeometryGraphReader.CreateFromFile(GetGeomGraphFileName("bug1.msagl.geom"));
  184. var settings = new BundlingSettings();
  185. var router = new SplineRouter(graph, 0.1, 0.75, Math.PI / 6, settings);
  186. router.Run();
  187. }
  188. [TestMethod]
  189. [Description("the run does not stop")]
  190. public void ComplexGeomGraph() {
  191. var graph = GeometryGraphReader.CreateFromFile(GetGeomGraphFileName("complex.msagl.geom"));
  192. var settings = new BundlingSettings();
  193. var br = new SplineRouter(graph, 1, 1.5, Math.PI / 6, settings);
  194. br.Run();
  195. }
  196. [TestMethod]
  197. [Description("bundling with groups")]
  198. public void BundlingWithGroups() {
  199. var graph = GeometryGraphReader.CreateFromFile(GetGeomGraphFileName("graphWithGroups.msagl.geom"));
  200. var settings = new BundlingSettings();
  201. var router = new SplineRouter(graph, 3, 1, Math.PI / 6, settings);
  202. router.Run();
  203. }
  204. string GetGeomGraphFileName(string graphName) {
  205. var dirName = (null != this.TestContext) ? this.TestContext.DeploymentDirectory : Path.GetTempPath();
  206. return Path.Combine(dirName, graphName);
  207. }
  208. [TestMethod]
  209. [Description("Simple test of rectilinear routing between two nodes, one inside a cluster")]
  210. public void SimpleClusterGraphRectilinear()
  211. {
  212. var g = new GeometryGraph();
  213. var node0 = new Node(CurveFactory.CreateRectangle(10, 10, new Point()), 0);
  214. var node1 = new Node(CurveFactory.CreateRectangle(10, 10, new Point()), 1);
  215. var cluster = new Cluster(new[] { node1 });
  216. cluster.UserData = 2;
  217. cluster.BoundaryCurve = CurveFactory.CreateRectangle(10, 10, new Point());
  218. var edge = new Edge(node0, node1) { Length = 100 };
  219. g.Nodes.Add(node0);
  220. g.Nodes.Add(node1);
  221. g.Edges.Add(edge);
  222. var cluster2 = new Cluster(new[] { node0 }, new[] { cluster });
  223. cluster2.UserData = 3;
  224. cluster2.BoundaryCurve = CurveFactory.CreateRectangle(10, 10, new Point());
  225. g.RootCluster = cluster2;
  226. InitialLayout initialLayout = new InitialLayout(g, new FastIncrementalLayoutSettings() { AvoidOverlaps = true });
  227. initialLayout.Run();
  228. RectilinearEdgeRouter router = new RectilinearEdgeRouter(g, 1, 1, false);
  229. router.Run();
  230. EnableDebugViewer();
  231. ShowGraphInDebugViewer(g);
  232. var bb0 = node0.BoundingBox;
  233. bb0.Pad(1);
  234. Assert.IsTrue(bb0.Contains(edge.EdgeGeometry.Curve.Start));
  235. var bb1 = node1.BoundingBox;
  236. bb1.Pad(1);
  237. Assert.IsTrue(bb1.Contains(edge.EdgeGeometry.Curve.End));
  238. }
  239. [Ignore, WorkItem(535708)]
  240. [TestMethod]
  241. [TestCategory("Rectilinear routing")]
  242. [TestCategory("NonRollingBuildTest")]
  243. [Timeout(5000)]
  244. [Description("Create three groups, a couple of embedded and see if the routing succeeds")]
  245. public void RoutingWithThreeGroups()
  246. {
  247. var graph = LoadGraph("abstract.msagl.geom");
  248. var root = graph.RootCluster;
  249. var a = new Cluster { UserData = "a" };
  250. foreach (string id in new[] { "17", "39", "13", "19", "28", "12" })
  251. a.AddChild(graph.FindNodeByUserData(id));
  252. var b = new Cluster { UserData = "b" };
  253. b.AddChild(a);
  254. b.AddChild(graph.FindNodeByUserData("18"));
  255. root.AddChild(b);
  256. var c = new Cluster { UserData = "c" };
  257. foreach (string id in new[] { "30", "5", "6", "7", "8" })
  258. c.AddChild(graph.FindNodeByUserData(id));
  259. root.AddChild(c);
  260. var clusterNodes = new Set<Node>(root.AllClustersDepthFirst().SelectMany(cl => cl.Nodes));
  261. foreach (var node in graph.Nodes.Where(n => clusterNodes.Contains(n) == false))
  262. root.AddChild(node);
  263. FixClusterBoundariesWithNoRectBoundaries(root, 5);
  264. var defaultSettings = new FastIncrementalLayoutSettings();
  265. var rootSettings = new FastIncrementalLayoutSettings() { AvoidOverlaps = true };
  266. var initialLayout = new InitialLayoutByCluster(graph, new[] { graph.RootCluster }, cl => cl == root ? rootSettings : defaultSettings);
  267. initialLayout.Run();
  268. const double Padding = 5;
  269. SplineRouter splineRouter = new SplineRouter(graph, Padding/3, Padding, Math.PI / 6);
  270. splineRouter.Run();
  271. #if TEST_MSAGL
  272. if (!DontShowTheDebugViewer())
  273. {
  274. graph.UpdateBoundingBox();
  275. DisplayGeometryGraph.ShowGraph(graph);
  276. }
  277. #endif
  278. }
  279. static void FixClusterBoundariesWithNoRectBoundaries(Cluster cluster, double padding) {
  280. foreach (Cluster cl in cluster.Clusters)
  281. FixClusterBoundariesWithNoRectBoundaries(cl, padding);
  282. var box = Rectangle.CreateAnEmptyBox();
  283. var clusterPoints =
  284. cluster.Clusters.SelectMany(c => ClusterPoints(c)).Concat(
  285. cluster.Nodes.SelectMany(n => NodePerimeterPoints(n)));
  286. foreach (var clusterPoint in clusterPoints)
  287. box.Add(clusterPoint);
  288. box.Pad(padding);
  289. cluster.BoundaryCurve = box.Perimeter();
  290. cluster.RectangularBoundary = new RectangularClusterBoundary();
  291. }
  292. static IEnumerable<Point> NodePerimeterPoints(Node node) {
  293. return new[] {
  294. node.BoundingBox.RightTop, node.BoundingBox.LeftBottom, node.BoundingBox.LeftTop,
  295. node.BoundingBox.RightBottom
  296. };
  297. }
  298. static IEnumerable<Point> ClusterPoints(Cluster cluster) {
  299. return cluster.BoundaryCurve as Polyline;
  300. }
  301. }
  302. }