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);
}
}
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
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.
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.
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.
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.
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.