mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 23:17:32 -06:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
d683a6b77b
5 changed files with 67 additions and 50 deletions
|
@ -79,6 +79,7 @@ class CuraApplication(QtApplication):
|
|||
self._platform_activity = False
|
||||
|
||||
self.activeMachineChanged.connect(self._onActiveMachineChanged)
|
||||
self.getController().getScene().sceneChanged.connect(self.updatePlatformActivity)
|
||||
|
||||
Preferences.getInstance().addPreference("cura/active_machine", "")
|
||||
Preferences.getInstance().addPreference("cura/active_mode", "simple")
|
||||
|
@ -214,24 +215,15 @@ class CuraApplication(QtApplication):
|
|||
def getPlatformActivity(self):
|
||||
return self._platform_activity
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def setPlatformActivity(self, activity):
|
||||
##Sets the _platform_activity variable on true or false depending on whether there is a mesh on the platform
|
||||
if activity == True:
|
||||
self._platform_activity = activity
|
||||
elif activity == False:
|
||||
nodes = []
|
||||
def updatePlatformActivity(self, node = None):
|
||||
count = 0
|
||||
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
|
||||
if type(node) is not SceneNode or not node.getMeshData():
|
||||
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
|
||||
|
||||
count += 1
|
||||
|
||||
self._platform_activity = True if count > 0 else False
|
||||
self.activityChanged.emit()
|
||||
|
||||
## Remove an object from the scene
|
||||
|
@ -252,7 +244,6 @@ class CuraApplication(QtApplication):
|
|||
group_node = group_node.getParent()
|
||||
op = RemoveSceneNodeOperation(group_node)
|
||||
op.push()
|
||||
self.setPlatformActivity(False)
|
||||
|
||||
## Create a number of copies of existing object.
|
||||
@pyqtSlot("quint64", int)
|
||||
|
@ -300,7 +291,6 @@ class CuraApplication(QtApplication):
|
|||
op.addOperation(RemoveSceneNodeOperation(node))
|
||||
|
||||
op.push()
|
||||
self.setPlatformActivity(False)
|
||||
|
||||
## Reset all translation on nodes with mesh data.
|
||||
@pyqtSlot()
|
||||
|
|
|
@ -15,9 +15,9 @@ import os
|
|||
import struct
|
||||
import math
|
||||
from os import listdir
|
||||
import untangle
|
||||
import zipfile
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
|
||||
class ThreeMFReader(MeshReader):
|
||||
|
@ -25,6 +25,11 @@ class ThreeMFReader(MeshReader):
|
|||
super(ThreeMFReader, self).__init__()
|
||||
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):
|
||||
result = None
|
||||
extension = os.path.splitext(file_name)[1]
|
||||
|
@ -33,32 +38,39 @@ class ThreeMFReader(MeshReader):
|
|||
# The base object of 3mf is a zipped archive.
|
||||
archive = zipfile.ZipFile(file_name, 'r')
|
||||
try:
|
||||
# The model is always stored in this place.
|
||||
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.
|
||||
root = ET.parse(archive.open("3D/3dmodel.model"))
|
||||
|
||||
# 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()
|
||||
node = SceneNode()
|
||||
vertex_list = []
|
||||
for vertex in object.mesh.vertices.vertex:
|
||||
vertex_list.append([vertex['x'],vertex['y'],vertex['z']])
|
||||
#for vertex in object.mesh.vertices.vertex:
|
||||
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:
|
||||
v1 = int(triangle["v1"])
|
||||
v2 = int(triangle["v2"])
|
||||
v3 = int(triangle["v3"])
|
||||
mesh.reserveFaceCount(len(triangles))
|
||||
|
||||
#for triangle in object.mesh.triangles.triangle:
|
||||
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])
|
||||
#TODO: We currently do not check for normals and simply recalculate them.
|
||||
mesh.calculateNormals()
|
||||
node.setMeshData(mesh)
|
||||
node.setSelectable(True)
|
||||
|
||||
# Magical python comprehension; looks for the matching transformation
|
||||
transformation = next((x for x in root.model.build.item if x["objectid"] == object["id"]), None)
|
||||
transformation = root.findall("./3mf:build/3mf:item[@objectid='{0}']".format(object.get("id")), self._namespaces)
|
||||
if transformation:
|
||||
transformation = transformation[0]
|
||||
|
||||
if transformation["transform"]:
|
||||
splitted_transformation = transformation["transform"].split()
|
||||
if transformation.get("transform"):
|
||||
splitted_transformation = transformation.get("transform").split()
|
||||
## Transformation is saved as:
|
||||
## M00 M01 M02 0.0
|
||||
## M10 M11 M12 0.0
|
||||
|
@ -100,9 +112,9 @@ class ThreeMFReader(MeshReader):
|
|||
node.rotate(rotation)
|
||||
result.addChild(node)
|
||||
|
||||
# If there is more then one object, group them.
|
||||
#If there is more then one object, group them.
|
||||
try:
|
||||
if len(root.model.resources.object) > 1:
|
||||
if len(objects) > 1:
|
||||
group_decorator = GroupDecorator()
|
||||
result.addDecorator(group_decorator)
|
||||
except:
|
||||
|
|
|
@ -17,8 +17,8 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||
super().__init__(device_id)
|
||||
|
||||
self.setName(device_name)
|
||||
self.setShortDescription(catalog.i18nc("", "Save to Removable Drive"))
|
||||
self.setDescription(catalog.i18nc("", "Save to Removable Drive {0}").format(device_name))
|
||||
self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
|
||||
self.setDescription(catalog.i18nc("@info:tooltip", "Save to Removable Drive {0}").format(device_name))
|
||||
self.setIconName("save_sd")
|
||||
self.setPriority(1)
|
||||
|
||||
|
@ -49,7 +49,7 @@ class RemovableDriveOutputDevice(OutputDevice):
|
|||
job.progress.connect(self._onProgress)
|
||||
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()
|
||||
|
||||
job._message = message
|
||||
|
|
|
@ -63,7 +63,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
self._listen_thread.daemon = True
|
||||
|
||||
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()
|
||||
|
||||
|
@ -222,6 +222,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
|
||||
self.setProgress(100, 100)
|
||||
|
||||
self.firmwareUpdateComplete.emit()
|
||||
|
||||
## Upload new firmware to machine
|
||||
# \param filename full path of firmware file to be uploaded
|
||||
def updateFirmware(self, file_name):
|
||||
|
@ -277,9 +279,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
if line is None:
|
||||
self.setIsConnected(False) # Something went wrong with reading, could be that close was called.
|
||||
return
|
||||
|
||||
if b"T:" in line:
|
||||
self._serial.timeout = 0.5
|
||||
self._sendCommand("M105")
|
||||
sucesfull_responses += 1
|
||||
if sucesfull_responses >= self._required_responses_auto_baud:
|
||||
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)
|
||||
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)
|
||||
self.close() # Unable to connect, wrap up.
|
||||
self.setIsConnected(False)
|
||||
|
@ -319,6 +323,9 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
except Exception as e:
|
||||
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:
|
||||
self.setIsConnected(False)
|
||||
try:
|
||||
|
@ -327,6 +334,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
pass
|
||||
self._serial.close()
|
||||
|
||||
self._listen_thread = threading.Thread(target=self._listen)
|
||||
self._listen_thread.daemon = True
|
||||
self._serial = None
|
||||
|
||||
def isConnected(self):
|
||||
|
@ -579,3 +588,10 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
|||
def _getBaudrateList(self):
|
||||
ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600]
|
||||
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()
|
||||
|
|
|
@ -481,7 +481,6 @@ UM.MainWindow {
|
|||
onAccepted:
|
||||
{
|
||||
UM.MeshFileHandler.readLocalFile(fileUrl)
|
||||
Printer.setPlatformActivity(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue