chiark / gitweb /
Fix slicing really big GCode files on windows.
authordaid <daid303@gmail.com>
Fri, 26 Sep 2014 05:48:58 +0000 (07:48 +0200)
committerdaid <daid303@gmail.com>
Fri, 26 Sep 2014 05:48:58 +0000 (07:48 +0200)
Cura/cura.py
Cura/gui/sceneView.py
Cura/util/bigDataStorage.py [new file with mode: 0644]
Cura/util/gcodeInterpreter.py
Cura/util/pluginInfo.py
Cura/util/sliceEngine.py

index 50e9fd9201d21bfc7391f3f21f6809b27dcdf8dc..765580685fb3b60ff432c30bf2ece8822a0ea872 100644 (file)
@@ -72,7 +72,12 @@ def main():
                if not options.output:
                        options.output = args[0] + profile.getGCodeExtension()
                with open(options.output, "wb") as f:
-                       f.write(engine.getResult().getGCode())
+                       gcode = engine.getResult().getGCode()
+                       while True:
+                               data = gcode.read()
+                               if len(data) == 0:
+                                       break
+                               f.write(data)
                print 'GCode file saved : %s' % options.output
 
                engine.cleanup()
index c90bf6a3824bdafd771e2fa845942a6e3e851cb7..e7d25bd93750f2b2ed5608151348f8cc442c7fee 100644 (file)
@@ -293,7 +293,7 @@ class SceneView(openglGui.glGuiPanel):
                                connection.window = printWindow.printWindowBasic(self, connection)
                connection.window.Show()
                connection.window.Raise()
-               if not connection.loadGCodeData(StringIO.StringIO(self._engine.getResult().getGCode())):
+               if not connection.loadGCodeData(self._engine.getResult().getGCode()):
                        if connection.isPrinting():
                                self.notification.message("Cannot start print, because other print still running.")
                        else:
@@ -315,17 +315,18 @@ class SceneView(openglGui.glGuiPanel):
                threading.Thread(target=self._saveGCode,args=(filename,)).start()
 
        def _saveGCode(self, targetFilename, ejectDrive = False):
-               data = self._engine.getResult().getGCode()
+               gcode = self._engine.getResult().getGCode()
                try:
-                       size = float(len(data))
-                       fsrc = StringIO.StringIO(data)
+                       size = float(len(gcode))
+                       read_pos = 0
                        with open(targetFilename, 'wb') as fdst:
                                while 1:
-                                       buf = fsrc.read(16*1024)
-                                       if not buf:
+                                       buf = gcode.read(16*1024)
+                                       if len(buf) < 1:
                                                break
+                                       read_pos += len(buf)
                                        fdst.write(buf)
-                                       self.printButton.setProgressBar(float(fsrc.tell()) / size)
+                                       self.printButton.setProgressBar(read_pos / size)
                                        self._queueRefresh()
                except:
                        import sys, traceback
diff --git a/Cura/util/bigDataStorage.py b/Cura/util/bigDataStorage.py
new file mode 100644 (file)
index 0000000..9150455
--- /dev/null
@@ -0,0 +1,81 @@
+import cStringIO as StringIO\r
+\r
+class BigDataStorage(object):\r
+       """\r
+       The StringIO from python aborts with an out-of-memory error after 250MB.\r
+       So the BigDataStorage stores data in multiple StringIOs to prevent this issue.\r
+       """\r
+       def __init__(self):\r
+               self._active = StringIO.StringIO()\r
+               self._list = [self._active]\r
+               self._read_index = None\r
+\r
+       def write(self, data):\r
+               self._active.write(data)\r
+               if self._active.tell() > 1024 * 1024 * 100:\r
+                       self._active = StringIO.StringIO()\r
+                       self._list.append(self._active)\r
+\r
+       def seekStart(self):\r
+               self._active = self._list[0]\r
+               self._active.seek(0)\r
+               self._read_index = 0\r
+\r
+       def read(self, size=None):\r
+               ret = self._active.read(size)\r
+               if ret == '':\r
+                       if self._read_index + 1 < len(self._list):\r
+                               self._read_index += 1\r
+                               self._active = self._list[self._read_index]\r
+                               self._active.seek(0)\r
+                               ret = self._active.read(size)\r
+               return ret\r
+\r
+       def replaceAtStart(self, key, value):\r
+               data = self._list[0].getvalue()\r
+               block0 = data[0:2048]\r
+               value = (value + ' ' * len(key))[:len(key)]\r
+               block0 = block0.replace(key, value)\r
+               self._list[0] = StringIO.StringIO()\r
+               self._list[0].write(block0)\r
+               self._list[0].write(data[2048:])\r
+\r
+       def __len__(self):\r
+               ret = 0\r
+               for data in self._list:\r
+                       pos = data.tell()\r
+                       data.seek(0, 2)\r
+                       ret += data.tell()\r
+                       data.seek(pos)\r
+               return ret\r
+\r
+       def __iter__(self):\r
+               self._iter_index = 0\r
+               return self\r
+\r
+       def next(self):\r
+               if self._iter_index < len(self._list):\r
+                       ret = self._list[self._iter_index].readline()\r
+                       if ret == '':\r
+                               self._iter_index += 1\r
+                               if self._iter_index < len(self._list):\r
+                                       self._list[self._iter_index].seek(0)\r
+                               return self.next()\r
+                       return ret\r
+               raise StopIteration\r
+\r
+       def tell(self):\r
+               pos = 0\r
+               for data in self._list[:self._iter_index]:\r
+                       pos += data.tell()\r
+               if self._iter_index < len(self._list):\r
+                       pos += self._list[self._iter_index].tell()\r
+               return pos\r
+\r
+       def clone(self):\r
+               clone = BigDataStorage()\r
+               clone._list = []\r
+               for item in self._list:\r
+                       clone._list.append(StringIO.StringIO(item.getvalue()))\r
+               clone._active = clone._list[-1]\r
+               return clone
\ No newline at end of file
index b187ea319cf29e8004701a4527582fc65a0c5aa7..95b42d751732fd9c6f450fe79e10499a94c59ca3 100644 (file)
@@ -51,9 +51,9 @@ class gcode(object):
                elif type(data) is list:
                        self._load(data)
                else:
