Skip to content

Commit

Permalink
Merge branch 'main' into 5.8
Browse files Browse the repository at this point in the history
  • Loading branch information
wawanbreton authored Aug 12, 2024
2 parents 081b9b5 + e3287a1 commit fec7637
Show file tree
Hide file tree
Showing 43 changed files with 326 additions and 171 deletions.
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/SlicingCrash.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ body:
attributes:
value: |
### ✨Try our improved Cura 5.7✨
Before filling out the report below, we want you to try the latest Cura 5.7 Beta.
Before filling out the report below, we want you to try the latest Cura 5.7.
This version of Cura has become significantly more reliable and has an updated slicing engine that will automatically send a report to the Cura Team for analysis.
#### [You can find the downloads here](https://github.com/Ultimaker/Cura/releases/tag/5.7.0-beta.1) ####
#### [You can find the downloads here](https://github.com/Ultimaker/Cura/releases/latest) ####
If you still encounter a crash you are still welcome to report the issue so we can use your model as a test case, you can find instructions on how to do that below.
### Project File
Expand All @@ -35,7 +35,7 @@ body:
- type: markdown
attributes:
value: |
We work hard on improving our slicing crashes. Our most recent release is 5.6.0.
We work hard on improving our slicing crashes. Our most recent release is 5.7.1.
If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/latest)
- type: input
attributes:
Expand Down
14 changes: 7 additions & 7 deletions conandata.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
version: "5.8.0"
version: "5.9.0-alpha.0"
requirements:
- "cura_resources/5.8.0"
- "uranium/5.8.0"
- "curaengine/5.8.0"
- "cura_binary_data/5.8.0"
- "fdm_materials/5.8.0"
- "cura_resources/(latest)@ultimaker/testing"
- "uranium/(latest)@ultimaker/testing"
- "curaengine/(latest)@ultimaker/testing"
- "cura_binary_data/(latest)@ultimaker/testing"
- "fdm_materials/(latest)@ultimaker/testing"
- "curaengine_plugin_gradual_flow/0.1.0-beta.4"
- "dulcificum/0.2.1"
- "pysavitar/5.3.0"
- "pynest2d/5.3.0"
- "native_cad_plugin/2.0.0"
requirements_internal:
- "fdm_materials/5.8.0"
- "fdm_materials/(latest)@internal/testing"
- "cura_private_data/(latest)@internal/testing"
urls:
default:
Expand Down
62 changes: 61 additions & 1 deletion cura/API/Interface/Settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.

from typing import TYPE_CHECKING
from dataclasses import asdict

from typing import cast, Dict, TYPE_CHECKING

from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
from cura.Settings.GlobalStack import GlobalStack

