Chris
Chris

Reputation: 2168

Retrieve Pairs of Points from PointCollection?

I have a collection of Points, stored in a PointCollection.

I need the points in the collection to draw lines. So, for example, if a point collection has four points, that will be two lines, as I use pairs of points in the collection to draw the line. I am looking for a way, preferably using linq, and as few lines of code as possible, to essentially iterate through my PointCollection, extracting the next available pairs of points, and then drawing the line using the pairs of points. Is there a way to do this using linq, lambda expressions, or extension method?

Thanks.

Upvotes: 2

Views: 2660

Answers (4)

Dynami Le Savard
Dynami Le Savard

Reputation: 5036

Assuming you are not using parallelism on your foreach, you could use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;

namespace PointDrawing
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Point> points = new List<Point>();
            points.Add(new Point(1, 1));
            points.Add(new Point(2, 2));
            points.Add(new Point(3, 3));
            points.Add(new Point(4, 4));
            points.Add(new Point(5, 5));
            points.Add(new Point(6, 6));
            points.Add(new Point(7, 7));

            if (points.Count > 0)
            {
                Point src = points[0];
                points.ForEach(p => Draw(ref src, p));
            }
        }

        public static void Draw(ref Point p1, Point p2)
        {
            if (p1 != p2)
            {
                //Draw from p1 to p2 here
            }

            p1 = p2; //assign so that p2 is the next origin
        }
    }
}

That would work with a list of point, but if PointCollection is an IEnumerable you could always add the ever so usefull ForEach extension to your IEnumerables:

public static class Extensions
{
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
        {
            action(item);
        }
    }
}

Upvotes: 1

Amy B
Amy B

Reputation: 110221

Here's a quick snip of code to get the pairs.

var listOfPairs = points
  .Select((p, i) => new {p, i})
  .GroupBy(x => x.i / 2)
  .Where(g => g.Skip(1).Any())
  .Select(g => g.Select(x => x.p).ToList())
  .ToList();

This is not performant if you have thousands of points, compared to a foreach loop.


Here's the other requested form, using a captured variable.

Point previous = points.FirstOrDefault();

List<Pair> pairs = points
  .Skip(1)
  .Select(p =>
  {
    Pair result = new Pair(p, previous)
    previous = p;
    return result;
  })
  .ToList();

Upvotes: 1

Mike Jacobs
Mike Jacobs

Reputation: 509

another approach, using a bit of LINQ and recursion:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace overflow2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Point> points = new List<Point>();
            points.Add(new Point(1, 1));
            points.Add(new Point(2, 2));
            points.Add(new Point(3, 3));
            points.Add(new Point(4, 4));
            points.Add(new Point(5, 5));
            points.Add(new Point(6, 6));
            points.Add(new Point(7, 7)); // odd number to test end

            foreach (LineSegment<Point> linesegment in points.GetPairs())
                Console.WriteLine("From " + linesegment.Value1.ToString() + " to " + linesegment.Value2.ToString());

            Console.ReadLine();
        }
    }

    public class Point
    {
        public int x { get; set; }
        public int y { get; set; }

        public Point(int _x, int _y)
        {
            x = _x;
            y = _x;
        }

        public override string ToString()
        {
            return string.Format("{0},{1}", x, y);
        }
    }

    public class LineSegment<T>
    {
        public T Value1 { get; private set; }
        public T Value2 { get; private set; }

        public LineSegment(T value1, T value2)
        {
            Value1 = value1;
            Value2 = value2;
        }
    }

    public static class Util
    {
        public static List<LineSegment<Point>> GetPairs(this List<Point> points)
        {
            if (points.Count >= 2)
            {
                var pair = new LineSegment<Point>(points.Take(1).First(), points.Skip(1).Take(1).First());
                var res = new List<LineSegment<Point>>() { pair };
                res.AddRange(points.Skip(2).ToList().GetPairs());  // recursion
                return res;
            }
            else
                return new List<LineSegment<Point>>();
        }
    }
}

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1064204

Assuming you just want sequential pairs (note this doesn't draw them - it just lists them):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
static class Program {
    static void Main() {
        PointCollection points = new PointCollection();
        points.Add(new Point(1, 1));
        points.Add(new Point(2, 2));
        points.Add(new Point(3, 3));
        points.Add(new Point(4, 4));
        points.Add(new Point(5, 5));
        points.Add(new Point(6, 6));
        points.Add(new Point(7, 7)); // odd number to test end

        foreach (Tuple<Point, Point> pair in GetPairs(points)) {
            Console.WriteLine("From " + pair.Value1 + " to " + pair.Value2);
        }
    }
    public static IEnumerable<Tuple<Point, Point>>
            GetPairs(PointCollection points) {
        using (IEnumerator<Point> iter = points.GetEnumerator()) {
            while (iter.MoveNext()) {
                Point value1 = (Point)iter.Current;
                if (!iter.MoveNext()) { yield break; }
                yield return new Tuple<Point, Point>(value1, (Point)iter.Current);
            }
        }
    }
}
public struct Tuple<T1, T2> {
    public T1 Value1 { get { return value1; } }
    public T2 Value2 { get { return value2; } }
    private readonly T1 value1;
    private readonly T2 value2;
    public Tuple(T1 value1, T2 value2) {
        this.value1 = value1;
        this.value2 = value2;
    }
}

Upvotes: 0

Related Questions