Commit 77ac4453 authored by Guillaume Seguin's avatar Guillaume Seguin

Rework gcview to make it cleaner, better and faster

parent bf64e797
#!/usr/bin/python #!/usr/bin/python
# This file is part of the Printrun suite. # This file is part of the Printrun suite.
# #
# Printrun is free software: you can redistribute it and/or modify # Printrun is free software: you can redistribute it and/or modify
...@@ -16,43 +17,39 @@ ...@@ -16,43 +17,39 @@
import os import os
import math import math
import stltool
import wx import wx
from wx import glcanvas from wx import glcanvas
import time import gcoder
import threading
import pyglet import pyglet
pyglet.options['shadow_window'] = False pyglet.options['debug_gl'] = True
pyglet.options['debug_gl'] = False
from pyglet.gl import *
import stltool
import threading from pyglet.gl import *
from pyglet import gl
from pyglet.graphics.vertexbuffer import create_buffer
from printrun.libtatlin import actors
class GLPanel(wx.Panel): class wxGLPanel(wx.Panel):
'''A simple class for using OpenGL with wxPython.''' '''A simple class for using OpenGL with wxPython.'''
def __init__(self, parent, id, pos = wx.DefaultPosition, def __init__(self, parent, id, pos = wx.DefaultPosition,
size = wx.DefaultSize, style = 0): size = wx.DefaultSize, style = 0):
# Forcing a no full repaint to stop flickering # Forcing a no full repaint to stop flickering
style = style | wx.NO_FULL_REPAINT_ON_RESIZE style = style | wx.NO_FULL_REPAINT_ON_RESIZE
#call super function super(wxGLPanel, self).__init__(parent, id, pos, size, style)
super(GLPanel, self).__init__(parent, id, pos, size, style)
#init gl canvas data
self.GLinitialized = False self.GLinitialized = False
attribList = (glcanvas.WX_GL_RGBA, # RGBA attribList = (glcanvas.WX_GL_RGBA, # RGBA
glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered
glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit
# Create the canvas
self.sizer = wx.BoxSizer(wx.HORIZONTAL) self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.canvas = glcanvas.GLCanvas(self, attribList = attribList) self.canvas = glcanvas.GLCanvas(self, attribList = attribList)
self.sizer.Add(self.canvas, 1, wx.EXPAND) self.sizer.Add(self.canvas, 1, wx.EXPAND)
self.SetSizer(self.sizer) self.SetSizer(self.sizer)
#self.sizer.Fit(self) self.sizer.Fit(self)
self.Layout()
# bind events # bind events
self.canvas.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent) self.canvas.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent)
...@@ -89,12 +86,12 @@ class GLPanel(wx.Panel): ...@@ -89,12 +86,12 @@ class GLPanel(wx.Panel):
self.OnReshape(size.width, size.height) self.OnReshape(size.width, size.height)
self.canvas.Refresh(False) self.canvas.Refresh(False)
event.Skip() event.Skip()
#wx.CallAfter(self.Refresh)
def processPaintEvent(self, event): def processPaintEvent(self, event):
'''Process the drawing event.''' '''Process the drawing event.'''
self.canvas.SetCurrent() self.canvas.SetCurrent()
# This is a 'perfect' time to initialize OpenGL ... only if we need to
if not self.GLinitialized: if not self.GLinitialized:
self.OnInitGL() self.OnInitGL()
self.GLinitialized = True self.GLinitialized = True
...@@ -104,7 +101,7 @@ class GLPanel(wx.Panel): ...@@ -104,7 +101,7 @@ class GLPanel(wx.Panel):
def Destroy(self): def Destroy(self):
#clean up the pyglet OpenGL context #clean up the pyglet OpenGL context
#self.pygletcontext.destroy() self.pygletcontext.destroy()
#call the super method #call the super method
super(wx.Panel, self).Destroy() super(wx.Panel, self).Destroy()
...@@ -116,51 +113,23 @@ class GLPanel(wx.Panel): ...@@ -116,51 +113,23 @@ class GLPanel(wx.Panel):
#create a pyglet context for this panel #create a pyglet context for this panel
self.pmat = (GLdouble * 16)() self.pmat = (GLdouble * 16)()
self.mvmat = (GLdouble * 16)() self.mvmat = (GLdouble * 16)()
self.pygletcontext = Context(current_context) self.pygletcontext = gl.Context(gl.current_context)
self.pygletcontext.set_current() self.pygletcontext.set_current()
self.dist = 1000 self.dist = 1000
self.vpmat = None self.vpmat = None
#normal gl init #normal gl init
glClearColor(0, 0, 0, 1) glClearColor(0.98, 0.98, 0.78, 1)
glColor3f(1, 0, 0) glClearDepth(1.0) # set depth value to 1
glDepthFunc(GL_LEQUAL)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_DEPTH_TEST) glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE) glEnable(GL_CULL_FACE)
# Uncomment this line for a wireframe view glEnable(GL_BLEND)
#glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
self.OnReshape(*self.GetClientSize())
# 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): def OnReshape(self, width, height):
'''Reshape the OpenGL viewport based on the dimensions of the window.''' '''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) glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION) glMatrixMode(GL_PROJECTION)
glLoadIdentity() glLoadIdentity()
...@@ -170,8 +139,6 @@ class GLPanel(wx.Panel): ...@@ -170,8 +139,6 @@ class GLPanel(wx.Panel):
#pyglet stuff #pyglet stuff
self.vpmat = (GLint * 4)(0, 0, *list(self.GetClientSize())) self.vpmat = (GLint * 4)(0, 0, *list(self.GetClientSize()))
glGetDoublev(GL_PROJECTION_MATRIX, self.pmat) glGetDoublev(GL_PROJECTION_MATRIX, self.pmat)
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
#glMatrixMode(GL_PROJECTION)
# Wrap text to the width of the window # Wrap text to the width of the window
if self.GLinitialized: if self.GLinitialized:
...@@ -180,13 +147,9 @@ class GLPanel(wx.Panel): ...@@ -180,13 +147,9 @@ class GLPanel(wx.Panel):
def OnDraw(self, *args, **kwargs): def OnDraw(self, *args, **kwargs):
"""Draw the window.""" """Draw the window."""
#clear the context
self.canvas.SetCurrent()
self.pygletcontext.set_current() self.pygletcontext.set_current()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
#draw objects
self.draw_objects() self.draw_objects()
#update screen
self.SwapBuffers() self.SwapBuffers()
#========================================================================== #==========================================================================
...@@ -204,262 +167,8 @@ class GLPanel(wx.Panel): ...@@ -204,262 +167,8 @@ class GLPanel(wx.Panel):
'''called in the middle of ondraw after the buffer has been cleared''' '''called in the middle of ondraw after the buffer has been cleared'''
pass 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
self.length = 0
class gcline(object):
"""gcode move line
Once initialised, it knows its position, length and extrusion ratio
Returns lines into gcview batch()
"""
def __init__(self, x = None, y = None, z = None, e = None, f = 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.f = f
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 and feedrate %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.f,
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, upper_limit = None, lower_limit = 0, max_feedrate = 0):
if self.extrusion_ratio == 0:
return [255, 255, 255, 0, 0, 0]
else:
blue_color = 0
green_color = 0
if upper_limit is not None:
if self.extrusion_ratio <= lower_limit:
blue_color = 0
else:
blue_color = int ((self.extrusion_ratio - lower_limit) / (upper_limit - lower_limit) * 255)
else:
blue_color = 0
if max_feedrate > 0 and self.f > 0:
green_color = int((self.f/max_feedrate) * 255)
if green_color > 255:
green_color = 255
if green_color < 0:
green_color = 0
if blue_color > 255:
blue_color = 255
if blue_color < 0:
blue_color = 0
return[255, green_color, blue_color, 128, green_color, blue_color/4]
def float_from_line(axe, line):
return float(line.split(axe)[1].split(" ")[0])
class gcThreadRenderer(threading.Thread):
def __init__(self, gcview, lines):
threading.Thread.__init__(self)
self.gcview = gcview
self.lines = lines
print "q init"
def run(self):
for line in self.lines:
layer_name = line.z
if line.z not in self.gcview.layers:
self.gcview.layers[line.z] = pyglet.graphics.Batch()
self.gcview.layerlist = self.gcview.layers.keys()
self.gcview.layerlist.sort()
self.gcview.layers[line.z].add(2, GL_LINES, None, ("v3f", line.glline()), ("c3B", line.glcolor(self.gcview.upper_limit, self.gcview.lower_limit, self.gcview.max_feedrate)))
self.gcview.t2 = time.time()
print "Rendered lines in %fs" % (self.gcview.t2-self.gcview.t1)
class gcview(object):
"""gcode visualiser
Holds opengl objects for all layers
"""
def __init__(self, lines, batch, w = 0.5, h = 0.5):
if len(lines) == 0:
return
print "Loading %s lines" % (len(lines))
#End pos of previous mode
self.prev = gcpoint()
# Correction for G92 moves
self.delta = [0, 0, 0, 0]
self.layers = {}
self.t0 = time.time()
self.lastf = 0
lines = [self.transform(i) for i in lines]
lines = [i for i in lines if i is not None]
self.t1 = time.time()
print "transformed %s lines in %fs" % (len(lines), self.t1- self.t0)
self.upper_limit = 0
self.lower_limit = None
self.max_feedrate = 0
for line in lines:
if line.extrusion_ratio and line.length > 0.005: #lines shorter than 0.003 can have large extrusion ratio
if line.extrusion_ratio > self.upper_limit:
self.upper_limit = line.extrusion_ratio
if self.lower_limit is None or line.extrusion_ratio < self.lower_limit:
self.lower_limit = line.extrusion_ratio
if line.f > self.max_feedrate:
self.max_feedrate = line.f
#print upper_limit, lower_limit
#self.render_gl(lines)
q = gcThreadRenderer(self, lines)
q.setDaemon(True)
q.start()
def transform(self, line):
"""transforms line of gcode into gcline object (or None if its not move)
Tracks coordinates across resets in self.delta
"""
orgline = line
line = line.split(";")[0]
cur = [None, 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 "F" in line:
cur[4] = float_from_line("F", line)
if cur == [None, None, None, None, None]:
return None
else:
#print cur
if cur[4] is None:
cur[4] = self.lastf
else:
self.lastf = cur[4]
r = gcline(x = cur[0], y = cur[1], z = cur[2], e = cur[3], f = cur[4], prev_gcline = 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): def trackball(p1x, p1y, p2x, p2y, r):
TRACKBALLSIZE = r TRACKBALLSIZE = r
#float a[3]; /* Axis of rotation */ #float a[3]; /* Axis of rotation */
#float phi; /* how much to rotate about axis */ #float phi; /* how much to rotate about axis */
#float p1[3], p2[3], d[3]; #float p1[3], p2[3], d[3];
...@@ -537,15 +246,15 @@ def mulquat(q1, rq): ...@@ -537,15 +246,15 @@ def mulquat(q1, rq):
q1[3] * rq[3] - q1[0] * rq[0] - q1[1] * rq[1] - q1[2] * rq[2]] q1[3] * rq[3] - q1[0] * rq[0] - q1[1] * rq[1] - q1[2] * rq[2]]
class TestGlPanel(GLPanel): class GcodeViewPanel(wxGLPanel):
def __init__(self, parent, size, id = wx.ID_ANY): def __init__(self, parent, id = wx.ID_ANY):
super(TestGlPanel, self).__init__(parent, id, wx.DefaultPosition, size, 0) super(GcodeViewPanel, self).__init__(parent, id, wx.DefaultPosition, wx.DefaultSize, 0)
self.batches = [] self.batches = []
self.rot = 0 self.rot = 0
self.canvas.Bind(wx.EVT_MOUSE_EVENTS, self.move) self.canvas.Bind(wx.EVT_MOUSE_EVENTS, self.move)
self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.double) self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.double)
self.initialized = 1 self.initialized = 0
self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.wheel) self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.wheel)
self.parent = parent self.parent = parent
self.initpos = None self.initpos = None
...@@ -553,64 +262,67 @@ class TestGlPanel(GLPanel): ...@@ -553,64 +262,67 @@ class TestGlPanel(GLPanel):
self.bedsize = [200, 200] self.bedsize = [200, 200]
self.transv = [0, 0, -self.dist] self.transv = [0, 0, -self.dist]
self.basequat = [0, 0, 0, 1] self.basequat = [0, 0, 0, 1]
wx.CallAfter(self.forceresize)
self.mousepos = [0, 0] self.mousepos = [0, 0]
def create_objects(self):
'''create opengl objects when opengl is initialized'''
for obj in self.parent.objects:
if obj.model and obj.model.loaded and not obj.model.initialized:
obj.model.init()
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
self.create_objects()
#glLoadIdentity()
#print list(self.pmat)
if self.rot == 1:
glLoadIdentity()
glMultMatrixd(self.mvmat)
else:
glLoadIdentity()
glTranslatef(*self.transv)
glPushMatrix()
glTranslatef(-self.parent.platform.width/2, -self.parent.platform.depth/2, 0)
for obj in self.parent.objects:
if not obj.model or not obj.model.loaded or not obj.model.initialized:
continue
glPushMatrix()
glTranslatef(*(obj.offsets))
glRotatef(obj.rot, 0.0, 0.0, 1.0)
glScalef(*obj.scale)
obj.model.display()
glPopMatrix()
glPopMatrix()
def double(self, event): def double(self, event):
p = event.GetPositionTuple() p = event.GetPositionTuple()
sz = self.GetClientSize() sz = self.GetClientSize()
v = map(lambda m, w, b: b * m / w, p, sz, self.bedsize) v = map(lambda m, w, b: b * m / w, p, sz, self.bedsize)
v[1] = self.bedsize[1] - v[1] v[1] = self.bedsize[1] - v[1]
v += [300] v += [300]
print v print "Double-click at "+str(v)+" in "
self.add_file("../prusa/metric-prusa/x-end-idler.stl", v) print self
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): def move(self, event):
"""react to mouse actions: """react to mouse actions:
no mouse: show red mousedrop no mouse: show red mousedrop
LMB: move active object, LMB: rotate viewport
with shift rotate viewport RMB: move viewport
RMB: nothing
with shift move viewport
""" """
if event.Dragging() and event.LeftIsDown(): if event.Dragging() and event.LeftIsDown():
if self.initpos == None: if self.initpos == None:
self.initpos = event.GetPositionTuple() self.initpos = event.GetPositionTuple()
else: 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 #print self.initpos
p1 = self.initpos p1 = self.initpos
self.initpos = None self.initpos = None
...@@ -642,7 +354,7 @@ class TestGlPanel(GLPanel): ...@@ -642,7 +354,7 @@ class TestGlPanel(GLPanel):
if self.initpos is not None: if self.initpos is not None:
self.initpos = None self.initpos = None
elif event.Dragging() and event.RightIsDown() and event.ShiftDown(): elif event.Dragging() and event.RightIsDown():
if self.initpos is None: if self.initpos is None:
self.initpos = event.GetPositionTuple() self.initpos = event.GetPositionTuple()
else: else:
...@@ -659,51 +371,35 @@ class TestGlPanel(GLPanel): ...@@ -659,51 +371,35 @@ class TestGlPanel(GLPanel):
glLoadIdentity() glLoadIdentity()
glTranslatef(self.transv[0], self.transv[1], 0) glTranslatef(self.transv[0], self.transv[1], 0)
glTranslatef(0, 0, self.transv[2]) glTranslatef(0, 0, self.transv[2])
if(self.rot): if self.rot:
glMultMatrixd(build_rotmatrix(self.basequat)) glMultMatrixd(build_rotmatrix(self.basequat))
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
self.rot = 1 self.rot = 1
self.initpos = None self.initpos = None
else: else:
#mouse is moving without a button press return
p = event.GetPositionTuple() wx.CallAfter(self.Refresh)
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): def wheel(self, event):
"""react to mouse wheel actions: """react to mouse wheel actions:
rotate object without shift: set max layer
with shift zoom viewport with shift: zoom viewport
""" """
z = event.GetWheelRotation() z = event.GetWheelRotation()
angle = 10 angle = 10
if not event.ShiftDown(): if event.ShiftDown():
i = self.parent.l.GetSelection() if not self.parent.model:
if i < 0:
try:
self.parent.setlayerindex(z)
except:
pass
return return
if z > 0: if z > 0:
self.rotate_shape(angle / 2) max_layers = self.parent.model.max_layers
current_layer = self.parent.model.num_layers_to_draw
new_layer = min(max_layers, current_layer + 1)
self.parent.model.num_layers_to_draw = new_layer
else: else:
self.rotate_shape(-angle / 2) current_layer = self.parent.model.num_layers_to_draw
new_layer = max(1, current_layer - 1)
self.parent.model.num_layers_to_draw = new_layer
wx.CallAfter(self.Refresh)
return return
if z > 0: if z > 0:
self.transv[2] += angle self.transv[2] += angle
...@@ -712,10 +408,11 @@ class TestGlPanel(GLPanel): ...@@ -712,10 +408,11 @@ class TestGlPanel(GLPanel):
glLoadIdentity() glLoadIdentity()
glTranslatef(*self.transv) glTranslatef(*self.transv)
if(self.rot): if self.rot:
glMultMatrixd(build_rotmatrix(self.basequat)) glMultMatrixd(build_rotmatrix(self.basequat))
glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat) glGetDoublev(GL_MODELVIEW_MATRIX, self.mvmat)
self.rot = 1 self.rot = 1
wx.CallAfter(self.Refresh)
def keypress(self, event): def keypress(self, event):
"""gets keypress events and moves/rotates acive shape""" """gets keypress events and moves/rotates acive shape"""
...@@ -745,268 +442,69 @@ class TestGlPanel(GLPanel): ...@@ -745,268 +442,69 @@ class TestGlPanel(GLPanel):
if keycode == 93: if keycode == 93:
self.rotate_shape(angle) self.rotate_shape(angle)
event.Skip() 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) wx.CallAfter(self.Refresh)
def drawmodel(self, m, n): class GCObject(object):
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): def __init__(self, model):
'''called when the window recieves only if opengl is initialized''' self.offsets = [0, 0, 0]
pass self.rot = 0
self.curlayer = 0.0
def draw_objects(self): self.scale = [1.0, 1.0, 1.0]
'''called in the middle of ondraw after the buffer has been cleared''' self.batch = pyglet.graphics.Batch()
if self.vpmat is None: self.model = model
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)
#glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.93, 0.37, 0.25, 1))
glEnable(GL_COLOR_MATERIAL)
if i.curlayer == -1:
# curlayer == -1 means we are over the top.
glLineWidth (0.8)
[i.gc.layers[j].draw() for j in i.gc.layerlist]
else:
glLineWidth (0.6)
tmpindex = i.gc.layerlist.index(i.curlayer)
if tmpindex >= 5:
thin_layer = i.gc.layerlist[tmpindex - 5]
[i.gc.layers[j].draw() for j in i.gc.layerlist if j <= thin_layer]
if tmpindex > 4:
glLineWidth (0.9)
i.gc.layers[i.gc.layerlist[tmpindex - 4]].draw()
if tmpindex > 3:
glLineWidth (1.1)
i.gc.layers[i.gc.layerlist[tmpindex - 3]].draw()
if tmpindex > 2:
glLineWidth (1.3)
i.gc.layers[i.gc.layerlist[tmpindex - 2]].draw()
if tmpindex > 1:
glLineWidth (2.2)
i.gc.layers[i.gc.layerlist[tmpindex - 1]].draw()
glLineWidth (3.5)
i.gc.layers[i.curlayer].draw()
glLineWidth (1.5)
glDisable(GL_COLOR_MATERIAL)
glPopMatrix()
glPopMatrix()
#print "drawn batch"
def GetSelection(self):
return wx.NOT_FOUND
class GCFrame(wx.Frame): class GcodeViewFrame(wx.Frame):
'''A simple class for using OpenGL with wxPython.''' '''A simple class for using OpenGL with wxPython.'''
def __init__(self, parent, ID, title, pos = wx.DefaultPosition, def __init__(self, parent, ID, title, build_dimensions, pos = wx.DefaultPosition,
size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE): size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE):
super(GCFrame, self).__init__(parent, ID, title, pos, (size[0] + 150, size[1]), style) super(GcodeViewFrame, self).__init__(parent, ID, title, pos, size, style)
self.p = self # Hack for backwards compatibility with gviz API
class d: self.platform = actors.Platform(build_dimensions)
def GetSelection(self): self.model = None
return wx.NOT_FOUND self.objects = [GCObject(self.platform), GCObject(None)]
self.p = self self.glpanel = GcodeViewPanel(self)
m = d()
m.offsets = [0, 0, 0] def addfile(self, gcode = None):
m.rot = 0 self.model = actors.GcodeModel()
m.curlayer = -1 if gcode:
m.scale = [1.0, 1.0, 1.0] self.model.load_data(gcode)
m.batch = pyglet.graphics.Batch() self.objects[-1].model = self.model
m.gc = gcview([], batch = m.batch) wx.CallAfter(self.Refresh)
self.models = {"GCODE": m}
self.l = d()
self.modelindex = 0
self.GLPanel1 = TestGlPanel(self, size)
def addfile(self, gcode = []):
self.models["GCODE"].gc.delete()
self.models["GCODE"].gc = gcview(gcode, batch = self.models["GCODE"].batch)
self.setlayerindex(None)
def clear(self): def clear(self):
self.models["GCODE"].gc.delete() self.model = None
self.models["GCODE"].gc = gcview([], batch = self.models["GCODE"].batch) self.objects[-1].model = None
wx.CallAfter(self.Refresh)
def Show(self, arg = True): def Show(self, arg = True):
wx.Frame.Show(self, arg) wx.Frame.Show(self, arg)
self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1)) self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1))
self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1)) self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1))
self.Refresh() self.Refresh()
wx.FutureCall(500, self.GLPanel1.forceresize)
#threading.Thread(target = self.update).start()
#self.initialized = 0
def setlayerindex(self, z): def setlayerindex(self, z):
m = self.models["GCODE"] model = self.objects[-1].model
try: if not model:
mlk = m.gc.layerlist return
except: mlk = sorted(m.gc.layers.keys())
mlk = [] if z > 0 and self.modelindex < len(mlk) - 1:
if z is None: self.modelindex += 1
self.modelindex = -1 if z < 0 and self.modelindex > 0:
elif z > 0: self.modelindex -= 1
if self.modelindex < len(mlk) - 1: m.curlayer = mlk[self.modelindex]
if self.modelindex > -1: wx.CallAfter(self.SetTitle, "Gcode view, shift to move. Layer %d, Z = %f" % (self.modelindex, m.curlayer))
self.modelindex += 1
else:
self.modelindex = -1
elif z < 0:
if self.modelindex > 0:
self.modelindex -= 1
elif self.modelindex == -1:
self.modelindex = len(mlk)
if self.modelindex >= 0:
m.curlayer = mlk[self.modelindex]
wx.CallAfter(self.SetTitle, "Gcode view, shift to move. Layer %d/%d, Z = %f" % (self.modelindex, len(mlk), m.curlayer))
else:
m.curlayer = -1
wx.CallAfter(self.SetTitle, "Gcode view, shift to move view, mousewheel to set layer")
def main(): if __name__ == "__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 import sys
for filename in sys.argv: app = wx.App(redirect = False)
if ".gcode" in filename: build_dimensions = [200, 200, 100, 0, 0, 0]
frame.addfile(list(open(filename))) frame = GcodeViewFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size = (400, 400), build_dimensions = build_dimensions)
elif ".stl" in filename: frame.addfile(gcoder.GCode(open(sys.argv[1])))
#TODO: add stl here
pass
#frame = wx.Frame(None, -1, "GL Window", size = (400, 400))
#panel = TestGlPanel(frame, size = (300, 300))
frame.Show(True) frame.Show(True)
app.MainLoop() app.MainLoop()
app.Destroy() app.Destroy()
if __name__ == "__main__":
#import cProfile
#print cProfile.run("main()")
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment