Quantcast
Channel: Rhino Developer - McNeel Forum
Viewing all articles
Browse latest Browse all 8547

GetObject selection behavior

$
0
0

I finally decided to try some Rhino (6/mac) scripting, with a simple tool to export paths as gcode. It mostly works well, but I have had a lot of difficulty understanding how to get the selection behavior I want.

It would be great if anyone could suggest a resource that explains this topic in general. The RhinoCommon documentation lists a ton of methods and properties related to selection, but it is not at all clear how they interact, and I managed to crash Rhino quite a lot by trying to experiment.

My specific, current problem is that I need the user to pick objects one by one in a specific order, and I want to select the objects as they are picked – partly to provide feedback, and partly because it shouldn’t be possible to pick the same object twice. The OneByOnePostSelect property gives me part of this behavior, but the objects are not visibly selected when I pick them, and if I call rhinoscriptsyntax.SelectObject() on the picked ObjectRef, nothing happens.

I’ve attached my script below – hopefully it is understandable, but it will probably be obvious to Rhino experts that I haven’t used these APIs (or python) before!

import rhinoscriptsyntax as rs
import Rhino

gcodeFile = None
feedrate = 1500.0
spindle = 10000.0
retractHeight = 6.0
tool = 0
jobOrigin = 0
firstPath = True
gcodeState = dict(
    x = 0,
    y = 0,
    z = 0,
    f = 0
    )



# prompt for an output location and setup origin, and then repeatedly
# prompt for toolpaths and machine settings to write to the file in order
def event_loop():
    global gcodeFile
    global feedrate
    global spindle
    global retractHeight
    global tool
    global jobOrigin
    global firstPath
    filename = rs.SaveFileName(
        title = "Export G Code",
        filter = "G Code File (*.nc)|*.nc|All files (*.*)|*.*||",
        filename = "Untitled",
        extension = "nc"
        )
    if not filename: return
    gcodeFile = open(filename, "w")
    jobOrigin = rs.GetPoint("Select toolpath origin")
    prompt = Rhino.Input.Custom.GetObject()
    feedrateOption = Rhino.Input.Custom.OptionDouble(feedrate, 1.0, 5000)
    prompt.AddOptionDouble("Feed", feedrateOption, "New feed rate (mm/min)")
    spindleOption = Rhino.Input.Custom.OptionDouble(spindle, 0, 10000.0)
    prompt.AddOptionDouble("Speed", spindleOption, "New spindle speed (rpm)")
    retractOption = Rhino.Input.Custom.OptionDouble(retractHeight, 0, 100.0)
    prompt.AddOptionDouble("RetractHeight", retractOption, "Safe retract height (mm)")
    toolOption = Rhino.Input.Custom.OptionInteger(tool, 0, 1000)
    prompt.AddOptionInteger("Tool", toolOption, "Tool number")
    prompt.AcceptNothing(True)
    prompt.EnablePreSelect(False, True)
    prompt.OneByOnePostSelect = True
    prompt.SetCommandPrompt("Select first toolpath curve")
    prompt.GeometryFilter = Rhino.DocObjects.ObjectType.Curve
    while True:
        rc = prompt.Get()
        if prompt.CommandResult() != Rhino.Commands.Result.Success:
            return prompt.CommandResult()
        if rc == Rhino.Input.GetResult.Object:
            curveRef = prompt.Object(0)
            if not curveRef: return Rhino.Commands.Result.Failure
            append_toolpath(curveRef)
            if firstPath:
                firstPath = False
                prompt.SetCommandPrompt("Select next toolpath curve")
            continue
        elif rc == Rhino.Input.GetResult.Option:
            opt = prompt.OptionIndex()
            if feedrateOption.CurrentValue != feedrate:
                feedrate = feedrateOption.CurrentValue
            if spindleOption.CurrentValue != spindle:
                spindle = spindleOption.CurrentValue
                if not firstPath: gcodeFile.write("M3 S{}\n".format(gcs(spindle)))
            if retractHeight != retractOption.CurrentValue:
                retractHeight = retractOption.CurrentValue
            if tool != toolOption.CurrentValue:
                tool = toolOption.CurrentValue
                gcodeFile.write("M6 T{:d}\n".format(tool))
            continue
        elif rc == Rhino.Input.GetResult.Nothing:
            close_file()
            print ("Exported GCode to "+filename)
            break
        elif rc == Rhino.Input.GetResult.Cancel:
            #TODO use a temp file so it's actually possible to cancel export...
            close_file()
            print ("GCode Export cancelled")
        break

    return Rhino.Commands.Result.Success