-                       data = data.getvalue()
                        self._fileSize = len(data)
-                       self._load(StringIO.StringIO(data))
+                       data.seekStart()
+                       self._load(data)
 
        def calculateWeight(self):
                #Calculates the weight of the filament in kg
index 7290c8bc31a6571669368c9c73825e1f718dfbd2..05b50a4f64fd71ea32350982e17781aaaedd521d 100644 (file)
@@ -129,7 +129,12 @@ def runPostProcessingPlugins(engineResult):
                if tempfilename is None:
                        f = tempfile.NamedTemporaryFile(prefix='CuraPluginTemp', delete=False)
                        tempfilename = f.name
-                       f.write(engineResult.getGCode())
+                       gcode = engineResult.getGCode()
+                       while True:
+                               data = gcode.read()
+                               if len(data) == 0:
+                                       break
+                               f.write(data)
                        f.close()
 
                locals = {'filename': tempfilename}
index e6f8b16117412eeb96d823e50b3e46fd9add7a97..344adf2155b168ba6f17c96bfed05ce2d66f6706 100644 (file)
@@ -19,8 +19,8 @@ import hashlib
 import socket
 import struct
 import errno
-import cStringIO as StringIO
 
+from Cura.util.bigDataStorage import BigDataStorage
 from Cura.util import profile
 from Cura.util import pluginInfo
 from Cura.util import version
@@ -34,6 +34,8 @@ def getEngineFilename():
        if platform.system() == 'Windows':
                if version.isDevVersion() and os.path.exists('C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'):
                        return 'C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'
+               if version.isDevVersion() and os.path.exists('C:/Program Files (x86)/Cura_14.09/CuraEngine.exe'):
+                       return 'C:/Program Files (x86)/Cura_14.09/CuraEngine.exe'
                return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine.exe'))
        if hasattr(sys, 'frozen'):
                return os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../..', 'CuraEngine'))
@@ -53,7 +55,7 @@ class EngineResult(object):
        """
        def __init__(self):
                self._engineLog = []
-               self._gcodeData = StringIO.StringIO()
+               self._gcodeData = BigDataStorage()
                self._polygons = []
                self._replaceInfo = {}
                self._success = False
@@ -101,17 +103,12 @@ class EngineResult(object):
                return self._engineLog
 
        def getGCode(self):
-               data = self._gcodeData.getvalue()
-               if len(self._replaceInfo) > 0:
-                       block0 = data[0:2048]
-                       for k, v in self._replaceInfo.items():
-                               v = (v + ' ' * len(k))[:len(k)]
-                               block0 = block0.replace(k, v)
-                       return block0 + data[2048:]
-               return data
+               self._gcodeData.seekStart()
+               return self._gcodeData
 
        def setGCode(self, gcode):
-               self._gcodeData = StringIO.StringIO(gcode)
+               self._gcodeData = BigDataStorage()
+               self._gcodeData.write(gcode)
                self._replaceInfo = {}
 
        def addLog(self, line):
@@ -121,6 +118,9 @@ class EngineResult(object):
                self._modelHash = hash
 
        def setFinished(self, result):
+               if result:
+                       for k, v in self._replaceInfo.items():
+                               self._gcodeData.replaceAtStart(k, v)
                self._finished = result
 
        def isFinished(self):
@@ -131,7 +131,7 @@ class EngineResult(object):
                        return None
                if self._gcodeInterpreter.layerList is None and self._gcodeLoadThread is None:
                        self._gcodeInterpreter.progressCallback = self._gcodeInterpreterCallback
-                       self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData))
+                       self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData.clone()))
                        self._gcodeLoadCallback = loadCallback
                        self._gcodeLoadThread.daemon = True
                        self._gcodeLoadThread.start()