src/Tools/Graphview/layout.scala
author wenzelm
Mon, 05 Jan 2015 22:41:09 +0100
changeset 59292 fef652c88263
parent 59290 569a8109eeb2
child 59302 4d985afc0565
permissions -rw-r--r--
proper bounding box including dummies;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
     1
/*  Title:      Tools/Graphview/layout.scala
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     2
    Author:     Markus Kaiser, TU Muenchen
59240
e411afcfaa29 tuned headers;
wenzelm
parents: 59232
diff changeset
     3
    Author:     Makarius
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
     4
59261
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
     5
DAG layout algorithm, according to:
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
     6
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
     7
  Georg Sander, "Graph Layout through the VCG Tool", in: Graph Drawing,
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
     8
  DIMACS International Workshop (GD'94), Springer LNCS 894, 1995.
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
     9
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
    10
  http://dx.doi.org/10.1007/3-540-58950-3_371
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
    11
  ftp://ftp.cs.uni-sb.de/pub/graphics/vcg/doc/tr-A03-94.ps.gz
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    12
*/
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    13
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    14
package isabelle.graphview
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    15
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    16
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    17
import isabelle._
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    18
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    19
59232
07a7dfd6d694 tuned signature;
wenzelm
parents: 59202
diff changeset
    20
object Layout
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    21
{
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    22
  object Point { val zero: Point = Point(0.0, 0.0) }
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    23
  case class Point(x: Double, y: Double)
50469
wenzelm
parents: 50468
diff changeset
    24
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    25
  private type Key = Graph_Display.Node
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    26
  private type Coordinates = Map[Key, Point]
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    27
  private type Level = List[Key]
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    28
  private type Levels = List[Level]
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
    29
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
    30
  val empty: Layout =
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
    31
    new Layout(Metrics.default, Graph_Display.empty_graph, Map.empty, Map.empty)
50470
wenzelm
parents: 50469
diff changeset
    32
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    33
  val pendulum_iterations = 10
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    34
  val minimize_crossings_iterations = 40
50469
wenzelm
parents: 50468
diff changeset
    35
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
    36
  def make(metrics: Metrics, visible_graph: Graph_Display.Graph): Layout =
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    37
  {
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    38
    if (visible_graph.is_empty) empty
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    39
    else {
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    40
      val initial_levels = level_map(visible_graph)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    41
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    42
      val (dummy_graph, dummies, dummy_levels) =
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    43
        ((visible_graph, Map.empty[(Key, Key), List[Key]], initial_levels) /:
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    44
          visible_graph.edges_iterator) {
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    45
            case ((graph, dummies, levels), (from, to)) =>
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    46
              if (levels(to) - levels(from) <= 1) (graph, dummies, levels)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    47
              else {
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    48
                val (graph1, ds, levels1) = add_dummies(graph, from, to, levels)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    49
                (graph1, dummies + ((from, to) -> ds), levels1)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    50
              }
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
    51
          }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    52
50469
wenzelm
parents: 50468
diff changeset
    53
      val levels = minimize_crossings(dummy_graph, level_list(dummy_levels))
wenzelm
parents: 50468
diff changeset
    54
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    55
      val initial_coordinates: Coordinates =
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    56
        (((Map.empty[Key, Point], 0.0) /: levels) {
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    57
          case ((coords1, y), level) =>
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    58
            ((((coords1, 0.0) /: level) {
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    59
              case ((coords2, x), key) =>
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    60
                val w2 = metrics.box_width2(key)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    61
                (coords2 + (key -> Point(x + w2, y)), x + 2 * w2 + metrics.box_gap)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    62
            })._1, y + metrics.box_height(level.length))
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    63
        })._1
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
    64
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    65
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    66
      val coords = pendulum(metrics, dummy_graph, levels, initial_coordinates)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    67
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    68
      val dummy_coords =
50467
wenzelm
parents: 49746
diff changeset
    69
        (Map.empty[(Key, Key), List[Point]] /: dummies.keys) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    70
          case (map, key) => map + (key -> dummies(key).map(coords(_)))
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    71
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    72
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
    73
      new Layout(metrics, visible_graph, coords, dummy_coords)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    74
    }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
    75
  }
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
    76
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    77
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    78
  def add_dummies(graph: Graph_Display.Graph, from: Key, to: Key, levels: Map[Key, Int])
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    79
    : (Graph_Display.Graph, List[Key], Map[Key, Int]) =
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    80
  {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    81
    val ds =
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    82
      ((levels(from) + 1) until levels(to)).map(l => {
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    83
          // FIXME !?
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    84
          val ident = "%s$%s$%d".format(from.ident, to.ident, l)
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
    85
          Graph_Display.Node(" ", ident)
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    86
        }).toList
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    87
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    88
    val ls =
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    89
      (levels /: ((levels(from) + 1) until levels(to)).zip(ds)) {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    90
        case (ls, (l, d)) => ls + (d -> l)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    91
      }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    92
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
    93
    val graph1 = (graph /: ds)(_.new_node(_, Nil))
49744
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    94
    val graph2 =
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    95
      (graph1.del_edge(from, to) /: (from :: ds ::: List(to)).sliding(2)) {
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    96
        case (g, List(x, y)) => g.add_edge(x, y)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    97
      }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    98
    (graph2, ds, ls)
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
    99
  }
84904ce4905b tuned source structure;
wenzelm
parents: 49737
diff changeset
   100
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   101
  def level_map(graph: Graph_Display.Graph): Map[Key, Int] =
50467
wenzelm
parents: 49746
diff changeset
   102
    (Map.empty[Key, Int] /: graph.topological_order) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   103
      (levels, key) => {
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   104
        val lev = 1 + (-1 /: graph.imm_preds(key)) { case (m, key) => m max levels(key) }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   105
        levels + (key -> lev)
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   106
      }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   107
    }
