blob: 31dc3e6a5f9bb8c03a9c79a329562534269fc971 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2011, 2019 SAP SE
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* mwenz Bug 352119 - initial API, implementation and documentation contributed by Benjamin Schmeling
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.graphiti.ui.internal.parts;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.AbstractRouter;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.gef.EditPart;
import org.eclipse.graphiti.mm.algorithms.styles.PrecisionPoint;
import org.eclipse.graphiti.mm.pictograms.CurvedConnection;
import org.eclipse.graphiti.ui.internal.config.IConfigurationProviderInternal;
public class CurvedConnectionEditPart extends ConnectionEditPart {
public CurvedConnectionEditPart(IConfigurationProviderInternal configurationProvider, CurvedConnection connection,
EditPart contextParent) {
super(configurationProvider, connection, contextParent);
}
private CurvedConnection getCurvedConnection() {
return (CurvedConnection) super.getConnection();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
*/
@Override
protected IFigure createFigure() {
IFigure ret = super.createFigure();
if (ret instanceof org.eclipse.draw2d.Connection) {
org.eclipse.draw2d.Connection draw2dConnection = (org.eclipse.draw2d.Connection) ret;
List<PrecisionPoint> controllPoints = new ArrayList<PrecisionPoint>();
controllPoints.addAll(getCurvedConnection().getControlPoints());
draw2dConnection.setConnectionRouter(new BezierRouter(controllPoints));
}
return ret;
}
@Override
protected void refreshVisuals() {
super.refreshVisuals();
refreshControlPoints();
}
private void refreshControlPoints() {
IFigure figure = getFigure();
if (figure instanceof org.eclipse.draw2d.Connection) {
org.eclipse.draw2d.Connection draw2dConnection = (org.eclipse.draw2d.Connection) figure;
draw2dConnection.getConnectionRouter().invalidate(draw2dConnection);
}
}
private class BezierRouter extends AbstractRouter {
private List<PrecisionPoint> bezierPoints;
private Map<org.eclipse.draw2d.Connection, Object> constraints = new HashMap<org.eclipse.draw2d.Connection, Object>(
11);
public BezierRouter(List<PrecisionPoint> bezierPoints) {
this.bezierPoints = bezierPoints;
}
@Override
public void invalidate(Connection connection) {
super.invalidate(connection);
bezierPoints.clear();
bezierPoints.addAll(getCurvedConnection().getControlPoints());
}
public void route(org.eclipse.draw2d.Connection connection) {
List<org.eclipse.draw2d.geometry.PrecisionPoint> controllPoints = new ArrayList<org.eclipse.draw2d.geometry.PrecisionPoint>();
PointList points = connection.getPoints();
points.removeAllPoints();
Point ref1 = connection.getTargetAnchor().getReferencePoint();
Point ref2 = connection.getSourceAnchor().getReferencePoint();
org.eclipse.draw2d.geometry.PrecisionPoint start = new org.eclipse.draw2d.geometry.PrecisionPoint();
org.eclipse.draw2d.geometry.PrecisionPoint end = new org.eclipse.draw2d.geometry.PrecisionPoint();
start.setLocation(connection.getSourceAnchor().getLocation(ref1));
connection.translateToRelative(start);
end.setLocation(connection.getTargetAnchor().getLocation(ref2));
connection.translateToRelative(end);
controllPoints.add(start);
double gradient = (end.preciseY() - start.preciseY()) / (-end.preciseX() + start.preciseX());
double ortho_gradient = -Math.pow(gradient, -1);
double orthovector_x = 1;
double orthovector_y = ortho_gradient;
double factor_to_length = 1 / Math.sqrt((Math.pow(orthovector_y, 2) + Math.pow(orthovector_x, 2)));
for (PrecisionPoint precisionPoint : this.bezierPoints) {
double orthovector_x_cp = factor_to_length * orthovector_x * precisionPoint.getY();
double orthovector_y_cp = factor_to_length * orthovector_y * precisionPoint.getY();
if (Double.isNaN(orthovector_x_cp)) {
orthovector_x_cp = 0;
}
if (Double.isNaN(orthovector_y_cp)) {
orthovector_y_cp = 1 * precisionPoint.getY();
}
org.eclipse.draw2d.geometry.PrecisionPoint anchor = new org.eclipse.draw2d.geometry.PrecisionPoint(
(start.x + (end.x - start.x) * precisionPoint.getX() - orthovector_x_cp),
(start.y - (start.y - end.y) * precisionPoint.getX()) + orthovector_y_cp);
controllPoints.add(anchor);
}
controllPoints.add(end);
int precision = 10;
double factor = 1.0d / precision;
points.addPoint(start);
for (int i = 1; i < precision; i++) {
int j = 0;
double sum_x = 0;
double sum_y = 0;
for (Point point : controllPoints) {
sum_x += (bezier(j, controllPoints.size() - 1, i * factor) * point.preciseX());
sum_y += (bezier(j, controllPoints.size() - 1, i * factor) * point.preciseY());
j++;
}
org.eclipse.draw2d.geometry.PrecisionPoint bezierPoint = new org.eclipse.draw2d.geometry.PrecisionPoint(
sum_x, sum_y);
points.addPoint(bezierPoint);
}
points.addPoint(end);
connection.setPoints(points);
}
private double bezier(int i, int n, double t) {
return binomialCoefficients(n, i) * Math.pow(t, i) * Math.pow((1 - t), (n - i));
}
private long binomialCoefficients(int n, int k) {
long coeff = 1;
for (int i = n - k + 1; i <= n; i++) {
coeff *= i;
}
for (int i = 1; i <= k; i++) {
coeff /= i;
}
return coeff;
}
@Override
public void setConstraint(org.eclipse.draw2d.Connection connection, Object constraint) {
constraints.put(connection, constraint);
}
@Override
public void remove(org.eclipse.draw2d.Connection connection) {
constraints.remove(connection);
}
@Override
public Object getConstraint(org.eclipse.draw2d.Connection connection) {
return constraints.get(connection);
}
}
}