All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jungrapht.visualization.layout.algorithms.sugiyama.VerticalAlignment Maven / Gradle / Ivy

The newest version!
package org.jungrapht.visualization.layout.algorithms.sugiyama;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.jgrapht.Graph;
import org.jgrapht.alg.util.NeighborCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @see "Fast and Simple Horizontal Coordinate Assignment, Ulrik Brandes and Boris Köpf, Department
 *     of Computer & Information Science, University of Konstanz"
 * @param 
 * @param 
 */
public abstract class VerticalAlignment {

  private static final Logger log = LoggerFactory.getLogger(VerticalAlignment.class);

  protected Map, LV> rootMap = new HashMap<>();
  protected Map, LV> alignMap = new HashMap<>();
  protected LV[][] layers;
  protected Graph, LE> svGraph;
  protected Set> markedSegments;
  protected NeighborCache, LE> neighborCache;

  public Map, LV> getRootMap() {
    return rootMap;
  }

  public Map, LV> getAlignMap() {
    return alignMap;
  }

  public abstract void align();

  protected VerticalAlignment(
      LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
    this.layers = layers;
    this.svGraph = svGraph;
    this.neighborCache = new NeighborCache<>(svGraph);
    this.markedSegments = markedSegments;
    // initialize root and align
    Arrays.stream(layers)
        .flatMap(Arrays::stream)
        .forEach(
            v -> {
              rootMap.put(v, v);
              alignMap.put(v, v);
            });
  }

  protected boolean notMarked(LE edge) {
    return !markedSegments.contains(edge);
  }

  protected LV root(LV v) {
    return rootMap.get(v);
  }

  protected void root(LV k, LV v) {
    rootMap.put(k, v);
  }

  protected LV align(LV v) {
    return alignMap.get(v);
  }

  protected void align(LV k, LV v) {
    alignMap.put(k, v);
  }

  /**
   * @param v vertix to get pos for
   * @return the pos (index in rank) of the passed vertex
   */
  protected int pos(LV v) {
    return v.getIndex();
  }

  protected int alignMoveCursor(LV um, LV vkofi) {
    align(um, vkofi);
    root(vkofi, root(um));
    align(vkofi, root(vkofi));
    return pos(um);
  }

  /**
   * start at first layer, work down, looking at predecessors
   *
   * @param 
   * @param 
   */
  public static class LeftmostUpper extends VerticalAlignment {

    public LeftmostUpper(
        LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
      super(layers, svGraph, markedSegments);
    }

    @Override
    public void align() {
      for (int i = 0; i <= layers.length - 1; i++) {
        int r = -1;
        LV[] currentLayer = layers[i];
        for (int k = 0; k <= currentLayer.length - 1; k++) {
          LV vkofi = currentLayer[k];
          List> neighbors =
              neighborCache
                  .predecessorsOf(vkofi)
                  .stream()
                  .sorted(Comparator.comparingInt(LV::getIndex))
                  .collect(Collectors.toList());
          int d = neighbors.size();
          if (d > 0) {
            int floor = (int) Math.floor((d - 1) / 2.0);
            int ceil = (int) Math.ceil((d - 1) / 2.0);
            for (int m : new int[] {floor, ceil}) {
              if (align(vkofi) == vkofi) {
                LV um = neighbors.get(m);
                LE edge = svGraph.getEdge(um, vkofi);
                if (notMarked(edge) && r < pos(um)) {
                  r = alignMoveCursor(um, vkofi);
                }
              }
              if (floor == ceil) {
                break;
              }
            }
          }
        }
      }
    }
  }

  public static class RightmostUpper extends VerticalAlignment {

    // up right from top to bottom of layers, from left to right of rows
    public RightmostUpper(
        LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
      super(layers, svGraph, markedSegments);
    }

