/ nc_files / holecircle.py
holecircle.py
  1  import sys, os
  2  BASE = os.environ['EMC2_HOME']
  3  sys.path.insert(0, os.path.join(BASE, "lib", "python"))
  4  
  5  import math
  6  
  7  def _(s): return s
  8  
  9  def ui():
 10      import Tkinter
 11      import pickle
 12      import nf
 13      import rs274.options
 14      import os
 15  
 16      app = Tkinter.Tk()
 17      rs274.options.install(app)
 18      app.tk.call("source", os.path.join(BASE, "share", "axis", "tcl", "combobox.tcl"))
 19  
 20      app.wm_title(_("Circular Holes"))
 21      app.wm_iconname(_("Circular Holes"))
 22  
 23      prev = Tkinter.Canvas(app, width=200, height=200)
 24      f = Tkinter.Frame(app)
 25      b = Tkinter.Frame(app)
 26      prev.grid(row=0, column=0, sticky="nw")
 27      f.grid(row=0, column=1, sticky="nw")
 28      b.grid(row=1, column=0, columnspan=2, sticky="ne")
 29  
 30      validate_float    = "expr {[regexp {^-?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}"
 31      validate_int      = "expr {[regexp {^-?([0-9]+|)$} %P]}"
 32      validate_posfloat = "expr {[regexp {^?([0-9]+(\.[0-9]*)?|\.[0-9]+|)$} %P]}"
 33      validate_posint   = "expr {[regexp {^([0-9]+|)$} %P]}"
 34      def posfloatentry(f, v):
 35          var = Tkinter.DoubleVar(f)
 36          var.set(v)
 37          w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_posfloat, validate="all", width=10)
 38          return w, var
 39  
 40      def floatentry(f, v):
 41          var = Tkinter.DoubleVar(f)
 42          var.set(v)
 43          w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_float, validate="all", width=10)
 44          return w, var
 45  
 46      def posintentry(f, v):
 47          var = Tkinter.IntVar(f)
 48          var.set(v)
 49          w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_posint, validate="all", width=10)
 50          return w, var
 51  
 52  
 53      def intentry(f, v):
 54          var = Tkinter.IntVar(f)
 55          var.set(v)
 56          w = Tkinter.Entry(f, textvariable=var, validatecommand=validate_int, validate="all", width=10)
 57          return w, var
 58  
 59      def checkbutton(k, v):
 60          var = Tkinter.BooleanVar(f)
 61          var.set(v)
 62          g = Tkinter.Frame(f)
 63          w = Tkinter.Checkbutton(g, variable=var, text="Yes")
 64          w.pack(side="left")
 65          return g, var 
 66  
 67      def intscale(k, v, min=1, max = 100):
 68          var = Tkinter.IntVar(f)
 69          var.set(v)
 70          g = Tkinter.Frame(f, borderwidth=0)
 71          w = Tkinter.Scale(g, orient="h", variable=var, from_=min, to=max, showvalue=False)
 72          l = Tkinter.Label(g, textvariable=var, width=3)
 73          l.pack(side="left")
 74          w.pack(side="left", fill="x", expand=1)
 75          return g, var
 76  
 77      def optionmenu(k, v, *options):
 78          options = list(options)
 79          def trace(*args):
 80              try:
 81                  var.set(options.index(svar.get()))
 82              except ValueError:
 83                  pass
 84  
 85          try:
 86              opt = options[v]
 87          except (TypeError, IndexError):
 88              v = 0
 89              opt = options[0]
 90  
 91          var = Tkinter.IntVar(f)    
 92          var.set(v)
 93          svar = Tkinter.StringVar(f)
 94          svar.set(options[v])
 95          svar.trace("w", trace)
 96          wp = f._w.rstrip(".") + ".c" + svar._name
 97          f.tk.call("combobox::combobox", wp, "-editable", 0, "-width",
 98                  max(len(opt) for opt in options)+3, "-textvariable", svar._name,
 99                  "-background", "white")
