1#!/usr/local/bin/python3.8 2""" 3 K40 Whisperer 4 5 Copyright (C) <2017-2021> <Scorch> 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19""" 20version = '0.58' 21title_text = "K40 Whisperer V"+version 22 23import sys 24from math import * 25from egv import egv 26from nano_library import K40_CLASS 27from dxf import DXF_CLASS 28from svg_reader import SVG_READER 29from svg_reader import SVG_TEXT_EXCEPTION 30from svg_reader import SVG_PXPI_EXCEPTION 31from g_code_library import G_Code_Rip 32from interpolate import interpolate 33from ecoords import ECoord 34from convex_hull import hull2D 35from embedded_images import K40_Whisperer_Images 36 37import inkex 38import simplestyle 39import simpletransform 40import cubicsuperpath 41import cspsubdiv 42import traceback 43import struct 44 45DEBUG = False 46 47if DEBUG: 48 import inspect 49 50VERSION = sys.version_info[0] 51LOAD_MSG = "" 52 53if VERSION == 3: 54 from tkinter import * 55 from tkinter.filedialog import * 56 import tkinter.messagebox 57 MAXINT = sys.maxsize 58 59else: 60 from Tkinter import * 61 from tkFileDialog import * 62 import tkMessageBox 63 MAXINT = sys.maxint 64 65if VERSION < 3 and sys.version_info[1] < 6: 66 def next(item): 67 #return item.next() 68 return item.__next__() 69 70try: 71 import psyco 72 psyco.full() 73 LOAD_MSG = LOAD_MSG+"\nPsyco Loaded\n" 74except: 75 pass 76 77import math 78from time import time 79import os 80import re 81import binascii 82import getopt 83import operator 84import webbrowser 85from PIL import Image 86from PIL import ImageOps 87from PIL import ImageFilter 88 89try: 90 Image.warnings.simplefilter('ignore', Image.DecompressionBombWarning) 91except: 92 pass 93try: 94 from PIL import ImageTk 95 from PIL import _imaging 96except: 97 pass #Don't worry everything will still work 98 99PYCLIPPER=True 100try: 101 import pyclipper 102except: 103 print("Unable to load Pyclipper library (Offset trace outline will not work without it)") 104 PYCLIPPER = False 105 106try: 107 os.chdir(os.path.dirname(__file__)) 108except: 109 pass 110 111QUIET = False 112 113################################################################################ 114class Application(Frame): 115 def __init__(self, master): 116 self.trace_window = toplevel_dummy() 117 Frame.__init__(self, master) 118 self.w = 780 119 self.h = 490 120 frame = Frame(master, width= self.w, height=self.h) 121 self.master = master 122 self.x = -1 123 self.y = -1 124 self.createWidgets() 125 self.micro = False 126 127 128 def resetPath(self): 129 self.RengData = ECoord() 130 self.VengData = ECoord() 131 self.VcutData = ECoord() 132 self.GcodeData = ECoord() 133 self.SCALE = 1 134 self.Design_bounds = (0,0,0,0) 135 self.UI_image = None 136 #if self.HomeUR.get(): 137 self.move_head_window_temporary([0.0,0.0]) 138 #else: 139 # self.move_head_window_temporary([0.0,0.0]) 140 141 self.pos_offset=[0.0,0.0] 142 143 def createWidgets(self): 144 self.initComplete = 0 145 self.stop=[True] 146 147 self.k40 = None 148 self.run_time = 0 149 150 self.master.bind("<Configure>", self.Master_Configure) 151 self.master.bind('<Enter>', self.bindConfigure) 152 self.master.bind('<F1>', self.KEY_F1) 153 self.master.bind('<F2>', self.KEY_F2) 154 self.master.bind('<F3>', self.KEY_F3) 155 self.master.bind('<F4>', self.KEY_F4) 156 self.master.bind('<F5>', self.KEY_F5) 157 self.master.bind('<F6>', self.KEY_F6) 158 self.master.bind('<Home>', self.Home) 159 160 161 self.master.bind('<Control-Left>' , self.Move_Left) 162 self.master.bind('<Control-Right>' , self.Move_Right) 163 self.master.bind('<Control-Up>' , self.Move_Up) 164 self.master.bind('<Control-Down>' , self.Move_Down) 165 166 self.master.bind('<Control-Home>' , self.Move_UL) 167 self.master.bind('<Control-Prior>' , self.Move_UR) 168 self.master.bind('<Control-Next>' , self.Move_LR) 169 self.master.bind('<Control-End>' , self.Move_LL) 170 self.master.bind('<Control-Clear>' , self.Move_CC) 171 172 self.master.bind('<Control-Key-4>' , self.Move_Left) 173 self.master.bind('<Control-6>' , self.Move_Right) 174 self.master.bind('<Control-8>' , self.Move_Up) 175 self.master.bind('<Control-Key-2>' , self.Move_Down) 176 177 self.master.bind('<Control-7>' , self.Move_UL) 178 self.master.bind('<Control-9>' , self.Move_UR) 179 self.master.bind('<Control-Key-3>' , self.Move_LR) 180 self.master.bind('<Control-Key-1>' , self.Move_LL) 181 self.master.bind('<Control-Key-5>' , self.Move_CC) 182 183 ##### 184 185 self.master.bind('<Alt-Control-Left>' , self.Move_Arb_Left) 186 self.master.bind('<Alt-Control-Right>', self.Move_Arb_Right) 187 self.master.bind('<Alt-Control-Up>' , self.Move_Arb_Up) 188 self.master.bind('<Alt-Control-Down>' , self.Move_Arb_Down) 189 190 self.master.bind('<Alt-Control-Key-4>', self.Move_Arb_Left) 191 self.master.bind('<Alt-Control-6>' , self.Move_Arb_Right) 192 self.master.bind('<Alt-Control-8>' , self.Move_Arb_Up) 193 self.master.bind('<Alt-Control-Key-2>', self.Move_Arb_Down) 194 195 196 self.master.bind('<Alt-Left>' , self.Move_Arb_Left) 197 self.master.bind('<Alt-Right>', self.Move_Arb_Right) 198 self.master.bind('<Alt-Up>' , self.Move_Arb_Up) 199 self.master.bind('<Alt-Down>' , self.Move_Arb_Down) 200 201 self.master.bind('<Alt-Key-4>', self.Move_Arb_Left) 202 self.master.bind('<Alt-6>' , self.Move_Arb_Right) 203 self.master.bind('<Alt-8>' , self.Move_Arb_Up) 204 self.master.bind('<Alt-Key-2>', self.Move_Arb_Down) 205 206 ##### 207 self.master.bind('<Control-i>' , self.Initialize_Laser) 208 self.master.bind('<Control-o>' , self.menu_File_Open_Design) 209 self.master.bind('<Control-l>' , self.menu_Reload_Design) 210 self.master.bind('<Control-h>' , self.Home) 211 self.master.bind('<Control-u>' , self.Unlock) 212 self.master.bind('<Escape>' , self.Stop) 213 self.master.bind('<Control-t>' , self.TRACE_Settings_Window) 214 215 self.include_Reng = BooleanVar() 216 self.include_Rpth = BooleanVar() 217 self.include_Veng = BooleanVar() 218 self.include_Vcut = BooleanVar() 219 self.include_Gcde = BooleanVar() 220 self.include_Time = BooleanVar() 221 222 self.advanced = BooleanVar() 223 224 self.halftone = BooleanVar() 225 self.mirror = BooleanVar() 226 self.rotate = BooleanVar() 227 self.negate = BooleanVar() 228 self.inputCSYS = BooleanVar() 229 self.HomeUR = BooleanVar() 230 self.engraveUP = BooleanVar() 231 self.init_home = BooleanVar() 232 self.post_home = BooleanVar() 233 self.post_beep = BooleanVar() 234 self.post_disp = BooleanVar() 235 self.post_exec = BooleanVar() 236 237 self.pre_pr_crc = BooleanVar() 238 self.inside_first = BooleanVar() 239 self.rotary = BooleanVar() 240 241 242 self.ht_size = StringVar() 243 self.Reng_feed = StringVar() 244 self.Veng_feed = StringVar() 245 self.Vcut_feed = StringVar() 246 247 self.Reng_passes = StringVar() 248 self.Veng_passes = StringVar() 249 self.Vcut_passes = StringVar() 250 self.Gcde_passes = StringVar() 251 252 253 self.board_name = StringVar() 254 self.units = StringVar() 255 self.jog_step = StringVar() 256 self.rast_step = StringVar() 257 self.funits = StringVar() 258 259 260 self.bezier_M1 = StringVar() 261 self.bezier_M2 = StringVar() 262 self.bezier_weight = StringVar() 263 264## self.unsharp_flag = BooleanVar() 265## self.unsharp_r = StringVar() 266## self.unsharp_p = StringVar() 267## self.unsharp_t = StringVar() 268## self.unsharp_flag.set(False) 269## self.unsharp_r.set("40") 270## self.unsharp_p.set("350") 271## self.unsharp_t.set("3") 272 273 self.LaserXsize = StringVar() 274 self.LaserYsize = StringVar() 275 276 self.LaserXscale = StringVar() 277 self.LaserYscale = StringVar() 278 self.LaserRscale = StringVar() 279 280 self.rapid_feed = StringVar() 281 282 self.gotoX = StringVar() 283 self.gotoY = StringVar() 284 285 self.n_egv_passes = StringVar() 286 287 self.inkscape_path = StringVar() 288 self.batch_path = StringVar() 289 self.ink_timeout = StringVar() 290 291 self.t_timeout = StringVar() 292 self.n_timeouts = StringVar() 293 294 self.Reng_time = StringVar() 295 self.Veng_time = StringVar() 296 self.Vcut_time = StringVar() 297 self.Gcde_time = StringVar() 298 299 self.comb_engrave = BooleanVar() 300 self.comb_vector = BooleanVar() 301 self.zoom2image = BooleanVar() 302 303 self.trace_w_laser = BooleanVar() 304 self.trace_gap = StringVar() 305 self.trace_speed = StringVar() 306 307 ########################################################################### 308 # INITILIZE VARIABLES # 309 # if you want to change a default setting this is the place to do it # 310 ########################################################################### 311 self.include_Reng.set(1) 312 self.include_Rpth.set(0) 313 self.include_Veng.set(1) 314 self.include_Vcut.set(1) 315 self.include_Gcde.set(1) 316 self.include_Time.set(0) 317 self.advanced.set(0) 318 319 self.halftone.set(1) 320 self.mirror.set(0) 321 self.rotate.set(0) 322 self.negate.set(0) 323 self.inputCSYS.set(0) 324 self.HomeUR.set(0) 325 self.engraveUP.set(0) 326 self.init_home.set(1) 327 self.post_home.set(0) 328 self.post_beep.set(0) 329 self.post_disp.set(0) 330 self.post_exec.set(0) 331 332 self.pre_pr_crc.set(1) 333 self.inside_first.set(1) 334 self.rotary.set(0) 335 336 self.ht_size.set(500) 337 338 self.Reng_feed.set("100") 339 self.Veng_feed.set("20") 340 self.Vcut_feed.set("10") 341 self.Reng_passes.set("1") 342 self.Veng_passes.set("1") 343 self.Vcut_passes.set("1") 344 self.Gcde_passes.set("1") 345 346 347 self.jog_step.set("10.0") 348 self.rast_step.set("0.002") 349 350 self.bezier_weight.set("3.5") 351 self.bezier_M1.set("2.5") 352 self.bezier_M2.set("0.50") 353 354 self.bezier_weight_default = float(self.bezier_weight.get()) 355 self.bezier_M1_default = float(self.bezier_M1.get()) 356 self.bezier_M2_default = float(self.bezier_M2.get()) 357 358 359 self.board_name.set("LASER-M2") # Options are 360 # "LASER-M2", 361 # "LASER-M1", 362 # "LASER-M", 363 # "LASER-B2", 364 # "LASER-B1", 365 # "LASER-B", 366 # "LASER-A" 367 368 369 self.units.set("mm") # Options are "in" and "mm" 370 371 self.ink_timeout.set("3") 372 self.t_timeout.set("200") 373 self.n_timeouts.set("30") 374 375 self.HOME_DIR = os.path.expanduser("~") 376 377 if not os.path.isdir(self.HOME_DIR): 378 self.HOME_DIR = "" 379 380 self.DESIGN_FILE = (self.HOME_DIR+"/None") 381 self.EGV_FILE = None 382 383 self.aspect_ratio = 0 384 self.segID = [] 385 386 self.LaserXsize.set("325") 387 self.LaserYsize.set("220") 388 389 self.LaserXscale.set("1.000") 390 self.LaserYscale.set("1.000") 391 self.LaserRscale.set("1.000") 392 393 self.rapid_feed.set("0.0") 394 395 self.gotoX.set("0.0") 396 self.gotoY.set("0.0") 397 398 self.n_egv_passes.set("1") 399 400 self.comb_engrave.set(0) 401 self.comb_vector.set(0) 402 self.zoom2image.set(0) 403 404 405 self.trace_w_laser.set(0) 406 self.trace_gap.set(0) 407 self.trace_speed.set(50) 408 409 self.laserX = 0.0 410 self.laserY = 0.0 411 self.PlotScale = 1.0 412 self.GUI_Disabled = False 413 414 # PAN and ZOOM STUFF 415 self.panx = 0 416 self.panx = 0 417 self.lastx = 0 418 self.lasty = 0 419 self.move_start_x = 0 420 self.move_start_y = 0 421 422 423 self.RengData = ECoord() 424 self.VengData = ECoord() 425 self.VcutData = ECoord() 426 self.GcodeData = ECoord() 427 self.SCALE = 1 428 self.Design_bounds = (0,0,0,0) 429 self.UI_image = None 430 self.pos_offset=[0.0,0.0] 431 self.inkscape_warning = False 432 433 # Derived variables 434 if self.units.get() == 'in': 435 self.funits.set('in/min') 436 self.units_scale = 1.0 437 else: 438 self.units.set('mm') 439 self.funits.set('mm/s') 440 self.units_scale = 25.4 441 442 self.statusMessage = StringVar() 443 self.statusMessage.set("Welcome to K40 Whisperer") 444 445 446 self.Reng_time.set("0") 447 self.Veng_time.set("0") 448 self.Vcut_time.set("0") 449 self.Gcde_time.set("0") 450 451 self.min_vector_speed = 1.1 #in/min 452 self.min_raster_speed = 12 #in/min 453 454 ########################################################################## 455 ### END INITILIZING VARIABLES ### 456 ########################################################################## 457 458 # make a Status Bar 459 self.statusbar = Label(self.master, textvariable=self.statusMessage, \ 460 bd=1, relief=SUNKEN , height=1) 461 self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) 462 463 464 # Canvas 465 lbframe = Frame( self.master ) 466 self.PreviewCanvas_frame = lbframe 467 self.PreviewCanvas = Canvas(lbframe, width=self.w-(220+20), height=self.h-200, background="grey75") 468 self.PreviewCanvas.pack(side=LEFT, fill=BOTH, expand=1) 469 self.PreviewCanvas_frame.place(x=230, y=10) 470 471 self.PreviewCanvas.tag_bind('LaserTag',"<1>" , self.mousePanStart) 472 self.PreviewCanvas.tag_bind('LaserTag',"<B1-Motion>" , self.mousePan) 473 self.PreviewCanvas.tag_bind('LaserTag',"<ButtonRelease-1>", self.mousePanStop) 474 475 self.PreviewCanvas.tag_bind('LaserDot',"<3>" , self.right_mousePanStart) 476 self.PreviewCanvas.tag_bind('LaserDot',"<B3-Motion>" , self.right_mousePan) 477 self.PreviewCanvas.tag_bind('LaserDot',"<ButtonRelease-3>", self.right_mousePanStop) 478 479 # Left Column # 480 self.separator1 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 481 self.separator2 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 482 self.separator3 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 483 self.separator4 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 484 485 self.Label_Reng_feed_u = Label(self.master,textvariable=self.funits, anchor=W) 486 self.Entry_Reng_feed = Entry(self.master,width="15") 487 self.Entry_Reng_feed.configure(textvariable=self.Reng_feed,justify='center',fg="black") 488 self.Reng_feed.trace_variable("w", self.Entry_Reng_feed_Callback) 489 self.NormalColor = self.Entry_Reng_feed.cget('bg') 490 491 self.Label_Veng_feed_u = Label(self.master,textvariable=self.funits, anchor=W) 492 self.Entry_Veng_feed = Entry(self.master,width="15") 493 self.Entry_Veng_feed.configure(textvariable=self.Veng_feed,justify='center',fg="blue") 494 self.Veng_feed.trace_variable("w", self.Entry_Veng_feed_Callback) 495 self.NormalColor = self.Entry_Veng_feed.cget('bg') 496 497 self.Label_Vcut_feed_u = Label(self.master,textvariable=self.funits, anchor=W) 498 self.Entry_Vcut_feed = Entry(self.master,width="15") 499 self.Entry_Vcut_feed.configure(textvariable=self.Vcut_feed,justify='center',fg="red") 500 self.Vcut_feed.trace_variable("w", self.Entry_Vcut_feed_Callback) 501 self.NormalColor = self.Entry_Vcut_feed.cget('bg') 502 503 # Buttons 504 self.Reng_Button = Button(self.master,text="Raster Engrave", command=self.Raster_Eng) 505 self.Veng_Button = Button(self.master,text="Vector Engrave", command=self.Vector_Eng) 506 self.Vcut_Button = Button(self.master,text="Vector Cut" , command=self.Vector_Cut) 507 self.Grun_Button = Button(self.master,text="Run G-Code" , command=self.Gcode_Cut) 508 509 510 self.Reng_Veng_Button = Button(self.master,text="Raster and\nVector Engrave", command=self.Raster_Vector_Eng) 511 self.Veng_Vcut_Button = Button(self.master,text="Vector Engrave\nand Cut", command=self.Vector_Eng_Cut) 512 self.Reng_Veng_Vcut_Button = Button(self.master,text="Raster Engrave\nVector Engrave\nand\nVector Cut", command=self.Raster_Vector_Cut) 513 514 self.Label_Position_Control = Label(self.master,text="Position Controls:", anchor=W) 515 516 self.Initialize_Button = Button(self.master,text="Initialize Laser Cutter", command=self.Initialize_Laser) 517 518 self.Open_Button = Button(self.master,text="Open\nDesign File", command=self.menu_File_Open_Design) 519 self.Reload_Button = Button(self.master,text="Reload\nDesign File", command=self.menu_Reload_Design) 520 521 self.Home_Button = Button(self.master,text="Home", command=self.Home) 522 self.UnLock_Button = Button(self.master,text="Unlock Rail", command=self.Unlock) 523 self.Stop_Button = Button(self.master,text="Pause/Stop", command=self.Stop) 524 525 try: 526 self.left_image = PhotoImage(data=K40_Whisperer_Images.left_B64, format='gif') 527 self.right_image = PhotoImage(data=K40_Whisperer_Images.right_B64, format='gif') 528 self.up_image = PhotoImage(data=K40_Whisperer_Images.up_B64, format='gif') 529 self.down_image = PhotoImage(data=K40_Whisperer_Images.down_B64, format='gif') 530 531 self.Right_Button = Button(self.master,image=self.right_image, command=self.Move_Right) 532 self.Left_Button = Button(self.master,image=self.left_image, command=self.Move_Left) 533 self.Up_Button = Button(self.master,image=self.up_image, command=self.Move_Up) 534 self.Down_Button = Button(self.master,image=self.down_image, command=self.Move_Down) 535 536 self.UL_image = PhotoImage(data=K40_Whisperer_Images.UL_B64, format='gif') 537 self.UR_image = PhotoImage(data=K40_Whisperer_Images.UR_B64, format='gif') 538 self.LR_image = PhotoImage(data=K40_Whisperer_Images.LR_B64, format='gif') 539 self.LL_image = PhotoImage(data=K40_Whisperer_Images.LL_B64, format='gif') 540 self.CC_image = PhotoImage(data=K40_Whisperer_Images.CC_B64, format='gif') 541 542 self.UL_Button = Button(self.master,image=self.UL_image, command=self.Move_UL) 543 self.UR_Button = Button(self.master,image=self.UR_image, command=self.Move_UR) 544 self.LR_Button = Button(self.master,image=self.LR_image, command=self.Move_LR) 545 self.LL_Button = Button(self.master,image=self.LL_image, command=self.Move_LL) 546 self.CC_Button = Button(self.master,image=self.CC_image, command=self.Move_CC) 547 548 except: 549 self.Right_Button = Button(self.master,text=">", command=self.Move_Right) 550 self.Left_Button = Button(self.master,text="<", command=self.Move_Left) 551 self.Up_Button = Button(self.master,text="^", command=self.Move_Up) 552 self.Down_Button = Button(self.master,text="v", command=self.Move_Down) 553 554 self.UL_Button = Button(self.master,text=" ", command=self.Move_UL) 555 self.UR_Button = Button(self.master,text=" ", command=self.Move_UR) 556 self.LR_Button = Button(self.master,text=" ", command=self.Move_LR) 557 self.LL_Button = Button(self.master,text=" ", command=self.Move_LL) 558 self.CC_Button = Button(self.master,text=" ", command=self.Move_CC) 559 560 self.Label_Step = Label(self.master,text="Jog Step", anchor=CENTER ) 561 self.Label_Step_u = Label(self.master,textvariable=self.units, anchor=W) 562 self.Entry_Step = Entry(self.master,width="15") 563 self.Entry_Step.configure(textvariable=self.jog_step, justify='center') 564 self.jog_step.trace_variable("w", self.Entry_Step_Callback) 565 566 ########################################################################### 567 self.GoTo_Button = Button(self.master,text="Move To", command=self.GoTo) 568 569 self.Entry_GoToX = Entry(self.master,width="15",justify='center') 570 self.Entry_GoToX.configure(textvariable=self.gotoX) 571 self.gotoX.trace_variable("w", self.Entry_GoToX_Callback) 572 self.Entry_GoToY = Entry(self.master,width="15",justify='center') 573 self.Entry_GoToY.configure(textvariable=self.gotoY) 574 self.gotoY.trace_variable("w", self.Entry_GoToY_Callback) 575 576 self.Label_GoToX = Label(self.master,text="X", anchor=CENTER ) 577 self.Label_GoToY = Label(self.master,text="Y", anchor=CENTER ) 578 ########################################################################### 579 # End Left Column # 580 581 # Advanced Column # 582 self.separator_vert = Frame(self.master, height=2, bd=1, relief=SUNKEN) 583 self.Label_Advanced_column = Label(self.master,text="Advanced Settings",anchor=CENTER) 584 self.separator_adv = Frame(self.master, height=2, bd=1, relief=SUNKEN) 585 586 self.Label_Halftone_adv = Label(self.master,text="Halftone (Dither)") 587 self.Checkbutton_Halftone_adv = Checkbutton(self.master,text=" ", anchor=W) 588 self.Checkbutton_Halftone_adv.configure(variable=self.halftone) 589 self.halftone.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) #self.menu_View_Refresh_Callback 590 591 self.Label_Negate_adv = Label(self.master,text="Invert Raster Color") 592 self.Checkbutton_Negate_adv = Checkbutton(self.master,text=" ", anchor=W) 593 self.Checkbutton_Negate_adv.configure(variable=self.negate) 594 self.negate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) 595 596 self.separator_adv2 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 597 598 self.Label_Mirror_adv = Label(self.master,text="Mirror Design") 599 self.Checkbutton_Mirror_adv = Checkbutton(self.master,text=" ", anchor=W) 600 self.Checkbutton_Mirror_adv.configure(variable=self.mirror) 601 self.mirror.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) 602 603 self.Label_Rotate_adv = Label(self.master,text="Rotate Design") 604 self.Checkbutton_Rotate_adv = Checkbutton(self.master,text=" ", anchor=W) 605 self.Checkbutton_Rotate_adv.configure(variable=self.rotate) 606 self.rotate.trace_variable("w", self.View_Refresh_and_Reset_RasterPath) 607 608 self.separator_adv3 = Frame(self.master, height=2, bd=1, relief=SUNKEN) 609 610 self.Label_inputCSYS_adv = Label(self.master,text="Use Input CSYS") 611 self.Checkbutton_inputCSYS_adv = Checkbutton(self.master,text=" ", anchor=W) 612 self.Checkbutton_inputCSYS_adv.configure(variable=self.inputCSYS) 613 self.inputCSYS.trace_variable("w", self.menu_View_inputCSYS_Refresh_Callback) 614 615 self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First") 616 self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ", anchor=W) 617 self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first) 618 self.inside_first.trace_variable("w", self.menu_Inside_First_Callback) 619 620 self.Label_Inside_First_adv = Label(self.master,text="Cut Inside First") 621 self.Checkbutton_Inside_First_adv = Checkbutton(self.master,text=" ", anchor=W) 622 self.Checkbutton_Inside_First_adv.configure(variable=self.inside_first) 623 624 self.Label_Rotary_Enable_adv = Label(self.master,text="Use Rotary Settings") 625 self.Checkbutton_Rotary_Enable_adv = Checkbutton(self.master,text="") 626 self.Checkbutton_Rotary_Enable_adv.configure(variable=self.rotary) 627 self.rotary.trace_variable("w", self.Reset_RasterPath_and_Update_Time) 628 629 630 ##### 631 self.separator_comb = Frame(self.master, height=2, bd=1, relief=SUNKEN) 632 633 self.Label_Comb_Engrave_adv = Label(self.master,text="Group Engrave Tasks") 634 self.Checkbutton_Comb_Engrave_adv = Checkbutton(self.master,text=" ", anchor=W) 635 self.Checkbutton_Comb_Engrave_adv.configure(variable=self.comb_engrave) 636 self.comb_engrave.trace_variable("w", self.menu_View_Refresh_Callback) 637 638 self.Label_Comb_Vector_adv = Label(self.master,text="Group Vector Tasks") 639 self.Checkbutton_Comb_Vector_adv = Checkbutton(self.master,text=" ", anchor=W) 640 self.Checkbutton_Comb_Vector_adv.configure(variable=self.comb_vector) 641 self.comb_vector.trace_variable("w", self.menu_View_Refresh_Callback) 642 ##### 643 644 self.Label_Reng_passes = Label(self.master,text="Raster Eng. Passes") 645 self.Entry_Reng_passes = Entry(self.master,width="15") 646 self.Entry_Reng_passes.configure(textvariable=self.Reng_passes,justify='center',fg="black") 647 self.Reng_passes.trace_variable("w", self.Entry_Reng_passes_Callback) 648 self.NormalColor = self.Entry_Reng_passes.cget('bg') 649 650 self.Label_Veng_passes = Label(self.master,text="Vector Eng. Passes") 651 self.Entry_Veng_passes = Entry(self.master,width="15") 652 self.Entry_Veng_passes.configure(textvariable=self.Veng_passes,justify='center',fg="blue") 653 self.Veng_passes.trace_variable("w", self.Entry_Veng_passes_Callback) 654 self.NormalColor = self.Entry_Veng_passes.cget('bg') 655 656 self.Label_Vcut_passes = Label(self.master,text="Vector Cut Passes") 657 self.Entry_Vcut_passes = Entry(self.master,width="15") 658 self.Entry_Vcut_passes.configure(textvariable=self.Vcut_passes,justify='center',fg="red") 659 self.Vcut_passes.trace_variable("w", self.Entry_Vcut_passes_Callback) 660 self.NormalColor = self.Entry_Vcut_passes.cget('bg') 661 662 self.Label_Gcde_passes = Label(self.master,text="G-Code Passes") 663 self.Entry_Gcde_passes = Entry(self.master,width="15") 664 self.Entry_Gcde_passes.configure(textvariable=self.Gcde_passes,justify='center',fg="black") 665 self.Gcde_passes.trace_variable("w", self.Entry_Gcde_passes_Callback) 666 self.NormalColor = self.Entry_Gcde_passes.cget('bg') 667 668 669 self.Hide_Adv_Button = Button(self.master,text="Hide Advanced", command=self.Hide_Advanced) 670 671 # End Right Column # 672 self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time) 673 674 #GEN Setting Window Entry initializations 675 self.Entry_Sspeed = Entry() 676 self.Entry_BoxGap = Entry() 677 self.Entry_ContAngle = Entry() 678 679 # Make Menu Bar 680 self.menuBar = Menu(self.master, relief = "raised", bd=2) 681 682 683 684 685 top_File = Menu(self.menuBar, tearoff=0) 686 top_File.add("command", label = "Save Settings File", command = self.menu_File_Save) 687 top_File.add("command", label = "Read Settings File", command = self.menu_File_Open_Settings_File) 688 689 top_File.add_separator() 690 top_File.add("command", label = "Open Design (SVG/DXF/G-Code)" , command = self.menu_File_Open_Design) 691 top_File.add("command", label = "Reload Design" , command = self.menu_Reload_Design) 692 693 top_File.add_separator() 694 top_File.add("command", label = "Send EGV File to Laser" , command = self.menu_File_Open_EGV) 695 696 SaveEGVmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0) 697 top_File.add_cascade(label="Save EGV File", menu=SaveEGVmenu) 698 SaveEGVmenu.add("command", label = "Raster Engrave" , command = self.menu_File_Raster_Engrave) 699 SaveEGVmenu.add("command", label = "Vector Engrave" , command = self.menu_File_Vector_Engrave) 700 SaveEGVmenu.add("command", label = "Vector Cut" , command = self.menu_File_Vector_Cut) 701 SaveEGVmenu.add("command", label = "G-Code Operations" , command = self.menu_File_G_Code) 702 SaveEGVmenu.add_separator() 703 SaveEGVmenu.add("command", label = "Raster and Vector Engrave" , command = self.menu_File_Raster_Vector_Engrave) 704 SaveEGVmenu.add("command", label = "Vector Engrave and Cut" , command = self.menu_File_Vector_Engrave_Cut) 705 SaveEGVmenu.add("command", label = "Raster, Vector Engrave and Vector Cut" , command = self.menu_File_Raster_Vector_Cut) 706 707 708 top_File.add_separator() 709 top_File.add("command", label = "Exit" , command = self.menu_File_Quit) 710 711 self.menuBar.add("cascade", label="File", menu=top_File) 712 713 #top_Edit = Menu(self.menuBar, tearoff=0) 714 #self.menuBar.add("cascade", label="Edit", menu=top_Edit) 715 716 top_View = Menu(self.menuBar, tearoff=0) 717 top_View.add("command", label = "Refresh <F5>", command = self.menu_View_Refresh) 718 top_View.add_separator() 719 top_View.add_checkbutton(label = "Show Raster Image" , variable=self.include_Reng ,command= self.menu_View_Refresh) 720 if DEBUG: 721 top_View.add_checkbutton(label = "Show Raster Paths" ,variable=self.include_Rpth ,command= self.menu_View_Refresh) 722 723 top_View.add_checkbutton(label = "Show Vector Engrave", variable=self.include_Veng ,command= self.menu_View_Refresh) 724 top_View.add_checkbutton(label = "Show Vector Cut" , variable=self.include_Vcut ,command= self.menu_View_Refresh) 725 top_View.add_checkbutton(label = "Show G-Code Paths" , variable=self.include_Gcde ,command= self.menu_View_Refresh) 726 top_View.add_separator() 727 top_View.add_checkbutton(label = "Show Time Estimates", variable=self.include_Time ,command= self.menu_View_Refresh) 728 top_View.add_checkbutton(label = "Zoom to Design Size", variable=self.zoom2image ,command= self.menu_View_Refresh) 729 730 #top_View.add_separator() 731 #top_View.add("command", label = "computeAccurateReng",command= self.computeAccurateReng) 732 #top_View.add("command", label = "computeAccurateVeng",command= self.computeAccurateVeng) 733 #top_View.add("command", label = "computeAccurateVcut",command= self.computeAccurateVcut) 734 735 self.menuBar.add("cascade", label="View", menu=top_View) 736 737 top_Tools = Menu(self.menuBar, tearoff=0) 738 self.menuBar.add("cascade", label="Tools", menu=top_Tools) 739 USBmenu = Menu(self.master, relief = "raised", bd=2, tearoff=0) 740 741 top_Tools.add("command", label = "Calculate Raster Time", command = self.menu_Calc_Raster_Time) 742 top_Tools.add("command", label = "Trace Design Boundary <Ctrl-t>", command = self.TRACE_Settings_Window) 743 top_Tools.add_separator() 744 top_Tools.add("command", label = "Initialize Laser <Ctrl-i>", command = self.Initialize_Laser) 745 top_Tools.add_cascade(label="USB", menu=USBmenu) 746 USBmenu.add("command", label = "Reset USB", command = self.Reset) 747 USBmenu.add("command", label = "Release USB", command = self.Release_USB) 748 749 750 751 #top_USB = Menu(self.menuBar, tearoff=0) 752 #top_USB.add("command", label = "Reset USB", command = self.Reset) 753 #top_USB.add("command", label = "Release USB", command = self.Release_USB) 754 #top_USB.add("command", label = "Initialize Laser", command = self.Initialize_Laser) 755 #self.menuBar.add("cascade", label="USB", menu=top_USB) 756 757 758 top_Settings = Menu(self.menuBar, tearoff=0) 759 top_Settings.add("command", label = "General Settings <F2>", command = self.GEN_Settings_Window) 760 top_Settings.add("command", label = "Raster Settings <F3>", command = self.RASTER_Settings_Window) 761 top_Settings.add("command", label = "Rotary Settings <F4>", command = self.ROTARY_Settings_Window) 762 top_Settings.add_separator() 763 top_Settings.add_checkbutton(label = "Advanced Settings <F6>", variable=self.advanced ,command= self.menu_View_Refresh) 764 765 self.menuBar.add("cascade", label="Settings", menu=top_Settings) 766 767 top_Help = Menu(self.menuBar, tearoff=0) 768 top_Help.add("command", label = "About (e-mail)", command = self.menu_Help_About) 769 top_Help.add("command", label = "K40 Whisperer Web Page", command = self.menu_Help_Web) 770 top_Help.add("command", label = "Manual (Web Page)", command = self.menu_Help_Manual) 771 self.menuBar.add("cascade", label="Help", menu=top_Help) 772 773 self.master.config(menu=self.menuBar) 774 775 ########################################################################## 776 # Config File and command line options # 777 ########################################################################## 778 config_file = "k40_whisperer.txt" 779 home_config1 = self.HOME_DIR + "/" + config_file 780 if ( os.path.isfile(config_file) ): 781 self.Open_Settings_File(config_file) 782 elif ( os.path.isfile(home_config1) ): 783 self.Open_Settings_File(home_config1) 784 785 786# opts, args = None, None 787# try: 788# opts, args = getopt.getopt(sys.argv[1:], "ho:",["help", "other_option"]) 789# except: 790# debug_message('Unable interpret command line options') 791# sys.exit() 792# for option, value in opts: 793## if option in ('-h','--help'): 794## fmessage(' ') 795## fmessage('Usage: python .py [-g file]') 796## fmessage('-o : unknown other option (also --other_option)') 797## fmessage('-h : print this help (also --help)\n') 798## sys.exit() 799# if option in ('-m','--micro'): 800# self.micro = True 801 802 ########################################################################## 803 804################################################################################ 805 def entry_set(self, val2, calc_flag=0, new=0): 806 if calc_flag == 0 and new==0: 807 try: 808 self.statusbar.configure( bg = 'yellow' ) 809 val2.configure( bg = 'yellow' ) 810 self.statusMessage.set(" Recalculation required.") 811 except: 812 pass 813 elif calc_flag == 3: 814 try: 815 val2.configure( bg = 'red' ) 816 self.statusbar.configure( bg = 'red' ) 817 self.statusMessage.set(" Value should be a number. ") 818 except: 819 pass 820 elif calc_flag == 2: 821 try: 822 self.statusbar.configure( bg = 'red' ) 823 val2.configure( bg = 'red' ) 824 except: 825 pass 826 elif (calc_flag == 0 or calc_flag == 1) and new==1 : 827 try: 828 self.statusbar.configure( bg = 'white' ) 829 self.statusMessage.set(" ") 830 val2.configure( bg = 'white' ) 831 except: 832 pass 833 elif (calc_flag == 1) and new==0 : 834 try: 835 self.statusbar.configure( bg = 'white' ) 836 self.statusMessage.set(" ") 837 val2.configure( bg = 'white' ) 838 except: 839 pass 840 841 elif (calc_flag == 0 or calc_flag == 1) and new==2: 842 return 0 843 return 1 844 845################################################################################ 846 def Write_Config_File(self, event): 847 848 config_data = self.WriteConfig() 849 config_file = "k40_whisperer.txt" 850 configname_full = self.HOME_DIR + "/" + config_file 851 852 current_name = event.widget.winfo_parent() 853 win_id = event.widget.nametowidget(current_name) 854 855 if ( os.path.isfile(configname_full) ): 856 try: 857 win_id.withdraw() 858 except: 859 pass 860 861 if not message_ask_ok_cancel("Replace", "Replace Exiting Configuration File?\n"+configname_full): 862 try: 863 win_id.deiconify() 864 except: 865 pass 866 return 867 try: 868 fout = open(configname_full,'w') 869 except: 870 self.statusMessage.set("Unable to open file for writing: %s" %(configname_full)) 871 self.statusbar.configure( bg = 'red' ) 872 return 873 for line in config_data: 874 try: 875 fout.write(line+'\n') 876 except: 877 fout.write('(skipping line)\n') 878 fout.close 879 self.statusMessage.set("Configuration File Saved: %s" %(configname_full)) 880 self.statusbar.configure( bg = 'white' ) 881 try: 882 win_id.deiconify() 883 except: 884 pass 885 886 ################################################################################ 887 def WriteConfig(self): 888 global Zero 889 header = [] 890 header.append('( K40 Whisperer Settings: '+version+' )') 891 header.append('( by Scorch - 2019 )') 892 header.append("(=========================================================)") 893 # BOOL 894 header.append('(k40_whisperer_set include_Reng %s )' %( int(self.include_Reng.get()) )) 895 header.append('(k40_whisperer_set include_Veng %s )' %( int(self.include_Veng.get()) )) 896 header.append('(k40_whisperer_set include_Vcut %s )' %( int(self.include_Vcut.get()) )) 897 header.append('(k40_whisperer_set include_Gcde %s )' %( int(self.include_Gcde.get()) )) 898 header.append('(k40_whisperer_set include_Time %s )' %( int(self.include_Time.get()) )) 899 900 header.append('(k40_whisperer_set halftone %s )' %( int(self.halftone.get()) )) 901 header.append('(k40_whisperer_set HomeUR %s )' %( int(self.HomeUR.get()) )) 902 header.append('(k40_whisperer_set inputCSYS %s )' %( int(self.inputCSYS.get()) )) 903 header.append('(k40_whisperer_set advanced %s )' %( int(self.advanced.get()) )) 904 header.append('(k40_whisperer_set mirror %s )' %( int(self.mirror.get()) )) 905 header.append('(k40_whisperer_set rotate %s )' %( int(self.rotate.get()) )) 906 header.append('(k40_whisperer_set negate %s )' %( int(self.negate.get()) )) 907 908 header.append('(k40_whisperer_set engraveUP %s )' %( int(self.engraveUP.get()) )) 909 header.append('(k40_whisperer_set init_home %s )' %( int(self.init_home.get()) )) 910 header.append('(k40_whisperer_set post_home %s )' %( int(self.post_home.get()) )) 911 header.append('(k40_whisperer_set post_beep %s )' %( int(self.post_beep.get()) )) 912 header.append('(k40_whisperer_set post_disp %s )' %( int(self.post_disp.get()) )) 913 header.append('(k40_whisperer_set post_exec %s )' %( int(self.post_exec.get()) )) 914 915 header.append('(k40_whisperer_set pre_pr_crc %s )' %( int(self.pre_pr_crc.get()) )) 916 header.append('(k40_whisperer_set inside_first %s )' %( int(self.inside_first.get()) )) 917 918 header.append('(k40_whisperer_set comb_engrave %s )' %( int(self.comb_engrave.get()) )) 919 header.append('(k40_whisperer_set comb_vector %s )' %( int(self.comb_vector.get()) )) 920 header.append('(k40_whisperer_set zoom2image %s )' %( int(self.zoom2image.get()) )) 921 header.append('(k40_whisperer_set rotary %s )' %( int(self.rotary.get()) )) 922 923 header.append('(k40_whisperer_set trace_w_laser %s )' %( int(self.trace_w_laser.get()) )) 924 925 # STRING.get() 926 header.append('(k40_whisperer_set board_name %s )' %( self.board_name.get() )) 927 header.append('(k40_whisperer_set units %s )' %( self.units.get() )) 928 header.append('(k40_whisperer_set Reng_feed %s )' %( self.Reng_feed.get() )) 929 header.append('(k40_whisperer_set Veng_feed %s )' %( self.Veng_feed.get() )) 930 header.append('(k40_whisperer_set Vcut_feed %s )' %( self.Vcut_feed.get() )) 931 header.append('(k40_whisperer_set jog_step %s )' %( self.jog_step.get() )) 932 933 header.append('(k40_whisperer_set Reng_passes %s )' %( self.Reng_passes.get() )) 934 header.append('(k40_whisperer_set Veng_passes %s )' %( self.Veng_passes.get() )) 935 header.append('(k40_whisperer_set Vcut_passes %s )' %( self.Vcut_passes.get() )) 936 header.append('(k40_whisperer_set Gcde_passes %s )' %( self.Gcde_passes.get() )) 937 938 header.append('(k40_whisperer_set rast_step %s )' %( self.rast_step.get() )) 939 header.append('(k40_whisperer_set ht_size %s )' %( self.ht_size.get() )) 940 941 header.append('(k40_whisperer_set LaserXsize %s )' %( self.LaserXsize.get() )) 942 header.append('(k40_whisperer_set LaserYsize %s )' %( self.LaserYsize.get() )) 943 header.append('(k40_whisperer_set LaserXscale %s )' %( self.LaserXscale.get() )) 944 header.append('(k40_whisperer_set LaserYscale %s )' %( self.LaserYscale.get() )) 945 header.append('(k40_whisperer_set LaserRscale %s )' %( self.LaserRscale.get() )) 946 header.append('(k40_whisperer_set rapid_feed %s )' %( self.rapid_feed.get() )) 947 948 header.append('(k40_whisperer_set gotoX %s )' %( self.gotoX.get() )) 949 header.append('(k40_whisperer_set gotoY %s )' %( self.gotoY.get() )) 950 951 header.append('(k40_whisperer_set bezier_M1 %s )' %( self.bezier_M1.get() )) 952 header.append('(k40_whisperer_set bezier_M2 %s )' %( self.bezier_M2.get() )) 953 header.append('(k40_whisperer_set bezier_weight %s )' %( self.bezier_weight.get() )) 954 955 header.append('(k40_whisperer_set trace_gap %s )' %( self.trace_gap.get() )) 956 header.append('(k40_whisperer_set trace_speed %s )' %( self.trace_speed.get() )) 957 958## header.append('(k40_whisperer_set unsharp_flag %s )' %( int(self.unsharp_flag.get()) )) 959## header.append('(k40_whisperer_set unsharp_r %s )' %( self.unsharp_r.get() )) 960## header.append('(k40_whisperer_set unsharp_p %s )' %( self.unsharp_p.get() )) 961## header.append('(k40_whisperer_set unsharp_t %s )' %( self.unsharp_t.get() )) 962 963 header.append('(k40_whisperer_set t_timeout %s )' %( self.t_timeout.get() )) 964 header.append('(k40_whisperer_set n_timeouts %s )' %( self.n_timeouts.get() )) 965 966 header.append('(k40_whisperer_set ink_timeout %s )' %( self.ink_timeout.get() )) 967 968 969 header.append('(k40_whisperer_set designfile \042%s\042 )' %( self.DESIGN_FILE )) 970 header.append('(k40_whisperer_set inkscape_path \042%s\042 )' %( self.inkscape_path.get() )) 971 header.append('(k40_whisperer_set batch_path \042%s\042 )' %( self.batch_path.get() )) 972 973 974 self.jog_step 975 header.append("(=========================================================)") 976 977 return header 978 ###################################################### 979 980 def Quit_Click(self, event): 981 self.statusMessage.set("Exiting!") 982 self.Release_USB 983 root.destroy() 984 985 def mousePanStart(self,event): 986 self.panx = event.x 987 self.pany = event.y 988 self.move_start_x = event.x 989 self.move_start_y = event.y 990 991 def mousePan(self,event): 992 all = self.PreviewCanvas.find_all() 993 dx = event.x-self.panx 994 dy = event.y-self.pany 995 996 self.PreviewCanvas.move('LaserTag', dx, dy) 997 self.lastx = self.lastx + dx 998 self.lasty = self.lasty + dy 999 self.panx = event.x 1000 self.pany = event.y 1001 1002 def mousePanStop(self,event): 1003 Xold = round(self.laserX,3) 1004 Yold = round(self.laserY,3) 1005 1006 can_dx = event.x-self.move_start_x 1007 can_dy = -(event.y-self.move_start_y) 1008 1009 dx = can_dx*self.PlotScale 1010 dy = can_dy*self.PlotScale 1011 if self.HomeUR.get(): 1012 dx = -dx 1013 self.laserX,self.laserY = self.XY_in_bounds(dx,dy) 1014 DXmils = round((self.laserX - Xold)*1000.0,0) 1015 DYmils = round((self.laserY - Yold)*1000.0,0) 1016 1017 if self.Send_Rapid_Move(DXmils,DYmils): 1018 self.menu_View_Refresh() 1019 1020 def right_mousePanStart(self,event): 1021 self.s_panx = event.x 1022 self.s_pany = event.y 1023 self.s_move_start_x = event.x 1024 self.s_move_start_y = event.y 1025 1026 def right_mousePan(self,event): 1027 all = self.PreviewCanvas.find_all() 1028 dx = event.x-self.s_panx 1029 dy = event.y-self.s_pany 1030 1031 self.PreviewCanvas.move('LaserDot', dx, dy) 1032 self.s_lastx = self.lastx + dx 1033 self.s_lasty = self.lasty + dy 1034 self.s_panx = event.x 1035 self.s_pany = event.y 1036 1037 def right_mousePanStop(self,event): 1038 Xold = round(self.laserX,3) 1039 Yold = round(self.laserY,3) 1040 can_dx = event.x-self.s_move_start_x 1041 can_dy = -(event.y-self.s_move_start_y) 1042 1043 dx = can_dx*self.PlotScale 1044 dy = can_dy*self.PlotScale 1045 1046 DX = round(dx*1000) 1047 DY = round(dy*1000) 1048 self.Move_Arbitrary(DX,DY) 1049 self.menu_View_Refresh() 1050 1051 def LASER_Size(self): 1052 MINX = 0.0 1053 MAXY = 0.0 1054 if self.units.get()=="in": 1055 MAXX = float(self.LaserXsize.get()) 1056 MINY = -float(self.LaserYsize.get()) 1057 else: 1058 MAXX = float(self.LaserXsize.get())/25.4 1059 MINY = -float(self.LaserYsize.get())/25.4 1060 1061 return (MAXX-MINX,MAXY-MINY) 1062 1063 1064 def XY_in_bounds(self,dx_inches,dy_inches, no_size=False): 1065 MINX = 0.0 1066 MAXY = 0.0 1067 if self.units.get()=="in": 1068 MAXX = float(self.LaserXsize.get()) 1069 MINY = -float(self.LaserYsize.get()) 1070 else: 1071 MAXX = float(self.LaserXsize.get())/25.4 1072 MINY = -float(self.LaserYsize.get())/25.4 1073 1074 if (self.inputCSYS.get() and self.RengData.image == None) or no_size: 1075 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0 1076 else: 1077 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 1078 1079 X = self.laserX + dx_inches 1080 Y = self.laserY + dy_inches 1081 ################ 1082 dx=xmax-xmin 1083 dy=ymax-ymin 1084 if X < MINX: 1085 X = MINX 1086 if X+dx > MAXX: 1087 X = MAXX-dx 1088 1089 if Y-dy < MINY: 1090 Y = MINY+dy 1091 if Y > MAXY: 1092 Y = MAXY 1093 ################ 1094 if not no_size: 1095 XOFF = self.pos_offset[0]/1000.0 1096 YOFF = self.pos_offset[1]/1000.0 1097 if X+XOFF < MINX: 1098 X= X +(MINX-(X+XOFF)) 1099 if X+XOFF > MAXX: 1100 X= X -((X+XOFF)-MAXX) 1101 if Y+YOFF < MINY: 1102 Y= Y + (MINY-(Y+YOFF)) 1103 if Y+YOFF > MAXY: 1104 Y= Y -((Y+YOFF)-MAXY) 1105 ################ 1106 X = round(X,3) 1107 Y = round(Y,3) 1108 return X,Y 1109 1110## def computeAccurateVeng(self): 1111## self.update_gui("Optimize vector engrave.") 1112## self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords),data_sorted=True) 1113## self.refreshTime() 1114## 1115## def computeAccurateVcut(self): 1116## self.update_gui("Optimize vector cut.") 1117## self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True) 1118## self.refreshTime() 1119## 1120## def computeAccurateReng(self): 1121## self.update_gui("Calculating Raster engrave.") 1122## if self.RengData.image != None: 1123## if self.RengData.ecoords == []: 1124## self.make_raster_coords() 1125## self.RengData.sorted = True 1126## self.refreshTime() 1127 1128 1129 def format_time(self,time_in_seconds): 1130 # format the duration from seconds to something human readable 1131 if time_in_seconds !=None and time_in_seconds >=0 : 1132 s = round(time_in_seconds) 1133 m,s=divmod(s,60) 1134 h,m=divmod(m,60) 1135 res = "" 1136 if h > 0: 1137 res = "%dh " %(h) 1138 if m > 0: 1139 res += "%dm " %(m) 1140 if h == 0: 1141 res += "%ds " %(s) 1142 #L=len(res) 1143 #for i in range(L,8): 1144 # res = res+" " 1145 return res 1146 else : 1147 return "?" 1148 1149 def refreshTime(self): 1150 if not self.include_Time.get(): 1151 return 1152 if self.units.get() == 'in': 1153 factor = 60.0 1154 else : 1155 factor = 25.4 1156 1157 Raster_eng_feed = float(self.Reng_feed.get()) / factor 1158 Vector_eng_feed = float(self.Veng_feed.get()) / factor 1159 Vector_cut_feed = float(self.Vcut_feed.get()) / factor 1160 1161 Raster_eng_passes = float(self.Reng_passes.get()) 1162 Vector_eng_passes = float(self.Veng_passes.get()) 1163 Vector_cut_passes = float(self.Vcut_passes.get()) 1164 Gcode_passes = float(self.Gcde_passes.get()) 1165 1166 rapid_feed = 100.0 / 25.4 # 100 mm/s move feed to be confirmed 1167 1168 if self.RengData.rpaths: 1169 Reng_time=0 1170 else: 1171 Reng_time = None 1172 Veng_time = 0 1173 Vcut_time = 0 1174 1175 if self.RengData.len!=None: 1176 # these equations are a terrible hack based on measured raster engraving times 1177 # to be fixed someday 1178 if Raster_eng_feed*60.0 <= 300: 1179 accel_time=8.3264*(Raster_eng_feed*60.0)**(-0.7451) 1180 else: 1181 accel_time=2.5913*(Raster_eng_feed*60.0)**(-0.4795) 1182 1183 t_accel = self.RengData.n_scanlines * accel_time 1184 Reng_time = ( (self.RengData.len)/Raster_eng_feed ) * Raster_eng_passes + t_accel 1185 if self.VengData.len!=None: 1186 Veng_time = (self.VengData.len / Vector_eng_feed + self.VengData.move / rapid_feed) * Vector_eng_passes 1187 if self.VcutData.len!=None: 1188 Vcut_time = (self.VcutData.len / Vector_cut_feed + self.VcutData.move / rapid_feed) * Vector_cut_passes 1189 1190 Gcode_time = self.GcodeData.gcode_time * Gcode_passes 1191 1192 self.Reng_time.set("Raster Engrave: %s" %(self.format_time(Reng_time))) 1193 self.Veng_time.set("Vector Engrave: %s" %(self.format_time(Veng_time))) 1194 self.Vcut_time.set(" Vector Cut: %s" %(self.format_time(Vcut_time))) 1195 self.Gcde_time.set(" Gcode: %s" %(self.format_time(Gcode_time))) 1196 1197 ########################################## 1198 cszw = int(self.PreviewCanvas.cget("width")) 1199 cszh = int(self.PreviewCanvas.cget("height")) 1200 HUD_vspace = 15 1201 HUD_X = cszw-5 1202 HUD_Y = cszh-5 1203 1204 w = int(self.master.winfo_width()) 1205 h = int(self.master.winfo_height()) 1206 HUD_X2 = w-20 1207 HUD_Y2 = h-75 1208 1209 self.PreviewCanvas.delete("HUD") 1210 self.calc_button.place_forget() 1211 1212 if self.GcodeData.ecoords == []: 1213 self.PreviewCanvas.create_text(HUD_X, HUD_Y , fill = "red" ,text =self.Vcut_time.get(), anchor="se",tags="HUD") 1214 self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace , fill = "blue" ,text =self.Veng_time.get(), anchor="se",tags="HUD") 1215 1216 if (Reng_time==None): 1217 #try: 1218 # self.calc_button.place_forget() 1219 #except: 1220 # pass 1221 #self.calc_button = Button(self.master,text="Calculate Raster Time", command=self.menu_Calc_Raster_Time) 1222 self.calc_button.place(x=HUD_X2, y=HUD_Y2, width=120+20, height=17, anchor="se") 1223 else: 1224 self.calc_button.place_forget() 1225 self.PreviewCanvas.create_text(HUD_X, HUD_Y-HUD_vspace*2, fill = "black", 1226 text =self.Reng_time.get(), anchor="se",tags="HUD") 1227 else: 1228 self.PreviewCanvas.create_text(HUD_X, HUD_Y, fill = "black",text =self.Gcde_time.get(), anchor="se",tags="HUD") 1229 ########################################## 1230 1231 1232 def Settings_ReLoad_Click(self, event): 1233 win_id=self.grab_current() 1234 1235 def Close_Current_Window_Click(self,event=None): 1236 current_name = event.widget.winfo_parent() 1237 win_id = event.widget.nametowidget(current_name) 1238 win_id.destroy() 1239 1240 # Left Column # 1241 ############################# 1242 def Entry_Reng_feed_Check(self): 1243 try: 1244 value = float(self.Reng_feed.get()) 1245 vfactor=(25.4/60.0)/self.feed_factor() 1246 low_limit = self.min_raster_speed*vfactor 1247 if value < low_limit: 1248 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit)) 1249 return 2 # Value is invalid number 1250 except: 1251 return 3 # Value not a number 1252 self.refreshTime() 1253 return 0 # Value is a valid number 1254 def Entry_Reng_feed_Callback(self, varName, index, mode): 1255 self.entry_set(self.Entry_Reng_feed, self.Entry_Reng_feed_Check(), new=1) 1256 ############################# 1257 def Entry_Veng_feed_Check(self): 1258 try: 1259 value = float(self.Veng_feed.get()) 1260 vfactor=(25.4/60.0)/self.feed_factor() 1261 low_limit = self.min_vector_speed*vfactor 1262 if value < low_limit: 1263 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit)) 1264 return 2 # Value is invalid number 1265 except: 1266 return 3 # Value not a number 1267 self.refreshTime() 1268 return 0 # Value is a valid number 1269 def Entry_Veng_feed_Callback(self, varName, index, mode): 1270 self.entry_set(self.Entry_Veng_feed, self.Entry_Veng_feed_Check(), new=1) 1271 ############################# 1272 def Entry_Vcut_feed_Check(self): 1273 try: 1274 value = float(self.Vcut_feed.get()) 1275 vfactor=(25.4/60.0)/self.feed_factor() 1276 low_limit = self.min_vector_speed*vfactor 1277 if value < low_limit: 1278 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit)) 1279 return 2 # Value is invalid number 1280 except: 1281 return 3 # Value not a number 1282 self.refreshTime() 1283 return 0 # Value is a valid number 1284 def Entry_Vcut_feed_Callback(self, varName, index, mode): 1285 self.entry_set(self.Entry_Vcut_feed, self.Entry_Vcut_feed_Check(), new=1) 1286 1287 ############################# 1288 def Entry_Step_Check(self): 1289 try: 1290 value = float(self.jog_step.get()) 1291 if value <= 0.0: 1292 self.statusMessage.set(" Step should be greater than 0.0 ") 1293 return 2 # Value is invalid number 1294 except: 1295 return 3 # Value not a number 1296 return 0 # Value is a valid number 1297 def Entry_Step_Callback(self, varName, index, mode): 1298 self.entry_set(self.Entry_Step, self.Entry_Step_Check(), new=1) 1299 1300 1301 ############################# 1302 def Entry_GoToX_Check(self): 1303 try: 1304 value = float(self.gotoX.get()) 1305 if (value < 0.0) and (not self.HomeUR.get()): 1306 self.statusMessage.set(" Value should be greater than 0.0 ") 1307 return 2 # Value is invalid number 1308 elif (value > 0.0) and self.HomeUR.get(): 1309 self.statusMessage.set(" Value should be less than 0.0 ") 1310 return 2 # Value is invalid number 1311 except: 1312 return 3 # Value not a number 1313 return 0 # Value is a valid number 1314 def Entry_GoToX_Callback(self, varName, index, mode): 1315 self.entry_set(self.Entry_GoToX, self.Entry_GoToX_Check(), new=1) 1316 1317 ############################# 1318 def Entry_GoToY_Check(self): 1319 try: 1320 value = float(self.gotoY.get()) 1321 if value > 0.0: 1322 self.statusMessage.set(" Value should be less than 0.0 ") 1323 return 2 # Value is invalid number 1324 except: 1325 return 3 # Value not a number 1326 return 0 # Value is a valid number 1327 def Entry_GoToY_Callback(self, varName, index, mode): 1328 self.entry_set(self.Entry_GoToY, self.Entry_GoToY_Check(), new=1) 1329 1330 ############################# 1331 def Entry_Rstep_Check(self): 1332 try: 1333 value = self.get_raster_step_1000in() 1334 if value <= 0 or value > 63: 1335 self.statusMessage.set(" Step should be between 0.001 and 0.063 in") 1336 return 2 # Value is invalid number 1337 except: 1338 return 3 # Value not a number 1339 return 0 # Value is a valid number 1340 def Entry_Rstep_Callback(self, varName, index, mode): 1341 self.RengData.reset_path() 1342 self.refreshTime() 1343 self.entry_set(self.Entry_Rstep, self.Entry_Rstep_Check(), new=1) 1344 1345## ############################# 1346## def Entry_Unsharp_Radius_Check(self): 1347## try: 1348## value = float(self.unsharp_r.get()) 1349## if value <= 0: 1350## self.statusMessage.set(" Radius should be greater than zero.") 1351## return 2 # Value is invalid number 1352## except: 1353## return 3 # Value not a number 1354## self.menu_View_Refresh_Callback() 1355## return 0 # Value is a valid number 1356## def Entry_Unsharp_Radius_Callback(self, varName, index, mode): 1357## self.entry_set(self.Entry_Unsharp_Radius, self.Entry_Unsharp_Radius_Check(), new=1) 1358## 1359## 1360## ############################# 1361## def Entry_Unsharp_Percent_Check(self): 1362## try: 1363## value = float(self.unsharp_p.get()) 1364## if value <= 0: 1365## self.statusMessage.set(" Percent should be greater than zero.") 1366## return 2 # Value is invalid number 1367## except: 1368## return 3 # Value not a number 1369## self.menu_View_Refresh_Callback() 1370## return 0 # Value is a valid number 1371## def Entry_Unsharp_Percent_Callback(self, varName, index, mode): 1372## self.entry_set(self.Entry_Unsharp_Percent, self.Entry_Unsharp_Percent_Check(), new=1) 1373## 1374## ############################# 1375## def Entry_Unsharp_Threshold_Check(self): 1376## try: 1377## value = float(self.unsharp_t.get()) 1378## if value < 0: 1379## self.statusMessage.set(" Threshold should be greater than or equal to zero.") 1380## return 2 # Value is invalid number 1381## except: 1382## return 3 # Value not a number 1383## self.menu_View_Refresh_Callback() 1384## return 0 # Value is a valid number 1385## def Entry_Unsharp_Threshold_Callback(self, varName, index, mode): 1386## self.entry_set(self.Entry_Unsharp_Threshold, self.Entry_Unsharp_Threshold_Check(), new=1) 1387 1388 ############################# 1389 # End Left Column # 1390 ############################# 1391 def bezier_weight_Callback(self, varName=None, index=None, mode=None): 1392 self.Reset_RasterPath_and_Update_Time() 1393 self.bezier_plot() 1394 1395 def bezier_M1_Callback(self, varName=None, index=None, mode=None): 1396 self.Reset_RasterPath_and_Update_Time() 1397 self.bezier_plot() 1398 1399 def bezier_M2_Callback(self, varName=None, index=None, mode=None): 1400 self.Reset_RasterPath_and_Update_Time() 1401 self.bezier_plot() 1402 1403 def bezier_plot(self): 1404 self.BezierCanvas.delete('bez') 1405 1406 #self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="black", capstyle="round", width = 2, tags='bez') 1407 M1 = float(self.bezier_M1.get()) 1408 M2 = float(self.bezier_M2.get()) 1409 w = float(self.bezier_weight.get()) 1410 num = 10 1411 x,y = self.generate_bezier(M1,M2,w,n=num) 1412 for i in range(0,num): 1413 self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="black", \ 1414 capstyle="round", width = 2, tags='bez') 1415 self.BezierCanvas.create_text(128, 0, text="Output Level vs. Input Level",anchor="n", tags='bez') 1416 1417 1418 ############################# 1419 def Entry_Ink_Timeout_Check(self): 1420 try: 1421 value = float(self.ink_timeout.get()) 1422 if value < 0.0: 1423 self.statusMessage.set(" Timeout should be 0 or greater") 1424 return 2 # Value is invalid number 1425 except: 1426 return 3 # Value not a number 1427 return 0 # Value is a valid number 1428 def Entry_Ink_Timeout_Callback(self, varName, index, mode): 1429 self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(), new=1) 1430 1431 1432 ############################# 1433 def Entry_Timeout_Check(self): 1434 try: 1435 value = float(self.t_timeout.get()) 1436 if value <= 0.0: 1437 self.statusMessage.set(" Timeout should be greater than 0 ") 1438 return 2 # Value is invalid number 1439 except: 1440 return 3 # Value not a number 1441 return 0 # Value is a valid number 1442 def Entry_Timeout_Callback(self, varName, index, mode): 1443 self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(), new=1) 1444 1445 ############################# 1446 def Entry_N_Timeouts_Check(self): 1447 try: 1448 value = float(self.n_timeouts.get()) 1449 if value <= 0.0: 1450 self.statusMessage.set(" N_Timeouts should be greater than 0 ") 1451 return 2 # Value is invalid number 1452 except: 1453 return 3 # Value not a number 1454 return 0 # Value is a valid number 1455 def Entry_N_Timeouts_Callback(self, varName, index, mode): 1456 self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(), new=1) 1457 1458 ############################# 1459 def Entry_N_EGV_Passes_Check(self): 1460 try: 1461 value = int(self.n_egv_passes.get()) 1462 if value < 1: 1463 self.statusMessage.set(" EGV passes should be 1 or higher") 1464 return 2 # Value is invalid number 1465 except: 1466 return 3 # Value not a number 1467 return 0 # Value is a valid number 1468 def Entry_N_EGV_Passes_Callback(self, varName, index, mode): 1469 self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(), new=1) 1470 1471 ############################# 1472 def Entry_Laser_Area_Width_Check(self): 1473 try: 1474 value = float(self.LaserXsize.get()) 1475 if value <= 0.0: 1476 self.statusMessage.set(" Width should be greater than 0 ") 1477 return 2 # Value is invalid number 1478 except: 1479 return 3 # Value not a number 1480 return 0 # Value is a valid number 1481 def Entry_Laser_Area_Width_Callback(self, varName, index, mode): 1482 self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(), new=1) 1483 1484 ############################# 1485 def Entry_Laser_Area_Height_Check(self): 1486 try: 1487 value = float(self.LaserYsize.get()) 1488 if value <= 0.0: 1489 self.statusMessage.set(" Height should be greater than 0 ") 1490 return 2 # Value is invalid number 1491 except: 1492 return 3 # Value not a number 1493 return 0 # Value is a valid number 1494 def Entry_Laser_Area_Height_Callback(self, varName, index, mode): 1495 self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(), new=1) 1496 1497 1498 ############################# 1499 def Entry_Laser_X_Scale_Check(self): 1500 try: 1501 value = float(self.LaserXscale.get()) 1502 if value <= 0.0: 1503 self.statusMessage.set(" X scale factor should be greater than 0 ") 1504 return 2 # Value is invalid number 1505 except: 1506 return 3 # Value not a number 1507 self.Reset_RasterPath_and_Update_Time() 1508 return 0 # Value is a valid number 1509 def Entry_Laser_X_Scale_Callback(self, varName, index, mode): 1510 self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(), new=1) 1511 ############################# 1512 def Entry_Laser_Y_Scale_Check(self): 1513 try: 1514 value = float(self.LaserYscale.get()) 1515 if value <= 0.0: 1516 self.statusMessage.set(" Y scale factor should be greater than 0 ") 1517 return 2 # Value is invalid number 1518 except: 1519 return 3 # Value not a number 1520 self.Reset_RasterPath_and_Update_Time() 1521 return 0 # Value is a valid number 1522 def Entry_Laser_Y_Scale_Callback(self, varName, index, mode): 1523 self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(), new=1) 1524 1525 ############################# 1526 def Entry_Laser_R_Scale_Check(self): 1527 try: 1528 value = float(self.LaserRscale.get()) 1529 if value <= 0.0: 1530 self.statusMessage.set(" Rotary scale factor should be greater than 0 ") 1531 return 2 # Value is invalid number 1532 except: 1533 return 3 # Value not a number 1534 self.Reset_RasterPath_and_Update_Time() 1535 return 0 # Value is a valid number 1536 def Entry_Laser_R_Scale_Callback(self, varName, index, mode): 1537 self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(), new=1) 1538 1539 ############################# 1540 def Entry_Laser_Rapid_Feed_Check(self): 1541 try: 1542 value = float(self.rapid_feed.get()) 1543 vfactor=(25.4/60.0)/self.feed_factor() 1544 low_limit = 1.0*vfactor 1545 if value !=0 and value < low_limit: 1546 self.statusMessage.set(" Rapid feed should be greater than or equal to %f (or 0 for default speed) " %(low_limit)) 1547 return 2 # Value is invalid number 1548 except: 1549 return 3 # Value not a number 1550 return 0 # Value is a valid number 1551 def Entry_Laser_Rapid_Feed_Callback(self, varName, index, mode): 1552 self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(), new=1) 1553 1554 # Advanced Column # 1555 ############################# 1556 def Entry_Reng_passes_Check(self): 1557 try: 1558 value = int(self.Reng_passes.get()) 1559 if value < 1: 1560 self.statusMessage.set(" Number of passes should be greater than 0 ") 1561 return 2 # Value is invalid number 1562 except: 1563 return 3 # Value not a number 1564 self.refreshTime() 1565 return 0 # Value is a valid number 1566 def Entry_Reng_passes_Callback(self, varName, index, mode): 1567 self.entry_set(self.Entry_Reng_passes, self.Entry_Reng_passes_Check(), new=1) 1568 ############################# 1569 def Entry_Veng_passes_Check(self): 1570 try: 1571 value = int(self.Veng_passes.get()) 1572 if value < 1: 1573 self.statusMessage.set(" Number of passes should be greater than 0 ") 1574 return 2 # Value is invalid number 1575 except: 1576 return 3 # Value not a number 1577 self.refreshTime() 1578 return 0 # Value is a valid number 1579 def Entry_Veng_passes_Callback(self, varName, index, mode): 1580 self.entry_set(self.Entry_Veng_passes, self.Entry_Veng_passes_Check(), new=1) 1581 ############################# 1582 def Entry_Vcut_passes_Check(self): 1583 try: 1584 value = int(self.Vcut_passes.get()) 1585 if value < 1: 1586 self.statusMessage.set(" Number of passes should be greater than 0 ") 1587 return 2 # Value is invalid number 1588 except: 1589 return 3 # Value not a number 1590 self.refreshTime() 1591 return 0 # Value is a valid number 1592 def Entry_Vcut_passes_Callback(self, varName, index, mode): 1593 self.entry_set(self.Entry_Vcut_passes, self.Entry_Vcut_passes_Check(), new=1) 1594 1595 ############################# 1596 def Entry_Gcde_passes_Check(self): 1597 try: 1598 value = int(self.Gcde_passes.get()) 1599 if value < 1: 1600 self.statusMessage.set(" Number of passes should be greater than 0 ") 1601 return 2 # Value is invalid number 1602 except: 1603 return 3 # Value not a number 1604 self.refreshTime() 1605 return 0 # Value is a valid number 1606 def Entry_Gcde_passes_Callback(self, varName, index, mode): 1607 self.entry_set(self.Entry_Gcde_passes, self.Entry_Gcde_passes_Check(), new=1) 1608 1609 ############################# 1610 1611 def Entry_Trace_Gap_Check(self): 1612 try: 1613 value = float(self.trace_gap.get()) 1614 except: 1615 return 3 # Value not a number 1616 self.menu_View_Refresh() 1617 return 0 # Value is a valid number 1618 def Entry_Trace_Gap_Callback(self, varName, index, mode): 1619 self.entry_set(self.Entry_Trace_Gap, self.Entry_Trace_Gap_Check(), new=1) 1620 1621 ############################# 1622 1623 def Entry_Trace_Speed_Check(self): 1624 try: 1625 value = float(self.trace_speed.get()) 1626 vfactor=(25.4/60.0)/self.feed_factor() 1627 low_limit = self.min_vector_speed*vfactor 1628 if value < low_limit: 1629 self.statusMessage.set(" Feed Rate should be greater than or equal to %f " %(low_limit)) 1630 return 2 # Value is invalid number 1631 except: 1632 return 3 # Value not a number 1633 self.refreshTime() 1634 return 0 # Value is a valid number 1635 def Entry_Trace_Speed_Callback(self, varName, index, mode): 1636 self.entry_set(self.Entry_Trace_Speed, self.Entry_Trace_Speed_Check(), new=1) 1637 1638 ############################# 1639 def Inkscape_Path_Click(self, event): 1640 self.Inkscape_Path_Message() 1641 win_id=self.grab_current() 1642 newfontdir = askopenfilename(filetypes=[("Executable Files",("inkscape.exe","*inkscape*")),\ 1643 ("All Files","*")],\ 1644 initialdir=self.inkscape_path.get()) 1645 if newfontdir != "" and newfontdir != (): 1646 if type(newfontdir) is not str: 1647 newfontdir = newfontdir.encode("utf-8") 1648 self.inkscape_path.set(newfontdir) 1649 1650 try: 1651 win_id.withdraw() 1652 win_id.deiconify() 1653 except: 1654 pass 1655 1656 def Inkscape_Path_Message(self, event=None): 1657 if self.inkscape_warning == False: 1658 self.inkscape_warning = True 1659 msg1 = "Beware:" 1660 msg2 = "Most people should leave the 'Inkscape Executable' entry field blank. " 1661 msg3 = "K40 Whisperer will find Inkscape in one of the the standard locations after you install Inkscape." 1662 message_box(msg1, msg2+msg3) 1663 1664 1665 def Entry_units_var_Callback(self): 1666 if (self.units.get() == 'in') and (self.funits.get()=='mm/s'): 1667 self.funits.set('in/min') 1668 self.Scale_Linear_Inputs('in') 1669 elif (self.units.get() == 'mm') and (self.funits.get()=='in/min'): 1670 self.funits.set('mm/s') 1671 self.Scale_Linear_Inputs('mm') 1672 1673 def Scale_Linear_Inputs(self, new_units=None): 1674 if new_units=='in': 1675 self.units_scale = 1.0 1676 factor = 1/25.4 1677 vfactor = 60.0/25.4 1678 elif new_units=='mm': 1679 factor = 25.4 1680 vfactor = 25.4/60.0 1681 self.units_scale = 25.4 1682 else: 1683 return 1684 self.LaserXsize.set ( self.Scale_Text_Value('%.2f',self.LaserXsize.get() ,factor ) ) 1685 self.LaserYsize.set ( self.Scale_Text_Value('%.2f',self.LaserYsize.get() ,factor ) ) 1686 self.jog_step.set ( self.Scale_Text_Value('%.3f',self.jog_step.get() ,factor ) ) 1687 self.gotoX.set ( self.Scale_Text_Value('%.3f',self.gotoX.get() ,factor ) ) 1688 self.gotoY.set ( self.Scale_Text_Value('%.3f',self.gotoY.get() ,factor ) ) 1689 self.Reng_feed.set ( self.Scale_Text_Value('%.1f',self.Reng_feed.get() ,vfactor) ) 1690 self.Veng_feed.set ( self.Scale_Text_Value('%.1f',self.Veng_feed.get() ,vfactor) ) 1691 self.Vcut_feed.set ( self.Scale_Text_Value('%.1f',self.Vcut_feed.get() ,vfactor) ) 1692 self.trace_speed.set( self.Scale_Text_Value('%.1f',self.trace_speed.get() ,vfactor) ) 1693 self.rapid_feed.set ( self.Scale_Text_Value('%.1f',self.rapid_feed.get() ,vfactor) ) 1694 1695 def Scale_Text_Value(self,format_txt,Text_Value,factor): 1696 try: 1697 return format_txt %(float(Text_Value)*factor ) 1698 except: 1699 return '' 1700 1701 def menu_File_Open_Settings_File(self,event=None): 1702 init_dir = os.path.dirname(self.DESIGN_FILE) 1703 if ( not os.path.isdir(init_dir) ): 1704 init_dir = self.HOME_DIR 1705 fileselect = askopenfilename(filetypes=[("Settings Files","*.txt"),\ 1706 ("All Files","*")],\ 1707 initialdir=init_dir) 1708 if fileselect != '' and fileselect != (): 1709 self.Open_Settings_File(fileselect) 1710 1711 1712 def menu_Reload_Design(self,event=None): 1713 if self.GUI_Disabled: 1714 return 1715 file_full = self.DESIGN_FILE 1716 file_name = os.path.basename(file_full) 1717 if ( os.path.isfile(file_full) ): 1718 filename = file_full 1719 elif ( os.path.isfile( file_name ) ): 1720 filename = file_name 1721 elif ( os.path.isfile( self.HOME_DIR+"/"+file_name ) ): 1722 filename = self.HOME_DIR+"/"+file_name 1723 else: 1724 self.statusMessage.set("file not found: %s" %(os.path.basename(file_full)) ) 1725 self.statusbar.configure( bg = 'red' ) 1726 return 1727 1728 Name, fileExtension = os.path.splitext(filename) 1729 TYPE=fileExtension.upper() 1730 if TYPE=='.DXF': 1731 self.Open_DXF(filename) 1732 elif TYPE=='.SVG': 1733 self.Open_SVG(filename) 1734 elif TYPE=='.EGV': 1735 self.EGV_Send_Window(filename) 1736 else: 1737 self.Open_G_Code(filename) 1738 self.menu_View_Refresh() 1739 1740 1741 1742 def menu_File_Open_Design(self,event=None): 1743 if self.GUI_Disabled: 1744 return 1745 init_dir = os.path.dirname(self.DESIGN_FILE) 1746 if ( not os.path.isdir(init_dir) ): 1747 init_dir = self.HOME_DIR 1748 1749 design_types = ("Design Files", ("*.svg","*.dxf")) 1750 gcode_types = ("G-Code Files", ("*.ngc","*.gcode","*.g","*.tap")) 1751 1752 Name, fileExtension = os.path.splitext(self.DESIGN_FILE) 1753 TYPE=fileExtension.upper() 1754 if TYPE != '.DXF' and TYPE!='.SVG' and TYPE!='.EGV' and TYPE!='': 1755 default_types = gcode_types 1756 else: 1757 default_types = design_types 1758 1759 fileselect = askopenfilename(filetypes=[default_types, 1760 ("G-Code Files ", ("*.ngc","*.gcode","*.g","*.tap")),\ 1761 ("DXF Files ","*.dxf"),\ 1762 ("SVG Files ","*.svg"),\ 1763 ("All Files ","*"),\ 1764 ("Design Files ", ("*.svg","*.dxf"))],\ 1765 initialdir=init_dir) 1766 1767 if fileselect == () or (not os.path.isfile(fileselect)): 1768 return 1769 1770 Name, fileExtension = os.path.splitext(fileselect) 1771 self.update_gui("Opening '%s'" % fileselect ) 1772 TYPE=fileExtension.upper() 1773 if TYPE=='.DXF': 1774 self.Open_DXF(fileselect) 1775 elif TYPE=='.SVG': 1776 self.Open_SVG(fileselect) 1777 else: 1778 self.Open_G_Code(fileselect) 1779 1780 1781 self.DESIGN_FILE = fileselect 1782 self.menu_View_Refresh() 1783 1784 def menu_File_Raster_Engrave(self): 1785 self.menu_File_save_EGV(operation_type="Raster_Eng") 1786 1787 def menu_File_Vector_Engrave(self): 1788 self.menu_File_save_EGV(operation_type="Vector_Eng") 1789 1790 def menu_File_Vector_Cut(self): 1791 self.menu_File_save_EGV(operation_type="Vector_Cut") 1792 1793 def menu_File_G_Code(self): 1794 self.menu_File_save_EGV(operation_type="Gcode_Cut") 1795 1796 def menu_File_Raster_Vector_Engrave(self): 1797 self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng") 1798 1799 def menu_File_Vector_Engrave_Cut(self): 1800 self.menu_File_save_EGV(operation_type="Vector_Eng-Vector_Cut") 1801 1802 def menu_File_Raster_Vector_Cut(self): 1803 self.menu_File_save_EGV(operation_type="Raster_Eng-Vector_Eng-Vector_Cut") 1804 1805 def menu_File_save_EGV(self,operation_type=None,default_name="out.EGV"): 1806 self.stop[0]=False 1807 if DEBUG: 1808 start=time() 1809 fileName, fileExtension = os.path.splitext(self.DESIGN_FILE) 1810 init_file=os.path.basename(fileName) 1811 default_name = init_file+"_"+operation_type 1812 1813 if self.EGV_FILE != None: 1814 init_dir = os.path.dirname(self.EGV_FILE) 1815 else: 1816 init_dir = os.path.dirname(self.DESIGN_FILE) 1817 1818 if ( not os.path.isdir(init_dir) ): 1819 init_dir = self.HOME_DIR 1820 1821 fileName, fileExtension = os.path.splitext(default_name) 1822 init_file=os.path.basename(fileName) 1823 1824 filename = asksaveasfilename(defaultextension='.EGV', \ 1825 filetypes=[("EGV File","*.EGV")],\ 1826 initialdir=init_dir,\ 1827 initialfile= init_file ) 1828 1829 if filename != '' and filename != (): 1830 1831 if operation_type.find("Raster_Eng") > -1: 1832 self.make_raster_coords() 1833 else: 1834 self.statusbar.configure( bg = 'yellow' ) 1835 self.statusMessage.set("No raster data to engrave") 1836 1837 self.send_data(operation_type=operation_type, output_filename=filename) 1838 self.EGV_FILE = filename 1839 if DEBUG: 1840 print("time = %d seconds" %(int(time()-start))) 1841 self.stop[0]=True 1842 1843 1844 1845 def menu_File_Open_EGV(self): 1846 init_dir = os.path.dirname(self.DESIGN_FILE) 1847 if ( not os.path.isdir(init_dir) ): 1848 init_dir = self.HOME_DIR 1849 fileselect = askopenfilename(filetypes=[("Engraver Files", ("*.egv","*.EGV")),\ 1850 ("All Files","*")],\ 1851 initialdir=init_dir) 1852 if fileselect != '' and fileselect != (): 1853 self.resetPath() 1854 self.DESIGN_FILE = fileselect 1855 self.EGV_Send_Window(fileselect) 1856 1857 def Open_EGV(self,filemname,n_passes=1): 1858 self.stop[0]=False 1859 EGV_data=[] 1860 value1 = "" 1861 value2 = "" 1862 value3 = "" 1863 value4 = "" 1864 data="" 1865 #value1 and value2 are the absolute y and x starting positions 1866 #value3 and value4 are the absolute y and x end positions 1867 with open(filemname) as f: 1868 while True: 1869 ## Skip header 1870 c = f.read(1) 1871 while c!="%" and c: 1872 c = f.read(1) 1873 ## Read 1st Value 1874 c = f.read(1) 1875 while c!="%" and c: 1876 value1 = value1 + c 1877 c = f.read(1) 1878 y_start_mils = int(value1) 1879 ## Read 2nd Value 1880 c = f.read(1) 1881 while c!="%" and c: 1882 value2 = value2 + c 1883 c = f.read(1) 1884 x_start_mils = int(value2) 1885 ## Read 3rd Value 1886 c = f.read(1) 1887 while c!="%" and c: 1888 value3 = value3 + c 1889 c = f.read(1) 1890 y_end_mils = int(value3) 1891 ## Read 4th Value 1892 c = f.read(1) 1893 while c!="%" and c: 1894 value4 = value4 + c 1895 c = f.read(1) 1896 x_end_mils = int(value4) 1897 break 1898 1899 ## Read Data 1900 while True: 1901 c = f.read(1) 1902 if not c: 1903 break 1904 if c=='\n' or c==' ' or c=='\r': 1905 pass 1906 else: 1907 data=data+"%c" %c 1908 EGV_data.append(ord(c)) 1909 1910 if ( (x_end_mils != 0) or (y_end_mils != 0) ): 1911 n_passes=1 1912 else: 1913 x_start_mils = 0 1914 y_start_mils = 0 1915 1916 try: 1917 self.send_egv_data(EGV_data,n_passes) 1918 except MemoryError as e: 1919 msg1 = "Memory Error:" 1920 msg2 = "Memory Error: Out of Memory." 1921 self.statusMessage.set(msg2) 1922 self.statusbar.configure( bg = 'red' ) 1923 message_box(msg1, msg2) 1924 debug_message(traceback.format_exc()) 1925 1926 except Exception as e: 1927 msg1 = "Sending Data Stopped: " 1928 msg2 = "%s" %(e) 1929 if msg2 == "": 1930 formatted_lines = traceback.format_exc().splitlines() 1931 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 1932 self.statusbar.configure( bg = 'red' ) 1933 message_box(msg1, msg2) 1934 debug_message(traceback.format_exc()) 1935 1936 #rapid move back to starting position 1937 dxmils = -(x_end_mils - x_start_mils) 1938 dymils = y_end_mils - y_start_mils 1939 self.Send_Rapid_Move(dxmils,dxmils) 1940 self.stop[0]=True 1941 1942 1943 def Open_SVG(self,filemname): 1944 self.resetPath() 1945 1946 self.SVG_FILE = filemname 1947 svg_reader = SVG_READER() 1948 svg_reader.set_inkscape_path(self.inkscape_path.get()) 1949 self.input_dpi = 1000 1950 svg_reader.image_dpi = self.input_dpi 1951 svg_reader.timout = int(float( self.ink_timeout.get())*60.0) 1952 dialog_pxpi = None 1953 dialog_viewbox = None 1954 try: 1955 try: 1956 try: 1957 svg_reader.parse_svg(self.SVG_FILE) 1958 svg_reader.make_paths() 1959 except SVG_PXPI_EXCEPTION as e: 1960 pxpi_dialog = pxpiDialog(root, 1961 self.units.get(), 1962 svg_reader.SVG_Size, 1963 svg_reader.SVG_ViewBox, 1964 svg_reader.SVG_inkscape_version) 1965 1966 svg_reader = SVG_READER() 1967 svg_reader.set_inkscape_path(self.inkscape_path.get()) 1968 if pxpi_dialog.result == None: 1969 return 1970 1971 dialog_pxpi,dialog_viewbox = pxpi_dialog.result 1972 svg_reader.parse_svg(self.SVG_FILE) 1973 svg_reader.set_size(dialog_pxpi,dialog_viewbox) 1974 svg_reader.make_paths() 1975 1976 except SVG_TEXT_EXCEPTION as e: 1977 svg_reader = SVG_READER() 1978 svg_reader.set_inkscape_path(self.inkscape_path.get()) 1979 self.statusMessage.set("Converting TEXT to PATHS.") 1980 self.master.update() 1981 svg_reader.parse_svg(self.SVG_FILE) 1982 if dialog_pxpi != None and dialog_viewbox != None: 1983 svg_reader.set_size(dialog_pxpi,dialog_viewbox) 1984 svg_reader.make_paths(txt2paths=True) 1985 1986 except Exception as e: 1987 msg1 = "SVG Error: " 1988 msg2 = "%s" %(e) 1989 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 1990 self.statusbar.configure( bg = 'red' ) 1991 message_box(msg1, msg2) 1992 debug_message(traceback.format_exc()) 1993 return 1994 except: 1995 self.statusMessage.set("Unable To open SVG File: %s" %(filemname)) 1996 debug_message(traceback.format_exc()) 1997 return 1998 xmax = svg_reader.Xsize/25.4 1999 ymax = svg_reader.Ysize/25.4 2000 xmin = 0 2001 ymin = 0 2002 2003 self.Design_bounds = (xmin,xmax,ymin,ymax) 2004 2005 ########################## 2006 ### Create ECOORDS ### 2007 ########################## 2008 self.VcutData.make_ecoords(svg_reader.cut_lines,scale=1/25.4) 2009 self.VengData.make_ecoords(svg_reader.eng_lines,scale=1/25.4) 2010 2011 ########################## 2012 ### Load Image ### 2013 ########################## 2014 self.RengData.set_image(svg_reader.raster_PIL) 2015 2016 if (self.RengData.image != None): 2017 self.wim, self.him = self.RengData.image.size 2018 self.aspect_ratio = float(self.wim-1) / float(self.him-1) 2019 #self.make_raster_coords() 2020 self.refreshTime() 2021 margin=0.0625 # A bit of margin to prevent the warningwindow for designs that are close to being within the bounds 2022 if self.Design_bounds[0] > self.VengData.bounds[0]+margin or\ 2023 self.Design_bounds[0] > self.VcutData.bounds[0]+margin or\ 2024 self.Design_bounds[1] < self.VengData.bounds[1]-margin or\ 2025 self.Design_bounds[1] < self.VcutData.bounds[1]-margin or\ 2026 self.Design_bounds[2] > self.VengData.bounds[2]+margin or\ 2027 self.Design_bounds[2] > self.VcutData.bounds[2]+margin or\ 2028 self.Design_bounds[3] < self.VengData.bounds[3]-margin or\ 2029 self.Design_bounds[3] < self.VcutData.bounds[3]-margin: 2030 line1 = "Warning:\n" 2031 line2 = "There is vector cut or vector engrave data located outside of the SVG page bounds.\n\n" 2032 line3 = "K40 Whisperer will attempt to use all of the vector data. " 2033 line4 = "Please verify that the vector data is not outside of your lasers working area before engraving." 2034 message_box("Warning", line1+line2+line3+line4) 2035 2036 2037 ##################################################################### 2038 def make_raster_coords(self): 2039 if self.RengData.rpaths: 2040 return 2041 try: 2042 hcoords=[] 2043 if (self.RengData.image != None and self.RengData.ecoords==[]): 2044 ecoords=[] 2045 cutoff=128 2046 image_temp = self.RengData.image.convert("L") 2047## if self.unsharp_flag.get(): 2048## from PIL import ImageFilter 2049## #image_temp = image_temp.filter(UnsharpMask(radius=self.unsharp_r, percent=self.unsharp_p, threshold=self.unsharp_t)) 2050## filter = ImageFilter.UnsharpMask() 2051## filter.radius = float(self.unsharp_r.get()) # radius 3-5 pixels 2052## filter.percent = int(float(self.unsharp_p.get())) # precent 500% 2053## filter.threshold = int(float(self.unsharp_t.get())) # Threshold 0 2054## image_temp = image_temp.filter(filter) 2055 2056 if self.negate.get(): 2057 image_temp = ImageOps.invert(image_temp) 2058 2059 if self.mirror.get(): 2060 image_temp = ImageOps.mirror(image_temp) 2061 2062 if self.rotate.get(): 2063 #image_temp = image_temp.rotate(90,expand=True) 2064 image_temp = self.rotate_raster(image_temp) 2065 2066 Xscale = float(self.LaserXscale.get()) 2067 Yscale = float(self.LaserYscale.get()) 2068 if self.rotary.get(): 2069 Rscale = float(self.LaserRscale.get()) 2070 Yscale = Yscale*Rscale 2071 2072 if Xscale != 1.0 or Yscale != 1.0: 2073 wim,him = image_temp.size 2074 nw = int(wim*Xscale) 2075 nh = int(him*Yscale) 2076 image_temp = image_temp.resize((nw,nh)) 2077 2078 2079 if self.halftone.get(): 2080 #start = time() 2081 ht_size_mils = round( 1000.0 / float(self.ht_size.get()) ,1) 2082 npixels = int( round(ht_size_mils,1) ) 2083 if npixels == 0: 2084 return 2085 wim,him = image_temp.size 2086 # Convert to Halftoning and save 2087 nw=int(wim / npixels) 2088 nh=int(him / npixels) 2089 image_temp = image_temp.resize((nw,nh)) 2090 2091 image_temp = self.convert_halftoning(image_temp) 2092 image_temp = image_temp.resize((wim,him)) 2093 #print time()-start 2094 else: 2095 image_temp = image_temp.point(lambda x: 0 if x<128 else 255, '1') 2096 #image_temp = image_temp.convert('1',dither=Image.NONE) 2097 2098 2099 if DEBUG: 2100 image_name = os.path.expanduser("~")+"/IMAGE.png" 2101 image_temp.save(image_name,"PNG") 2102 2103 Reng_np = image_temp.load() 2104 wim,him = image_temp.size 2105 del image_temp 2106 ####################################### 2107 x=0 2108 y=0 2109 loop=1 2110 LENGTH=0 2111 n_scanlines = 0 2112 2113 my_hull = hull2D() 2114 bignumber = 9999999; 2115 Raster_step = self.get_raster_step_1000in() 2116 timestamp=0 2117 for i in range(0,him,Raster_step): 2118 stamp=int(3*time()) #update every 1/3 of a second 2119 if (stamp != timestamp): 2120 timestamp=stamp #interlock 2121 self.statusMessage.set("Creating Scan Lines: %.1f %%" %( (100.0*i)/him ) ) 2122 self.master.update() 2123 if self.stop[0]==True: 2124 raise Exception("Action stopped by User.") 2125 line = [] 2126 cnt=1 2127 LEFT = bignumber; 2128 RIGHT =-bignumber; 2129 for j in range(1,wim): 2130 if (Reng_np[j,i] == Reng_np[j-1,i]): 2131 cnt = cnt+1 2132 else: 2133 #laser = "U" if Reng_np[j-1,i] > cutoff else "D" 2134 if Reng_np[j-1,i]: 2135 laser = "U" 2136 else: 2137 laser = "D" 2138 LEFT = min(j-cnt,LEFT) 2139 RIGHT = max(j,RIGHT) 2140 2141 line.append((cnt,laser)) 2142 cnt=1 2143 #laser = "U" if Reng_np[j-1,i] > cutoff else "D" 2144 if Reng_np[j-1,i] > cutoff: 2145 laser = "U" 2146 else: 2147 laser = "D" 2148 LEFT = min(j-cnt,LEFT) 2149 RIGHT = max(j,RIGHT) 2150 2151 line.append((cnt,laser)) 2152 if LEFT != bignumber and RIGHT != -bignumber: 2153 LENGTH = LENGTH + (RIGHT - LEFT)/1000.0 2154 n_scanlines = n_scanlines + 1 2155 2156 y=(him-i)/1000.0 2157 x=0 2158 if LEFT != bignumber: 2159 hcoords.append([LEFT/1000.0,y]) 2160 if RIGHT != -bignumber: 2161 hcoords.append([RIGHT/1000.0,y]) 2162 if hcoords!=[]: 2163 hcoords = my_hull.convexHullecoords(hcoords) 2164 2165 #rng = range(0,len(line),1) 2166 rng = list(range(0,len(line),1)) 2167 2168 for i in rng: 2169 seg = line[i] 2170 delta = seg[0]/1000.0 2171 if seg[1]=="D": 2172 loop=loop+1 2173 ecoords.append([x ,y,loop]) 2174 ecoords.append([x+delta,y,loop]) 2175 x = x + delta 2176 #if ecoords!=[]: 2177 self.RengData.set_ecoords(ecoords,data_sorted=True) 2178 self.RengData.len=LENGTH 2179 self.RengData.n_scanlines = n_scanlines 2180 #Set Flag indicating raster paths have been calculated 2181 self.RengData.rpaths = True 2182 self.RengData.hull_coords = hcoords 2183 2184 except MemoryError as e: 2185 msg1 = "Memory Error:" 2186 msg2 = "Memory Error: Out of Memory." 2187 self.statusMessage.set(msg2) 2188 self.statusbar.configure( bg = 'red' ) 2189 message_box(msg1, msg2) 2190 debug_message(traceback.format_exc()) 2191 2192 except Exception as e: 2193 msg1 = "Making Raster Coords Stopped: " 2194 msg2 = "%s" %(e) 2195 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2196 self.statusbar.configure( bg = 'red' ) 2197 message_box(msg1, msg2) 2198 debug_message(traceback.format_exc()) 2199 ####################################################################### 2200 2201 2202 def rotate_raster(self,image_in): 2203 wim,him = image_in.size 2204 im_rotated = Image.new("L", (him, wim), "white") 2205 2206 image_in_np = image_in.load() 2207 im_rotated_np = im_rotated.load() 2208 2209 for i in range(1,him): 2210 for j in range(1,wim): 2211 im_rotated_np[i,wim-j] = image_in_np[j,i] 2212 return im_rotated 2213 2214 def get_raster_step_1000in(self): 2215 val_in = float(self.rast_step.get()) 2216 value = int(round(val_in*1000.0,1)) 2217 return value 2218 2219 2220 def generate_bezier(self,M1,M2,w,n=100): 2221 if (M1==M2): 2222 x1=0 2223 y1=0 2224 else: 2225 x1 = 255*(1-M2)/(M1-M2) 2226 y1 = M1*x1 2227 x=[] 2228 y=[] 2229 # Calculate Bezier Curve 2230 for step in range(0,n+1): 2231 t = float(step)/float(n) 2232 Ct = 1 / ( pow(1-t,2)+2*(1-t)*t*w+pow(t,2) ) 2233 x.append( Ct*( 2*(1-t)*t*w*x1+pow(t,2)*255) ) 2234 y.append( Ct*( 2*(1-t)*t*w*y1+pow(t,2)*255) ) 2235 return x,y 2236 2237 '''This Example opens an Image and transform the image into halftone. -Isai B. Cicourel''' 2238 # Create a Half-tone version of the image 2239 def convert_halftoning(self,image): 2240 image = image.convert('L') 2241 x_lim, y_lim = image.size 2242 pixel = image.load() 2243 2244 M1 = float(self.bezier_M1.get()) 2245 M2 = float(self.bezier_M2.get()) 2246 w = float(self.bezier_weight.get()) 2247 2248 if w > 0: 2249 x,y = self.generate_bezier(M1,M2,w) 2250 2251 interp = interpolate(x, y) # Set up interpolate class 2252 val_map=[] 2253 # Map Bezier Curve to values between 0 and 255 2254 for val in range(0,256): 2255 val_out = int(round(interp[val])) # Get the interpolated value at each value 2256 val_map.append(val_out) 2257 # Adjust image 2258 timestamp=0 2259 for y in range(1, y_lim): 2260 stamp=int(3*time()) #update every 1/3 of a second 2261 if (stamp != timestamp): 2262 timestamp=stamp #interlock 2263 self.statusMessage.set("Adjusting Image Darkness: %.1f %%" %( (100.0*y)/y_lim ) ) 2264 self.master.update() 2265 for x in range(1, x_lim): 2266 pixel[x, y] = val_map[ pixel[x, y] ] 2267 2268 self.statusMessage.set("Creating Halftone Image." ) 2269 self.master.update() 2270 image = image.convert('1') 2271 return image 2272 2273 ####################################################################### 2274 2275 def gcode_error_message(self,message): 2276 error_report = Toplevel(width=525,height=60) 2277 error_report.title("G-Code Reading Errors/Warnings") 2278 error_report.iconname("G-Code Errors") 2279 error_report.grab_set() 2280 return_value = StringVar() 2281 return_value.set("none") 2282 2283 2284 def Close_Click(event): 2285 return_value.set("close") 2286 error_report.destroy() 2287 2288 #Text Box 2289 Error_Frame = Frame(error_report) 2290 scrollbar = Scrollbar(Error_Frame, orient=VERTICAL) 2291 Error_Text = Text(Error_Frame, width="80", height="20",yscrollcommand=scrollbar.set,bg='white') 2292 for line in message: 2293 Error_Text.insert(END,line+"\n") 2294 scrollbar.config(command=Error_Text.yview) 2295 scrollbar.pack(side=RIGHT,fill=Y) 2296 #End Text Box 2297 2298 Button_Frame = Frame(error_report) 2299 close_button = Button(Button_Frame,text=" Close ") 2300 close_button.bind("<ButtonRelease-1>", Close_Click) 2301 close_button.pack(side=RIGHT,fill=X) 2302 2303 Error_Text.pack(side=LEFT,fill=BOTH,expand=1) 2304 Button_Frame.pack(side=BOTTOM) 2305 Error_Frame.pack(side=LEFT,fill=BOTH,expand=1) 2306 2307 root.wait_window(error_report) 2308 return return_value.get() 2309 2310 def Open_G_Code(self,filename): 2311 self.resetPath() 2312 2313 g_rip = G_Code_Rip() 2314 try: 2315 MSG = g_rip.Read_G_Code(filename, XYarc2line = True, arc_angle=2, units="in", Accuracy="") 2316 Error_Text = "" 2317 if MSG!=[]: 2318 self.gcode_error_message(MSG) 2319 2320 #except StandardError as e: 2321 except Exception as e: 2322 msg1 = "G-Code Load Failed: " 2323 msg2 = "Filename: %s" %(filename) 2324 msg3 = "%s" %(e) 2325 self.statusMessage.set((msg1+msg3).split("\n")[0] ) 2326 self.statusbar.configure( bg = 'red' ) 2327 message_box(msg1, "%s\n%s" %(msg2,msg3)) 2328 debug_message(traceback.format_exc()) 2329 2330 2331 ecoords= g_rip.generate_laser_paths(g_rip.g_code_data) 2332 self.GcodeData.set_ecoords(ecoords,data_sorted=True) 2333 self.Design_bounds = self.GcodeData.bounds 2334 2335 2336 def Open_DXF(self,filemname): 2337 self.resetPath() 2338 2339 self.DXF_FILE = filemname 2340 dxf_import=DXF_CLASS() 2341 tolerance = .0005 2342 try: 2343 fd = open(self.DXF_FILE) 2344 dxf_import.GET_DXF_DATA(fd,lin_tol = tolerance,get_units=True,units=None) 2345 fd.seek(0) 2346 2347 dxf_units = dxf_import.units 2348 if dxf_units=="Unitless": 2349 d = UnitsDialog(root) 2350 dxf_units = d.result 2351 if dxf_units=="Inches": 2352 dxf_scale = 1.0 2353 elif dxf_units=="Feet": 2354 dxf_scale = 12.0 2355 elif dxf_units=="Miles": 2356 dxf_scale = 5280.0*12.0 2357 elif dxf_units=="Millimeters": 2358 dxf_scale = 1.0/25.4 2359 elif dxf_units=="Centimeters": 2360 dxf_scale = 1.0/2.54 2361 elif dxf_units=="Meters": 2362 dxf_scale = 1.0/254.0 2363 elif dxf_units=="Kilometers": 2364 dxf_scale = 1.0/254000.0 2365 elif dxf_units=="Microinches": 2366 dxf_scale = 1.0/1000000.0 2367 elif dxf_units=="Mils": 2368 dxf_scale = 1.0/1000.0 2369 else: 2370 return 2371 2372 lin_tol = tolerance / dxf_scale 2373 dxf_import.GET_DXF_DATA(fd,lin_tol=lin_tol,get_units=False,units=None) 2374 fd.close() 2375 #except StandardError as e: 2376 except Exception as e: 2377 msg1 = "DXF Load Failed:" 2378 msg2 = "%s" %(e) 2379 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2380 self.statusbar.configure( bg = 'red' ) 2381 message_box(msg1, msg2) 2382 debug_message(traceback.format_exc()) 2383 except: 2384 fmessage("Unable To open Drawing Exchange File (DXF) file.") 2385 debug_message(traceback.format_exc()) 2386 return 2387 2388 new_origin=False 2389 dxf_engrave_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=True, new_origin=False) 2390 dxf_cut_coords = dxf_import.DXF_COORDS_GET_TYPE(engrave=False,new_origin=False) 2391## if DEBUG: 2392## dxf_code = dxf_import.WriteDXF(close_loops=False) 2393## fout = open('Z:\\out.dxf','w') 2394## for line in dxf_code: 2395## fout.write(line+'\n') 2396## fout.close 2397 2398 if dxf_import.dxf_messages != "": 2399 msg_split=dxf_import.dxf_messages.split("\n") 2400 msg_split.sort() 2401 msg_split.append("") 2402 mcnt=1 2403 msg_out = "" 2404 for i in range(1,len(msg_split)): 2405 if msg_split[i-1]==msg_split[i]: 2406 mcnt=mcnt+1 2407 else: 2408 if msg_split[i-1]!="": 2409 msg_line = "%s (%d places)\n" %(msg_split[i-1],mcnt) 2410 msg_out = msg_out + msg_line 2411 mcnt=1 2412 message_box("DXF Import:",msg_out) 2413 2414 ########################## 2415 ### Create ECOORDS ### 2416 ########################## 2417 self.VcutData.make_ecoords(dxf_cut_coords ,scale=dxf_scale) 2418 self.VengData.make_ecoords(dxf_engrave_coords,scale=dxf_scale) 2419 2420 xmin = min(self.VcutData.bounds[0],self.VengData.bounds[0]) 2421 xmax = max(self.VcutData.bounds[1],self.VengData.bounds[1]) 2422 ymin = min(self.VcutData.bounds[2],self.VengData.bounds[2]) 2423 ymax = max(self.VcutData.bounds[3],self.VengData.bounds[3]) 2424 self.Design_bounds = (xmin,xmax,ymin,ymax) 2425 2426 2427 def Open_Settings_File(self,filename): 2428 try: 2429 fin = open(filename,'r') 2430 except: 2431 fmessage("Unable to open file: %s" %(filename)) 2432 return 2433 2434 text_codes=[] 2435 ident = "k40_whisperer_set" 2436 for line in fin: 2437 try: 2438 if ident in line: 2439 # BOOL 2440 if "include_Reng" in line: 2441 self.include_Reng.set(line[line.find("include_Reng"):].split()[1]) 2442 elif "include_Veng" in line: 2443 self.include_Veng.set(line[line.find("include_Veng"):].split()[1]) 2444 elif "include_Vcut" in line: 2445 self.include_Vcut.set(line[line.find("include_Vcut"):].split()[1]) 2446 elif "include_Gcde" in line: 2447 self.include_Gcde.set(line[line.find("include_Gcde"):].split()[1]) 2448 elif "include_Time" in line: 2449 self.include_Time.set(line[line.find("include_Time"):].split()[1]) 2450 elif "halftone" in line: 2451 self.halftone.set(line[line.find("halftone"):].split()[1]) 2452 elif "negate" in line: 2453 self.negate.set(line[line.find("negate"):].split()[1]) 2454 elif "HomeUR" in line: 2455 self.HomeUR.set(line[line.find("HomeUR"):].split()[1]) 2456 elif "inputCSYS" in line: 2457 self.inputCSYS.set(line[line.find("inputCSYS"):].split()[1]) 2458 elif "advanced" in line: 2459 self.advanced.set(line[line.find("advanced"):].split()[1]) 2460 elif "mirror" in line: 2461 self.mirror.set(line[line.find("mirror"):].split()[1]) 2462 elif "rotate" in line: 2463 self.rotate.set(line[line.find("rotate"):].split()[1]) 2464 elif "engraveUP" in line: 2465 self.engraveUP.set(line[line.find("engraveUP"):].split()[1]) 2466 elif "init_home" in line: 2467 self.init_home.set(line[line.find("init_home"):].split()[1]) 2468 elif "post_home" in line: 2469 self.post_home.set(line[line.find("post_home"):].split()[1]) 2470 elif "post_beep" in line: 2471 self.post_beep.set(line[line.find("post_beep"):].split()[1]) 2472 elif "post_disp" in line: 2473 self.post_disp.set(line[line.find("post_disp"):].split()[1]) 2474 elif "post_exec" in line: 2475 self.post_exec.set(line[line.find("post_exec"):].split()[1]) 2476 2477 elif "pre_pr_crc" in line: 2478 self.pre_pr_crc.set(line[line.find("pre_pr_crc"):].split()[1]) 2479 elif "inside_first" in line: 2480 self.inside_first.set(line[line.find("inside_first"):].split()[1]) 2481 elif "comb_engrave" in line: 2482 self.comb_engrave.set(line[line.find("comb_engrave"):].split()[1]) 2483 elif "comb_vector" in line: 2484 self.comb_vector.set(line[line.find("comb_vector"):].split()[1]) 2485 elif "zoom2image" in line: 2486 self.zoom2image.set(line[line.find("zoom2image"):].split()[1]) 2487 2488 elif "rotary" in line: 2489 self.rotary.set(line[line.find("rotary"):].split()[1]) 2490 elif "trace_w_laser" in line: 2491 self.trace_w_laser.set(line[line.find("trace_w_laser"):].split()[1]) 2492 2493 # STRING.set() 2494 elif "board_name" in line: 2495 self.board_name.set(line[line.find("board_name"):].split()[1]) 2496 elif "units" in line: 2497 self.units.set(line[line.find("units"):].split()[1]) 2498 elif "Reng_feed" in line: 2499 self.Reng_feed .set(line[line.find("Reng_feed"):].split()[1]) 2500 elif "Veng_feed" in line: 2501 self.Veng_feed .set(line[line.find("Veng_feed"):].split()[1]) 2502 elif "Vcut_feed" in line: 2503 self.Vcut_feed.set(line[line.find("Vcut_feed"):].split()[1]) 2504 elif "jog_step" in line: 2505 self.jog_step.set(line[line.find("jog_step"):].split()[1]) 2506 2507 elif "Reng_passes" in line: 2508 self.Reng_passes.set(line[line.find("Reng_passes"):].split()[1]) 2509 elif "Veng_passes" in line: 2510 self.Veng_passes.set(line[line.find("Veng_passes"):].split()[1]) 2511 elif "Vcut_passes" in line: 2512 self.Vcut_passes.set(line[line.find("Vcut_passes"):].split()[1]) 2513 elif "Gcde_passes" in line: 2514 self.Gcde_passes.set(line[line.find("Gcde_passes"):].split()[1]) 2515 2516 elif "rast_step" in line: 2517 self.rast_step.set(line[line.find("rast_step"):].split()[1]) 2518 elif "ht_size" in line: 2519 self.ht_size.set(line[line.find("ht_size"):].split()[1]) 2520 2521 elif "LaserXsize" in line: 2522 self.LaserXsize.set(line[line.find("LaserXsize"):].split()[1]) 2523 elif "LaserYsize" in line: 2524 self.LaserYsize.set(line[line.find("LaserYsize"):].split()[1]) 2525 2526 elif "LaserXscale" in line: 2527 self.LaserXscale.set(line[line.find("LaserXscale"):].split()[1]) 2528 elif "LaserYscale" in line: 2529 self.LaserYscale.set(line[line.find("LaserYscale"):].split()[1]) 2530 elif "LaserRscale" in line: 2531 self.LaserRscale.set(line[line.find("LaserRscale"):].split()[1]) 2532 2533 elif "rapid_feed" in line: 2534 self.rapid_feed.set(line[line.find("rapid_feed"):].split()[1]) 2535 2536 elif "gotoX" in line: 2537 self.gotoX.set(line[line.find("gotoX"):].split()[1]) 2538 elif "gotoY" in line: 2539 self.gotoY.set(line[line.find("gotoY"):].split()[1]) 2540 2541 elif "bezier_M1" in line: 2542 self.bezier_M1.set(line[line.find("bezier_M1"):].split()[1]) 2543 elif "bezier_M2" in line: 2544 self.bezier_M2.set(line[line.find("bezier_M2"):].split()[1]) 2545 elif "bezier_weight" in line: 2546 self.bezier_weight.set(line[line.find("bezier_weight"):].split()[1]) 2547 elif "trace_gap" in line: 2548 self.trace_gap.set(line[line.find("trace_gap"):].split()[1]) 2549 elif "trace_speed" in line: 2550 self.trace_speed.set(line[line.find("trace_speed"):].split()[1]) 2551 2552 ## elif "unsharp_flag" in line: 2553 ## self.unsharp_flag.set(line[line.find("unsharp_flag"):].split()[1]) 2554 ## elif "unsharp_r" in line: 2555 ## self.unsharp_r.set(line[line.find("unsharp_r"):].split()[1]) 2556 ## elif "unsharp_p" in line: 2557 ## self.unsharp_p.set(line[line.find("unsharp_p"):].split()[1]) 2558 ## elif "unsharp_t" in line: 2559 ## self.unsharp_t.set(line[line.find("unsharp_t"):].split()[1]) 2560 2561 elif "t_timeout" in line: 2562 self.t_timeout.set(line[line.find("t_timeout"):].split()[1]) 2563 elif "n_timeouts" in line: 2564 self.n_timeouts.set(line[line.find("n_timeouts"):].split()[1]) 2565 2566 elif "ink_timeout" in line: 2567 self.ink_timeout.set(line[line.find("ink_timeout"):].split()[1]) 2568 2569 elif "designfile" in line: 2570 self.DESIGN_FILE=(line[line.find("designfile"):].split("\042")[1]) 2571 elif "inkscape_path" in line: 2572 self.inkscape_path.set(line[line.find("inkscape_path"):].split("\042")[1]) 2573 elif "batch_path" in line: 2574 self.batch_path.set(line[line.find("batch_path"):].split("\042")[1]) 2575 2576 2577 except: 2578 #Ignoring exeptions during reading data from line 2579 pass 2580 2581 fin.close() 2582 2583 fileName, fileExtension = os.path.splitext(self.DESIGN_FILE) 2584 init_file=os.path.basename(fileName) 2585 2586 if init_file != "None": 2587 if ( os.path.isfile(self.DESIGN_FILE) ): 2588 pass 2589 else: 2590 self.statusMessage.set("Image file not found: %s " %(self.DESIGN_FILE)) 2591 2592 if self.units.get() == 'in': 2593 self.funits.set('in/min') 2594 self.units_scale = 1.0 2595 else: 2596 self.units.set('mm') 2597 self.funits.set('mm/s') 2598 self.units_scale = 25.4 2599 2600 temp_name, fileExtension = os.path.splitext(filename) 2601 file_base=os.path.basename(temp_name) 2602 2603 if self.initComplete == 1: 2604 self.menu_Mode_Change() 2605 self.DESIGN_FILE = filename 2606 2607 ########################################################################## 2608 ########################################################################## 2609 def menu_File_Save(self): 2610 settings_data = self.WriteConfig() 2611 init_dir = os.path.dirname(self.DESIGN_FILE) 2612 if ( not os.path.isdir(init_dir) ): 2613 init_dir = self.HOME_DIR 2614 2615 fileName, fileExtension = os.path.splitext(self.DESIGN_FILE) 2616 init_file=os.path.basename(fileName) 2617 2618 filename = asksaveasfilename(defaultextension='.txt', \ 2619 filetypes=[("Text File","*.txt")],\ 2620 initialdir=init_dir,\ 2621 initialfile= init_file ) 2622 2623 if filename != '' and filename != (): 2624 try: 2625 fout = open(filename,'w') 2626 except: 2627 self.statusMessage.set("Unable to open file for writing: %s" %(filename)) 2628 self.statusbar.configure( bg = 'red' ) 2629 return 2630 2631 for line in settings_data: 2632 try: 2633 fout.write(line+'\n') 2634 except: 2635 fout.write('(skipping line)\n') 2636 debug_message(traceback.format_exc()) 2637 fout.close 2638 self.statusMessage.set("File Saved: %s" %(filename)) 2639 self.statusbar.configure( bg = 'white' ) 2640 2641 def Get_Design_Bounds(self): 2642 if self.rotate.get(): 2643 ymin = self.Design_bounds[0] 2644 ymax = self.Design_bounds[1] 2645 xmin = -self.Design_bounds[3] 2646 xmax = -self.Design_bounds[2] 2647 else: 2648 xmin,xmax,ymin,ymax = self.Design_bounds 2649 return (xmin,xmax,ymin,ymax) 2650 2651 def Move_UL(self,dummy=None): 2652 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 2653 if self.HomeUR.get(): 2654 Xnew = self.laserX + (xmax-xmin) 2655 DX = round((xmax-xmin)*1000.0) 2656 else: 2657 Xnew = self.laserX 2658 DX = 0 2659 2660 (Xsize,Ysize)=self.LASER_Size() 2661 if Xnew <= Xsize+.001: 2662 self.move_head_window_temporary([DX,0.0]) 2663 else: 2664 pass 2665 2666 def Move_UR(self,dummy=None): 2667 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 2668 if self.HomeUR.get(): 2669 Xnew = self.laserX 2670 DX = 0 2671 else: 2672 Xnew = self.laserX + (xmax-xmin) 2673 DX = round((xmax-xmin)*1000.0) 2674 2675 (Xsize,Ysize)=self.LASER_Size() 2676 if Xnew <= Xsize+.001: 2677 self.move_head_window_temporary([DX,0.0]) 2678 else: 2679 pass 2680 2681 def Move_LR(self,dummy=None): 2682 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 2683 if self.HomeUR.get(): 2684 Xnew = self.laserX 2685 DX = 0 2686 else: 2687 Xnew = self.laserX + (xmax-xmin) 2688 DX = round((xmax-xmin)*1000.0) 2689 2690 Ynew = self.laserY - (ymax-ymin) 2691 (Xsize,Ysize)=self.LASER_Size() 2692 if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001: 2693 DY = round((ymax-ymin)*1000.0) 2694 self.move_head_window_temporary([DX,-DY]) 2695 else: 2696 pass 2697 2698 def Move_LL(self,dummy=None): 2699 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 2700 if self.HomeUR.get(): 2701 Xnew = self.laserX + (xmax-xmin) 2702 DX = round((xmax-xmin)*1000.0) 2703 else: 2704 Xnew = self.laserX 2705 DX = 0 2706 2707 Ynew = self.laserY - (ymax-ymin) 2708 (Xsize,Ysize)=self.LASER_Size() 2709 if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001: 2710 DY = round((ymax-ymin)*1000.0) 2711 self.move_head_window_temporary([DX,-DY]) 2712 else: 2713 pass 2714 2715 def Move_CC(self,dummy=None): 2716 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 2717 if self.HomeUR.get(): 2718 Xnew = self.laserX + (xmax-xmin)/2.0 2719 DX = round((xmax-xmin)/2.0*1000.0) 2720 else: 2721 Xnew = self.laserX + (xmax-xmin)/2.0 2722 DX = round((xmax-xmin)/2.0*1000.0) 2723 2724 2725 Ynew = self.laserY - (ymax-ymin)/2.0 2726 (Xsize,Ysize)=self.LASER_Size() 2727 if Xnew <= Xsize+.001 and Ynew >= -Ysize-.001: 2728 DY = round((ymax-ymin)/2.0*1000.0) 2729 self.move_head_window_temporary([DX,-DY]) 2730 else: 2731 pass 2732 2733 def Move_Arbitrary(self,MoveX,MoveY,dummy=None): 2734 if self.GUI_Disabled: 2735 return 2736 if self.HomeUR.get(): 2737 DX = -MoveX 2738 else: 2739 DX = MoveX 2740 DY = MoveY 2741 NewXpos = self.pos_offset[0]+DX 2742 NewYpos = self.pos_offset[1]+DY 2743 self.move_head_window_temporary([NewXpos,NewYpos]) 2744 2745 def Move_Arb_Step(self,dx,dy): 2746 if self.GUI_Disabled: 2747 return 2748 if self.units.get()=="in": 2749 dx_inches = round(dx*1000) 2750 dy_inches = round(dy*1000) 2751 else: 2752 dx_inches = round(dx/25.4*1000) 2753 dy_inches = round(dy/25.4*1000) 2754 self.Move_Arbitrary( dx_inches,dy_inches ) 2755 2756 def Move_Arb_Right(self,dummy=None): 2757 JOG_STEP = float( self.jog_step.get() ) 2758 self.Move_Arb_Step( JOG_STEP,0 ) 2759 2760 def Move_Arb_Left(self,dummy=None): 2761 JOG_STEP = float( self.jog_step.get() ) 2762 self.Move_Arb_Step( -JOG_STEP,0 ) 2763 2764 def Move_Arb_Up(self,dummy=None): 2765 JOG_STEP = float( self.jog_step.get() ) 2766 self.Move_Arb_Step( 0,JOG_STEP ) 2767 2768 def Move_Arb_Down(self,dummy=None): 2769 JOG_STEP = float( self.jog_step.get() ) 2770 self.Move_Arb_Step( 0,-JOG_STEP ) 2771 2772 #################################################### 2773 2774 def Move_Right(self,dummy=None): 2775 JOG_STEP = float( self.jog_step.get() ) 2776 self.Rapid_Move( JOG_STEP,0 ) 2777 2778 def Move_Left(self,dummy=None): 2779 JOG_STEP = float( self.jog_step.get() ) 2780 self.Rapid_Move( -JOG_STEP,0 ) 2781 2782 def Move_Up(self,dummy=None): 2783 JOG_STEP = float( self.jog_step.get() ) 2784 self.Rapid_Move( 0,JOG_STEP ) 2785 2786 def Move_Down(self,dummy=None): 2787 JOG_STEP = float( self.jog_step.get() ) 2788 self.Rapid_Move( 0,-JOG_STEP ) 2789 2790 def Rapid_Move(self,dx,dy): 2791 if self.GUI_Disabled: 2792 return 2793 if self.units.get()=="in": 2794 dx_inches = round(dx,3) 2795 dy_inches = round(dy,3) 2796 else: 2797 dx_inches = round(dx/25.4,3) 2798 dy_inches = round(dy/25.4,3) 2799 2800 if (self.HomeUR.get()): 2801 dx_inches = -dx_inches 2802 2803 Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches) 2804 dxmils = (Xnew - self.laserX)*1000.0 2805 dymils = (Ynew - self.laserY)*1000.0 2806 2807 if self.k40 == None: 2808 self.laserX = Xnew 2809 self.laserY = Ynew 2810 self.menu_View_Refresh() 2811 elif self.Send_Rapid_Move(dxmils,dymils): 2812 self.laserX = Xnew 2813 self.laserY = Ynew 2814 self.menu_View_Refresh() 2815 2816 2817 def Send_Rapid_Move(self,dxmils,dymils): 2818 try: 2819 if self.k40 != None: 2820 Xscale = float(self.LaserXscale.get()) 2821 Yscale = float(self.LaserYscale.get()) 2822 if self.rotary.get(): 2823 Rscale = float(self.LaserRscale.get()) 2824 Yscale = Yscale*Rscale 2825 2826 if Xscale != 1.0 or Yscale != 1.0: 2827 dxmils = int(round(dxmils *Xscale)) 2828 dymils = int(round(dymils *Yscale)) 2829 self.k40.n_timeouts = 10 2830 2831 if self.rotary.get() and float(self.rapid_feed.get()): 2832 self.slow_jog(int(dxmils),int(dymils)) 2833 else: 2834 self.k40.rapid_move(int(dxmils),int(dymils)) 2835 2836 return True 2837 else: 2838 return True 2839 #except StandardError as e: 2840 except Exception as e: 2841 msg1 = "Rapid Move Failed: " 2842 msg2 = "%s" %(e) 2843 if msg2 == "": 2844 formatted_lines = traceback.format_exc().splitlines() 2845 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2846 self.statusbar.configure( bg = 'red' ) 2847 debug_message(traceback.format_exc()) 2848 return False 2849 2850 2851 def slow_jog(self,dxmils,dymils): 2852 if int(dxmils)==0 and int(dymils)==0: 2853 return 2854 self.stop[0]=False 2855 Rapid_data=[] 2856 Rapid_inst = egv(target=lambda s:Rapid_data.append(s)) 2857 Rapid_feed = float(self.rapid_feed.get())*self.feed_factor() 2858 Rapid_inst.make_egv_rapid(dxmils,dymils,Feed=Rapid_feed,board_name=self.board_name.get()) 2859 self.send_egv_data(Rapid_data, 1, None) 2860 self.stop[0]=True 2861 2862 def update_gui(self, message=None, bgcolor='white'): 2863 if message!=None: 2864 self.statusMessage.set(message) 2865 self.statusbar.configure( bg = bgcolor ) 2866 self.master.update() 2867 return True 2868 2869 def set_gui(self,new_state="normal"): 2870 if new_state=="normal": 2871 self.GUI_Disabled=False 2872 else: 2873 self.GUI_Disabled=True 2874 2875 try: 2876 self.menuBar.entryconfigure("File" , state=new_state) 2877 self.menuBar.entryconfigure("View" , state=new_state) 2878 self.menuBar.entryconfigure("Tools" , state=new_state) 2879 self.menuBar.entryconfigure("Settings", state=new_state) 2880 self.menuBar.entryconfigure("Help" , state=new_state) 2881 self.PreviewCanvas.configure(state=new_state) 2882 2883 for w in self.master.winfo_children(): 2884 try: 2885 w.configure(state=new_state) 2886 except: 2887 pass 2888 self.Stop_Button.configure(state="normal") 2889 self.statusbar.configure(state="normal") 2890 self.master.update() 2891 except: 2892 if DEBUG: 2893 debug_message(traceback.format_exc()) 2894 2895 def Vector_Cut(self, output_filename=None): 2896 self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.") 2897 if self.VcutData.ecoords!=[]: 2898 self.send_data("Vector_Cut", output_filename) 2899 else: 2900 self.statusbar.configure( bg = 'yellow' ) 2901 self.statusMessage.set("No vector data to cut") 2902 self.Finish_Job() 2903 2904 def Vector_Eng(self, output_filename=None): 2905 self.Prepare_for_laser_run("Vector Engrave: Processing Vector Data.") 2906 if self.VengData.ecoords!=[]: 2907 self.send_data("Vector_Eng", output_filename) 2908 else: 2909 self.statusbar.configure( bg = 'yellow' ) 2910 self.statusMessage.set("No vector data to engrave") 2911 self.Finish_Job() 2912 2913 def Trace_Eng(self, output_filename=None): 2914 self.Prepare_for_laser_run("Boundary Trace: Processing Data.") 2915 self.trace_coords = self.make_trace_path() 2916 2917 if self.trace_coords!=[]: 2918 self.send_data("Trace_Eng", output_filename) 2919 else: 2920 self.statusbar.configure( bg = 'yellow' ) 2921 self.statusMessage.set("No trace data to follow") 2922 self.Finish_Job() 2923 2924 def Raster_Eng(self, output_filename=None): 2925 self.Prepare_for_laser_run("Raster Engraving: Processing Image Data.") 2926 try: 2927 self.make_raster_coords() 2928 if self.RengData.ecoords!=[]: 2929 self.send_data("Raster_Eng", output_filename) 2930 else: 2931 self.statusbar.configure( bg = 'yellow' ) 2932 self.statusMessage.set("No raster data to engrave") 2933 2934 except MemoryError as e: 2935 msg1 = "Memory Error:" 2936 msg2 = "Memory Error: Out of Memory." 2937 self.statusMessage.set(msg2) 2938 self.statusbar.configure( bg = 'red' ) 2939 message_box(msg1, msg2) 2940 debug_message(traceback.format_exc()) 2941 2942 except Exception as e: 2943 msg1 = "Making Raster Data Stopped: " 2944 msg2 = "%s" %(e) 2945 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2946 self.statusbar.configure( bg = 'red' ) 2947 message_box(msg1, msg2) 2948 debug_message(traceback.format_exc()) 2949 self.Finish_Job() 2950 2951 def Raster_Vector_Eng(self, output_filename=None): 2952 self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.") 2953 try: 2954 self.make_raster_coords() 2955 if self.RengData.ecoords!=[] or self.VengData.ecoords!=[]: 2956 self.send_data("Raster_Eng+Vector_Eng", output_filename) 2957 else: 2958 self.statusbar.configure( bg = 'yellow' ) 2959 self.statusMessage.set("No data to engrave") 2960 except Exception as e: 2961 msg1 = "Preparing Data Stopped: " 2962 msg2 = "%s" %(e) 2963 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2964 self.statusbar.configure( bg = 'red' ) 2965 message_box(msg1, msg2) 2966 debug_message(traceback.format_exc()) 2967 self.Finish_Job() 2968 2969 def Vector_Eng_Cut(self, output_filename=None): 2970 self.Prepare_for_laser_run("Vector Cut: Processing Vector Data.") 2971 if self.VcutData.ecoords!=[] or self.VengData.ecoords!=[]: 2972 self.send_data("Vector_Eng+Vector_Cut", output_filename) 2973 else: 2974 self.statusbar.configure( bg = 'yellow' ) 2975 self.statusMessage.set("No vector data.") 2976 self.Finish_Job() 2977 2978 def Raster_Vector_Cut(self, output_filename=None): 2979 self.Prepare_for_laser_run("Raster Engraving: Processing Image and Vector Data.") 2980 try: 2981 self.make_raster_coords() 2982 if self.RengData.ecoords!=[] or self.VengData.ecoords!=[] or self.VcutData.ecoords!=[]: 2983 self.send_data("Raster_Eng+Vector_Eng+Vector_Cut", output_filename) 2984 else: 2985 self.statusbar.configure( bg = 'yellow' ) 2986 self.statusMessage.set("No data to engrave/cut") 2987 except Exception as e: 2988 msg1 = "Preparing Data Stopped: " 2989 msg2 = "%s" %(e) 2990 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 2991 self.statusbar.configure( bg = 'red' ) 2992 message_box(msg1, msg2) 2993 debug_message(traceback.format_exc()) 2994 self.Finish_Job() 2995 2996 def Gcode_Cut(self, output_filename=None): 2997 self.Prepare_for_laser_run("G Code Cutting.") 2998 if self.GcodeData.ecoords!=[]: 2999 self.send_data("Gcode_Cut", output_filename) 3000 else: 3001 self.statusbar.configure( bg = 'yellow' ) 3002 self.statusMessage.set("No g-code data to cut") 3003 self.Finish_Job() 3004 3005 def Prepare_for_laser_run(self,msg): 3006 self.stop[0]=False 3007 self.move_head_window_temporary([0,0]) 3008 self.set_gui("disabled") 3009 self.statusbar.configure( bg = 'green' ) 3010 self.statusMessage.set(msg) 3011 self.master.update() 3012 3013 def Finish_Job(self, event=None): 3014 self.set_gui("normal") 3015 self.stop[0]=True 3016 if self.post_home.get(): 3017 self.Unlock() 3018 3019 if self.post_beep.get(): 3020 self.master.bell() 3021 3022 stderr = '' 3023 stdout = '' 3024 if self.post_exec.get(): 3025 cmd = [self.batch_path.get()] 3026 from subprocess import Popen, PIPE 3027 startupinfo=None 3028 proc = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, stdin=PIPE, startupinfo=startupinfo) 3029 stdout,stderr = proc.communicate() 3030 3031 if self.post_disp.get() or stderr != '': 3032 msg1 = '' 3033 minutes = floor(self.run_time / 60) 3034 seconds = self.run_time - minutes*60 3035 msg2 = "Job Ended.\nRun Time = %02d:%02d" %(minutes,seconds) 3036 if stdout != '': 3037 msg2=msg2+'\n\nBatch File Output:\n'+stdout 3038 if stderr != '': 3039 msg2=msg2+'\n\nBatch File Errors:\n'+stderr 3040 self.run_time = 0 3041 message_box(msg1, msg2) 3042 3043 3044 def make_trace_path(self): 3045 my_hull = hull2D() 3046 if self.inputCSYS.get() and self.RengData.image == None: 3047 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0 3048 else: 3049 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 3050 3051 startx = xmin 3052 starty = ymax 3053 3054 ####################################### 3055 Vcut_coords = self.VcutData.ecoords 3056 Veng_coords = self.VengData.ecoords 3057 Gcode_coords= self.GcodeData.ecoords 3058 if self.mirror.get() or self.rotate.get(): 3059 Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords) 3060 Veng_coords = self.mirror_rotate_vector_coords(Veng_coords) 3061 Gcode_coords= self.mirror_rotate_vector_coords(Gcode_coords) 3062 3063 ####################################### 3064 if self.RengData.ecoords==[]: 3065 if self.stop[0] == True: 3066 self.stop[0]=False 3067 self.make_raster_coords() 3068 self.stop[0]=True 3069 else: 3070 self.make_raster_coords() 3071 3072 RengHullCoords = [] 3073 Xscale = 1/float(self.LaserXscale.get()) 3074 Yscale = 1/float(self.LaserYscale.get()) 3075 if self.rotary.get(): 3076 Rscale = 1/float(self.LaserRscale.get()) 3077 Yscale = Yscale*Rscale 3078 3079 for point in self.RengData.hull_coords: 3080 RengHullCoords.append([point[0]*Xscale+xmin, point[1]*Yscale, point[2]]) 3081 3082 all_coords = [] 3083 all_coords.extend(Vcut_coords) 3084 all_coords.extend(Veng_coords) 3085 all_coords.extend(Gcode_coords) 3086 all_coords.extend(RengHullCoords) 3087 3088 trace_coords=[] 3089 if all_coords != []: 3090 trace_coords = my_hull.convexHullecoords(all_coords) 3091 gap = float(self.trace_gap.get())/self.units_scale 3092 trace_coords = self.offset_eccords(trace_coords,gap) 3093 3094 trace_coords,startx,starty = self.scale_vector_coords(trace_coords,startx,starty) 3095 return trace_coords 3096 3097 3098 ################################################################################ 3099 def Sort_Paths(self,ecoords,i_loop=2): 3100 ########################## 3101 ### find loop ends ### 3102 ########################## 3103 Lbeg=[] 3104 Lend=[] 3105 if len(ecoords)>0: 3106 Lbeg.append(0) 3107 loop_old=ecoords[0][i_loop] 3108 for i in range(1,len(ecoords)): 3109 loop = ecoords[i][i_loop] 3110 if loop != loop_old: 3111 Lbeg.append(i) 3112 Lend.append(i-1) 3113 loop_old=loop 3114 Lend.append(i) 3115 3116 ####################################################### 3117 # Find new order based on distance to next beg or end # 3118 ####################################################### 3119 order_out = [] 3120 use_beg=0 3121 if len(ecoords)>0: 3122 order_out.append([Lbeg[0],Lend[0]]) 3123 inext = 0 3124 total=len(Lbeg) 3125 for i in range(total-1): 3126 if use_beg==1: 3127 ii=Lbeg.pop(inext) 3128 Lend.pop(inext) 3129 else: 3130 ii=Lend.pop(inext) 3131 Lbeg.pop(inext) 3132 3133 Xcur = ecoords[ii][0] 3134 Ycur = ecoords[ii][1] 3135 3136 dx = Xcur - ecoords[ Lbeg[0] ][0] 3137 dy = Ycur - ecoords[ Lbeg[0] ][1] 3138 min_dist = dx*dx + dy*dy 3139 3140 dxe = Xcur - ecoords[ Lend[0] ][0] 3141 dye = Ycur - ecoords[ Lend[0] ][1] 3142 min_diste = dxe*dxe + dye*dye 3143 3144 inext=0 3145 inexte=0 3146 for j in range(1,len(Lbeg)): 3147 dx = Xcur - ecoords[ Lbeg[j] ][0] 3148 dy = Ycur - ecoords[ Lbeg[j] ][1] 3149 dist = dx*dx + dy*dy 3150 if dist < min_dist: 3151 min_dist=dist 3152 inext=j 3153 ### 3154 dxe = Xcur - ecoords[ Lend[j] ][0] 3155 dye = Ycur - ecoords[ Lend[j] ][1] 3156 diste = dxe*dxe + dye*dye 3157 if diste < min_diste: 3158 min_diste=diste 3159 inexte=j 3160 ### 3161 if min_diste < min_dist: 3162 inext=inexte 3163 order_out.append([Lend[inexte],Lbeg[inexte]]) 3164 use_beg=1 3165 else: 3166 order_out.append([Lbeg[inext],Lend[inext]]) 3167 use_beg=0 3168 ########################################################### 3169 return order_out 3170 3171 ##################################################### 3172 # determine if a point is inside a given polygon or not 3173 # Polygon is a list of (x,y) pairs. 3174 # http://www.ariel.com.au/a/python-point-int-poly.html 3175 ##################################################### 3176 def point_inside_polygon(self,x,y,poly): 3177 n = len(poly) 3178 inside = -1 3179 p1x = poly[0][0] 3180 p1y = poly[0][1] 3181 for i in range(n+1): 3182 p2x = poly[i%n][0] 3183 p2y = poly[i%n][1] 3184 if y > min(p1y,p2y): 3185 if y <= max(p1y,p2y): 3186 if x <= max(p1x,p2x): 3187 if p1y != p2y: 3188 xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x 3189 if p1x == p2x or x <= xinters: 3190 inside = inside * -1 3191 p1x,p1y = p2x,p2y 3192 3193 return inside 3194 3195 def optimize_paths(self,ecoords,inside_check=True): 3196 order_out = self.Sort_Paths(ecoords) 3197 lastx=-999 3198 lasty=-999 3199 Acc=0.004 3200 cuts=[] 3201 3202 for line in order_out: 3203 temp=line 3204 if temp[0] > temp[1]: 3205 step = -1 3206 else: 3207 step = 1 3208 3209 loop_old = -1 3210 3211 for i in range(temp[0],temp[1]+step,step): 3212 x1 = ecoords[i][0] 3213 y1 = ecoords[i][1] 3214 loop = ecoords[i][2] 3215 # check and see if we need to move to a new discontinuous start point 3216 if (loop != loop_old): 3217 dx = x1-lastx 3218 dy = y1-lasty 3219 dist = sqrt(dx*dx + dy*dy) 3220 if dist > Acc: 3221 cuts.append([[x1,y1]]) 3222 else: 3223 cuts[-1].append([x1,y1]) 3224 else: 3225 cuts[-1].append([x1,y1]) 3226 lastx = x1 3227 lasty = y1 3228 loop_old = loop 3229 3230 if inside_check: 3231 ##################################################### 3232 # For each loop determine if other loops are inside # 3233 ##################################################### 3234 Nloops=len(cuts) 3235 self.LoopTree=[] 3236 for iloop in range(Nloops): 3237 self.LoopTree.append([]) 3238 ## CUR_PCT=float(iloop)/Nloops*100.0 3239 ## if (not self.batch.get()): 3240 ## self.statusMessage.set('Determining Which Side of Loop to Cut: %d of %d' %(iloop+1,Nloops)) 3241 ## self.master.update() 3242 ipoly = cuts[iloop] 3243 ## Check points in other loops (could just check one) ## 3244 if ipoly != []: 3245 for jloop in range(Nloops): 3246 if jloop != iloop: 3247 inside = 0 3248 inside = inside + self.point_inside_polygon(cuts[jloop][0][0],cuts[jloop][0][1],ipoly) 3249 if inside > 0: 3250 self.LoopTree[iloop].append(jloop) 3251 ##################################################### 3252 for i in range(Nloops): 3253 lns=[] 3254 lns.append(i) 3255 self.remove_self_references(lns,self.LoopTree[i]) 3256 3257 self.order=[] 3258 self.loops = list(range(Nloops)) 3259 for i in range(Nloops): 3260 if self.LoopTree[i]!=[]: 3261 self.addlist(self.LoopTree[i]) 3262 self.LoopTree[i]=[] 3263 if self.loops[i]!=[]: 3264 self.order.append(self.loops[i]) 3265 self.loops[i]=[] 3266 #END inside_check 3267 ecoords_out = [] 3268 for i in self.order: 3269 line = cuts[i] 3270 for coord in line: 3271 ecoords_out.append([coord[0],coord[1],i]) 3272 #END inside_check 3273 else: 3274 ecoords_out = [] 3275 for i in range(len(cuts)): 3276 line = cuts[i] 3277 for coord in line: 3278 ecoords_out.append([coord[0],coord[1],i]) 3279 3280 return ecoords_out 3281 3282 def remove_self_references(self,loop_numbers,loops): 3283 for i in range(0,len(loops)): 3284 for j in range(0,len(loop_numbers)): 3285 if loops[i]==loop_numbers[j]: 3286 loops.pop(i) 3287 return 3288 if self.LoopTree[loops[i]]!=[]: 3289 loop_numbers.append(loops[i]) 3290 self.remove_self_references(loop_numbers,self.LoopTree[loops[i]]) 3291 3292 def addlist(self,list): 3293 for i in list: 3294 try: #this try/except is a bad hack fix to a recursion error. It should be fixed properly later. 3295 if self.LoopTree[i]!=[]: 3296 self.addlist(self.LoopTree[i]) #too many recursions here causes cmp error 3297 self.LoopTree[i]=[] 3298 except: 3299 pass 3300 if self.loops[i]!=[]: 3301 self.order.append(self.loops[i]) 3302 self.loops[i]=[] 3303 3304 3305 def mirror_rotate_vector_coords(self,coords): 3306 xmin = self.Design_bounds[0] 3307 xmax = self.Design_bounds[1] 3308 coords_rotate_mirror=[] 3309 3310 for i in range(len(coords)): 3311 coords_rotate_mirror.append(coords[i][:]) 3312 if self.mirror.get(): 3313 if self.inputCSYS.get() and self.RengData.image == None: 3314 coords_rotate_mirror[i][0]=-coords_rotate_mirror[i][0] 3315 else: 3316 coords_rotate_mirror[i][0]=xmin+xmax-coords_rotate_mirror[i][0] 3317 3318 3319 if self.rotate.get(): 3320 x = coords_rotate_mirror[i][0] 3321 y = coords_rotate_mirror[i][1] 3322 coords_rotate_mirror[i][0] = -y 3323 coords_rotate_mirror[i][1] = x 3324 3325 return coords_rotate_mirror 3326 3327 def scale_vector_coords(self,coords,startx,starty): 3328 3329 Xscale = float(self.LaserXscale.get()) 3330 Yscale = float(self.LaserYscale.get()) 3331 if self.rotary.get(): 3332 Rscale = float(self.LaserRscale.get()) 3333 Yscale = Yscale*Rscale 3334 3335 coords_scale=[] 3336 if Xscale != 1.0 or Yscale != 1.0: 3337 for i in range(len(coords)): 3338 coords_scale.append(coords[i][:]) 3339 x = coords_scale[i][0] 3340 y = coords_scale[i][1] 3341 coords_scale[i][0] = x*Xscale 3342 coords_scale[i][1] = y*Yscale 3343 scaled_startx = startx*Xscale 3344 scaled_starty = starty*Yscale 3345 else: 3346 coords_scale = coords 3347 scaled_startx = startx 3348 scaled_starty = starty 3349 3350 return coords_scale,scaled_startx,scaled_starty 3351 3352 3353 def feed_factor(self): 3354 if self.units.get()=='in': 3355 feed_factor = 25.4/60.0 3356 else: 3357 feed_factor = 1.0 3358 return feed_factor 3359 3360 def send_data(self,operation_type=None, output_filename=None): 3361 num_passes=0 3362 if self.k40 == None and output_filename == None: 3363 self.statusMessage.set("Laser Cutter is not Initialized...") 3364 self.statusbar.configure( bg = 'red' ) 3365 return 3366 try: 3367 feed_factor=self.feed_factor() 3368 3369 if self.inputCSYS.get() and self.RengData.image == None: 3370 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0 3371 else: 3372 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 3373 3374 startx = xmin 3375 starty = ymax 3376 3377 if self.HomeUR.get(): 3378 Xscale = float(self.LaserXscale.get()) 3379 FlipXoffset = Xscale*abs(xmax-xmin) 3380 if self.rotate.get(): 3381 startx = -xmin 3382 else: 3383 FlipXoffset = 0 3384 3385 if self.rotary.get(): 3386 Rapid_Feed = float(self.rapid_feed.get())*feed_factor 3387 else: 3388 Rapid_Feed = 0.0 3389 3390 Raster_Eng_data=[] 3391 Vector_Eng_data=[] 3392 Trace_Eng_data=[] 3393 Vector_Cut_data=[] 3394 G_code_Cut_data=[] 3395 3396 if (operation_type.find("Vector_Cut") > -1) and (self.VcutData.ecoords!=[]): 3397 Feed_Rate = float(self.Vcut_feed.get())*feed_factor 3398 self.statusMessage.set("Vector Cut: Determining Cut Order....") 3399 self.master.update() 3400 if not self.VcutData.sorted and self.inside_first.get(): 3401 self.VcutData.set_ecoords(self.optimize_paths(self.VcutData.ecoords),data_sorted=True) 3402 3403 3404## DEBUG_PLOT=False 3405## test_ecoords=self.VcutData.ecoords 3406## if DEBUG_PLOT: 3407## import matplotlib.pyplot as plt 3408## plt.ion() 3409## plt.clf() 3410## X=[] 3411## Y=[] 3412## LOOP_OLD = test_ecoords[0][2] 3413## for i in range(len(test_ecoords)): 3414## LOOP = test_ecoords[i][2] 3415## if LOOP != LOOP_OLD: 3416## plt.plot(X,Y) 3417## plt.pause(.5) 3418## X=[] 3419## Y=[] 3420## LOOP_OLD=LOOP 3421## X.append(test_ecoords[i][0]) 3422## Y.append(test_ecoords[i][1]) 3423## plt.plot(X,Y) 3424 3425 3426 self.statusMessage.set("Generating EGV data...") 3427 self.master.update() 3428 3429 Vcut_coords = self.VcutData.ecoords 3430 if self.mirror.get() or self.rotate.get(): 3431 Vcut_coords = self.mirror_rotate_vector_coords(Vcut_coords) 3432 3433 Vcut_coords,startx,starty = self.scale_vector_coords(Vcut_coords,startx,starty) 3434 Vector_Cut_egv_inst = egv(target=lambda s:Vector_Cut_data.append(s)) 3435 Vector_Cut_egv_inst.make_egv_data( 3436 Vcut_coords, \ 3437 startX=startx, \ 3438 startY=starty, \ 3439 Feed = Feed_Rate, \ 3440 board_name=self.board_name.get(), \ 3441 Raster_step = 0, \ 3442 update_gui=self.update_gui, \ 3443 stop_calc=self.stop, \ 3444 FlipXoffset=FlipXoffset, \ 3445 Rapid_Feed_Rate = Rapid_Feed, \ 3446 use_laser=True 3447 ) 3448 3449 if (operation_type.find("Vector_Eng") > -1) and (self.VengData.ecoords!=[]): 3450 Feed_Rate = float(self.Veng_feed.get())*feed_factor 3451 self.statusMessage.set("Vector Engrave: Determining Cut Order....") 3452 self.master.update() 3453 if not self.VengData.sorted and self.inside_first.get(): 3454 self.VengData.set_ecoords(self.optimize_paths(self.VengData.ecoords,inside_check=False),data_sorted=True) 3455 self.statusMessage.set("Generating EGV data...") 3456 self.master.update() 3457 3458 Veng_coords = self.VengData.ecoords 3459 if self.mirror.get() or self.rotate.get(): 3460 Veng_coords = self.mirror_rotate_vector_coords(Veng_coords) 3461 3462 Veng_coords,startx,starty = self.scale_vector_coords(Veng_coords,startx,starty) 3463 Vector_Eng_egv_inst = egv(target=lambda s:Vector_Eng_data.append(s)) 3464 Vector_Eng_egv_inst.make_egv_data( 3465 Veng_coords, \ 3466 startX=startx, \ 3467 startY=starty, \ 3468 Feed = Feed_Rate, \ 3469 board_name=self.board_name.get(), \ 3470 Raster_step = 0, \ 3471 update_gui=self.update_gui, \ 3472 stop_calc=self.stop, \ 3473 FlipXoffset=FlipXoffset, \ 3474 Rapid_Feed_Rate = Rapid_Feed, \ 3475 use_laser=True 3476 ) 3477 3478 3479 if (operation_type.find("Trace_Eng") > -1) and (self.trace_coords!=[]): 3480 Feed_Rate = float(self.trace_speed.get())*feed_factor 3481 laser_on = self.trace_w_laser.get() 3482 self.statusMessage.set("Generating EGV data...") 3483 self.master.update() 3484 Trace_Eng_egv_inst = egv(target=lambda s:Trace_Eng_data.append(s)) 3485 Trace_Eng_egv_inst.make_egv_data( 3486 self.trace_coords, \ 3487 startX=startx, \ 3488 startY=starty, \ 3489 Feed = Feed_Rate, \ 3490 board_name=self.board_name.get(), \ 3491 Raster_step = 0, \ 3492 update_gui=self.update_gui, \ 3493 stop_calc=self.stop, \ 3494 FlipXoffset=FlipXoffset, \ 3495 Rapid_Feed_Rate = Rapid_Feed, \ 3496 use_laser=laser_on 3497 ) 3498 3499 3500 if (operation_type.find("Raster_Eng") > -1) and (self.RengData.ecoords!=[]): 3501 Feed_Rate = float(self.Reng_feed.get())*feed_factor 3502 Raster_step = self.get_raster_step_1000in() 3503 if not self.engraveUP.get(): 3504 Raster_step = -Raster_step 3505 3506 raster_startx = 0 3507 3508 Yscale = float(self.LaserYscale.get()) 3509 if self.rotary.get(): 3510 Rscale = float(self.LaserRscale.get()) 3511 Yscale = Yscale*Rscale 3512 raster_starty = Yscale*starty 3513 3514 self.statusMessage.set("Generating EGV data...") 3515 self.master.update() 3516 Raster_Eng_egv_inst = egv(target=lambda s:Raster_Eng_data.append(s)) 3517 Raster_Eng_egv_inst.make_egv_data( 3518 self.RengData.ecoords, \ 3519 startX=raster_startx, \ 3520 startY=raster_starty, \ 3521 Feed = Feed_Rate, \ 3522 board_name=self.board_name.get(), \ 3523 Raster_step = Raster_step, \ 3524 update_gui=self.update_gui, \ 3525 stop_calc=self.stop, \ 3526 FlipXoffset=FlipXoffset, \ 3527 Rapid_Feed_Rate = Rapid_Feed, \ 3528 use_laser=True 3529 ) 3530 #self.RengData.reset_path() 3531 3532 if (operation_type.find("Gcode_Cut") > -1) and (self.GcodeData.ecoords!=[]): 3533 self.statusMessage.set("Generating EGV data...") 3534 self.master.update() 3535 Gcode_coords = self.GcodeData.ecoords 3536 if self.mirror.get() or self.rotate.get(): 3537 Gcode_coords = self.mirror_rotate_vector_coords(Gcode_coords) 3538 3539 Gcode_coords,startx,starty = self.scale_vector_coords(Gcode_coords,startx,starty) 3540 G_code_Cut_egv_inst = egv(target=lambda s:G_code_Cut_data.append(s)) 3541 G_code_Cut_egv_inst.make_egv_data( 3542 Gcode_coords, \ 3543 startX=startx, \ 3544 startY=starty, \ 3545 Feed = None, \ 3546 board_name=self.board_name.get(), \ 3547 Raster_step = 0, \ 3548 update_gui=self.update_gui, \ 3549 stop_calc=self.stop, \ 3550 FlipXoffset=FlipXoffset, \ 3551 Rapid_Feed_Rate = Rapid_Feed, \ 3552 use_laser=True 3553 ) 3554 3555 ### Join Resulting Data together ### 3556 data=[] 3557 data.append(ord("I")) 3558 if Trace_Eng_data!=[]: 3559 trace_passes=1 3560 for k in range(trace_passes): 3561 if len(data)> 4: 3562 data[-4]=ord("@") 3563 data.extend(Trace_Eng_data) 3564 if Raster_Eng_data!=[]: 3565 num_passes = int(float(self.Reng_passes.get())) 3566 for k in range(num_passes): 3567 if len(data)> 4: 3568 data[-4]=ord("@") 3569 data.extend(Raster_Eng_data) 3570 if Vector_Eng_data!=[]: 3571 num_passes = int(float(self.Veng_passes.get())) 3572 for k in range(num_passes): 3573 if len(data)> 4: 3574 data[-4]=ord("@") 3575 data.extend(Vector_Eng_data) 3576 if Vector_Cut_data!=[]: 3577 num_passes = int(float(self.Vcut_passes.get())) 3578 for k in range(num_passes): 3579 if len(data)> 4: 3580 data[-4]=ord("@") 3581 data.extend(Vector_Cut_data) 3582 if G_code_Cut_data!=[]: 3583 num_passes = int(float(self.Gcde_passes.get())) 3584 for k in range(num_passes): 3585 if len(data)> 4: 3586 data[-4]=ord("@") 3587 data.extend(G_code_Cut_data) 3588 if len(data)< 4: 3589 raise Exception("No laser data was generated.") 3590 3591 self.master.update() 3592 if output_filename != None: 3593 self.write_egv_to_file(data,output_filename) 3594 else: 3595 self.send_egv_data(data, 1, output_filename) 3596 self.menu_View_Refresh() 3597 3598 except MemoryError as e: 3599 msg1 = "Memory Error:" 3600 msg2 = "Memory Error: Out of Memory." 3601 self.statusMessage.set(msg2) 3602 self.statusbar.configure( bg = 'red' ) 3603 message_box(msg1, msg2) 3604 debug_message(traceback.format_exc()) 3605 3606 except Exception as e: 3607 msg1 = "Sending Data Stopped: " 3608 msg2 = "%s" %(e) 3609 if msg2 == "": 3610 formatted_lines = traceback.format_exc().splitlines() 3611 self.statusMessage.set((msg1+msg2).split("\n")[0] ) 3612 self.statusbar.configure( bg = 'red' ) 3613 message_box(msg1, msg2) 3614 debug_message(traceback.format_exc()) 3615 3616 def send_egv_data(self,data,num_passes=1,output_filename=None): 3617 pre_process_CRC = self.pre_pr_crc.get() 3618 if self.k40 != None: 3619 self.k40.timeout = int(float( self.t_timeout.get() )) 3620 self.k40.n_timeouts = int(float( self.n_timeouts.get() )) 3621 time_start = time() 3622 self.k40.send_data(data,self.update_gui,self.stop,num_passes,pre_process_CRC, wait_for_laser=True) 3623 self.run_time = time()-time_start 3624 if DEBUG: 3625 print(("Elapsed Time: %.6f" %(time()-time_start))) 3626 3627 else: 3628 self.statusMessage.set("Laser is not initialized.") 3629 self.statusbar.configure( bg = 'yellow' ) 3630 return 3631 self.menu_View_Refresh() 3632 3633 ########################################################################## 3634 ########################################################################## 3635 def write_egv_to_file(self,data,fname): 3636 if len(data) == 0: 3637 raise Exception("No data available to write to file.") 3638 try: 3639 fout = open(fname,'w') 3640 except: 3641 raise Exception("Unable to open file ( %s ) for writing." %(fname)) 3642 fout.write("Document type : LHYMICRO-GL file\n") 3643 fout.write("Creator-Software: K40 Whisperer\n") 3644 3645 fout.write("\n") 3646 fout.write("%0%0%0%0%") 3647 for char_val in data: 3648 char = chr(char_val) 3649 fout.write("%s" %(char)) 3650 3651 #fout.write("\n") 3652 fout.close 3653 self.menu_View_Refresh() 3654 self.statusMessage.set("Data saved to: %s" %(fname)) 3655 3656 def Home(self, event=None): 3657 if self.GUI_Disabled: 3658 return 3659 if self.k40 != None: 3660 self.k40.home_position() 3661 self.laserX = 0.0 3662 self.laserY = 0.0 3663 self.pos_offset = [0.0,0.0] 3664 self.menu_View_Refresh() 3665 3666 def GoTo(self): 3667 xpos = float(self.gotoX.get()) 3668 ypos = float(self.gotoY.get()) 3669 if self.k40 != None: 3670 self.k40.home_position() 3671 self.laserX = 0.0 3672 self.laserY = 0.0 3673 self.Rapid_Move(xpos,ypos) 3674 self.menu_View_Refresh() 3675 3676 def Reset(self): 3677 if self.k40 != None: 3678 try: 3679 self.k40.reset_usb() 3680 self.statusMessage.set("USB Reset Succeeded") 3681 except: 3682 debug_message(traceback.format_exc()) 3683 pass 3684 3685 def Stop(self,event=None): 3686 if self.stop[0]==True: 3687 return 3688 line1 = "Sending data to the laser from K40 Whisperer is currently Paused." 3689 line2 = "Press \"OK\" to abort any jobs currently running." 3690 line3 = "Press \"Cancel\" to resume." 3691 if self.k40 != None: 3692 self.k40.pause_un_pause() 3693 3694 if message_ask_ok_cancel("Stop Laser Job.", "%s\n\n%s\n%s" %(line1,line2,line3)): 3695 self.stop[0]=True 3696 else: 3697 if self.k40 != None: 3698 self.k40.pause_un_pause() 3699 3700 def Hide_Advanced(self,event=None): 3701 self.advanced.set(0) 3702 self.menu_View_Refresh() 3703 3704 def Release_USB(self): 3705 if self.k40 != None: 3706 try: 3707 self.k40.release_usb() 3708 self.statusMessage.set("USB Release Succeeded") 3709 except: 3710 debug_message(traceback.format_exc()) 3711 pass 3712 self.k40=None 3713 3714 def Initialize_Laser(self,event=None): 3715 if self.GUI_Disabled: 3716 return 3717 self.stop[0]=True 3718 self.Release_USB() 3719 self.k40=None 3720 self.move_head_window_temporary([0.0,0.0]) 3721 self.k40=K40_CLASS() 3722 try: 3723 self.k40.initialize_device() 3724 self.k40.say_hello() 3725 if self.init_home.get(): 3726 self.Home() 3727 else: 3728 self.Unlock() 3729 3730 except Exception as e: 3731 error_text = "%s" %(e) 3732 if "BACKEND" in error_text.upper(): 3733 error_text = error_text + " (libUSB driver not installed)" 3734 self.statusMessage.set("USB Error: %s" %(error_text)) 3735 self.statusbar.configure( bg = 'red' ) 3736 self.k40=None 3737 debug_message(traceback.format_exc()) 3738 3739 except: 3740 self.statusMessage.set("Unknown USB Error") 3741 self.statusbar.configure( bg = 'red' ) 3742 self.k40=None 3743 debug_message(traceback.format_exc()) 3744 3745 def Unlock(self,event=None): 3746 if self.GUI_Disabled: 3747 return 3748 if self.k40 != None: 3749 try: 3750 self.k40.unlock_rail() 3751 self.statusMessage.set("Rail Unlock Succeeded") 3752 self.statusbar.configure( bg = 'white' ) 3753 except: 3754 self.statusMessage.set("Rail Unlock Failed.") 3755 self.statusbar.configure( bg = 'red' ) 3756 debug_message(traceback.format_exc()) 3757 pass 3758 3759 ########################################################################## 3760 ########################################################################## 3761 3762 def menu_File_Quit(self): 3763 if message_ask_ok_cancel("Exit", "Exiting...."): 3764 self.Quit_Click(None) 3765 3766 def Reset_RasterPath_and_Update_Time(self, varName=0, index=0, mode=0): 3767 self.RengData.reset_path() 3768 self.refreshTime() 3769 3770 def View_Refresh_and_Reset_RasterPath(self, varName=0, index=0, mode=0): 3771 self.RengData.reset_path() 3772 self.SCALE = 0 3773 self.menu_View_Refresh() 3774 3775 def menu_View_inputCSYS_Refresh_Callback(self, varName, index, mode): 3776 self.move_head_window_temporary([0.0,0.0]) 3777 self.SCALE = 0 3778 self.menu_View_Refresh() 3779 3780 def menu_View_Refresh_Callback(self, varName=0, index=0, mode=0): 3781 self.SCALE = 0 3782 self.menu_View_Refresh() 3783 3784 if DEBUG: 3785 curframe = inspect.currentframe() 3786 calframe = inspect.getouterframes(curframe, 2) 3787 print('menu_View_Refresh_Callback called by: %s' %(calframe[1][3])) 3788 3789 def menu_View_Refresh(self): 3790 if DEBUG: 3791 curframe = inspect.currentframe() 3792 calframe = inspect.getouterframes(curframe, 2) 3793 print('menu_View_Refresh called by: %s' %(calframe[1][3])) 3794 3795 try: 3796 app.master.title(title_text+" "+ self.DESIGN_FILE) 3797 except: 3798 pass 3799 dummy_event = Event() 3800 dummy_event.widget=self.master 3801 self.Master_Configure(dummy_event,1) 3802 self.Plot_Data() 3803 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 3804 W = xmax-xmin 3805 H = ymax-ymin 3806 3807 if self.units.get()=="in": 3808 X_display = self.laserX + self.pos_offset[0]/1000.0 3809 Y_display = self.laserY + self.pos_offset[1]/1000.0 3810 W_display = W 3811 H_display = H 3812 U_display = self.units.get() 3813 else: 3814 X_display = (self.laserX + self.pos_offset[0]/1000.0)*self.units_scale 3815 Y_display = (self.laserY + self.pos_offset[1]/1000.0)*self.units_scale 3816 W_display = W*self.units_scale 3817 H_display = H*self.units_scale 3818 U_display = self.units.get() 3819 if self.HomeUR.get(): 3820 X_display = -X_display 3821 3822 self.statusMessage.set(" Current Position: X=%.3f Y=%.3f ( W X H )=( %.3f%s X %.3f%s ) " 3823 %(X_display, 3824 Y_display, 3825 W_display, 3826 U_display, 3827 H_display, 3828 U_display)) 3829 3830 self.statusbar.configure( bg = 'white' ) 3831 3832 def menu_Inside_First_Callback(self, varName, index, mode): 3833 if self.GcodeData.ecoords != []: 3834 if self.VcutData.sorted == True: 3835 self.menu_Reload_Design() 3836 elif self.VengData.sorted == True: 3837 self.menu_Reload_Design() 3838 3839 def menu_Mode_Change(self): 3840 dummy_event = Event() 3841 dummy_event.widget=self.master 3842 self.Master_Configure(dummy_event,1) 3843 3844 def menu_Calc_Raster_Time(self,event=None): 3845 self.set_gui("disabled") 3846 self.stop[0]=False 3847 self.make_raster_coords() 3848 self.stop[0]=True 3849 self.refreshTime() 3850 self.set_gui("normal") 3851 self.menu_View_Refresh() 3852 3853 3854 def menu_Help_About(self): 3855 application="K40 Whisperer" 3856 about = "%s Version %s\n\n" %(application,version) 3857 about = about + "By Scorch.\n" 3858 about = about + "\163\143\157\162\143\150\100\163\143\157\162" 3859 about = about + "\143\150\167\157\162\153\163\056\143\157\155\n" 3860 about = about + "https://www.scorchworks.com/\n\n" 3861 try: 3862 python_version = "%d.%d.%d" %(sys.version_info.major,sys.version_info.minor,sys.version_info.micro) 3863 except: 3864 python_version = "" 3865 about = about + "Python "+python_version+" (%d bit)" %(struct.calcsize("P") * 8) 3866 message_box("About %s" %(application),about) 3867 3868 def menu_Help_Web(self): 3869 webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40whisperer.html") 3870 3871 def menu_Help_Manual(self): 3872 webbrowser.open_new(r"https://www.scorchworks.com/K40whisperer/k40w_manual.html") 3873 3874 def KEY_F1(self, event): 3875 if self.GUI_Disabled: 3876 return 3877 self.menu_Help_About() 3878 3879 def KEY_F2(self, event): 3880 if self.GUI_Disabled: 3881 return 3882 self.GEN_Settings_Window() 3883 3884 def KEY_F3(self, event): 3885 if self.GUI_Disabled: 3886 return 3887 self.RASTER_Settings_Window() 3888 3889 def KEY_F4(self, event): 3890 if self.GUI_Disabled: 3891 return 3892 self.ROTARY_Settings_Window() 3893 self.menu_View_Refresh() 3894 3895 def KEY_F5(self, event): 3896 if self.GUI_Disabled: 3897 return 3898 self.menu_View_Refresh() 3899 3900 def KEY_F6(self, event): 3901 if self.GUI_Disabled: 3902 return 3903 self.advanced.set(not self.advanced.get()) 3904 self.menu_View_Refresh() 3905 3906 def bindConfigure(self, event): 3907 if not self.initComplete: 3908 self.initComplete = 1 3909 self.menu_Mode_Change() 3910 3911 def Master_Configure(self, event, update=0): 3912 if event.widget != self.master: 3913 return 3914 x = int(self.master.winfo_x()) 3915 y = int(self.master.winfo_y()) 3916 w = int(self.master.winfo_width()) 3917 h = int(self.master.winfo_height()) 3918 if (self.x, self.y) == (-1,-1): 3919 self.x, self.y = x,y 3920 if abs(self.w-w)>10 or abs(self.h-h)>10 or update==1: 3921 ################################################### 3922 # Form changed Size (resized) adjust as required # 3923 ################################################### 3924 self.w=w 3925 self.h=h 3926 3927 if True: 3928 # Left Column # 3929 w_label=90 3930 w_entry=48 3931 w_units=52 3932 3933 x_label_L=10 3934 x_entry_L=x_label_L+w_label+20-5 3935 x_units_L=x_entry_L+w_entry+2 3936 3937 Yloc=10 3938 self.Initialize_Button.place (x=12, y=Yloc, width=100*2, height=23) 3939 Yloc=Yloc+33 3940 3941 self.Open_Button.place (x=12, y=Yloc, width=100, height=40) 3942 self.Reload_Button.place(x=12+100, y=Yloc, width=100, height=40) 3943 if h>=560: 3944 Yloc=Yloc+50 3945 self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2) 3946 Yloc=Yloc+6 3947 self.Label_Position_Control.place(x=x_label_L, y=Yloc, width=w_label*2, height=21) 3948 3949 Yloc=Yloc+25 3950 self.Home_Button.place (x=12, y=Yloc, width=100, height=23) 3951 self.UnLock_Button.place(x=12+100, y=Yloc, width=100, height=23) 3952 3953 Yloc=Yloc+33 3954 self.Label_Step.place(x=x_label_L, y=Yloc, width=w_label, height=21) 3955 self.Label_Step_u.place(x=x_units_L, y=Yloc, width=w_units, height=21) 3956 self.Entry_Step.place(x=x_entry_L, y=Yloc, width=w_entry, height=23) 3957 3958 ########################################################################### 3959 Yloc=Yloc+30 3960 bsz=40 3961 xoffst=35 3962 self.UL_Button.place (x=xoffst+12 , y=Yloc, width=bsz, height=bsz) 3963 self.Up_Button.place (x=xoffst+12+bsz , y=Yloc, width=bsz, height=bsz) 3964 self.UR_Button.place (x=xoffst+12+bsz*2, y=Yloc, width=bsz, height=bsz) 3965 Yloc=Yloc+bsz 3966 self.Left_Button.place (x=xoffst+12 ,y=Yloc, width=bsz, height=bsz) 3967 self.CC_Button.place (x=xoffst+12+bsz ,y=Yloc, width=bsz, height=bsz) 3968 self.Right_Button.place (x=xoffst+12+bsz*2,y=Yloc, width=bsz, height=bsz) 3969 Yloc=Yloc+bsz 3970 self.LL_Button.place (x=xoffst+12 , y=Yloc, width=bsz, height=bsz) 3971 self.Down_Button.place (x=xoffst+12+bsz , y=Yloc, width=bsz, height=bsz) 3972 self.LR_Button.place (x=xoffst+12+bsz*2, y=Yloc, width=bsz, height=bsz) 3973 3974 3975 Yloc=Yloc+bsz 3976 ########################################################################### 3977 self.Label_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23) 3978 self.Label_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23) 3979 Yloc=Yloc+25 3980 self.GoTo_Button.place (x=12, y=Yloc, width=100, height=23) 3981 self.Entry_GoToX.place(x=x_entry_L, y=Yloc, width=w_entry, height=23) 3982 self.Entry_GoToY.place(x=x_units_L, y=Yloc, width=w_entry, height=23) 3983 ########################################################################### 3984 else: 3985 ########################################################################### 3986 self.separator1.place_forget() 3987 self.Label_Position_Control.place_forget() 3988 ## 3989 Yloc=Yloc+50 3990 self.separator1.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2) 3991 Yloc=Yloc+6 3992 self.Home_Button.place (x=12, y=Yloc, width=100, height=23) 3993 self.UnLock_Button.place(x=12+100, y=Yloc, width=100, height=23) 3994 ## 3995 self.Label_Step.place_forget() 3996 self.Label_Step_u.place_forget() 3997 self.Entry_Step.place_forget() 3998 self.UL_Button.place_forget() 3999 self.Up_Button.place_forget() 4000 self.UR_Button.place_forget() 4001 self.Left_Button.place_forget() 4002 self.CC_Button.place_forget() 4003 self.Right_Button.place_forget() 4004 self.LL_Button.place_forget() 4005 self.Down_Button.place_forget() 4006 self.LR_Button.place_forget() 4007 self.Label_GoToX.place_forget() 4008 self.Label_GoToY.place_forget() 4009 self.GoTo_Button.place_forget() 4010 self.Entry_GoToX.place_forget() 4011 self.Entry_GoToY.place_forget() 4012 ########################################################################### 4013 4014 #From Bottom up 4015 BUinit = self.h-70 4016 Yloc = BUinit 4017 self.Stop_Button.place (x=12, y=Yloc, width=100*2, height=30) 4018 4019 self.Stop_Button.configure(bg='light coral') 4020 Yloc=Yloc-10+10 4021 4022 wadv = 220 #200 4023 wadv_use = wadv-20 4024 Xvert_sep = 220 4025 Xadvanced = Xvert_sep+10 4026 w_label_adv= wadv-80 # 110 w_entry 4027 4028 if self.GcodeData.ecoords == []: 4029 self.Grun_Button.place_forget() 4030 self.Reng_Veng_Vcut_Button.place_forget() 4031 self.Reng_Veng_Button.place_forget() 4032 self.Veng_Vcut_Button.place_forget() 4033 4034 Yloc=Yloc-30 4035 self.Vcut_Button.place (x=12, y=Yloc, width=100, height=23) 4036 self.Entry_Vcut_feed.place (x=x_entry_L, y=Yloc, width=w_entry, height=23) 4037 self.Label_Vcut_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23) 4038 Y_Vcut=Yloc 4039 4040 Yloc=Yloc-30 4041 self.Veng_Button.place (x=12, y=Yloc, width=100, height=23) 4042 self.Entry_Veng_feed.place( x=x_entry_L, y=Yloc, width=w_entry, height=23) 4043 self.Label_Veng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23) 4044 Y_Veng=Yloc 4045 4046 Yloc=Yloc-30 4047 self.Reng_Button.place (x=12, y=Yloc, width=100, height=23) 4048 self.Entry_Reng_feed.place( x=x_entry_L, y=Yloc, width=w_entry, height=23) 4049 self.Label_Reng_feed_u.place(x=x_units_L, y=Yloc, width=w_units, height=23) 4050 Y_Reng=Yloc 4051 4052 if self.comb_vector.get() or self.comb_engrave.get(): 4053 if self.comb_engrave.get(): 4054 self.Veng_Button.place_forget() 4055 self.Reng_Button.place_forget() 4056 if self.comb_vector.get(): 4057 self.Vcut_Button.place_forget() 4058 self.Veng_Button.place_forget() 4059 4060 if self.comb_engrave.get(): 4061 if self.comb_vector.get(): 4062 self.Reng_Veng_Vcut_Button.place(x=12, y=Y_Reng, width=100, height=23*3+14) 4063 else: 4064 self.Reng_Veng_Button.place(x=12, y=Y_Reng, width=100, height=23*2+7) 4065 elif self.comb_vector.get(): 4066 self.Veng_Vcut_Button.place(x=12, y=Y_Veng, width=100, height=23*2+7) 4067 4068 4069 else: 4070 self.Vcut_Button.place_forget() 4071 self.Entry_Vcut_feed.place_forget() 4072 self.Label_Vcut_feed_u.place_forget() 4073 4074 self.Veng_Button.place_forget() 4075 self.Entry_Veng_feed.place_forget() 4076 self.Label_Veng_feed_u.place_forget() 4077 4078 self.Reng_Button.place_forget() 4079 self.Entry_Reng_feed.place_forget() 4080 self.Label_Reng_feed_u.place_forget() 4081 4082 self.Reng_Veng_Vcut_Button.place_forget() 4083 self.Reng_Veng_Button.place_forget() 4084 self.Veng_Vcut_Button.place_forget() 4085 4086 Yloc=Yloc-30 4087 self.Grun_Button.place (x=12, y=Yloc, width=100*2, height=23) 4088 4089 if h>=560: 4090 Yloc=Yloc-15 4091 self.separator2.place(x=x_label_L, y=Yloc,width=w_label+75+40, height=2) 4092 else: 4093 self.separator2.place_forget() 4094 4095 # End Left Column # 4096 4097 if self.advanced.get(): 4098 4099 self.PreviewCanvas.configure( width = self.w-240-wadv, height = self.h-50 ) 4100 self.PreviewCanvas_frame.place(x=220+wadv, y=10) 4101 self.separator_vert.place(x=220, y=10,width=2, height=self.h-50) 4102 4103 adv_Yloc=25-10 #15 4104 self.Label_Advanced_column.place(x=Xadvanced, y=adv_Yloc, width=wadv_use, height=21) 4105 adv_Yloc=adv_Yloc+25 4106 self.separator_adv.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2) 4107 4108 if h>=560: 4109 adv_Yloc=adv_Yloc+25-20 #15 4110 self.Label_Halftone_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4111 self.Checkbutton_Halftone_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4112 4113 adv_Yloc=adv_Yloc+25 4114 self.Label_Negate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4115 self.Checkbutton_Negate_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4116 4117 adv_Yloc=adv_Yloc+25 4118 self.separator_adv2.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2) 4119 4120 adv_Yloc=adv_Yloc+25-20 4121 self.Label_Mirror_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4122 self.Checkbutton_Mirror_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4123 4124 adv_Yloc=adv_Yloc+25 4125 self.Label_Rotate_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4126 self.Checkbutton_Rotate_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4127 4128 adv_Yloc=adv_Yloc+25 4129 self.Label_inputCSYS_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4130 self.Checkbutton_inputCSYS_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4131 4132 adv_Yloc=adv_Yloc+25 4133 self.separator_adv3.place(x=Xadvanced, y=adv_Yloc,width=wadv_use, height=2) 4134 4135 adv_Yloc=adv_Yloc+25-20 4136 self.Label_Inside_First_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4137 self.Checkbutton_Inside_First_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4138 4139 adv_Yloc=adv_Yloc+25 4140 self.Label_Rotary_Enable_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4141 self.Checkbutton_Rotary_Enable_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4142 else: 4143 #self.Label_Advanced_column.place_forget() 4144 #self.separator_adv.place_forget() 4145 self.Label_Halftone_adv.place_forget() 4146 self.Checkbutton_Halftone_adv.place_forget() 4147 self.Label_Negate_adv.place_forget() 4148 self.Checkbutton_Negate_adv.place_forget() 4149 self.separator_adv2.place_forget() 4150 self.Label_Mirror_adv.place_forget() 4151 self.Checkbutton_Mirror_adv.place_forget() 4152 self.Label_Rotate_adv.place_forget() 4153 self.Checkbutton_Rotate_adv.place_forget() 4154 self.Label_inputCSYS_adv.place_forget() 4155 self.Checkbutton_inputCSYS_adv.place_forget() 4156 self.separator_adv3.place_forget() 4157 self.Label_Inside_First_adv.place_forget() 4158 self.Checkbutton_Inside_First_adv.place_forget() 4159 self.Label_Rotary_Enable_adv.place_forget() 4160 self.Checkbutton_Rotary_Enable_adv.place_forget() 4161 4162 adv_Yloc = BUinit 4163 self.Hide_Adv_Button.place (x=Xadvanced, y=adv_Yloc, width=wadv_use, height=30) 4164 4165 if self.RengData.image != None: 4166 self.Label_inputCSYS_adv.configure(state="disabled") 4167 self.Checkbutton_inputCSYS_adv.place_forget() 4168 else: 4169 self.Label_inputCSYS_adv.configure(state="normal") 4170 4171 if self.GcodeData.ecoords == []: 4172 #adv_Yloc = adv_Yloc-40 4173 self.Label_Vcut_passes.place(x=Xadvanced, y=Y_Vcut, width=w_label_adv, height=21) 4174 self.Entry_Vcut_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Vcut, width=w_entry, height=23) 4175 4176 #adv_Yloc=adv_Yloc-30 4177 self.Label_Veng_passes.place(x=Xadvanced, y=Y_Veng, width=w_label_adv, height=21) 4178 self.Entry_Veng_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Veng, width=w_entry, height=23) 4179 4180 #adv_Yloc=adv_Yloc-30 4181 self.Label_Reng_passes.place(x=Xadvanced, y=Y_Reng, width=w_label_adv, height=21) 4182 self.Entry_Reng_passes.place(x=Xadvanced+w_label_adv+2, y=Y_Reng, width=w_entry, height=23) 4183 self.Label_Gcde_passes.place_forget() 4184 self.Entry_Gcde_passes.place_forget() 4185 adv_Yloc = Y_Reng 4186 4187 #### 4188 adv_Yloc=adv_Yloc-15 4189 self.separator_comb.place(x=Xadvanced-1, y=adv_Yloc, width=wadv_use, height=2) 4190 4191 adv_Yloc=adv_Yloc-25 4192 self.Label_Comb_Vector_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4193 self.Checkbutton_Comb_Vector_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4194 4195 adv_Yloc=adv_Yloc-25 4196 self.Label_Comb_Engrave_adv.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4197 self.Checkbutton_Comb_Engrave_adv.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=25, height=23) 4198 #### 4199 4200 else: 4201 adv_Yloc=adv_Yloc-40 4202 self.Label_Gcde_passes.place(x=Xadvanced, y=adv_Yloc, width=w_label_adv, height=21) 4203 self.Entry_Gcde_passes.place(x=Xadvanced+w_label_adv+2, y=adv_Yloc, width=w_entry, height=23) 4204 self.Label_Vcut_passes.place_forget() 4205 self.Entry_Vcut_passes.place_forget() 4206 self.Label_Veng_passes.place_forget() 4207 self.Entry_Veng_passes.place_forget() 4208 self.Label_Reng_passes.place_forget() 4209 self.Entry_Reng_passes.place_forget() 4210 4211 else: 4212 self.PreviewCanvas_frame.place_forget() 4213 self.separator_vert.place_forget() 4214 self.Label_Advanced_column.place_forget() 4215 self.separator_adv.place_forget() 4216 self.Label_Halftone_adv.place_forget() 4217 self.Checkbutton_Halftone_adv.place_forget() 4218 self.Label_Negate_adv.place_forget() 4219 self.Checkbutton_Negate_adv.place_forget() 4220 self.separator_adv2.place_forget() 4221 self.Label_Mirror_adv.place_forget() 4222 self.Checkbutton_Mirror_adv.place_forget() 4223 self.Label_Rotate_adv.place_forget() 4224 self.Checkbutton_Rotate_adv.place_forget() 4225 self.Label_inputCSYS_adv.place_forget() 4226 self.Checkbutton_inputCSYS_adv.place_forget() 4227 self.separator_adv3.place_forget() 4228 self.Label_Inside_First_adv.place_forget() 4229 self.Checkbutton_Inside_First_adv.place_forget() 4230 4231 self.Label_Rotary_Enable_adv.place_forget() 4232 self.Checkbutton_Rotary_Enable_adv.place_forget() 4233 4234 self.separator_comb.place_forget() 4235 self.Label_Comb_Engrave_adv.place_forget() 4236 self.Checkbutton_Comb_Engrave_adv.place_forget() 4237 self.Label_Comb_Vector_adv.place_forget() 4238 self.Checkbutton_Comb_Vector_adv.place_forget() 4239 4240 4241 self.Entry_Vcut_passes.place_forget() 4242 self.Label_Vcut_passes.place_forget() 4243 self.Entry_Veng_passes.place_forget() 4244 self.Label_Veng_passes.place_forget() 4245 self.Entry_Reng_passes.place_forget() 4246 self.Label_Reng_passes.place_forget() 4247 self.Label_Gcde_passes.place_forget() 4248 self.Entry_Gcde_passes.place_forget() 4249 self.Hide_Adv_Button.place_forget() 4250 4251 self.PreviewCanvas.configure( width = self.w-240, height = self.h-50 ) 4252 self.PreviewCanvas_frame.place(x=Xvert_sep, y=10) 4253 self.separator_vert.place_forget() 4254 4255 self.Set_Input_States() 4256 4257 self.Plot_Data() 4258 4259 def Recalculate_RQD_Click(self, event): 4260 self.menu_View_Refresh() 4261 4262 def Set_Input_States(self): 4263 pass 4264 4265 def Set_Input_States_Event(self,event): 4266 self.Set_Input_States() 4267 4268 def Set_Input_States_RASTER(self,event=None): 4269 if self.halftone.get(): 4270 self.Label_Halftone_DPI.configure(state="normal") 4271 self.Halftone_DPI_OptionMenu.configure(state="normal") 4272 self.Label_Halftone_u.configure(state="normal") 4273 self.Label_bezier_M1.configure(state="normal") 4274 self.bezier_M1_Slider.configure(state="normal") 4275 self.Label_bezier_M2.configure(state="normal") 4276 self.bezier_M2_Slider.configure(state="normal") 4277 self.Label_bezier_weight.configure(state="normal") 4278 self.bezier_weight_Slider.configure(state="normal") 4279 else: 4280 self.Label_Halftone_DPI.configure(state="disabled") 4281 self.Halftone_DPI_OptionMenu.configure(state="disabled") 4282 self.Label_Halftone_u.configure(state="disabled") 4283 self.Label_bezier_M1.configure(state="disabled") 4284 self.bezier_M1_Slider.configure(state="disabled") 4285 self.Label_bezier_M2.configure(state="disabled") 4286 self.bezier_M2_Slider.configure(state="disabled") 4287 self.Label_bezier_weight.configure(state="disabled") 4288 self.bezier_weight_Slider.configure(state="disabled") 4289 4290 def Set_Input_States_BATCH(self): 4291 if self.post_exec.get(): 4292 self.Entry_Batch_Path.configure(state="normal") 4293 else: 4294 self.Entry_Batch_Path.configure(state="disabled") 4295## def Set_Input_States_Unsharp(self,event=None): 4296## if self.unsharp_flag.get(): 4297## self.Label_Unsharp_Radius.configure(state="normal") 4298## self.Label_Unsharp_Radius_u.configure(state="normal") 4299## self.Entry_Unsharp_Radius.configure(state="normal") 4300## self.Label_Unsharp_Percent.configure(state="normal") 4301## self.Label_Unsharp_Percent_u.configure(state="normal") 4302## self.Entry_Unsharp_Percent.configure(state="normal") 4303## self.Label_Unsharp_Threshold.configure(state="normal") 4304## self.Entry_Unsharp_Threshold.configure(state="normal") 4305## 4306## else: 4307## self.Label_Unsharp_Radius.configure(state="disabled") 4308## self.Label_Unsharp_Radius_u.configure(state="disabled") 4309## self.Entry_Unsharp_Radius.configure(state="disabled") 4310## self.Label_Unsharp_Percent.configure(state="disabled") 4311## self.Label_Unsharp_Percent_u.configure(state="disabled") 4312## self.Entry_Unsharp_Percent.configure(state="disabled") 4313## self.Label_Unsharp_Threshold.configure(state="disabled") 4314## self.Entry_Unsharp_Threshold.configure(state="disabled") 4315 4316 def Set_Input_States_Rotary(self,event=None): 4317 if self.rotary.get(): 4318 self.Label_Laser_R_Scale.configure(state="normal") 4319 self.Entry_Laser_R_Scale.configure(state="normal") 4320 self.Label_Laser_Rapid_Feed.configure(state="normal") 4321 self.Label_Laser_Rapid_Feed_u.configure(state="normal") 4322 self.Entry_Laser_Rapid_Feed.configure(state="normal") 4323 else: 4324 self.Label_Laser_R_Scale.configure(state="disabled") 4325 self.Entry_Laser_R_Scale.configure(state="disabled") 4326 self.Label_Laser_Rapid_Feed.configure(state="disabled") 4327 self.Label_Laser_Rapid_Feed_u.configure(state="disabled") 4328 self.Entry_Laser_Rapid_Feed.configure(state="disabled") 4329 4330# def Set_Input_States_RASTER_Event(self,event): 4331# self.Set_Input_States_RASTER() 4332 4333 def Imaging_Free(self,image_in,bg="#ffffff"): 4334 image_in = image_in.convert('L') 4335 wim,him = image_in.size 4336 image_out=PhotoImage(width=wim,height=him) 4337 pixel=image_in.load() 4338 if bg!=None: 4339 image_out.put(bg, to=(0,0,wim,him)) 4340 for y in range(0,him): 4341 for x in range(0,wim): 4342 val=pixel[x,y] 4343 if val!=255: 4344 image_out.put("#%02x%02x%02x" %(val,val,val),(x,y)) 4345 return image_out 4346 4347 ########################################## 4348 # CANVAS PLOTTING STUFF # 4349 ########################################## 4350 def Plot_Data(self): 4351 self.PreviewCanvas.delete(ALL) 4352 self.calc_button.place_forget() 4353 4354 for seg in self.segID: 4355 self.PreviewCanvas.delete(seg) 4356 self.segID = [] 4357 4358 cszw = int(self.PreviewCanvas.cget("width")) 4359 cszh = int(self.PreviewCanvas.cget("height")) 4360 buff=10 4361 wc = float(cszw/2) 4362 hc = float(cszh/2) 4363 4364 maxx = float(self.LaserXsize.get()) / self.units_scale 4365 minx = 0.0 4366 maxy = 0.0 4367 miny = -float(self.LaserYsize.get()) / self.units_scale 4368 midx=(maxx+minx)/2 4369 midy=(maxy+miny)/2 4370 4371 4372 if self.inputCSYS.get() and self.RengData.image == None: 4373 xmin,xmax,ymin,ymax = 0.0,0.0,0.0,0.0 4374 else: 4375 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 4376 4377 if (self.HomeUR.get()): 4378 XlineShift = maxx - self.laserX - (xmax-xmin) 4379 else: 4380 XlineShift = self.laserX 4381 YlineShift = self.laserY 4382 4383 if min((xmax-xmin),(ymax-ymin)) > 0 and self.zoom2image.get(): 4384 self.PlotScale = max((xmax-xmin)/(cszw-buff), (ymax-ymin)/(cszh-buff)) 4385 x_lft = minx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2 4386 x_rgt = maxx / self.PlotScale - self.laserX / self.PlotScale + (cszw-(xmax-xmin)/self.PlotScale)/2 4387 y_bot = -miny / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2 4388 y_top = -maxy / self.PlotScale + self.laserY / self.PlotScale + (cszh-(ymax-ymin)/self.PlotScale)/2 4389 self.segID.append( self.PreviewCanvas.create_rectangle( 4390 x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) ) 4391 else: 4392 self.PlotScale = max((maxx-minx)/(cszw-buff), (maxy-miny)/(cszh-buff)) 4393 x_lft = cszw/2 + (minx-midx) / self.PlotScale 4394 x_rgt = cszw/2 + (maxx-midx) / self.PlotScale 4395 y_bot = cszh/2 + (maxy-midy) / self.PlotScale 4396 y_top = cszh/2 + (miny-midy) / self.PlotScale 4397 self.segID.append( self.PreviewCanvas.create_rectangle( 4398 x_lft, y_bot, x_rgt, y_top, fill="gray80", outline="gray80", width = 0) ) 4399 4400 4401 ###################################### 4402 ### Plot Raster Image ### 4403 ###################################### 4404 if self.RengData.image != None: 4405 if self.include_Reng.get(): 4406 try: 4407 new_SCALE = (1.0/self.PlotScale)/self.input_dpi 4408 if new_SCALE != self.SCALE: 4409 self.SCALE = new_SCALE 4410 nw=int(self.SCALE*self.wim) 4411 nh=int(self.SCALE*self.him) 4412 4413 plot_im = self.RengData.image.convert("L") 4414## if self.unsharp_flag.get(): 4415## from PIL import ImageFilter 4416## filter = ImageFilter.UnsharpMask() 4417## filter.radius = float(self.unsharp_r.get()) 4418## filter.percent = int(float(self.unsharp_p.get())) 4419## filter.threshold = int(float(self.unsharp_t.get())) 4420## plot_im = plot_im.filter(filter) 4421 4422 if self.negate.get(): 4423 plot_im = ImageOps.invert(plot_im) 4424 4425 if self.halftone.get() == False: 4426 plot_im = plot_im.point(lambda x: 0 if x<128 else 255, '1') 4427 plot_im = plot_im.convert("L") 4428 4429 if self.mirror.get(): 4430 plot_im = ImageOps.mirror(plot_im) 4431 4432 if self.rotate.get(): 4433 plot_im = plot_im.rotate(90,expand=True) 4434 nh=int(self.SCALE*self.wim) 4435 nw=int(self.SCALE*self.him) 4436 4437 try: 4438 self.UI_image = ImageTk.PhotoImage(plot_im.resize((nw,nh), Image.ANTIALIAS)) 4439 except: 4440 debug_message("Imaging_Free Used.") 4441 self.UI_image = self.Imaging_Free(plot_im.resize((nw,nh), Image.ANTIALIAS)) 4442 except: 4443 self.SCALE = 1 4444 debug_message(traceback.format_exc()) 4445 4446 self.Plot_Raster(self.laserX+.001, self.laserY-.001, x_lft,y_top,self.PlotScale,im=self.UI_image) 4447 else: 4448 self.UI_image = None 4449 4450 4451 ###################################### 4452 ### Plot Reng Coords ### 4453 ###################################### 4454 if self.include_Rpth.get() and self.RengData.ecoords!=[]: 4455 loop_old = -1 4456 4457 ##### 4458 Xscale = 1/float(self.LaserXscale.get()) 4459 Yscale = 1/float(self.LaserYscale.get()) 4460 if self.rotary.get(): 4461 Rscale = 1/float(self.LaserRscale.get()) 4462 Yscale = Yscale*Rscale 4463 ###### 4464 4465 for line in self.RengData.ecoords: 4466 XY = line 4467 x1 = XY[0]*Xscale 4468 y1 = XY[1]*Yscale-ymax 4469 loop = XY[2] 4470 color = "black" 4471 # check and see if we need to move to a new discontinuous start point 4472 if (loop == loop_old): 4473 self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, color) 4474 loop_old = loop 4475 xold=x1 4476 yold=y1 4477 4478 4479 ###################################### 4480 ### Plot Veng Coords ### 4481 ###################################### 4482 if self.include_Veng.get(): 4483 loop_old = -1 4484 4485 4486 plot_coords = self.VengData.ecoords 4487 if self.mirror.get() or self.rotate.get(): 4488 plot_coords = self.mirror_rotate_vector_coords(plot_coords) 4489 4490 for line in plot_coords: 4491 XY = line 4492 x1 = (XY[0]-xmin) 4493 y1 = (XY[1]-ymax) 4494 loop = XY[2] 4495 # check and see if we need to move to a new discontinuous start point 4496 if (loop == loop_old): 4497 self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "blue") 4498 loop_old = loop 4499 xold=x1 4500 yold=y1 4501 4502 ###################################### 4503 ### Plot Vcut Coords ### 4504 ###################################### 4505 if self.include_Vcut.get(): 4506 loop_old = -1 4507 4508 plot_coords = self.VcutData.ecoords 4509 if self.mirror.get() or self.rotate.get(): 4510 plot_coords = self.mirror_rotate_vector_coords(plot_coords) 4511 4512 for line in plot_coords: 4513 XY = line 4514 x1 = (XY[0]-xmin) 4515 y1 = (XY[1]-ymax) 4516 loop = XY[2] 4517 # check and see if we need to move to a new discontinuous start point 4518 if (loop == loop_old): 4519 self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "red") 4520 loop_old = loop 4521 xold=x1 4522 yold=y1 4523 4524 ###################################### 4525 ### Plot Gcode Coords ### 4526 ###################################### 4527 if self.include_Gcde.get(): 4528 loop_old = -1 4529 scale=1 4530 4531 plot_coords = self.GcodeData.ecoords 4532 if self.mirror.get() or self.rotate.get(): 4533 plot_coords = self.mirror_rotate_vector_coords(plot_coords) 4534 4535 for line in plot_coords: 4536 XY = line 4537 x1 = (XY[0]-xmin)*scale 4538 y1 = (XY[1]-ymax)*scale 4539 4540 loop = XY[2] 4541 # check and see if we need to move to a new discontinuous start point 4542 if (loop == loop_old): 4543 self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, self.PlotScale, "white") 4544 loop_old = loop 4545 xold=x1 4546 yold=y1 4547 4548 4549 ###################################### 4550 ### Plot Trace Coords ### 4551 ###################################### 4552 if self.trace_window.winfo_exists(): # or DEBUG: 4553 ##### 4554 Xscale = 1/float(self.LaserXscale.get()) 4555 Yscale = 1/float(self.LaserYscale.get()) 4556 if self.rotary.get(): 4557 Rscale = 1/float(self.LaserRscale.get()) 4558 Yscale = Yscale*Rscale 4559 ###### 4560 trace_coords = self.make_trace_path() 4561 for i in range(len(trace_coords)): 4562 trace_coords[i]=[trace_coords[i][0]*Xscale,trace_coords[i][1]*Yscale,trace_coords[i][2]] 4563 4564 for line in trace_coords: 4565 XY = line 4566 x1 = (XY[0]-xmin)*scale 4567 y1 = (XY[1]-ymax)*scale 4568 loop = XY[2] 4569 # check and see if we need to move to a new discontinuous start point 4570 if (loop == loop_old): 4571 green = "#%02x%02x%02x" % (0, 200, 0) 4572 self.Plot_Line(xold, yold, x1, y1, x_lft, y_top, XlineShift, YlineShift, 4573 self.PlotScale, green, thick=2,tag_value=('LaserTag', 'trace')) 4574 loop_old = loop 4575 xold=x1 4576 yold=y1 4577 4578 4579 ###################################### 4580 self.refreshTime() 4581 dot_col = "grey50" 4582 xoff = self.pos_offset[0]/1000.0 4583 yoff = self.pos_offset[1]/1000.0 4584 4585 if abs(self.pos_offset[0])+abs(self.pos_offset[1]) > 0: 4586 head_offset=True 4587 else: 4588 head_offset=False 4589 4590 self.Plot_circle(self.laserX+xoff,self.laserY+yoff,x_lft,y_top,self.PlotScale,dot_col,radius=5,cross_hair=head_offset) 4591 4592 def Plot_Raster(self, XX, YY, Xleft, Ytop, PlotScale, im): 4593 if (self.HomeUR.get()): 4594 maxx = float(self.LaserXsize.get()) / self.units_scale 4595 xmin,xmax,ymin,ymax = self.Get_Design_Bounds() 4596 xplt = Xleft + ( maxx-XX-(xmax-xmin) )/PlotScale 4597 else: 4598 xplt = Xleft + XX/PlotScale 4599 4600 yplt = Ytop - YY/PlotScale 4601 self.segID.append( 4602 self.PreviewCanvas.create_image(xplt, yplt, anchor=NW, image=self.UI_image,tags='LaserTag') 4603 ) 4604 4605 4606 def offset_eccords(self,ecoords_in,offset_val): 4607 if not PYCLIPPER: 4608 return ecoords_in 4609 4610 loop_num = ecoords_in[0][2] 4611 pco = pyclipper.PyclipperOffset() 4612 ecoords_out=[] 4613 pyclip_path = [] 4614 for i in range(0,len(ecoords_in)): 4615 pyclip_path.append([ecoords_in[i][0]*1000,ecoords_in[i][1]*1000]) 4616 4617 pco.AddPath(pyclip_path, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON) 4618 try: 4619 plot_coords = pco.Execute(offset_val*1000.0)[0] 4620 plot_coords.append(plot_coords[0]) 4621 except: 4622 plot_coords=[] 4623 4624 for i in range(0,len(plot_coords)): 4625 ecoords_out.append([plot_coords[i][0]/1000.0,plot_coords[i][1]/1000.0,loop_num]) 4626 return ecoords_out 4627 4628 4629 def Plot_circle(self, XX, YY, Xleft, Ytop, PlotScale, col, radius=0, cross_hair=False): 4630 circle_tags = ('LaserTag','LaserDot') 4631 if (self.HomeUR.get()): 4632 maxx = float(self.LaserXsize.get()) / self.units_scale 4633 xplt = Xleft + maxx/PlotScale - XX/PlotScale 4634 else: 4635 xplt = Xleft + XX/PlotScale 4636 yplt = Ytop - YY/PlotScale 4637 4638 4639 if cross_hair: 4640 radius=radius*2 4641 leg = int(radius*.707) 4642 self.segID.append( 4643 self.PreviewCanvas.create_polygon( 4644 xplt-radius, 4645 yplt, 4646 xplt-leg, 4647 yplt+leg, 4648 xplt, 4649 yplt+radius, 4650 xplt+leg, 4651 yplt+leg, 4652 xplt+radius, 4653 yplt, 4654 xplt+leg, 4655 yplt-leg, 4656 xplt, 4657 yplt-radius, 4658 xplt-leg, 4659 yplt-leg, 4660 fill=col, outline=col, width = 1, stipple='gray12',tags=circle_tags )) 4661 4662 self.segID.append( 4663 self.PreviewCanvas.create_line( xplt-radius, 4664 yplt, 4665 xplt+radius, 4666 yplt, 4667 fill=col, capstyle="round", width = 1, tags=circle_tags )) 4668 self.segID.append( 4669 self.PreviewCanvas.create_line( xplt, 4670 yplt-radius, 4671 xplt, 4672 yplt+radius, 4673 fill=col, capstyle="round", width = 1, tags=circle_tags )) 4674 else: 4675 self.segID.append( 4676 self.PreviewCanvas.create_oval( 4677 xplt-radius, 4678 yplt-radius, 4679 xplt+radius, 4680 yplt+radius, 4681 fill=col, outline=col, width = 0, stipple='gray50',tags=circle_tags )) 4682 4683 4684 def Plot_Line(self, XX1, YY1, XX2, YY2, Xleft, Ytop, XlineShift, YlineShift, PlotScale, col, thick=0, tag_value='LaserTag'): 4685 xplt1 = Xleft + (XX1 + XlineShift )/PlotScale 4686 xplt2 = Xleft + (XX2 + XlineShift )/PlotScale 4687 yplt1 = Ytop - (YY1 + YlineShift )/PlotScale 4688 yplt2 = Ytop - (YY2 + YlineShift )/PlotScale 4689 4690 self.segID.append( 4691 self.PreviewCanvas.create_line( xplt1, 4692 yplt1, 4693 xplt2, 4694 yplt2, 4695 fill=col, capstyle="round", width = thick, tags=tag_value) ) 4696 4697 ################################################################################ 4698 # Temporary Move Window # 4699 ################################################################################ 4700 def move_head_window_temporary(self,new_pos_offset): 4701 if self.GUI_Disabled: 4702 return 4703 dx_inches = round(new_pos_offset[0]/1000.0,3) 4704 dy_inches = round(new_pos_offset[1]/1000.0,3) 4705 Xnew,Ynew = self.XY_in_bounds(dx_inches,dy_inches,no_size=True) 4706 4707 pos_offset_X = round((Xnew-self.laserX)*1000.0) 4708 pos_offset_Y = round((Ynew-self.laserY)*1000.0) 4709 new_pos_offset = [pos_offset_X,pos_offset_Y] 4710 4711 if self.inputCSYS.get() and self.RengData.image == None: 4712 new_pos_offset = [0,0] 4713 xdist = -self.pos_offset[0] 4714 ydist = -self.pos_offset[1] 4715 else: 4716 xdist = -self.pos_offset[0] + new_pos_offset[0] 4717 ydist = -self.pos_offset[1] + new_pos_offset[1] 4718 4719 if self.k40 != None: 4720 if self.Send_Rapid_Move( xdist,ydist ): 4721 self.pos_offset = new_pos_offset 4722 self.menu_View_Refresh() 4723 else: 4724 self.pos_offset = new_pos_offset 4725 self.menu_View_Refresh() 4726 4727 ################################################################################ 4728 # General Settings Window # 4729 ################################################################################ 4730 def GEN_Settings_Window(self): 4731 gen_width = 560 4732 gen_settings = Toplevel(width=gen_width, height=560) #460+75) 4733 gen_settings.grab_set() # Use grab_set to prevent user input in the main window 4734 gen_settings.focus_set() 4735 gen_settings.resizable(0,0) 4736 gen_settings.title('General Settings') 4737 gen_settings.iconname("General Settings") 4738 4739 D_Yloc = 6 4740 D_dY = 26 4741 xd_label_L = 12 4742 4743 w_label=150 4744 w_entry=40 4745 w_units=45 4746 xd_entry_L=xd_label_L+w_label+10 4747 xd_units_L=xd_entry_L+w_entry+5 4748 sep_border=10 4749 4750 #Radio Button 4751 D_Yloc=D_Yloc+D_dY 4752 self.Label_Units = Label(gen_settings,text="Units") 4753 self.Label_Units.place(x=xd_label_L, y=D_Yloc, width=113, height=21) 4754 self.Radio_Units_IN = Radiobutton(gen_settings,text="inch", value="in", 4755 width="100", anchor=W) 4756 self.Radio_Units_IN.place(x=w_label+22, y=D_Yloc, width=75, height=23) 4757 self.Radio_Units_IN.configure(variable=self.units, command=self.Entry_units_var_Callback ) 4758 self.Radio_Units_MM = Radiobutton(gen_settings,text="mm", value="mm", 4759 width="100", anchor=W) 4760 self.Radio_Units_MM.place(x=w_label+110, y=D_Yloc, width=75, height=23) 4761 self.Radio_Units_MM.configure(variable=self.units, command=self.Entry_units_var_Callback ) 4762 4763 D_Yloc=D_Yloc+D_dY 4764 self.Label_init_home = Label(gen_settings,text="Home Upon Initialize") 4765 self.Label_init_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4766 self.Checkbutton_init_home = Checkbutton(gen_settings,text="", anchor=W) 4767 self.Checkbutton_init_home.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 4768 self.Checkbutton_init_home.configure(variable=self.init_home) 4769 4770 4771 D_Yloc=D_Yloc+D_dY 4772 self.Label_post_home = Label(gen_settings,text="After Job Finishes:") 4773 self.Label_post_home.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4774 4775 Xoption_width = 120 4776 Xoption_col1 = xd_entry_L 4777 Xoption_col2 = xd_entry_L+Xoption_width 4778 Xoption_col3 = xd_entry_L+Xoption_width*2 4779 4780 self.Checkbutton_post_home = Checkbutton(gen_settings,text="Unlock Rail", anchor=W) 4781 self.Checkbutton_post_home.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23) 4782 self.Checkbutton_post_home.configure(variable=self.post_home) 4783 4784 self.Checkbutton_post_beep = Checkbutton(gen_settings,text="Beep", anchor=W) 4785 self.Checkbutton_post_beep.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23) 4786 self.Checkbutton_post_beep.configure(variable=self.post_beep) 4787 4788 D_Yloc=D_Yloc+D_dY 4789 self.Checkbutton_post_disp = Checkbutton(gen_settings,text="Popup Report", anchor=W) 4790 self.Checkbutton_post_disp.place(x=Xoption_col1, y=D_Yloc, width=Xoption_width, height=23) 4791 self.Checkbutton_post_disp.configure(variable=self.post_disp) 4792 4793 self.Checkbutton_post_exec = Checkbutton(gen_settings,text="Run Batch File:", anchor=W, command=self.Set_Input_States_BATCH) 4794 self.Checkbutton_post_exec.place(x=Xoption_col2, y=D_Yloc, width=Xoption_width, height=23) 4795 self.Checkbutton_post_exec.configure(variable=self.post_exec) 4796 4797 4798 self.Entry_Batch_Path = Entry(gen_settings) 4799 self.Entry_Batch_Path.place(x=Xoption_col3, y=D_Yloc, width=Xoption_width, height=23) 4800 self.Entry_Batch_Path.configure(textvariable=self.batch_path) 4801 4802 4803 D_Yloc=D_Yloc+D_dY 4804 self.Label_Preprocess_CRC = Label(gen_settings,text="Preprocess CRC Data") 4805 self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4806 self.Checkbutton_Preprocess_CRC = Checkbutton(gen_settings,text="", anchor=W) 4807 self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 4808 self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc) 4809 4810 #D_Yloc=D_Yloc+D_dY 4811 #self.Label_Timeout = Label(gen_settings,text="USB Timeout") 4812 #self.Label_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4813 #self.Label_Timeout_u = Label(gen_settings,text="ms", anchor=W) 4814 #self.Label_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 4815 #self.Entry_Timeout = Entry(gen_settings,width="15") 4816 #self.Entry_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4817 #self.Entry_Timeout.configure(textvariable=self.t_timeout) 4818 #self.t_timeout.trace_variable("w", self.Entry_Timeout_Callback) 4819 #self.entry_set(self.Entry_Timeout,self.Entry_Timeout_Check(),2) 4820 4821 #D_Yloc=D_Yloc+D_dY 4822 #self.Label_N_Timeouts = Label(gen_settings,text="Number of Timeouts") 4823 #self.Label_N_Timeouts.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4824 #self.Entry_N_Timeouts = Entry(gen_settings,width="15") 4825 #self.Entry_N_Timeouts.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4826 #self.Entry_N_Timeouts.configure(textvariable=self.n_timeouts) 4827 #self.n_timeouts.trace_variable("w", self.Entry_N_Timeouts_Callback) 4828 #self.entry_set(self.Entry_N_Timeouts,self.Entry_N_Timeouts_Check(),2) 4829 4830 D_Yloc=D_Yloc+D_dY*1.25 4831 self.gen_separator1 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN) 4832 self.gen_separator1.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2) 4833 4834 D_Yloc=D_Yloc+D_dY*.25 4835 self.Label_Inkscape_title = Label(gen_settings,text="Inkscape Options") 4836 self.Label_Inkscape_title.place(x=xd_label_L, y=D_Yloc, width=gen_width-40, height=21) 4837 4838 D_Yloc=D_Yloc+D_dY 4839 font_entry_width=215 4840 self.Label_Inkscape_Path = Label(gen_settings,text="Inkscape Executable") 4841 self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4842 self.Entry_Inkscape_Path = Entry(gen_settings,width="15") 4843 self.Entry_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=font_entry_width, height=23) 4844 self.Entry_Inkscape_Path.configure(textvariable=self.inkscape_path) 4845 self.Entry_Inkscape_Path.bind('<FocusIn>', self.Inkscape_Path_Message) 4846 self.Inkscape_Path = Button(gen_settings,text="Find Inkscape") 4847 self.Inkscape_Path.place(x=xd_entry_L+font_entry_width+10, y=D_Yloc, width=110, height=23) 4848 self.Inkscape_Path.bind("<ButtonRelease-1>", self.Inkscape_Path_Click) 4849 4850 D_Yloc=D_Yloc+D_dY 4851 self.Label_Ink_Timeout = Label(gen_settings,text="Inkscape Timeout") 4852 self.Label_Ink_Timeout.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4853 self.Label_Ink_Timeout_u = Label(gen_settings,text="minutes", anchor=W) 4854 self.Label_Ink_Timeout_u.place(x=xd_units_L, y=D_Yloc, width=w_units*2, height=21) 4855 self.Entry_Ink_Timeout = Entry(gen_settings,width="15") 4856 self.Entry_Ink_Timeout.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4857 self.Entry_Ink_Timeout.configure(textvariable=self.ink_timeout) 4858 self.ink_timeout.trace_variable("w", self.Entry_Ink_Timeout_Callback) 4859 self.entry_set(self.Entry_Ink_Timeout,self.Entry_Ink_Timeout_Check(),2) 4860 4861 D_Yloc=D_Yloc+D_dY*1.25 4862 self.gen_separator2 = Frame(gen_settings, height=2, bd=1, relief=SUNKEN) 4863 self.gen_separator2.place(x=xd_label_L, y=D_Yloc,width=gen_width-40, height=2) 4864 4865 D_Yloc=D_Yloc+D_dY*.5 4866 self.Label_no_com = Label(gen_settings,text="Home in Upper Right") 4867 self.Label_no_com.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4868 self.Checkbutton_no_com = Checkbutton(gen_settings,text="", anchor=W) 4869 self.Checkbutton_no_com.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 4870 self.Checkbutton_no_com.configure(variable=self.HomeUR) 4871 self.HomeUR.trace_variable("w",self.menu_View_Refresh_Callback) 4872 4873 D_Yloc=D_Yloc+D_dY 4874 self.Label_Board_Name = Label(gen_settings,text="Board Name", anchor=CENTER ) 4875 self.Board_Name_OptionMenu = OptionMenu(gen_settings, self.board_name, 4876 "LASER-M2", 4877 "LASER-M1", 4878 "LASER-M", 4879 "LASER-B2", 4880 "LASER-B1", 4881 "LASER-B", 4882 "LASER-A") 4883 self.Label_Board_Name.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4884 self.Board_Name_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry*3, height=23) 4885 4886 D_Yloc=D_Yloc+D_dY 4887 self.Label_Laser_Area_Width = Label(gen_settings,text="Laser Area Width") 4888 self.Label_Laser_Area_Width.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4889 self.Label_Laser_Area_Width_u = Label(gen_settings,textvariable=self.units, anchor=W) 4890 self.Label_Laser_Area_Width_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 4891 self.Entry_Laser_Area_Width = Entry(gen_settings,width="15") 4892 self.Entry_Laser_Area_Width.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4893 self.Entry_Laser_Area_Width.configure(textvariable=self.LaserXsize) 4894 self.LaserXsize.trace_variable("w", self.Entry_Laser_Area_Width_Callback) 4895 self.entry_set(self.Entry_Laser_Area_Width,self.Entry_Laser_Area_Width_Check(),2) 4896 4897 D_Yloc=D_Yloc+D_dY 4898 self.Label_Laser_Area_Height = Label(gen_settings,text="Laser Area Height") 4899 self.Label_Laser_Area_Height.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4900 self.Label_Laser_Area_Height_u = Label(gen_settings,textvariable=self.units, anchor=W) 4901 self.Label_Laser_Area_Height_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 4902 self.Entry_Laser_Area_Height = Entry(gen_settings,width="15") 4903 self.Entry_Laser_Area_Height.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4904 self.Entry_Laser_Area_Height.configure(textvariable=self.LaserYsize) 4905 self.LaserYsize.trace_variable("w", self.Entry_Laser_Area_Height_Callback) 4906 self.entry_set(self.Entry_Laser_Area_Height,self.Entry_Laser_Area_Height_Check(),2) 4907 4908 D_Yloc=D_Yloc+D_dY 4909 self.Label_Laser_X_Scale = Label(gen_settings,text="X Scale Factor") 4910 self.Label_Laser_X_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4911 self.Entry_Laser_X_Scale = Entry(gen_settings,width="15") 4912 self.Entry_Laser_X_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4913 self.Entry_Laser_X_Scale.configure(textvariable=self.LaserXscale) 4914 self.LaserXscale.trace_variable("w", self.Entry_Laser_X_Scale_Callback) 4915 self.entry_set(self.Entry_Laser_X_Scale,self.Entry_Laser_X_Scale_Check(),2) 4916 4917 D_Yloc=D_Yloc+D_dY 4918 self.Label_Laser_Y_Scale = Label(gen_settings,text="Y Scale Factor") 4919 self.Label_Laser_Y_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4920 self.Entry_Laser_Y_Scale = Entry(gen_settings,width="15") 4921 self.Entry_Laser_Y_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4922 self.Entry_Laser_Y_Scale.configure(textvariable=self.LaserYscale) 4923 self.LaserYscale.trace_variable("w", self.Entry_Laser_Y_Scale_Callback) 4924 self.entry_set(self.Entry_Laser_Y_Scale,self.Entry_Laser_Y_Scale_Check(),2) 4925 4926 D_Yloc=D_Yloc+D_dY+10 4927 self.Label_SaveConfig = Label(gen_settings,text="Configuration File") 4928 self.Label_SaveConfig.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4929 4930 self.GEN_SaveConfig = Button(gen_settings,text="Save") 4931 self.GEN_SaveConfig.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=21, anchor="nw") 4932 self.GEN_SaveConfig.bind("<ButtonRelease-1>", self.Write_Config_File) 4933 4934 ## Buttons ## 4935 gen_settings.update_idletasks() 4936 Ybut=int(gen_settings.winfo_height())-30 4937 Xbut=int(gen_settings.winfo_width()/2) 4938 4939 self.GEN_Close = Button(gen_settings,text="Close") 4940 self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center") 4941 self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click) 4942 4943 self.Set_Input_States_BATCH() 4944 4945 ################################################################################ 4946 # Raster Settings Window # 4947 ################################################################################ 4948 def RASTER_Settings_Window(self): 4949 Wset=425+280 4950 Hset=330 #260 4951 raster_settings = Toplevel(width=Wset, height=Hset) 4952 raster_settings.grab_set() # Use grab_set to prevent user input in the main window 4953 raster_settings.focus_set() 4954 raster_settings.resizable(0,0) 4955 raster_settings.title('Raster Settings') 4956 raster_settings.iconname("Raster Settings") 4957 4958 D_Yloc = 6 4959 D_dY = 24 4960 xd_label_L = 12 4961 4962 w_label=155 4963 w_entry=60 4964 w_units=35 4965 xd_entry_L=xd_label_L+w_label+10 4966 xd_units_L=xd_entry_L+w_entry+5 4967 4968 D_Yloc=D_Yloc+D_dY 4969 self.Label_Rstep = Label(raster_settings,text="Scanline Step", anchor=CENTER ) 4970 self.Label_Rstep.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4971 self.Label_Rstep_u = Label(raster_settings,text="in", anchor=W) 4972 self.Label_Rstep_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 4973 self.Entry_Rstep = Entry(raster_settings,width="15") 4974 self.Entry_Rstep.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 4975 self.Entry_Rstep.configure(textvariable=self.rast_step) 4976 self.rast_step.trace_variable("w", self.Entry_Rstep_Callback) 4977 4978 D_Yloc=D_Yloc+D_dY 4979 self.Label_EngraveUP = Label(raster_settings,text="Engrave Bottom Up") 4980 self.Checkbutton_EngraveUP = Checkbutton(raster_settings,text=" ", anchor=W) 4981 self.Checkbutton_EngraveUP.configure(variable=self.engraveUP) 4982 self.Label_EngraveUP.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4983 self.Checkbutton_EngraveUP.place(x=w_label+22, y=D_Yloc, width=75, height=23) 4984 4985 D_Yloc=D_Yloc+D_dY 4986 self.Label_Halftone = Label(raster_settings,text="Halftone (Dither)") 4987 self.Label_Halftone.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 4988 self.Checkbutton_Halftone = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_RASTER) 4989 self.Checkbutton_Halftone.place(x=w_label+22, y=D_Yloc, width=75, height=23) 4990 self.Checkbutton_Halftone.configure(variable=self.halftone) 4991 self.halftone.trace_variable("w", self.menu_View_Refresh_Callback) 4992 4993 ############ 4994 D_Yloc=D_Yloc+D_dY 4995 self.Label_Halftone_DPI = Label(raster_settings,text="Halftone Resolution", anchor=CENTER ) 4996 self.Halftone_DPI_OptionMenu = OptionMenu(raster_settings, self.ht_size, 4997 "1000", 4998 "500", 4999 "333", 5000 "250", 5001 "200", 5002 "167", 5003 "143", 5004 "125") 5005 self.Label_Halftone_DPI.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5006 self.Halftone_DPI_OptionMenu.place(x=xd_entry_L, y=D_Yloc, width=w_entry+30, height=23) 5007 5008 5009 self.Label_Halftone_u = Label(raster_settings,text="dpi", anchor=W) 5010 self.Label_Halftone_u.place(x=xd_units_L+30, y=D_Yloc, width=w_units, height=21) 5011 5012 ############ 5013 D_Yloc=D_Yloc+D_dY+5 5014 self.Label_bezier_M1 = Label(raster_settings, 5015 text="Slope, Black (%.1f)"%(self.bezier_M1_default), 5016 anchor=CENTER ) 5017 self.bezier_M1_Slider = Scale(raster_settings, from_=1, to=50, resolution=0.1, \ 5018 orient=HORIZONTAL, variable=self.bezier_M1) 5019 self.bezier_M1_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 )) 5020 D_Yloc=D_Yloc+21 5021 self.Label_bezier_M1.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5022 self.bezier_M1.trace_variable("w", self.bezier_M1_Callback) 5023 5024 D_Yloc=D_Yloc+D_dY-8 5025 self.Label_bezier_M2 = Label(raster_settings, 5026 text="Slope, White (%.2f)"%(self.bezier_M2_default), 5027 anchor=CENTER ) 5028 self.bezier_M2_Slider = Scale(raster_settings, from_=0.0, to=1, \ 5029 orient=HORIZONTAL,resolution=0.01, variable=self.bezier_M2) 5030 self.bezier_M2_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 )) 5031 D_Yloc=D_Yloc+21 5032 self.Label_bezier_M2.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5033 self.bezier_M2.trace_variable("w", self.bezier_M2_Callback) 5034 5035 D_Yloc=D_Yloc+D_dY-8 5036 self.Label_bezier_weight = Label(raster_settings, 5037 text="Transition (%.1f)"%(self.bezier_M1_default), 5038 anchor=CENTER ) 5039 self.bezier_weight_Slider = Scale(raster_settings, from_=0, to=10, resolution=0.1, \ 5040 orient=HORIZONTAL, variable=self.bezier_weight) 5041 self.bezier_weight_Slider.place(x=xd_entry_L, y=D_Yloc, width=(Wset-xd_entry_L-25-280 )) 5042 D_Yloc=D_Yloc+21 5043 self.Label_bezier_weight.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5044 self.bezier_weight.trace_variable("w", self.bezier_weight_Callback) 5045 5046## show_unsharp = False 5047## if DEBUG and show_unsharp: 5048## D_Yloc=D_Yloc+D_dY 5049## self.Label_UnsharpMask = Label(raster_settings,text="Unsharp Mask") 5050## self.Label_UnsharpMask.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5051## self.Checkbutton_UnsharpMask = Checkbutton(raster_settings,text=" ", anchor=W, command=self.Set_Input_States_Unsharp) 5052## self.Checkbutton_UnsharpMask.place(x=w_label+22, y=D_Yloc, width=75, height=23) 5053## self.Checkbutton_UnsharpMask.configure(variable=self.unsharp_flag) 5054## self.unsharp_flag.trace_variable("w", self.menu_View_Refresh_Callback) 5055## 5056## D_Yloc=D_Yloc+D_dY 5057## self.Label_Unsharp_Radius = Label(raster_settings,text="Unsharp Mask Radius", anchor=CENTER ) 5058## self.Label_Unsharp_Radius.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5059## self.Label_Unsharp_Radius_u = Label(raster_settings,text="Pixels", anchor=W) 5060## self.Label_Unsharp_Radius_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5061## self.Entry_Unsharp_Radius = Entry(raster_settings,width="15") 5062## self.Entry_Unsharp_Radius.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5063## self.Entry_Unsharp_Radius.configure(textvariable=self.unsharp_r) 5064## self.unsharp_r.trace_variable("w", self.Entry_Unsharp_Radius_Callback) 5065## 5066## D_Yloc=D_Yloc+D_dY 5067## self.Label_Unsharp_Percent = Label(raster_settings,text="Unsharp Mask Percent", anchor=CENTER ) 5068## self.Label_Unsharp_Percent.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5069## self.Label_Unsharp_Percent_u = Label(raster_settings,text="%", anchor=W) 5070## self.Label_Unsharp_Percent_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5071## self.Entry_Unsharp_Percent = Entry(raster_settings,width="15") 5072## self.Entry_Unsharp_Percent.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5073## self.Entry_Unsharp_Percent.configure(textvariable=self.unsharp_p) 5074## self.unsharp_p.trace_variable("w", self.Entry_Unsharp_Percent_Callback) 5075## 5076## D_Yloc=D_Yloc+D_dY 5077## self.Label_Unsharp_Threshold = Label(raster_settings,text="Unsharp Mask Threshold", anchor=CENTER ) 5078## self.Label_Unsharp_Threshold.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5079## #self.Label_Unsharp_Threshold_u = Label(raster_settings,text="Pixels", anchor=W) 5080## #self.Label_Unsharp_Threshold_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5081## self.Entry_Unsharp_Threshold = Entry(raster_settings,width="15") 5082## self.Entry_Unsharp_Threshold.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5083## self.Entry_Unsharp_Threshold.configure(textvariable=self.unsharp_t) 5084## self.unsharp_t.trace_variable("w", self.Entry_Unsharp_Threshold_Callback) 5085 5086 # Bezier Canvas 5087 self.Bezier_frame = Frame(raster_settings, bd=1, relief=SUNKEN) 5088 self.Bezier_frame.place(x=Wset-280, y=10, height=265, width=265) 5089 self.BezierCanvas = Canvas(self.Bezier_frame, background="white") 5090 self.BezierCanvas.pack(side=LEFT, fill=BOTH, expand=1) 5091 self.BezierCanvas.create_line( 5,260-0,260,260-255,fill="grey75", capstyle="round", width = 2, tags='perm') 5092 5093 5094 M1 = self.bezier_M1_default 5095 M2 = self.bezier_M2_default 5096 w = self.bezier_weight_default 5097 num = 10 5098 x,y = self.generate_bezier(M1,M2,w,n=num) 5099 for i in range(0,num): 5100 self.BezierCanvas.create_line( 5+x[i],260-y[i],5+x[i+1],260-y[i+1],fill="grey85", stipple='gray25',\ 5101 capstyle="round", width = 2, tags='perm') 5102 5103 5104 ## Buttons ## 5105 raster_settings.update_idletasks() 5106 Ybut=int(raster_settings.winfo_height())-30 5107 Xbut=int(raster_settings.winfo_width()/2) 5108 5109 self.RASTER_Close = Button(raster_settings,text="Close") 5110 self.RASTER_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center") 5111 self.RASTER_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click) 5112 5113 self.bezier_M1_Callback() 5114 self.Set_Input_States_RASTER() 5115 #if DEBUG and show_unsharp: 5116 # self.Set_Input_States_Unsharp() 5117 5118 5119 ################################################################################ 5120 # Rotary Settings Window # 5121 ################################################################################ 5122 def ROTARY_Settings_Window(self): 5123 rotary_settings = Toplevel(width=350, height=175) 5124 rotary_settings.grab_set() # Use grab_set to prevent user input in the main window 5125 rotary_settings.focus_set() 5126 rotary_settings.resizable(0,0) 5127 rotary_settings.title('Rotary Settings') 5128 rotary_settings.iconname("Rotary Settings") 5129 5130 D_Yloc = 6 5131 D_dY = 30 5132 xd_label_L = 12 5133 5134 w_label=180 5135 w_entry=40 5136 w_units=45 5137 xd_entry_L=xd_label_L+w_label+10 5138 xd_units_L=xd_entry_L+w_entry+5 5139 sep_border=10 5140 5141 5142 D_Yloc=D_Yloc+D_dY-15 5143 self.Label_Rotary_Enable = Label(rotary_settings,text="Use Rotary Settings") 5144 self.Label_Rotary_Enable.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5145 self.Checkbutton_Rotary_Enable = Checkbutton(rotary_settings,text="", anchor=W, command=self.Set_Input_States_Rotary) 5146 self.Checkbutton_Rotary_Enable.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 5147 self.Checkbutton_Rotary_Enable.configure(variable=self.rotary) 5148 5149 D_Yloc=D_Yloc+D_dY 5150 self.Label_Laser_R_Scale = Label(rotary_settings,text="Rotary Scale Factor (Y axis)") 5151 self.Label_Laser_R_Scale.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5152 self.Entry_Laser_R_Scale = Entry(rotary_settings,width="15") 5153 self.Entry_Laser_R_Scale.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5154 self.Entry_Laser_R_Scale.configure(textvariable=self.LaserRscale) 5155 self.LaserRscale.trace_variable("w", self.Entry_Laser_R_Scale_Callback) 5156 self.entry_set(self.Entry_Laser_R_Scale,self.Entry_Laser_R_Scale_Check(),2) 5157 5158 D_Yloc=D_Yloc+D_dY 5159 self.Label_Laser_Rapid_Feed = Label(rotary_settings,text="Rapid Speed (default=0)") 5160 self.Label_Laser_Rapid_Feed.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5161 self.Label_Laser_Rapid_Feed_u = Label(rotary_settings,textvariable=self.funits, anchor=W) 5162 self.Label_Laser_Rapid_Feed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5163 self.Entry_Laser_Rapid_Feed = Entry(rotary_settings,width="15") 5164 self.Entry_Laser_Rapid_Feed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5165 self.Entry_Laser_Rapid_Feed.configure(textvariable=self.rapid_feed) 5166 self.rapid_feed.trace_variable("w", self.Entry_Laser_Rapid_Feed_Callback) 5167 self.entry_set(self.Entry_Laser_Rapid_Feed,self.Entry_Laser_Rapid_Feed_Check(),2) 5168 5169 ## Buttons ## 5170 rotary_settings.update_idletasks() 5171 Ybut=int(rotary_settings.winfo_height())-30 5172 Xbut=int(rotary_settings.winfo_width()/2) 5173 5174 self.GEN_Close = Button(rotary_settings,text="Close") 5175 self.GEN_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center") 5176 self.GEN_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click) 5177 5178 self.Set_Input_States_Rotary() 5179 5180 ################################################################################ 5181 # Trace Send Window # 5182 ################################################################################ 5183 5184 def TRACE_Settings_Window(self, dummy=None): 5185 if self.GUI_Disabled: 5186 return 5187 trace_window = Toplevel(width=350, height=180) 5188 self.trace_window=trace_window 5189 trace_window.grab_set() # Use grab_set to prevent user input in the main window during calculations 5190 trace_window.resizable(0,0) 5191 trace_window.title('Trace Boundary') 5192 trace_window.iconname("Trace Boundary") 5193 5194 def Close_Click(): 5195 win_id=self.grab_current() 5196 self.PreviewCanvas.delete('trace') 5197 win_id.destroy() 5198 5199 def Close_and_Send_Click(): 5200 win_id=self.grab_current() 5201 self.PreviewCanvas.delete('trace') 5202 win_id.destroy() 5203 self.Trace_Eng() 5204 5205 D_Yloc = 0 5206 D_dY = 28 5207 xd_label_L = 12 5208 5209 w_label=225 5210 w_entry=40 5211 w_units=50 5212 xd_entry_L=xd_label_L+w_label+10 5213 xd_units_L=xd_entry_L+w_entry+5 5214 5215 D_Yloc=D_Yloc+D_dY 5216 self.Label_Laser_Trace = Label(trace_window,text="Laser 'On' During Trace") 5217 self.Label_Laser_Trace.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5218 self.Checkbutton_Laser_Trace = Checkbutton(trace_window,text="", anchor=W) 5219 self.Checkbutton_Laser_Trace.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 5220 self.Checkbutton_Laser_Trace.configure(variable=self.trace_w_laser) 5221 5222 D_Yloc=D_Yloc+D_dY 5223 self.Label_Trace_Gap = Label(trace_window,text="Gap Between Design and Trace") 5224 self.Label_Trace_Gap.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5225 self.Entry_Trace_Gap = Entry(trace_window,width="15") 5226 self.Entry_Trace_Gap.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5227 self.Label_Trace_Gap_u = Label(trace_window,textvariable=self.units, anchor=W) 5228 self.Label_Trace_Gap_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5229 self.Entry_Trace_Gap.configure(textvariable=self.trace_gap,justify='center') 5230 self.trace_gap.trace_variable("w", self.Entry_Trace_Gap_Callback) 5231 self.entry_set(self.Entry_Trace_Gap,self.Entry_Trace_Gap_Check(),2) 5232 if not PYCLIPPER: 5233 self.Label_Trace_Gap.configure(state="disabled") 5234 self.Label_Trace_Gap_u.configure(state="disabled") 5235 self.Entry_Trace_Gap.configure(state="disabled") 5236 5237 D_Yloc=D_Yloc+D_dY 5238 self.Trace_Button = Button(trace_window,text="Trace Boundary With Laser Head",command=Close_and_Send_Click) 5239 self.Trace_Button.place(x=xd_label_L, y=D_Yloc, width=w_label, height=23) 5240 5241 self.Entry_Trace_Speed = Entry(trace_window,width="15") 5242 self.Entry_Trace_Speed.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5243 green = "#%02x%02x%02x" % (0, 200, 0) 5244 self.Entry_Trace_Speed.configure(textvariable=self.trace_speed,justify='center',fg=green) 5245 self.trace_speed.trace_variable("w", self.Entry_Trace_Speed_Callback) 5246 self.entry_set(self.Entry_Trace_Speed,self.Entry_Trace_Speed_Check(),2) 5247 self.Label_Trace_Speed_u = Label(trace_window,textvariable=self.funits, anchor=W) 5248 self.Label_Trace_Speed_u.place(x=xd_units_L, y=D_Yloc, width=w_units, height=21) 5249 5250 5251 ## Buttons ## 5252 trace_window.update_idletasks() 5253 Ybut=int(trace_window.winfo_height())-30 5254 Xbut=int(trace_window.winfo_width()/2) 5255 5256 self.Trace_Close = Button(trace_window,text="Cancel",command=Close_Click) 5257 self.Trace_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="center") 5258 ################################################################################ 5259 5260 ################################################################################ 5261 # EGV Send Window # 5262 ################################################################################ 5263 def EGV_Send_Window(self,EGV_filename): 5264 5265 egv_send = Toplevel(width=400, height=180) 5266 egv_send.grab_set() # Use grab_set to prevent user input in the main window during calculations 5267 egv_send.resizable(0,0) 5268 egv_send.title('EGV Send') 5269 egv_send.iconname("EGV Send") 5270 5271 D_Yloc = 0 5272 D_dY = 28 5273 xd_label_L = 12 5274 5275 w_label=150 5276 w_entry=40 5277 w_units=35 5278 xd_entry_L=xd_label_L+w_label+10 5279 xd_units_L=xd_entry_L+w_entry+5 5280 5281 D_Yloc=D_Yloc+D_dY 5282 self.Label_Preprocess_CRC = Label(egv_send,text="Preprocess CRC Data") 5283 self.Label_Preprocess_CRC.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5284 self.Checkbutton_Preprocess_CRC = Checkbutton(egv_send,text="", anchor=W) 5285 self.Checkbutton_Preprocess_CRC.place(x=xd_entry_L, y=D_Yloc, width=75, height=23) 5286 self.Checkbutton_Preprocess_CRC.configure(variable=self.pre_pr_crc) 5287 5288 D_Yloc=D_Yloc+D_dY 5289 self.Label_N_EGV_Passes = Label(egv_send,text="Number of EGV Passes") 5290 self.Label_N_EGV_Passes.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5291 self.Entry_N_EGV_Passes = Entry(egv_send,width="15") 5292 self.Entry_N_EGV_Passes.place(x=xd_entry_L, y=D_Yloc, width=w_entry, height=23) 5293 self.Entry_N_EGV_Passes.configure(textvariable=self.n_egv_passes) 5294 self.n_egv_passes.trace_variable("w", self.Entry_N_EGV_Passes_Callback) 5295 self.entry_set(self.Entry_N_EGV_Passes,self.Entry_N_EGV_Passes_Check(),2) 5296 5297 D_Yloc=D_Yloc+D_dY 5298 font_entry_width=215 5299 self.Label_Inkscape_Path = Label(egv_send,text="EGV File:") 5300 self.Label_Inkscape_Path.place(x=xd_label_L, y=D_Yloc, width=w_label, height=21) 5301 5302 EGV_Name = os.path.basename(EGV_filename) 5303 self.Label_Inkscape_Path = Label(egv_send,text=EGV_Name,anchor="w") #,bg="yellow") 5304 self.Label_Inkscape_Path.place(x=xd_entry_L, y=D_Yloc, width=200, height=21,anchor="nw") 5305 5306 ## Buttons ## 5307 egv_send.update_idletasks() 5308 Ybut=int(egv_send.winfo_height())-30 5309 Xbut=int(egv_send.winfo_width()/2) 5310 5311 self.EGV_Close = Button(egv_send,text="Cancel") 5312 self.EGV_Close.place(x=Xbut, y=Ybut, width=130, height=30, anchor="e") 5313 self.EGV_Close.bind("<ButtonRelease-1>", self.Close_Current_Window_Click) 5314 5315 def Close_and_Send_Click(): 5316 win_id=self.grab_current() 5317 win_id.destroy() 5318 self.Open_EGV(EGV_filename, n_passes=int( float(self.n_egv_passes.get()) )) 5319 5320 self.EGV_Send = Button(egv_send,text="Send EGV Data",command=Close_and_Send_Click) 5321 self.EGV_Send.place(x=Xbut, y=Ybut, width=130, height=30, anchor="w") 5322 ################################################################################ 5323 5324 5325################################################################################ 5326# Function for outputting messages to different locations # 5327# depending on what options are enabled # 5328################################################################################ 5329def fmessage(text,newline=True): 5330 global QUIET 5331 if (not QUIET): 5332 if newline==True: 5333 try: 5334 sys.stdout.write(text) 5335 sys.stdout.write("\n") 5336 debug_message(traceback.format_exc()) 5337 except: 5338 debug_message(traceback.format_exc()) 5339 pass 5340 else: 5341 try: 5342 sys.stdout.write(text) 5343 debug_message(traceback.format_exc()) 5344 except: 5345 debug_message(traceback.format_exc()) 5346 pass 5347 5348################################################################################ 5349# Message Box # 5350################################################################################ 5351def message_box(title,message): 5352 title = "%s (K40 Whisperer V%s)" %(title,version) 5353 if VERSION == 3: 5354 tkinter.messagebox.showinfo(title,message) 5355 else: 5356 tkMessageBox.showinfo(title,message) 5357 pass 5358 5359################################################################################ 5360# Message Box ask OK/Cancel # 5361################################################################################ 5362def message_ask_ok_cancel(title, mess): 5363 if VERSION == 3: 5364 result=tkinter.messagebox.askokcancel(title, mess) 5365 else: 5366 result=tkMessageBox.askokcancel(title, mess) 5367 return result 5368 5369################################################################################ 5370# Debug Message Box # 5371################################################################################ 5372def debug_message(message): 5373 global DEBUG 5374 title = "Debug Message" 5375 if DEBUG: 5376 if VERSION == 3: 5377 tkinter.messagebox.showinfo(title,message) 5378 else: 5379 tkMessageBox.showinfo(title,message) 5380 pass 5381 5382################################################################################ 5383# Choose Units Dialog # 5384################################################################################ 5385if VERSION < 3: 5386 import tkSimpleDialog 5387else: 5388 import tkinter.simpledialog as tkSimpleDialog 5389 5390class UnitsDialog(tkSimpleDialog.Dialog): 5391 def body(self, master): 5392 self.resizable(0,0) 5393 self.title('Units') 5394 self.iconname("Units") 5395 5396 self.uom = StringVar() 5397 self.uom.set("Millimeters") 5398 5399 Label(master, text="Select DXF Import Units:").grid(row=0) 5400 Radio_Units_IN = Radiobutton(master,text="Inches", value="Inches") 5401 Radio_Units_MM = Radiobutton(master,text="Millimeters", value="Millimeters") 5402 Radio_Units_CM = Radiobutton(master,text="Centimeters", value="Centimeters") 5403 5404 Radio_Units_IN.grid(row=1, sticky=W) 5405 Radio_Units_MM.grid(row=2, sticky=W) 5406 Radio_Units_CM.grid(row=3, sticky=W) 5407 5408 Radio_Units_IN.configure(variable=self.uom) 5409 Radio_Units_MM.configure(variable=self.uom) 5410 Radio_Units_CM.configure(variable=self.uom) 5411 5412 def apply(self): 5413 self.result = self.uom.get() 5414 return 5415 5416 5417class toplevel_dummy(): 5418 def winfo_exists(self): 5419 return False 5420 5421class pxpiDialog(tkSimpleDialog.Dialog): 5422 5423 def __init__(self, 5424 parent, 5425 units = "mm", 5426 SVG_Size =None, 5427 SVG_ViewBox =None, 5428 SVG_inkscape_version=None): 5429 5430 self.result = None 5431 self.svg_pxpi = StringVar() 5432 self.other = StringVar() 5433 self.svg_width = StringVar() 5434 self.svg_height = StringVar() 5435 self.svg_units = StringVar() 5436 self.fixed_size = False 5437 self.svg_units.set(units) 5438 if units=="mm": 5439 self.scale=1.0 5440 else: 5441 self.scale=1/25.4 5442 5443 5444 ################################### 5445 ## Set initial pxpi # 5446 ################################### 5447 pxpi = 72.0 5448 if SVG_inkscape_version != None: 5449 if SVG_inkscape_version >=.92: 5450 pxpi = 96.0 5451 else: 5452 pxpi = 90.0 5453 5454 self.svg_pxpi.set("%d"%(pxpi)) 5455 self.other.set("%d"%(pxpi)) 5456 5457 ################################### 5458 ## Set minx/miny # 5459 ################################### 5460 if SVG_ViewBox!=None and SVG_ViewBox[0]!=None and SVG_ViewBox[1]!=None: 5461 self.minx_pixels = SVG_ViewBox[0] 5462 self.miny_pixels = SVG_ViewBox[1] 5463 else: 5464 self.minx_pixels = 0.0 5465 self.miny_pixels = 0.0 5466 5467 ################################### 5468 ## Set Initial Size # 5469 ################################### 5470 if SVG_Size!=None and SVG_Size[2]!=None and SVG_Size[3]!=None: 5471 self.width_pixels = SVG_Size[2] 5472 self.height_pixels = SVG_Size[3] 5473 elif SVG_ViewBox!=None and SVG_ViewBox[2]!=None and SVG_ViewBox[3]!=None: 5474 self.width_pixels = SVG_ViewBox[2] 5475 self.height_pixels = SVG_ViewBox[3] 5476 else: 5477 self.width_pixels = 500.0 5478 self.height_pixels = 500.0 5479 ################################### 5480 ## Set Initial Size # 5481 ################################### 5482 if SVG_Size[0]!=None and SVG_Size[1]!=None: 5483 width = SVG_Size[0] 5484 height = SVG_Size[1] 5485 self.fixed_size=True 5486 else: 5487 width = self.width_pixels/float(self.svg_pxpi.get())*25.4 5488 height = self.height_pixels/float(self.svg_pxpi.get())*25.4 5489 5490 self.svg_width.set("%f" %(width*self.scale)) 5491 self.svg_height.set("%f" %(height*self.scale)) 5492 ################################### 5493 tkSimpleDialog.Dialog.__init__(self, parent) 5494 5495 5496 def body(self, master): 5497 self.resizable(0,0) 5498 self.title('SVG Import Scale:') 5499 self.iconname("SVG Scale") 5500 5501 ########################################################################### 5502 def Entry_custom_Check(): 5503 try: 5504 value = float(self.other.get()) 5505 if value <= 0.0: 5506 return 2 # Value is invalid number 5507 except: 5508 return 3 # Value not a number 5509 return 0 # Value is a valid number 5510 def Entry_custom_Callback(varName, index, mode): 5511 if Entry_custom_Check() > 0: 5512 Entry_Custom_pxpi.configure( bg = 'red' ) 5513 else: 5514 Entry_Custom_pxpi.configure( bg = 'white' ) 5515 pxpi = float(self.other.get()) 5516 width = self.width_pixels/pxpi*25.4 5517 height = self.height_pixels/pxpi*25.4 5518 if self.fixed_size: 5519 pass 5520 else: 5521 Set_Value(width=width*self.scale,height=height*self.scale) 5522 self.svg_pxpi.set("custom") 5523 ################################################### 5524 def Entry_Width_Check(): 5525 try: 5526 value = float(self.svg_width.get())/self.scale 5527 if value <= 0.0: 5528 return 2 # Value is invalid number 5529 except: 5530 return 3 # Value not a number 5531 return 0 # Value is a valid number 5532 def Entry_Width_Callback(varName, index, mode): 5533 if Entry_Width_Check() > 0: 5534 Entry_Custom_Width.configure( bg = 'red' ) 5535 else: 5536 Entry_Custom_Width.configure( bg = 'white' ) 5537 width = float(self.svg_width.get())/self.scale 5538 pxpi = self.width_pixels*25.4/width 5539 height = self.height_pixels/pxpi*25.4 5540 Set_Value(other=pxpi,height=height*self.scale) 5541 self.svg_pxpi.set("custom") 5542 ################################################### 5543 def Entry_Height_Check(): 5544 try: 5545 value = float(self.svg_height.get()) 5546 if value <= 0.0: 5547 return 2 # Value is invalid number 5548 except: 5549 return 3 # Value not a number 5550 return 0 # Value is a valid number 5551 def Entry_Height_Callback(varName, index, mode): 5552 if Entry_Height_Check() > 0: 5553 Entry_Custom_Height.configure( bg = 'red' ) 5554 else: 5555 Entry_Custom_Height.configure( bg = 'white' ) 5556 height = float(self.svg_height.get())/self.scale 5557 pxpi = self.height_pixels*25.4/height 5558 width = self.width_pixels/pxpi*25.4 5559 Set_Value(other=pxpi,width=width*self.scale) 5560 self.svg_pxpi.set("custom") 5561 ################################################### 5562 def SVG_pxpi_callback(varName, index, mode): 5563 if self.svg_pxpi.get() == "custom": 5564 try: 5565 pxpi=float(self.other.get()) 5566 except: 5567 pass 5568 else: 5569 pxpi=float(self.svg_pxpi.get()) 5570 width = self.width_pixels/pxpi*25.4 5571 height = self.height_pixels/pxpi*25.4 5572 if self.fixed_size: 5573 Set_Value(other=pxpi) 5574 else: 5575 Set_Value(other=pxpi,width=width*self.scale,height=height*self.scale) 5576 5577 ########################################################################### 5578 5579 def Set_Value(other=None,width=None,height=None): 5580 self.svg_pxpi.trace_vdelete("w",self.trace_id_svg_pxpi) 5581 self.other.trace_vdelete("w",self.trace_id_pxpi) 5582 self.svg_width.trace_vdelete("w",self.trace_id_width) 5583 self.svg_height.trace_vdelete("w",self.trace_id_height) 5584 self.update_idletasks() 5585 5586 if other != None: 5587 self.other.set("%f" %(other)) 5588 if width != None: 5589 self.svg_width.set("%f" %(width)) 5590 if height != None: 5591 self.svg_height.set("%f" %(height)) 5592 5593 self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback) 5594 self.trace_id_pxpi = self.other.trace_variable("w", Entry_custom_Callback) 5595 self.trace_id_width = self.svg_width.trace_variable("w", Entry_Width_Callback) 5596 self.trace_id_height = self.svg_height.trace_variable("w", Entry_Height_Callback) 5597 self.update_idletasks() 5598 5599 ########################################################################### 5600 t0="This dialog opens if the SVG file you are opening\n" 5601 t1="does not contain enough information to determine\n" 5602 t2="the intended physical size of the design.\n" 5603 t3="Select an SVG Import Scale:\n" 5604 Title_Text0 = Label(master, text=t0+t1+t2, anchor=W) 5605 Title_Text1 = Label(master, text=t3, anchor=W) 5606 5607 Radio_SVG_pxpi_96 = Radiobutton(master,text=" 96 units/in", value="96") 5608 Label_SVG_pxpi_96 = Label(master,text="(File saved with Inkscape v0.92 or newer)", anchor=W) 5609 5610 Radio_SVG_pxpi_90 = Radiobutton(master,text=" 90 units/in", value="90") 5611 Label_SVG_pxpi_90 = Label(master,text="(File saved with Inkscape v0.91 or older)", anchor=W) 5612 5613 Radio_SVG_pxpi_72 = Radiobutton(master,text=" 72 units/in", value="72") 5614 Label_SVG_pxpi_72 = Label(master,text="(File saved with Adobe Illustrator)", anchor=W) 5615 5616 Radio_Res_Custom = Radiobutton(master,text=" Custom:", value="custom") 5617 Bottom_row = Label(master, text=" ") 5618 5619 5620 Entry_Custom_pxpi = Entry(master,width="10") 5621 Entry_Custom_pxpi.configure(textvariable=self.other) 5622 Label_pxpi_units = Label(master,text="units/in", anchor=W) 5623 self.trace_id_pxpi = self.other.trace_variable("w", Entry_custom_Callback) 5624 5625 Label_Width = Label(master,text="Width", anchor=W) 5626 Entry_Custom_Width = Entry(master,width="10") 5627 Entry_Custom_Width.configure(textvariable=self.svg_width) 5628 Label_Width_units = Label(master,textvariable=self.svg_units, anchor=W) 5629 self.trace_id_width = self.svg_width.trace_variable("w", Entry_Width_Callback) 5630 5631 Label_Height = Label(master,text="Height", anchor=W) 5632 Entry_Custom_Height = Entry(master,width="10") 5633 Entry_Custom_Height.configure(textvariable=self.svg_height) 5634 Label_Height_units = Label(master,textvariable=self.svg_units, anchor=W) 5635 self.trace_id_height = self.svg_height.trace_variable("w", Entry_Height_Callback) 5636 5637 if self.fixed_size == True: 5638 Entry_Custom_Width.configure(state="disabled") 5639 Entry_Custom_Height.configure(state="disabled") 5640 ########################################################################### 5641 rn=0 5642 Title_Text0.grid(row=rn,column=0,columnspan=5, sticky=W) 5643 5644 rn=rn+1 5645 Title_Text1.grid(row=rn,column=0,columnspan=5, sticky=W) 5646 5647 rn=rn+1 5648 Radio_SVG_pxpi_96.grid( row=rn, sticky=W) 5649 Label_SVG_pxpi_96.grid( row=rn, column=1,columnspan=50, sticky=W) 5650 5651 rn=rn+1 5652 Radio_SVG_pxpi_90.grid( row=rn, sticky=W) 5653 Label_SVG_pxpi_90.grid( row=rn, column=1,columnspan=50, sticky=W) 5654 5655 rn=rn+1 5656 Radio_SVG_pxpi_72.grid( row=rn, column=0, sticky=W) 5657 Label_SVG_pxpi_72.grid( row=rn, column=1,columnspan=50, sticky=W) 5658 5659 rn=rn+1 5660 Radio_Res_Custom.grid( row=rn, column=0, sticky=W) 5661 Entry_Custom_pxpi.grid( row=rn, column=1, sticky=E) 5662 Label_pxpi_units.grid( row=rn, column=2, sticky=W) 5663 5664 rn=rn+1 5665 Label_Width.grid( row=rn, column=0, sticky=E) 5666 Entry_Custom_Width.grid( row=rn, column=1, sticky=E) 5667 Label_Width_units.grid( row=rn, column=2, sticky=W) 5668 5669 rn=rn+1 5670 Label_Height.grid( row=rn, column=0, sticky=E) 5671 Entry_Custom_Height.grid( row=rn, column=1, sticky=E) 5672 Label_Height_units.grid( row=rn, column=2, sticky=W) 5673 5674 rn=rn+1 5675 Bottom_row.grid(row=rn,columnspan=50) 5676 5677 Radio_SVG_pxpi_96.configure (variable=self.svg_pxpi) 5678 Radio_SVG_pxpi_90.configure (variable=self.svg_pxpi) 5679 Radio_SVG_pxpi_72.configure (variable=self.svg_pxpi) 5680 Radio_Res_Custom.configure (variable=self.svg_pxpi) 5681 self.trace_id_svg_pxpi = self.svg_pxpi.trace_variable("w", SVG_pxpi_callback) 5682 ########################################################################### 5683 5684 def apply(self): 5685 width = float(self.svg_width.get())/self.scale 5686 height = float(self.svg_height.get())/self.scale 5687 pxpi = float(self.other.get()) 5688 viewbox = [self.minx_pixels, self.miny_pixels, width/25.4*pxpi, height/25.4*pxpi] 5689 self.result = pxpi,viewbox 5690 return 5691 5692################################################################################ 5693# Startup Application # 5694################################################################################ 5695 5696root = Tk() 5697app = Application(root) 5698app.master.title(title_text) 5699app.master.iconname("K40") 5700app.master.minsize(800,560) 5701app.master.geometry("800x560") 5702try: 5703 try: 5704 import tkFont 5705 default_font = tkFont.nametofont("TkDefaultFont") 5706 except: 5707 import tkinter.font 5708 default_font = tkinter.font.nametofont("TkDefaultFont") 5709 5710 default_font.configure(size=9) 5711 default_font.configure(family='arial') 5712 #print(default_font.cget("size")) 5713 #print(default_font.cget("family")) 5714except: 5715 debug_message("Font Set Failed.") 5716 5717################################## Set Icon ######################################## 5718Icon_Set=False 5719 5720try: 5721 debug_message("Icon set %s" %(sys.argv[0])) 5722 root.iconbitmap(default="emblem") 5723 debug_message("Icon set worked %s" %(sys.argv[0])) 5724 Icon_Set=True 5725except: 5726 debug_message(traceback.format_exc()) 5727 Icon_Set=False 5728 5729if not Icon_Set: 5730 try: 5731 scorch_ico_B64=b'R0lGODlhEAAQAIYAAA\ 5732 AAABAQEBYWFhcXFxsbGyUlJSYmJikpKSwsLC4uLi8vLzExMTMzMzc3Nzg4ODk5OTs7Oz4+PkJCQkRERE\ 5733 VFRUtLS0xMTE5OTlNTU1dXV1xcXGBgYGVlZWhoaGtra3FxcXR0dHh4eICAgISEhI+Pj5mZmZ2dnaKioq\ 5734 Ojo62tra6urrS0tLi4uLm5ub29vcLCwsbGxsjIyMzMzM/Pz9PT09XV1dbW1tjY2Nzc3OHh4eLi4uXl5e\ 5735 fn5+jo6Ovr6+/v7/Hx8fLy8vT09PX19fn5+fv7+/z8/P7+/v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ 5736 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ 5737 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ 5738 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEKAEkALAAAAAAQABAAQAj/AJMIFBhBQYAACRIkWbgwAA\ 5739 4kEFEECACAxBAkGH8ESEKgBZIiAIQECBAjAA8kNwIkScKgQhAkRggAIJACCZIaJxgk2clgAY4OAAoEAO\ 5740 ABCIIDSZIwkIHEBw0YFAAA6IGDCBIkLAhMyICka9cAKZCIRTLEBIMkaA0MSNGjSBEVIgpESEK3LgMCI1\ 5741 aAWCFDA4EDSQInwaDACBEAImLwCAFARw4HFJJcgGADyZEAL3YQcMGBBpIjHx4EeIGkRoMFJgakWADABx\ 5742 IkPwIgcIGkdm0AMJDo1g3jQBIBRZAINyKAwxEkyHEUSMIcwYYbEgwYmQGgyI8SD5Jo327hgIIAAQ5cBs\ 5743 CQpHySgAA7' 5744 icon_im =PhotoImage(data=scorch_ico_B64, format='gif') 5745 root.call('wm', 'iconphoto', root._w, '-default', icon_im) 5746 except: 5747 pass 5748##################################################################################### 5749 5750 5751if LOAD_MSG != "": 5752 message_box("K40 Whisperer",LOAD_MSG) 5753 5754opts, args = None, None 5755try: 5756 opts, args = getopt.getopt(sys.argv[1:], "hpd",["help", "pi", "debug"]) 5757except: 5758 print('Unable interpret command line options') 5759 sys.exit() 5760 5761for option, value in opts: 5762 if option in ('-h','--help'): 5763 print(' ') 5764 print('Usage: python k40_whisperer.py [-h -p]') 5765 print('-h : print this help (also --help)') 5766 print('-p : Small screen option (for small raspberry pi display) (also --pi)') 5767 sys.exit() 5768 elif option in ('-p','--pi'): 5769 print("pi mode") 5770 app.master.minsize(480,320) 5771 app.master.geometry("480x320") 5772 elif option in ('-d','--debug'): 5773 DEBUG=True 5774 5775if DEBUG: 5776 import inspect 5777debug_message("Debuging is turned on.") 5778 5779root.mainloop() 5780