Некоторое время я пытался найти решение для рисования путей между элементами управления, которые не пересекаются и не перекрывают друг друга, но, похоже, у меня закончились идеи. Я пробовал использовать MSAGL 1.1.6, а также пытался реализовать его с нуля.
Зеленые пути на изображении представляют пути, которые я хочу нарисовать. Однако я продолжаю получать пути, подобные красным, которые пересекаются друг с другом или с другими элементами управления или частично перекрываются.
Некоторое время я пытался найти решение для рисования путей между элементами управления, которые не пересекаются и не перекрывают друг друга, но, похоже, у меня закончились идеи. Я пробовал использовать MSAGL 1.1.6, а также пытался реализовать его с нуля. [img]https://i.sstatic.net/9nVsxDGK.png[/img]
Зеленые пути на изображении представляют пути, которые я хочу нарисовать. Однако я продолжаю получать пути, подобные красным, которые пересекаются друг с другом или с другими элементами управления или частично перекрываются. [code]private class Conn { public IIndicatorUser Src = null; public IIndicatorUser Dst = null; public Rectangle Rs; public Rectangle Rd; public GPoint SrcCenter; public GPoint DstCenter; public Side SrcSide; public Side DstSide; public int SrcIndex; public int SrcCount; public int DstIndex; public int DstCount; } private enum Side { Left, Right, Top, Bottom }
private static Side ChooseSideTowards(Rectangle rect,GPoint toward) { var center = new GPoint(rect.Left + (rect.Width / 2.0), rect.Top + (rect.Height / 2.0)); var dx = Math.Abs(toward.X - center.X); var dy = Math.Abs(toward.Y - center.Y); const double horizontalBias = 2.7; if(dx>dy*horizontalBias) return toward.X=center.Y ? Side.Bottom : Side.Top; }
private static GPoint AnchorOnSide(Rectangle r,Side side,int index,int count) { const int margin = 6; count=Math.Max(1,count); index=Math.Max(0,Math.Min(index,count-1)); if(side==Side.Left||side==Side.Right) { var x = side == Side.Left ? r.Left : r.Right; var span = Math.Max(0, r.Height - (2 * margin)); var y = r.Top + margin + (span * ((index + 1.0) / (count + 1.0))); return new GPoint(x,y); } else { var y = side == Side.Top ? r.Top : r.Bottom; var span = Math.Max(0, r.Width - (2 * margin)); var x = r.Left + margin + (span * ((index + 1.0) / (count + 1.0))); return new GPoint(x,y); } }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); using(var outPen = new Pen(Color.Black,3.5f)) using(var penGreen = new Pen(Color.LimeGreen,3.0f)) using(var penRed = new Pen(Color.Red,3.0f)) { if(_connections.Count==0) return;
var obstacles = new List(); var inflatedBounds = new Dictionary(); foreach(IIndicatorUser btn in Controls.OfType()) { if(btn.IsDisposed) continue; var r = new Rectangle(btn.Location, new Size(btn.Width, btn.Height)); r.Inflate(1,1); inflatedBounds[btn]=r;
var center = new GPoint(r.Left + (r.Width / 2.0), r.Top + (r.Height / 2.0)); ICurve boundary = CurveFactory.CreateRectangle(r.Width, r.Height, center); var shape = new Microsoft.Msagl.Routing.Shape(boundary); obstacles.Add(shape); }
var conns = new List(); foreach((IIndicatorUser Src, IIndicatorUser Dst) in _connections) { IIndicatorUser src = Src; IIndicatorUser dst = Dst; if(src.IsDisposed||dst.IsDisposed) continue; if(!Controls.Contains((Control)src)||!Controls.Contains((Control)dst)) continue;
Rectangle rs = inflatedBounds[src]; Rectangle rd = inflatedBounds[dst]; var srcCenter = new GPoint(rs.Left + (rs.Width / 2.0), rs.Top + (rs.Height / 2.0)); var dstCenter = new GPoint(rd.Left + (rd.Width / 2.0), rd.Top + (rd.Height / 2.0)); Side ss = ChooseSideTowards(rs, dstCenter); Side ds = ChooseSideTowards(rd, srcCenter);
var srcGroups = new Dictionary(); var dstGroups = new Dictionary(); foreach(Conn c in conns) { (IIndicatorUser Src, Side SrcSide) gs = (c.Src, c.SrcSide); (IIndicatorUser Dst, Side DstSide) gd = (c.Dst, c.DstSide); if(!srcGroups.TryGetValue(gs,out List l1)) { l1=new List(); srcGroups[gs]=l1; } if(!dstGroups.TryGetValue(gd,out List l2)) { l2=new List(); dstGroups[gd]=l2; } l1.Add(c); l2.Add(c); }
foreach(KeyValuePair kv in srcGroups) { Side side = kv.Key.Item2; List list = kv.Value; if(side==Side.Left||side==Side.Right) list.Sort((a,b) => a.DstCenter.Y.CompareTo(b.DstCenter.Y)); else list.Sort((a,b) => a.DstCenter.X.CompareTo(b.DstCenter.X));
for(var i = 0; i a.SrcCenter.Y.CompareTo(b.SrcCenter.Y)); else list.Sort((a,b) => a.SrcCenter.X.CompareTo(b.SrcCenter.X));