100          f.tk.call(wp, "list", "insert", "end", *options)
101          w = nf.makewidget(f, Tkinter.Widget, wp)
102          return w, var
103  
104      rc = os.path.expanduser("~/.holecirclerc")
105      constructors = [
106          ("units", lambda f, v: optionmenu(f, v, _("G20 (in)"), _("G21 (mm)"))),
107          ("cx", floatentry),
108          ("cy", floatentry),
109  	("th0", floatentry),
110  	("inc", floatentry),
111  	("rad", posfloatentry),
112  	("count", posintentry),
113  	("feedrate", posfloatentry),
114  	("depth", floatentry),
115  	("dwell", posfloatentry),
116  	("retract", floatentry),
117      ]
118  
119      defaults = dict(
120  	cx = 0,
121  	cy = 0,
122  	th0 = 0,
123  	inc = 15,
124  	count = 6,
125  	feedrate = 8,
126  	depth=-.1,
127  	retract=.1,
128  	units=0,
129  	dwell=0,
130  	rad=1
131      )
132  
133      texts = dict(
134          units=_("Units"),
135  	rad=_("Radius"),
136  	cx=_("Center X"),
137  	cy=_("Center Y"),
138  	th0=_("Start Angle"),
139  	inc=_("Increment Angle"),
140  	count=_("Hole Count"),
141  	feedrate=_("Feed Rate"),
142  	depth=_("Hole Depth"),
143  	retract=_("Retract Height"),
144  	dwell=("Dwell (0=no dwell)"),
145      )
146  
147      try:
148          defaults.update(pickle.load(open(rc, "rb")))
149      except (IOError, pickle.PickleError): pass
150  
151      vars = {}
152      widgets = {}
153      for j, (k, con) in enumerate(constructors):
154          v = defaults[k]
155          text = texts.get(k, k.replace("_", " "))
156          lab = Tkinter.Label(f, text=text)
157          widgets[k], vars[k] = con(f, v)
158          lab.grid(row=j, column=0, sticky="w")
159          widgets[k].grid(row=j, column=1, sticky="ew")
160  
161      def update_preview(*args):
162  	prev.delete("all")
163  	try:
164  	    count = vars['count'].get()
165  	    th0 = vars['th0'].get()
166  	    inc = vars['inc'].get()
167  	except ValueError: return
168  	for i in range(count):
169  	    th = (th0 + i * inc) * math.pi / 180
170  	    x = 100 + 75 * math.cos(th)
171  	    y = 100 - 75 * math.sin(th)
172  	    prev.create_oval((x-4,y-4,x+4,y+4), fill='black')
173  
174      def update_ok(*args):
175  	result = True
176  	for i in vars.values():
177  	    try:
178  		i.get()
179  	    except ValueError:
180  		result = False
181  		break
182  	if result: bb.configure(state="normal")
183  	else: bb.configure(state="disabled")
184  	# This line creates an error when you load holecircle twice
185  	# from inside linuxcnc eg. gladevcp filechooser or AXIS GUI
186  	#print >>sys.stderr, "update_ok", args
187      
188      vars['count'].trace('w', update_preview)
189      vars['inc'].trace('w', update_preview)
190      vars['th0'].trace('w', update_preview)
191  
192      for i in vars.values(): i.trace('w', update_ok)
193  
194      update_preview()
195  
196      status = Tkinter.IntVar()
197      bb = Tkinter.Button(b, text=_("OK"), command=lambda:status.set(1), width=8, default="active")
198      bb.pack(side="left", padx=4, pady=4)
199      bc = Tkinter.Button(b, text=_("Cancel"), command=lambda:status.set(-1), width=8, default="normal")
200      bc.pack(side="left", padx=4, pady=4)
201      
202      app.bind("<Escape>", lambda evt: bc.invoke())
203      app.bind("<Return>", lambda evt: bb.invoke())
204      app.wm_protocol("WM_DELETE_WINDOW", lambda: bc.invoke())
205      app.wm_resizable(0,0)
206  
207      app.wait_visibility()
208      app.tk.call("after", "idle", ("after", "idle", "focus [tk_focusNext .]"))
209      #app.tk_focusNext().focus()
210      app.wait_variable(status)
211  
212      if status.get() == -1:
213  	raise SystemExit(1)
214  
215      for k, v in vars.items():
216          defaults[k] = v.get()
217  
218      app.destroy()
219  
220      pickle.dump(defaults, open(rc, "wb"))
221  
222      return defaults
223  
224  unitcodes = ['G20', 'G21']
225  u = ui()
226  print unitcodes[u['units']]
227  print "F%.1f" % u['feedrate']
228  
229  count = u['count']
230  th0 = u['th0']
231  inc = u['inc']
232  depth = u['depth']
233  retract = u['retract']
234  cx = u['cx']
235  cy = u['cy']
236  rad = u['rad']
237  
238  if u['dwell']: cycle = "G82 P% 8.4f" % u['dwell']
239  else: cycle = "G81"
240  for i in range(count):
241      th = (th0 + i * inc) * math.pi / 180
242      x = cx + rad * math.cos(th)
243      y = cy + rad * math.sin(th)
244      print "%s X% 8.4f Y% 8.4f Z% 8.4f R% 8.4f" % (cycle, x, y, depth, retract)
245  print "M2"