If I have a Rhino.Geometry.Polyline object which is closed and I want to shift the start point a certain number of indices along the curve, is there a simple method?
Not finding anything like a “Change seam” or “Shift list” method in the Polyline class, I improvised this - which is more than a bit of a kludge:
#orig_polyline is already a polyline and I want to shift the start point, say 2
#new blank polyline
plx=Rhino.Geometry.Polyline()
new_start index=2
#add from index to end of list-1 (but not end point!)
for i in range(new_start index,orig_polyline.Count-1):
plx.Add(orig_polyline[i])
#add the beginning of the original polyline list to the end of the new list
for j in range(curr_index):
plx.Add(orig_polyline[j])
#add the first point as the last point so it is closed
plx.Add(plx[0])
But that seems pretty crazy and messy. There must be something better that I missed.
I’ve needed this as well. And although still kludgey, I like to use collections.deque for shifting lists. Here’s a function that offsets the polyline vertex order to start a given input point:
import Rhino as rc
import collections
def setPolylineStart(polyline,point):
""" Offset polyline vertex order to start at point """
vts = polyline.ToArray()
vts = collections.deque(vts)
vts.rotate(len(vts)-polyline.ClosestIndex(point))
pl = rc.Geometry.Polyline(vts)
return pl
Interesting, but this doesn’t appear to work with closed polylines, as the start and end points are repeated. By ‘rotating’ the list you end up with a duplicate point somewhere in the middle (the old start/end) and the thus created polyline is invalid and cannot be added to the document. That’s why I excluded the last (end) point in my scriptlet above and added a new one - corresponding to the new start point - at the end.
Ah yes sorry, I missed the closed requirement (at home with covid ). Adding to the kludge, one could check and remove/add the last vertex before/after the rotation. Something like this should work I think:
import Rhino as rc
import collections
def setPolylineStart(polyline,point):
""" Offset polyline vertex order to start at point """
vts = collections.deque(polyline)
if polyline.IsClosed:
del vts[-1]
vts.rotate(len(vts)-polyline.ClosestIndex(point))
if polyline.IsClosed:
vts.append(vts[0])
pl = rc.Geometry.Polyline(vts)
return pl
Also interesting - if I give it a number, deque.rotate seems to rotate “backwards” from the end of the list… So if I want it to shift x indices “forward” from the polyline start, I need to feed it -x
However the advantage of using deque.rotate is that you can ‘rotate’ more than the length of the list, whereas my list slicing method will error out if I feed it a number to shift greater than the list length.
I use rs.CurveSeam() for this exact purpose. Digging its function definition, it seems to call the Curve.ChangeClosedCurveSeam method
Best regards,
Tim
def CurveSeam(curve_id, parameter):
"""Adjusts the seam, or start/end, point of a closed curve.
Parameters:
curve_id (guid): identifier of the curve object
parameter (number): The parameter of the new start/end point.
Note, if successful, the resulting curve's
domain will start at `parameter`.
Returns:
bool: True or False indicating success or failure.
Example:
import rhinoscriptsyntax as rs
obj = rs.GetObject("Select closed curve", rs.filter.curve)
if rs.IsCurveClosed(obj):
domain = rs.CurveDomain(obj)
parameter = (domain[0] + domain[1])/2.0
rs.CurveSeam( obj, parameter )
See Also:
IsCurve
IsCurveClosed
"""
curve = rhutil.coercecurve(curve_id, -1, True)
if (not curve.IsClosed or not curve.Domain.IncludesParameter(parameter)):
return False
dupe = curve.Duplicate()
if dupe:
dupe.ChangeClosedCurveSeam(parameter)
curve_id = rhutil.coerceguid(curve_id)
dupe_obj = scriptcontext.doc.Objects.Replace(curve_id, dupe)
return dupe_obj is not None
return False
Yes, thanks, I looked at that, but the idea was to stay in polyline form (which is just a list of points basically) rather than converting to a polyline curve, figuring out which parameter is the next n points along the curve, changing the curve seam then converting the result back to a polyline.