50469
wenzelm
parents: 50468
diff changeset
   108
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   109
  def level_list(map: Map[Key, Int]): Levels =
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   110
  {
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   111
    val max_lev = (-1 /: map) { case (m, (_, l)) => m max l }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   112
    val buckets = new Array[Level](max_lev + 1)
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   113
    for (l <- 0 to max_lev) { buckets(l) = Nil }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   114
    for ((key, l) <- map) { buckets(l) = key :: buckets(l) }
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   115
    buckets.iterator.map(_.sorted(Graph_Display.Node.Ordering)).toList
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   116
  }
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   117
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   118
  def count_crossings(graph: Graph_Display.Graph, levels: Levels): Int =
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   119
  {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   120
    def in_level(ls: Levels): Int = ls match {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   121
      case List(top, bot) =>
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   122
        top.iterator.zipWithIndex.map {
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   123
          case (outer_parent, outer_parent_index) =>
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   124
            graph.imm_succs(outer_parent).iterator.map(bot.indexOf(_))
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   125
            .map(outer_child =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   126
              (0 until outer_parent_index)
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   127
              .map(inner_parent =>
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   128
                graph.imm_succs(top(inner_parent)).iterator.map(bot.indexOf(_))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   129
                .filter(inner_child => outer_child < inner_child)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   130
                .size
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   131
              ).sum
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   132
            ).sum
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   133
        }.sum
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   134
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   135
      case _ => 0
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   136
    }
49746
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   137
5073cb632b6c minor tuning;
wenzelm
parents: 49745
diff changeset
   138
    levels.iterator.sliding(2).map(ls => in_level(ls.toList)).sum
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   139
  }
50469
wenzelm
parents: 50468
diff changeset
   140
59245
be4180f3c236 more formal Graph_Display.Node (with ordering) and Graph_Display.Edge;
wenzelm
parents: 59240
diff changeset
   141
  def minimize_crossings(graph: Graph_Display.Graph, levels: Levels): Levels =
49745
083accbfa77d more conventional Double constants;
wenzelm
parents: 49744
diff changeset
   142
  {
50469
wenzelm
parents: 50468
diff changeset
   143
    def resort_level(parent: Level, child: Level, top_down: Boolean): Level =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   144
      child.map(k => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   145
          val ps = if (top_down) graph.imm_preds(k) else graph.imm_succs(k)
50469
wenzelm
parents: 50468
diff changeset
   146
          val weight =
50468
7a2a4b84c5ee tuned min/max;
wenzelm
parents: 50467
diff changeset
   147
            (0.0 /: ps) { (w, p) => w + (0 max parent.indexOf(p)) } / (ps.size max 1)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   148
          (k, weight)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   149
      }).sortBy(_._2).map(_._1)
50469
wenzelm
parents: 50468
diff changeset
   150
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   151
    def resort(levels: Levels, top_down: Boolean) =
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   152
      if (top_down)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   153
        (List(levels.head) /: levels.tail)((tops, bot) =>
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   154
          resort_level(tops.head, bot, top_down) :: tops).reverse
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   155
      else {
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   156
        val rev_levels = levels.reverse
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   157
        (List(rev_levels.head) /: rev_levels.tail)((bots, top) =>
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   158
          resort_level(bots.head, top, top_down) :: bots)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   159
      }
