2012-01-24 19:13:22 +00:00
|
|
|
#!/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
|
|
|
|
|
2012-01-27 22:14:20 +00:00
|
|
|
import threading
|
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
class GLPanel(wx.Panel):
|
|
|
|
'''A simple class for using OpenGL with wxPython.'''
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, parent, id, pos = wx.DefaultPosition,
|
|
|
|
size = wx.DefaultSize, style = 0):
|
2012-01-24 19:13:22 +00:00
|
|
|
# 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)
|
2012-08-08 07:38:48 +00:00
|
|
|
self.canvas = glcanvas.GLCanvas(self, attribList = attribList)
|
2012-01-24 19:13:22 +00:00
|
|
|
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"""
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, x = 0, y = 0, z = 0, e = 0):
|
2012-01-25 13:50:07 +00:00
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
self.z = z
|
|
|
|
self.e = e
|
|
|
|
self.length = 0
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
class gcline(object):
|
|
|
|
"""gcode move line
|
2012-08-08 07:38:48 +00:00
|
|
|
Once initialised, it knows its position, length and extrusion ratio
|
2012-01-25 13:13:12 +00:00
|
|
|
Returns lines into gcview batch()
|
2012-01-24 19:13:22 +00:00
|
|
|
"""
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, x = None, y = None, z = None, e = None, f = None, prev_gcline = None, orgline = False):
|
2012-01-24 19:13:22 +00:00
|
|
|
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)
|
|
|
|
|
2012-01-25 20:58:07 +00:00
|
|
|
self.f = f
|
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
self.orgline = orgline
|
|
|
|
|
|
|
|
self.calc_delta()
|
|
|
|
self.calc_len()
|
|
|
|
|
|
|
|
def __str__(self):
|
2012-01-27 22:14:20 +00:00
|
|
|
return u"line from %s,%s,%s to %s,%s,%s with extrusion ratio %s and feedrate %s\n%s" % (
|
2012-01-24 19:13:22 +00:00
|
|
|
self.prev_gcline.x,
|
|
|
|
self.prev_gcline.y,
|
|
|
|
self.prev_gcline.z,
|
|
|
|
self.x,
|
|
|
|
self.y,
|
|
|
|
self.z,
|
|
|
|
self.extrusion_ratio,
|
2012-01-25 20:58:07 +00:00
|
|
|
self.f,
|
2012-01-24 19:13:22 +00:00
|
|
|
self.orgline,
|
|
|
|
)
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def calc_delta(self, prev_gcline = None):
|
2012-01-24 19:13:22 +00:00
|
|
|
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,
|
|
|
|
]
|
2012-01-25 20:58:07 +00:00
|
|
|
def glcolor(self, upper_limit = None, lower_limit = 0, max_feedrate = 0):
|
2012-01-24 19:13:22 +00:00
|
|
|
if self.extrusion_ratio == 0:
|
2012-08-08 07:58:09 +00:00
|
|
|
return [255, 255, 255, 0, 0, 0]
|
2012-01-24 19:13:22 +00:00
|
|
|
else:
|
2012-01-25 20:58:07 +00:00
|
|
|
blue_color = 0
|
|
|
|
green_color = 0
|
2012-01-25 13:50:07 +00:00
|
|
|
if upper_limit is not None:
|
|
|
|
if self.extrusion_ratio <= lower_limit:
|
2012-01-25 20:58:07 +00:00
|
|
|
blue_color = 0
|
2012-01-25 13:50:07 +00:00
|
|
|
else:
|
2012-01-25 20:58:07 +00:00
|
|
|
blue_color = int ((self.extrusion_ratio - lower_limit) / (upper_limit - lower_limit) * 255)
|
2012-01-25 13:50:07 +00:00
|
|
|
else:
|
2012-01-25 20:58:07 +00:00
|
|
|
blue_color = 0
|
|
|
|
if max_feedrate > 0 and self.f > 0:
|
|
|
|
green_color = int((self.f/max_feedrate) * 255)
|
2012-01-25 13:50:07 +00:00
|
|
|
|
2012-01-25 20:58:07 +00:00
|
|
|
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
|
2012-08-08 07:38:48 +00:00
|
|
|
return[255, green_color, blue_color, 128, green_color, blue_color/4]
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
def float_from_line(axe, line):
|
|
|
|
return float(line.split(axe)[1].split(" ")[0])
|
|
|
|
|
2012-01-27 22:14:20 +00:00
|
|
|
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)
|
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
class gcview(object):
|
2012-01-25 13:13:12 +00:00
|
|
|
"""gcode visualiser
|
|
|
|
Holds opengl objects for all layers
|
|
|
|
"""
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, lines, batch, w = 0.5, h = 0.5):
|
2012-01-27 22:14:20 +00:00
|
|
|
if len(lines) == 0:
|
|
|
|
return
|
|
|
|
print "Loading %s lines" % (len(lines))
|
2012-01-24 19:13:22 +00:00
|
|
|
#End pos of previous mode
|
|
|
|
self.prev = gcpoint()
|
|
|
|
# Correction for G92 moves
|
|
|
|
self.delta = [0, 0, 0, 0]
|
|
|
|
self.layers = {}
|
2012-01-27 22:14:20 +00:00
|
|
|
self.t0 = time.time()
|
2012-01-25 20:58:07 +00:00
|
|
|
self.lastf = 0
|
2012-01-24 19:13:22 +00:00
|
|
|
lines = [self.transform(i) for i in lines]
|
2012-01-25 13:50:07 +00:00
|
|
|
lines = [i for i in lines if i is not None]
|
2012-01-27 22:14:20 +00:00
|
|
|
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
|
2012-01-25 13:50:07 +00:00
|
|
|
for line in lines:
|
2012-01-25 20:58:07 +00:00
|
|
|
if line.extrusion_ratio and line.length > 0.005: #lines shorter than 0.003 can have large extrusion ratio
|
2012-01-27 22:14:20 +00:00
|
|
|
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
|
2012-01-25 13:50:07 +00:00
|
|
|
#print upper_limit, lower_limit
|
2012-01-27 22:14:20 +00:00
|
|
|
#self.render_gl(lines)
|
|
|
|
q = gcThreadRenderer(self, lines)
|
|
|
|
q.setDaemon(True)
|
|
|
|
q.start()
|
|
|
|
|
|
|
|
|
2012-01-25 13:50:07 +00:00
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
def transform(self, line):
|
2012-01-25 13:13:12 +00:00
|
|
|
"""transforms line of gcode into gcline object (or None if its not move)
|
|
|
|
Tracks coordinates across resets in self.delta
|
|
|
|
"""
|
2012-01-24 19:13:22 +00:00
|
|
|
orgline = line
|
|
|
|
line = line.split(";")[0]
|
2012-01-25 20:58:07 +00:00
|
|
|
cur = [None, None, None, None, None]
|
2012-01-24 19:13:22 +00:00
|
|
|
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]
|
2012-01-25 20:58:07 +00:00
|
|
|
if "F" in line:
|
|
|
|
cur[4] = float_from_line("F", line)
|
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
|
2012-01-25 20:58:07 +00:00
|
|
|
if cur == [None, None, None, None, None]:
|
2012-01-24 19:13:22 +00:00
|
|
|
return None
|
|
|
|
else:
|
|
|
|
#print cur
|
2012-01-25 20:58:07 +00:00
|
|
|
if cur[4] is None:
|
|
|
|
cur[4] = self.lastf
|
|
|
|
else:
|
|
|
|
self.lastf = cur[4]
|
|
|
|
|
2012-08-08 07:58:09 +00:00
|
|
|
r = gcline(x = cur[0], y = cur[1], z = cur[2], e = cur[3], f = cur[4], prev_gcline = self.prev, orgline = orgline)
|
2012-01-24 19:13:22 +00:00
|
|
|
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):
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, parent, size, id = wx.ID_ANY):
|
2012-01-24 19:13:22 +00:00
|
|
|
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))
|
2012-08-08 07:38:48 +00:00
|
|
|
threading.Thread(target = self.update).start()
|
2012-01-24 19:13:22 +00:00
|
|
|
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)
|
2012-08-08 07:38:48 +00:00
|
|
|
#print p1x, p1y, p2x, p2y
|
2012-01-24 19:13:22 +00:00
|
|
|
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()
|
2012-08-08 07:38:48 +00:00
|
|
|
stl = stlview(m.facets, batch = batch)
|
2012-01-24 19:13:22 +00:00
|
|
|
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)
|
2012-01-25 12:44:07 +00:00
|
|
|
#glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.93, 0.37, 0.25, 1))
|
|
|
|
glEnable(GL_COLOR_MATERIAL)
|
|
|
|
|
2012-01-27 22:14:20 +00:00
|
|
|
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()
|
2012-01-25 12:44:07 +00:00
|
|
|
glLineWidth (1.5)
|
|
|
|
|
|
|
|
glDisable(GL_COLOR_MATERIAL)
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
glPopMatrix()
|
|
|
|
glPopMatrix()
|
|
|
|
#print "drawn batch"
|
|
|
|
|
|
|
|
|
|
|
|
class GCFrame(wx.Frame):
|
|
|
|
'''A simple class for using OpenGL with wxPython.'''
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, parent, ID, title, pos = wx.DefaultPosition,
|
|
|
|
size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE):
|
2012-01-24 19:13:22 +00:00
|
|
|
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()
|
2012-08-08 07:38:48 +00:00
|
|
|
m.gc = gcview([], batch = m.batch)
|
2012-01-25 13:13:12 +00:00
|
|
|
self.models = {"GCODE": m}
|
2012-01-24 19:13:22 +00:00
|
|
|
self.l = d()
|
|
|
|
self.modelindex = 0
|
|
|
|
self.GLPanel1 = TestGlPanel(self, size)
|
|
|
|
|
2012-08-08 07:58:09 +00:00
|
|
|
def addfile(self, gcode = []):
|
2012-01-25 13:13:12 +00:00
|
|
|
self.models["GCODE"].gc.delete()
|
2012-08-08 07:38:48 +00:00
|
|
|
self.models["GCODE"].gc = gcview(gcode, batch = self.models["GCODE"].batch)
|
2012-01-24 19:13:22 +00:00
|
|
|
self.setlayerindex(None)
|
|
|
|
|
|
|
|
def clear(self):
|
2012-01-25 13:13:12 +00:00
|
|
|
self.models["GCODE"].gc.delete()
|
2012-08-08 07:38:48 +00:00
|
|
|
self.models["GCODE"].gc = gcview([], batch = self.models["GCODE"].batch)
|
2012-01-24 19:13:22 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def Show(self, arg = True):
|
2012-01-24 19:13:22 +00:00
|
|
|
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):
|
2012-01-25 13:13:12 +00:00
|
|
|
m = self.models["GCODE"]
|
2012-01-27 22:14:20 +00:00
|
|
|
try:
|
|
|
|
mlk = m.gc.layerlist
|
|
|
|
except:
|
|
|
|
mlk = []
|
|
|
|
if z is None:
|
|
|
|
self.modelindex = -1
|
|
|
|
elif z > 0:
|
|
|
|
if self.modelindex < len(mlk) - 1:
|
|
|
|
if self.modelindex > -1:
|
|
|
|
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")
|
|
|
|
|
2012-01-24 19:13:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
2012-08-08 07:38:48 +00:00
|
|
|
app = wx.App(redirect = False)
|
|
|
|
frame = GCFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size = (400, 400))
|
2012-01-24 19:13:22 +00:00
|
|
|
import sys
|
2012-01-25 13:13:12 +00:00
|
|
|
for filename in sys.argv:
|
|
|
|
if ".gcode" in filename:
|
|
|
|
frame.addfile(list(open(filename)))
|
|
|
|
elif ".stl" in filename:
|
|
|
|
#TODO: add stl here
|
|
|
|
pass
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
#frame = wx.Frame(None, -1, "GL Window", size = (400, 400))
|
|
|
|
#panel = TestGlPanel(frame, size = (300, 300))
|
2012-01-24 19:13:22 +00:00
|
|
|
frame.Show(True)
|
|
|
|
app.MainLoop()
|
|
|
|
app.Destroy()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
#import cProfile
|
|
|
|
#print cProfile.run("main()")
|
|
|
|
main()
|