2012-04-10 14:45:53 +00:00
from __future__ import division
2012-05-03 16:41:58 +00:00
import sys , math , threading , re , time , os
2012-02-19 23:30:49 +00:00
2012-02-29 17:25:57 +00:00
from wx import glcanvas
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-04-18 10:15:07 +00:00
from gui import toolbarUtil
2012-04-05 20:35:52 +00:00
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-05-29 11:42:33 +00:00
from util import sliceRun
2012-03-15 16:14:20 +00:00
2012-04-24 16:46:29 +00:00
class previewObject ( ) :
def __init__ ( self ) :
self . mesh = None
self . filename = None
self . displayList = None
self . dirty = False
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-04-18 10:15:07 +00:00
super ( previewPanel , self ) . __init__ ( parent , - 1 )
2012-02-23 13:08:34 +00:00
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-02-23 21:47:42 +00:00
self . glCanvas = PreviewGLCanvas ( self )
2012-04-24 16:46:29 +00:00
self . objectList = [ ]
2012-05-03 18:09:46 +00:00
self . errorList = [ ]
2012-02-28 16:39:46 +00:00
self . gcode = None
2012-04-24 16:46:29 +00:00
self . objectsMinV = None
self . objectsMaxV = None
2012-03-22 15:04:53 +00:00
self . loadThread = None
2012-05-01 09:39:52 +00:00
self . machineSize = util3d . Vector3 ( profile . getPreferenceFloat ( ' machine_width ' ) , profile . getPreferenceFloat ( ' machine_depth ' ) , profile . getPreferenceFloat ( ' 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-04-18 10:15:07 +00:00
self . toolbar = toolbarUtil . Toolbar ( self )
2012-02-28 14:02:24 +00:00
2012-04-18 10:39:05 +00:00
group = [ ]
2012-04-18 17:03:31 +00:00
toolbarUtil . RadioButton ( self . toolbar , group , ' object-3d-on.png ' , ' object-3d-off.png ' , ' 3D view ' , callback = self . On3DClick )
toolbarUtil . RadioButton ( self . toolbar , group , ' object-top-on.png ' , ' object-top-off.png ' , ' Topdown view ' , callback = self . OnTopClick )
2012-04-18 10:39:05 +00:00
self . toolbar . AddSeparator ( )
2012-02-28 16:39:46 +00:00
2012-04-18 13:14:43 +00:00
group = [ ]
2012-04-18 18:27:34 +00:00
self . normalViewButton = toolbarUtil . RadioButton ( self . toolbar , group , ' view-normal-on.png ' , ' view-normal-off.png ' , ' Normal model view ' , callback = self . OnViewChange )
self . transparentViewButton = toolbarUtil . RadioButton ( self . toolbar , group , ' view-transparent-on.png ' , ' view-transparent-off.png ' , ' Transparent model view ' , callback = self . OnViewChange )
self . xrayViewButton = toolbarUtil . RadioButton ( self . toolbar , group , ' view-xray-on.png ' , ' view-xray-off.png ' , ' X-Ray view ' , callback = self . OnViewChange )
self . gcodeViewButton = toolbarUtil . RadioButton ( self . toolbar , group , ' view-gcode-on.png ' , ' view-gcode-off.png ' , ' GCode view ' , callback = self . OnViewChange )
self . mixedViewButton = toolbarUtil . RadioButton ( self . toolbar , group , ' view-mixed-on.png ' , ' view-mixed-off.png ' , ' Mixed model/GCode view ' , callback = self . OnViewChange )
2012-04-18 13:14:43 +00:00
self . toolbar . AddSeparator ( )
2012-03-18 12:00:31 +00:00
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
2012-04-18 10:15:07 +00:00
self . toolbar2 = toolbarUtil . Toolbar ( self )
2012-03-21 14:53:29 +00:00
2012-04-18 09:00:41 +00:00
# Mirror
2012-04-18 10:15:07 +00:00
self . mirrorX = toolbarUtil . ToggleButton ( self . toolbar2 , ' flip_x ' , ' object-mirror-x-on.png ' , ' object-mirror-x-off.png ' , ' Mirror X ' , callback = self . updateModelTransform )
self . mirrorY = toolbarUtil . ToggleButton ( self . toolbar2 , ' flip_y ' , ' object-mirror-y-on.png ' , ' object-mirror-y-off.png ' , ' Mirror Y ' , callback = self . updateModelTransform )
self . mirrorZ = toolbarUtil . ToggleButton ( self . toolbar2 , ' flip_z ' , ' object-mirror-z-on.png ' , ' object-mirror-z-off.png ' , ' Mirror Z ' , callback = self . updateModelTransform )
2012-04-12 20:18:34 +00:00
self . toolbar2 . AddSeparator ( )
2012-04-18 09:00:41 +00:00
# Swap
2012-04-18 10:15:07 +00:00
self . swapXZ = toolbarUtil . ToggleButton ( self . toolbar2 , ' swap_xz ' , ' object-swap-xz-on.png ' , ' object-swap-xz-off.png ' , ' Swap XZ ' , callback = self . updateModelTransform )
self . swapYZ = toolbarUtil . ToggleButton ( self . toolbar2 , ' swap_yz ' , ' object-swap-yz-on.png ' , ' object-swap-yz-off.png ' , ' Swap YZ ' , callback = self . updateModelTransform )
2012-04-17 22:41:40 +00:00
self . toolbar2 . AddSeparator ( )
2012-04-18 09:00:41 +00:00
# Scale
2012-04-18 10:15:07 +00:00
self . scaleReset = toolbarUtil . NormalButton ( self . toolbar2 , self . OnScaleReset , ' object-scale.png ' , ' Reset model scale ' )
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 )
2012-04-18 09:00:41 +00:00
self . scale . Bind ( wx . EVT_TEXT , self . OnScale )
2012-04-18 10:22:01 +00:00
self . scaleMax = toolbarUtil . NormalButton ( self . toolbar2 , self . OnScaleMax , ' object-max-size.png ' , ' Scale object to fix machine size ' )
2012-03-22 10:24:52 +00:00
2012-04-17 22:41:40 +00:00
self . toolbar2 . AddSeparator ( )
2012-04-18 09:00:41 +00:00
# Multiply
2012-04-29 12:22:20 +00:00
#self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')
#self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')
#self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')
#self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')
#self.toolbar2.AddSeparator()
2012-04-17 22:41:40 +00:00
2012-04-18 09:00:41 +00:00
# Rotate
2012-04-18 10:15:07 +00:00
self . rotateReset = toolbarUtil . NormalButton ( self . toolbar2 , self . OnRotateReset , ' object-rotate.png ' , ' Reset model rotation ' )
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-05-03 16:41:58 +00:00
self . rotate . 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-05-02 12:14:41 +00:00
self . OnViewChange ( )
2012-03-05 21:30:54 +00:00
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-12 21:13:56 +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 ) ) )
2012-04-18 15:48:34 +00:00
self . glCanvas . Refresh ( )
2012-03-22 10:24:52 +00:00
def OnMulXSubClick ( self , e ) :
profile . putProfileSetting ( ' model_multiply_x ' , str ( max ( 1 , int ( profile . getProfileSetting ( ' model_multiply_x ' ) ) - 1 ) ) )
2012-04-18 15:48:34 +00:00
self . glCanvas . Refresh ( )
2012-03-22 10:24:52 +00:00
def OnMulYAddClick ( self , e ) :
profile . putProfileSetting ( ' model_multiply_y ' , str ( max ( 1 , int ( profile . getProfileSetting ( ' model_multiply_y ' ) ) + 1 ) ) )
2012-04-18 15:48:34 +00:00
self . glCanvas . Refresh ( )
2012-03-22 10:24:52 +00:00
def OnMulYSubClick ( self , e ) :
profile . putProfileSetting ( ' model_multiply_y ' , str ( max ( 1 , int ( profile . getProfileSetting ( ' model_multiply_y ' ) ) - 1 ) ) )
2012-04-18 15:48:34 +00:00
self . glCanvas . Refresh ( )
2012-03-22 10:24:52 +00:00
2012-04-17 23:51:34 +00:00
def OnScaleReset ( self , e ) :
2012-04-17 23:56:25 +00:00
self . scale . SetValue ( ' 1.0 ' )
2012-04-18 09:00:41 +00:00
self . OnScale ( None )
2012-04-17 23:51:34 +00:00
2012-03-21 15:53:05 +00:00
def OnScale ( self , e ) :
2012-04-18 14:08:58 +00:00
scale = 1.0
if self . scale . GetValue ( ) != ' ' :
2012-04-18 15:06:32 +00:00
scale = self . scale . GetValue ( )
2012-04-18 14:08:58 +00:00
profile . putProfileSetting ( ' model_scale ' , scale )
2012-04-18 15:04:03 +00:00
self . glCanvas . Refresh ( )
2012-03-22 11:33:39 +00:00
2012-04-17 10:08:19 +00:00
def OnScaleMax ( self , e ) :
2012-04-24 16:46:29 +00:00
if self . objectsMinV == None :
2012-04-17 10:08:19 +00:00
return
2012-04-24 16:46:29 +00:00
vMin = self . objectsMinV
vMax = self . objectsMaxV
2012-04-17 10:08:19 +00:00
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 ( ) )
2012-04-18 15:04:03 +00:00
self . glCanvas . Refresh ( )
2012-04-17 23:51:34 +00:00
def OnRotateReset ( self , e ) :
self . rotate . SetValue ( 0 )
2012-04-18 09:00:41 +00:00
self . OnRotate ( None )
2012-04-17 23:51:34 +00:00
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-04-18 10:39:05 +00:00
def On3DClick ( self ) :
2012-02-28 14:02:24 +00:00
self . glCanvas . yaw = 30
self . glCanvas . pitch = 60
2012-04-22 11:11:21 +00:00
self . glCanvas . zoom = 300
2012-02-28 14:02:24 +00:00
self . glCanvas . view3D = True
self . glCanvas . Refresh ( )
2012-04-18 10:39:05 +00:00
def OnTopClick ( self ) :
2012-02-28 14:02:24 +00:00
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 ) :
self . glCanvas . Refresh ( )
2012-04-23 12:16:23 +00:00
def updateCenterX ( self ) :
self . machineCenter . x = profile . getProfileSettingFloat ( ' machine_center_x ' )
2012-02-24 22:01:22 +00:00
self . glCanvas . Refresh ( )
2012-04-23 12:16:23 +00:00
def updateCenterY ( self ) :
self . machineCenter . y = profile . getProfileSettingFloat ( ' machine_center_y ' )
2012-02-24 22:01:22 +00:00
self . glCanvas . Refresh ( )
2012-02-19 23:30:49 +00:00
2012-03-23 13:04:50 +00:00
def setViewMode ( self , mode ) :
2012-04-18 13:14:43 +00:00
if mode == " Normal " :
self . normalViewButton . SetValue ( True )
if mode == " GCode " :
self . gcodeViewButton . SetValue ( True )
self . glCanvas . viewMode = mode
2012-03-23 13:04:50 +00:00
wx . CallAfter ( self . glCanvas . Refresh )
2012-04-24 16:46:29 +00:00
def loadModelFiles ( self , filelist ) :
while len ( filelist ) > len ( self . objectList ) :
self . objectList . append ( previewObject ( ) )
2012-04-29 09:44:07 +00:00
for idx in xrange ( len ( filelist ) , len ( self . objectList ) ) :
2012-04-24 16:46:29 +00:00
self . objectList [ idx ] . mesh = None
2012-04-29 09:44:07 +00:00
self . objectList [ idx ] . filename = None
2012-04-24 16:46:29 +00:00
for idx in xrange ( 0 , len ( filelist ) ) :
obj = self . objectList [ idx ]
if obj . filename != filelist [ idx ] :
obj . fileTime = None
self . gcodeFileTime = None
self . logFileTime = None
obj . filename = filelist [ idx ]
2012-03-19 15:15:16 +00:00
2012-05-29 11:42:33 +00:00
self . gcodeFilename = sliceRun . getExportFilename ( filelist [ 0 ] )
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
2012-04-24 16:46:29 +00:00
def loadReModelFiles ( self , filelist ) :
2012-03-20 11:22:44 +00:00
#Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
2012-04-24 16:46:29 +00:00
for idx in xrange ( 0 , len ( filelist ) ) :
if self . objectList [ idx ] . filename != filelist [ idx ] :
return False
self . loadModelFiles ( filelist )
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-04-24 16:46:29 +00:00
for obj in self . objectList :
2012-04-29 09:44:07 +00:00
if obj . filename != None and os . path . isfile ( obj . filename ) and obj . fileTime != os . stat ( obj . filename ) . st_mtime :
2012-04-24 16:46:29 +00:00
obj . ileTime = os . stat ( obj . filename ) . st_mtime
mesh = stl . stlModel ( )
mesh . load ( obj . filename )
obj . dirty = False
obj . mesh = mesh
self . updateModelTransform ( )
2012-06-21 12:18:31 +00:00
self . errorList = [ ]
2012-04-24 16:46:29 +00:00
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 )
2012-03-19 15:15:16 +00:00
self . gcodeDirty = False
self . gcode = gcode
self . gcodeDirty = True
2012-07-05 12:12:13 +00:00
2012-03-19 16:11:50 +00:00
errorList = [ ]
2012-07-05 12:12:13 +00:00
for line in open ( self . gcodeFilename , " 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 )
2012-03-19 16:11:50 +00:00
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
2012-07-05 12:12:13 +00:00
wx . CallAfter ( self . updateToolbar )
2012-03-19 16:11:50 +00:00
wx . CallAfter ( self . glCanvas . Refresh )
2012-07-05 12:12:13 +00:00
elif not os . path . isfile ( self . gcodeFilename ) :
self . gcode = None
2012-02-21 22:05:30 +00:00
2012-03-22 15:04:53 +00:00
def loadProgress ( self , progress ) :
2012-04-24 16:46:29 +00:00
pass
2012-03-22 15:04:53 +00:00
2012-02-28 16:39:46 +00:00
def updateToolbar ( self ) :
2012-05-02 12:14:41 +00:00
self . gcodeViewButton . Show ( self . gcode != None )
self . mixedViewButton . Show ( self . gcode != None )
self . layerSpin . Show ( self . glCanvas . viewMode == " GCode " or self . glCanvas . viewMode == " Mixed " )
2012-02-28 16:39:46 +00:00
if self . gcode != None :
2012-05-03 18:09:46 +00:00
self . layerSpin . SetRange ( 1 , len ( self . gcode . layerList ) - 1 )
2012-03-05 21:30:54 +00:00
self . toolbar . Realize ( )
2012-02-28 16:39:46 +00:00
2012-04-18 13:14:43 +00:00
def OnViewChange ( self ) :
if self . normalViewButton . GetValue ( ) :
self . glCanvas . viewMode = " Normal "
elif self . transparentViewButton . GetValue ( ) :
self . glCanvas . viewMode = " Transparent "
elif self . xrayViewButton . GetValue ( ) :
self . glCanvas . viewMode = " X-Ray "
elif self . gcodeViewButton . GetValue ( ) :
self . glCanvas . viewMode = " GCode "
elif self . mixedViewButton . GetValue ( ) :
self . glCanvas . viewMode = " Mixed "
2012-05-02 12:14:41 +00:00
self . updateToolbar ( )
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 ) :
2012-04-24 16:46:29 +00:00
if len ( self . objectList ) < 1 or self . objectList [ 0 ] . mesh == None :
return
2012-05-18 08:10:51 +00:00
rotate = profile . getProfileSettingFloat ( ' model_rotate_base ' )
mirrorX = profile . getProfileSetting ( ' flip_x ' ) == ' True '
mirrorY = profile . getProfileSetting ( ' flip_y ' ) == ' True '
mirrorZ = profile . getProfileSetting ( ' flip_z ' ) == ' True '
swapXZ = profile . getProfileSetting ( ' swap_xz ' ) == ' True '
swapYZ = profile . getProfileSetting ( ' swap_yz ' ) == ' True '
2012-04-24 16:46:29 +00:00
for obj in self . objectList :
if obj . mesh == None :
continue
2012-05-18 08:10:51 +00:00
obj . mesh . setRotateMirror ( rotate , mirrorX , mirrorY , mirrorZ , swapXZ , swapYZ )
2012-04-24 16:46:29 +00:00
minV = self . objectList [ 0 ] . mesh . getMinimum ( )
maxV = self . objectList [ 0 ] . mesh . getMaximum ( )
for obj in self . objectList :
if obj . mesh == None :
continue
obj . mesh . getMinimumZ ( )
minV = minV . min ( obj . mesh . getMinimum ( ) )
maxV = maxV . max ( obj . mesh . getMaximum ( ) )
self . objectsMaxV = maxV
self . objectsMinV = minV
for obj in self . objectList :
if obj . mesh == None :
continue
for v in obj . mesh . vertexes :
v . z - = minV . z
v . x - = minV . x + ( maxV . x - minV . x ) / 2
v . y - = minV . y + ( maxV . y - minV . y ) / 2
obj . mesh . getMinimumZ ( )
obj . dirty = True
2012-03-07 15:58:04 +00:00
self . glCanvas . Refresh ( )
2012-06-22 04:53:18 +00:00
def updateProfileToControls ( self ) :
self . scale . SetValue ( profile . getProfileSetting ( ' model_scale ' ) )
self . rotate . SetValue ( profile . getProfileSettingFloat ( ' model_rotate_base ' ) )
self . mirrorX . SetValue ( profile . getProfileSetting ( ' flip_x ' ) == ' True ' )
self . mirrorY . SetValue ( profile . getProfileSetting ( ' flip_y ' ) == ' True ' )
self . mirrorZ . SetValue ( profile . getProfileSetting ( ' flip_z ' ) == ' True ' )
self . swapXZ . SetValue ( profile . getProfileSetting ( ' swap_xz ' ) == ' True ' )
self . swapYZ . SetValue ( profile . getProfileSetting ( ' swap_yz ' ) == ' True ' )
self . updateModelTransform ( )
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-03-18 12:00:31 +00:00
self . gcodeDisplayList = None
2012-05-07 11:51:28 +00:00
self . gcodeDisplayListMade = None
2012-05-03 16:41:58 +00:00
self . gcodeDisplayListCount = 0
2012-04-24 16:46:29 +00:00
self . objColor = [ [ 1.0 , 0.8 , 0.6 , 1.0 ] , [ 0.2 , 1.0 , 0.1 , 1.0 ] , [ 1.0 , 0.2 , 0.1 , 1.0 ] , [ 0.1 , 0.2 , 1.0 , 1.0 ] ]
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-05-31 16:37:59 +00:00
#Workaround for buggy ATI cards.
2012-05-18 08:26:13 +00:00
size = self . GetSizeTuple ( )
self . SetSize ( ( size [ 0 ] + 1 , size [ 1 ] ) )
self . SetSize ( ( size [ 0 ] , size [ 1 ] ) )
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. \n No 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 )
2012-05-03 18:09:46 +00:00
if self . viewMode == " GCode " or self . viewMode == " Mixed " :
2012-05-16 10:10:56 +00:00
if self . parent . gcode != None and len ( self . parent . gcode . layerList ) > self . parent . layerSpin . GetValue ( ) and len ( self . parent . gcode . layerList [ self . parent . layerSpin . GetValue ( ) ] ) > 0 :
2012-05-03 18:09:46 +00:00
glTranslate ( 0 , 0 , - self . parent . gcode . layerList [ self . parent . layerSpin . GetValue ( ) ] [ 0 ] . list [ - 1 ] . z )
else :
if self . parent . objectsMaxV != None :
glTranslate ( 0 , 0 , - self . parent . objectsMaxV . z * profile . getProfileSettingFloat ( ' model_scale ' ) / 2 )
2012-04-05 20:35:52 +00:00
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-05-03 18:09:46 +00:00
if self . parent . gcode != None and self . parent . gcodeDirty :
if self . gcodeDisplayListCount < len ( self . parent . gcode . layerList ) or self . gcodeDisplayList == None :
if self . gcodeDisplayList != None :
glDeleteLists ( self . gcodeDisplayList , self . gcodeDisplayListCount )
self . gcodeDisplayList = glGenLists ( len ( self . parent . gcode . layerList ) ) ;
self . gcodeDisplayListCount = len ( self . parent . gcode . layerList )
self . parent . gcodeDirty = False
2012-05-07 16:12:26 +00:00
self . gcodeDisplayListMade = 0
2012-05-07 11:51:28 +00:00
2012-05-07 16:12:26 +00:00
if self . parent . gcode != None and self . gcodeDisplayListMade < len ( self . parent . gcode . layerList ) :
glNewList ( self . gcodeDisplayList + self . gcodeDisplayListMade , GL_COMPILE )
opengl . DrawGCodeLayer ( self . parent . gcode . layerList [ self . gcodeDisplayListMade ] )
glEndList ( )
self . gcodeDisplayListMade + = 1
self . Refresh ( )
2012-02-20 23:54:04 +00:00
2012-05-03 18:09:46 +00:00
if self . parent . gcode != None and ( self . viewMode == " GCode " or self . viewMode == " Mixed " ) :
glEnable ( GL_COLOR_MATERIAL )
glEnable ( GL_LIGHTING )
2012-05-07 16:12:26 +00:00
drawUpToLayer = min ( self . gcodeDisplayListMade , self . parent . layerSpin . GetValue ( ) + 1 )
2012-07-06 12:59:03 +00:00
starttime = time . time ( )
for i in xrange ( drawUpToLayer - 1 , - 1 , - 1 ) :
2012-05-03 18:09:46 +00:00
c = 1.0
if i < self . parent . layerSpin . GetValue ( ) :
2012-05-07 16:12:26 +00:00
c = 0.9 - ( drawUpToLayer - i ) * 0.1
2012-05-03 18:09:46 +00:00
if c < 0.4 :
c = ( 0.4 + c ) / 2
if c < 0.1 :
c = 0.1
glLightfv ( GL_LIGHT0 , GL_DIFFUSE , [ 0 , 0 , 0 , 0 ] )
glLightfv ( GL_LIGHT0 , GL_AMBIENT , [ c , c , c , c ] )
2012-05-07 16:12:26 +00:00
glCallList ( self . gcodeDisplayList + i )
2012-07-06 12:59:03 +00:00
if time . time ( ) - starttime > 0.1 :
break
2012-05-03 18:09:46 +00:00
glDisable ( GL_LIGHTING )
glDisable ( GL_COLOR_MATERIAL )
glMaterialfv ( GL_FRONT_AND_BACK , GL_AMBIENT , [ 0.2 , 0.2 , 0.2 , 1.0 ] ) ;
glMaterialfv ( GL_FRONT_AND_BACK , GL_DIFFUSE , [ 0.8 , 0.8 , 0.8 , 1.0 ] ) ;
glColor3f ( 1.0 , 1.0 , 1.0 )
2012-06-21 12:18:31 +00:00
glPushMatrix ( )
2012-04-24 16:46:29 +00:00
glTranslate ( self . parent . machineCenter . x , self . parent . machineCenter . y , 0 )
for obj in self . parent . objectList :
if obj . mesh == None :
continue
if obj . displayList == None :
obj . displayList = glGenLists ( 1 ) ;
if obj . dirty :
obj . dirty = False
glNewList ( obj . displayList , GL_COMPILE )
opengl . DrawSTL ( obj . mesh )
2012-02-20 23:54:04 +00:00
glEndList ( )
2012-04-05 20:35:52 +00:00
2012-04-18 13:14:43 +00:00
if self . viewMode == " Transparent " or self . viewMode == " Mixed " :
2012-04-24 16:46:29 +00:00
glLightfv ( GL_LIGHT0 , GL_DIFFUSE , map ( lambda x : x / 2 , self . objColor [ self . parent . objectList . index ( obj ) ] ) )
glLightfv ( GL_LIGHT0 , GL_AMBIENT , map ( lambda x : x / 10 , self . objColor [ self . parent . objectList . index ( obj ) ] ) )
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 )
2012-05-03 18:09:46 +00:00
glColor3f ( 0.0 , 0.0 , 0.0 )
2012-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-05-03 18:09:46 +00:00
glColor3f ( 1.0 , 1.0 , 1.0 )
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 )
2012-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-04-18 13:14:43 +00:00
elif self . viewMode == " 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 )
2012-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-02-29 17:25:57 +00:00
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-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-02-29 17:25:57 +00:00
glStencilFunc ( GL_EQUAL , 1 , 1 ) ;
glColor ( 1 , 0 , 0 )
2012-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-02-29 17:25:57 +00:00
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-04-18 13:14:43 +00:00
elif self . viewMode == " Normal " :
2012-04-24 16:46:29 +00:00
glLightfv ( GL_LIGHT0 , GL_DIFFUSE , self . objColor [ self . parent . objectList . index ( obj ) ] )
glLightfv ( GL_LIGHT0 , GL_AMBIENT , map ( lambda x : x / 5 , self . objColor [ self . parent . objectList . index ( obj ) ] ) )
2012-02-20 23:54:04 +00:00
glEnable ( GL_LIGHTING )
2012-04-24 16:46:29 +00:00
self . drawModel ( obj )
2012-06-21 12:18:31 +00:00
glPopMatrix ( )
2012-05-03 18:09:46 +00:00
if self . viewMode == " Normal " or self . viewMode == " Transparent " or self . viewMode == " X-Ray " :
glDisable ( GL_LIGHTING )
glDisable ( GL_DEPTH_TEST )
glDisable ( GL_BLEND )
glColor3f ( 1 , 0 , 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 ( )
glEnable ( GL_DEPTH_TEST )
2012-03-09 15:12:59 +00:00
glFlush ( )
2012-04-18 15:48:34 +00:00
2012-04-24 16:46:29 +00:00
def drawModel ( self , obj ) :
2012-04-29 12:22:20 +00:00
multiX = 1 #int(profile.getProfileSetting('model_multiply_x'))
multiY = 1 #int(profile.getProfileSetting('model_multiply_y'))
2012-04-18 15:48:34 +00:00
modelScale = profile . getProfileSettingFloat ( ' model_scale ' )
2012-04-24 16:46:29 +00:00
modelSize = ( obj . mesh . getMaximum ( ) - obj . mesh . getMinimum ( ) ) * modelScale
2012-04-18 15:48:34 +00:00
glPushMatrix ( )
glTranslate ( - ( modelSize . x + 10 ) * ( multiX - 1 ) / 2 , - ( modelSize . y + 10 ) * ( multiY - 1 ) / 2 , 0 )
for mx in xrange ( 0 , multiX ) :
for my in xrange ( 0 , multiY ) :
glPushMatrix ( )
glTranslate ( ( modelSize . x + 10 ) * mx , ( modelSize . y + 10 ) * my , 0 )
glScalef ( modelScale , modelScale , modelScale )
2012-04-24 16:46:29 +00:00
glCallList ( obj . displayList )
2012-04-18 15:48:34 +00:00
glPopMatrix ( )
glPopMatrix ( )