@dale Hi,

I often need to do a repetitive work. Can Rhinoceros code or python code works for this?

Thanks for your help!


Here is some python code which might be helpful. Just pre- or post-select the controlpoints, then click the start and endpoint of your line and the controlpoints are pulled to it…

import rhinoscriptsyntax as rs

def PullGripsToLine():
    msg = "Select control points to pull"
    grips = rs.GetObjectGrips(message=msg, preselect=True, select=True)
    if not grips: return
    line = rs.GetLine(mode=1, point=None)
    if not line: return
    for grip in grips:
        obj_id, index, point = grip
        closest = rs.LineClosestPoint(line, point)
        if closest:
            rs.ObjectGripLocation(obj_id, index, closest)



@clement Hi clement,

Thank you for your help.

I am sorry, My error. Because sometimes the distance of the control points are small or outside of the region, I have use the closest pulled results error. I want to make the number of control points selected pulled to divide points of the line by the start and the end point. Does it possible?

(Willem Derks) #4

Hi Robin,

I took a stab at this while waiting for a long script to finish:

import rhinoscriptsyntax as rs
import Rhino

def SetGripsInLine():
    msg = "Select control points to pull"
    grips = rs.GetObjectGrips(message=msg, preselect=True, select=True)
    if not grips: return
    if len(grips) < 3: 
        print 'Error: Select at least 3 grips'
    if not all( [grips[0][0] == test_grip[0] for test_grip in grips] ):
        print 'Error: Controlpoints from different surfaces'
    #sort by index
    grips.sort(key = lambda g : g[1])
    line_curve = Rhino.Geometry.LineCurve(grips[0][2], grips[-1][2])
    if not line_curve: return
    parms = line_curve.DivideByCount(len(grips)-1, True)
    pts = [line_curve.PointAt(parm) for parm in parms]
    for pt,grip in zip(pts,grips):
        rs.ObjectGripLocation(grip[0], grip[1], pt)


It works on your specific case ditribute controlpoints on a line between the most outer* 2:
Outer in relation to their U or V relationschip not 3D position.

After a Select controlpoints to be distributed inline
It gets the ‘first’ and ‘last’ controlpoint and creates a line between them
The inbetween grips are distributed over the line between them.



@Willem, that is very nice. I was wondering if this could not be done with a scripted version of MoveUVN, by applying smoothing in either U or V direction but MoveUVN does not have a equivalent in RhinoCommon and the settings are unavailable in the commandline, so it cannot be used within a macro or Rhino.Command…

I guess if larger rows of grips have to be set to a line in equal distances, it would be most convenient if the user only has to select the start and end grips and the script automatically finds the ones between them.



@Willem , It is very good. It works for me.
Thank you for your help.
But if I could to select the start and end grips and the script automatically finds the divide count between them,It would be nice. Can you do this?

(Willem Derks) #7

Hi Robin,

I’m rather short in time at the moment so for now I’m not able to add that functionality.



Below is a script which does this. Slightly painful though… (2.7 KB)



@clement , Very nice. Thank you!
It works well.


Hi Willem,
I also need sorting a window selection, but unsorted.Sort(...) only returns a empty result (movePoints).

unsorted seems to be fully valid before attempting to sort it (and it runs three rounds in the Sort function). How can this be?

Any hints about why it fails?

// Rolf

(Willem Derks) #11

Hi Rolf.

Note how in my example the list was sorted in place the list itself was changed and no result was expected.
You assumed the .sort method to return a sorted list yet what happened is that the list “unsorted” got sorted.
You could use however
movePoints = sorted (unsorted, key = lambda g : g[1])

Some more on sorting in python



OK, I found the error, sort of.

list.sort doesn’t return the sorted list, it only returns None, so the correct use should be (in my case)

unsorted.sort(key = lambda g : g[1])
sorted = unsorted                     # now sorted

// Rolf


Ops, didn’t see that you had posted. Sorry.

But now I have another problem. When I select a row, the following code disregards the selected points (in the list) and picks a row in the other direction instead.

I simply can’t understand why it does so.

// Rolf


Sorry for the delay, below is a script which does this. I’ve added a commandline option so the changed grips are selected after the command (default is yes). (3.3 KB)


Align and distribute spacing points on surface