2012-04-10 14:45:53 +00:00
|
|
|
from __future__ import division
|
|
|
|
|
2012-02-22 19:44:00 +00:00
|
|
|
import sys
|
|
|
|
import math
|
|
|
|
import threading
|
|
|
|
import re
|
2012-03-14 15:24:18 +00:00
|
|
|
import time
|
2012-03-18 12:00:31 +00:00
|
|
|
import os
|
2012-02-19 23:30:49 +00:00
|
|
|
|
2012-02-29 17:25:57 +00:00
|
|
|
from wx import glcanvas
|
2012-04-12 20:18:34 +00:00
|
|
|
from wx.lib import buttons
|
2012-02-23 21:47:42 +00:00
|
|
|
import wx
|
2012-02-20 15:44:43 +00:00
|
|
|
try:
|
2012-03-22 14:12:37 +00:00
|
|
|
import OpenGL
|
|
|
|
OpenGL.ERROR_CHECKING = False
|
2012-02-20 15:44:43 +00:00
|
|
|
from OpenGL.GLU import *
|
|
|
|
from OpenGL.GL import *
|
|
|
|
hasOpenGLlibs = True
|
|
|
|
except:
|
|
|
|
print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
|
|
|
|
hasOpenGLlibs = False
|
|
|
|
|
2012-04-05 20:35:52 +00:00
|
|
|
from gui import opengl
|
|
|
|
|
2012-03-28 12:26:40 +00:00
|
|
|
from util import profile
|
|
|
|
from util import gcodeInterpreter
|
2012-03-28 14:53:08 +00:00
|
|
|
from util import stl
|
2012-03-28 12:26:40 +00:00
|
|
|
from util import util3d
|
2012-03-15 16:14:20 +00:00
|
|
|
|
2012-04-17 21:16:24 +00:00
|
|
|
class ToggleButton(buttons.GenBitmapToggleButton):
|
2012-04-17 21:27:11 +00:00
|
|
|
def __init__(self, parent, popupParent, profileSetting, bitmapFilenameOn, bitmapFilenameOff,
|
2012-04-17 21:16:24 +00:00
|
|
|
helpText='', id=-1, size=(20,20)):
|
2012-04-17 21:27:11 +00:00
|
|
|
self.bitmapOn = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilenameOn))
|
|
|
|
self.bitmapOff = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilenameOff))
|
|
|
|
|
|
|
|
buttons.GenBitmapToggleButton.__init__(self, parent, id, self.bitmapOff, size=size)
|
2012-04-17 21:16:24 +00:00
|
|
|
|
|
|
|
self.popupParent = popupParent
|
|
|
|
self.profileSetting = profileSetting
|
|
|
|
self.helpText = helpText
|
|
|
|
|
|
|
|
self.bezelWidth = 1
|
|
|
|
self.useFocusInd = False
|
|
|
|
|
|
|
|
if self.profileSetting != '':
|
|
|
|
self.SetValue(profile.getProfileSetting(self.profileSetting) == 'True')
|
|
|
|
self.Bind(wx.EVT_BUTTON, self.OnButtonProfile)
|
|
|
|
else:
|
|
|
|
self.Bind(wx.EVT_BUTTON, self.OnButton)
|
|
|
|
|
|
|
|
self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
|
|
|
|
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
|
|
|
|
|
|
|
|
def SetBitmap(self, bool):
|
|
|
|
if bool:
|
|
|
|
buttons.GenBitmapToggleButton.SetBitmapLabel(self, self.bitmapOn, False)
|
|
|
|
else:
|
|
|
|
buttons.GenBitmapToggleButton.SetBitmapLabel(self, self.bitmapOff, False)
|
|
|
|
|
|
|
|
def SetValue(self, bool):
|
|
|
|
self.SetBitmap(bool)
|
|
|
|
buttons.GenBitmapToggleButton.SetValue(self, bool)
|
|
|
|
|
|
|
|
def OnButton(self, event):
|
|
|
|
self.SetBitmap(buttons.GenBitmapToggleButton.GetValue(self))
|
|
|
|
event.Skip()
|
|
|
|
|
|
|
|
def OnButtonProfile(self, event):
|
|
|
|
if buttons.GenBitmapToggleButton.GetValue(self):
|
|
|
|
self.SetBitmap(True)
|
|
|
|
profile.putProfileSetting(self.profileSetting, 'True')
|
|
|
|
else:
|
|
|
|
self.SetBitmap(False)
|
|
|
|
profile.putProfileSetting(self.profileSetting, 'False')
|
|
|
|
self.popupParent.updateModelTransform()
|
|
|
|
event.Skip()
|
|
|
|
|
|
|
|
def OnMouseEnter(self, event):
|
|
|
|
self.popupParent.OnPopupDisplay(event)
|
|
|
|
event.Skip()
|
|
|
|
|
|
|
|
def OnMouseLeave(self, event):
|
|
|
|
self.popupParent.OnPopupHide(event)
|
|
|
|
event.Skip()
|
2012-04-16 21:06:02 +00:00
|
|
|
|
2012-04-17 22:08:42 +00:00
|
|
|
class NormalButton(buttons.GenBitmapButton):
|
|
|
|
def __init__(self, parent, popupParent, bitmapFilename,
|
|
|
|
helpText='', id=-1, size=(20,20)):
|
|
|
|
self.bitmap = wx.Bitmap(os.path.join(os.path.split(__file__)[0], "../images", bitmapFilename))
|
|
|
|
buttons.GenBitmapButton.__init__(self, parent, id, self.bitmap, size=size)
|
|
|
|
|
|
|
|
self.popupParent = popupParent
|
|
|
|
self.helpText = helpText
|
|
|
|
|
|
|
|
self.bezelWidth = 1
|
|
|
|
self.useFocusInd = False
|
|
|
|
|
|
|
|
self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
|
|
|
|
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
|
|
|
|
|
|
|
|
def OnMouseEnter(self, event):
|
|
|
|
self.popupParent.OnPopupDisplay(event)
|
|
|
|
event.Skip()
|
|
|
|
|
|
|
|
def OnMouseLeave(self, event):
|
|
|
|
self.popupParent.OnPopupHide(event)
|
|
|
|
event.Skip()
|
|
|
|
|
2012-02-23 13:08:34 +00:00
|
|
|
class previewPanel(wx.Panel):
|
2012-02-19 23:30:49 +00:00
|
|
|
def __init__(self, parent):
|
2012-02-23 13:08:34 +00:00
|
|
|
wx.Panel.__init__(self, parent,-1)
|
|
|
|
|
|
|
|
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW))
|
2012-03-22 11:33:39 +00:00
|
|
|
self.SetMinSize((440,320))
|
2012-03-22 19:29:03 +00:00
|
|
|
|
2012-04-12 21:13:56 +00:00
|
|
|
# Create popup window
|
|
|
|
self.popup = wx.PopupWindow(self, flags=wx.BORDER_SIMPLE)
|
|
|
|
self.popup.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK))
|
|
|
|
self.popup.text = wx.StaticText(self.popup, -1, '')
|
|
|
|
self.popup.sizer = wx.BoxSizer()
|
|
|
|
self.popup.sizer.Add(self.popup.text, flag=wx.EXPAND|wx.ALL, border=1)
|
|
|
|
self.popup.SetSizer(self.popup.sizer)
|
2012-04-17 21:16:24 +00:00
|
|
|
self.popupOwner = None
|
2012-04-12 21:13:56 +00:00
|
|
|
|
2012-02-23 21:47:42 +00:00
|
|
|
self.glCanvas = PreviewGLCanvas(self)
|
2012-02-19 23:30:49 +00:00
|
|
|
self.init = 0
|
|
|
|
self.triangleMesh = None
|
2012-02-28 16:39:46 +00:00
|
|
|
self.gcode = None
|
2012-03-19 15:15:16 +00:00
|
|
|
self.modelFilename = None
|
2012-03-22 15:04:53 +00:00
|
|
|
self.loadingProgressAmount = 0
|
|
|
|
self.loadThread = None
|
2012-03-28 14:53:08 +00:00
|
|
|
self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
|
2012-03-29 12:45:14 +00:00
|
|
|
self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)
|
2012-02-23 13:08:34 +00:00
|
|
|
|
2012-03-05 21:30:54 +00:00
|
|
|
self.toolbar = wx.ToolBar( self, -1 )
|
|
|
|
self.toolbar.SetToolBitmapSize( ( 21, 21 ) )
|
2012-02-28 14:02:24 +00:00
|
|
|
|
2012-03-05 21:30:54 +00:00
|
|
|
button = wx.Button(self.toolbar, -1, "3D", size=(21*2,21))
|
|
|
|
self.toolbar.AddControl(button)
|
2012-02-28 14:02:24 +00:00
|
|
|
self.Bind(wx.EVT_BUTTON, self.On3DClick, button)
|
|
|
|
|
2012-03-05 21:30:54 +00:00
|
|
|
button = wx.Button(self.toolbar, -1, "Top", size=(21*2,21))
|
|
|
|
self.toolbar.AddControl(button)
|
2012-02-28 14:02:24 +00:00
|
|
|
self.Bind(wx.EVT_BUTTON, self.OnTopClick, button)
|
2012-02-28 16:39:46 +00:00
|
|
|
|
2012-03-18 12:00:31 +00:00
|
|
|
self.viewSelect = wx.ComboBox(self.toolbar, -1, 'Model - Normal', choices=['Model - Normal', 'Model - Transparent', 'Model - X-Ray', 'GCode', 'Mixed'], style=wx.CB_DROPDOWN|wx.CB_READONLY)
|
|
|
|
self.toolbar.AddControl(self.viewSelect)
|
2012-03-21 09:46:04 +00:00
|
|
|
self.viewSelect.Bind(wx.EVT_COMBOBOX, self.OnViewChange)
|
2012-03-18 12:00:31 +00:00
|
|
|
self.glCanvas.viewMode = self.viewSelect.GetValue()
|
|
|
|
|
2012-03-05 21:30:54 +00:00
|
|
|
self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
|
|
|
|
self.toolbar.AddControl(self.layerSpin)
|
2012-02-28 16:39:46 +00:00
|
|
|
self.Bind(wx.EVT_SPINCTRL, self.OnLayerNrChange, self.layerSpin)
|
2012-04-17 22:41:40 +00:00
|
|
|
|
|
|
|
self.scaleMax = NormalButton(self.toolbar, self, 'object-max-size.png', 'Scale object to fix machine size')
|
|
|
|
self.scaleMax.Bind(wx.EVT_BUTTON, self.OnScaleMax)
|
|
|
|
self.toolbar.AddControl(self.scaleMax)
|
2012-03-22 19:29:03 +00:00
|
|
|
|
2012-04-16 21:06:02 +00:00
|
|
|
self.toolbar2 = wx.ToolBar( self, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER )
|
2012-03-21 14:53:29 +00:00
|
|
|
self.toolbar2.SetToolBitmapSize( ( 21, 21 ) )
|
|
|
|
|
2012-04-17 22:41:40 +00:00
|
|
|
# Mirror
|
2012-04-17 21:27:11 +00:00
|
|
|
self.mirrorX = ToggleButton(self.toolbar2, self, 'flip_x', 'object-mirror-x-on.png', 'object-mirror-x-off.png', 'Mirror X')
|
2012-04-12 22:05:09 +00:00
|
|
|
self.toolbar2.AddControl(self.mirrorX)
|
2012-04-16 21:06:02 +00:00
|
|
|
|
2012-04-17 21:27:11 +00:00
|
|
|
self.mirrorY = ToggleButton(self.toolbar2, self, 'flip_y', 'object-mirror-y-on.png', 'object-mirror-y-off.png', 'Mirror Y')
|
2012-04-12 22:05:09 +00:00
|
|
|
self.toolbar2.AddControl(self.mirrorY)
|
2012-04-16 21:06:02 +00:00
|
|
|
|
2012-04-17 21:27:11 +00:00
|
|
|
self.mirrorZ = ToggleButton(self.toolbar2, self, 'flip_z', 'object-mirror-z-on.png', 'object-mirror-z-off.png', 'Mirror Z')
|
2012-04-12 22:05:09 +00:00
|
|
|
self.toolbar2.AddControl(self.mirrorZ)
|
2012-04-05 20:35:52 +00:00
|
|
|
|
2012-04-12 20:18:34 +00:00
|
|
|
self.toolbar2.AddSeparator()
|
|
|
|
|
2012-04-17 22:41:40 +00:00
|
|
|
# Swap
|
2012-04-17 21:27:11 +00:00
|
|
|
self.swapXZ = ToggleButton(self.toolbar2, self, 'swap_xz', 'object-swap-xz-on.png', 'object-swap-xz-off.png', 'Swap XZ')
|
2012-04-17 18:08:24 +00:00
|
|
|
self.toolbar2.AddControl(self.swapXZ)
|
2012-04-05 20:35:52 +00:00
|
|
|
|
2012-04-17 21:27:11 +00:00
|
|
|
self.swapYZ = ToggleButton(self.toolbar2, self, 'swap_yz', 'object-swap-yz-on.png', 'object-swap-yz-off.png', 'Swap YZ')
|
2012-04-17 18:08:24 +00:00
|
|
|
self.toolbar2.AddControl(self.swapYZ)
|
2012-03-05 21:30:54 +00:00
|
|
|
|
2012-04-17 22:41:40 +00:00
|
|
|
self.toolbar2.AddSeparator()
|
|
|
|
|
|
|
|
# Scale
|
2012-04-17 23:51:34 +00:00
|
|
|
self.scaleReset = NormalButton(self.toolbar2, self, 'object-scale.png', 'Reset model scale')
|
|
|
|
self.scaleReset.Bind(wx.EVT_BUTTON, self.OnScaleReset)
|
|
|
|
self.toolbar2.AddControl(self.scaleReset)
|
2012-03-21 15:53:05 +00:00
|
|
|
self.scale = wx.TextCtrl(self.toolbar2, -1, profile.getProfileSetting('model_scale'), size=(21*2,21))
|
|
|
|
self.toolbar2.AddControl(self.scale)
|
|
|
|
self.Bind(wx.EVT_TEXT, self.OnScale, self.scale)
|
2012-03-22 10:24:52 +00:00
|
|
|
|
2012-04-17 22:41:40 +00:00
|
|
|
self.toolbar2.AddSeparator()
|
|
|
|
|
|
|
|
# Multiply
|
|
|
|
self.mulXadd = NormalButton(self.toolbar2, self, 'object-mul-x-add.png', 'Increase number of models on X axis')
|
|
|
|
self.mulXadd.Bind(wx.EVT_BUTTON, self.OnMulXAddClick)
|
2012-03-22 10:24:52 +00:00
|
|
|
self.toolbar2.AddControl(self.mulXadd)
|
|
|
|
|
2012-04-17 22:41:40 +00:00
|
|
|
self.mulXsub = NormalButton(self.toolbar2, self, 'object-mul-x-sub.png', 'Decrease number of models on X axis')
|
|
|
|
self.mulXsub.Bind(wx.EVT_BUTTON, self.OnMulXSubClick)
|
|
|
|
self.toolbar2.AddControl(self.mulXsub)
|
|
|
|
|
|
|
|
self.mulYadd = NormalButton(self.toolbar2, self, 'object-mul-y-add.png', 'Increase number of models on Y axis')
|
|
|
|
self.mulYadd.Bind(wx.EVT_BUTTON, self.OnMulYAddClick)
|
2012-03-22 10:24:52 +00:00
|
|
|
self.toolbar2.AddControl(self.mulYadd)
|
2012-04-17 22:41:40 +00:00
|
|
|
|
|
|
|
self.mulYsub = NormalButton(self.toolbar2, self, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')
|
|
|
|
self.mulYsub.Bind(wx.EVT_BUTTON, self.OnMulYSubClick)
|
|
|
|
self.toolbar2.AddControl(self.mulYsub)
|
|
|
|
|
|
|
|
self.toolbar2.AddSeparator()
|
|
|
|
|
|
|
|
# Rotate
|
2012-04-17 23:51:34 +00:00
|
|
|
self.rotateReset = NormalButton(self.toolbar2, self, 'object-rotate.png', 'Reset model rotation')
|
|
|
|
self.rotateReset.Bind(wx.EVT_BUTTON, self.OnRotateReset)
|
|
|
|
self.toolbar2.AddControl(self.rotateReset)
|
2012-03-22 11:33:39 +00:00
|
|
|
self.rotate = wx.SpinCtrl(self.toolbar2, -1, profile.getProfileSetting('model_rotate_base'), size=(21*3,21), style=wx.SP_WRAP|wx.SP_ARROW_KEYS)
|
|
|
|
self.rotate.SetRange(0, 360)
|
2012-04-17 23:51:34 +00:00
|
|
|
self.Bind(wx.EVT_TEXT, self.OnRotate)
|
2012-03-22 11:33:39 +00:00
|
|
|
self.toolbar2.AddControl(self.rotate)
|
2012-04-17 10:08:19 +00:00
|
|
|
|
2012-03-21 15:53:05 +00:00
|
|
|
self.toolbar2.Realize()
|
2012-03-05 21:30:54 +00:00
|
|
|
self.updateToolbar()
|
|
|
|
|
2012-02-23 13:08:34 +00:00
|
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
2012-03-05 21:30:54 +00:00
|
|
|
sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
|
2012-02-23 13:08:34 +00:00
|
|
|
sizer.Add(self.glCanvas, 1, flag=wx.EXPAND)
|
2012-03-21 14:53:29 +00:00
|
|
|
sizer.Add(self.toolbar2, 0, flag=wx.EXPAND|wx.BOTTOM|wx.LEFT|wx.RIGHT, border=1)
|
2012-02-23 13:08:34 +00:00
|
|
|
self.SetSizer(sizer)
|
2012-04-17 23:51:34 +00:00
|
|
|
|
2012-04-12 21:13:56 +00:00
|
|
|
def OnPopupDisplay(self, e):
|
|
|
|
self.UpdatePopup(e.GetEventObject())
|
|
|
|
self.popup.Show(True)
|
|
|
|
|
|
|
|
def OnPopupHide(self, e):
|
2012-04-17 21:16:24 +00:00
|
|
|
if self.popupOwner == e.GetEventObject():
|
|
|
|
self.popup.Show(False)
|
2012-04-12 21:13:56 +00:00
|
|
|
|
|
|
|
def UpdatePopup(self, control):
|
2012-04-17 21:16:24 +00:00
|
|
|
self.popupOwner = control
|
2012-04-12 22:11:11 +00:00
|
|
|
self.popup.text.SetLabel(control.helpText)
|
2012-04-12 21:13:56 +00:00
|
|
|
self.popup.text.Wrap(350)
|
|
|
|
self.popup.Fit();
|
|
|
|
if os.name == 'darwin':
|
|
|
|
x, y = self.ClientToScreenXY(0, 0)
|
|
|
|
sx, sy = self.GetClientSizeTuple()
|
|
|
|
else:
|
|
|
|
x, y = control.ClientToScreenXY(0, 0)
|
|
|
|
sx, sy = control.GetSizeTuple()
|
|
|
|
self.popup.SetPosition((x, y+sy))
|
2012-04-05 20:35:52 +00:00
|
|
|
|
2012-03-22 10:24:52 +00:00
|
|
|
def OnMulXAddClick(self, e):
|
|
|
|
profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1)))
|
|
|
|
self.updateModelTransform()
|
|
|
|
|
|
|
|
def OnMulXSubClick(self, e):
|
|
|
|
profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))-1)))
|
|
|
|
self.updateModelTransform()
|
|
|
|
|
|
|
|
def OnMulYAddClick(self, e):
|
|
|
|
profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))+1)))
|
|
|
|
self.updateModelTransform()
|
|
|
|
|
|
|
|
def OnMulYSubClick(self, e):
|
|
|
|
profile.putProfileSetting('model_multiply_y', str(max(1, int(profile.getProfileSetting('model_multiply_y'))-1)))
|
|
|
|
self.updateModelTransform()
|
|
|
|
|
2012-04-17 23:51:34 +00:00
|
|
|
def OnScaleReset(self, e):
|
|
|
|
self.scale.SetValue('1')
|
|
|
|
|
2012-03-21 15:53:05 +00:00
|
|
|
def OnScale(self, e):
|
2012-04-10 14:45:53 +00:00
|
|
|
profile.putProfileSetting('model_scale', self.scale.GetValue())
|
2012-03-21 15:53:05 +00:00
|
|
|
self.updateModelTransform()
|
2012-03-22 11:33:39 +00:00
|
|
|
|
2012-04-17 10:08:19 +00:00
|
|
|
def OnScaleMax(self, e):
|
|
|
|
if self.triangleMesh == None:
|
|
|
|
return
|
|
|
|
scale = float(self.scale.GetValue())
|
|
|
|
vMin = self.triangleMesh.getMinimum() / scale
|
|
|
|
vMax = self.triangleMesh.getMaximum() / scale
|
|
|
|
scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
|
|
|
|
scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
|
|
|
|
scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
|
|
|
|
scaleY2 = (self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
|
|
|
|
scaleZ = self.machineSize.z / (vMax.z - vMin.z)
|
|
|
|
scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ)
|
|
|
|
self.scale.SetValue(str(scale))
|
|
|
|
profile.putProfileSetting('model_scale', self.scale.GetValue())
|
|
|
|
self.updateModelTransform()
|
2012-04-17 23:51:34 +00:00
|
|
|
|
|
|
|
def OnRotateReset(self, e):
|
|
|
|
self.rotate.SetValue(0)
|
|
|
|
|
2012-03-22 11:33:39 +00:00
|
|
|
def OnRotate(self, e):
|
|
|
|
profile.putProfileSetting('model_rotate_base', self.rotate.GetValue())
|
|
|
|
self.updateModelTransform()
|
2012-03-21 15:53:05 +00:00
|
|
|
|
2012-02-28 14:02:24 +00:00
|
|
|
def On3DClick(self, e):
|
|
|
|
self.glCanvas.yaw = 30
|
|
|
|
self.glCanvas.pitch = 60
|
|
|
|
self.glCanvas.zoom = 150
|
|
|
|
self.glCanvas.view3D = True
|
|
|
|
self.glCanvas.Refresh()
|
|
|
|
|
|
|
|
def OnTopClick(self, e):
|
|
|
|
self.glCanvas.view3D = False
|
2012-02-28 16:39:46 +00:00
|
|
|
self.glCanvas.zoom = 100
|
2012-02-28 14:02:24 +00:00
|
|
|
self.glCanvas.offsetX = 0
|
|
|
|
self.glCanvas.offsetY = 0
|
|
|
|
self.glCanvas.Refresh()
|
|
|
|
|
2012-02-28 16:39:46 +00:00
|
|
|
def OnLayerNrChange(self, e):
|
2012-03-18 12:00:31 +00:00
|
|
|
self.gcodeDirty = True
|
2012-02-28 16:39:46 +00:00
|
|
|
self.glCanvas.Refresh()
|
|
|
|
|
2012-02-24 22:01:22 +00:00
|
|
|
def updateCenterX(self, x):
|
|
|
|
self.machineCenter.x = x
|
|
|
|
self.moveModel()
|
|
|
|
self.glCanvas.Refresh()
|
|
|
|
|
|
|
|
def updateCenterY(self, y):
|
|
|
|
self.machineCenter.y = y
|
|
|
|
self.moveModel()
|
|
|
|
self.glCanvas.Refresh()
|
2012-02-19 23:30:49 +00:00
|
|
|
|
2012-03-23 13:04:50 +00:00
|
|
|
def setViewMode(self, mode):
|
|
|
|
self.viewSelect.SetValue(mode)
|
|
|
|
self.glCanvas.viewMode = self.viewSelect.GetValue()
|
|
|
|
wx.CallAfter(self.glCanvas.Refresh)
|
|
|
|
|
2012-02-21 22:05:30 +00:00
|
|
|
def loadModelFile(self, filename):
|
2012-03-19 15:15:16 +00:00
|
|
|
if self.modelFilename != filename:
|
|
|
|
self.modelFileTime = None
|
|
|
|
self.gcodeFileTime = None
|
2012-03-19 16:11:50 +00:00
|
|
|
self.logFileTime = None
|
2012-03-19 15:15:16 +00:00
|
|
|
|
2012-02-21 22:05:30 +00:00
|
|
|
self.modelFilename = filename
|
2012-03-19 16:11:50 +00:00
|
|
|
self.gcodeFilename = filename[: filename.rfind('.')] + "_export.gcode"
|
|
|
|
self.logFilename = filename[: filename.rfind('.')] + "_export.log"
|
2012-02-21 22:05:30 +00:00
|
|
|
#Do the STL file loading in a background thread so we don't block the UI.
|
2012-03-22 15:04:53 +00:00
|
|
|
if self.loadThread != None and self.loadThread.isAlive():
|
|
|
|
self.loadThread.join()
|
|
|
|
self.loadThread = threading.Thread(target=self.doFileLoadThread)
|
|
|
|
self.loadThread.daemon = True
|
|
|
|
self.loadThread.start()
|
2012-03-20 11:22:44 +00:00
|
|
|
|
|
|
|
def loadReModelFile(self, filename):
|
|
|
|
#Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
|
|
|
|
if self.modelFilename != filename:
|
2012-03-23 13:04:50 +00:00
|
|
|
return False
|
2012-03-22 15:04:53 +00:00
|
|
|
self.loadModelFile(filename)
|
2012-03-23 13:04:50 +00:00
|
|
|
return True
|
2012-02-20 22:27:34 +00:00
|
|
|
|
2012-03-22 15:04:53 +00:00
|
|
|
def doFileLoadThread(self):
|
2012-03-19 15:15:16 +00:00
|
|
|
if os.path.isfile(self.modelFilename) and self.modelFileTime != os.stat(self.modelFilename).st_mtime:
|
|
|
|
self.modelFileTime = os.stat(self.modelFilename).st_mtime
|
2012-03-28 14:53:08 +00:00
|
|
|
triangleMesh = stl.stlModel()
|
|
|
|
triangleMesh.load(self.modelFilename)
|
2012-03-19 15:15:16 +00:00
|
|
|
triangleMesh.origonalVertexes = list(triangleMesh.vertexes)
|
|
|
|
for i in xrange(0, len(triangleMesh.origonalVertexes)):
|
|
|
|
triangleMesh.origonalVertexes[i] = triangleMesh.origonalVertexes[i].copy()
|
|
|
|
triangleMesh.getMinimumZ()
|
|
|
|
self.modelDirty = False
|
2012-03-19 16:11:50 +00:00
|
|
|
self.errorList = []
|
2012-03-19 15:15:16 +00:00
|
|
|
self.triangleMesh = triangleMesh
|
|
|
|
self.updateModelTransform()
|
|
|
|
wx.CallAfter(self.updateToolbar)
|
|
|
|
wx.CallAfter(self.glCanvas.Refresh)
|
2012-03-18 12:00:31 +00:00
|
|
|
|
2012-03-19 15:15:16 +00:00
|
|
|
if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:
|
|
|
|
self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime
|
2012-03-22 15:04:53 +00:00
|
|
|
gcode = gcodeInterpreter.gcode()
|
|
|
|
gcode.progressCallback = self.loadProgress
|
|
|
|
gcode.load(self.gcodeFilename)
|
|
|
|
self.loadingProgressAmount = 0
|
2012-03-19 15:15:16 +00:00
|
|
|
self.gcodeDirty = False
|
2012-03-19 16:11:50 +00:00
|
|
|
self.errorList = []
|
2012-03-19 15:15:16 +00:00
|
|
|
self.gcode = gcode
|
|
|
|
self.gcodeDirty = True
|
|
|
|
wx.CallAfter(self.updateToolbar)
|
|
|
|
wx.CallAfter(self.glCanvas.Refresh)
|
2012-03-19 16:11:50 +00:00
|
|
|
elif not os.path.isfile(self.gcodeFilename):
|
|
|
|
self.gcode = None
|
|
|
|
|
|
|
|
if os.path.isfile(self.logFilename):
|
|
|
|
errorList = []
|
|
|
|
for line in open(self.logFilename, "rt"):
|
|
|
|
res = re.search('Model error\(([a-z ]*)\): \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\) \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\)', line)
|
|
|
|
if res != None:
|
|
|
|
v1 = util3d.Vector3(float(res.group(2)), float(res.group(3)), float(res.group(4)))
|
|
|
|
v2 = util3d.Vector3(float(res.group(5)), float(res.group(6)), float(res.group(7)))
|
|
|
|
errorList.append([v1, v2])
|
|
|
|
self.errorList = errorList
|
|
|
|
wx.CallAfter(self.glCanvas.Refresh)
|
2012-02-21 22:05:30 +00:00
|
|
|
|
2012-03-22 15:04:53 +00:00
|
|
|
def loadProgress(self, progress):
|
|
|
|
self.loadingProgressAmount = progress
|
|
|
|
wx.CallAfter(self.glCanvas.Refresh)
|
|
|
|
|
2012-02-28 16:39:46 +00:00
|
|
|
def updateToolbar(self):
|
|
|
|
self.layerSpin.Show(self.gcode != None)
|
|
|
|
if self.gcode != None:
|
2012-03-29 09:01:33 +00:00
|
|
|
self.layerSpin.SetRange(1, len(self.gcode.layerList))
|
2012-03-05 21:30:54 +00:00
|
|
|
self.toolbar.Realize()
|
2012-02-28 16:39:46 +00:00
|
|
|
|
2012-03-18 12:00:31 +00:00
|
|
|
def OnViewChange(self, e):
|
|
|
|
self.glCanvas.viewMode = self.viewSelect.GetValue()
|
2012-02-23 21:47:42 +00:00
|
|
|
self.glCanvas.Refresh()
|
2012-02-20 23:54:04 +00:00
|
|
|
|
2012-03-07 15:58:04 +00:00
|
|
|
def updateModelTransform(self, f=0):
|
|
|
|
if self.triangleMesh == None:
|
|
|
|
return
|
|
|
|
scale = 1.0
|
|
|
|
rotate = 0.0
|
|
|
|
try:
|
2012-04-10 14:45:53 +00:00
|
|
|
scale = profile.getProfileSettingFloat('model_scale')
|
|
|
|
rotate = profile.getProfileSettingFloat('model_rotate_base') / 180.0 * math.pi
|
2012-03-07 15:58:04 +00:00
|
|
|
except:
|
|
|
|
pass
|
|
|
|
scaleX = scale
|
|
|
|
scaleY = scale
|
|
|
|
scaleZ = scale
|
2012-03-17 11:03:38 +00:00
|
|
|
if profile.getProfileSetting('flip_x') == 'True':
|
2012-03-07 15:58:04 +00:00
|
|
|
scaleX = -scaleX
|
2012-03-17 11:03:38 +00:00
|
|
|
if profile.getProfileSetting('flip_y') == 'True':
|
2012-03-07 15:58:04 +00:00
|
|
|
scaleY = -scaleY
|
2012-03-17 11:03:38 +00:00
|
|
|
if profile.getProfileSetting('flip_z') == 'True':
|
2012-03-07 15:58:04 +00:00
|
|
|
scaleZ = -scaleZ
|
2012-04-05 20:35:52 +00:00
|
|
|
swapXZ = profile.getProfileSetting('swap_xz') == 'True'
|
|
|
|
swapYZ = profile.getProfileSetting('swap_yz') == 'True'
|
2012-03-07 15:58:04 +00:00
|
|
|
mat00 = math.cos(rotate) * scaleX
|
|
|
|
mat01 =-math.sin(rotate) * scaleY
|
|
|
|
mat10 = math.sin(rotate) * scaleX
|
|
|
|
mat11 = math.cos(rotate) * scaleY
|
|
|
|
|
|
|
|
for i in xrange(0, len(self.triangleMesh.origonalVertexes)):
|
2012-04-05 20:35:52 +00:00
|
|
|
x = self.triangleMesh.origonalVertexes[i].x
|
|
|
|
y = self.triangleMesh.origonalVertexes[i].y
|
|
|
|
z = self.triangleMesh.origonalVertexes[i].z
|
|
|
|
if swapXZ:
|
|
|
|
x, z = z, x
|
|
|
|
if swapYZ:
|
|
|
|
y, z = z, y
|
|
|
|
self.triangleMesh.vertexes[i].x = x * mat00 + y * mat01
|
|
|
|
self.triangleMesh.vertexes[i].y = x * mat10 + y * mat11
|
|
|
|
self.triangleMesh.vertexes[i].z = z * scaleZ
|
2012-03-14 15:24:18 +00:00
|
|
|
|
|
|
|
for face in self.triangleMesh.faces:
|
2012-03-28 14:53:08 +00:00
|
|
|
v1 = face.v[0]
|
|
|
|
v2 = face.v[1]
|
|
|
|
v3 = face.v[2]
|
2012-03-14 15:24:18 +00:00
|
|
|
face.normal = (v2 - v1).cross(v3 - v1)
|
|
|
|
face.normal.normalize()
|
|
|
|
|
2012-03-07 15:58:04 +00:00
|
|
|
self.moveModel()
|
|
|
|
|
2012-02-20 17:55:54 +00:00
|
|
|
def moveModel(self):
|
2012-02-20 15:44:43 +00:00
|
|
|
if self.triangleMesh == None:
|
|
|
|
return
|
2012-02-20 17:55:54 +00:00
|
|
|
minZ = self.triangleMesh.getMinimumZ()
|
2012-03-28 14:53:08 +00:00
|
|
|
min = self.triangleMesh.getMinimum()
|
|
|
|
max = self.triangleMesh.getMaximum()
|
2012-02-19 23:30:49 +00:00
|
|
|
for v in self.triangleMesh.vertexes:
|
|
|
|
v.z -= minZ
|
|
|
|
v.x -= min.x + (max.x - min.x) / 2
|
|
|
|
v.y -= min.y + (max.y - min.y) / 2
|
|
|
|
v.x += self.machineCenter.x
|
|
|
|
v.y += self.machineCenter.y
|
2012-02-20 22:27:34 +00:00
|
|
|
self.triangleMesh.getMinimumZ()
|
|
|
|
self.modelDirty = True
|
2012-03-07 15:58:04 +00:00
|
|
|
self.glCanvas.Refresh()
|
2012-02-23 21:47:42 +00:00
|
|
|
|
2012-02-29 17:25:57 +00:00
|
|
|
class PreviewGLCanvas(glcanvas.GLCanvas):
|
2012-02-23 21:47:42 +00:00
|
|
|
def __init__(self, parent):
|
2012-03-09 15:39:45 +00:00
|
|
|
attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
|
2012-02-29 17:25:57 +00:00
|
|
|
glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)
|
2012-02-23 21:47:42 +00:00
|
|
|
self.parent = parent
|
2012-03-09 15:39:45 +00:00
|
|
|
self.context = glcanvas.GLContext(self)
|
2012-02-23 21:47:42 +00:00
|
|
|
wx.EVT_PAINT(self, self.OnPaint)
|
|
|
|
wx.EVT_SIZE(self, self.OnSize)
|
|
|
|
wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
|
|
|
|
wx.EVT_MOTION(self, self.OnMouseMotion)
|
2012-02-28 14:02:24 +00:00
|
|
|
wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
|
2012-02-23 21:47:42 +00:00
|
|
|
self.yaw = 30
|
|
|
|
self.pitch = 60
|
2012-04-17 11:29:16 +00:00
|
|
|
self.zoom = 300
|
2012-02-28 14:02:24 +00:00
|
|
|
self.offsetX = 0
|
|
|
|
self.offsetY = 0
|
|
|
|
self.view3D = True
|
2012-02-23 21:47:42 +00:00
|
|
|
self.modelDisplayList = None
|
2012-03-18 12:00:31 +00:00
|
|
|
self.gcodeDisplayList = None
|
2012-03-09 19:00:22 +00:00
|
|
|
|
2012-02-19 23:30:49 +00:00
|
|
|
def OnMouseMotion(self,e):
|
|
|
|
if e.Dragging() and e.LeftIsDown():
|
2012-02-28 14:02:24 +00:00
|
|
|
if self.view3D:
|
|
|
|
self.yaw += e.GetX() - self.oldX
|
|
|
|
self.pitch -= e.GetY() - self.oldY
|
|
|
|
if self.pitch > 170:
|
|
|
|
self.pitch = 170
|
|
|
|
if self.pitch < 10:
|
|
|
|
self.pitch = 10
|
|
|
|
else:
|
|
|
|
self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2
|
|
|
|
self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2
|
2012-02-20 22:27:34 +00:00
|
|
|
self.Refresh()
|
2012-02-19 23:30:49 +00:00
|
|
|
if e.Dragging() and e.RightIsDown():
|
|
|
|
self.zoom += e.GetY() - self.oldY
|
2012-02-28 14:02:24 +00:00
|
|
|
if self.zoom < 1:
|
|
|
|
self.zoom = 1
|
2012-02-20 22:27:34 +00:00
|
|
|
self.Refresh()
|
2012-02-19 23:30:49 +00:00
|
|
|
self.oldX = e.GetX()
|
|
|
|
self.oldY = e.GetY()
|
|
|
|
|
2012-02-28 14:02:24 +00:00
|
|
|
def OnMouseWheel(self,e):
|
2012-03-07 21:45:41 +00:00
|
|
|
self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
|
|
|
|
if self.zoom < 1.0:
|
|
|
|
self.zoom = 1.0
|
2012-02-28 14:02:24 +00:00
|
|
|
self.Refresh()
|
|
|
|
|
2012-02-19 23:30:49 +00:00
|
|
|
def OnEraseBackground(self,event):
|
2012-03-18 12:00:31 +00:00
|
|
|
#Workaround for windows background redraw flicker.
|
2012-02-19 23:30:49 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def OnSize(self,event):
|
|
|
|
self.Refresh()
|
|
|
|
|
|
|
|
def OnPaint(self,event):
|
2012-02-20 15:44:43 +00:00
|
|
|
dc = wx.PaintDC(self)
|
|
|
|
if not hasOpenGLlibs:
|
|
|
|
dc.Clear()
|
|
|
|
dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
|
|
|
|
return
|
2012-03-09 15:39:45 +00:00
|
|
|
self.SetCurrent(self.context)
|
2012-04-05 20:35:52 +00:00
|
|
|
opengl.InitGL(self, self.view3D, self.zoom)
|
|
|
|
if self.view3D:
|
|
|
|
glTranslate(0,0,-self.zoom)
|
|
|
|
glRotate(-self.pitch, 1,0,0)
|
|
|
|
glRotate(self.yaw, 0,0,1)
|
|
|
|
if self.parent.triangleMesh != None:
|
|
|
|
glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2)
|
|
|
|
else:
|
|
|
|
glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
|
|
|
|
glTranslate(self.offsetX, self.offsetY, 0.0)
|
|
|
|
glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
|
|
|
|
|
2012-02-19 23:30:49 +00:00
|
|
|
self.OnDraw()
|
2012-03-09 15:26:54 +00:00
|
|
|
self.SwapBuffers()
|
2012-02-19 23:30:49 +00:00
|
|
|
|
|
|
|
def OnDraw(self):
|
2012-02-23 21:47:42 +00:00
|
|
|
machineSize = self.parent.machineSize
|
2012-04-05 20:35:52 +00:00
|
|
|
opengl.DrawMachine(machineSize)
|
2012-02-21 22:05:30 +00:00
|
|
|
|
2012-02-28 16:39:46 +00:00
|
|
|
if self.parent.gcode != None:
|
2012-03-18 12:00:31 +00:00
|
|
|
if self.gcodeDisplayList == None:
|
|
|
|
self.gcodeDisplayList = glGenLists(1);
|
|
|
|
if self.parent.gcodeDirty:
|
|
|
|
self.parent.gcodeDirty = False
|
|
|
|
glNewList(self.gcodeDisplayList, GL_COMPILE)
|
2012-03-18 22:00:33 +00:00
|
|
|
prevLayerZ = 0.0
|
|
|
|
curLayerZ = 0.0
|
|
|
|
|
|
|
|
layerThickness = 0.0
|
|
|
|
filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
|
|
|
|
filamentArea = math.pi * filamentRadius * filamentRadius
|
2012-04-05 14:50:59 +00:00
|
|
|
lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2 / 10
|
2012-03-18 22:00:33 +00:00
|
|
|
|
|
|
|
curLayerNum = 0
|
2012-03-29 09:01:33 +00:00
|
|
|
for layer in self.parent.gcode.layerList:
|
2012-04-05 14:50:59 +00:00
|
|
|
curLayerZ = layer[0].list[1].z
|
|
|
|
layerThickness = curLayerZ - prevLayerZ
|
|
|
|
prevLayerZ = layer[-1].list[-1].z
|
2012-03-29 09:01:33 +00:00
|
|
|
for path in layer:
|
|
|
|
c = 1.0
|
|
|
|
if curLayerNum != self.parent.layerSpin.GetValue():
|
|
|
|
if curLayerNum < self.parent.layerSpin.GetValue():
|
|
|
|
c = 0.9 - (self.parent.layerSpin.GetValue() - curLayerNum) * 0.1
|
|
|
|
if c < 0.4:
|
|
|
|
c = 0.4
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
if path.type == 'move':
|
|
|
|
glColor3f(0,0,c)
|
|
|
|
if path.type == 'extrude':
|
|
|
|
if path.pathType == 'FILL':
|
|
|
|
glColor3f(c/2,c/2,0)
|
|
|
|
elif path.pathType == 'WALL-INNER':
|
|
|
|
glColor3f(0,c,0)
|
2012-04-03 21:45:42 +00:00
|
|
|
elif path.pathType == 'SUPPORT':
|
|
|
|
glColor3f(0,c,c)
|
|
|
|
elif path.pathType == 'SKIRT':
|
|
|
|
glColor3f(0,c/2,c/2)
|
2012-03-29 09:01:33 +00:00
|
|
|
else:
|
|
|
|
glColor3f(c,0,0)
|
|
|
|
if path.type == 'retract':
|
|
|
|
glColor3f(0,c,c)
|
|
|
|
if c > 0.4 and path.type == 'extrude':
|
|
|
|
for i in xrange(0, len(path.list)-1):
|
|
|
|
v0 = path.list[i]
|
|
|
|
v1 = path.list[i+1]
|
2012-03-19 10:45:40 +00:00
|
|
|
|
2012-03-29 09:01:33 +00:00
|
|
|
# Calculate line width from ePerDistance (needs layer thickness and filament diameter)
|
|
|
|
dist = (v0 - v1).vsize()
|
|
|
|
if dist > 0 and layerThickness > 0:
|
2012-03-31 19:48:23 +00:00
|
|
|
extrusionMMperDist = (v1.e - v0.e) / dist
|
2012-03-29 09:01:33 +00:00
|
|
|
lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
|
2012-03-18 22:00:33 +00:00
|
|
|
|
2012-03-29 09:01:33 +00:00
|
|
|
normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
|
|
|
|
normal.normalize()
|
|
|
|
v2 = v0 + normal * lineWidth
|
|
|
|
v3 = v1 + normal * lineWidth
|
|
|
|
v0 = v0 - normal * lineWidth
|
|
|
|
v1 = v1 - normal * lineWidth
|
2012-02-28 16:39:46 +00:00
|
|
|
|
2012-03-29 09:01:33 +00:00
|
|
|
glBegin(GL_QUADS)
|
|
|
|
if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
|
|
|
|
glVertex3f(v0.x, v0.y, v0.z - 0.02)
|
|
|
|
glVertex3f(v1.x, v1.y, v1.z - 0.02)
|
|
|
|
glVertex3f(v3.x, v3.y, v3.z - 0.02)
|
|
|
|
glVertex3f(v2.x, v2.y, v2.z - 0.02)
|
|
|
|
else:
|
|
|
|
glVertex3f(v0.x, v0.y, v0.z - 0.01)
|
|
|
|
glVertex3f(v1.x, v1.y, v1.z - 0.01)
|
|
|
|
glVertex3f(v3.x, v3.y, v3.z - 0.01)
|
|
|
|
glVertex3f(v2.x, v2.y, v2.z - 0.01)
|
|
|
|
glEnd()
|
2012-03-22 15:04:53 +00:00
|
|
|
|
2012-03-29 09:01:33 +00:00
|
|
|
#for v in path['list']:
|
|
|
|
# glBegin(GL_TRIANGLE_FAN)
|
|
|
|
# glVertex3f(v.x, v.y, v.z - 0.001)
|
|
|
|
# for i in xrange(0, 16+1):
|
|
|
|
# if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
|
|
|
|
# glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.02)
|
|
|
|
# else:
|
|
|
|
# glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.01)
|
|
|
|
# glEnd()
|
|
|
|
else:
|
|
|
|
glBegin(GL_LINE_STRIP)
|
|
|
|
for v in path.list:
|
|
|
|
glVertex3f(v.x, v.y, v.z)
|
|
|
|
glEnd()
|
|
|
|
curLayerNum += 1
|
2012-02-26 13:30:34 +00:00
|
|
|
glEndList()
|
2012-03-18 12:00:31 +00:00
|
|
|
if self.viewMode == "GCode" or self.viewMode == "Mixed":
|
|
|
|
glCallList(self.gcodeDisplayList)
|
2012-02-20 23:54:04 +00:00
|
|
|
|
2012-02-23 21:47:42 +00:00
|
|
|
if self.parent.triangleMesh != None:
|
2012-02-20 23:54:04 +00:00
|
|
|
if self.modelDisplayList == None:
|
|
|
|
self.modelDisplayList = glGenLists(1);
|
2012-02-23 21:47:42 +00:00
|
|
|
if self.parent.modelDirty:
|
|
|
|
self.parent.modelDirty = False
|
2012-03-17 11:03:38 +00:00
|
|
|
multiX = int(profile.getProfileSetting('model_multiply_x'))
|
|
|
|
multiY = int(profile.getProfileSetting('model_multiply_y'))
|
2012-03-28 14:53:08 +00:00
|
|
|
modelSize = self.parent.triangleMesh.getMaximum() - self.parent.triangleMesh.getMinimum()
|
2012-02-20 23:54:04 +00:00
|
|
|
glNewList(self.modelDisplayList, GL_COMPILE)
|
2012-03-16 11:07:43 +00:00
|
|
|
glPushMatrix()
|
2012-03-18 22:00:33 +00:00
|
|
|
glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
|
2012-03-16 11:07:43 +00:00
|
|
|
for mx in xrange(0, multiX):
|
|
|
|
for my in xrange(0, multiY):
|
2012-04-05 20:35:52 +00:00
|
|
|
glPushMatrix()
|
|
|
|
glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
|
|
|
|
opengl.DrawSTL(self.parent.triangleMesh)
|
|
|
|
glPopMatrix()
|
2012-03-16 11:07:43 +00:00
|
|
|
glPopMatrix()
|
2012-02-20 23:54:04 +00:00
|
|
|
glEndList()
|
2012-04-05 20:35:52 +00:00
|
|
|
|
2012-03-18 12:00:31 +00:00
|
|
|
if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed":
|
2012-04-05 20:35:52 +00:00
|
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0])
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0])
|
2012-02-20 23:54:04 +00:00
|
|
|
#If we want transparent, then first render a solid black model to remove the printer size lines.
|
2012-03-18 12:00:31 +00:00
|
|
|
if self.viewMode != "Mixed":
|
|
|
|
glDisable(GL_BLEND)
|
|
|
|
glDisable(GL_LIGHTING)
|
|
|
|
glColor3f(0,0,0)
|
|
|
|
glCallList(self.modelDisplayList)
|
|
|
|
glColor3f(1,1,1)
|
2012-02-20 23:54:04 +00:00
|
|
|
#After the black model is rendered, render the model again but now with lighting and no depth testing.
|
|
|
|
glDisable(GL_DEPTH_TEST)
|
|
|
|
glEnable(GL_LIGHTING)
|
|
|
|
glEnable(GL_BLEND)
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE)
|
|
|
|
glEnable(GL_LIGHTING)
|
|
|
|
glCallList(self.modelDisplayList)
|
2012-03-18 12:00:31 +00:00
|
|
|
elif self.viewMode == "Model - X-Ray":
|
2012-02-29 17:25:57 +00:00
|
|
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
|
|
|
|
glDisable(GL_DEPTH_TEST)
|
|
|
|
glEnable(GL_STENCIL_TEST);
|
|
|
|
glStencilFunc(GL_ALWAYS, 1, 1)
|
|
|
|
glStencilOp(GL_INCR, GL_INCR, GL_INCR)
|
|
|
|
glCallList(self.modelDisplayList)
|
|
|
|
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
|
|
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
|
|
|
|
glStencilFunc(GL_EQUAL, 0, 1);
|
2012-03-18 12:00:31 +00:00
|
|
|
glColor(1, 1, 1)
|
2012-02-29 17:25:57 +00:00
|
|
|
glCallList(self.modelDisplayList)
|
|
|
|
glStencilFunc(GL_EQUAL, 1, 1);
|
|
|
|
glColor(1, 0, 0)
|
|
|
|
glCallList(self.modelDisplayList)
|
|
|
|
|
|
|
|
glPushMatrix()
|
|
|
|
glLoadIdentity()
|
2012-03-18 12:00:31 +00:00
|
|
|
for i in xrange(2, 15, 2):
|
2012-02-29 17:25:57 +00:00
|
|
|
glStencilFunc(GL_EQUAL, i, 0xFF);
|
2012-03-18 12:00:31 +00:00
|
|
|
glColor(float(i)/10, float(i)/10, float(i)/5)
|
2012-02-29 17:25:57 +00:00
|
|
|
glBegin(GL_QUADS)
|
2012-03-05 21:30:54 +00:00
|
|
|
glVertex3f(-1000,-1000,-1)
|
|
|
|
glVertex3f( 1000,-1000,-1)
|
|
|
|
glVertex3f( 1000, 1000,-1)
|
|
|
|
glVertex3f(-1000, 1000,-1)
|
2012-02-29 17:25:57 +00:00
|
|
|
glEnd()
|
2012-03-18 12:00:31 +00:00
|
|
|
for i in xrange(1, 15, 2):
|
2012-02-29 17:25:57 +00:00
|
|
|
glStencilFunc(GL_EQUAL, i, 0xFF);
|
|
|
|
glColor(float(i)/10, 0, 0)
|
|
|
|
glBegin(GL_QUADS)
|
2012-03-05 21:30:54 +00:00
|
|
|
glVertex3f(-1000,-1000,-1)
|
|
|
|
glVertex3f( 1000,-1000,-1)
|
|
|
|
glVertex3f( 1000, 1000,-1)
|
|
|
|
glVertex3f(-1000, 1000,-1)
|
2012-02-29 17:25:57 +00:00
|
|
|
glEnd()
|
|
|
|
glPopMatrix()
|
|
|
|
|
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
glEnable(GL_DEPTH_TEST)
|
2012-03-18 12:00:31 +00:00
|
|
|
elif self.viewMode == "Model - Normal":
|
2012-04-05 20:35:52 +00:00
|
|
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])
|
|
|
|
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0])
|
2012-02-20 23:54:04 +00:00
|
|
|
glEnable(GL_LIGHTING)
|
|
|
|
glCallList(self.modelDisplayList)
|
2012-03-21 11:18:57 +00:00
|
|
|
|
|
|
|
if self.viewMode == "Model - Normal" or self.viewMode == "Model - Transparent" or self.viewMode == "Model - X-Ray":
|
2012-03-19 16:11:50 +00:00
|
|
|
glDisable(GL_LIGHTING)
|
|
|
|
glDisable(GL_DEPTH_TEST)
|
2012-03-21 11:18:57 +00:00
|
|
|
glDisable(GL_BLEND)
|
2012-03-19 16:11:50 +00:00
|
|
|
glColor3f(1,0,0)
|
|
|
|
glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
|
|
|
|
glBegin(GL_LINES)
|
|
|
|
for err in self.parent.errorList:
|
|
|
|
glVertex3f(err[0].x, err[0].y, err[0].z)
|
|
|
|
glVertex3f(err[1].x, err[1].y, err[1].z)
|
|
|
|
glEnd()
|
2012-03-22 15:04:53 +00:00
|
|
|
|
2012-03-09 15:12:59 +00:00
|
|
|
glFlush()
|