This commit is contained in:
Jaime van Kessel 2015-08-19 10:27:41 +02:00
commit d683a6b77b
5 changed files with 67 additions and 50 deletions

View file

@ -79,6 +79,7 @@ class CuraApplication(QtApplication):
self._platform_activity = False self._platform_activity = False
self.activeMachineChanged.connect(self._onActiveMachineChanged) self.activeMachineChanged.connect(self._onActiveMachineChanged)
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
Preferences.getInstance().addPreference("cura/active_machine", "") Preferences.getInstance().addPreference("cura/active_machine", "")
Preferences.getInstance().addPreference("cura/active_mode", "simple") Preferences.getInstance().addPreference("cura/active_mode", "simple")
@ -214,24 +215,15 @@ class CuraApplication(QtApplication):
def getPlatformActivity(self): def getPlatformActivity(self):
return self._platform_activity return self._platform_activity
@pyqtSlot(bool) def updatePlatformActivity(self, node = None):
def setPlatformActivity(self, activity): count = 0
##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if activity == True: if type(node) is not SceneNode or not node.getMeshData():
self._platform_activity = activity continue
elif activity == False:
nodes = [] count += 1
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): self._platform_activity = True if count > 0 else False
continue
nodes.append(node)
i = 0
for node in nodes:
if not node.getMeshData():
continue
i += 1
if i <= 1: ## i == 0 when the meshes are removed using the deleteAll function; i == 1 when the last remaining mesh is removed using the deleteObject function
self._platform_activity = activity
self.activityChanged.emit() self.activityChanged.emit()
## Remove an object from the scene ## Remove an object from the scene
@ -252,7 +244,6 @@ class CuraApplication(QtApplication):
group_node = group_node.getParent() group_node = group_node.getParent()
op = RemoveSceneNodeOperation(group_node) op = RemoveSceneNodeOperation(group_node)
op.push() op.push()
self.setPlatformActivity(False)
## Create a number of copies of existing object. ## Create a number of copies of existing object.
@pyqtSlot("quint64", int) @pyqtSlot("quint64", int)
@ -300,7 +291,6 @@ class CuraApplication(QtApplication):
op.addOperation(RemoveSceneNodeOperation(node)) op.addOperation(RemoveSceneNodeOperation(node))
op.push() op.push()
self.setPlatformActivity(False)
## Reset all translation on nodes with mesh data. ## Reset all translation on nodes with mesh data.
@pyqtSlot() @pyqtSlot()

View file

@ -15,9 +15,9 @@ import os
import struct import struct
import math import math
from os import listdir from os import listdir
import untangle
import zipfile import zipfile
import xml.etree.ElementTree as ET
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes! ## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
class ThreeMFReader(MeshReader): class ThreeMFReader(MeshReader):
@ -25,6 +25,11 @@ class ThreeMFReader(MeshReader):
super(ThreeMFReader, self).__init__() super(ThreeMFReader, self).__init__()
self._supported_extension = ".3mf" self._supported_extension = ".3mf"
self._namespaces = {
"3mf": "http://schemas.microsoft.com/3dmanufacturing/core/2015/02",
"cura": "http://software.ultimaker.com/xml/cura/3mf/2015/10"
}
def read(self, file_name): def read(self, file_name):
result = None result = None
extension = os.path.splitext(file_name)[1] extension = os.path.splitext(file_name)[1]
@ -33,32 +38,39 @@ class ThreeMFReader(MeshReader):
# The base object of 3mf is a zipped archive. # The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, 'r') archive = zipfile.ZipFile(file_name, 'r')
try: try:
# The model is always stored in this place. root = ET.parse(archive.open("3D/3dmodel.model"))
root = untangle.parse(archive.read("3D/3dmodel.model").decode("utf-8"))
for object in root.model.resources.object: # There can be multiple objects, try to load all of them. # There can be multiple objects, try to load all of them.
objects = root.findall("./3mf:resources/3mf:object", self._namespaces)
for object in objects:
mesh = MeshData() mesh = MeshData()
node = SceneNode() node = SceneNode()
vertex_list = [] vertex_list = []
for vertex in object.mesh.vertices.vertex: #for vertex in object.mesh.vertices.vertex:
vertex_list.append([vertex['x'],vertex['y'],vertex['z']]) for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
mesh.reserveFaceCount(len(object.mesh.triangles.triangle)) triangles = object.findall(".//3mf:triangle", self._namespaces)
for triangle in object.mesh.triangles.triangle: mesh.reserveFaceCount(len(triangles))
v1 = int(triangle["v1"])
v2 = int(triangle["v2"]) #for triangle in object.mesh.triangles.triangle:
v3 = int(triangle["v3"]) for triangle in triangles:
v1 = int(triangle.get("v1"))
v2 = int(triangle.get("v2"))
v3 = int(triangle.get("v3"))
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2]) mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
#TODO: We currently do not check for normals and simply recalculate them. #TODO: We currently do not check for normals and simply recalculate them.
mesh.calculateNormals() mesh.calculateNormals()
node.setMeshData(mesh) node.setMeshData(mesh)
node.setSelectable(True) node.setSelectable(True)
# Magical python comprehension; looks for the matching transformation transformation = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(object.get("id")), self._namespaces)
transformation = next((x for x in root.model.build.item if x["objectid"] == object["id"]), None) if transformation:
transformation = transformation[0]
if transformation["transform"]: if transformation.get("transform"):
splitted_transformation = transformation["transform"].split() splitted_transformation = transformation.get("transform").split()
## Transformation is saved as: ## Transformation is saved as:
## M00 M01 M02 0.0 ## M00 M01 M02 0.0
## M10 M11 M12 0.0 ## M10 M11 M12 0.0
@ -100,9 +112,9 @@ class ThreeMFReader(MeshReader):
node.rotate(rotation) node.rotate(rotation)
result.addChild(node) result.addChild(node)
# If there is more then one object, group them. #If there is more then one object, group them.
try: try:
if len(root.model.resources.object) > 1: if len(objects) > 1:
group_decorator = GroupDecorator() group_decorator = GroupDecorator()
result.addDecorator(group_decorator) result.addDecorator(group_decorator)
except: except:

