From: daid Date: Tue, 28 Jan 2014 16:46:32 +0000 (+0100) Subject: Use socket to communicate polygon data, so it can be done in binary. This also remove... X-Git-Tag: 14.02-RC1~51 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=b1221d8e1cb83623074abf60f5c1654fad0f1a50;p=cura.git Use socket to communicate polygon data, so it can be done in binary. This also removes the temp file used to communicate the 3D model to the slicer. --- diff --git a/Cura/gui/util/engineResultView.py b/Cura/gui/util/engineResultView.py index 757af7db..e662ec13 100644 --- a/Cura/gui/util/engineResultView.py +++ b/Cura/gui/util/engineResultView.py @@ -65,11 +65,11 @@ class engineResultView(object): lineTypeList = [ ('inset0', 'WALL-OUTER', [1,0,0,1]), ('insetx', 'WALL-INNER', [0,1,0,1]), - ('openoutline', None, [1,0,0,1]), - ('skin', 'FILL', [1,1,0,1]), - ('infill', None, [1,1,0,1]), - ('support', 'SUPPORT',[0,1,1,1]), - ('outline', None, [0,0,0,1]) + ('openoutline', None, [1,0,0,1]), + ('skin', 'FILL', [1,1,0,1]), + ('infill', None, [1,1,0,1]), + ('support', 'SUPPORT', [0,1,1,1]), + ('outline', None, [0,0,0,1]) ] n = 0 gcodeLayers = self._result.getGCodeLayers() @@ -96,10 +96,10 @@ class engineResultView(object): layerVBOs[typeName].render() n += 20 else: - while len(self._layerVBOs) < n + 1: - self._layerVBOs.append({}) c = 1.0 - ((layerNr - n) - 1) * 0.05 c = max(0.5, c) + while len(self._layerVBOs) < n + 1: + self._layerVBOs.append({}) layerVBOs = self._layerVBOs[n] if gcodeLayers is not None and layerNr - 10 < n < len(gcodeLayers): for _, typeName, color in lineTypeList: diff --git a/Cura/util/sliceEngine.py b/Cura/util/sliceEngine.py index 3b224cfd..ae7a5be3 100644 --- a/Cura/util/sliceEngine.py +++ b/Cura/util/sliceEngine.py @@ -12,6 +12,8 @@ import sys import urllib import urllib2 import hashlib +import socket +import struct import cStringIO as StringIO from Cura.util import profile @@ -136,21 +138,92 @@ class EngineResult(object): pass class Engine(object): + GUI_CMD_REQUEST_MESH = 0x01 + GUI_CMD_SEND_POLYGONS = 0x02 + def __init__(self, progressCallback): self._process = None self._thread = None self._callback = progressCallback - self._binaryStorageFilename = getTempFilename() self._progressSteps = ['inset', 'skin', 'export'] self._objCount = 0 self._result = None + self._serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._serverPortNr = 0xC20A + while True: + try: + self._serversocket.bind(('127.0.0.1', self._serverPortNr)) + except: + print "Failed to listen on port: %d" % (self._serverPortNr) + self._serverPortNr += 1 + if self._serverPortNr > 0xFFFF: + print "Failed to listen on any port..." + break + else: + break + print 'Listening for engine communications on %d' % (self._serverPortNr) + self._serversocket.listen(1) + thread = threading.Thread(target=self._socketListenThread) + thread.daemon = True + thread.start() + + def _socketListenThread(self): + while True: + sock, _ = self._serversocket.accept() + thread = threading.Thread(target=self._socketConnectionThread, args=(sock,)) + thread.daemon = True + thread.start() + + def _socketConnectionThread(self, sock): + print "Connection", sock + while True: + try: + data = sock.recv(4) + except: + data = '' + if len(data) == 0: + print "Connection closed" + sock.close() + return + cmd = struct.unpack('@i', data)[0] + if cmd == self.GUI_CMD_REQUEST_MESH: + meshInfo = self._modelData[0] + self._modelData = self._modelData[1:] + sock.sendall(struct.pack('@i', meshInfo[0])) + sock.sendall(meshInfo[1].tostring()) + elif cmd == self.GUI_CMD_SEND_POLYGONS: + cnt = struct.unpack('@i', sock.recv(4))[0] + layerNr = struct.unpack('@i', sock.recv(4))[0] + z = struct.unpack('@i', sock.recv(4))[0] + z = float(z) / 1000.0 + typeNameLen = struct.unpack('@i', sock.recv(4))[0] + typeName = sock.recv(typeNameLen) + while len(self._result._polygons) < layerNr + 1: + self._result._polygons.append({}) + polygons = self._result._polygons[layerNr] + if typeName not in polygons: + polygons[typeName] = [] + for n in xrange(0, cnt): + length = struct.unpack('@i', sock.recv(4))[0] + data = '' + while len(data) < length * 8 * 2: + recvData = sock.recv(length * 8 * 2 - len(data)) + if len(recvData) < 1: + return + data += recvData + polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0 + polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2)) + polygon = numpy.empty((len(polygon2d), 3), numpy.float32) + polygon[:,:-1] = polygon2d + polygon[:,2] = z + polygons[typeName].append(polygon) + else: + print "Unknown command on socket: %x" % (cmd) + def cleanup(self): self.abortEngine() - try: - os.remove(self._binaryStorageFilename) - except: - pass + self._serversocket.close() def abortEngine(self): if self._process is not None: @@ -182,69 +255,69 @@ class Engine(object): commandList = [getEngineFilename(), '-vvv'] for k, v in self._engineSettings(extruderCount).iteritems(): commandList += ['-s', '%s=%s' % (k, str(v))] - commandList += ['-b', self._binaryStorageFilename] + commandList += ['-g', '%d' % self._serverPortNr] self._objCount = 0 - with open(self._binaryStorageFilename, "wb") as f: - hash = hashlib.sha512() - order = scene.printOrder() - if order is None: - pos = numpy.array(profile.getMachineCenterCoords()) * 1000 - objMin = None - objMax = None + engineModelData = [] + hash = hashlib.sha512() + order = scene.printOrder() + if order is None: + pos = numpy.array(profile.getMachineCenterCoords()) * 1000 + objMin = None + objMax = None + for obj in scene.objects(): + if scene.checkPlatform(obj): + oMin = obj.getMinimum()[0:2] + obj.getPosition() + oMax = obj.getMaximum()[0:2] + obj.getPosition() + if objMin is None: + objMin = oMin + objMax = oMax + else: + objMin[0] = min(oMin[0], objMin[0]) + objMin[1] = min(oMin[1], objMin[1]) + objMax[0] = max(oMax[0], objMax[0]) + objMax[1] = max(oMax[1], objMax[1]) + if objMin is None: + return + pos += (objMin + objMax) / 2.0 * 1000 + commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])] + + vertexTotal = [0] * 4 + meshMax = 1 + for obj in scene.objects(): + if scene.checkPlatform(obj): + meshMax = max(meshMax, len(obj._meshList)) + for n in xrange(0, len(obj._meshList)): + vertexTotal[n] += obj._meshList[n].vertexCount + + for n in xrange(0, meshMax): + verts = numpy.zeros((0, 3), numpy.float32) for obj in scene.objects(): if scene.checkPlatform(obj): - oMin = obj.getMinimum()[0:2] + obj.getPosition() - oMax = obj.getMaximum()[0:2] + obj.getPosition() - if objMin is None: - objMin = oMin - objMax = oMax - else: - objMin[0] = min(oMin[0], objMin[0]) - objMin[1] = min(oMin[1], objMin[1]) - objMax[0] = max(oMax[0], objMax[0]) - objMax[1] = max(oMax[1], objMax[1]) - if objMin is None: - return - pos += (objMin + objMax) / 2.0 * 1000 + if n < len(obj._meshList): + vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA() + vertexes -= obj._drawOffset + vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0]) + verts = numpy.concatenate((verts, vertexes)) + hash.update(obj._meshList[n].vertexes.tostring()) + engineModelData.append((vertexTotal[n], verts)) + + commandList += ['$' * meshMax] + self._objCount = 1 + else: + for n in order: + obj = scene.objects()[n] + for mesh in obj._meshList: + engineModelData.append((mesh.vertexCount, mesh.vertexes)) + hash.update(mesh.vertexes.tostring()) + pos = obj.getPosition() * 1000 + pos += numpy.array(profile.getMachineCenterCoords()) * 1000 + commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))] commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])] - - vertexTotal = [0] * 4 - meshMax = 1 - for obj in scene.objects(): - if scene.checkPlatform(obj): - meshMax = max(meshMax, len(obj._meshList)) - for n in xrange(0, len(obj._meshList)): - vertexTotal[n] += obj._meshList[n].vertexCount - - for n in xrange(0, meshMax): - f.write(numpy.array([vertexTotal[n]], numpy.int32).tostring()) - for obj in scene.objects(): - if scene.checkPlatform(obj): - if n < len(obj._meshList): - vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA() - vertexes -= obj._drawOffset - vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0]) - f.write(vertexes.tostring()) - hash.update(obj._meshList[n].vertexes.tostring()) - - commandList += ['#' * meshMax] - self._objCount = 1 - else: - for n in order: - obj = scene.objects()[n] - for mesh in obj._meshList: - f.write(numpy.array([mesh.vertexCount], numpy.int32).tostring()) - s = mesh.vertexes.tostring() - f.write(s) - hash.update(s) - pos = obj.getPosition() * 1000 - pos += numpy.array(profile.getMachineCenterCoords()) * 1000 - commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))] - commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])] - commandList += ['#' * len(obj._meshList)] - self._objCount += 1 - modelHash = hash.hexdigest() + commandList += ['$' * len(obj._meshList)] + self._objCount += 1 + modelHash = hash.hexdigest() if self._objCount > 0: + self._modelData = engineModelData self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, modelHash)) self._thread.daemon = True self._thread.start() @@ -319,27 +392,6 @@ class Engine(object): self._callback(progressValue) except: pass - elif line.startswith('Polygons:'): - line = line.split(':') - typeName = line[1] - layerNr = int(line[2]) - size = int(line[3]) - z = float(line[4]) - while len(self._result._polygons) < layerNr + 1: - self._result._polygons.append({}) - polygons = self._result._polygons[layerNr] - for n in xrange(0, size): - polygon = stderr.readline().strip() - if not polygon: - continue - polygon2d = numpy.fromstring(polygon, dtype=numpy.float32, sep=' ') - polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2)) - polygon = numpy.empty((len(polygon2d), 3), numpy.float32) - polygon[:,:-1] = polygon2d - polygon[:,2] = z - if typeName not in polygons: - polygons[typeName] = [] - polygons[typeName].append(polygon) elif line.startswith('Print time:'): self._result._printTimeSeconds = int(line.split(':')[1].strip()) elif line.startswith('Filament:'): @@ -449,7 +501,7 @@ class Engine(object): settings['gcodeFlavor'] = 1 if profile.getProfileSetting('spiralize') == 'True': settings['spiralizeMode'] = 1 - if profile.getProfileSetting('wipe_tower') == 'True': + if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1: settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness'])) if profile.getProfileSetting('ooze_shield') == 'True': settings['enableOozeShield'] = 1