C# - Offset curves consistently

Hello all,

I’m trying to make a C# component that will offset planar curves consistently regardless of curve directions.
The process would be:

  1. Close all curves, if not closed.
  2. Get center points of curves.
  3. Get normal vectors of surfaces from curves
  4. Offset curves

I asked a similar question before here, but the curve offset method seems changed in Rhino 6.

I’m embarrassed that I didn’t make much progress on coding since then, but can you help me write this component in C#?

//Create surfaces to get normal vectors from surfaces using ClosestPoint method.
Brep[] crvBreps = Brep.CreatePlanarBreps(crvs, 0.1);

//Get centroid of curves 
AreaMassProperties AMP = AreaMassProperties.Compute(crvs);
Point3d cen = AMP.Centroid;

//Get Vector3d normal using Brep.ClosestPoint method 
Vector3d[] normalCrvs;
Point3d[] cPoints;
int ci;
double s;
double t;
crvBreps.ClosestPoint(cen, out cPoints, out ci, out s, out t, 100.00, out normalCrvs);

I skipped the step 1 for now and am trying to get normal vectors from surfaces using Brep.CloestPoint method. Can someone let me know I can make this work?
Once I get normal vectors, I’m thinking to use Curve.Offset Method (Point3d, Vector3d, Double, Double, CurveOffsetCornerStyle).
Thank you.


I broke down my questions hoping to get an answer…
Can someone let me know how I can get closest points and normal vectors in this example?

Closest points.gh (5.4 KB)

Not directly to do with your script, but my approach for offsetting closed curves via scripting has been to offset both sides - by running the offset twice with both plus and minus offset distance values. Then figure out which one is inside and which is outside - which is fairly easy once the offsets exist - and just ignore/discard the one you don’t want. I find this more reliable than trying to find an “inside” or “outside” offset point.



Thanks a lot for your answer, and it looks like a better idea.
In order for me to learn C#, do you know how this code doesn’t work?
I assumed “crvBreps” would have a method of ClosestPoint, because they contain Breps. The error message seems to conflict my assumption.

Unfortunately, I don’t know anything about C#, I am using RhinoCommon via Python…

That being said, a single brep has a ClosestPoint() method, but not a collection/list of breps… So you would need to iterate through the breps in crvBreps individually to get their closest points if I understood your code correctly… Brep.CreatePlanarBreps() returns a list/array of breps - as it is possible to create multiple breps with the method.

I’m not sure what you intend to do here? You call everything as curves (plural) but have the component set to item(singular), also you use the singular method for CreatePlanarBreps. So just for naming you should name things like crv not crvs (for clarity).

The reason nothing is working is because out is a variable not a list. Also CreatePlanarBreps gives you an array, so you will need to run a loop. You would run that closest point method in a loop and keep adding to the list, for each Brep (even if it is one in the array).

Lastly, in the ClosestPoint method you are using you forgot the Maximum distance (In this case I used document tolerance). Also ci (Component Index) is not an int, it is a Component Index.

Take a closer look at the method: http://developer.rhino3d.com/5/api/RhinoCommon/html/M_Rhino_Geometry_Brep_ClosestPoint_1.htm

Closest points_MP.gh (5.8 KB)

Overall though, @Helvetosaur approach would be better.

Thank you Michael and Helvetosaur.
Obviously, I missed several important things in my attempt, but it’s great that I’m learning a lot in my trial. Thanks again for helping!

Can I bother you one more time? I wanted to understand how I could deal with “list access” instead of “item access” for the input, so I modified your code. Not surprisingly, it’s not working again. It makes Breps, but it doesn’t make closest points and normal vectors. Would you let me know what’s wrong in this?

Closest points_curve list.gh (8.8 KB)

OK, I could figure it out by myself, and I’m posting the working script just in case someone is trying to learn like me in the future.

Closest points_curve list_working.gh (13.1 KB)

You don’t need that first curve list since you are inputting a curve list already. Just use crvs directly instead of listCrvs.

I see. GH C# component takes care of making a list for curves with “list access” automatically, so I don’t have to create a list for them. It’s working per your suggestion. Thanks Michael!! Again, I’m posting the result for others later…

The other potential issue I see here. You should get the area of the breps, not the curves. There are cases where that CreatePlanarBreps method can make less breps than input curves, like if you have a closed curve inside of a closed curve.


Very good point!! Thanks for the tip.

I’m sorry to keep bothering you, but I have one more question. I don’t know how I can offset curves within a for loop. I guess I have to offset curve one by one, but offset method makes a list, not curve. Can you let me know how I can offset curves based on the offset method in this situation? I would try a method suggested by Helvetosaur, but I want to take this opportunity to learn C# more.
imageoffset curves.gh (9.6 KB)

I guess I have to offset curve one by one, but offset method makes a list, not curve.

It doesnt make a list. It makes an array. Array is like DataType[ ] arrayName. List is like List< DataType > listName. They are treated different. You can do a google search about the differences but for a loop the difference is that when counting an array should be .Length;, where a list is .Count;

Offset makes an array yes because there are cases where offsetting one curve can result in more than one curve, when the offset break.

I don’t know how I can offset curves within a for loop

What do you need the loop for? I need to know what you are trying to do with the offset. Do you have something like distances as a list and you want to offset each curve for each distance?

Thank you for clarifying the difference between array and list. Can you let me know how I can offset curve one by one within a for loop and add it to a list? It’s clear to me that I can make a list of Point3d when Centroid method makes a Point3d, not an array. Curve.Offset method makes an array, not a curve, so I don’t know how I can offset curves one by one and add it to a curve list. I’m trying to understand how to use methods making arrays in Rhino Common.

I didn’t see your answer to the second part of my questions…so should I offset all curves one time without offsetting each curve within a for loop?

Curve.Offset method makes an array, not a curve, so I don’t know how I can offset curves one by one and add it to a curve list.

The same way you did your crvBreps (that was also an array). offset makes an array of curves

you could make your curve list outside of your for loop that is counting the crvBreps.
List< Curve > offsetCrvs = new List< Curve >;

Then do your offset where you have it in the for loop already
Curve[ ] offsetCrv = crvs[i].Offset(cPoint, normal, offsetDim, 0.1,0); <<I know it can result in an array but I would name it as offsetCrv singular and make your list as offsetCrvs plural.

After that use .AddRange(); to add to your offsetCrvs list rather than .Add(); AddRange lets you add an entire List or Array to a List. This will add all the result of the offset to your offsetCrvs list, in case the result is more than one curve in the array.

1 Like

Thanks so much Michael. I don’t know how you can find time to kindly answer to all of my questions. I’m also wondering how you learned all of what you have now. It’d be great, if you could share a good learning path or your learning experience in the development of C# components in Grasshopper.

Mostly by asking questions and getting help from others far better than I (believe it or not I only started C# about 9 months ago - but I put A LOT of hours into it)

Also, firstly I watched C# intro videos without GH, I highly suggest that. Turn off GH for a week and watch this (8+ hour) video - and try not to fall asleep. https://www.youtube.com/watch?v=sQurwqK0JNE

Then take another week and watch these which are specific to GH: http://developer.rhino3d.com/videos/

This way you can at least comprehend whats going on (even if you cannot do it so comfortably yourself yet)

and of course keep asking questions.