View file

@ -17,8 +17,8 @@ class RemovableDriveOutputDevice(OutputDevice):
super().__init__(device_id) super().__init__(device_id)
self.setName(device_name) self.setName(device_name)
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive")) self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name)) self.setDescription(catalog.i18nc("@info:tooltip", "Save to Removable Drive {0}").format(device_name))
self.setIconName("save_sd") self.setIconName("save_sd")
self.setPriority(1) self.setPriority(1)
@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice):
job.progress.connect(self._onProgress) job.progress.connect(self._onProgress)
job.finished.connect(self._onFinished) job.finished.connect(self._onFinished)
message = Message(catalog.i18nc("", "Saving to Removable Drive {0}").format(self.getName()), 0, False, -1) message = Message(catalog.i18nc("@info:status", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
message.show() message.show()
job._message = message job._message = message

View file

@ -63,7 +63,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self._listen_thread.daemon = True self._listen_thread.daemon = True
self._update_firmware_thread = threading.Thread(target= self._updateFirmware) self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.demon = True self._update_firmware_thread.deamon = True
self._heatup_wait_start_time = time.time() self._heatup_wait_start_time = time.time()
@ -222,6 +222,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
self.setProgress(100, 100) self.setProgress(100, 100)
self.firmwareUpdateComplete.emit()
## Upload new firmware to machine ## Upload new firmware to machine
# \param filename full path of firmware file to be uploaded # \param filename full path of firmware file to be uploaded
def updateFirmware(self, file_name): def updateFirmware(self, file_name):
@ -277,9 +279,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
if line is None: if line is None:
self.setIsConnected(False) # Something went wrong with reading, could be that close was called. self.setIsConnected(False) # Something went wrong with reading, could be that close was called.
return return
if b"T:" in line: if b"T:" in line:
self._serial.timeout = 0.5 self._serial.timeout = 0.5
self._sendCommand("M105")
sucesfull_responses += 1 sucesfull_responses += 1
if sucesfull_responses >= self._required_responses_auto_baud: if sucesfull_responses >= self._required_responses_auto_baud:
self._serial.timeout = 2 #Reset serial timeout self._serial.timeout = 2 #Reset serial timeout
@ -287,6 +289,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
Logger.log("i", "Established printer connection on port %s" % self._serial_port) Logger.log("i", "Established printer connection on port %s" % self._serial_port)
return return
self._sendCommand("M105") # Send M105 as long as we are listening, otherwise we end up in an undefined state
Logger.log("e", "Baud rate detection for %s failed", self._serial_port) Logger.log("e", "Baud rate detection for %s failed", self._serial_port)
self.close() # Unable to connect, wrap up. self.close() # Unable to connect, wrap up.
self.setIsConnected(False) self.setIsConnected(False)
@ -319,6 +323,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
except Exception as e: except Exception as e:
pass # This should work, but it does fail sometimes for some reason pass # This should work, but it does fail sometimes for some reason
self._connect_thread = threading.Thread(target=self._connect)
self._connect_thread.daemon = True
if self._serial is not None: if self._serial is not None:
self.setIsConnected(False) self.setIsConnected(False)
try: try:
@ -327,6 +334,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
pass pass
self._serial.close() self._serial.close()
self._listen_thread = threading.Thread(target=self._listen)
self._listen_thread.daemon = True
self._serial = None self._serial = None
def isConnected(self): def isConnected(self):
@ -579,3 +588,10 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
def _getBaudrateList(self): def _getBaudrateList(self):
ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600] ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600]
return ret return ret
def _onFirmwareUpdateComplete(self):
self._update_firmware_thread.join()
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
self._update_firmware_thread.deamon = True
self.connect()

View file

@ -481,7 +481,6 @@ UM.MainWindow {
onAccepted: onAccepted:
{ {
UM.MeshFileHandler.readLocalFile(fileUrl) UM.MeshFileHandler.readLocalFile(fileUrl)
Printer.setPlatformActivity(true)
} }
} }