diff --git a/CMakeLists.txt b/CMakeLists.txt index ba427a745d..4406fd4856 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,6 @@ set(CURA_APP_NAME "cura" CACHE STRING "Short name of Cura, used for configuratio set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura") set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") -set(CURA_SDK_VERSION "" CACHE STRING "SDK version of Cura") set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root") set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version") diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index 06fdd7a3f0..aea68c0af5 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -9,7 +9,6 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" DEFAULT_CURA_VERSION = "master" DEFAULT_CURA_BUILD_TYPE = "" DEFAULT_CURA_DEBUG_MODE = False -DEFAULT_CURA_SDK_VERSION = "6.1.0" try: from cura.CuraVersion import CuraAppName # type: ignore @@ -42,9 +41,4 @@ try: except ImportError: CuraDebugMode = DEFAULT_CURA_DEBUG_MODE -try: - from cura.CuraVersion import CuraSDKVersion # type: ignore - if CuraSDKVersion == "": - CuraSDKVersion = DEFAULT_CURA_SDK_VERSION -except ImportError: - CuraSDKVersion = DEFAULT_CURA_SDK_VERSION +from cura.CuraVersion import CuraSDKVersion # type: ignore diff --git a/cura/Arranging/ShapeArray.py b/cura/Arranging/ShapeArray.py index 64b78d6f17..9227e446fb 100644 --- a/cura/Arranging/ShapeArray.py +++ b/cura/Arranging/ShapeArray.py @@ -1,12 +1,18 @@ +#Copyright (c) 2019 Ultimaker B.V. +#Cura is released under the terms of the LGPLv3 or higher. + import numpy import copy +from typing import Optional, Tuple, TYPE_CHECKING from UM.Math.Polygon import Polygon +if TYPE_CHECKING: + from UM.Scene.SceneNode import SceneNode ## Polygon representation as an array for use with Arrange class ShapeArray: - def __init__(self, arr, offset_x, offset_y, scale = 1): + def __init__(self, arr: numpy.array, offset_x: float, offset_y: float, scale: float = 1) -> None: self.arr = arr self.offset_x = offset_x self.offset_y = offset_y @@ -16,7 +22,7 @@ class ShapeArray: # \param vertices # \param scale scale the coordinates @classmethod - def fromPolygon(cls, vertices, scale = 1): + def fromPolygon(cls, vertices: numpy.array, scale: float = 1) -> "ShapeArray": # scale vertices = vertices * scale # flip y, x -> x, y @@ -42,7 +48,7 @@ class ShapeArray: # \param min_offset offset for the offset ShapeArray # \param scale scale the coordinates @classmethod - def fromNode(cls, node, min_offset, scale = 0.5, include_children = False): + def fromNode(cls, node: "SceneNode", min_offset: float, scale: float = 0.5, include_children: bool = False) -> Tuple[Optional["ShapeArray"], Optional["ShapeArray"]]: transform = node._transformation transform_x = transform._data[0][3] transform_y = transform._data[2][3] @@ -88,7 +94,7 @@ class ShapeArray: # \param shape numpy format shape, [x-size, y-size] # \param vertices @classmethod - def arrayFromPolygon(cls, shape, vertices): + def arrayFromPolygon(cls, shape: Tuple[int, int], vertices: numpy.array) -> numpy.array: base_array = numpy.zeros(shape, dtype = numpy.int32) # Initialize your array of zeros fill = numpy.ones(base_array.shape) * True # Initialize boolean array defining shape fill @@ -111,9 +117,9 @@ class ShapeArray: # \param p2 2-tuple with x, y for point 2 # \param base_array boolean array to project the line on @classmethod - def _check(cls, p1, p2, base_array): + def _check(cls, p1: numpy.array, p2: numpy.array, base_array: numpy.array) -> bool: if p1[0] == p2[0] and p1[1] == p2[1]: - return + return False idxs = numpy.indices(base_array.shape) # Create 3D array of indices p1 = p1.astype(float) @@ -131,5 +137,4 @@ class ShapeArray: max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1] sign = numpy.sign(p2[0] - p1[0]) - return idxs[1] * sign <= max_col_idx * sign - + return idxs[1] * sign <= max_col_idx * sign \ No newline at end of file diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 3358fe8b85..bf38e6e562 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -787,11 +787,14 @@ class BuildVolume(SceneNode): # where that extruder may not print. def _computeDisallowedAreasPrinted(self, used_extruders): result = {} + adhesion_extruder = None #type: ExtruderStack for extruder in used_extruders: + if int(extruder.getProperty("extruder_nr", "value")) == int(self._global_container_stack.getProperty("adhesion_extruder_nr", "value")): + adhesion_extruder = extruder result[extruder.getId()] = [] # Currently, the only normally printed object is the prime tower. - if self._global_container_stack.getProperty("prime_tower_enable"): + if self._global_container_stack.getProperty("prime_tower_enable", "value"): prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value") machine_width = self._global_container_stack.getProperty("machine_width", "value") machine_depth = self._global_container_stack.getProperty("machine_depth", "value") @@ -801,11 +804,11 @@ class BuildVolume(SceneNode): prime_tower_x = prime_tower_x - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left. prime_tower_y = prime_tower_y + machine_depth / 2 - if self._global_container_stack.getProperty("prime_tower_brim_enable", "value") and self._global_container_stack.getProperty("adhesion_type", "value") != "raft": + if adhesion_extruder is not None and self._global_container_stack.getProperty("prime_tower_brim_enable", "value") and self._global_container_stack.getProperty("adhesion_type", "value") != "raft": brim_size = ( - extruder.getProperty("brim_line_count", "value") * - extruder.getProperty("skirt_brim_line_width", "value") / 100.0 * - extruder.getProperty("initial_layer_line_width_factor", "value") + adhesion_extruder.getProperty("brim_line_count", "value") * + adhesion_extruder.getProperty("skirt_brim_line_width", "value") / 100.0 * + adhesion_extruder.getProperty("initial_layer_line_width_factor", "value") ) prime_tower_x -= brim_size prime_tower_y += brim_size diff --git a/cura/CuraVersion.py.in b/cura/CuraVersion.py.in index 1a500df248..abbc3a0a0d 100644 --- a/cura/CuraVersion.py.in +++ b/cura/CuraVersion.py.in @@ -6,7 +6,9 @@ CuraAppDisplayName = "@CURA_APP_DISPLAY_NAME@" CuraVersion = "@CURA_VERSION@" CuraBuildType = "@CURA_BUILDTYPE@" CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False -CuraSDKVersion = "@CURA_SDK_VERSION@" + +CuraSDKVersion = "6.1.0" + CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@" CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@" CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@" diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 3366d67d25..764ad8ed43 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -986,8 +986,9 @@ class MachineManager(QObject): self._application.globalContainerStackChanged.emit() self.forceUpdateAllSettings() + # Note that this function is deprecated, but the decorators for this don't play well together! + # @deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2") @pyqtSlot(int, result = QObject) - @deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2") def getExtruder(self, position: int) -> Optional[ExtruderStack]: if self._global_container_stack: return self._global_container_stack.extruders.get(str(position)) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index bbd3f5b870..6944a09115 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -963,20 +963,20 @@ "maximum_value_warning": "2 * machine_nozzle_size", "settable_per_mesh": false, "settable_per_extruder": true - }, - "initial_layer_line_width_factor": - { - "label": "Initial Layer Line Width", - "description": "Multiplier of the line width on the first layer. Increasing this could improve bed adhesion.", - "type": "float", - "unit": "%", - "default_value": 100.0, - "minimum_value": "0.001", - "maximum_value_warning": "150", - "settable_per_mesh": false, - "settable_per_extruder": true } } + }, + "initial_layer_line_width_factor": + { + "label": "Initial Layer Line Width", + "description": "Multiplier of the line width on the first layer. Increasing this could improve bed adhesion.", + "type": "float", + "unit": "%", + "default_value": 100.0, + "minimum_value": "0.001", + "maximum_value_warning": "150", + "settable_per_mesh": false, + "settable_per_extruder": true } } }, @@ -2346,7 +2346,195 @@ "minimum_value_warning": "50", "maximum_value_warning": "150", "enabled": "machine_gcode_flavor != \"UltiGCode\"", - "settable_per_mesh": true + "settable_per_mesh": true, + "children": + { + "wall_material_flow": + { + "label": "Wall Flow", + "description": "Flow compensation on wall lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "limit_to_extruder": "wall_0_extruder_nr if wall_x_extruder_nr == wall_0_extruder_nr else -1", + "settable_per_mesh": true, + "children": + { + "wall_0_material_flow": + { + "label": "Outer Wall Flow", + "description": "Flow compensation on the outermost wall line.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "wall_material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "limit_to_extruder": "wall_0_extruder_nr", + "settable_per_mesh": true + }, + "wall_x_material_flow": + { + "label": "Inner Wall(s) Flow", + "description": "Flow compensation on wall lines for all wall lines except the outermost one.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "wall_material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "limit_to_extruder": "wall_x_extruder_nr", + "settable_per_mesh": true + } + } + }, + "skin_material_flow": + { + "label": "Top/Bottom Flow", + "description": "Flow compensation on top/bottom lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "top_layers > 0 or bottom_layers > 0", + "limit_to_extruder": "top_bottom_extruder_nr", + "settable_per_mesh": true + }, + "roofing_material_flow": + { + "label": "Top Surface Skin Flow", + "description": "Flow compensation on lines of the areas at the top of the print.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "skin_material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "limit_to_extruder": "roofing_extruder_nr", + "settable_per_mesh": true, + "enabled": "roofing_layer_count > 0 and top_layers > 0" + }, + "infill_material_flow": + { + "label": "Infill Flow", + "description": "Flow compensation on infill lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "infill_sparse_density > 0", + "limit_to_extruder": "infill_extruder_nr", + "settable_per_mesh": true + }, + "skirt_brim_material_flow": + { + "label": "Skirt/Brim Flow", + "description": "Flow compensation on skirt or brim lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "resolveOrValue('adhesion_type') == 'skirt' or resolveOrValue('adhesion_type') == 'brim'", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "support_material_flow": + { + "label": "Support Flow", + "description": "Flow compensation on support structure lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "limit_to_extruder": "support_infill_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "support_interface_material_flow": + { + "label": "Support Interface Flow", + "description": "Flow compensation on lines of support roof or floor.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "support_enable and support_interface_enable", + "limit_to_extruder": "support_interface_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true, + "children": + { + "support_roof_material_flow": + { + "label": "Support Roof Flow", + "description": "Flow compensation on support roof lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "extruderValue(support_roof_extruder_nr, 'support_interface_material_flow')", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "support_enable and support_roof_enable", + "limit_to_extruder": "support_roof_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "support_bottom_material_flow": + { + "label": "Support Floor Flow", + "description": "Flow compensation on support floor lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "extruderValue(support_bottom_extruder_nr, 'support_interface_material_flow')", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "enabled": "support_enable and support_bottom_enable", + "limit_to_extruder": "support_bottom_extruder_nr", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } + }, + "prime_tower_flow": + { + "label": "Prime Tower Flow", + "description": "Flow compensation on prime tower lines.", + "unit": "%", + "type": "float", + "default_value": 100, + "value": "material_flow", + "minimum_value": "5", + "minimum_value_warning": "50", + "maximum_value_warning": "150", + "settable_per_mesh": false, + "settable_per_extruder": true + } + } }, "material_flow_layer_0": { @@ -2354,7 +2542,6 @@ "description": "Flow compensation for the first layer: the amount of material extruded on the initial layer is multiplied by this value.", "unit": "%", "default_value": 100, - "value": "material_flow", "type": "float", "minimum_value": "0.0001", "minimum_value_warning": "50", @@ -5439,21 +5626,6 @@ "settable_per_mesh": false, "settable_per_extruder": false }, - "prime_tower_flow": - { - "label": "Prime Tower Flow", - "description": "Flow compensation: the amount of material extruded is multiplied by this value.", - "type": "float", - "unit": "%", - "enabled": "resolveOrValue('prime_tower_enable')", - "default_value": 100, - "value": "material_flow", - "minimum_value": "0.0001", - "minimum_value_warning": "50", - "maximum_value_warning": "150", - "settable_per_mesh": false, - "settable_per_extruder": true - }, "prime_tower_wipe_enabled": { "label": "Wipe Inactive Nozzle on Prime Tower", diff --git a/resources/qml/Menus/ViewMenu.qml b/resources/qml/Menus/ViewMenu.qml index 59e6dd24d0..4e5545223f 100644 --- a/resources/qml/Menus/ViewMenu.qml +++ b/resources/qml/Menus/ViewMenu.qml @@ -24,6 +24,51 @@ Menu MenuItem { action: Cura.Actions.viewRightSideCamera; } } + Menu + { + id: cameraViewMenu + property string cameraMode: UM.Preferences.getValue("general/camera_perspective_mode") + Connections + { + target: UM.Preferences + onPreferenceChanged: + { + if (preference !== "general/camera_perspective_mode") + { + return + } + cameraViewMenu.cameraMode = UM.Preferences.getValue("general/camera_perspective_mode") + } + } + + title: catalog.i18nc("@action:inmenu menubar:view","Camera view") + MenuItem + { + text: catalog.i18nc("@action:inmenu menubar:view", "Perspective") + checkable: true + checked: cameraViewMenu.cameraMode == "perspective" + onTriggered: + { + UM.Preferences.setValue("general/camera_perspective_mode", "perspective") + checked = cameraViewMenu.cameraMode == "perspective" + } + exclusiveGroup: group + } + MenuItem + { + text: catalog.i18nc("@action:inmenu menubar:view", "Orthographic") + checkable: true + checked: cameraViewMenu.cameraMode == "orthogonal" + onTriggered: + { + UM.Preferences.setValue("general/camera_perspective_mode", "orthogonal") + checked = cameraViewMenu.cameraMode == "orthogonal" + } + exclusiveGroup: group + } + ExclusiveGroup { id: group } + } + MenuSeparator { visible: UM.Preferences.getValue("cura/use_multi_build_plate") diff --git a/resources/setting_visibility/expert.cfg b/resources/setting_visibility/expert.cfg index ea3d4e6ef1..3f28f5d48d 100644 --- a/resources/setting_visibility/expert.cfg +++ b/resources/setting_visibility/expert.cfg @@ -113,6 +113,18 @@ material_bed_temperature_layer_0 material_adhesion_tendency material_surface_energy material_flow +wall_material_flow +wall_0_material_flow +wall_x_material_flow +skin_material_flow +roofing_material_flow +infill_material_flow +skirt_brim_material_flow +support_material_flow +support_interface_material_flow +support_roof_material_flow +support_bottom_material_flow +prime_tower_flow material_flow_layer_0 retraction_enable retract_at_layer_change @@ -297,7 +309,6 @@ prime_tower_size prime_tower_min_volume prime_tower_position_x prime_tower_position_y -prime_tower_flow prime_tower_wipe_enabled prime_tower_brim_enable ooze_shield_enabled diff --git a/tests/TestBuildVolume.py b/tests/TestBuildVolume.py index 902d8a839c..6ccb3d0fb7 100644 --- a/tests/TestBuildVolume.py +++ b/tests/TestBuildVolume.py @@ -1,9 +1,9 @@ from unittest.mock import MagicMock, patch - +from UM.Math.AxisAlignedBox import AxisAlignedBox import pytest from UM.Math.Polygon import Polygon -from UM.Settings.SettingInstance import InstanceState +from UM.Math.Vector import Vector from cura.BuildVolume import BuildVolume, PRIME_CLEARANCE import numpy @@ -304,6 +304,25 @@ class TestRebuild: build_volume.rebuild() assert build_volume.getMeshData() is None + def test_updateBoundingBox(self, build_volume: BuildVolume): + build_volume.setWidth(10) + build_volume.setHeight(10) + build_volume.setDepth(10) + + mocked_global_stack = MagicMock() + build_volume._global_container_stack = mocked_global_stack + build_volume.getEdgeDisallowedSize = MagicMock(return_value = 0) + build_volume.updateNodeBoundaryCheck = MagicMock() + + # Fake the the "engine is created callback" + build_volume._onEngineCreated() + build_volume.rebuild() + + bounding_box = build_volume.getBoundingBox() + assert bounding_box.minimum == Vector(-5.0, -1.0, -5.0) + assert bounding_box.maximum == Vector(5.0, 10.0, 5.0) + + class TestUpdateMachineSizeProperties: setting_property_dict = {"machine_width": {"value": 50}, "machine_depth": {"value": 100},