Author Topic: How to use LINQ to....  (Read 2158 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
How to use LINQ to....
« on: December 11, 2012, 10:59:38 PM »
... compare a Point3d with list of Civil3d PointEntity objects to determine if any of these points share the same location? Must work with .NET3.5 and newer. For whatever reasons, every time I think I can use LINQ, based on other's examples I've seen, I get confused as soon as I try to write something to try. I don't know why I'm having such a hard time grasping this, as it sure SEEMS simple. AT any rate, a nudge or two, or three, to get me moving would sure help.

In this example, I have a polyline that I will step through it's vertices and want to get the PointEntity, if any, at each one, returning the PointNumber as a string. The PointEntity has a Location property which is a Point3d object. The points are stored in a List<PointEntity> named points.

Code: [Select]
                List<string> ptnums = new List<string>();
                //loop thru vertices, add Pt# to ptnums list if Cogopoint lies at vertex
                for (int i = 0; i < pline.EndParam; i++)
                {
                    Point3d vpt = pline.GetPointAtParameter(i);
                    // use Linq for doing comparison?
                }

Or should this be done in a different way?
« Last Edit: December 11, 2012, 11:33:29 PM by Jeff_M »

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: How to use LINQ to....
« Reply #1 on: December 12, 2012, 12:12:44 AM »
Answered my own question, I think. At least it works and does what I needed.
Code: [Select]
                List<string> ptnums = new List<string>();
                //loop thru vertices, add Pt# to ptnums list if Cogopoint lies at vertex
                for (int i = 0; i < pline.EndParam; i++)
                {
                    Point3d vpt = pline.GetPointAtParameter(i);
                    IEnumerable<PointEntity> foundpt = from p in points
                                  where p.Location.X == vpt.X
                                  where p.Location.Y == vpt.Y
                                  select p;
                    List<PointEntity> ptlist = foundpt.ToList<PointEntity>();
                    if (ptlist.Count > 0)
                        ptnums.Add(ptlist[0].PointNumber.ToString());
                }
It could probably be written differently, but this Linq is still pretty foreign to me.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: How to use LINQ to....
« Reply #2 on: December 12, 2012, 01:58:08 AM »
This Intersect operator might be a little simpler and keep from creating a query inside a loop.
 
Code - C#: [Select]
  1.             int[] first = new int[] { 1, 2, 3 };
  2.             int[] second = new int[] { 3, 4, 5 };
  3.             // intersect returns only elements from the first collection
  4.             // collection that are ALSO in the second collection.
  5.             var q = first.Intersect(second);
  6.  
  7.             foreach (var item in q)
  8.                 Console.Write(item + " ");
  9.  
  10.  

TheMaster

  • Guest
Re: How to use LINQ to....
« Reply #3 on: December 12, 2012, 09:12:29 PM »
... compare a Point3d with list of Civil3d PointEntity objects to determine if any of these points share the same location? Must work with .NET3.5 and newer. For whatever reasons, every time I think I can use LINQ, based on other's examples I've seen, I get confused as soon as I try to write something to try. I don't know why I'm having such a hard time grasping this, as it sure SEEMS simple. AT any rate, a nudge or two, or three, to get me moving would sure help.

In this example, I have a polyline that I will step through it's vertices and want to get the PointEntity, if any, at each one, returning the PointNumber as a string. The PointEntity has a Location property which is a Point3d object. The points are stored in a List<PointEntity> named points.

Code: [Select]
                List<string> ptnums = new List<string>();
                //loop thru vertices, add Pt# to ptnums list if Cogopoint lies at vertex
                for (int i = 0; i < pline.EndParam; i++)
                {
                    Point3d vpt = pline.GetPointAtParameter(i);
                    // use Linq for doing comparison?
                }

Or should this be done in a different way?

Not sure how frequently you need to do this, but spatial indexing is the classical way to approach the problem, as you only need to compare a very small number of candidate points to each point you are searching.

Jeff_M

  • King Gator
  • Posts: 4094
  • C3D user & customizer
Re: How to use LINQ to....
« Reply #4 on: December 12, 2012, 10:13:14 PM »
Thanks, Tony. I know OF spatial indexing but have never had a need to use it (that I know of anyway). The purpose of this code is to find C3D points that were used to snap to their nodes while creating polylines. Most drawings will contain less than 10,000 points and the polylines will most likely not have more than 100, or so, vertices...with most less than 20. In my initial tests, with a drawing containing 5k C3D points, any polyline I select to return the point numbers of, I get the result instantly. So I guess, for this specific purpose, this approach is 'good enough'. :-)

I should note that my iteration of the pline vertices was flawed in the code shown above. It should be i <= pline.EndParam .

Oh, and this little routine will not be used very often, by very many people. If that makes any difference.