import Rhino
import rhinoscriptsyntax as rs

def AveragePoint3d(aPts):

    X = Y = Z = 0
    L = len(aPts)
    
    for i in range(len(aPts)):
        X += aPts[i].X
        Y += aPts[i].Y
        Z += aPts[i].Z
        
    return Rhino.Geometry.Point3d(X/L, Y/L, Z/L)

def MoveOnSurfaceNormal():
    ids = rs.GetObjects("Select objects to move.", preselect=True)
    if not ids: return
    
    srfId = rs.GetObject("Select base surface.", 8)
    if not srfId: return
    
    #    if srfId in ids:
    #        ids.pop(ids.index(srfId))
    
    srf = rs.coercesurface(srfId)
    id = ids[0]
    
    bb = rs.BoundingBox(id)

    p1 = AveragePoint3d([bb[0],bb[6]])
    
    rc, parU, parV = srf.ClosestPoint(p1)
    if not rc:return
    
    vecNorm = srf.NormalAt(parU,parV)
    dist = Rhino.RhinoMath.UnsetValue
    down=False
    while True:
        gp = Rhino.Input.Custom.GetPoint()
      
        gp.Constrain(p1, p1+vecNorm)
        gp.SetBasePoint(p1, True)
        gp.AcceptNumber(True,False)
        gp.ConstrainDistanceFromBasePoint(dist)
        get_rc = gp.Get()
        
        if gp.CommandResult()!=Rhino.Commands.Result.Success:
            return gp.CommandResult()

        if get_rc==Rhino.Input.GetResult.Number:
            dist = gp.Number()
            continue
            
        if get_rc==Rhino.Input.GetResult.Point:
            point = gp.Point()
            break
     
    if vecNorm.IsParallelTo(point-p1) == -1: down = True
     
    scale = point.DistanceTo(p1)
    rs.EnableRedraw(False)
    
    for id in ids:
        bb = rs.BoundingBox(id)
        p1 = AveragePoint3d([bb[0],bb[6]])
        rc, parU, parV = srf.ClosestPoint(p1)
        if not rc:continue
        vecNorm  = srf.NormalAt(parU, parV)
        if down: vecNorm.Reverse()
        vecNorm = vecNorm*scale
        point  = p1 + vecNorm
        #point = srf.PointAt(parU,parV)
        rs.MoveObject(id, point-p1)
        
    rs.EnableRedraw(True)
    
if __name__ == "__main__": MoveOnSurfaceNormal()