#format numbers for CNC without wasting bytes
def gcs(num): return "{:.99g}".format(round(num,3))

#convert Rhino units to mm
def rtomm(n): return n * rs.UnitScale(2)

#convert mm to Rhino units
def mmtor(n): return n / rs.UnitScale(2)




# write out G code for initial setup and tool positioning
# (once we know where the first toolpath begins)
def write_prefix(startX=0, startY=0):
    global gcodeState
    gcodeFile.write("\n".join((
        "G21 (distances in mm)",
        "G90 (absolute coords)",
        "G17 (use XY plane for arcs)",
        "G0 Z" + gcs(retractHeight) + " (rapid to safe height)",
        "G0 X" + gcs(startX) + " Y" + gcs(startY) + " (rapid to start XY)",
        "M3 S" + gcs(spindle) + " (run spindle clockwise)",
        "",
        )))
    gcodeState['x'] = startX
    gcodeState['y'] = startY
    gcodeState['z'] = retractHeight
    return



# write out G code for a toolpath, prepending commands to
# move the tool safely (you hope) from its previous position
def append_toolpath(curveRef):
    global gcodeState
    curve = curveRef.Curve()
    if rs.IsPolyline(curve):
        polyline = curve
    else:
        polyline = rs.ConvertCurveToPolyline(curve, 5.0, mmtor(0.01), False)
    points = rs.PolylineVertices(polyline)
    point = rs.PointSubtract(points[0], jobOrigin)
    if firstPath:
        write_prefix(point.X, point.Y)
    else:
        gcodeFile.write("G1 Z{}\nG0 X{} Y{}\n".format(
            gcs(retractHeight),
            gcs(point.X),
            gcs(point.Y)
            ))
    gcodeFile.write("\n(toolpath {}mm)\n".format(gcs(rs.CurveLength(curve))))
    for i in range(len(points)):
        point = rs.PointSubtract(points[i], jobOrigin)
        write_G1(point)
    if not rs.IsPolyline(curve): rs.DeleteObject(polyline)
    rs.SelectObject(curveRef)
    return


# write out a G1 command (single linear move) in a compact form,
# setting the X,Y,Z and F parameters only where they have changed
def write_G1(dest):
    epsilon = mmtor(0.001)
    if rs.Distance(dest, (gcodeState['x'],gcodeState['y'],gcodeState['z'])) < epsilon:
        return
    cmd = "G1 "
    sep = ""
    if abs(dest.X - gcodeState['x']) > epsilon:
        cmd += "X" + gcs(rtomm(dest.X))
        gcodeState['x'] = dest.X
        sep = " "
    if abs(dest.Y - gcodeState['y']) > epsilon:
        cmd += sep + "Y" + gcs(rtomm(dest.Y))
        gcodeState['y'] = dest.Y
        sep = " "
    if abs(dest.Z - gcodeState['z']) > epsilon:
        cmd += sep + "Z" + gcs(rtomm(dest.Z))
        gcodeState['z'] = dest.Z
        sep = " "
    if feedrate != gcodeState['f']:
        cmd += sep + "F" + gcs(feedrate)
        gcodeState['f'] = feedrate
    gcodeFile.write(cmd + "\n")
    return



# move tool to a safe height, write final commands and close file
def close_file():
    gcodeFile.write ("G1 Z" + gcs(retractHeight) + "\n\n")
    gcodeFile.write ("M5 (stop spindle)\nM30 (program end)\n")
    gcodeFile.close()
    return



if(__name__ == "__main__"):
    event_loop()

gcExport.py (6.2 KB)

2 posts - 2 participants

Read full topic


Viewing all articles
Browse latest Browse all 8547

Trending Articles