import threading
import math
import platform
+import cStringIO as StringIO
import OpenGL
-OpenGL.ERROR_CHECKING = False
+#OpenGL.ERROR_CHECKING = False
from OpenGL.GLU import *
from OpenGL.GL import *
from Cura.util import sliceEngine
from Cura.util import machineCom
from Cura.util import removableStorage
-from Cura.util import gcodeInterpreter
from Cura.util import explorer
from Cura.util.printerConnection import printerConnectionManager
from Cura.gui.util import previewTools
from Cura.gui.util import opengl
from Cura.gui.util import openglGui
+from Cura.gui.util import engineResultView
from Cura.gui.tools import youmagineGui
from Cura.gui.tools import imageToMesh
self._pitch = 60
self._zoom = 300
self._scene = objectScene.Scene()
- self._gcode = None
- self._gcodeVBOs = []
- self._gcodeFilename = None
- self._gcodeLoadThread = None
self._objectShader = None
self._objectLoadShader = None
self._focusObj = None
self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None)
self.viewSelection = openglGui.glComboButton(self, _("View mode"), [7,19,11,15,23], [_("Normal"), _("Overhang"), _("Transparent"), _("X-Ray"), _("Layers")], (-1,0), self.OnViewChange)
- self.layerSelect = openglGui.glSlider(self, 10000, 0, 1, (-1,-2), lambda : self.QueueRefresh())
self.youMagineButton = openglGui.glButton(self, 26, _("Share on YouMagine"), (2,0), lambda button: youmagineGui.youmagineManager(self.GetTopLevelParent(), self._scene))
self.youMagineButton.setDisabled(True)
self.notification = openglGui.glNotification(self, (0, 0))
- self._slicer = sliceEngine.Slicer(self._updateSliceProgress)
+ self._engine = sliceEngine.Engine(self._updateEngineProgress)
+ self._engineResultView = engineResultView.engineResultView(self)
self._sceneUpdateTimer = wx.Timer(self)
- self.Bind(wx.EVT_TIMER, self._onRunSlicer, self._sceneUpdateTimer)
+ self.Bind(wx.EVT_TIMER, self._onRunEngine, self._sceneUpdateTimer)
self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
def loadGCodeFile(self, filename):
self.OnDeleteAll(None)
- if self._gcode is not None:
- self._gcode = None
- for layerVBOlist in self._gcodeVBOs:
- for vbo in layerVBOlist:
- self.glReleaseList.append(vbo)
- self._gcodeVBOs = []
- self._gcode = gcodeInterpreter.gcode()
- self._gcodeFilename = filename
+ #TODO: Load straight GCodeFile
self.printButton.setBottomText('')
self.viewSelection.setValue(4)
self.printButton.setDisabled(False)
else:
drive = drives[0]
filename = self._scene._objectList[0].getName() + '.gcode'
- threading.Thread(target=self._copyFile,args=(self._gcodeFilename, drive[1] + filename, drive[1])).start()
+ threading.Thread(target=self._saveGCode,args=(drive[1] + filename, drive[1])).start()
elif connectionGroup is not None:
connections = connectionGroup.getAvailableConnections()
if len(connections) < 2:
menu.connectionMap[i.GetId()] = connection
self.Bind(wx.EVT_MENU, lambda e: self._openPrintWindowForConnection(e.GetEventObject().connectionMap[e.GetId()]), i)
self.Bind(wx.EVT_MENU, lambda e: self.showSaveGCode(), menu.Append(-1, _("Save GCode...")))
- self.Bind(wx.EVT_MENU, lambda e: self._showSliceLog(), menu.Append(-1, _("Slice engine log...")))
+ self.Bind(wx.EVT_MENU, lambda e: self._showEngineLog(), menu.Append(-1, _("Slice engine log...")))
self.PopupMenu(menu)
menu.Destroy()
connection.window = printWindow2.printWindow(connection)
connection.window.Show()
connection.window.Raise()
+ #TODO: Fix for _engine.getResult
if not connection.loadFile(self._gcodeFilename):
if connection.isPrinting():
self.notification.message("Cannot start print, because other print still running.")
if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
wx.MessageBox(_("USB printing on the Ultimaker2 is not supported."), _("USB Printing Error"), wx.OK | wx.ICON_WARNING)
return
- self._usbPrintMonitor.loadFile(self._gcodeFilename, self._slicer.getID())
- if self._gcodeFilename == self._slicer.getGCodeFilename():
- self._slicer.submitSliceInfoOnline()
+ #TODO: Fix for _engine.getResult
+ self._usbPrintMonitor.loadFile(self._gcodeFilename, self._engine.getID())
+ if self._gcodeFilename is None:
+ self._engine.submitInfoOnline()
def showSaveGCode(self):
if len(self._scene._objectList) < 1:
filename = dlg.GetPath()
dlg.Destroy()
- threading.Thread(target=self._copyFile,args=(self._gcodeFilename, filename)).start()
+ threading.Thread(target=self._saveGCode,args=(filename,)).start()
- def _copyFile(self, fileA, fileB, allowEject = False):
+ def _saveGCode(self, targetFilename, ejectDrive = False):
+ data = self._engine.getResult().getGCode()
try:
- size = float(os.stat(fileA).st_size)
- with open(fileA, 'rb') as fsrc:
- with open(fileB, 'wb') as fdst:
- while 1:
- buf = fsrc.read(16*1024)
- if not buf:
- break
- fdst.write(buf)
- self.printButton.setProgressBar(float(fsrc.tell()) / size)
- self._queueRefresh()
+ size = float(len(data))
+ fsrc = StringIO.StringIO(data)
+ with open(targetFilename, 'wb') as fdst:
+ while 1:
+ buf = fsrc.read(16*1024)
+ if not buf:
+ break
+ fdst.write(buf)
+ self.printButton.setProgressBar(float(fsrc.tell()) / size)
+ self._queueRefresh()
except:
- import sys
- print sys.exc_info()
+ import sys, traceback
+ traceback.print_exc()
self.notification.message("Failed to save")
else:
- if allowEject:
- self.notification.message("Saved as %s" % (fileB), lambda : self._doEjectSD(allowEject), 31, 'Eject')
+ if ejectDrive:
+ self.notification.message("Saved as %s" % (targetFilename), lambda : self._doEjectSD(ejectDrive), 31, 'Eject')
elif explorer.hasExplorer():
- self.notification.message("Saved as %s" % (fileB), lambda : explorer.openExplorer(fileB), 4, 'Open folder')
+ self.notification.message("Saved as %s" % (targetFilename), lambda : explorer.openExplorer(targetFilename), 4, 'Open folder')
else:
- self.notification.message("Saved as %s" % (fileB))
+ self.notification.message("Saved as %s" % (targetFilename))
self.printButton.setProgressBar(None)
- if fileA == self._slicer.getGCodeFilename():
- self._slicer.submitSliceInfoOnline()
+ self._engine.getResult().submitInfoOnline()
def _doEjectSD(self, drive):
if removableStorage.ejectDrive(drive):
else:
self.notification.message('Safe remove failed...')
- def _showSliceLog(self):
- dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._slicer.getSliceLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
+ def _showEngineLog(self):
+ dlg = wx.TextEntryDialog(self, _("The slicing engine reported the following"), _("Engine log..."), '\n'.join(self._engine.getResult().getLog()), wx.TE_MULTILINE | wx.OK | wx.CENTRE)
dlg.ShowModal()
dlg.Destroy()
def OnViewChange(self):
if self.viewSelection.getValue() == 4:
self.viewMode = 'gcode'
- if self._gcode is not None and self._gcode.layerList is not None:
- self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
- self._selectObject(None)
elif self.viewSelection.getValue() == 1:
self.viewMode = 'overhang'
elif self.viewSelection.getValue() == 2:
self.viewMode = 'xray'
else:
self.viewMode = 'normal'
- self.layerSelect.setHidden(self.viewMode != 'gcode')
+ self._engineResultView.setEnabled(self.viewMode == 'gcode')
self.QueueRefresh()
def OnRotateReset(self, button):
def sceneUpdated(self):
self._sceneUpdateTimer.Start(500, True)
- self._slicer.abortSlicer()
+ self._engine.abortEngine()
self._scene.updateSizeOffsets()
self.QueueRefresh()
- def _onRunSlicer(self, e):
+ def _onRunEngine(self, e):
if self._isSimpleMode:
self.GetTopLevelParent().simpleSettingsPanel.setupSlice()
- self._slicer.runSlicer(self._scene)
+ self._engine.runEngine(self._scene)
if self._isSimpleMode:
profile.resetTempOverride()
- def _updateSliceProgress(self, progressValue, ready):
- if not ready:
+ def _updateEngineProgress(self, progressValue):
+ result = self._engine.getResult()
+ finished = result is not None and result.isFinished()
+ if not finished:
if self.printButton.getProgressBar() is not None and progressValue >= 0.0 and abs(self.printButton.getProgressBar() - progressValue) < 0.01:
return
- self.printButton.setDisabled(not ready)
+ self.printButton.setDisabled(not finished)
if progressValue >= 0.0:
self.printButton.setProgressBar(progressValue)
else:
self.printButton.setProgressBar(None)
- if self._gcode is not None:
- self._gcode = None
- for layerVBOlist in self._gcodeVBOs:
- for vbo in layerVBOlist:
- self.glReleaseList.append(vbo)
- self._gcodeVBOs = []
- if ready:
+ self._engineResultView.setResult(result)
+ if finished:
self.printButton.setProgressBar(None)
- text = '%s' % (self._slicer.getPrintTime())
+ text = '%s' % (result.getPrintTime())
for e in xrange(0, int(profile.getMachineSetting('extruder_amount'))):
- amount = self._slicer.getFilamentAmount(e)
+ amount = result.getFilamentAmount(e)
if amount is None:
continue
text += '\n%s' % (amount)
- cost = self._slicer.getFilamentCost(e)
+ cost = result.getFilamentCost(e)
if cost is not None:
text += '\n%s' % (cost)
self.printButton.setBottomText(text)
- self._gcode = gcodeInterpreter.gcode()
- self._gcodeFilename = self._slicer.getGCodeFilename()
else:
self.printButton.setBottomText('')
self.QueueRefresh()
- def _loadGCode(self):
- self._gcode.progressCallback = self._gcodeLoadCallback
- self._gcode.load(self._gcodeFilename)
-
- def _gcodeLoadCallback(self, progress):
- if not self or self._gcode is None:
- return True
- if len(self._gcode.layerList) % 15 == 0:
- time.sleep(0.1)
- if self._gcode is None:
- return True
- self.layerSelect.setRange(1, len(self._gcode.layerList) - 1)
- if self.viewMode == 'gcode':
- self._queueRefresh()
- return False
-
def loadScene(self, fileList):
for filename in fileList:
try:
self.scaleZmmctrl.setValue(round(size[2], 2))
def OnKeyChar(self, keyCode):
+ if self._engineResultView.OnKeyChar(keyCode):
+ return
if keyCode == wx.WXK_DELETE or keyCode == wx.WXK_NUMPAD_DELETE or (keyCode == wx.WXK_BACK and platform.system() == "Darwin"):
if self._selectedObj is not None:
self._deleteObject(self._selectedObj)
self.QueueRefresh()
- if self.viewMode == 'gcode':
- if keyCode == wx.WXK_UP:
- self.layerSelect.setValue(self.layerSelect.getValue() + 1)
- self.QueueRefresh()
- elif keyCode == wx.WXK_DOWN:
- self.layerSelect.setValue(self.layerSelect.getValue() - 1)
- self.QueueRefresh()
- elif keyCode == wx.WXK_PAGEUP:
- self.layerSelect.setValue(self.layerSelect.getValue() + 10)
- self.QueueRefresh()
- elif keyCode == wx.WXK_PAGEDOWN:
- self.layerSelect.setValue(self.layerSelect.getValue() - 10)
- self.QueueRefresh()
- else:
- if keyCode == wx.WXK_UP:
- if wx.GetKeyState(wx.WXK_SHIFT):
- self._zoom /= 1.2
- if self._zoom < 1:
- self._zoom = 1
- else:
- self._pitch -= 15
- self.QueueRefresh()
- elif keyCode == wx.WXK_DOWN:
- if wx.GetKeyState(wx.WXK_SHIFT):
- self._zoom *= 1.2
- if self._zoom > numpy.max(self._machineSize) * 3:
- self._zoom = numpy.max(self._machineSize) * 3
- else:
- self._pitch += 15
- self.QueueRefresh()
- elif keyCode == wx.WXK_LEFT:
- self._yaw -= 15
- self.QueueRefresh()
- elif keyCode == wx.WXK_RIGHT:
- self._yaw += 15
- self.QueueRefresh()
- elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='):
+ if keyCode == wx.WXK_UP:
+ if wx.GetKeyState(wx.WXK_SHIFT):
self._zoom /= 1.2
if self._zoom < 1:
self._zoom = 1
- self.QueueRefresh()
- elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'):
+ else:
+ self._pitch -= 15
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_DOWN:
+ if wx.GetKeyState(wx.WXK_SHIFT):
self._zoom *= 1.2
if self._zoom > numpy.max(self._machineSize) * 3:
self._zoom = numpy.max(self._machineSize) * 3
- self.QueueRefresh()
- elif keyCode == wx.WXK_HOME:
- self._yaw = 30
- self._pitch = 60
- self.QueueRefresh()
- elif keyCode == wx.WXK_PAGEUP:
- self._yaw = 0
- self._pitch = 0
- self.QueueRefresh()
- elif keyCode == wx.WXK_PAGEDOWN:
- self._yaw = 0
- self._pitch = 90
- self.QueueRefresh()
- elif keyCode == wx.WXK_END:
- self._yaw = 90
- self._pitch = 90
- self.QueueRefresh()
+ else:
+ self._pitch += 15
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_LEFT:
+ self._yaw -= 15
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_RIGHT:
+ self._yaw += 15
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_NUMPAD_ADD or keyCode == wx.WXK_ADD or keyCode == ord('+') or keyCode == ord('='):
+ self._zoom /= 1.2
+ if self._zoom < 1:
+ self._zoom = 1
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_NUMPAD_SUBTRACT or keyCode == wx.WXK_SUBTRACT or keyCode == ord('-'):
+ self._zoom *= 1.2
+ if self._zoom > numpy.max(self._machineSize) * 3:
+ self._zoom = numpy.max(self._machineSize) * 3
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_HOME:
+ self._yaw = 30
+ self._pitch = 60
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_PAGEUP:
+ self._yaw = 0
+ self._pitch = 0
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_PAGEDOWN:
+ self._yaw = 0
+ self._pitch = 90
+ self.QueueRefresh()
+ elif keyCode == wx.WXK_END:
+ self._yaw = 90
+ self._pitch = 90
+ self.QueueRefresh()
if keyCode == wx.WXK_F3 and wx.GetKeyState(wx.WXK_SHIFT):
shaderEditor(self, self.ShaderUpdate, self._objectLoadShader.getVertexShader(), self._objectLoadShader.getFragmentShader())
self._zoom = self._animZoom.getPosition()
if self._animZoom.isDone():
self._animZoom = None
- if self.viewMode == 'gcode' and self._gcode is not None:
- try:
- self._viewTarget[2] = self._gcode.layerList[self.layerSelect.getValue()][-1]['points'][0][2]
- except:
- pass
if self._objectShader is None:
if opengl.hasShaderSupport():
self._objectShader = opengl.GLShader("""
glRotate(self._yaw, 0,0,1)
glTranslate(-self._viewTarget[0],-self._viewTarget[1],-self._viewTarget[2])
- if self.viewMode == 'gcode':
- if self._gcode is not None and self._gcode.layerList is None:
- self._gcodeLoadThread = threading.Thread(target=self._loadGCode)
- self._gcodeLoadThread.daemon = True
- self._gcodeLoadThread.start()
- if self._gcode is not None and self._gcode.layerList is not None:
- glPushMatrix()
- if profile.getMachineSetting('machine_center_is_zero') != 'True':
- glTranslate(-self._machineSize[0] / 2, -self._machineSize[1] / 2, 0)
- t = time.time()
- drawUpTill = min(len(self._gcode.layerList), self.layerSelect.getValue() + 1)
- for n in xrange(0, drawUpTill):
- c = 1.0 - float(drawUpTill - n) / 15
- c = max(0.3, c)
- if len(self._gcodeVBOs) < n + 1:
- self._gcodeVBOs.append(self._generateGCodeVBOs(self._gcode.layerList[n]))
- if time.time() - t > 0.5:
- self.QueueRefresh()
- break
- #['WALL-OUTER', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']
- if n == drawUpTill - 1:
- if len(self._gcodeVBOs[n]) < 9:
- self._gcodeVBOs[n] += self._generateGCodeVBOs2(self._gcode.layerList[n])
- glColor3f(c, 0, 0)
- self._gcodeVBOs[n][8].render(GL_QUADS)
- glColor3f(c/2, 0, c)
- self._gcodeVBOs[n][9].render(GL_QUADS)
- glColor3f(0, c, c/2)
- self._gcodeVBOs[n][10].render(GL_QUADS)
- glColor3f(c, 0, 0)
- self._gcodeVBOs[n][11].render(GL_QUADS)
-
- glColor3f(0, c, 0)
- self._gcodeVBOs[n][12].render(GL_QUADS)
- glColor3f(c/2, c/2, 0.0)
- self._gcodeVBOs[n][13].render(GL_QUADS)
- glColor3f(0, c, c)
- self._gcodeVBOs[n][14].render(GL_QUADS)
- self._gcodeVBOs[n][15].render(GL_QUADS)
- glColor3f(0, 0, c)
- self._gcodeVBOs[n][16].render(GL_LINES)
- else:
- glColor3f(c, 0, 0)
- self._gcodeVBOs[n][0].render(GL_LINES)
- glColor3f(c/2, 0, c)
- self._gcodeVBOs[n][1].render(GL_LINES)
- glColor3f(0, c, c/2)
- self._gcodeVBOs[n][2].render(GL_LINES)
- glColor3f(c, 0, 0)
- self._gcodeVBOs[n][3].render(GL_LINES)
-
- glColor3f(0, c, 0)
- self._gcodeVBOs[n][4].render(GL_LINES)
- glColor3f(c/2, c/2, 0.0)
- self._gcodeVBOs[n][5].render(GL_LINES)
- glColor3f(0, c, c)
- self._gcodeVBOs[n][6].render(GL_LINES)
- self._gcodeVBOs[n][7].render(GL_LINES)
- glPopMatrix()
- else:
+ self._objectShader.unbind()
+ self._engineResultView.OnDraw()
+ if self.viewMode != 'gcode':
glStencilFunc(GL_ALWAYS, 1, 1)
glStencilOp(GL_INCR, GL_INCR, GL_INCR)
if self.viewMode == 'overhang':
self._objectOverhangShader.bind()
- self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - 60)))
+ self._objectOverhangShader.setUniform('cosAngle', math.cos(math.radians(90 - profile.getProfileSettingFloat('support_angle'))))
else:
self._objectShader.bind()
for obj in self._scene.objects():
self._drawMachine()
- if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._slicer.getID():
+ if self._usbPrintMonitor.getState() == 'PRINTING' and self._usbPrintMonitor.getID() == self._engine.getID():
z = self._usbPrintMonitor.getZ()
if self.viewMode == 'gcode':
layer_height = profile.getProfileSettingFloat('layer_height')
glVertex3f(-size[0]/2, size[1]/2, z)
glEnd()
- if self.viewMode == 'gcode':
- if self._gcodeLoadThread is not None and self._gcodeLoadThread.isAlive():
- glDisable(GL_DEPTH_TEST)
- glPushMatrix()
- glLoadIdentity()
- glTranslate(0,-4,-10)
- glColor4ub(60,60,60,255)
- opengl.glDrawStringCenter(_("Loading toolpath for visualization..."))
- glPopMatrix()
- else:
+ if self.viewMode != 'gcode':
#Draw the object box-shadow, so you can see where it will collide with other objects.
if self._selectedObj is not None:
glEnable(GL_BLEND)
n = 0
for m in obj._meshList:
if m.vbo is None:
- m.vbo = opengl.GLVBO(m.vertexes, m.normal)
+ m.vbo = opengl.GLVBO(GL_TRIANGLES, m.vertexes, m.normal)
if brightness:
glColor4fv(map(lambda n: n * brightness, self._objColors[n]))
n += 1
polys = profile.getMachineSizePolygons()
height = profile.getMachineSettingFloat('machine_height')
+ circular = profile.getMachineSetting('machine_shape') == 'Circular'
glBegin(GL_QUADS)
for n in xrange(0, len(polys[0])):
- if n % 2 == 0:
- glColor4ub(5, 171, 231, 96)
+ if not circular:
+ if n % 2 == 0:
+ glColor4ub(5, 171, 231, 96)
+ else:
+ glColor4ub(5, 171, 231, 64)
else:
- glColor4ub(5, 171, 231, 64)
+ glColor4ub(5, 171, 231, 96)
+
glVertex3f(polys[0][n][0], polys[0][n][1], height)
glVertex3f(polys[0][n][0], polys[0][n][1], 0)
glVertex3f(polys[0][n-1][0], polys[0][n-1][1], 0)
glDisable(GL_BLEND)
glDisable(GL_CULL_FACE)
- def _generateGCodeVBOs(self, layer):
- ret = []
- for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
- if ':' in extrudeType:
- extruder = int(extrudeType[extrudeType.find(':')+1:])
- extrudeType = extrudeType[0:extrudeType.find(':')]
- else:
- extruder = None
- pointList = numpy.zeros((0,3), numpy.float32)
- for path in layer:
- if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
- a = path['points']
- a = numpy.concatenate((a[:-1], a[1:]), 1)
- a = a.reshape((len(a) * 2, 3))
- pointList = numpy.concatenate((pointList, a))
- ret.append(opengl.GLVBO(pointList))
- return ret
-
- def _generateGCodeVBOs2(self, layer):
- filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
- filamentArea = math.pi * filamentRadius * filamentRadius
- useFilamentArea = profile.getMachineSetting('gcode_flavor') == 'UltiGCode'
-
- ret = []
- for extrudeType in ['WALL-OUTER:0', 'WALL-OUTER:1', 'WALL-OUTER:2', 'WALL-OUTER:3', 'WALL-INNER', 'FILL', 'SUPPORT', 'SKIRT']:
- if ':' in extrudeType:
- extruder = int(extrudeType[extrudeType.find(':')+1:])
- extrudeType = extrudeType[0:extrudeType.find(':')]
- else:
- extruder = None
- pointList = numpy.zeros((0,3), numpy.float32)
- for path in layer:
- if path['type'] == 'extrude' and path['pathType'] == extrudeType and (extruder is None or path['extruder'] == extruder):
- a = path['points']
- if extrudeType == 'FILL':
- a[:,2] += 0.01
-
- normal = a[1:] - a[:-1]
- lens = numpy.sqrt(normal[:,0]**2 + normal[:,1]**2)
- normal[:,0], normal[:,1] = -normal[:,1] / lens, normal[:,0] / lens
- normal[:,2] /= lens
-
- ePerDist = path['extrusion'][1:] / lens
- if useFilamentArea:
- lineWidth = ePerDist / path['layerThickness'] / 2.0
- else:
- lineWidth = ePerDist * (filamentArea / path['layerThickness'] / 2)
-
- normal[:,0] *= lineWidth
- normal[:,1] *= lineWidth
-
- b = numpy.zeros((len(a)-1, 0), numpy.float32)
- b = numpy.concatenate((b, a[1:] + normal), 1)
- b = numpy.concatenate((b, a[1:] - normal), 1)
- b = numpy.concatenate((b, a[:-1] - normal), 1)
- b = numpy.concatenate((b, a[:-1] + normal), 1)
- b = b.reshape((len(b) * 4, 3))
-
- if len(a) > 2:
- normal2 = normal[:-1] + normal[1:]
- lens2 = numpy.sqrt(normal2[:,0]**2 + normal2[:,1]**2)
- normal2[:,0] /= lens2
- normal2[:,1] /= lens2
- normal2[:,0] *= lineWidth[:-1]
- normal2[:,1] *= lineWidth[:-1]
-
- c = numpy.zeros((len(a)-2, 0), numpy.float32)
- c = numpy.concatenate((c, a[1:-1]), 1)
- c = numpy.concatenate((c, a[1:-1]+normal[1:]), 1)
- c = numpy.concatenate((c, a[1:-1]+normal2), 1)
- c = numpy.concatenate((c, a[1:-1]+normal[:-1]), 1)
-
- c = numpy.concatenate((c, a[1:-1]), 1)
- c = numpy.concatenate((c, a[1:-1]-normal[1:]), 1)
- c = numpy.concatenate((c, a[1:-1]-normal2), 1)
- c = numpy.concatenate((c, a[1:-1]-normal[:-1]), 1)
-
- c = c.reshape((len(c) * 8, 3))
-
- pointList = numpy.concatenate((pointList, b, c))
- else:
- pointList = numpy.concatenate((pointList, b))
- ret.append(opengl.GLVBO(pointList))
-
- pointList = numpy.zeros((0,3), numpy.float32)
- for path in layer:
- if path['type'] == 'move':
- a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
- a = numpy.concatenate((a[:-1], a[1:]), 1)
- a = a.reshape((len(a) * 2, 3))
- pointList = numpy.concatenate((pointList, a))
- if path['type'] == 'retract':
- a = path['points'] + numpy.array([0,0,0.01], numpy.float32)
- a = numpy.concatenate((a[:-1], a[1:] + numpy.array([0,0,1], numpy.float32)), 1)
- a = a.reshape((len(a) * 2, 3))
- pointList = numpy.concatenate((pointList, a))
- ret.append(opengl.GLVBO(pointList))
-
- return ret
-
def getObjectCenterPos(self):
if self._selectedObj is None:
return [0.0, 0.0, 0.0]