Hi Guys. This is a seemingly simple problem that's got me stuck, so I'd be very grateful for any ideas you can offer.

I'm working on a program that has to display fixed nodes and the links between them. The links are uni-directional, but often pairs of nodes have two links (one in each direction). However, those two links are independent - eg one may be available but the other not available. That's what I'm having difficulty displaying.
I have the x,y coords of each node, so for each link I have the x,y of its start and end points. A pair of links are therefore (x1, y1, x2, y2) and (x2, y2, x1,y1). If i simply draw those lines then, of course, one overwrites the other.
Ideally I'd like to shift each line a bit to the right (relative to its direction) so the two links look like the two sides of a motorway (freeway) on a map. That has to be some arithmetic thing you do to the start/end coordinates, but I'm damned if I can work out what that arithmetic is. Can anyone help?
(The code is Java, and maybe there's sone Java-specific trick that can help, but the problem is a math/geometry one that's language-independednt)


2 Weeks
Discussion Span
Last Post by ddanbe

Yes, thanks. Java has something similar, but the unanswered question is how to determine the correct offset to use.
I'm thinking I may be able to fudge it by hard-coding the offsets for all the 45n degree directions, then using the one which is closest to the actual line direction - after all it only has to be good to the nearest pixel!
Still, I suspect that the proper algorithm will turn out to be fairly simple, once you know what it is.


Just as easy to describe I think...

imagine a straight line going in some direction. I want to move that line a few pixels to its right (as seen when facing the same was as the line). Ie the move is at 90 degrees to the line itself.

Imagine the same line but drawn in the reverse direction. That wll move a few pixels to the opposite side, thus giving me two parallel lines 2*a few pixels apart


How about cheating? It's clear you are going to have to check if the new line has been drawn before. And here's what may be a cheat.

Change the line draw to a rectangle with fill. If the lines are just vertical and horizontal the rectangle with the fill or texture pattern would be pretty easy. Nod to http://zetcode.com/gfx/java2d/shapesandfills/

OK so as your rectangle width increases then the texture patern might have more lines.

As to supporting all possible angles, this would be a matter of rotating the fill pattern and using that pattern.

-> Not saying this is the best solution but wanted to share my thought of a dirty fix.


Well, cheating is always an option!
Right now I have just implemented (just a couple of minutes ago) a cheat...
if line is near vertical, shift right if its going down or left if its drawn going up
if line is near horizontal, shift down if its going right or up if its drawn going left
otherwize do both shifts (as above) but for only 0.7*distance (45 degree cases)
(The code is easier than the description!)

Looks OK enough to allow me to continue, but I'd still prefer a proper solution.

:) J


Yes, I see what you are doing there, but will be using color coding for the status of each link, so the forward link may be OK (green) but the backwards link may be out (grey).

Here's a fragment showing some active/inactive nodes and a few active forward links


Edited by JamesCherrill


Maybe I'm wrong, but as I see it, you could always draw your nodes(circles) connected with two lines. No more offset needed in that case. Now act on the lines according to link status.


That was just some test data from the WIP, and there are situations where the nodes are linked just one way.
But anyway, that's still the same question:
the Nodes' centers are at x1,y1 and x2,y2
What are the start/end coordinates of the two lines?


Eureka time...

Looking at my cheated version I noticed that the factors I was using (1, 0, .7) corresponded to the sin and cos of the line's angle, so from that I was able to generalise the solution. And it's just as simple as I thought it would be, once you know it...

    public static Line2D.Double offsetLine(double x1, double y1, double x2, double y2, double offset) {

         // creates a line (x1,y1) - (x2,y2) 
         // but offset a given distance normal to its direction, 
        // offset>0 offsets to right, <0 offsets to left

        // length of line along x and y axis...
        double xLength = x2 - x1;
        double yLength = y2 - y1;

        // sin/cos of the angle of this line...
        double hyp = Math.sqrt(xLength * xLength + yLength * yLength);
        double sin = yLength / hyp;
        double cos = xLength / hyp;

        // deltas to shift the line sideways (relative to its direction)
        double dx = -offset * sin;
        double dy = offset * cos;

        return new Line2D.Double(x1 + dx, y1 + dy, x2 + dx, y2 + dy);

Edited by JamesCherrill


For what it's worth, my solution: (reffering to the picture)
The angle T = arcsin(offset / r)
And so the point (X,Y) can be calculated by
X=x1+ r.sin(T)
Y=y1+ r.cos(T)

The equation for a line given two points is
(y-y1)/(x-x1) = (y2-y1)/(x2-x1)
Hope it helps a bit.


Thanks for that - it's similar to mine, but better in that it fits to the node circles better. Great. DaniWeb (what remains of it) still rules!
Thanks again

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.