"""Realigns objects along chosen axis with specified space between objects.
Works on curves, breps, meshes. Script by Mitch Heynick 16.11.15"""
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def CommandLineOptions(prompt,msg,ini,limits):
    go = Rhino.Input.Custom.GetOption()
    go.SetCommandPrompt(prompt)
    
    dblOption0 = Rhino.Input.Custom.OptionDouble(ini[0],limits[0][0],limits[0][1])
    lstOption1 = go.AddOptionList(msg[1],limits[1],ini[1])
    go.AddOptionDouble(msg[0],dblOption0)
    
    go.AcceptNothing(True)
    index=ini[1]
    while True:
        get_rc = go.Get()
        if go.CommandResult()== Rhino.Commands.Result.Cancel:
            return
        elif go.CommandResult()== Rhino.Commands.Result.Nothing:
            break
        elif get_rc==Rhino.Input.GetResult.Option:
            if go.OptionIndex()==lstOption1:
                index = go.Option().CurrentListOptionIndex
            continue
        break
    return (dblOption0.CurrentValue,index)
    
def BBPoints(obj_id):
    geo=sc.doc.Objects.Find(obj_id).Geometry
    bb=geo.GetBoundingBox(True)
    return bb.Center,bb.GetCorners()

def SpaceOutObjsXYZ():
    #get input objects and options
    objs=rs.GetObjects("Select objects to space out",4+8+16+32,preselect=True)
    if not objs: return
    
    if "SpaceObjsSpace" in sc.sticky: prev_space = sc.sticky["SpaceObjsSpace"]
    else: prev_space = 1.0
    if "SpaceObjsAxis" in sc.sticky: prev_axis = sc.sticky["SpaceObjsAxis"]
    else: prev_axis = 0
    
    prompt="Alignment options:"
    msg=["ObjectSpacing","Axis"]
    limits=[[True,sc.doc.ModelAbsoluteTolerance],["X","Y","Z"]]
    ini=[prev_space,prev_axis]    
    opts=CommandLineOptions(prompt,msg,ini,limits)
    if not opts: return
    
    obj_list=[]
     #sort according to bb ctr and axis
    for obj in objs:
        ctr,bb=BBPoints(obj)
        if opts[1]==0:
            obj_list.append((ctr.X,bb,obj))
        elif opts[1]==1:
            obj_list.append((ctr.Y,bb,obj))
        else:
            obj_list.append((ctr.Z,bb,obj))
    obj_list.sort()
    
    #move objects into position
    rs.EnableRedraw(False)
    if opts[1]==0:
        spx=obj_list[0][1][1].X+opts[0]
        for i in range(1,len(obj_list)):
            bb=(obj_list[i][1])
            move_vec=rs.coerce3dvector([spx-bb[0].X,0,0])
            rs.MoveObject(obj_list[i][2],move_vec)
            spx=bb[1].X+move_vec.X+opts[0]
    elif opts[1]==1:
        spx=obj_list[0][1][2].Y+opts[0]
        for i in range(1,len(obj_list)):
            bb=(obj_list[i][1])
            move_vec=rs.coerce3dvector([0,spx-bb[1].Y,0,])
            rs.MoveObject(obj_list[i][2],move_vec)
            spx=bb[2].Y+move_vec.Y+opts[0]
    else:
        spx=obj_list[0][1][4].Z+opts[0]
        for i in range(1,len(obj_list)):
            bb=(obj_list[i][1])
            move_vec=rs.coerce3dvector([0,0,spx-bb[1].Z])
            rs.MoveObject(obj_list[i][2],move_vec)
            spx=bb[4].Z+move_vec.Z+opts[0]
            
    sc.sticky["SpaceObjsSpace"] = opts[0]
    sc.sticky["SpaceObjsAxis"] = opts[1]

SpaceOutObjsXYZ()