diff --git a/gcview.py b/gcview.py new file mode 100644 index 0000000..373a46c --- /dev/null +++ b/gcview.py @@ -0,0 +1,886 @@ +#!/usr/bin/python +import os +import math +import wx +from wx import glcanvas +import time +import threading + +import pyglet +pyglet.options['shadow_window'] = False +pyglet.options['debug_gl'] = False +from pyglet.gl import * + +import stltool + + +class GLPanel(wx.Panel): + '''A simple class for using OpenGL with wxPython.''' + + def __init__(self, parent, id, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + # Forcing a no full repaint to stop flickering + style = style | wx.NO_FULL_REPAINT_ON_RESIZE + #call super function + super(GLPanel, self).__init__(parent, id, pos, size, style) + + #init gl canvas data + self.GLinitialized = False + attribList = (glcanvas.WX_GL_RGBA, # RGBA + glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered + glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit + # Create the canvas + self.sizer = wx.BoxSizer(wx.HORIZONTAL) + self.canvas = glcanvas.GLCanvas(self, attribList=attribList) + self.sizer.Add(self.canvas, 1, wx.EXPAND) + self.SetSizer(self.sizer) + #self.sizer.Fit(self) + self.Layout() + + # bind events + self.canvas.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent) + self.canvas.Bind(wx.EVT_SIZE, self.processSizeEvent) + self.canvas.Bind(wx.EVT_PAINT, self.processPaintEvent) + + #========================================================================== + # Canvas Proxy Methods + #========================================================================== + def GetGLExtents(self): + '''Get the extents of the OpenGL canvas.''' + return self.canvas.GetClientSize() + + def SwapBuffers(self): + '''Swap the OpenGL buffers.''' + self.canvas.SwapBuffers() + + #========================================================================== + # wxPython Window Handlers + #========================================================================== + def processEraseBackgroundEvent(self, event): + '''Process the erase background event.''' + pass # Do nothing, to avoid flashing on MSWin + + def processSizeEvent(self, event): + '''Process the resize event.''' + if self.canvas.GetContext(): + # Make sure the frame is shown before calling SetCurrent. + self.Show() + self.canvas.SetCurrent() + size = self.GetGLExtents() + self.winsize = (size.width, size.height) + self.width, self.height = size.width, size.height + self.OnReshape(size.width, size.height) + self.canvas.Refresh(False) + event.Skip() + + def processPaintEvent(self, event): + '''Process the drawing event.''' + self.canvas.SetCurrent() + + # This is a 'perfect' time to initialize OpenGL ... only if we need to + if not self.GLinitialized: + self.OnInitGL() + self.GLinitialized = True + + self.OnDraw() + event.Skip() + + def Destroy(self): + #clean up the pyglet OpenGL context + #self.pygletcontext.destroy() + #call the super method + super(wx.Panel, self).Destroy() + + #========================================================================== + # GLFrame OpenGL Event Handlers + #========================================================================== + def OnInitGL(self): + '''Initialize OpenGL for use in the window.''' + #create a pyglet context for this panel + self.pmat = (GLdouble * 16)() + self.mvmat = (GLdouble * 16)() + self.pygletcontext = Context(current_context) + self.pygletcontext.set_current() + self.dist = 1000 + self.vpmat = None + #normal gl init + glClearColor(0, 0, 0, 1) + glColor3f(1, 0, 0) + glEnable(GL_DEPTH_TEST) + glEnable(GL_CULL_FACE) + # Uncomment this line for a wireframe view + #glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + + # Simple light setup. On Windows GL_LIGHT0 is enabled by default, + # but this is not the case on Linux or Mac, so remember to always + # include it. + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glEnable(GL_LIGHT1) + + # Define a simple function to create ctypes arrays of floats: + def vec(*args): + return (GLfloat * len(args))(*args) + + glLightfv(GL_LIGHT0, GL_POSITION, vec(.5, .5, 1, 0)) + glLightfv(GL_LIGHT0, GL_SPECULAR, vec(.5, .5, 1, 1)) + glLightfv(GL_LIGHT0, GL_DIFFUSE, vec(1, 1, 1, 1)) + glLightfv(GL_LIGHT1, GL_POSITION, vec(1, 0, .5, 0)) + glLightfv(GL_LIGHT1, GL_DIFFUSE, vec(.5, .5, .5, 1)) + glLightfv(GL_LIGHT1, GL_SPECULAR, vec(1, 1, 1, 1)) + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.5, 0, 0.3, 1)) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, vec(1, 1, 1, 1)) + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50) + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vec(0, 0.1, 0, 0.9)) + #create objects to draw + #self.create_objects() + + def OnReshape(self, width, height): + '''Reshape the OpenGL viewport based on the dimensions of the window.''' + + if not self.GLinitialized: + self.OnInitGL() + self.GLinitialized = True + self.pmat = (GLdouble * 16)() + self.mvmat = (GLdouble * 16)() + glViewport(0, 0, width, height) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(60., width / float(height), .1, 1000.) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + #pyglet stuff + self.vpmat = (GLint * 4)(0, 0, *list(self.GetClientSize())) + glGetDoublev(GL_PROJECTION_MATRIX, self.pmat) + glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) + #glMatrixMode(GL_PROJECTION) + + # Wrap text to the width of the window + if self.GLinitialized: + self.pygletcontext.set_current() + self.update_object_resize() + + def OnDraw(self, *args, **kwargs): + """Draw the window.""" + #clear the context + self.canvas.SetCurrent() + self.pygletcontext.set_current() + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + #draw objects + self.draw_objects() + #update screen + self.SwapBuffers() + + #========================================================================== + # To be implemented by a sub class + #========================================================================== + def create_objects(self): + '''create opengl objects when opengl is initialized''' + pass + + def update_object_resize(self): + '''called when the window recieves only if opengl is initialized''' + pass + + def draw_objects(self): + '''called in the middle of ondraw after the buffer has been cleared''' + pass + + +def _dist(dist): + """return axis length, or 0 if None""" + if dist is None: + return 0 + else: + return float(dist) + +class gcpoint(object): + """gcode point + stub for first line""" + def __init__(self, x=0,y=0,z=0,e=0): + self.x=x + self.y=y + self.z=z + self.e=e + + +class gcline(object): + """gcode move line + Once initialised,it knows its position, length and extrusion ratio + """ + def __init__(self, x=None, y=None, z=None, e=None, prev_gcline=None, orgline = False): + if prev_gcline is None: + self.prev_gcline = gcpoint() + else: + self.prev_gcline = prev_gcline + if x is None: + self.x = self.prev_gcline.x + else: + self.x = float(x) + if y is None: + self.y = self.prev_gcline.y + else: + self.y = float(y) + if z is None: + self.z = self.prev_gcline.z + else: + self.z = float(z) + if e is None: + self.e = self.prev_gcline.e + else: + self.e = float(e) + + self.orgline = orgline + + self.calc_delta() + self.calc_len() + + def __str__(self): + return u"line from %s,%s,%s to %s,%s,%s with extrusion ratio %s\n%s" % ( + self.prev_gcline.x, + self.prev_gcline.y, + self.prev_gcline.z, + self.x, + self.y, + self.z, + self.extrusion_ratio, + self.orgline, + ) + + def calc_delta(self, prev_gcline=None): + if prev_gcline is None: + prev_gcline = self.prev_gcline + if self.prev_gcline is not None: + self.dx = self.x - prev_gcline.x + self.dy = self.y - prev_gcline.y + self.dz = self.z - prev_gcline.z + self.de = self.e - prev_gcline.e + else: + self.dx = self.x + self.dy = self.y + self.dz = self.z + self.de = self.e + + def calc_len(self): + if self.dz != 0: + self.length = math.sqrt(self.dx**2 + self.dy**2 + self.dz**2) + else: + self.length = math.sqrt(self.dx**2 + self.dy**2) + if self.de: + self.extrusion_ratio = self.length / self.de + else: + self.extrusion_ratio = 0 + + def glline(self): + return [ + self.prev_gcline.x, + self.prev_gcline.y, + self.prev_gcline.z, + self.x, + self.y, + self.z, + ] + def glcolor(self): + if self.extrusion_ratio == 0: + return [10,10,10,0,10,10,10,0] + else: + return[255,128,128,120,255,128,128,120] + + +def float_from_line(axe, line): + return float(line.split(axe)[1].split(" ")[0]) + +class gcview(object): + """gcode visualiser""" + def __init__(self, lines, batch, w=0.5, h=0.5): + print len(lines) + self.sq2 = math.sqrt(2.0) / 2.0 + # Create the vertex and normal arrays. + vertices = [] + normals = [] + #End pos of previous mode + self.prev = gcpoint() + # Correction for G92 moves + self.delta = [0, 0, 0, 0] + self.fline = True + #self.vlists = [] + self.layers = {} + t0 = time.time() + lines = [self.transform(i) for i in lines] + lines = [i for i in lines if i is not None] + t1 = time.time() + print "transformed %s lines in %fs" % (len(lines), t1- t0) + layertemp = {} + counter = 0 + for line in lines: + layer_name = line.z + if line.z not in self.layers: + self.layers[line.z] = pyglet.graphics.Batch() + self.layers[line.z].add(2, GL_LINES, None, ("c4B", line.glcolor())) + self.layers[line.z].add(2, GL_LINES, None, ("v3f", line.glline())) + self.layerlist = self.layers.keys() + self.layerlist.sort() + t2 = time.time() + print "Rendered lines in %fs" % (t2-t1) + + def transform(self, line): + orgline = line + line = line.split(";")[0] + cur = [None, None, None, None] + if len(line) > 0: + if "G92" in line: + #Recalculate delta on G92 (reset) + if("X" in line): + try: + self.delta[0] = float_from_line("X", line) + self.prev.x + except: + self.delta[0] = 0 + if("Y" in line): + try: + self.delta[1] = float_from_line("Y", line) + self.prev.y + except: + self.delta[1] = 0 + if("Z" in line): + try: + self.delta[2] = float_from_line("Z", line) + self.prev.z + except: + self.delta[2] = 0 + if("E" in line): + try: + self.delta[3] = float_from_line("E", line) + self.prev.e + except: + self.delta[3] = 0 + return None + + if "G1" in line or "G0" in line: + #Create new gcline + if("X" in line): + cur[0] = float_from_line("X", line) + self.delta[0] + if("Y" in line): + cur[1] = float_from_line("Y", line) + self.delta[1] + if("Z" in line): + cur[2] = float_from_line("Z", line) + self.delta[2] + if("E" in line): + cur[3] = float_from_line("E", line) + self.delta[3] + + if cur == [None, None, None, None]: + return None + else: + #print cur + r = gcline(cur[0], cur[1], cur[2], cur[3], self.prev, orgline=orgline) + self.prev = r + return r + return None + + def delete(self): + #for i in self.vlists: + # i.delete() + #self.vlists = [] + pass + + +def trackball(p1x, p1y, p2x, p2y, r): + TRACKBALLSIZE = r + +#float a[3]; /* Axis of rotation */ +#float phi; /* how much to rotate about axis */ +#float p1[3], p2[3], d[3]; +#float t; + + if (p1x == p2x and p1y == p2y): + return [0.0, 0.0, 0.0, 1.0] + + p1 = [p1x, p1y, project_to_sphere(TRACKBALLSIZE, p1x, p1y)] + p2 = [p2x, p2y, project_to_sphere(TRACKBALLSIZE, p2x, p2y)] + a = stltool.cross(p2, p1) + + d = map(lambda x, y: x - y, p1, p2) + t = math.sqrt(sum(map(lambda x: x * x, d))) / (2.0 * TRACKBALLSIZE) + + if (t > 1.0): + t = 1.0 + if (t < -1.0): + t = -1.0 + phi = 2.0 * math.asin(t) + + return axis_to_quat(a, phi) + + +def vec(*args): + return (GLfloat * len(args))(*args) + + +def axis_to_quat(a, phi): + #print a, phi + lena = math.sqrt(sum(map(lambda x: x * x, a))) + q = map(lambda x: x * (1 / lena), a) + q = map(lambda x: x * math.sin(phi / 2.0), q) + q.append(math.cos(phi / 2.0)) + return q + + +def build_rotmatrix(q): + m = (GLdouble * 16)() + m[0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]) + m[1] = 2.0 * (q[0] * q[1] - q[2] * q[3]) + m[2] = 2.0 * (q[2] * q[0] + q[1] * q[3]) + m[3] = 0.0 + + m[4] = 2.0 * (q[0] * q[1] + q[2] * q[3]) + m[5] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]) + m[6] = 2.0 * (q[1] * q[2] - q[0] * q[3]) + m[7] = 0.0 + + m[8] = 2.0 * (q[2] * q[0] - q[1] * q[3]) + m[9] = 2.0 * (q[1] * q[2] + q[0] * q[3]) + m[10] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]) + m[11] = 0.0 + + m[12] = 0.0 + m[13] = 0.0 + m[14] = 0.0 + m[15] = 1.0 + return m + + +def project_to_sphere(r, x, y): + d = math.sqrt(x * x + y * y) + if (d < r * 0.70710678118654752440): + return math.sqrt(r * r - d * d) + else: + t = r / 1.41421356237309504880 + return t * t / d + + +def mulquat(q1, rq): + return [q1[3] * rq[0] + q1[0] * rq[3] + q1[1] * rq[2] - q1[2] * rq[1], + q1[3] * rq[1] + q1[1] * rq[3] + q1[2] * rq[0] - q1[0] * rq[2], + q1[3] * rq[2] + q1[2] * rq[3] + q1[0] * rq[1] - q1[1] * rq[0], + q1[3] * rq[3] - q1[0] * rq[0] - q1[1] * rq[1] - q1[2] * rq[2]] + + +class TestGlPanel(GLPanel): + + def __init__(self, parent, size, id=wx.ID_ANY): + super(TestGlPanel, self).__init__(parent, id, wx.DefaultPosition, size, 0) + self.batches = [] + self.rot = 0 + self.canvas.Bind(wx.EVT_MOUSE_EVENTS, self.move) + self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.double) + self.initialized = 1 + self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.wheel) + self.parent = parent + self.initpos = None + self.dist = 200 + self.bedsize = [200, 200] + self.transv = [0, 0, -self.dist] + self.basequat = [0, 0, 0, 1] + wx.CallAfter(self.forceresize) + self.mousepos = [0, 0] + + def double(self, event): + p = event.GetPositionTuple() + sz = self.GetClientSize() + v = map(lambda m, w, b: b * m / w, p, sz, self.bedsize) + v[1] = self.bedsize[1] - v[1] + v += [300] + print v + self.add_file("../prusa/metric-prusa/x-end-idler.stl", v) + + def forceresize(self): + self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1)) + self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1)) + threading.Thread(target=self.update).start() + self.initialized = 0 + + def move_shape(self, delta): + """moves shape (selected in l, which is list ListBox of shapes) + by an offset specified in tuple delta. + Positive numbers move to (rigt, down)""" + name = self.parent.l.GetSelection() + if name == wx.NOT_FOUND: + return False + + name = self.parent.l.GetString(name) + + model = self.parent.models[name] + model.offsets = [ + model.offsets[0] + delta[0], + model.offsets[1] + delta[1], + model.offsets[2] + ] + self.Refresh() + return True + + def move(self, event): + """react to mouse actions: + no mouse: show red mousedrop + LMB: move active object, + with shift rotate viewport + RMB: nothing + with shift move viewport + """ + if event.Dragging() and event.LeftIsDown(): + if self.initpos == None: + self.initpos = event.GetPositionTuple() + else: + if not event.ShiftDown(): + currentpos = event.GetPositionTuple() + delta = ( + (currentpos[0] - self.initpos[0]), + -(currentpos[1] - self.initpos[1]) + ) + self.move_shape(delta) + self.initpos = None + return + #print self.initpos + p1 = self.initpos + self.initpos = None + p2 = event.GetPositionTuple() + sz = self.GetClientSize() + p1x = (float(p1[0]) - sz[0] / 2) / (sz[0] / 2) + p1y = -(float(p1[1]) - sz[1] / 2) / (sz[1] / 2) + p2x = (float(p2[0]) - sz[0] / 2) / (sz[0] / 2) + p2y = -(float(p2[1]) - sz[1] / 2) / (sz[1] / 2) + #print p1x,p1y,p2x,p2y + quat = trackball(p1x, p1y, p2x, p2y, -self.transv[2] / 250.0) + if self.rot: + self.basequat = mulquat(self.basequat, quat) + #else: + glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) + #self.basequat = quatx + mat = build_rotmatrix(self.basequat) + glLoadIdentity() + glTranslatef(self.transv[0], self.transv[1], 0) + glTranslatef(0, 0, self.transv[2]) + glMultMatrixd(mat) + glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) + self.rot = 1 + + elif event.ButtonUp(wx.MOUSE_BTN_LEFT): + if self.initpos is not None: + self.initpos = None + elif event.ButtonUp(wx.MOUSE_BTN_RIGHT): + if self.initpos is not None: + self.initpos = None + + elif event.Dragging() and event.RightIsDown() and event.ShiftDown(): + if self.initpos is None: + self.initpos = event.GetPositionTuple() + else: + p1 = self.initpos + p2 = event.GetPositionTuple() + sz = self.GetClientSize() + p1 = list(p1) + p2 = list(p2) + p1[1] *= -1 + p2[1] *= -1 + + self.transv = map(lambda x, y, z, c: c - self.dist * (x - y) / z, list(p1) + [0], list(p2) + [0], list(sz) + [1], self.transv) + + glLoadIdentity() + glTranslatef(self.transv[0], self.transv[1], 0) + glTranslatef(0, 0, self.transv[2]) + if(self.rot): + glMultMatrixd(build_rotmatrix(self.basequat)) + glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) + self.rot = 1 + self.initpos = None + else: + #mouse is moving without a button press + p = event.GetPositionTuple() + sz = self.GetClientSize() + v = map(lambda m, w, b: b * m / w, p, sz, self.bedsize) + v[1] = self.bedsize[1] - v[1] + self.mousepos = v + + def rotate_shape(self, angle): + """rotates acive shape + positive angle is clockwise + """ + name = self.parent.l.GetSelection() + if name == wx.NOT_FOUND: + return False + name = self.parent.l.GetString(name) + model = self.parent.models[name] + model.rot += angle + + def wheel(self, event): + """react to mouse wheel actions: + rotate object + with shift zoom viewport + """ + z = event.GetWheelRotation() + angle = 10 + if not event.ShiftDown(): + i = self.parent.l.GetSelection() + + if i < 0: + try: + self.parent.setlayerindex(z) + except: + pass + return + + if z > 0: + self.rotate_shape(angle / 2) + else: + self.rotate_shape(-angle / 2) + return + if z > 0: + self.transv[2] += angle + else: + self.transv[2] -= angle + + glLoadIdentity() + glTranslatef(*self.transv) + if(self.rot): + glMultMatrixd(build_rotmatrix(self.basequat)) + glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) + self.rot = 1 + + def keypress(self, event): + """gets keypress events and moves/rotates acive shape""" + keycode = event.GetKeyCode() + print keycode + step = 5 + angle = 18 + if event.ControlDown(): + step = 1 + angle = 1 + #h + if keycode == 72: + self.move_shape((-step, 0)) + #l + if keycode == 76: + self.move_shape((step, 0)) + #j + if keycode == 75: + self.move_shape((0, step)) + #k + if keycode == 74: + self.move_shape((0, -step)) + #[ + if keycode == 91: + self.rotate_shape(-angle) + #] + if keycode == 93: + self.rotate_shape(angle) + event.Skip() + + def update(self): + while(1): + dt = 0.05 + time.sleep(0.05) + try: + wx.CallAfter(self.Refresh) + except: + return + + def anim(self, obj): + g = 50 * 9.8 + v = 20 + dt = 0.05 + basepos = obj.offsets[2] + obj.offsets[2] += obj.animoffset + while obj.offsets[2] > -1: + time.sleep(dt) + obj.offsets[2] -= v * dt + v += g * dt + if(obj.offsets[2] < 0): + obj.scale[2] *= 1 - 3 * dt + #return + v = v / 4 + while obj.offsets[2] < basepos: + time.sleep(dt) + obj.offsets[2] += v * dt + v -= g * dt + obj.scale[2] *= 1 + 5 * dt + obj.scale[2] = 1.0 + + def create_objects(self): + '''create opengl objects when opengl is initialized''' + self.initialized = 1 + wx.CallAfter(self.Refresh) + + def drawmodel(self, m, n): + batch = pyglet.graphics.Batch() + stl = stlview(m.facets, batch=batch) + m.batch = batch + m.animoffset = 300 + #print m + #threading.Thread(target = self.anim, args = (m, )).start() + wx.CallAfter(self.Refresh) + + def update_object_resize(self): + '''called when the window recieves only if opengl is initialized''' + pass + + def draw_objects(self): + '''called in the middle of ondraw after the buffer has been cleared''' + if self.vpmat is None: + return + if not self.initialized: + self.create_objects() + + #glLoadIdentity() + #print list(self.pmat) + if self.rot == 1: + glLoadIdentity() + glMultMatrixd(self.mvmat) + else: + glLoadIdentity() + glTranslatef(*self.transv) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.2, 0.2, 0.2, 1)) + glBegin(GL_LINES) + glNormal3f(0, 0, 1) + rows = 10 + cols = 10 + zheight = 50 + for i in xrange(-rows, rows + 1): + if i % 5 == 0: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.6, 0.6, 0.6, 1)) + else: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.2, 0.2, 0.2, 1)) + glVertex3f(10 * -cols, 10 * i, 0) + glVertex3f(10 * cols, 10 * i, 0) + for i in xrange(-cols, cols + 1): + if i % 5 == 0: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.6, 0.6, 0.6, 1)) + else: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.2, 0.2, 0.2, 1)) + glVertex3f(10 * i, 10 * -rows, 0) + glVertex3f(10 * i, 10 * rows, 0) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.6, 0.6, 0.6, 1)) + glVertex3f(10 * -cols, 10 * -rows, 0) + glVertex3f(10 * -cols, 10 * -rows, zheight) + glVertex3f(10 * cols, 10 * rows, 0) + glVertex3f(10 * cols, 10 * rows, zheight) + glVertex3f(10 * cols, 10 * -rows, 0) + glVertex3f(10 * cols, 10 * -rows, zheight) + glVertex3f(10 * -cols, 10 * rows, 0) + glVertex3f(10 * -cols, 10 * rows, zheight) + + glVertex3f(10 * -cols, 10 * rows, zheight) + glVertex3f(10 * cols, 10 * rows, zheight) + glVertex3f(10 * cols, 10 * rows, zheight) + glVertex3f(10 * cols, 10 * -rows, zheight) + glVertex3f(10 * cols, 10 * -rows, zheight) + glVertex3f(10 * -cols, 10 * -rows, zheight) + glVertex3f(10 * -cols, 10 * -rows, zheight) + glVertex3f(10 * -cols, 10 * rows, zheight) + + glEnd() + glPushMatrix() + glTranslatef(self.mousepos[0] - self.bedsize[0] / 2, self.mousepos[1] - self.bedsize[1] / 2, 0) + glBegin(GL_TRIANGLES) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(1, 0, 0, 1)) + glNormal3f(0, 0, 1) + glVertex3f(2, 2, 0) + glVertex3f(-2, 2, 0) + glVertex3f(-2, -2, 0) + glVertex3f(2, -2, 0) + glVertex3f(2, 2, 0) + glVertex3f(-2, -2, 0) + glEnd() + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.3, 0.7, 0.5, 1)) + #glTranslatef(0, 40, 0) + glPopMatrix() + glPushMatrix() + glTranslatef(-100, -100, 0) + glEnable(GL_LINE_SMOOTH) + glEnable(GL_BLEND) + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + glHint (GL_LINE_SMOOTH_HINT, GL_NICEST) + glLineWidth (1.5) + + for i in self.parent.models.values(): + glPushMatrix() + glTranslatef(*(i.offsets)) + glRotatef(i.rot, 0.0, 0.0, 1.0) + glScalef(*i.scale) + #glEnable(GL_COLOR_MATERIAL) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.93, 0.37, 0.25, 1)) + [i.gc.layers[j].draw() for j in i.gc.layerlist if j < i.curlayer] + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.5, 0.6, 0.9, 1)) + i.gc.layers[i.curlayer].draw() + + glPopMatrix() + glPopMatrix() + #print "drawn batch" + + +class GCFrame(wx.Frame): + '''A simple class for using OpenGL with wxPython.''' + + def __init__(self, parent, ID, title, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE): + super(GCFrame, self).__init__(parent, ID, title, pos, (size[0] + 150, size[1]), style) + + class d: + def GetSelection(self): + return wx.NOT_FOUND + self.p = self + m = d() + m.offsets = [0, 0, 0] + m.rot = 0 + m.curlayer = -1 + m.scale = [1.0, 1.0, 1.0] + m.batch = pyglet.graphics.Batch() + m.gc = gcview([], batch=m.batch) + self.models = {"": m} + self.l = d() + self.modelindex = 0 + self.GLPanel1 = TestGlPanel(self, size) + + def addfile(self, gcode=[]): + self.models[""].gc.delete() + self.models[""].gc = gcview(gcode, batch=self.models[""].batch) + self.setlayerindex(None) + + def clear(self): + self.models[""].gc.delete() + self.models[""].gc = gcview([], batch=self.models[""].batch) + + def Show(self, arg=True): + wx.Frame.Show(self, arg) + self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1)) + self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1)) + self.Refresh() + wx.FutureCall(500, self.GLPanel1.forceresize) + #threading.Thread(target = self.update).start() + #self.initialized = 0 + + def setlayerindex(self, z): + m = self.models[""] + mlk = m.gc.layerlist + if z > 0 and self.modelindex < len(mlk) - 1: + self.modelindex += 1 + elif z < 0 and self.modelindex > 0: + self.modelindex -= 1 + elif z is None: + self.modelindex = len(mlk)-1 + + m.curlayer = mlk[self.modelindex] + wx.CallAfter(self.SetTitle, "Gcode view, shift to move. Layer %d, Z = %f" % (self.modelindex, m.curlayer)) + + +def main(): + app = wx.App(redirect=False) + frame = GCFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size=(400, 400)) + import sys + for gcfile in sys.argv: + if "gcode" in gcfile: + print gcfile + frame.addfile(list(open(gcfile))) + #frame = wx.Frame(None, -1, "GL Window", size=(400, 400)) + #panel = TestGlPanel(frame, size=(300,300)) + frame.Show(True) + app.MainLoop() + app.Destroy() + +if __name__ == "__main__": + #import cProfile + #print cProfile.run("main()") + main()