50469
wenzelm
parents: 50468
diff changeset
   160
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   161
    ((levels, count_crossings(graph, levels), true) /: (1 to minimize_crossings_iterations)) {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   162
      case ((old_levels, old_crossings, top_down), _) => {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   163
          val new_levels = resort(old_levels, top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   164
          val new_crossings = count_crossings(graph, new_levels)
49737
dd6fc7c9504a avoid somewhat heavy rebuilding of SortedMap via map where plain iteration is sufficient;
wenzelm
parents: 49565
diff changeset
   165
          if (new_crossings < old_crossings)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   166
            (new_levels, new_crossings, !top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   167
          else
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   168
            (old_levels, old_crossings, !top_down)
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   169
      }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   170
    }._1
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   171
  }
50469
wenzelm
parents: 50468
diff changeset
   172
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   173
  def pendulum(
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   174
    metrics: Metrics, graph: Graph_Display.Graph,
50474
6ee044e2d1a7 initial layout coordinates more like old browser;
wenzelm
parents: 50470
diff changeset
   175
    levels: Levels, coords: Map[Key, Point]): Coordinates =
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   176
  {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   177
    type Regions = List[List[Region]]
50469
wenzelm
parents: 50468
diff changeset
   178
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   179
    def iteration(
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   180
      coords: Coordinates, regions: Regions, top_down: Boolean): (Coordinates, Regions, Boolean) =
50469
wenzelm
parents: 50468
diff changeset
   181
    {
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   182
      val (coords1, regions1, moved) =
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   183
      ((coords, List.empty[List[Region]], false) /: (if (top_down) regions else regions.reverse)) {
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   184
        case ((coords, tops, moved), bot) =>
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   185
          val bot1 = collapse(coords, bot, top_down)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   186
          val (coords1, moved1) = deflect(coords, bot1, top_down)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   187
          (coords1, bot1 :: tops, moved || moved1)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   188
      }
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   189
      (coords1, regions1.reverse, moved)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   190
    }
50469
wenzelm
parents: 50468
diff changeset
   191
wenzelm
parents: 50468
diff changeset
   192
    def collapse(coords: Coordinates, level: List[Region], top_down: Boolean): List[Region] =
wenzelm
parents: 50468
diff changeset
   193
    {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   194
      if (level.size <= 1) level
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   195
      else {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   196
        var next = level
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   197
        var regions_changed = true
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   198
        while (regions_changed) {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   199
          regions_changed = false
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   200
          for (i <- Range(next.length - 1, 0, -1)) {
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   201
            val (r1, r2) = (next(i - 1), next(i))
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   202
            val d1 = r1.deflection(graph, coords, top_down)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   203
            val d2 = r2.deflection(graph, coords, top_down)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   204
50469
wenzelm
parents: 50468
diff changeset
   205
            if (// Do regions touch?
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   206
                r1.distance(metrics, coords, r2) <= 0.0 &&
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   207
                // Do they influence each other?
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   208
                (d1 <= 0.0 && d2 < d1 || d2 > 0.0 && d1 > d2 || d1 > 0.0 && d2 < 0.0))
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   209
            {
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   210
              regions_changed = true
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   211
              r1.nodes = r1.nodes ::: r2.nodes
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   212
              next = next.filter(next.indexOf(_) != i)
50469
wenzelm
parents: 50468
diff changeset
   213
            }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   214
          }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   215
        }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   216
        next
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   217
      }
50469
wenzelm
parents: 50468
diff changeset
   218
    }
wenzelm
parents: 50468
diff changeset
   219
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   220
    def deflect(
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   221
      coords: Coordinates, level: List[Region], top_down: Boolean): (Coordinates, Boolean) =
50469
wenzelm
parents: 50468
diff changeset
   222
    {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   223
      ((coords, false) /: (0 until level.length)) {
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   224
        case ((coords, moved), i) =>
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   225
          val r = level(i)
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   226
          val d = r.deflection(graph, coords, top_down)
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   227
          val offset =
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   228
            if (d < 0 && i > 0)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   229
              - (level(i - 1).distance(metrics, coords, r) min (- d))
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   230
            else if (d >= 0 && i < level.length - 1)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   231
              r.distance(metrics, coords, level(i + 1)) min d
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   232
            else d
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   233
          (r.move(coords, offset), moved || d != 0)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   234
      }
50469
wenzelm
parents: 50468
diff changeset
   235
    }
wenzelm
parents: 50468
diff changeset
   236
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   237
    val regions = levels.map(level => level.map(new Region(_)))
50469
wenzelm
parents: 50468
diff changeset
   238
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   239
    ((coords, regions, true, true) /: (1 to pendulum_iterations)) {
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   240
      case ((coords, regions, top_down, moved), _) =>
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   241
        if (moved) {
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   242
          val (coords1, regions1, m) = iteration(coords, regions, top_down)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   243
          (coords1, regions1, !top_down, m)
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   244
        }
59263
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   245
        else (coords, regions, !top_down, moved)
03aedb32a763 misc tuning;
wenzelm
parents: 59262
diff changeset
   246
    }._1
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   247
  }
50469
wenzelm
parents: 50468
diff changeset
   248
59261
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
   249
  /*This is an auxiliary class which is used by the layout algorithm when
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
   250
    calculating coordinates with the "pendulum method". A "region" is a
5e7280814916 tuned comments;
wenzelm
parents: 59260
diff changeset
   251
    group of nodes which "stick together".*/
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   252
  private class Region(node: Key)
50469
wenzelm
parents: 50468
diff changeset
   253
  {
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   254
    var nodes: List[Key] = List(node)
50469
wenzelm
parents: 50468
diff changeset
   255
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   256
    def distance(metrics: Metrics, coords: Coordinates, that: Region): Double =
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   257
    {
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   258
      val n1 = this.nodes.last; val x1 = coords(n1).x + metrics.box_width2(n1)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   259
      val n2 = that.nodes.head; val x2 = coords(n2).x - metrics.box_width2(n2)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   260
      x2 - x1 - metrics.box_gap
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   261
    }
50469
wenzelm
parents: 50468
diff changeset
   262
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   263
    def deflection(graph: Graph_Display.Graph, coords: Coordinates, top_down: Boolean): Double =
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   264
      ((for (a <- nodes.iterator) yield {
59264
wenzelm
parents: 59263
diff changeset
   265
        val x = coords(a).x
wenzelm
parents: 59263
diff changeset
   266
        val bs = if (top_down) graph.imm_preds(a) else graph.imm_succs(a)
wenzelm
parents: 59263
diff changeset
   267
        bs.iterator.map(coords(_).x - x).sum / (bs.size max 1)
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   268
      }).sum / nodes.length).round.toDouble
50469
wenzelm
parents: 50468
diff changeset
   269
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   270
    def move(coords: Coordinates, dx: Double): Coordinates =
59265
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   271
      if (dx == 0.0) coords
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   272
      else
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   273
        (coords /: nodes) {
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   274
          case (cs, node) =>
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   275
            val p = cs(node)
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   276
            cs + (node -> Point(p.x + dx, p.y))
962ad3942ea7 more metrics, with integer coordinates for layout;
wenzelm
parents: 59264
diff changeset
   277
        }
49557
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   278
  }
61988f9df94d added Graphview tool, based on Isabelle/Scala and Swing/Graphics2D;
Markus Kaiser <markus.kaiser@in.tum.de>
parents:
diff changeset
   279
}
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   280
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   281
final class Layout private(
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   282
  val metrics: Metrics,
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   283
  val visible_graph: Graph_Display.Graph,
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   284
  nodes: Map[Graph_Display.Node, Layout.Point],
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   285
  dummies: Map[Graph_Display.Edge, List[Layout.Point]])
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   286
{
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   287
  /* nodes */
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   288
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   289
  def get_node(node: Graph_Display.Node): Layout.Point =
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   290
    nodes.getOrElse(node, Layout.Point.zero)
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   291
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   292
  def map_node(node: Graph_Display.Node, f: Layout.Point => Layout.Point): Layout =
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   293
    nodes.get(node) match {
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   294
      case None => this
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   295
      case Some(p) =>
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   296
        val nodes1 = nodes + (node -> f(p))
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   297
        new Layout(metrics, visible_graph, nodes1, dummies)
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   298
    }
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   299
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   300
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   301
  /* dummies */
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   302
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   303
  def get_dummies(edge: Graph_Display.Edge): List[Layout.Point] =
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   304
    dummies.getOrElse(edge, Nil)
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   305
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   306
  def map_dummies(edge: Graph_Display.Edge, f: List[Layout.Point] => List[Layout.Point]): Layout =
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   307
    dummies.get(edge) match {
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   308
      case None => this
59290
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   309
      case Some(ds) =>
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   310
        val dummies1 = dummies + (edge -> f(ds))
569a8109eeb2 separate module Metrics;
wenzelm
parents: 59265
diff changeset
   311
        new Layout(metrics, visible_graph, nodes, dummies1)
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   312
    }
59292
fef652c88263 proper bounding box including dummies;
wenzelm
parents: 59290
diff changeset
   313
fef652c88263 proper bounding box including dummies;
wenzelm
parents: 59290
diff changeset
   314
  def dummies_iterator: Iterator[Layout.Point] =
fef652c88263 proper bounding box including dummies;
wenzelm
parents: 59290
diff changeset
   315
    for { (_, ds) <- dummies.iterator; d <- ds.iterator } yield d
59262
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   316
}
5cd92c743958 explicit Layout.Point;
wenzelm
parents: 59261
diff changeset
   317