Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » GEF » curved connections
curved connections [message #769560] Thu, 22 December 2011 10:30 Go to next message
sebastian.sprenger is currently offline 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 #775291 is a reply to message #769560] Thu, 05 January 2012 18:25 Go to previous messageGo to next message
Alex Kravets is currently offline Alex Kravets
Messages: 383
Registered: November 2009
Senior Member
This is pretty awesome! Wish this worked with ShortestPathConnectionRouter, but it's an excellent start.

[Updated on: Thu, 05 January 2012 18:26]

Report message to a moderator

Re: curved connections [message #775325 is a reply to message #775291] Thu, 05 January 2012 19:17 Go to previous messageGo to next message
Alex Kravets is currently offline Alex Kravets
Messages: 383
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 #872608 is a reply to message #775325] Wed, 16 May 2012 12:53 Go to previous messageGo to next message
Karthikeyan Missing name is currently offline Karthikeyan Missing name
Messages: 47
Registered: July 2011
Member
Hi,

1) Is it possible to add bendpoints to the above code. If possible how?
2) Is it possible to reduce the curve radius.

Thanks & Regards,
Karthikeyan.B
Re: curved connections [message #892028 is a reply to message #872608] Tue, 26 June 2012 21:48 Go to previous message
Sebastian Sprenger is currently offline 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
Previous Topic:Custom Figures for Connections in Zest
Next Topic:[Draw2D] Remove figure from layout calculation
Goto Forum:
  


Current Time: Mon Sep 22 18:19:28 GMT 2014

Powered by FUDForum. Page generated in 0.11066 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software