if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
Expand Down Expand Up @@ -47,3 +53,57 @@ def getContextMenuItems(self) -> list:
"""

return self.application.getSidebarCustomMenuItems()

def getSliceMetadata(self) -> Dict[str, Dict[str, Dict[str, str]]]:
"""Get all changed settings and all settings. For each extruder and the global stack"""
print_information = self.application.getPrintInformation()
machine_manager = self.application.getMachineManager()
settings = {
"material": {
"length": print_information.materialLengths,
"weight": print_information.materialWeights,
"cost": print_information.materialCosts,
},
"global": {
"changes": {},
"all_settings": {},
},
"quality": asdict(machine_manager.activeQualityDisplayNameMap()),
}

def _retrieveValue(container: InstanceContainer, setting_: str):
value_ = container.getProperty(setting_, "value")
for _ in range(0, 1024): # Prevent possibly endless loop by not using a limit.
if not isinstance(value_, SettingFunction):
return value_ # Success!
value_ = value_(container)
return 0 # Fallback value after breaking possibly endless loop.

global_stack = cast(GlobalStack, self.application.getGlobalContainerStack())

# Add global user or quality changes
global_flattened_changes = InstanceContainer.createMergedInstanceContainer(global_stack.userChanges, global_stack.qualityChanges)
for setting in global_flattened_changes.getAllKeys():
settings["global"]["changes"][setting] = _retrieveValue(global_flattened_changes, setting)

# Get global all settings values without user or quality changes
for setting in global_stack.getAllKeys():
settings["global"]["all_settings"][setting] = _retrieveValue(global_stack, setting)

for i, extruder in enumerate(global_stack.extruderList):
# Add extruder fields to settings dictionary
settings[f"extruder_{i}"] = {
"changes": {},
"all_settings": {},
}

# Add extruder user or quality changes
extruder_flattened_changes = InstanceContainer.createMergedInstanceContainer(extruder.userChanges, extruder.qualityChanges)
for setting in extruder_flattened_changes.getAllKeys():
settings[f"extruder_{i}"]["changes"][setting] = _retrieveValue(extruder_flattened_changes, setting)

# Get extruder all settings values without user or quality changes
for setting in extruder.getAllKeys():
settings[f"extruder_{i}"]["all_settings"][setting] = _retrieveValue(extruder, setting)

return settings
106 changes: 106 additions & 0 deletions cura/PrinterOutput/FormatMaps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Copyright (c) 2024 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.

from UM.Resources import Resources

import json
from typing import Dict, List, Optional

class FormatMaps:

# A map from the printer-type in their native file-formats to the internal name we use.
PRINTER_TYPE_NAME = {
"fire_e": "ultimaker_method",
"lava_f": "ultimaker_methodx",
"magma_10": "ultimaker_methodxl",
"sketch": "ultimaker_sketch"
}

# A map from the extruder-name in their native file-formats to the internal name we use.
EXTRUDER_NAME_MAP = {
"mk14_hot": "1XA",
"mk14_hot_s": "2XA",
"mk14_c": "1C",
"mk14": "1A",
"mk14_s": "2A",
"mk14_e": "LABS"
}

# A map from the material-name in their native file-formats to some info, including the internal name we use.
MATERIAL_MAP = {
"abs": {"name": "ABS", "guid": "2780b345-577b-4a24-a2c5-12e6aad3e690"},
"abs-cf10": {"name": "ABS-CF", "guid": "495a0ce5-9daf-4a16-b7b2-06856d82394d"},
"abs-wss1": {"name": "ABS-R", "guid": "88c8919c-6a09-471a-b7b6-e801263d862d"},
"asa": {"name": "ASA", "guid": "f79bc612-21eb-482e-ad6c-87d75bdde066"},
"nylon12-cf": {"name": "Nylon 12 CF", "guid": "3c6f2877-71cc-4760-84e6-4b89ab243e3b"},
"nylon": {"name": "Nylon", "guid": "283d439a-3490-4481-920c-c51d8cdecf9c"},
"pc": {"name": "PC", "guid": "62414577-94d1-490d-b1e4-7ef3ec40db02"},
"petg": {"name": "PETG", "guid": "69386c85-5b6c-421a-bec5-aeb1fb33f060"},
"pla": {"name": "PLA", "guid": "abb9c58e-1f56-48d1-bd8f-055fde3a5b56"},
"pva": {"name": "PVA", "guid": "add51ef2-86eb-4c39-afd5-5586564f0715"},
"wss1": {"name": "RapidRinse", "guid": "a140ef8f-4f26-4e73-abe0-cfc29d6d1024"},
"sr30": {"name": "SR-30", "guid": "77873465-83a9-4283-bc44-4e542b8eb3eb"},
"bvoh": {"name": "BVOH", "guid": "923e604c-8432-4b09-96aa-9bbbd42207f4"},
"cpe": {"name": "CPE", "guid": "da1872c1-b991-4795-80ad-bdac0f131726"},
"hips": {"name": "HIPS", "guid": "a468d86a-220c-47eb-99a5-bbb47e514eb0"},
"tpu": {"name": "TPU 95A", "guid": "19baa6a9-94ff-478b-b4a1-8157b74358d2"},
"im-pla": {"name": "Tough", "guid": "de031137-a8ca-4a72-bd1b-17bb964033ad"}
}

__inverse_printer_name: Optional[Dict[str, str]] = None
__inverse_extruder_type: Optional[Dict[str, str]] = None
__inverse_material_map: Optional[Dict[str, str]] = None
__product_to_id_map: Optional[Dict[str, List[str]]] = None

@classmethod
def getInversePrinterNameMap(cls) -> Dict[str, str]:
"""Returns the inverse of the printer name map, that is, from the internal name to the name used in output."""
if cls.__inverse_printer_name is not None:
return cls.__inverse_printer_name
cls.__inverse_printer_name = {}
for key, value in cls.PRINTER_TYPE_NAME.items():
cls.__inverse_printer_name[value] = key
return cls.__inverse_printer_name

@classmethod
def getInverseExtruderTypeMap(cls) -> Dict[str, str]:
"""Returns the inverse of the extruder type map, that is, from the internal name to the name used in output."""
if cls.__inverse_extruder_type is not None:
return cls.__inverse_extruder_type
cls.__inverse_extruder_type = {}
for key, value in cls.EXTRUDER_NAME_MAP.items():
cls.__inverse_extruder_type[value] = key
return cls.__inverse_extruder_type

@classmethod
def getInverseMaterialMap(cls) -> Dict[str, str]:
"""Returns the inverse of the material map, that is, from the internal name to the name used in output.
Note that this drops the extra info saved in the non-inverse material map, use that if you need it.
"""
if cls.__inverse_material_map is not None:
return cls.__inverse_material_map
cls.__inverse_material_map = {}
for key, value in cls.MATERIAL_MAP.items():
cls.__inverse_material_map[value["name"]] = key
return cls.__inverse_material_map

@classmethod
def getProductIdMap(cls) -> Dict[str, List[str]]:
"""Gets a mapping from product names (for example, in the XML files) to their definition IDs.
This loads the mapping from a file.
"""
if cls.__product_to_id_map is not None:
return cls.__product_to_id_map

product_to_id_file = Resources.getPath(Resources.Texts, "product_to_id.json")
with open(product_to_id_file, encoding = "utf-8") as f:
contents = ""
for line in f:
contents += line if "#" not in line else "".join([line.replace("#", str(n)) for n in range(1, 12)])
cls.__product_to_id_map = json.loads(contents)
cls.__product_to_id_map = {key: [value] for key, value in cls.__product_to_id_map.items()}
#This also loads "Ultimaker S5" -> "ultimaker_s5" even though that is not strictly necessary with the default to change spaces into underscores.
#However it is not always loaded with that default; this mapping is also used in serialize() without that default.
return cls.__product_to_id_map
15 changes: 4 additions & 11 deletions cura/PrinterOutput/Models/ExtruderConfigurationModel.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2024 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional

from PyQt6.QtCore import pyqtProperty, QObject, pyqtSignal

from cura.PrinterOutput.FormatMaps import FormatMaps
from .MaterialOutputModel import MaterialOutputModel


Expand Down Expand Up @@ -45,16 +46,8 @@ def setHotendID(self, hotend_id: Optional[str]) -> None:

@staticmethod
def applyNameMappingHotend(hotendId) -> str:
_EXTRUDER_NAME_MAP = {
"mk14_hot":"1XA",
"mk14_hot_s":"2XA",
"mk14_c":"1C",
"mk14":"1A",
"mk14_s":"2A",
"mk14_e": "LABS"
}
if hotendId in _EXTRUDER_NAME_MAP:
return _EXTRUDER_NAME_MAP[hotendId]
if hotendId in FormatMaps.EXTRUDER_NAME_MAP:
return FormatMaps.EXTRUDER_NAME_MAP[hotendId]
return hotendId

@pyqtProperty(str, fset = setHotendID, notify = extruderConfigurationChanged)
Expand Down
30 changes: 5 additions & 25 deletions cura/PrinterOutput/Models/MaterialOutputModel.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Copyright (c) 2017 Ultimaker B.V.
# Copyright (c) 2024 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.

from typing import Optional

from PyQt6.QtCore import pyqtProperty, QObject
from cura.PrinterOutput.FormatMaps import FormatMaps


class MaterialOutputModel(QObject):
Expand All @@ -23,30 +24,9 @@ def guid(self) -> str:

@staticmethod
def getMaterialFromDefinition(guid, type, brand, name):

_MATERIAL_MAP = { "abs" :{"name" :"ABS" ,"guid": "2780b345-577b-4a24-a2c5-12e6aad3e690"},
"abs-cf10" :{"name": "ABS-CF" ,"guid": "495a0ce5-9daf-4a16-b7b2-06856d82394d"},
"abs-wss1" :{"name" :"ABS-R" ,"guid": "88c8919c-6a09-471a-b7b6-e801263d862d"},
"asa" :{"name" :"ASA" ,"guid": "f79bc612-21eb-482e-ad6c-87d75bdde066"},
"nylon12-cf":{"name": "Nylon 12 CF" ,"guid": "3c6f2877-71cc-4760-84e6-4b89ab243e3b"},
"nylon" :{"name" :"Nylon" ,"guid": "283d439a-3490-4481-920c-c51d8cdecf9c"},
"pc" :{"name" :"PC" ,"guid": "62414577-94d1-490d-b1e4-7ef3ec40db02"},
"petg" :{"name" :"PETG" ,"guid": "69386c85-5b6c-421a-bec5-aeb1fb33f060"},
"pla" :{"name" :"PLA" ,"guid": "abb9c58e-1f56-48d1-bd8f-055fde3a5b56"},
"pva" :{"name" :"PVA" ,"guid": "add51ef2-86eb-4c39-afd5-5586564f0715"},
"wss1" :{"name" :"RapidRinse" ,"guid": "a140ef8f-4f26-4e73-abe0-cfc29d6d1024"},
"sr30" :{"name" :"SR-30" ,"guid": "77873465-83a9-4283-bc44-4e542b8eb3eb"},
"bvoh" :{"name" :"BVOH" ,"guid": "923e604c-8432-4b09-96aa-9bbbd42207f4"},
"cpe" :{"name" :"CPE" ,"guid": "da1872c1-b991-4795-80ad-bdac0f131726"},
"hips" :{"name" :"HIPS" ,"guid": "a468d86a-220c-47eb-99a5-bbb47e514eb0"},
"tpu" :{"name" :"TPU 95A" ,"guid": "19baa6a9-94ff-478b-b4a1-8157b74358d2"},
"im-pla" :{"name": "Tough" ,"guid": "de031137-a8ca-4a72-bd1b-17bb964033ad"}
}


if guid is None and brand != "empty" and type in _MATERIAL_MAP:
name = _MATERIAL_MAP[type]["name"]
guid = _MATERIAL_MAP[type]["guid"]
if guid is None and brand != "empty" and type in FormatMaps.MATERIAL_MAP:
name = FormatMaps.MATERIAL_MAP[type]["name"]
guid = FormatMaps.MATERIAL_MAP[type]["guid"]
return name, guid


Expand Down
13 changes: 4 additions & 9 deletions cura/PrinterOutput/NetworkedPrinterOutputDevice.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Copyright (c) 2021 Ultimaker B.V.
# Copyright (c) 2024 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.

from UM.FileHandler.FileHandler import FileHandler #For typing.
from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode #For typing.
from cura.API import Account
from cura.CuraApplication import CuraApplication
from cura.PrinterOutput.FormatMaps import FormatMaps

from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice, ConnectionState, ConnectionType

Expand Down Expand Up @@ -419,14 +420,8 @@ def printerType(self) -> str:

@staticmethod
def applyPrinterTypeMapping(printer_type):
_PRINTER_TYPE_NAME = {
"fire_e": "ultimaker_method",
"lava_f": "ultimaker_methodx",
"magma_10": "ultimaker_methodxl",
"sketch": "ultimaker_sketch"
}
if printer_type in _PRINTER_TYPE_NAME:
return _PRINTER_TYPE_NAME[printer_type]
if printer_type in FormatMaps.PRINTER_TYPE_NAME:
return FormatMaps.PRINTER_TYPE_NAME[printer_type]
return printer_type

@pyqtProperty(str, constant = True)
Expand Down
16 changes: 9 additions & 7 deletions plugins/3MFWriter/ThreeMFWriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,22 +114,24 @@ def _convertUMNodeToSavitarNode(um_node,

mesh_data = um_node.getMeshData()

node_matrix = um_node.getLocalTransformation()
node_matrix.preMultiply(transformation)

if center_mesh:
node_matrix = Matrix()
center_matrix = Matrix()
# compensate for original center position, if object(s) is/are not around its zero position
if mesh_data is not None:
extents = mesh_data.getExtents()
if extents is not None:
# We use a different coordinate space while writing, so flip Z and Y
center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
node_matrix.setByTranslation(center_vector)
node_matrix.multiply(um_node.getLocalTransformation())
else:
node_matrix = um_node.getLocalTransformation()
center_vector = Vector(-extents.center.x, -extents.center.y, -extents.center.z)
center_matrix.setByTranslation(center_vector)
node_matrix.preMultiply(center_matrix)

matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix.preMultiply(transformation))
matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix)

savitar_node.setTransformation(matrix_string)

if mesh_data is not None:
savitar_node.getMeshData().setVerticesFromBytes(mesh_data.getVerticesAsByteArray())
indices_array = mesh_data.getIndicesAsByteArray()
Expand Down
7 changes: 6 additions & 1 deletion plugins/CuraEngineBackend/StartSliceJob.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,12 @@ def run(self) -> None:
for extruder_stack in global_stack.extruderList:
self._buildExtruderMessage(extruder_stack)

for plugin in CuraApplication.getInstance().getBackendPlugins():
backend_plugins = CuraApplication.getInstance().getBackendPlugins()

# Sort backend plugins by name. Not a very good strategy, but at least it is repeatable. This will be improved later.
backend_plugins = sorted(backend_plugins, key=lambda backend_plugin: backend_plugin.getId())

for plugin in backend_plugins:
if not plugin.usePlugin():
continue
for slot in plugin.getSupportedSlots():
Expand Down
Loading

0 comments on commit fec7637

Please sign in to comment.