blob: 9bbe7f38e20dc70a23ddda938b120ab74867cd46 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
*
* @author Bob Brodt
******************************************************************************/
package org.eclipse.bpmn2.modeler.core.features;
import org.eclipse.bpmn2.modeler.core.utils.AnchorUtil;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.mm.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
/**
* Router for connections that can have user-settable bendpoints. The route is
* calculated such that it is the most direct line between source and target,
* but avoids collisions by navigating around shapes.
*/
public class AutomaticConnectionRouter extends BendpointConnectionRouter {
/** The minimum distance between a bendpoint and a shape when rerouting to avoid collisions. */
protected static final int margin = 10;
/**
* Instantiates a new bendpoint connection router.
*
* @param fp the Feature Provider
*/
public AutomaticConnectionRouter(IFeatureProvider fp) {
super(fp);
}
/**
* Calculate route.
*
* @return the connection route
*/
protected ConnectionRoute calculateRoute() {
if (isSelfConnection()) {
return calculateSelfConnectionRoute();
}
GraphicsUtil.debug = false;
Point start = null;
Point end = null;
Point middle = null;
if (movedBendpoint!=null) {
middle = movedBendpoint;
}
// relocate the source and target anchors for closest proximity to their
// opposite shapes' centers or the nearest bendpoint
int length = oldPoints.length;
Point ref;
if (length>2)
ref = oldPoints[1];
else
ref = GraphicsUtil.getShapeCenter(target);
AnchorUtil.moveAnchor(sourceAnchor, ref);
AnchorUtil.adjustAnchors(source);
if (length>2)
ref = oldPoints[length-2];
else
ref = GraphicsUtil.getShapeCenter(source);
AnchorUtil.moveAnchor(targetAnchor, ref);
AnchorUtil.adjustAnchors(target);
ConnectionRoute route = new ConnectionRoute(this, 1, source,target);
start = GraphicsUtil.createPoint(sourceAnchor);
end = GraphicsUtil.createPoint(targetAnchor);
route.setSourceAnchor(sourceAnchor);
route.setTargetAnchor(targetAnchor);
calculateRoute(route, start,middle,end);
return route;
}
protected ConnectionRoute calculateRoute(ConnectionRoute route, Point start, Point middle, Point end) {
if (middle!=null) {
calculateRoute(route, start, middle);
calculateRoute(route, middle, end);
}
else {
calculateRoute(route, start, end);
}
route.add(end);
return route;
}
protected ConnectionRoute calculateRoute(ConnectionRoute route, Point start, Point end) {
route.add(start);
Point p1 = start;
Point p2 = end;
while (true) {
ContainerShape shape = getCollision(p1,p2);
if (shape==null || shape==target || shape==source) {
break;
}
// navigate around this shape
DetourPoints detour = new DetourPoints(shape, margin);
for (Point d : detour.calculateDetour(p1, p2)) {
if (!route.add(d))
return route;
}
p1 = route.get(route.size() - 1);
}
return route;
}
protected void optimize(ConnectionRoute route) {
route.addSpecial(movedBendpoint);
route.optimize();
}
}