    @Override
    public void align() {
      for (int i = 1; i <= layers.length - 1; i++) {
        LV[] currentLayer = layers[i];
        LV[] previousLayerInSweep = layers[i - 1];
        int r =
            previousLayerInSweep.length
                + 1; // one past the last index in the previous layer of this sweep
        for (int k = currentLayer.length - 1; k >= 0; k--) {
          LV vkofi = currentLayer[k];
          List> neighbors =
              neighborCache
                  .predecessorsOf(vkofi)
                  .stream()
                  .sorted(Comparator.comparingInt(LV::getIndex))
                  .collect(Collectors.toList());
          int d = neighbors.size();
          if (d > 0) {
            int floor = (int) Math.floor((d - 1) / 2.0);
            int ceil = (int) Math.ceil((d - 1) / 2.0);
            for (int m : new int[] {ceil, floor}) {
              if (align(vkofi) == vkofi) {
                LV um = neighbors.get(m);
                LE edge = svGraph.getEdge(um, vkofi);
                if (notMarked(edge) && r > pos(um)) {
                  r = alignMoveCursor(um, vkofi);
                }
              }
              if (floor == ceil) {
                break;
              }
            }
          }
        }
      }
    }
  }

  /**
   * start at last layer, work upwards looking at successor positions
   *
   * @param 
   * @param 
   */
  public static class LeftmostLower extends VerticalAlignment {

    // down left from bottom to top of layers from left to right of rows
    public LeftmostLower(
        LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
      super(layers, svGraph, markedSegments);
    }

    @Override
    public void align() {
      for (int i = layers.length - 2; i >= 0; i--) {
        int r = -1; // one before the first index of the previous layer of this sweep
        LV[] currentLayer = layers[i];
        for (int k = 0; k < currentLayer.length; k++) {
          LV vkofi = currentLayer[k];
          List> neighbors =
              neighborCache
                  .successorsOf(vkofi)
                  .stream()
                  .sorted(Comparator.comparingInt(LV::getIndex))
                  .collect(Collectors.toList());
          int d = neighbors.size();
          if (d > 0) {
            int floor = (int) Math.floor((d - 1) / 2.0);
            int ceil = (int) Math.ceil((d - 1) / 2.0);
            for (int m : new int[] {floor, ceil}) {
              if (align(vkofi) == vkofi) {
                LV um = neighbors.get(m);
                LE edge = svGraph.getEdge(vkofi, um);
                if (notMarked(edge) && r < pos(um)) {
                  r = alignMoveCursor(um, vkofi);
                }
              }
              if (floor == ceil) {
                break;
              }
            }
          }
        }
      }
    }
  }

  /**
   * start at last layer, work up, looking at successors
   *
   * @param 
   * @param 
   */
  public static class RightmostLower extends VerticalAlignment {

    // down right from bottom to top of layers from right to left
    public RightmostLower(
        LV[][] layers, Graph, LE> svGraph, Set> markedSegments) {
      super(layers, svGraph, markedSegments);
    }

    @Override
    public void align() {
      for (int i = layers.length - 2; i >= 0; i--) {
        LV[] currentLayer = layers[i];
        LV[] previousLayerInSweep = layers[i + 1];
        int r =
            previousLayerInSweep.length
                + 1; // one past the last index in the previous layer of this sweep
        for (int k = currentLayer.length - 1; k >= 0; k--) {
          LV vkofi = currentLayer[k];
          List> neighbors =
              neighborCache
                  .successorsOf(vkofi)
                  .stream()
                  .sorted(Comparator.comparingInt(LV::getIndex))
                  .collect(Collectors.toList());
          int d = neighbors.size();
          if (d > 0) {
            int floor = (int) Math.floor((d - 1) / 2.0);
            int ceil = (int) Math.ceil((d - 1) / 2.0);
            for (int m : new int[] {ceil, floor}) {
              if (align(vkofi) == vkofi) {
                LV um = neighbors.get(m);
                LE edge = svGraph.getEdge(vkofi, um);
                if (notMarked(edge) && r > pos(um)) {
                  r = alignMoveCursor(um, vkofi);
                }
              }
              if (floor == ceil) {
                break;
              }
            }
          }
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy