C# errors in visual studio

I’m trying to learn to create a grasshopper component in visual studio 2017.
I found some example codes online, but when I paste them into VS there’s tons of errors when i try to compile.
I’ve fixed some of them, but there’s a few that I don’t know how to fix:

CS0019 Operator ‘==’ cannot be applied to operands of type ‘PointContainment’ and ‘int’
The line causing this error is:
if (curve2.Contains(pList[num]) == 1)

CS1061 ‘List’ does not contain a definition for ‘Last’ and no extension method ‘Last’ accepting a first argument of type ‘List’ could be found (are you missing a using directive or an assembly reference?)
The line causing this error is:
pList2.Add(pList[source.Last<int>()]);

Here’s my code:

protected override void SolveInstance(IGH_DataAccess DA)
        {
            List<Curve> cList = new List<Curve>();
            List<Point3d> pList = new List<Point3d>();
            List<Point3d> pList2 = new List<Point3d>();
            List<Curve> cList2 = new List<Curve>();
            List<Curve> cList3 = new List<Curve>();
            List<int> iList = new List<int>();
            List<int> iList2 = new List<int>();
            List<int> iList3 = new List<int>();
            List<int> iList4 = new List<int>();
            if ((DA.GetDataList<Curve>(0, cList) && DA.GetDataList<Point3d>(1, pList)) && DA.GetDataList<int>(2, iList))
            {
                int num;
                using (List<Curve>.Enumerator enumerator = cList.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        Curve curve = null;
                        if (!curve.IsPlanar())
                        {
                            this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "The input is not planar curve!");
                        }
                    }
                }
                foreach (Curve curve2 in cList)
                {
                    if (curve2.IsClosed)
                    {
                        num = 0;
                        while (num < pList.Count)
                        {
                            if (curve2.Contains(pList[num]) == 1)
                            {
                                iList2.Add(num);
                            }
                            num++;
                        }
                        if (iList2.Count != 0)
                        {
                            cList2.Add(curve2);
                        }
                    }
                }
                foreach (Curve curve in cList2)
                {
                    for (num = 0; num < pList.Count; num++)
                    {
                        if (curve.Contains(pList[num]) == 1)
                        {
                            iList3.Add(num);
                        }
                    }
                    List<int> source = new List<int>();
                    foreach (int num2 in iList3)
                    {
                        double maxValue = double.MaxValue;
                        curve.ClosestPoint(pList[num2], out double num4);
                        double num5 = curve.PointAt(num4).DistanceTo(pList[num2]);
                        if (maxValue > num5)
                        {
                            maxValue = num5;
                            source.Add(num2);
                        }
                    }
                    pList2.Add(pList[source.Last<int>()]);
                    iList4.Add(iList[source.Last<int>()]);
                }
                DA.SetDataList(0, cList2);
                DA.SetDataList(1, iList4);
            }
        }

Can anyone help?

C# doesn’t let you implicitly compare enum and integer types, you have to either use the enum name (more readable) or explicitly cast it to an int:

if (curve2.Contains(pList[num]) == PointContainment.Inside) //preferred
//or 
if ((int) curve2.Contains(pList[num]) == 1)

The line causing this error is:
pList2.Add(pList[source.Last<int>()]);

IEnumerable.Last does not take a generic type argument - you probably want
pList2.Add(pList[source.Last()]); instead.

(Where did you get these example scripts? That part with the enumerator and checking of a null curve makes no sense…)

Curve curve = null;
if (!curve.IsPlanar())
{
this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, “The input is not planar curve!”);
}

Isn’t this problematic? if you are making the curve always right above as null. Then what are you testing for planarity?

hum, didn’t closely read the whole code.
you’re right, this code doesn’t make any sense…

guess i’ll need to find a better example/tutorial.
thanks for the feedbacks

So i went back and read thru the code and rewrote some parts (i don’t 100% understand the original code, so i done some guessing here and there).

I think the code now makes more sense, but it’s not working as it should.
And i’m also getting an error:

Solution exception:Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

caused by
curve.ClosestPoint(pList[n], out double n2);

in the original version it’s suppose to be:
curve.ClosestPoint(pList[n], ref n2);

but if use the original code it’d say:

Error CS1620 Argument 2 must be passed with the 'out' keyword

but i don’t think it’s my edit that’s causing the problem.

Can someone take a look/read thru and explain to me why it’s not working?
thanks

here’s the edited code:

protected override void SolveInstance(IGH_DataAccess DA)
{
  List<Curve> cList = new List<Curve>();
  DA.GetDataList(0, cList);
  List<Point3d> pList = new List<Point3d>();
  DA.GetDataList(1, pList);
  List<int> nList = new List<int>();
  DA.GetDataList(2, nList);
  List<int> nList2 = new List<int>();
  List<Curve> cList2 = new List<Curve>();
  List<int> nList3 = new List<int>();

  for (int i=0; i<cList.Count; i++)
  {
    Curve pCurve = cList[i];
    if (!pCurve.IsPlanar())
    {
      this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Curve input(s) are not planar.");
    }
  }

  foreach (Curve cCurve in cList)
  {
    if (cCurve.IsClosed)
    {
      for (int i=0; i<pList.Count;i++)
      {
        if (cCurve.Contains(pList[i]) == PointContainment.Inside)
          nList2.Add(i);
      }
      if (nList2.Count != 0)
        cList2.Add(cCurve);
    }
  }

  foreach (Curve curve in cList2)
  {
    for(int i=0; i<pList.Count; i++)
    {
      if (curve.Contains(pList[i]) == PointContainment.Inside)
        nList3.Add(i);
    }
    List<int> source = new List<int>();
    foreach(int n in nList3)
    {
      double n2 = 0.0;
      double maxValue = double.MaxValue;
      curve.ClosestPoint(pList[n], ref n2);
      double n3 = curve.PointAt(n2).DistanceTo(pList[n]);
      if(maxValue>n3)
      {
        maxValue = n3;
        source.Add(n);
      }
    }
    nList3.Add(nList[source.Last()]);
  }
  DA.SetDataList(0, cList2);
  DA.SetDataList(1, nList3);
}

Started rewriting it, but I realised I do not understand what this code is supposed to do.
Can you explain it in English? All this list juggling is throwing me off the scent. (Also the naming of variables doesn’t help)

My partially rewritten method:

protected override void SolveInstance(IGH_DataAccess DA)
{
  List<Curve> curves = new List<Curve>();
  List<Point3d> points = new List<Point3d>();
  List<int> indices = new List<int>();

  DA.GetDataList(0, curves);
  DA.GetDataList(1, points);
  DA.GetDataList(2, indices); // Is this not used anywhere?

  List<int> nList2 = new List<int>();
  List<Curve> closedCurves = new List<Curve>();
  List<int> nList3 = new List<int>();

  for (int i = 0; i < curves.Count; i++)
    if (!curves[i].IsPlanar())
      this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Curve input(s) are not planar.");
      // If you're adding an error I'd expect the component to terminate.
      // Continuing anyway means it should probably be a warning.

  foreach (Curve curve in curves)
    if (curve.IsClosed)
    {
      for (int i = 0; i < points.Count; i++)
        if (curve.Contains(points[i]) == PointContainment.Inside) 
          nList2.Add(i);

      if (nList2.Count != 0) // I'm getting confused here, what's being checked?
        closedCurves.Add(curve);
    }

  foreach (Curve curve in closedCurves)
  {
    for (int i = 0; i < points.Count; i++)
      // Why are we doing this expensive check twice?
      if (curve.Contains(points[i]) == PointContainment.Inside)
        nList3.Add(i);

    List<int> source = new List<int>();
    foreach (int n in nList3)
    {
      double n2 = 0.0;
      double maxValue = double.MaxValue;
      curve.ClosestPoint(points[n], ref n2);
      double n3 = curve.PointAt(n2).DistanceTo(points[n]);
      if(maxValue>n3)
      {
        maxValue = n3;
        source.Add(n);
      }
    }
    nList3.Add(nList[source.Last()]); // This is dangerous, does 'source' contain _any_ items? Are you sure?
  }

  DA.SetDataList(0, closedCurves);
  DA.SetDataList(1, nList3);
}

The ultimate goal is to takes polylines and text from a rhino file and extrude the polylines according to the value of the text inside.

Polylines are simply fed into grasshopper as multiple curves.
Text is read from the rhino file using the human plugin, from which the location(point) and value of the text can be extracted.

the component (TBP) this C# code is trying to do is take polylines that are planar and closed, find the point that’s inside each polyline region and reorder the lists so that the polyline and text pair is in the right order to be fed into an extrusion.

There are some redundancies/weirdness in the C# code for reasons I don’t understand, as the original code was copied from some random online blog/tutorial, maybe it’s a mistake?

sidenote: the TBP in the screenshot have 3 outputs because I was messing around doing test, it’s only suppose to have 2, ignore the third one

copied from some random online blog/tutorial

A link to that would probably be useful

I’ve being trying to find that website again, but this was copied a long time ago (When i first wanted to learn C# for gh).
Unfortunately I can’t find it now, that’s why I’m directing my questions here; otherwise I would’ve directly asked the original author for an explanation.

and what is to happen if say multiple points are in one polyline or there are points that are not in a polyline?

I don’t think the code accounts for this, as the rhino file should’ve been cleaned to avoid these 2 situations.
but theoretically speaking, the solution would be:
1.multiple points are in one polyline - take the point closer to the center OR just randomly choose one(?)
2.points that are not in a polyline - these points would simply be ignored OR find the closest polyline and add to that (tho this’ll probably create problem 1)

The issue seems simple to just do with grasshoppers containment components. I think you will just need contains + a cull pattern. Can you upload the Rhino + GH file. Unless you really need it to be in c#?

True, containment+cull could probably do similar things.
But I want to practice C#/Component making, and it’d be nice if I can just make it into a component, so I don’t have to re-think how to connect everything everytime.

extrudeByText.3dm (25.0 KB)
extrudeByText.gh (12.2 KB)

This is all you need. If you want to practice C# I suggest starting from scratch and imitating this king of logic.


extrudeByText-MP.gh (12.1 KB)

Of course in C# the idea would be more like for each curve test the points until you find the one inside. If inside add the corresponding number to that point to double list, once a point is confirmed inside move on to the next curve.

1 Like

Here is a quick C# one, don’t have VS available at the moment so it is made in the script editor. Also, it doesn’t do checks for things like list matching the point and number inputs, multiple points in a curve, or if no points are in a curve - as it really depends on what you want those behaviors to be like (maybe none throws an error all together or maybe it inserts a null into the output list or something else) . Anyway quick start for you to look at and add to.


extrudeByText-MPcs.gh (12.3 KB)

1 Like

Slight update to improve speed by adding break once the contained point is found so we don’t keep searching. Also used RemoveAt to remove the point and its corresponding number from their lists once they are found in a curve so we don’t search for them again.

extrudeByText-MPcs-Update.gh (10.1 KB)

2 Likes