/*
* Copyright 2012 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.odysseus.ithaka.digraph.layout.sugiyama;
import java.util.Comparator;
import de.odysseus.ithaka.digraph.layout.DigraphLayoutDimension;
import de.odysseus.ithaka.digraph.layout.DigraphLayoutNode;
import de.odysseus.ithaka.digraph.layout.DigraphLayoutPoint;
public class SugiyamaNode<V> implements DigraphLayoutNode<V> {
public static final Comparator<SugiyamaNode<?>> CMP_ID = new Comparator<SugiyamaNode<?>>() {
@Override
public int compare(SugiyamaNode<?> o1, SugiyamaNode<?> o2) {
return o1.id < o2.id ? -1 : o1.id > o2.id ? 1 : 0;
}
};
public static final Comparator<SugiyamaNode<?>> CMP_INDEX = new Comparator<SugiyamaNode<?>>() {
@Override
public int compare(SugiyamaNode<?> o1, SugiyamaNode<?> o2) {
return o1.getIndex() < o2.getIndex() ? -1 : o1.getIndex() > o2.getIndex() ? 1 : 0;
}
};
private static int NEXT_ID = 1;
private int id;
private double position;
private int layer;
private int index;
private int temporary;
private V vertex;
private DigraphLayoutPoint point;
private DigraphLayoutDimension dimension;
private int lowerSlots;
private int upperSlots;
private int lowerCenterSlot = -1;
private int upperCenterSlot = -1;
private int maxSlotDistance = 0;
private SugiyamaNode<V> upper, lower; // for dummy nodes: upper and lower neighbors
/**
* Create dummy node.
* Dummy nodes have <code>null</code> data.
* @param dummyDimension
*/
public SugiyamaNode(DigraphLayoutDimension dummyDimension) {
this(null, dummyDimension, 0);
}
/**
* Create new vertex.
* @param vertex data
* @param dimension
*/
public SugiyamaNode(V vertex, DigraphLayoutDimension dimension, int maxSlotDistance) {
this.id = NEXT_ID++;
this.vertex = vertex;
this.dimension = dimension;
this.maxSlotDistance = Math.min(maxSlotDistance, dimension.w);
}
public int nextLowerSlot() {
return lowerSlots++;
}
public DigraphLayoutPoint getLowerSlotPoint(int slot) {
return new DigraphLayoutPoint(point.x + getOffset(slot, lowerSlots, lowerCenterSlot), point.y + dimension.h);
}
public int nextUpperSlot() {
return upperSlots++;
}
public DigraphLayoutPoint getUpperSlotPoint(int slot) {
return new DigraphLayoutPoint(point.x + getOffset(slot, upperSlots, upperCenterSlot), point.y);
}
private int getOffset(int slot, int slots, int center) {
int x = 0;
if (center < 0) {
int d = Math.min(maxSlotDistance, dimension.w / slots);
x = dimension.w / 2 + (slot - slots / 2) * d;
if (slots % 2 == 0) {
x += d / 2;
}
} else {
int d = Math.min(maxSlotDistance, dimension.w / (2 * Math.max(center, slots - center)));
x = dimension.w / 2 + (slot - center) * d;
}
return x;
}
public void setLowerCenterSlot(int slot) {
lowerCenterSlot = slot;
}
public void setUpperCenterSlot(int slot) {
upperCenterSlot = slot;
}
@Override
public DigraphLayoutDimension getDimension() {
return dimension;
}
public boolean isDummy() {
return vertex == null;
}
@Override
public V getVertex() {
return vertex;
}
public double getPosition() {
return position;
}
public void setPosition(double position) {
this.position = position;
}
public int getLayer() {
return layer;
}
public void setLayer(int layer) {
this.layer = layer;
}
@Override
public DigraphLayoutPoint getPoint() {
return point;
}
public void setPoint(DigraphLayoutPoint point) {
this.point = point;
}
@Override
public String toString() {
return isDummy() ? "<dummy>" : vertex.toString();
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public SugiyamaNode<V> getLower() {
return lower;
}
public void setLower(SugiyamaNode<V> lower) {
this.lower = lower;
}
public SugiyamaNode<V> getUpper() {
return upper;
}
public void setUpper(SugiyamaNode<V> upper) {
this.upper = upper;
}
public int getTemporary() {
return temporary;
}
public void setTemporary(int temporary) {
this.temporary = temporary;
}
}