/// <summary> /// Returns a collection of all the line segments (within certain % range) to all the nodes the current node links to /// </summary> /// <param name="skipPercent">The skip percentage, all segments before the given % will be ignored</param> /// <param name="takePercent">The amount of segments to take</param> /// <returns></returns> internal protected virtual IEnumerable <KeyValuePair <Point, Point> > GetLineSegmentsOfLinks(float skipPercent, float takePercent) { Rectangle area = Area; List <KeyValuePair <Point, Point> > segments = new List <KeyValuePair <Point, Point> >(); var nodes = GetLinkedNodes().ToArray(); int index = 0; foreach (var subn in nodes) { if (subn != null) { // get the start & end positions of the line segment Point source; Point dest; GetSourceAndDestPointsForLink(area, nodes.Length, index, subn, out source, out dest); PointF[] points = GetPointsForLink(subn, source, dest); var segmentsOfLink = new List <KeyValuePair <Point, Point> >(); // generate line segments based on the line type if (parent.LineType == LineTypeEnum.Bezier) { LinkManager.DoBezier(points, 100, (p, p2) => { segmentsOfLink.Add(new KeyValuePair <Point, Point>(new Point((int)p.X, (int)p.Y), new Point((int)p2.X, (int)p2.Y))); }); } else if (parent.LineType == LineTypeEnum.FourWay) { LinkManager.Do4WayLines(points, (p, p2) => { segmentsOfLink.Add(new KeyValuePair <Point, Point>(new Point((int)p.X, (int)p.Y), new Point((int)p2.X, (int)p2.Y))); }); } else if (parent.LineType == LineTypeEnum.Straight) { LinkManager.DoStraight(points, (p, p2) => { segmentsOfLink.Add(new KeyValuePair <Point, Point>(new Point((int)p.X, (int)p.Y), new Point((int)p2.X, (int)p2.Y))); }); } // add the segments to the collection segments.AddRange(segmentsOfLink.Skip((int)(skipPercent * segmentsOfLink.Count)).Take((int)(takePercent * segmentsOfLink.Count))); } index++; } return(segments); }
/// <summary> /// Draw the link with the 4 way lines algorithm /// </summary> /// <param name="g">The graphics object</param> /// <param name="viewportRect">The viewport bounds</param> /// <param name="color">The color of the line segements</param> /// <param name="points">The points to generate the line segments from</param> private void Draw4WayLine(Graphics g, Rectangle viewportRect, Color color, params PointF[] points) { LinkManager.Do4WayLines(points, (pt1, pt2, progress) => { Pen p = new Pen(color); if (progress == 1) { // at the end, draw an arrow p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; } // if the line falls inside the viewport, draw it if (viewportRect.IntersectsWithLine(pt1.X, pt1.Y, pt2.X, pt2.Y)) { g.DrawLine(p, pt1, pt2); } p.Dispose(); }); }
/// <summary> /// Tries to get a link at the given x,y coordinates /// </summary> /// <param name="x">The x coordinate</param> /// <param name="y">The y coordinate</param> /// <param name="l">The link if there is one at the given coordinates</param> /// <returns>True if a link is found</returns> internal bool TryGetLink(int x, int y, out Link l) { Rectangle area = Area; Point clickPoint = new Point(x, y); var nodes = GetLinkedNodes().ToArray(); int index = 0; Link link = default(Link); bool foundLink = false; // check all links to child nodes foreach (var subn in nodes) { if (subn != null) { // get the source & dest point Point source; Point dest; GetSourceAndDestPointsForLink(area, nodes.Length, index, subn, out source, out dest); // get all the control points PointF[] points = GetPointsForLink(subn, source, dest); // define the line segment action Action <PointF, PointF> lineSegmentAction = (p, p2) => { // check if the distance between the line segment and the point clicked is smaller than 3 float distToLine = (float)GetPointToLineDistance(p, p2, clickPoint); if (distToLine < 3) { // determine if the closest point to the line segment actually falls inside the segment float normalLength = (float)Math.Sqrt((p2.X - p.X) * (p2.X - p.X) + (p2.Y - p.Y) * (p2.Y - p.Y)); float u = (clickPoint.X - p.X) * (p2.X - p.X) + (clickPoint.Y - p.Y) * (p2.Y - p.Y); u /= normalLength; //PointF lineVector = new PointF((p2.X - p.X) / normalLength, (p2.Y - p.Y) / normalLength); if (u > 0 && u < normalLength) { // link found link = new Link(this, subn, index); foundLink = true; } } }; // do the appropriate algorithm if (parent.LineType == LineTypeEnum.Bezier) { LinkManager.DoBezier(points, 100, lineSegmentAction); } else if (parent.LineType == LineTypeEnum.FourWay) { LinkManager.Do4WayLines(points, lineSegmentAction); } else if (parent.LineType == LineTypeEnum.Straight) { LinkManager.DoStraight(points, lineSegmentAction); } } index++; } l = link; return(foundLink); }