📄 image-to-gcode.py
字号:
conv.g.safety() x, y, z = p1 pixelsize = conv.pixelsize cx = cmp(p1[0], p2[0]) cy = cmp(p1[1], p2[1]) radius = self.max_radius if cx != 0: h1 = conv.h1 for di in r: dx = di * pixelsize i = i0 + cx * di if i < 0 or i >= h1: break z1 = conv.get_z(i, j0) dz = (z1 - z0) if dz <= 0: continue if dz > dx: conv.g.write("(case 1)") radius = dx break rad1 = (dx * dx / dz + dz) / 2 if rad1 < radius: radius = rad1 if dx > radius: break z1 = min(p1[2] + radius, conv.safetyheight) x1 = p1[0] + cx * circ(radius, z1 - p1[2]) conv.g.rapid(x1, p1[1]) conv.g.cut(z=z1) conv.g.flush(); conv.g.lastgcode = None if cx > 0: conv.g.write("G3 X%f Z%f R%f" % (p1[0], p1[2], radius)) else: conv.g.write("G2 X%f Z%f R%f" % (p1[0], p1[2], radius)) conv.g.lastx = p1[0] conv.g.lasty = p1[1] conv.g.lastz = p1[2] else: w1 = conv.w1 for dj in r: dy = dj * pixelsize j = j0 - cy * dj if j < 0 or j >= w1: break z1 = conv.get_z(i0, j) dz = (z1 - z0) if dz <= 0: continue if dz > dy: radius = dy break rad1 = (dy * dy / dz + dz) / 2 if rad1 < radius: radius = rad1 if dy > radius: break z1 = min(p1[2] + radius, conv.safetyheight) y1 = p1[1] + cy * circ(radius, z1 - p1[2]) conv.g.rapid(p1[0], y1) conv.g.cut(z=z1) conv.g.flush(); conv.g.lastgcode = None if cy > 0: conv.g.write("G2 Y%f Z%f R%f" % (p1[1], p1[2], radius)) else: conv.g.write("G3 Y%f Z%f R%f" % (p1[1], p1[2], radius)) conv.g.lastx = p1[0] conv.g.lasty = p1[1] conv.g.lastz = p1[2] if self.feed: conv.g.set_feed(conv.feed)def ui(im, nim, im_name): import Tkinter import ImageTk import pickle import nf app = Tkinter.Tk() rs274.options.install(app) app.tk.call("source", os.path.join(BASE, "share", "axis", "tcl", "combobox.tcl")) name = os.path.basename(im_name) app.wm_title(_("%s: Image to gcode") % name) app.wm_iconname(_("Image to gcode")) w, h = im.size r1 = w / 300. r2 = h / 300. nw = int(w / max(r1, r2)) nh = int(h / max(r1, r2)) ui_image = im.resize((nw,nh), Image.ANTIALIAS) ui_image = ImageTk.PhotoImage(ui_image, master = app) i = Tkinter.Label(app, image=ui_image, compound="top", text=_("Image size: %d x %d pixels\n" "Minimum pixel value: %d\nMaximum pixel value: %d") % (im.size + (nim.min(), nim.max())), justify="left") f = Tkinter.Frame(app) g = Tkinter.Frame(app) b = Tkinter.Frame(app) i.grid(row=0, column=0, sticky="nw") f.grid(row=0, column=1, sticky="nw") b.grid(row=1, column=0, columnspan=2, sticky="ne") def filter_nonint(event): if event.keysym in ("Return", "Tab", "ISO_Left_Tab", "BackSpace"): return if event.char == "": return if event.char in "0123456789": return return "break" def filter_nonfloat(event): if event.keysym in ("Return", "Tab", "ISO_Left_Tab", "BackSpace"): return if event.char == "": return if event.char in "0123456789.": return return "break" validate_float = "expr {![regexp {^-?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}" validate_int = "expr {![regexp {^-?([0-9]+|)$} %P]}" validate_posfloat = "expr {![regexp {^?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}" validate_posint = "expr {![regexp {^([0-9]+|)$} %P]}" def floatentry(f, v): var = Tkinter.DoubleVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_float, validate="key", width=10) return w, var def intentry(f, v): var = Tkinter.IntVar(f) var.set(v) w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_int, validate="key", width=10) return w, var def checkbutton(k, v): var = Tkinter.BooleanVar(f) var.set(v) g = Tkinter.Frame(f) w = Tkinter.Checkbutton(g, variable=var, text=_("Yes")) w.pack(side="left") return g, var def intscale(k, v, min=1, max = 100): var = Tkinter.IntVar(f) var.set(v) g = Tkinter.Frame(f, borderwidth=0) w = Tkinter.Scale(g, orient="h", variable=var, from_=min, to=max, showvalue=False) l = Tkinter.Label(g, textvariable=var, width=3) l.pack(side="left") w.pack(side="left", fill="x", expand=1) return g, var def _optionmenu(k, v, *options): options = list(options) def trace(*args): try: var.set(options.index(svar.get())) except ValueError: pass try: opt = options[v] except (TypeError, IndexError): v = 0 opt = options[0] var = Tkinter.IntVar(f) var.set(v) svar = Tkinter.StringVar(f) svar.set(options[v]) svar.trace("w", trace) wp = f._w.rstrip(".") + ".c" + svar._name f.tk.call("combobox::combobox", wp, "-editable", 0, "-width", max(len(opt) for opt in options)+3, "-textvariable", svar._name, "-background", "white") f.tk.call(wp, "list", "insert", "end", *options) w = nf.makewidget(f, Tkinter.Widget, wp) return w, var def optionmenu(*options): return lambda f, v: _optionmenu(f, v, *options) rc = os.path.expanduser("~/.image2gcoderc") constructors = [ ("units", optionmenu(_("G20 (in)"), _("G21 (mm)"))), ("invert", checkbutton), ("normalize", checkbutton), ("expand", optionmenu(_("None"), _("White"), _("Black"))), ("tolerance", floatentry), ("pixel_size", floatentry), ("feed_rate", floatentry), ("plunge_feed_rate", floatentry), ("spindle_speed", floatentry), ("pattern", optionmenu(_("Rows"), _("Columns"), _("Rows then Columns"), _("Columns then Rows"))), ("converter", optionmenu(_("Positive"), _("Negative"), _("Alternating"), _("Up Milling"), _("Down Milling"))), ("depth", floatentry), ("pixelstep", intscale), ("tool_diameter", floatentry), ("safety_height", floatentry), ("tool_type", optionmenu(_("Ball End"), _("Flat End"), _("45 Degree"), _("60 Degree"))), ("bounded", optionmenu(_("None"), _("Secondary"), _("Full"))), ("contact_angle", floatentry), ("roughing_offset", floatentry), ("roughing_depth", floatentry), ] defaults = dict( invert = False, normalize = False, expand = 0, pixel_size = .006, depth = 0.25, pixelstep = 8, tool_diameter = 1/16., safety_height = .012, tool_type = 0, tolerance = .001, feed_rate = 12, plunge_feed_rate = 12, units = 0, pattern = 0, converter = 0, bounded = 0, contact_angle = 45, spindle_speed = 1000, roughing_offset = .1, roughing_depth = .25, ) texts = dict( invert=_("Invert Image"), normalize=_("Normalize Image"), expand=_("Extend Image Border"), pixel_size=_("Pixel Size (Units)"), depth=_("Depth (units)"), tolerance=_("Tolerance (units)"), pixelstep=_("Stepover (pixels)"), tool_diameter=_("Tool Diameter (units)"), tool_type=_("Tool Type"), feed_rate=_("Feed Rate (units per minute)"), plunge_feed_rate=_("Plunge Feed Rate (units per minute)"), units=_("Units"), safety_height=_("Safety Height (units)"), pattern=_("Scan Pattern"), converter=_("Scan Direction"), bounded=_("Lace Bounding"), contact_angle=_("Contact Angle (degrees)"), spindle_speed=_("Spindle Speed (RPM)"), roughing_offset=_("Roughing offset (units, 0=no roughing)"), roughing_depth=_("Roughing depth per pass (units)"), ) try: defaults.update(pickle.load(open(rc, "rb"))) except (IOError, pickle.PickleError): pass vars = {} widgets = {} for j, (k, con) in enumerate(constructors): v = defaults[k] text = texts.get(k, k.replace("_", " ")) lab = Tkinter.Label(f, text=text) widgets[k], vars[k] = con(f, v) lab.grid(row=j, column=0, sticky="w") widgets[k].grid(row=j, column=1, sticky="ew") def trace_pattern(*args): if vars['pattern'].get() > 1: widgets['bounded'].configure(state="normal") trace_bounded() else: widgets['bounded'].configure(state="disabled") widgets['contact_angle'].configure(state="disabled") def trace_bounded(*args): if vars['bounded'].get() != 0: widgets['contact_angle'].configure(state="normal") else: widgets['contact_angle'].configure(state="disabled") def trace_offset(*args): if vars['roughing_offset'].get() > 0: widgets['roughing_depth'].configure(state='normal') else: widgets['roughing_depth'].configure(state='disabled') vars['pattern'].trace('w', trace_pattern) vars['bounded'].trace('w', trace_bounded) vars['roughing_offset'].trace('w', trace_offset) trace_pattern() trace_bounded() trace_offset() status = Tkinter.IntVar() bb = Tkinter.Button(b, text=_("OK"), command=lambda:status.set(1), width=8, default="active") bb.pack(side="left", padx=4, pady=4) bb = Tkinter.Button(b, text=_("Cancel"), command=lambda:status.set(-1), width=8, default="normal") bb.pack(side="left", padx=4, pady=4) app.bind("<Escape>", lambda evt: status.set(-1)) app.bind("<Return>", lambda evt: status.set(1)) app.wm_protocol("WM_DELETE_WINDOW", lambda: status.set(-1)) app.wm_resizable(0,0) app.wait_visibility() app.tk.call("after", "idle", ("after", "idle", "focus [tk_focusNext .]")) #app.tk_focusNext().focus() app.wait_variable(status) for k, v in vars.items(): defaults[k] = v.get() app.destroy() if status.get() == -1: raise SystemExit(_("image-to-gcode: User pressed cancel")) pickle.dump(defaults, open(rc, "wb")) return defaultsdef main(): if len(sys.argv) > 1: im_name = sys.argv[1] else: import tkFileDialog, Tkinter im_name = tkFileDialog.askopenfilename(defaultextension=".png", filetypes = ( (_("Depth images"), ".gif .png .jpg"), (_("All files"), "*"))) if not im_name: raise SystemExit Tkinter._default_root.destroy() Tkinter._default_root = None im = Image.open(im_name) size = im.size im = im.convert("L") #grayscale w, h = im.size nim = numarray.fromstring(im.tostring(), 'UInt8', (h, w)).astype('Float32') options = ui(im, nim, im_name) step = options['pixelstep'] depth = options['depth'] if options['normalize']: a = nim.min() b = nim.max() if a != b: nim = (nim - a) / (b-a) else: nim = nim / 255.0 maker = tool_makers[options['tool_type']] tool_diameter = options['tool_diameter'] pixel_size = options['pixel_size'] tool = make_tool_shape(maker, tool_diameter, pixel_size) if options['expand']: if options['expand'] == 1: pixel = 1 else: pixel = 0 tw, th = tool.shape w1 = w + 2*tw h1 = h + 2*th nim1 = numarray.zeros((w1, h1), 'Float32') + pixel nim1[tw:tw+w, th:th+w] = nim nim = nim1 w, h = w1, h1 nim = nim * depth if options['invert']: nim = -nim else: nim = nim - depth rows = options['pattern'] != 1 columns = options['pattern'] != 0 columns_first = options['pattern'] == 3 spindle_speed = options['spindle_speed'] if rows: convert_rows = convert_makers[options['converter']]() else: convert_rows = None if columns: convert_cols = convert_makers[options['converter']]() else: convert_cols = None if options['bounded'] and rows and columns: slope = tan(options['contact_angle'] * pi / 180) if columns_first: convert_rows = Reduce_Scan_Lace(convert_rows, slope, step+1) else: convert_cols = Reduce_Scan_Lace(convert_cols, slope, step+1) if options['bounded'] > 1: if columns_first: convert_cols = Reduce_Scan_Lace(convert_cols, slope, step+1) else: convert_rows = Reduce_Scan_Lace(convert_rows, slope, step+1) units = unitcodes[options['units']] convert(nim, units, tool, pixel_size, step, options['safety_height'], options['tolerance'], options['feed_rate'], convert_rows, convert_cols, columns_first, ArcEntryCut(options['plunge_feed_rate'], .125), spindle_speed, options['roughing_offset'], options['roughing_depth'], options['feed_rate'])if __name__ == '__main__': main()# vim:sw=4:sts=4:et:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -