Commit a7c915bb authored by D1plo1d's avatar D1plo1d

Merge branch 'master' of github.com:kliment/Printrun

parents 182476ad d6f485a3
......@@ -549,7 +549,10 @@ class printcore():
if self.printer:
self.sent.append(command)
# run the command through the analyzer
self.analyzer.Analyze(command)
try: self.analyzer.Analyze(command)
except:
print "Warning: could not analyze command %s:" % command
traceback.print_exc(file = sys.stdout)
if self.loud:
print "SENT:", command
if self.sendcb:
......
......@@ -22,15 +22,23 @@ from . import gcoder
from .gl.panel import wxGLPanel
from .gl.trackball import build_rotmatrix
from .gl.libtatlin import actors
from .gl.libtatlin.actors import vec
from pyglet.gl import glPushMatrix, glPopMatrix, \
glTranslatef, glRotatef, glScalef, glMultMatrixd
from pyglet.gl import *
from .gviz import GvizBaseFrame
from printrun_utils import imagefile, install_locale
install_locale('pronterface')
def create_model(light):
if light:
return actors.GcodeModelLight()
else:
return actors.GcodeModel()
class GcodeViewPanel(wxGLPanel):
def __init__(self, parent, id = wx.ID_ANY,
......@@ -61,6 +69,8 @@ class GcodeViewPanel(wxGLPanel):
for filename in self.parent.filenames:
self.parent.load_file(filename)
self.parent.autoplate()
if hasattr(self.parent, "loadcb"):
self.parent.loadcb()
self.parent.filenames = None
def create_objects(self):
......@@ -78,10 +88,6 @@ class GcodeViewPanel(wxGLPanel):
self.create_objects()
glPushMatrix()
if self.orthographic:
glTranslatef(0, 0, -3 * self.dist) # Move back
else:
glTranslatef(0, 0, -self.dist) # Move back
# Rotate according to trackball
glMultMatrixd(build_rotmatrix(self.basequat))
# Move origin to bottom left of platform
......@@ -89,6 +95,14 @@ class GcodeViewPanel(wxGLPanel):
platformy0 = -self.build_dimensions[4] - self.parent.platform.depth / 2
glTranslatef(platformx0, platformy0, 0)
light_z = max(self.parent.platform.width, self.parent.platform.depth)
glLightfv(GL_LIGHT0, GL_POSITION, vec(0,
self.parent.platform.depth / 2,
light_z, 0))
glLightfv(GL_LIGHT1, GL_POSITION, vec(self.parent.platform.width,
self.parent.platform.depth / 2,
light_z, 0))
for obj in self.parent.objects:
if not obj.model \
or not obj.model.loaded \
......@@ -224,6 +238,7 @@ class GcodeViewPanel(wxGLPanel):
if not self.parent.model or not self.parent.model.loaded:
return
self.parent.model.only_current = not self.parent.model.only_current
wx.CallAfter(self.Refresh)
if key in kreset:
self.resetview()
event.Skip()
......@@ -246,7 +261,8 @@ class GCObject(object):
class GcodeViewMainWrapper(object):
def __init__(self, parent, build_dimensions):
def __init__(self, parent, build_dimensions, root):
self.root = root
self.glpanel = GcodeViewPanel(parent, realparent = self,
build_dimensions = build_dimensions)
self.glpanel.SetMinSize((150, 150))
......@@ -262,7 +278,8 @@ class GcodeViewMainWrapper(object):
return getattr(self.glpanel, name)
def set_current_gline(self, gline):
if gline.is_move and self.model and self.model.loaded:
if gline.is_move and gline.gcview_end_vertex is not None \
and self.model and self.model.loaded:
self.model.printed_until = gline.gcview_end_vertex
if not self.refresh_timer.IsRunning():
self.refresh_timer.Start()
......@@ -274,7 +291,8 @@ class GcodeViewMainWrapper(object):
pass
def addfile(self, gcode = None):
self.model = actors.GcodeModel()
self.model = create_model(self.root.settings.light3d
if self.root else False)
if gcode:
self.model.load_data(gcode)
self.objects[-1].model = self.model
......@@ -290,9 +308,10 @@ class GcodeViewFrame(GvizBaseFrame):
def __init__(self, parent, ID, title, build_dimensions, objects = None,
pos = wx.DefaultPosition, size = wx.DefaultSize,
style = wx.DEFAULT_FRAME_STYLE):
style = wx.DEFAULT_FRAME_STYLE, root = None):
super(GcodeViewFrame, self).__init__(parent, ID, title,
pos, size, style)
self.root = root
panel, vbox = self.create_base_ui()
......@@ -331,7 +350,8 @@ class GcodeViewFrame(GvizBaseFrame):
wx.CallAfter(self.Refresh)
def set_current_gline(self, gline):
if gline.is_move and self.model and self.model.loaded:
if gline.is_move and gline.gcview_end_vertex is not None \
and self.model and self.model.loaded:
self.model.printed_until = gline.gcview_end_vertex
if not self.refresh_timer.IsRunning():
self.refresh_timer.Start()
......@@ -340,7 +360,8 @@ class GcodeViewFrame(GvizBaseFrame):
if self.clonefrom:
self.model = self.clonefrom[-1].model.copy()
else:
self.model = actors.GcodeModel()
self.model = create_model(self.root.settings.light3d
if self.root else False)
if gcode:
self.model.load_data(gcode)
self.objects[-1].model = self.model
......
......@@ -21,18 +21,24 @@ import numpy
import math
import logging
from ctypes import sizeof
from pyglet.gl import glPushMatrix, glPopMatrix, glTranslatef, \
glGenLists, glNewList, GL_COMPILE, glEndList, glCallList, \
GL_ELEMENT_ARRAY_BUFFER, GL_UNSIGNED_INT, GL_TRIANGLES, \
GL_ARRAY_BUFFER, GL_STATIC_DRAW, glColor4f, glVertex3f, glRectf, \
glBegin, glEnd, GL_LINES, glEnable, glDisable, glGetFloatv, \
GL_LINE_SMOOTH, glLineWidth, GL_LINE_WIDTH, GLfloat, GL_FLOAT, \
glVertexPointer, glColorPointer, glDrawArrays, \
GL_LINE_SMOOTH, glLineWidth, GL_LINE_WIDTH, GLfloat, GL_FLOAT, GLuint, \
glVertexPointer, glColorPointer, glDrawArrays, glDrawRangeElements, \
glEnableClientState, glDisableClientState, GL_VERTEX_ARRAY, GL_COLOR_ARRAY
from pyglet.graphics.vertexbuffer import create_buffer, VertexBufferObject
from printrun.printrun_utils import install_locale
install_locale('pronterface')
def vec(*args):
return (GLfloat * len(args))(*args)
def compile_display_list(func, *options):
display_list = glGenLists(1)
glNewList(display_list, GL_COMPILE)
......@@ -46,6 +52,14 @@ def numpy2vbo(nparray, target = GL_ARRAY_BUFFER, usage = GL_STATIC_DRAW, use_vbo
vbo.set_data(nparray.ctypes.data)
return vbo
def triangulate_rectangle(i1, i2, i3, i4):
return [i1, i4, i3, i3, i2, i1]
def triangulate_box(i1, i2, i3, i4,
j1, j2, j3, j4):
return [i1, i2, j2, j2, j1, i1, i2, i3, j3, j3, j2, i2,
i3, i4, j4, j4, j3, i3, i4, i1, j1, j1, j4, i4]
class BoundingBox(object):
"""
A rectangular box (cuboid) enclosing a 3D model, defined by lower and upper corners.
......@@ -240,17 +254,30 @@ def movement_angle(src, dst, precision=0):
angle = math.degrees(math.atan2(y, -x)) # negate x for clockwise rotation angle
return round(angle, precision)
def get_next_move(gcode, layer_idx, gline_idx):
gline_idx += 1
while layer_idx < len(gcode.all_layers):
layer = gcode.all_layers[layer_idx]
while gline_idx < len(layer):
gline = layer[gline_idx]
if gline.is_move:
return gline
gline_idx += 1
layer_idx += 1
gline_idx = 0
return None
class GcodeModel(Model):
"""
Model for displaying Gcode data.
"""
color_travel = (0.6, 0.6, 0.6, 0.6)
color_tool0 = (1.0, 0.0, 0.0, 0.6)
color_tool1 = (0.31, 0.05, 0.9, 0.6)
color_printed = (0.2, 0.75, 0, 0.6)
color_current = (0, 0.9, 1.0, 0.8)
color_current_printed = (0.1, 0.4, 0, 0.8)
color_tool0 = (1.0, 0.0, 0.0, 1.0)
color_tool1 = (0.31, 0.05, 0.9, 1.0)
color_printed = (0.2, 0.75, 0, 1.0)
color_current = (0, 0.9, 1.0, 1.0)
color_current_printed = (0.1, 0.4, 0, 1.0)
use_vbos = True
loaded = False
......@@ -262,54 +289,152 @@ class GcodeModel(Model):
(model_data.ymin, model_data.ymax, model_data.depth),
(model_data.zmin, model_data.zmax, model_data.height))
count_travel_indices = [0]
count_print_indices = [0]
count_print_vertices = [0]
travel_vertex_list = []
max_travel_indices = []
max_print_indices = []
vertex_list = []
index_list = []
color_list = []
self.layer_stops = [0]
num_layers = len(model_data.all_layers)
prev_is_extruding = False
prev_move_x = None
prev_move_y = None
prev_pos = (0, 0, 0)
for layer_idx, layer in enumerate(model_data.all_layers):
for gline in layer:
has_movement = False
for gline_idx, gline in enumerate(layer):
if not gline.is_move:
continue
if gline.x is None and gline.y is None and gline.z is None:
continue
has_movement = True
current_pos = (gline.current_x, gline.current_y, gline.current_z)
if not gline.extruding:
travel_vertex_list.append(prev_pos)
travel_vertex_list.append(current_pos)
travel_vertex_list.extend(prev_pos)
travel_vertex_list.extend(current_pos)
prev_is_extruding = False
else:
gline_color = self.movement_color(gline)
vertex_list.append(prev_pos)
vertex_list.append(current_pos)
vertex_color = gline_color
color_list.append(vertex_color)
next_move = get_next_move(model_data, layer_idx, gline_idx)
next_is_extruding = (next_move.extruding
if next_move is not None else False)
delta_x = current_pos[0] - prev_pos[0]
delta_y = current_pos[1] - prev_pos[1]
norm = delta_x * delta_x + delta_y * delta_y
if norm == 0: # Don't draw anything if this move is Z+E only
continue
norm = math.sqrt(norm)
move_normal_x = - delta_y / norm
move_normal_y = delta_x / norm
path_halfwidth = 0.2
path_halfheight = 0.12
new_indices = []
new_vertices = []
if prev_is_extruding:
# Store previous vertices indices
prev_id = len(vertex_list) / 3 - 4
# Average directions
avg_move_x = delta_x + prev_move_x
avg_move_y = delta_y + prev_move_y
norm = avg_move_x * avg_move_x + avg_move_y * avg_move_y
# FIXME: handle norm == 0 or when paths go back (add an extra cap ?)
if norm == 0:
avg_move_normal_x = move_normal_x
avg_move_normal_y = move_normal_y
else:
norm = math.sqrt(norm)
avg_move_normal_x = - avg_move_y / norm
avg_move_normal_y = avg_move_x / norm
# Compute vertices
p1x = prev_pos[0] - path_halfwidth * avg_move_normal_x
p2x = prev_pos[0] + path_halfwidth * avg_move_normal_x
p1y = prev_pos[1] - path_halfwidth * avg_move_normal_y
p2y = prev_pos[1] + path_halfwidth * avg_move_normal_y
new_vertices.extend((p1x, p1y, prev_pos[2] + path_halfheight))
new_vertices.extend((p1x, p1y, prev_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, prev_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, prev_pos[2] + path_halfheight))
first = len(vertex_list) / 3
# Link to previous
new_indices += triangulate_box(prev_id, prev_id + 1,
prev_id + 2, prev_id + 3,
first, first + 1,
first + 2, first + 3)
else:
# Compute vertices normal to the current move and cap it
p1x = prev_pos[0] - path_halfwidth * move_normal_x
p2x = prev_pos[0] + path_halfwidth * move_normal_x
p1y = prev_pos[1] - path_halfwidth * move_normal_y
p2y = prev_pos[1] + path_halfwidth * move_normal_y
new_vertices.extend((p1x, p1y, prev_pos[2] + path_halfheight))
new_vertices.extend((p1x, p1y, prev_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, prev_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, prev_pos[2] + path_halfheight))
first = len(vertex_list) / 3
new_indices = triangulate_rectangle(first, first + 1,
first + 2, first + 3)
if not next_is_extruding:
# Compute caps and link everything
p1x = current_pos[0] - path_halfwidth * move_normal_x
p2x = current_pos[0] + path_halfwidth * move_normal_x
p1y = current_pos[1] - path_halfwidth * move_normal_y
p2y = current_pos[1] + path_halfwidth * move_normal_y
new_vertices.extend((p1x, p1y, current_pos[2] + path_halfheight))
new_vertices.extend((p1x, p1y, current_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, current_pos[2] - path_halfheight))
new_vertices.extend((p2x, p2y, current_pos[2] + path_halfheight))
end_first = len(vertex_list) / 3 + len(new_vertices) / 3 - 4
new_indices += triangulate_rectangle(end_first + 3, end_first + 2,
end_first + 1, end_first)
new_indices += triangulate_box(first, first + 1,
first + 2, first + 3,
end_first, end_first + 1,
end_first + 2, end_first + 3)
index_list += new_indices
vertex_list += new_vertices
color_list += list(gline_color) * (len(new_vertices) / 3)
prev_is_extruding = True
prev_move_x = delta_x
prev_move_y = delta_y
prev_pos = current_pos
max_travel_indices.append(len(travel_vertex_list))
#max_print_indices.append(len(index_list))
max_print_indices.append(len(vertex_list))
gline.gcview_end_vertex = len(max_print_indices)
count_travel_indices.append(len(travel_vertex_list) / 3)
count_print_indices.append(len(index_list))
count_print_vertices.append(len(vertex_list) / 3)
gline.gcview_end_vertex = len(count_print_indices) - 1
self.layer_stops.append(len(max_print_indices) - 1)
if has_movement:
self.layer_stops.append(len(count_print_indices) - 1)
if callback:
callback(layer_idx + 1, num_layers)
self.max_travel_indices = max_travel_indices
self.max_print_indices = max_print_indices
self.travels = numpy.array(travel_vertex_list, dtype = GLfloat)
self.vertices = numpy.array(vertex_list, dtype = GLfloat)
self.indices = numpy.array(index_list, dtype = GLfloat)
self.colors = numpy.array(color_list, dtype = GLfloat).repeat(2, 0)
self.count_travel_indices = count_travel_indices
self.count_print_indices = count_print_indices
self.count_print_vertices = count_print_vertices
self.travels = numpy.fromiter(travel_vertex_list, dtype = GLfloat,
count = len(travel_vertex_list))
self.vertices = numpy.fromiter(vertex_list, dtype = GLfloat,
count = len(vertex_list))
self.indices = numpy.fromiter(index_list, dtype = GLuint,
count = len(index_list))
self.colors = numpy.fromiter(color_list, dtype = GLfloat,
count = len(color_list))
self.max_layers = len(self.layer_stops) - 1
self.num_layers_to_draw = self.max_layers
self.printed_until = -1
self.num_layers_to_draw = self.max_layers + 1
self.printed_until = 0
self.only_current = False
self.initialized = False
self.loaded = True
......@@ -317,7 +442,7 @@ class GcodeModel(Model):
t_end = time.time()
logging.log(logging.INFO, _('Initialized 3D visualization in %.2f seconds') % (t_end - t_start))
logging.log(logging.INFO, _('Vertex count: %d') % (len(self.vertices) + len(self.travels)))
logging.log(logging.INFO, _('Vertex count: %d') % ((len(self.vertices) + len(self.travels)) / 3))
def copy(self):
copy = GcodeModel()
......@@ -347,7 +472,8 @@ class GcodeModel(Model):
def init(self):
self.travel_buffer = numpy2vbo(self.travels, use_vbos = self.use_vbos)
self.index_buffer = numpy2vbo(self.indices, use_vbos = self.use_vbos)
self.index_buffer = numpy2vbo(self.indices, use_vbos = self.use_vbos,
target = GL_ELEMENT_ARRAY_BUFFER)
self.vertex_buffer = numpy2vbo(self.vertices, use_vbos = self.use_vbos)
self.vertex_color_buffer = numpy2vbo(self.colors, use_vbos = self.use_vbos) # each pair of vertices shares the color
self.initialized = True
......@@ -356,14 +482,17 @@ class GcodeModel(Model):
glPushMatrix()
glTranslatef(self.offset_x, self.offset_y, 0)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
has_vbo = isinstance(self.vertex_buffer, VertexBufferObject)
self._display_travels(has_vbo)
glEnableClientState(GL_COLOR_ARRAY)
self._display_movements(has_vbo)
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
glPopMatrix()
def _display_travels(self, has_vbo):
......@@ -373,20 +502,28 @@ class GcodeModel(Model):
else:
glVertexPointer(3, GL_FLOAT, 0, self.travel_buffer.ptr)
# TODO: show current layer travels in a different color
end = self.layer_stops[min(self.num_layers_to_draw, self.max_layers)]
glDisableClientState(GL_COLOR_ARRAY)
end_index = self.count_travel_indices[end]
glColor4f(*self.color_travel)
if self.only_current:
if self.num_layers_to_draw < self.max_layers:
end_prev_layer = self.layer_stops[self.num_layers_to_draw - 1]
glDrawArrays(GL_LINES, self.max_travel_indices[end_prev_layer + 1],
self.max_travel_indices[end] - self.max_travel_indices[end_prev_layer + 1])
start_index = self.count_travel_indices[end_prev_layer + 1]
glDrawArrays(GL_LINES, start_index, end_index - start_index + 1)
else:
glDrawArrays(GL_LINES, 0, self.max_travel_indices[end])
glEnableClientState(GL_COLOR_ARRAY)
glDrawArrays(GL_LINES, 0, end_index)
self.travel_buffer.unbind()
def _draw_elements(self, start, end, draw_type = GL_TRIANGLES):
glDrawRangeElements(draw_type,
self.count_print_vertices[start - 1],
self.count_print_vertices[end] - 1,
self.count_print_indices[end] - self.count_print_indices[start - 1],
GL_UNSIGNED_INT,
sizeof(GLuint) * self.count_print_indices[start - 1])
def _display_movements(self, has_vbo):
self.vertex_buffer.bind()
if has_vbo:
......@@ -400,6 +537,195 @@ class GcodeModel(Model):
else:
glColorPointer(4, GL_FLOAT, 0, self.vertex_color_buffer.ptr)
self.index_buffer.bind()
start = 1
layer_selected = self.num_layers_to_draw <= self.max_layers
if layer_selected:
end_prev_layer = self.layer_stops[self.num_layers_to_draw - 1]
else:
end_prev_layer = 0
end = self.layer_stops[min(self.num_layers_to_draw, self.max_layers)]
glDisableClientState(GL_COLOR_ARRAY)
glColor4f(*self.color_printed)
# Draw printed stuff until end or end_prev_layer
cur_end = min(self.printed_until, end)
if not self.only_current:
if 1 <= end_prev_layer <= cur_end:
self._draw_elements(1, end_prev_layer)
elif cur_end >= 1:
self._draw_elements(1, cur_end)
glEnableClientState(GL_COLOR_ARRAY)
# Draw nonprinted stuff until end_prev_layer
start = max(cur_end, 1)
if end_prev_layer >= start:
if not self.only_current:
self._draw_elements(start, end_prev_layer)
cur_end = end_prev_layer
# Draw current layer
if layer_selected:
glDisableClientState(GL_COLOR_ARRAY)
# Backup & increase line width
orig_linewidth = (GLfloat)()
glGetFloatv(GL_LINE_WIDTH, orig_linewidth)
glLineWidth(2.0)
glColor4f(*self.color_current_printed)
if cur_end > end_prev_layer:
self._draw_elements(end_prev_layer + 1, cur_end)
glColor4f(*self.color_current)
if end > cur_end:
self._draw_elements(cur_end + 1, end)
# Restore line width
glLineWidth(orig_linewidth)
glEnableClientState(GL_COLOR_ARRAY)
# Draw non printed stuff until end (if not ending at a given layer)
start = max(self.printed_until, 1)
if not layer_selected and end >= start:
self._draw_elements(start, end)
self.vertex_buffer.unbind()
self.vertex_color_buffer.unbind()
class GcodeModelLight(Model):
"""
Model for displaying Gcode data.
"""
color_travel = (0.6, 0.6, 0.6, 0.6)
color_tool0 = (1.0, 0.0, 0.0, 0.6)
color_tool1 = (0.31, 0.05, 0.9, 0.6)
color_printed = (0.2, 0.75, 0, 0.6)
color_current = (0, 0.9, 1.0, 0.8)
color_current_printed = (0.1, 0.4, 0, 0.8)
use_vbos = True
loaded = False
def load_data(self, model_data, callback=None):
t_start = time.time()
self.dims = ((model_data.xmin, model_data.xmax, model_data.width),
(model_data.ymin, model_data.ymax, model_data.depth),
(model_data.zmin, model_data.zmax, model_data.height))
vertex_list = []
color_list = []
self.layer_stops = [0]
num_layers = len(model_data.all_layers)
prev_pos = (0, 0, 0)
for layer_idx, layer in enumerate(model_data.all_layers):
has_movement = False
for gline in layer:
if not gline.is_move:
continue
if gline.x is None and gline.y is None and gline.z is None:
continue
has_movement = True
vertex_list.extend(prev_pos)
current_pos = (gline.current_x, gline.current_y, gline.current_z)
vertex_list.extend(current_pos)
vertex_color = self.movement_color(gline)
color_list.extend(vertex_color + vertex_color)
prev_pos = current_pos
gline.gcview_end_vertex = len(vertex_list) / 3
if has_movement:
self.layer_stops.append(len(vertex_list) / 3)
if callback:
callback(layer_idx + 1, num_layers)
self.vertices = numpy.fromiter(vertex_list, dtype = GLfloat,
count = len(vertex_list))
self.colors = numpy.fromiter(color_list, dtype = GLfloat,
count = len(color_list))
self.max_layers = len(self.layer_stops) - 1
self.num_layers_to_draw = self.max_layers + 1
self.printed_until = -1
self.only_current = False
self.initialized = False
self.loaded = True
t_end = time.time()
logging.log(logging.INFO, _('Initialized 3D visualization in %.2f seconds') % (t_end - t_start))
logging.log(logging.INFO, _('Vertex count: %d') % (len(self.vertices) / 3))
def copy(self):
copy = GcodeModelLight()
for var in ["vertices", "colors", "max_layers",
"num_layers_to_draw", "printed_until",
"layer_stops", "dims", "only_current"]:
setattr(copy, var, getattr(self, var))
copy.loaded = True
copy.initialized = False
return copy
def movement_color(self, move):
"""
Return the color to use for particular type of movement.
"""
if move.extruding:
if move.current_tool == 0:
return self.color_tool0
else:
return self.color_tool1
return self.color_travel
# ------------------------------------------------------------------------
# DRAWING
# ------------------------------------------------------------------------
def init(self):
self.vertex_buffer = numpy2vbo(self.vertices, use_vbos = self.use_vbos)
self.vertex_color_buffer = numpy2vbo(self.colors, use_vbos = self.use_vbos) # each pair of vertices shares the color
self.initialized = True
def display(self, mode_2d=False):
glPushMatrix()
glTranslatef(self.offset_x, self.offset_y, 0)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
self._display_movements(mode_2d)
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
glPopMatrix()
def _display_movements(self, mode_2d=False):
self.vertex_buffer.bind()
has_vbo = isinstance(self.vertex_buffer, VertexBufferObject)
if has_vbo:
glVertexPointer(3, GL_FLOAT, 0, None)
else:
glVertexPointer(3, GL_FLOAT, 0, self.vertex_buffer.ptr)
self.vertex_color_buffer.bind()
if has_vbo:
glColorPointer(4, GL_FLOAT, 0, None)
else:
glColorPointer(4, GL_FLOAT, 0, self.vertex_color_buffer.ptr)
start = 0
if self.num_layers_to_draw <= self.max_layers:
end_prev_layer = self.layer_stops[self.num_layers_to_draw - 1]
......@@ -415,11 +741,9 @@ class GcodeModel(Model):
cur_end = min(self.printed_until, end)
if not self.only_current:
if 0 <= end_prev_layer <= cur_end:
glDrawArrays(GL_LINES, self.max_print_indices[start],
self.max_print_indices[end_prev_layer])
glDrawArrays(GL_LINES, start, end_prev_layer)
elif cur_end >= 0:
glDrawArrays(GL_LINES, self.max_print_indices[start],
self.max_print_indices[cur_end])
glDrawArrays(GL_LINES, start, cur_end)
glEnableClientState(GL_COLOR_ARRAY)
......@@ -427,8 +751,7 @@ class GcodeModel(Model):
start = max(cur_end, 0)
if end_prev_layer >= start:
if not self.only_current:
glDrawArrays(GL_LINES, self.max_print_indices[start],
self.max_print_indices[end_prev_layer] - self.max_print_indices[start])
glDrawArrays(GL_LINES, start, end_prev_layer - start)
cur_end = end_prev_layer
# Draw current layer
......@@ -443,14 +766,12 @@ class GcodeModel(Model):
glColor4f(*self.color_current_printed)
if cur_end > end_prev_layer:
glDrawArrays(GL_LINES, self.max_print_indices[end_prev_layer + 1],
self.max_print_indices[cur_end] - self.max_print_indices[end_prev_layer])
glDrawArrays(GL_LINES, end_prev_layer, cur_end - end_prev_layer)
glColor4f(*self.color_current)
if end > cur_end:
glDrawArrays(GL_LINES, self.max_print_indices[cur_end],
self.max_print_indices[end] - self.max_print_indices[cur_end])
glDrawArrays(GL_LINES, cur_end, end - cur_end)
# Restore line width
glLineWidth(orig_linewidth)
......@@ -461,8 +782,7 @@ class GcodeModel(Model):
start = max(self.printed_until, 0)
end = end - start
if end_prev_layer < 0 and end > 0 and not self.only_current:
glDrawArrays(GL_LINES, self.max_print_indices[start],
self.max_print_indices[end])
glDrawArrays(GL_LINES, start, end)
self.vertex_buffer.unbind()
self.vertex_color_buffer.unbind()
......@@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
from threading import Lock
import wx
from wx import glcanvas
......@@ -23,7 +25,7 @@ pyglet.options['debug_gl'] = True
from pyglet.gl import *
from pyglet import gl
from .trackball import trackball, mulquat
from .trackball import trackball, mulquat, build_rotmatrix
class wxGLPanel(wx.Panel):
'''A simple class for using OpenGL with wxPython.'''
......@@ -51,6 +53,10 @@ class wxGLPanel(wx.Panel):
self.sizer.Add(self.canvas, 1, wx.EXPAND)
self.SetSizerAndFit(self.sizer)
self.rot_lock = Lock()
self.basequat = [0, 0, 0, 1]
self.zoom_factor = 1.0
# bind events
self.canvas.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent)
self.canvas.Bind(wx.EVT_SIZE, self.processSizeEvent)
......@@ -119,9 +125,11 @@ class wxGLPanel(wx.Panel):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
if self.orthographic:
glOrtho(-width / 2, width / 2, -height / 2, height / 2, 0.1, 5 * self.dist)
glOrtho(-width / 2, width / 2, -height / 2, height / 2,
-5 * self.dist, 5 * self.dist)
else:
gluPerspective(60., float(width) / height, 10.0, 3 * self.dist)
glTranslatef(0, 0, -self.dist) # Move back
glMatrixMode(GL_MODELVIEW)
if not self.mview_initialized:
......@@ -142,6 +150,7 @@ class wxGLPanel(wx.Panel):
glLoadIdentity()
if self.orthographic:
ratio = factor * float(min(self.width, self.height)) / self.dist
self.zoom_factor = 1.0
glScalef(ratio, ratio, 1)
def OnDraw(self, *args, **kwargs):
......@@ -195,6 +204,7 @@ class wxGLPanel(wx.Panel):
delta_y = to[1]
glTranslatef(delta_x, delta_y, 0)
glScalef(factor, factor, 1)
self.zoom_factor *= factor
if to:
glTranslatef(-delta_x, -delta_y, 0)
wx.CallAfter(self.Refresh)
......@@ -216,7 +226,8 @@ class wxGLPanel(wx.Panel):
p2x = float(p2[0]) / (sz[0] / 2) - 1
p2y = 1 - float(p2[1]) / (sz[1] / 2)
quat = trackball(p1x, p1y, p2x, p2y, self.dist / 250.0)
self.basequat = mulquat(self.basequat, quat)
with self.rot_lock:
self.basequat = mulquat(self.basequat, quat)
self.initpos = p2
def handle_translation(self, event):
......
......@@ -44,8 +44,9 @@ def make_sized_button(*args):
def make_autosize_button(*args):
return make_button(*args, size = (-1, buttonSize[1]), style = wx.BU_EXACTFIT)
def make_custom_button(root, parentpanel, i):
btn = make_button(parentpanel, i.label, root.procbutton, i.tooltip)
def make_custom_button(root, parentpanel, i, style = 0):
btn = make_button(parentpanel, i.label, root.procbutton,
i.tooltip, style = style)
btn.SetBackgroundColour(i.background)
btn.SetForegroundColour("black")
btn.properties = i
......@@ -138,6 +139,32 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
if not extra_buttons:
ebuttonspanel = root.newPanel(parentpanel)
ebuttonssizer = wx.BoxSizer(wx.HORIZONTAL)
if root.settings.extruders > 1:
ebuttonssizer.Add(wx.StaticText(ebuttonspanel, -1, _("Tool:")), flag = wx.ALIGN_CENTER)
if root.settings.extruders == 2:
root.extrudersel = wx.Button(ebuttonspanel, -1, "0", style = wx.BU_EXACTFIT)
root.extrudersel.SetToolTip(wx.ToolTip(_("Click to switch current extruder")))
def extrudersel_cb(event):
if root.extrudersel.GetLabel() == "1":
new = "0"
else:
new = "1"
root.extrudersel.SetLabel(new)
root.tool_change(event)
root.extrudersel.Bind(wx.EVT_BUTTON, extrudersel_cb)
root.extrudersel.GetValue = root.extrudersel.GetLabel
root.extrudersel.SetValue = root.extrudersel.SetLabel
else:
choices = [str(i) for i in range(0, root.settings.extruders)]
root.extrudersel = wx.ComboBox(ebuttonspanel, -1, choices = choices,
style = wx.CB_DROPDOWN | wx.CB_READONLY,
size = (50, -1))
root.extrudersel.SetToolTip(wx.ToolTip(_("Select current extruder")))
root.extrudersel.SetValue(choices[0])
root.extrudersel.Bind(wx.EVT_COMBOBOX, root.tool_change)
root.printerControls.append(root.extrudersel)
ebuttonssizer.Add(root.extrudersel)
ebuttonspanel.SetSizer(ebuttonssizer)
self.Add(ebuttonspanel, pos = (base_line + 2, 0), span = (1, 5), flag = wx.EXPAND)
......@@ -210,7 +237,8 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
for i in root.cpbuttons:
if not i.pos or i.pos[0] != 4:
continue
btn = make_custom_button(root, ebuttonspanel, i)
btn = make_custom_button(root, ebuttonspanel, i,
style = wx.BU_EXACTFIT)
ebuttonssizer.Add(btn, 1, flag = wx.EXPAND)
class LeftPane(wx.GridBagSizer):
......@@ -285,7 +313,7 @@ class VizPane(wx.BoxSizer):
if root.settings.mainviz == "3D":
try:
import printrun.gcview
root.gviz = printrun.gcview.GcodeViewMainWrapper(parentpanel, root.build_dimensions_list)
root.gviz = printrun.gcview.GcodeViewMainWrapper(parentpanel, root.build_dimensions_list, root = root)
root.gviz.clickcb = root.showwin
except:
use2dview = True
......@@ -308,7 +336,7 @@ class VizPane(wx.BoxSizer):
objects = None
if isinstance(root.gviz, printrun.gcview.GcodeViewMainWrapper):
objects = root.gviz.objects
root.gwindow = printrun.gcview.GcodeViewFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size = (600, 600), build_dimensions = root.build_dimensions_list, objects = objects)
root.gwindow = printrun.gcview.GcodeViewFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size = (600, 600), build_dimensions = root.build_dimensions_list, objects = objects, root = root)
except:
use3dview = False
print "3D view mode requested, but we failed to initialize it."
......
......@@ -108,10 +108,6 @@ class StlViewPanel(wxGLPanel):
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))
......@@ -129,6 +125,8 @@ class StlViewPanel(wxGLPanel):
for filename in self.parent.filenames:
self.parent.load_file(filename)
self.parent.autoplate()
if hasattr(self.parent, "loadcb"):
self.parent.loadcb()
self.parent.filenames = None
def double(self, event):
......
......@@ -1156,6 +1156,24 @@ class pronsole(cmd.Cmd):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.bedtemps.keys() if i.startswith(text)]
def do_tool(self, l):
tool = None
try:
tool = int(l.lower().strip())
except:
self.logError(_("You must specify the tool index as an integer."))
if tool is not None and tool >= 0:
if self.p.online:
self.p.send_now("T%d" % tool)
self.log(_("Using tool %d.") % tool)
else:
self.logError(_("Printer is not online."))
else:
self.logError(_("You cannot set negative tool numbers."))
def help_tool(self):
self.log(_("Switches to the specified tool (e.g. doing tool 1 will emit a T1 G-Code)."))
def do_move(self, l):
if(len(l.split()) < 2):
self.logError(_("No move specified."))
......
......@@ -196,6 +196,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
monitorsetting = BooleanSetting("monitor", False)
monitorsetting.hidden = True
self.settings._add(monitorsetting)
self.settings._add(SpinSetting("extruders", 0, 1, 5, _("Extruders count"), _("Number of extruders"), "Printer"))
self.settings._add(BuildDimensionsSetting("build_dimensions", "200x200x100+0+0+0+0+0+0", _("Build dimensions"), _("Dimensions of Build Platform\n & optional offset of origin\n & optional switch position\n\nExamples:\n XXXxYYY\n XXX,YYY,ZZZ\n XXXxYYYxZZZ+OffX+OffY+OffZ\nXXXxYYYxZZZ+OffX+OffY+OffZ+HomeX+HomeY+HomeZ"), "Printer"))
self.settings._add(BooleanSetting("clamp_jogging", False, _("Clamp manual moves"), _("Prevent manual moves from leaving the specified build dimensions"), "Printer"))
self.settings._add(StringSetting("bgcolor", "#FFFFFF", _("Background color"), _("Pronterface background color"), "UI"))
......@@ -203,6 +204,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.settings._add(BooleanSetting("slic3rintegration", False, _("Enable Slic3r integration"), _("Add a menu to select Slic3r profiles directly from Pronterface"), "UI"))
self.settings._add(ComboSetting("mainviz", "2D", ["2D", "3D", "None"], _("Main visualization"), _("Select visualization for main window."), "UI"))
self.settings._add(BooleanSetting("viz3d", False, _("Use 3D in GCode viewer window"), _("Use 3D mode instead of 2D layered mode in the visualization window"), "UI"))
self.settings._add(BooleanSetting("light3d", True, _("Use a lighter 3D visualization"), _("Use a lighter visualization with simple lines instead of extruded paths for 3D viewer"), "UI"))
self.settings._add(BooleanSetting("tempgraph", True, _("Display temperature graph"), _("Display time-lapse temperature graph"), "UI"))
self.settings._add(BooleanSetting("tempgauges", False, _("Display temperature gauges"), _("Display graphical gauges for temperatures visualization"), "UI"))
self.settings._add(BooleanSetting("lockbox", False, _("Display interface lock checkbox"), _("Display a checkbox that, when check, locks most of Pronterface"), "UI"))
......@@ -373,6 +375,9 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.connectbtn.SetToolTip(wx.ToolTip("Disconnect from the printer"))
self.connectbtn.Bind(wx.EVT_BUTTON, self.disconnect)
if hasattr(self, "extrudersel"):
self.do_tool(self.extrudersel.GetValue())
for i in self.printerControls:
i.Enable()
......@@ -406,13 +411,16 @@ class PronterWindow(MainWindow, pronsole.pronsole):
temp = gline_s
if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp)
elif gline.command == "M140":
elif gline.command in ["M140", "M190"]:
gline.parse_coordinates(gline, split_raw, imperial = False, force = True)
gline_s = gcoder.S(gline)
if gline_s is not None:
temp = gline_s
if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, temp)
elif gline.command.startswith("T"):
tool = gline.command[1:]
if hasattr(self, "extrudersel"): wx.CallAfter(self.extrudersel.SetValue, tool)
else:
return
self.sentlines.put_nowait(line)
......@@ -840,6 +848,9 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.do_bedtemp("")
wx.CallAfter(self.btemp.SetInsertionPoint, 0)
def tool_change(self, event):
self.do_tool(self.extrudersel.GetValue())
def showwin(self, event):
if self.fgcode:
self.gwindow.Show(True)
......
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