using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; namespace AIStudio.Wpf.DiagramDesigner { public class BoundaryPathFinder : IPathFinder { public List UpdateConnectionPoints(IDiagramViewModel diagramViewModel, Point sourceA, Point sourceB, FullyCreatedConnectorInfo sourceConnectorInfo, ConnectorInfoBase sinkConnectorInfo) { List connectionPoints; var isFullConnection = sinkConnectorInfo is FullyCreatedConnectorInfo; var points = new List() { sourceA, sourceB }; ConnectorInfo sourceInfo = ConnectorInfo(sourceConnectorInfo.Orientation, points[0].X, points[0].Y, sourceConnectorInfo.DataItem.ItemWidth, sourceConnectorInfo.DataItem.ItemHeight, points[0]); //StartPoint = points[0]; if (isFullConnection) { ConnectorInfo sinkInfo = ConnectorInfo(sinkConnectorInfo.Orientation, points[1].X, points[1].Y, ((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemWidth, ((FullyCreatedConnectorInfo)sinkConnectorInfo).DataItem.ItemHeight, points[1]); connectionPoints = PointInfoBase.ToList(GetConnectionLine(diagramViewModel, sourceInfo, sinkInfo, false, sourceConnectorInfo.IsInnerPoint)); //EndPoint = ConnectionPoints.Last(); } else { connectionPoints = PointInfoBase.ToList(GetConnectionLine(diagramViewModel, sourceInfo, points[1], sourceConnectorInfo.Orientation, false, sourceConnectorInfo.IsInnerPoint)); //EndPoint = new Point(); } return connectionPoints; } public ConnectorInfo ConnectorInfo(ConnectorOrientation orientation, double left, double top, double width, double height, Point position) { return new ConnectorInfo() { Orientation = orientation, DesignerItemSize = new Size(width, height), DesignerItemLeft = left, DesignerItemTop = top, Position = position }; } public List GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false) { var points = new List(); var ends = new List { source.Position, sink.Position }; points.Add(ends[0]); points.AddRange(GetMiddlePoints(source, sink, diagramViewModel.GridCellSize, diagramViewModel.GridMargin, true)); points.Add(ends[1]); var res = points.ToArray(); DoShift(res); return res.ToList(); } public List GetConnectionLine(IDiagramViewModel diagramViewModel, ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false) { var points = new List(); var ends = new List { source.Position, sinkPoint }; points.Add(ends[0]); points.AddRange(GetMiddlePoints(source, new ConnectorInfo() { Orientation = ConnectorOrientation.Top, Position = sinkPoint }, diagramViewModel.GridCellSize, diagramViewModel.GridMargin, false)); points.Add(ends[1]); var res = points.ToArray(); DoShift(res); return res.ToList(); } private IEnumerable GetMiddlePoints(ConnectorInfo source, ConnectorInfo sink, Size gridCellSize, double gridMargin, bool isFullConnection) { var points = new List(); if (isFullConnection) { var p0 = GetFirstSegment(source.Orientation, source.Position, gridCellSize, gridMargin); var p1 = GetFirstSegment(sink.Orientation, sink.Position, gridCellSize, gridMargin); if (p0 == p1) return points; var p2 = new Point(GetNearestCross(p0.X, p1.X), GetNearestCross(p0.Y, p1.Y)); var p3 = new Point(GetNearestCross(p1.X, p0.X), GetNearestCross(p1.Y, p0.Y)); if (p2 == p3) { points.Add(p0); points.Add(p2); points.Add(p1); } else { points.Add(p0); points.Add(p2); if (!(Math.Abs(p2.X - p3.X) < 0.0001) && !(Math.Abs(p2.Y - p3.Y) < 0.0001)) points.Add(new Point(p2.X, p3.Y)); points.Add(p3); points.Add(p1); } DoScale(points, gridCellSize, gridMargin); } return points; } private Point GetFirstSegment(ConnectorOrientation orientation, Point point, Size cellSize, double margin) { double x = (int)((point.X - margin) / cellSize.Width) + 0.5; double y = (int)((point.Y - margin) / cellSize.Height) + 0.5; if (orientation == ConnectorOrientation.Top) return new Point(x, y - 0.5); else if (orientation == ConnectorOrientation.Bottom) return new Point(x, y + 0.5); else if (orientation == ConnectorOrientation.Left) return new Point(x - 0.5, y); else return new Point(x + 0.5, y); } public static double GetNearestCross(double a, double b) { if (Math.Abs(a - b) < 0.0001 && (int)a == a) return a; else if (a < b) return Math.Ceiling(a); else return Math.Floor(a); } public static Point SegmentMiddlePoint(Point p1, Point p2) { return new Point((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); } private void DoScale(List points, Size cellSize, double margin) { for (int i = 0; i < points.Count; i++) { points[i] = new Point(points[i].X * cellSize.Width + margin, points[i].Y * cellSize.Height + margin); } } private void DoShift(Point[] points) { double left = new Point[] { points.FirstOrDefault(), points.LastOrDefault() }.Min(p => p.X); double top = new Point[] { points.FirstOrDefault(), points.LastOrDefault() }.Min(p => p.Y); for (int i = 0; i < points.Length; i++) { points[i].X = points[i].X - left; points[i].Y = points[i].Y - top; } } } }