# Set curve or 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 curve or surface")
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Grip

    blnSelect = Rhino.Input.Custom.OptionToggle(True, "No", "Yes")
    go.AddOptionToggle("Select", blnSelect)

    while True:
        get_rc = go.GetMultiple(2, 2)
        if get_rc == Rhino.Input.GetResult.Option:
            continue
        break

    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

    # selected grips
    grip_a = go.Object(0).Object()
    grip_b = go.Object(1).Object()

    if rs.IsSurface(id):

        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]

    elif rs.IsCurve(id):

        lower = min(grip_a.Index, grip_b.Index)
        upper = max(grip_a.Index, grip_b.Index)
        slice = range(lower, upper+1)

    else:
        print "Error: Script works for curves or surfaces only"
        return

    # no points between selected grips case
    if not len(slice) > 2: 
        print "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
        if blnSelect.CurrentValue:
            grips[index].Select(True, True)

    # update surface
    scriptcontext.doc.Objects.GripUpdate(rhobj, True)
    scriptcontext.doc.Views.Redraw()

SetSurfaceGripsOnLine()