# Set surface grips equally on a line (c) 2016, Clement Greiner - CG3D

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

def SetSurfaceGripsOnLine():
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("Select two control points from same surface")
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Grip
    go.GetMultiple(2, 2)

    if go.CommandResult() != Rhino.Commands.Result.Success: 
        return

    if go.Object(0).Object().OwnerId != go.Object(1).Object().OwnerId:
        print "Error: both control points must belong to same object"
        return

    # surface id
    id = go.Object(0).Object().OwnerId
    if not rs.IsSurface(id):
        print "Error: please select only surface control points"
        return

    # selected grips
    grip_a = go.Object(0).Object()
    grip_b = go.Object(1).Object()

    u_count = rs.SurfacePointCount(id)[0] 
    v_count = rs.SurfacePointCount(id)[1] 

    rc = None

    # check if both selected grips are part of a row in u direction
    for u in xrange(u_count):
        row = []
        for v in xrange(v_count): row.append(u + v + (v_count-1) * u)
        if grip_a.Index in row and grip_b.Index in row:
            rc = row
            break

    # check if both selected grips are part of a row in v direction
    if not rc:
        for v in xrange(v_count):
            row = []
            for u in xrange(u_count): row.append(u + v + (v_count-1) * u)
            if grip_a.Index in row and grip_b.Index in row:
                rc = row
                break

    # no row found case
    if not rc:
        print "Error: no row found containing both picked control points"
        return

    # slice the resulting full row to contain only required grip indices
    lower = min(grip_a.Index, grip_b.Index)
    upper = max(grip_a.Index, grip_b.Index)
    slice = rc[rc.index(lower) : rc.index(upper)+1]

    # no points between selected grips case
    if not len(slice) > 2: 
        print "Error: no points between both picked control points"
        return

    # locations of picked grips
    a = rs.ObjectGripLocation(id, lower)
    b = rs.ObjectGripLocation(id, upper)

    line_curve = Rhino.Geometry.LineCurve(a, b)
    if not line_curve: return

    parms = line_curve.DivideByCount(len(slice)-1, True)
    pts = [line_curve.PointAt(parm) for parm in parms]

    rhobj = rs.coercerhinoobject(id, True, True)
    grips = rhobj.GetGrips()

    for pt, index in zip(pts, slice): grips[index].CurrentLocation = pt

    # update surface
    scriptcontext.doc.Objects.GripUpdate(rhobj, True)
    scriptcontext.doc.Views.Redraw()

SetSurfaceGripsOnLine()