Home » Eclipse Projects » GEF » curved connections
curved connections [message #769560] |
Thu, 22 December 2011 10:30 |
sebastian.sprenger Messages: 16 Registered: November 2009 |
Junior Member |
|
|
Hallo,
I was looking for a way to connect two nodes with a cubic curve and I recognized, that I wasn't the fist looking for it.
I wanted the connections to look like the pipe-connection in Yahoo Pipes. I didn't anything. So I tried it myself with the following result. It's quite alright but it could be better. I would be glad if somebody had some hints for improvements, because im not good in graphic programming. the screenshot shows, how the connections look. The connection doesn't work well with the ShortestPathConnectionRouter (I think its because of obstacle avoidance). I used ConnectionRouter.NULL.
This is the Connection-Class:
import java.awt.LayoutManager;
import java.awt.geom.AffineTransform;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.AbstractPointListShape;
import org.eclipse.draw2d.Connection;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.ConnectionRouter;
import org.eclipse.draw2d.FigureListener;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.LayoutListener;
import org.eclipse.draw2d.Polyline;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.RoutingListener;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.draw2d.UpdateListener;
import org.eclipse.draw2d.UpdateManager;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Listener;
/**
*
* @author scheglov_ke
*/
public class PipeConnection extends PolylineConnection {
private static int OFFSET_X = 80;
private static int OFFSET_Y = 15;
private PointList connectionPoints = new PointList();
private int bend_X;
private int bend_Y;
@Override
protected void outlineShape(Graphics g) {
Point bendPointStart = null;
Point bendPointEnd = null;
int lineup = calculateLineup(getStart(), getEnd());
switch (lineup) {
case 1:
bendPointStart = new Point(getStart().x + bend_X, getStart().y - bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);
break;
case 2:
bendPointStart = new Point(getStart().x + bend_X, getStart().y + bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);
break;
case 3:
bendPointStart = new Point(getStart().x + bend_X, getStart().y - bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);
break;
case 4:
bendPointStart = new Point(getStart().x + bend_X, getStart().y + bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);
break;
default:
break;
}
CubicCurve2D curve = new CubicCurve2D.Float(getStart().x, getStart().y,
bendPointStart.x, bendPointStart.y, bendPointEnd.x,
bendPointEnd.y, getEnd().x, getEnd().y);
PathIterator pi = curve.getPathIterator(null, Float.MIN_VALUE);
PointList pl = new PointList();
pl.addPoint(getStart());
while (pi.isDone() == false) {
Point p = getCurrentPoint(pi);
if(pl.size()>0){
Point last = pl.getLastPoint();
if(p.x != last.x && p.y != last.y){
pl.addPoint(p);
}
}
pi.next();
}
connectionPoints.removeAllPoints();
connectionPoints.addAll(pl);
g.setInterpolation(SWT.HIGH);
pl.addPoint(getEnd());
Display display = Display.getCurrent();
g.setAntialias(SWT.ON);
g.setForegroundColor(display.getSystemColor(SWT.COLOR_DARK_BLUE));
g.setLineWidth(3);
g.setAlpha(180);
g.drawPolyline(connectionPoints);
g.setForegroundColor(display.getSystemColor(SWT.COLOR_WHITE));
g.setLineWidth(1);
g.drawPolyline(connectionPoints);
}
@Override
public void paint(Graphics graphics) {
// TODO Auto-generated method stub
super.paint(graphics);
}
private Point getCurrentPoint(PathIterator pi) {
double[] coordinates = new double[6];
Point p = new Point();
int type = pi.currentSegment(coordinates);
if(type == PathIterator.SEG_LINETO || type == PathIterator.SEG_MOVETO){
Double d = new Double(coordinates[0]);
long x = Math.round(coordinates[0]);
long y = Math.round(coordinates[1]);
p.setX(new Long(x).intValue());
p.setY(new Long(y).intValue());
}
return p;
}
@Override
public Rectangle getBounds() {
// TODO Auto-generated method stub
Rectangle bounds = super.getBounds();
Rectangle newBounds = new Rectangle();
newBounds.width = bounds.width + 40;
newBounds.height = bounds.height + 40;
newBounds.x = bounds.x - 20;
newBounds.y = bounds.y - 20;
bounds.union(newBounds);
return bounds;
}
private int calculateLineup(Point startPoint, Point endPoint) {
if (startPoint.x <= endPoint.x && startPoint.y <= endPoint.y) {
this.bend_X = OFFSET_X;
this.bend_Y = OFFSET_Y;
return 1;
}
if (startPoint.x <= endPoint.x && startPoint.y >= endPoint.y) {
this.bend_X = OFFSET_X;
this.bend_Y = OFFSET_Y;
return 2;
}
if (startPoint.x >= endPoint.x && startPoint.y >= endPoint.y) {
int reference = (startPoint.x - endPoint.x);
if(reference>100)reference = 100;
this.bend_X = OFFSET_X+reference;
this.bend_Y = OFFSET_Y+30;
return 3;
}
if (startPoint.x >= endPoint.x && startPoint.y <= endPoint.y) {
int reference = (startPoint.x - endPoint.x)/2;
if(reference>130)reference = 130;
this.bend_X = OFFSET_X+reference;
this.bend_Y = OFFSET_Y+30;
return 4;
}
return 0;
}
public PointList getConnectionPoints() {
return connectionPoints;
}
public void setConnectionPoints(PointList connectionPoints) {
this.connectionPoints = connectionPoints;
}
}
|
|
| |
Re: curved connections [message #775325 is a reply to message #775291] |
Thu, 05 January 2012 19:17 |
Alex Kravets Messages: 561 Registered: November 2009 |
Senior Member |
|
|
I remember I saw a curved connection in GMF. Looking in the GMF code I found PolylineConnectionEx and abstract ConnectionEditPart, repurposing refreshSmoothness() in ConnectionEditPart and using PolylineConnectionEx for connection given results close to what you did. Close because bends are not as smooth and there is no long bend of outgoing connection, however GMF's approach works with ShortestPathConnectionRouter.
Here are screenshots of both solutions (yours in on the top): http://imgur.com/a/cjxXb
Also notice that target anchors are correctly translated in GMF's code.
[Updated on: Thu, 05 January 2012 19:19] Report message to a moderator
|
|
| |
Re: curved connections [message #892028 is a reply to message #872608] |
Tue, 26 June 2012 21:48 |
Sebastian Sprenger Messages: 10 Registered: January 2012 |
Junior Member |
|
|
Hallo,
because the curves were a little bit nasty, I tried to improve it a little.
here is the connection class:
package org.ssprenger.spectrecockpit.figures;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.widgets.Display;
/**
*
* @author scheglov_ke
*/
public class PipeConnection extends PolylineConnection {
private static int OFFSET_X = 80;
private static int OFFSET_Y = 15;
private List<PrecisionPoint> connectionPoints = new ArrayList<PrecisionPoint>();
private int bend_X;
private int bend_Y;
private int queueEntries = 0;
@Override
protected void outlineShape(Graphics g) {
connectionPoints.clear();
Point bendPointStart = null;
Point bendPointEnd = null;
int lineup = calculateLineup(getStart(), getEnd());
switch (lineup) {
case 1:
bendPointStart = new Point(getStart().x + bend_X, getStart().y
- bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);
break;
case 2:
bendPointStart = new Point(getStart().x + bend_X, getStart().y
+ bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);
break;
case 3:
bendPointStart = new Point(getStart().x + bend_X, getStart().y
- bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);
break;
case 4:
bendPointStart = new Point(getStart().x + bend_X, getStart().y
+ bend_Y);
bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);
break;
default:
break;
}
CubicCurve2D curve = new CubicCurve2D.Float(getStart().x, getStart().y,
bendPointStart.x, bendPointStart.y, bendPointEnd.x,
bendPointEnd.y, getEnd().x, getEnd().y);
PathIterator pi = curve.getPathIterator(null, Float.MIN_VALUE);
while (pi.isDone() == false) {
PrecisionPoint p = getCurrentPoint(pi);
connectionPoints.add(p);
pi.next();
}
Path p = new Path(Display.getCurrent());
p.moveTo(getStart().x, getStart().y);
for (PrecisionPoint po : connectionPoints) {
p.lineTo((float) po.preciseX(), (float) po.preciseY());
}
p.lineTo(getEnd().x, getEnd().y);
g.setInterpolation(SWT.HIGH);
Display display = Display.getCurrent();
g.setAntialias(SWT.ON);
g.setForegroundColor(display.getSystemColor(SWT.COLOR_DARK_BLUE));
g.setLineWidth(4);
g.setAlpha(180);
g.drawPath(p);
g.setForegroundColor(display.getSystemColor(SWT.COLOR_WHITE));
g.setLineWidth(2);
g.drawPath(p);
g.setForegroundColor(display.getSystemColor(SWT.COLOR_RED));
g.setLineWidth(4);
int counter = queueEntries;
Path path = new Path(Display.getCurrent());
PrecisionPoint last = connectionPoints.get(connectionPoints.size() - 1);
path.moveTo((float) last.preciseX(), (float) last.preciseY());
int size = connectionPoints.size() - 1;
for (int i = 0; i < counter * 35; i++) {
PrecisionPoint nextPoint = connectionPoints.get(size - i);
path.lineTo((float) nextPoint.preciseX(),
(float) nextPoint.preciseY());
}
if (counter > 1) {
g.drawPath(path);
}
}
@Override
public void paint(Graphics graphics) {
// TODO Auto-generated method stub
super.paint(graphics);
}
private PrecisionPoint getCurrentPoint(PathIterator pi) {
double[] coordinates = new double[6];
PrecisionPoint p = new PrecisionPoint();
int type = pi.currentSegment(coordinates);
if (type == PathIterator.SEG_LINETO || type == PathIterator.SEG_MOVETO) {
double x = coordinates[0];
double y = coordinates[1];
p.setPreciseX(x);
p.setPreciseY(y);
}
return p;
}
@Override
public Rectangle getBounds() {
// TODO Auto-generated method stub
Rectangle bounds = super.getBounds();
Rectangle newBounds = new Rectangle();
newBounds.width = bounds.width + 40;
newBounds.height = bounds.height + 40;
newBounds.x = bounds.x - 20;
newBounds.y = bounds.y - 20;
bounds.union(newBounds);
return bounds;
}
private int calculateLineup(Point startPoint, Point endPoint) {
if (startPoint.x <= endPoint.x && startPoint.y <= endPoint.y) {
this.bend_X = OFFSET_X;
this.bend_Y = OFFSET_Y;
return 1;
}
if (startPoint.x <= endPoint.x && startPoint.y >= endPoint.y) {
this.bend_X = OFFSET_X;
this.bend_Y = OFFSET_Y;
return 2;
}
if (startPoint.x >= endPoint.x && startPoint.y >= endPoint.y) {
int reference = (startPoint.x - endPoint.x);
if (reference > 100)
reference = 100;
this.bend_X = OFFSET_X + reference;
this.bend_Y = OFFSET_Y + 30;
return 3;
}
if (startPoint.x >= endPoint.x && startPoint.y <= endPoint.y) {
int reference = (startPoint.x - endPoint.x) / 2;
if (reference > 130)
reference = 130;
this.bend_X = OFFSET_X + reference;
this.bend_Y = OFFSET_Y + 30;
return 4;
}
return 0;
}
public List<PrecisionPoint> getConnectionPoints() {
return connectionPoints;
}
public void setConnectionPoints(List<PrecisionPoint> connectionPoints) {
this.connectionPoints = connectionPoints;
}
public void setEntry(int count) {
this.queueEntries = count;
}
}
in the attachment is screenshot that shows the connections
|
|
|
Goto Forum:
Current Time: Tue Mar 19 06:27:56 GMT 2024
Powered by FUDForum. Page generated in 0.02236 seconds
|