Port direction

I have orthogonal links, with control points movable by the user. Users cannot move the end points of the link, I want those to get automatically computed. I want the end points of the links to connect to the center of each side of a rectangle port automatically.

I almost have this working except the chosen port side is the one in the direction of my source node, instead of the side closest to the last point in the link. (This can sometimes happen when the users adjust the link so it makes a detour to the other side of my nodes to come in the opposite side.)

Is there a method I can override to compute which side of a rectangle port my links get connected to?

Anthony

Basically you may need to override GetFromLinkPoint, GetToLinkPoint, GetFromLinkDir, and GetToLinkDir.
Try: http://www.nwoods.com/forum/uploads/FlexibleEnd.cs
That file also includes a node class inheriting from GoBasicNode that makes use of the FlexibleEndPort, and a link class inheriting from GoLink that automatically adds a couple of points to the stroke and that handles resizing of the points that you care about, so that it dynamically adjusts the end segment, and that handles relinking operations in a smarter manner according to your policy.

Hi Walter,
I am interested in this solution for the adjustable end points, But the link for the file doesn’t work. Can you give me a valid link?

/*
* Copyright © Northwoods Software Corporation, 1998-2006. All Rights
* Reserved.
*
* Restricted Rights: Use, duplication, or disclosure by the U.S.
* Government is subject to restrictions as set forth in subparagraph
* © (1) (ii) of DFARS 252.227-7013, or in FAR 52.227-19, or in FAR
* 52.227-14 Alt. III, as applicable.
/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using Northwoods.Go;
namespace Demo1 {
// sample use:
/

FlexibleEndNode fen1 = new FlexibleEndNode();
fen1.Text = “hello”;
fen1.Location = new PointF(100, 100);
doc.Add(fen1);
FlexibleEndNode fen2 = new FlexibleEndNode();
fen2.Text = “goodbye”;
fen2.Location = new PointF(300, 150);
doc.Add(fen2);
FlexibleEndLink fel = new FlexibleEndLink();
fel.FromPort = fen1.Port;
fel.ToPort = fen2.Port;
doc.DefaultLayer.Add(fel);
fe1.CalculateStroke(); // needed because of override of OnPortChanged
*/
[Serializable]
public class FlexibleEndPort : GoPort {
public FlexibleEndPort() {}
public override PointF GetFromLinkPoint(IGoLink link) {
GoLink l = link as GoLink;
if (l == null && link is GoLabeledLink)
l = (link as GoLabeledLink).RealLink;
if (l != null && l.Orthogonal && l.PointsCount >= 6) {
PointF p = l.GetPoint(2);
p = OrthoPointToward§;
return GetLinkPointFromPoint§;
}
return base.GetFromLinkPoint(link);
}
public override PointF GetToLinkPoint(IGoLink link) {
GoLink l = link as GoLink;
if (l == null && link is GoLabeledLink)
l = (link as GoLabeledLink).RealLink;
if (l != null && l.Orthogonal && l.PointsCount >= 6) {
PointF p = l.GetPoint(l.PointsCount-3);
p = OrthoPointToward§;
return GetLinkPointFromPoint§;
}
return base.GetToLinkPoint(link);
}
private PointF OrthoPointToward(PointF p) {
PointF c = this.Center;
if (Math.Abs(p.X-c.X) >= Math.Abs(p.Y-c.Y)) {
if (p.X >= c.X)
p.X = 9999999;
else
p.X = -9999999;
p.Y = c.Y;
} else {
if (p.Y >= c.Y)
p.Y = 9999999;
else
p.Y = -9999999;
p.X = c.X;
}
return p;
}
public override float GetFromLinkDir(IGoLink link) {
PointF p = GetFromLinkPoint(link);
return OrthoDir§;
}
public override float GetToLinkDir(IGoLink link) {
PointF p = GetToLinkPoint(link);
return OrthoDir§;
}
private float OrthoDir(PointF p) {
float dx = p.X-this.Center.X;
float dy = p.Y-this.Center.Y;
bool q = (dx + dy < 1);
if (dx > dy) {
if (q) return 270; else return 0;
} else {
if (q) return 180; else return 90;
}
}
}
[Serializable]
public class FlexibleEndNode : GoBasicNode {
public FlexibleEndNode() {
this.LabelSpot = Middle;
}
protected override GoPort CreatePort() {
return new FlexibleEndPort();
}
protected override GoShape CreateShape(GoPort p) {
GoRectangle r = new GoRectangle();
r.Selectable = false;
r.Brush = Brushes.LightGreen;
return r;
}
}
[Serializable]
public class FlexibleEndLink : GoLink {
public FlexibleEndLink() {
this.Orthogonal = true;
this.AdjustingStyle = GoLinkAdjustingStyle.End;
}
protected override void AddOrthoPoints(PointF startFrom, float fromDir, PointF endTo, float toDir) {
int idx = this.PointsCount;
base.AddOrthoPoints(startFrom, fromDir, endTo, toDir);
AddPoint(GetPoint(this.PointsCount-1)); // double-up last ortho point
InsertPoint(idx, GetPoint(idx)); // double-up first ortho point
}
public override void DoResize(GoView view, RectangleF origRect, PointF newPoint, int whichHandle, GoInputState evttype, SizeF min, SizeF max) {
base.DoResize(view, origRect, newPoint, whichHandle, evttype, min, max);
// call CalculateStroke to re-determine the points of the end segments (points 0, 1, n-2, n-1),
// based on the positions of point 2 and point n-3
int i = whichHandle - LastHandle;
if (i == 2 || i == this.PointsCount-3 ||
whichHandle == MiddleLeft || whichHandle == MiddleRight || whichHandle == MiddleTop || whichHandle == MiddleBottom) {
this.CalculateStroke();
}
}
public override void OnPortChanged(IGoPort port, int subhint, int oldI, Object oldVal, RectangleF oldRect, int newI, Object newVal, RectangleF newRect) {
if (port == null)
return;
if (subhint == GoLink.ChangedFromPort || subhint == GoLink.ChangedToPort) {
// don’t call CalculateStroke, which OnPortChanged would normally do in these two cases
PortsOnLinkChanged(subhint, oldI, oldVal, oldRect, newI, newVal, newRect);
} else {
base.OnPortChanged(port, subhint, oldI, oldVal, oldRect, newI, newVal, newRect);
}
}
}
}