/*******************************************************************************
* Copyright (c) 2016 itemis AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
* Matthias Wienand (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.fx.nodes;
import java.util.List;
import org.eclipse.gef.fx.anchors.DynamicAnchor;
import org.eclipse.gef.fx.anchors.IAnchor;
import org.eclipse.gef.geometry.planar.Line;
import org.eclipse.gef.geometry.planar.Point;
import javafx.geometry.Point2D;
import javafx.scene.Node;
/**
* The {@link StraightRouter} is an {@link IConnectionRouter} that leaves the
* {@link Connection}'s control points untouched and only provides reference
* points for the {@link Connection}'s anchors.
*
* @author anyssen
* @author mwienand
*
*/
public class StraightRouter extends AbstractRouter {
/**
* Returns the reference point for the anchor at the given index.
*
* @param index
* The index specifying the anchor for which to provide a
* reference point.
* @return The reference point for the anchor at the given index within the
* local coordinate system of the anchored, which is the
* Connection's curve.
*/
@Override
protected Point getAnchoredReferencePoint(List<Point> points,
int index) {
if (index < 0 || index >= points.size()) {
throw new IndexOutOfBoundsException();
}
// compute new reference point
Point newRef = null;
Point pred = getPred(points, index);
Point succ = getSucc(points, index);
if (pred == null && succ == null) {
/*
* Neither predecessor nor successor can be identified. This can
* happen for the initialization of connections when a static
* position is inside the anchorage of the current anchor. This
* means, the reference point that is returned now will be discarded
* in a succeeding call (we have to come up with some value here for
* the DynamicAnchor to work with).
*/
newRef = new Point();
} else if (succ == null && pred != null) {
newRef = pred;
} else if (pred == null && succ != null) {
newRef = succ;
} else {
newRef = new Line(pred, succ).get(0.5);
}
return newRef;
}
private Point getNeighbor(List<Point> points, int anchorIndex, int step) {
List<IAnchor> anchors = getConnection().getAnchorsUnmodifiable();
IAnchor anchor = anchors.get(anchorIndex);
if (!(anchor instanceof DynamicAnchor)) {
throw new IllegalStateException(
"Specified anchor '" + anchor + "' is no DynamicAnchor.");
}
Node anchorage = anchor.getAnchorage();
// first uncontained static anchor (no anchorage)
// or first anchorage center
for (int i = anchorIndex + step; i < anchors.size()
&& i >= 0; i += step) {
IAnchor predAnchor = anchors.get(i);
if (predAnchor == null) {
throw new IllegalStateException(
"connection inconsistent (null anchor)");
}
Node predAnchorage = predAnchor.getAnchorage();
if (predAnchorage == null || predAnchorage == getConnection()) {
// anchor is static
Point position = points.get(i);
Point2D local = anchorage.sceneToLocal(
getConnection().localToScene(position.x, position.y));
if (!anchorage.contains(local)) {
return position;
}
} else {
// anchor position depends on anchorage
Point position = getAnchorageGeometry(i).getBounds()
.getCenter();
if (position == null || Double.isNaN(position.x)
|| Double.isNaN(position.y)) {
throw new IllegalStateException(
"cannot determine anchorage center");
}
return position;
}
}
// no neighbor found
return null;
}
private Point getPred(List<Point> points, int anchorIndex) {
return getNeighbor(points, anchorIndex, -1);
}
private Point getSucc(List<Point> points, int anchorIndex) {
return getNeighbor(points, anchorIndex, 1);
}
}