/******************************************************************************* * 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(); } }