Is it possible (I hope so!) to reference sub-curves in Grasshopper?
Currently I leverage various scripts to reference Sub-Objects (such as nested objects in groups) and those work great but I am specifically looking to be able to reference a sub-curve into GH in the following workflow.
-Have a polyline or draw a polyline in Rhino
-Use Ctrl+Shift Click / Sub-Selection to select a single sub curve or multiple sub curves
-Get these specific sub-curves as referenced curves in Grasshopper
-Do things to said specific sub-curves in Grasshopper
I know that I can reference the overall polyline, and then explode it in GH or use edge indices to select the curves I am after but I am trying to enable a workflow where the user can click the specific sub-curves they want without needing to know what index they are at and without the need to reference the entirety of the remaining curve.
An example of how I may use this script is by selecting the sub-curve of a “wall polyline” that resides in a “kitchen” and then having parametric cabinets generated along that specific sub-curve without exploding the overall polyline in Rhino that defines the “wall”.
The grasshopper part is beyond me (I don’t know how you reference componentindices in the calls).
Within the model geometry, I haven’t been able to find ID’s on anything but RhinoObjects (I don’t consider something like a Material definition to be a direct part of the geometry).
ID is declared at the RhinoObject level, and doesn’t seem to be defined on GeometryBase or the subclasses which might be the spans of a PolyCurve.
Further, the RhinoDoc’s object table returns a RhinoObject for the Find method, not something like GeometryBase or Object- and some subobjects aren’t even classes but structs.
Certain things like SubDFace do have an ID, but that’s simply an Int32 and seems to act like an index (I speculate that they may not want to make certain guarantees about how these behave given the way some recent objects only support ForEach iteration not random access and thus called it an ID rather than an index).
Ultimately, I couldn’t figure out a simpler way to track object and subobject selection than to create my own class. I even create ‘faux’ objects in certain cases, such as polylines in which Rhino seems to maximize efficiency by not storing segments as separate objects.
Note that the top level RhinoObject may or may not be selected: the event fires whether the selection is the top level object or just one of the subobjects (like a segment of a curve after the shft-ctrl-click select).
To retrieve the actual subobject, you need to look at the type of RhinoObject and ask for the piece which makes sense given the object type and the type of the ComponentIndex (the appropriate segment of a Curve, for example).
This works as expected for the conventional geometry objects except Extrusion and PolyLineCurve.
The former is a long story. The latter:
So far as I can tell, it doesn’t have objects for each segment. The way I deal with that is to create LineCurves as I need them from the points in the PolyLineCurve’s PolyLine representation.
I have been able to retrieve sub objects just fine but as you pointed out this doesn’t work with curves because the segments are not considered objects even though you can cut/paste/duplicate them “out” of the parent curve and then they will become their own object. Hmm…
The component index makes sense and I have not specifically looked at how that works under a selection event.
When you say you create line curves, you mean you draw new curves from point to point to create a faux poly line?
My question with this method is, is this any different from exploding the poly line?
What I need is for the poly line to remain intact but as you mentioned return the individual lines/segments or segment indices that are selected.
Curious what your faux pline looks like from a code perspective. Is it it’s own geometry type or class? Or is it still considered a poly line?
I really appreciate your help and response!
Just saw the constructor you linked and I think “Poly curve segment array” is what I need to dig into
That line segment, which is a span of a PolyCurve, actually exists in Rhino’s object model. I retrieve information about it from the parent Curve and draw it (Rhino’s select in yellow, my select in red).
These segments don’t actually exist in Rhino’s model, which is why I display them in parentheses. I keep track of the PolyLineCurve and extract data as required. In this case ‘as required’ means to pull tabular information about each segment and to do the red highlight.
What it looks like in code:
If you’ve got a PolyLineCurve (like the one pictured), from that you can get a .ToPolyLine(). This gives you the points of the polyline. From there, I just look at the points or create temporary LineCurves as needed.
These are all temporary constructions outside of the persistent Rhino Document but they could easily be used to make updates to the Doc. I don’t make any changes to the Rhino model: this plugin is a review/audit tool.
Interesting, thank you for sharing this! The visual examples are helpful as well!
This is essentially what I am after, instead highlighting the red selected line segment, I want to reference that into GH and I’ll then use properties of that segment such as tangency and length, start and end points, to create other geometry based on that as an underlying “guide curve”
My idea being, if that original polyline gets moved, control points shifted, etc. the sub-curve (your red curve) will of course get manipulated along with the parent curve and will then update the grasshopper definition logic downstream.
Like lets say we scale the overall parent curve by .75, the red segment will now be shorter slightly, meaning the grasshopper definition would now create a “shorter” element at that location.
Elements I am creating are mostly architectural focused such as walls, cabinets, doors, windows, etc.
So if the pentagon example was a building footprint boundary and I wanted to add a glazed curtain wall, I would select the red line you show, and the curtain wall would be created at that segment only, but if I selected the segment to the left or right as well, the curtain wall would be created “around the corner” to include both sub-curves.
Am I making sense?
I could sketch it out if you think it’d be helpful
Yes, but tracking the actual segment across changes to the parent RhinoObject will require some bookkeeping since there’s no direct changed event and ID for components the way we have for RhinoObjects with the replacement and related events.
A scaling should be easy. Dragging a segment or deleting one might get more complicated.
Sure. Your use case is interesting and parallels some problems which I either have solutions for or need to explore myself.
And here’s an example diagramming a persistent index tracking based on the original first implementation of the parent curve. I think we would have to store the original indices and the curve that would get “kept” would be whichever was extended such as the 3rd example we keep 4 and 7 because those were extended by the user.
Above in left example (example 1) the logic is “hosted” to index 6 sub-curve, when we modify the parent curve in example 2, the logic “extends”, and the way we modified the parent curve in example 3, the logic goes null as the “host” sub-curve was removed. I would probably add a warning here before executing the script letting the user know the host is about to be removed… but that’s down the road.
I’m not sure if you’ve worked with these before and the phrasing there is a little ambiguous (an event for the change, or a specific event for that change): There are events, but they don’t specify details of the change.
In this case, you’d get a replacing object event, a deleting object event and then an adding object event.
The replacing event is to let you know that the next pair of delete and add are an edit to the same object.
That’s at the RhinoObject level.
The extra bookkeeping we were discussing would be to figure out exactly what changed.
Undo makes everything even more fun
On my wish list is a “User is about to do x” event with a chance to modify or cancel it and a “User has finished doing x” event.
I’ll need to think about your diagrams and explanations a bit… not ignoring them.
Okay yes, the way you described events makes sense.
Thank you, I really appreciate your insights!
When I have some free time again I’m going to explore the polyline arrays and see how far I can get with that alone.
I barely got to play with the WIP constraints that were being worked on and subsequently were removed from R8 but I recall there perhaps being a constraint that would work on sub-curves that would have been great to have exposed in GH. Oh well! Maybe next version!