53 |
53 |
54 sealed abstract class Vertex |
54 sealed abstract class Vertex |
55 case class Node(node: Graph_Display.Node) extends Vertex |
55 case class Node(node: Graph_Display.Node) extends Vertex |
56 case class Dummy(node1: Graph_Display.Node, node2: Graph_Display.Node, index: Int) extends Vertex |
56 case class Dummy(node1: Graph_Display.Node, node2: Graph_Display.Node, index: Int) extends Vertex |
57 |
57 |
58 object Point { val zero: Point = Point(0.0, 0.0) } |
58 sealed case class Info( |
59 case class Point(x: Double, y: Double) |
59 x: Double, y: Double, width2: Double, height2: Double, lines: List[String]) |
60 |
60 { |
61 type Graph = isabelle.Graph[Vertex, Point] |
61 def left: Double = x - width2 |
62 |
62 def right: Double = x + width2 |
63 def make_graph(entries: List[((Vertex, Point), List[Vertex])]): Graph = |
63 def width: Double = 2 * width2 |
|
64 def height: Double = 2 * height2 |
|
65 } |
|
66 |
|
67 type Graph = isabelle.Graph[Vertex, Info] |
|
68 |
|
69 def make_graph(entries: List[((Vertex, Info), List[Vertex])]): Graph = |
64 isabelle.Graph.make(entries)(Vertex.Ordering) |
70 isabelle.Graph.make(entries)(Vertex.Ordering) |
65 |
71 |
66 val empty_graph: Graph = make_graph(Nil) |
72 val empty_graph: Graph = make_graph(Nil) |
67 |
73 |
68 |
74 |
69 /* vertex x coordinate */ |
75 /* vertex x coordinate */ |
70 |
76 |
71 private def vertex_left(metrics: Metrics, graph: Graph, v: Vertex): Double = |
77 private def vertex_left(graph: Graph, v: Vertex) = graph.get_node(v).left |
72 graph.get_node(v).x - metrics.box_width2(v) |
78 private def vertex_right(graph: Graph, v: Vertex) = graph.get_node(v).right |
73 |
|
74 private def vertex_right(metrics: Metrics, graph: Graph, v: Vertex): Double = |
|
75 graph.get_node(v).x + metrics.box_width2(v) |
|
76 |
79 |
77 private def move_vertex(graph: Graph, v: Vertex, dx: Double): Graph = |
80 private def move_vertex(graph: Graph, v: Vertex, dx: Double): Graph = |
78 if (dx == 0.0) graph else graph.map_node(v, p => Point(p.x + dx, p.y)) |
81 if (dx == 0.0) graph else graph.map_node(v, info => info.copy(x = info.x + dx)) |
79 |
82 |
80 |
83 |
81 /* layout */ |
84 /* layout */ |
82 |
85 |
83 val empty: Layout = new Layout(Metrics.default, Graph_Display.empty_graph, empty_graph) |
86 val empty: Layout = new Layout(Metrics.default, Graph_Display.empty_graph, empty_graph) |
84 |
87 |
85 |
88 |
86 private type Levels = Map[Vertex, Int] |
89 private type Levels = Map[Vertex, Int] |
87 private val empty_levels: Levels = Map.empty |
90 private val empty_levels: Levels = Map.empty |
88 |
91 |
89 def make(options: Options, metrics: Metrics, input_graph: Graph_Display.Graph): Layout = |
92 def make(options: Options, metrics: Metrics, |
|
93 node_text: (Graph_Display.Node, XML.Body) => String, |
|
94 input_graph: Graph_Display.Graph): Layout = |
90 { |
95 { |
91 if (input_graph.is_empty) empty |
96 if (input_graph.is_empty) empty |
92 else { |
97 else { |
93 /* initial graph */ |
98 /* initial graph */ |
94 |
99 |
95 val initial_graph = |
100 val initial_graph = |
96 make_graph( |
101 make_graph( |
97 input_graph.iterator.map( |
102 input_graph.iterator.map( |
98 { case (a, (_, (_, bs))) => ((Node(a), Point.zero), bs.toList.map(Node(_))) }).toList) |
103 { case (a, (content, (_, bs))) => |
|
104 val lines = split_lines(node_text(a, content)) |
|
105 val w2 = metrics.node_width2(lines) |
|
106 val h2 = metrics.node_height2(lines.length) |
|
107 ((Node(a), Info(0.0, 0.0, w2, h2, lines)), bs.toList.map(Node(_))) |
|
108 }).toList) |
99 |
109 |
100 val initial_levels: Levels = |
110 val initial_levels: Levels = |
101 (empty_levels /: initial_graph.topological_order) { |
111 (empty_levels /: initial_graph.topological_order) { |
102 case (levels, vertex) => |
112 case (levels, vertex) => |
103 val level = |
113 val level = |
105 levels + (vertex -> level) |
115 levels + (vertex -> level) |
106 } |
116 } |
107 |
117 |
108 |
118 |
109 /* graph with dummies */ |
119 /* graph with dummies */ |
|
120 |
|
121 val dummy_info = Info(0.0, 0.0, metrics.dummy_size2, metrics.dummy_size2, Nil) |
110 |
122 |
111 val (dummy_graph, dummy_levels) = |
123 val (dummy_graph, dummy_levels) = |
112 ((initial_graph, initial_levels) /: input_graph.edges_iterator) { |
124 ((initial_graph, initial_levels) /: input_graph.edges_iterator) { |
113 case ((graph, levels), (node1, node2)) => |
125 case ((graph, levels), (node1, node2)) => |
114 val v1 = Node(node1); val l1 = levels(v1) |
126 val v1 = Node(node1); val l1 = levels(v1) |
120 yield (Dummy(node1, node2, i), l)).toList |
132 yield (Dummy(node1, node2, i), l)).toList |
121 val dummies = dummies_levels.map(_._1) |
133 val dummies = dummies_levels.map(_._1) |
122 |
134 |
123 val levels1 = (levels /: dummies_levels)(_ + _) |
135 val levels1 = (levels /: dummies_levels)(_ + _) |
124 val graph1 = |
136 val graph1 = |
125 ((graph /: dummies)(_.new_node(_, Point.zero)).del_edge(v1, v2) /: |
137 ((graph /: dummies)(_.new_node(_, dummy_info)).del_edge(v1, v2) /: |
126 (v1 :: dummies ::: List(v2)).sliding(2)) { |
138 (v1 :: dummies ::: List(v2)).sliding(2)) { |
127 case (g, List(a, b)) => g.add_edge(a, b) } |
139 case (g, List(a, b)) => g.add_edge(a, b) } |
128 (graph1, levels1) |
140 (graph1, levels1) |
129 } |
141 } |
130 } |
142 } |
135 val levels = minimize_crossings(options, dummy_graph, level_list(dummy_levels)) |
147 val levels = minimize_crossings(options, dummy_graph, level_list(dummy_levels)) |
136 |
148 |
137 val levels_graph: Graph = |
149 val levels_graph: Graph = |
138 (((dummy_graph, 0.0) /: levels) { |
150 (((dummy_graph, 0.0) /: levels) { |
139 case ((graph, y), level) => |
151 case ((graph, y), level) => |
|
152 val num_lines = (0 /: level) { case (n, v) => n max graph.get_node(v).lines.length } |
140 val num_edges = (0 /: level) { case (n, v) => n + graph.imm_succs(v).size } |
153 val num_edges = (0 /: level) { case (n, v) => n + graph.imm_succs(v).size } |
141 ((((graph, 0.0) /: level) { |
154 |
142 case ((g, x), v) => |
155 val y1 = y + metrics.node_height2(num_lines) |
143 val w2 = metrics.box_width2(v) |
156 |
144 (g.map_node(v, _ => Point(x + w2, y)), x + 2 * w2 + metrics.box_gap) |
157 val graph1 = |
145 })._1, y + metrics.box_height(num_edges)) |
158 (((graph, 0.0) /: level) { case ((g, x), v) => |
|
159 val info = g.get_node(v) |
|
160 val g1 = g.map_node(v, _ => info.copy(x = x + info.width2, y = y1)) |
|
161 val x1 = x + info.width + metrics.gap |
|
162 (g1, x1) |
|
163 })._1 |
|
164 |
|
165 val y2 = y1 + metrics.level_height2(num_lines, num_edges) |
|
166 |
|
167 (graph1, y2) |
146 })._1 |
168 })._1 |
147 |
169 |
148 |
170 |
149 /* pendulum/rubberband layout */ |
171 /* pendulum/rubberband layout */ |
150 |
172 |
222 calculating coordinates with the "pendulum method". A "region" is a |
244 calculating coordinates with the "pendulum method". A "region" is a |
223 group of vertices which "stick together".*/ |
245 group of vertices which "stick together".*/ |
224 private class Region(val content: List[Vertex]) |
246 private class Region(val content: List[Vertex]) |
225 { |
247 { |
226 def distance(metrics: Metrics, graph: Graph, that: Region): Double = |
248 def distance(metrics: Metrics, graph: Graph, that: Region): Double = |
227 vertex_left(metrics, graph, that.content.head) - |
249 vertex_left(graph, that.content.head) - |
228 vertex_right(metrics, graph, this.content.last) - |
250 vertex_right(graph, this.content.last) - |
229 metrics.box_gap |
251 metrics.gap |
230 |
252 |
231 def deflection(graph: Graph, top_down: Boolean): Double = |
253 def deflection(graph: Graph, top_down: Boolean): Double = |
232 ((for (a <- content.iterator) yield { |
254 ((for (a <- content.iterator) yield { |
233 val x = graph.get_node(a).x |
255 val x = graph.get_node(a).x |
234 val bs = if (top_down) graph.imm_preds(a) else graph.imm_succs(a) |
256 val bs = if (top_down) graph.imm_preds(a) else graph.imm_succs(a) |
315 } |
337 } |
316 |
338 |
317 private def rubberband( |
339 private def rubberband( |
318 options: Options, metrics: Metrics, levels: List[Level], graph: Graph): Graph = |
340 options: Options, metrics: Metrics, levels: List[Level], graph: Graph): Graph = |
319 { |
341 { |
320 val gap = metrics.box_gap |
342 val gap = metrics.gap |
321 def left(g: Graph, v: Vertex) = vertex_left(metrics, g, v) |
|
322 def right(g: Graph, v: Vertex) = vertex_right(metrics, g, v) |
|
323 |
343 |
324 (graph /: (1 to options.int("graphview_iterations_rubberband"))) { case (graph, _) => |
344 (graph /: (1 to options.int("graphview_iterations_rubberband"))) { case (graph, _) => |
325 (graph /: levels) { case (graph, level) => |
345 (graph /: levels) { case (graph, level) => |
326 val m = level.length - 1 |
346 val m = level.length - 1 |
327 (graph /: level.iterator.zipWithIndex) { |
347 (graph /: level.iterator.zipWithIndex) { |
328 case (g, (v, i)) => |
348 case (g, (v, i)) => |
329 val d = force_weight(g, v) |
349 val d = force_weight(g, v) |
330 if (d < 0.0 && (i == 0 || right(g, level(i - 1)) + gap < left(g, v) + d) || |
350 if (d < 0.0 && (i == 0 || vertex_right(g, level(i - 1)) + gap < vertex_left(g, v) + d) || |
331 d > 0.0 && (i == m || left(g, level(i + 1)) - gap > right(g, v) + d)) |
351 d > 0.0 && (i == m || vertex_left(g, level(i + 1)) - gap > vertex_right(g, v) + d)) |
332 move_vertex(g, v, d.round.toDouble) |
352 move_vertex(g, v, d.round.toDouble) |
333 else g |
353 else g |
334 } |
354 } |
335 } |
355 } |
336 } |
356 } |
342 val input_graph: Graph_Display.Graph, |
362 val input_graph: Graph_Display.Graph, |
343 val output_graph: Layout.Graph) |
363 val output_graph: Layout.Graph) |
344 { |
364 { |
345 /* vertex coordinates */ |
365 /* vertex coordinates */ |
346 |
366 |
347 def get_vertex(v: Layout.Vertex): Layout.Point = |
|
348 if (output_graph.defined(v)) output_graph.get_node(v) |
|
349 else Layout.Point.zero |
|
350 |
|
351 def translate_vertex(v: Layout.Vertex, dx: Double, dy: Double): Layout = |
367 def translate_vertex(v: Layout.Vertex, dx: Double, dy: Double): Layout = |
352 { |
368 { |
353 if ((dx == 0.0 && dy == 0.0) || !output_graph.defined(v)) this |
369 if ((dx == 0.0 && dy == 0.0) || !output_graph.defined(v)) this |
354 else { |
370 else { |
355 val output_graph1 = output_graph.map_node(v, p => Layout.Point(p.x + dx, p.y + dy)) |
371 val output_graph1 = |
|
372 output_graph.map_node(v, info => info.copy(x = info.x + dx, y = info.y + dy)) |
356 new Layout(metrics, input_graph, output_graph1) |
373 new Layout(metrics, input_graph, output_graph1) |
357 } |
374 } |
358 } |
375 } |
359 |
376 |
360 |
377 |
|
378 /* regular nodes */ |
|
379 |
|
380 def get_node(node: Graph_Display.Node): Layout.Info = |
|
381 output_graph.get_node(Layout.Node(node)) |
|
382 |
|
383 def nodes_iterator: Iterator[Layout.Info] = |
|
384 for ((_: Layout.Node, (info, _)) <- output_graph.iterator) yield info |
|
385 |
|
386 |
361 /* dummies */ |
387 /* dummies */ |
362 |
388 |
363 def dummies_iterator: Iterator[Layout.Point] = |
389 def dummies_iterator: Iterator[Layout.Info] = |
364 for ((_: Layout.Dummy, (p, _)) <- output_graph.iterator) yield p |
390 for ((_: Layout.Dummy, (info, _)) <- output_graph.iterator) yield info |
365 |
391 |
366 def dummies_iterator(edge: Graph_Display.Edge): Iterator[Layout.Point] = |
392 def dummies_iterator(edge: Graph_Display.Edge): Iterator[Layout.Info] = |
367 new Iterator[Layout.Point] { |
393 new Iterator[Layout.Info] { |
368 private var index = 0 |
394 private var index = 0 |
369 def hasNext: Boolean = output_graph.defined(Layout.Dummy(edge._1, edge._2, index)) |
395 def hasNext: Boolean = output_graph.defined(Layout.Dummy(edge._1, edge._2, index)) |
370 def next: Layout.Point = |
396 def next: Layout.Info = |
371 { |
397 { |
372 val p = output_graph.get_node(Layout.Dummy(edge._1, edge._2, index)) |
398 val info = output_graph.get_node(Layout.Dummy(edge._1, edge._2, index)) |
373 index += 1 |
399 index += 1 |
374 p |
400 info |
375 } |
401 } |
376 } |
402 } |
377 } |
403 } |
378 |
404 |