From 3845da24a18867a50a949cff153cb4923ce7ccf7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Thu, 23 May 2019 15:53:00 +0200 Subject: [PATCH 01/18] Add new material properties for cleanly breaking off materials When performing a long retract, the firmware can use these material properties to determine how fast and how far it needs to retract. The retraction goes in two stages: Anti-ooze retraction stops oozing, and then the break retraction breaks off the filament from the bead in the nozzle. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 793a0e0889..f8cf1eb97f 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2234,6 +2234,64 @@ "settable_per_mesh": false, "settable_per_extruder": true }, + "material_crystallinity": + { + "label": "Crystalline Material", + "description": "Is this material the type that breaks off cleanly when heated, or is it the type that produces long intertwined polymer chains?", + "type": "bool", + "default_value": true, + "enabled": false, + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_anti_ooze_retraction_distance": + { + "label": "Anti-ooze Retraction Distance", + "description": "How far the material needs to be retracted before it stops oozing.", + "type": "float", + "unit": "mm", + "default_value": 4, + "minimum_value": "0", + "maximum_value_warning": "retraction_amount", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_anti_ooze_retraction_speed": + { + "label": "Anti-ooze Retraction Speed", + "description": "How fast the material needs to be retracted during a filament switch to prevent oozing.", + "type": "float", + "unit": "mm/s", + "default_value": 5, + "minimum_value": "0", + "maximum_value": "machine_max_feedrate_e", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_break_distance": + { + "label": "Break Retraction Distance", + "description": "How far can the filament be stretched before it breaks, while heated?", + "type": "float", + "unit": "mm", + "default_value": 16, + "minimum_value": "0", + "maximum_value_warning": "retraction_amount * 4", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_break_speed": + { + "label": "Break Retraction Speed", + "description": "How fast does the filament need to be retracted in order to break cleanly?", + "type": "float", + "unit": "mm/s", + "default_value": 2, + "minimum_value": "0", + "maximum_value": "machine_max_feedrate_e", + "settable_per_mesh": false, + "settable_per_extruder": true + }, "material_flow": { "label": "Flow", From d7d51571b5ebc4cb3392cf520303e79443d9f572 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 3 Jun 2019 17:25:00 +0200 Subject: [PATCH 02/18] Add additional settings from XML materials These are all needed to implement the end-of-filament deprime procedure in the PPA's experiment. They are not necessary for slicing. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 60 ++++++++++++++++++++--- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index f8cf1eb97f..6c315329de 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2268,10 +2268,10 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_break_distance": + "material_break_preparation_distance": { - "label": "Break Retraction Distance", - "description": "How far can the filament be stretched before it breaks, while heated?", + "label": "Break Preparation Retraction Distance", + "description": "How far the filament can be stretched before it breaks, while heated.", "type": "float", "unit": "mm", "default_value": 16, @@ -2280,10 +2280,10 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_break_speed": + "material_break_preparation_speed": { - "label": "Break Retraction Speed", - "description": "How fast does the filament need to be retracted in order to break cleanly?", + "label": "Break Preparation Retraction Speed", + "description": "How fast the filament needs to be retracted just before breaking it off in a retraction.", "type": "float", "unit": "mm/s", "default_value": 2, @@ -2292,6 +2292,54 @@ "settable_per_mesh": false, "settable_per_extruder": true }, + "material_break_preparation_temperature": + { + "label": "Break Preparation Temperature", + "description": "The temperature at which the filament needs to be stretched towards breaking.", + "type": "float", + "unit": "°C", + "default_value": 200, + "minimum_value": "-273.15", + "maximum_value_warning": "300", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_break_distance": + { + "label": "Break Retraction Distance", + "description": "How far to retract the filament in order to break it cleanly.", + "type": "float", + "unit": "mm", + "default_value": 50, + "minimum_value_warning": "0", + "maximum_value_warning": "100", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_break_speed": + { + "label": "Break Retraction Speed", + "description": "The speed at which to retract the filament in order to break it cleanly.", + "type": "float", + "unit": "mm/s", + "default_value": 25, + "minimum_value": "0", + "maximum_value": "machine_max_feedrate_e", + "settable_per_mesh": false, + "settable_per_extruder": true + }, + "material_break_temperature": + { + "label": "Break Temperature", + "description": "The temperature at which the filament is broken for a clean break.", + "type": "float", + "unit": "°C", + "default_value": 50, + "minimum_value": "-273.15", + "maximum_value_warning": "300", + "settable_per_mesh": false, + "settable_per_extruder": true + }, "material_flow": { "label": "Flow", From 3d6e43ba9e874240321a4112000b8f2e5b571a06 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Mon, 3 Jun 2019 17:28:53 +0200 Subject: [PATCH 03/18] Disable deprime-related settings Cura needs to be able to read these from the XML profiles in order to set up the experiment, but they don't affect slicing so the user doesn't need to adjust them. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 6c315329de..eebca3b87c 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2251,6 +2251,7 @@ "type": "float", "unit": "mm", "default_value": 4, + "enabled": false, "minimum_value": "0", "maximum_value_warning": "retraction_amount", "settable_per_mesh": false, @@ -2263,6 +2264,7 @@ "type": "float", "unit": "mm/s", "default_value": 5, + "enabled": false, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", "settable_per_mesh": false, @@ -2275,6 +2277,7 @@ "type": "float", "unit": "mm", "default_value": 16, + "enabled": false, "minimum_value": "0", "maximum_value_warning": "retraction_amount * 4", "settable_per_mesh": false, @@ -2287,6 +2290,7 @@ "type": "float", "unit": "mm/s", "default_value": 2, + "enabled": false, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", "settable_per_mesh": false, @@ -2299,6 +2303,7 @@ "type": "float", "unit": "°C", "default_value": 200, + "enabled": false, "minimum_value": "-273.15", "maximum_value_warning": "300", "settable_per_mesh": false, @@ -2311,6 +2316,7 @@ "type": "float", "unit": "mm", "default_value": 50, + "enabled": false, "minimum_value_warning": "0", "maximum_value_warning": "100", "settable_per_mesh": false, @@ -2323,6 +2329,7 @@ "type": "float", "unit": "mm/s", "default_value": 25, + "enabled": false, "minimum_value": "0", "maximum_value": "machine_max_feedrate_e", "settable_per_mesh": false, @@ -2335,6 +2342,7 @@ "type": "float", "unit": "°C", "default_value": 50, + "enabled": false, "minimum_value": "-273.15", "maximum_value_warning": "300", "settable_per_mesh": false, From b9e4ce8d150bfec323d764be76f881e249084c07 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Jun 2019 17:06:41 +0200 Subject: [PATCH 04/18] Remove break preparation temperature This setting is not used in the deprime procedure. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index eebca3b87c..16b5ae270b 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2296,19 +2296,6 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_break_preparation_temperature": - { - "label": "Break Preparation Temperature", - "description": "The temperature at which the filament needs to be stretched towards breaking.", - "type": "float", - "unit": "°C", - "default_value": 200, - "enabled": false, - "minimum_value": "-273.15", - "maximum_value_warning": "300", - "settable_per_mesh": false, - "settable_per_extruder": true - }, "material_break_distance": { "label": "Break Retraction Distance", @@ -2317,7 +2304,7 @@ "unit": "mm", "default_value": 50, "enabled": false, - "minimum_value_warning": "0", + "minimum_value": "0", "maximum_value_warning": "100", "settable_per_mesh": false, "settable_per_extruder": true From a0c3738a49649f17d87a01e72731cadc84a6c038 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Jun 2019 17:07:59 +0200 Subject: [PATCH 05/18] Add translations for deprime settings These need to be read for the deprime experiments in the PPA. Contributes to issue CURA-6329. --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index f057585cb5..2fb23d53e8 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -1180,6 +1180,14 @@ class XmlMaterialProfile(InstanceContainer): "surface energy": "material_surface_energy", "shrinkage percentage": "material_shrinkage_percentage", "build volume temperature": "build_volume_temperature", + "anti ooze retract position": "material_anti_ooze_retraction_distance", + "anti ooze retract speed": "material_anti_ooze_retraction_speed", + "break preparation position": "material_break_preparation_distance", + "break preparation speed": "material_break_preparation_speed", + "break preparation temperature": "material_break_preparation_temperature", + "break position": "material_break_distance", + "break speed": "material_break_speed", + "break temperature": "material_break_temperature" } __unmapped_settings = [ "hardware compatible", From 36a206b418f3585689185426eefe0eb500926b77 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 4 Jun 2019 17:23:20 +0200 Subject: [PATCH 06/18] Also remove translation for break preparation temperature This setting is no longer used. If I don't remove it, it'll complain when syncing materials with the printer because it tries to serialise the material profiles then. Contributes to issue CURA-6329. --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 2fb23d53e8..7e99b0f725 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -1184,7 +1184,6 @@ class XmlMaterialProfile(InstanceContainer): "anti ooze retract speed": "material_anti_ooze_retraction_speed", "break preparation position": "material_break_preparation_distance", "break preparation speed": "material_break_preparation_speed", - "break preparation temperature": "material_break_preparation_temperature", "break position": "material_break_distance", "break speed": "material_break_speed", "break temperature": "material_break_temperature" From 27ea9c813e4313585af4146e62e70bdd5538deec Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 7 Jun 2019 13:57:56 +0200 Subject: [PATCH 07/18] Allow negative retraction distances You COULD want to extrude. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 16b5ae270b..3722aadfbf 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2252,7 +2252,7 @@ "unit": "mm", "default_value": 4, "enabled": false, - "minimum_value": "0", + "minimum_value_warning": "0", "maximum_value_warning": "retraction_amount", "settable_per_mesh": false, "settable_per_extruder": true @@ -2278,7 +2278,7 @@ "unit": "mm", "default_value": 16, "enabled": false, - "minimum_value": "0", + "minimum_value_warning": "0", "maximum_value_warning": "retraction_amount * 4", "settable_per_mesh": false, "settable_per_extruder": true @@ -2304,7 +2304,7 @@ "unit": "mm", "default_value": 50, "enabled": false, - "minimum_value": "0", + "minimum_value_warning": "0", "maximum_value_warning": "100", "settable_per_mesh": false, "settable_per_extruder": true From abda45ee59b7ddcff3271791ae09fbf8ba48cc9b Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Fri, 7 Jun 2019 16:26:19 +0200 Subject: [PATCH 08/18] Set crystalline to false by default Because PLA is not crystalline. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 3722aadfbf..bba2caedbb 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2239,7 +2239,7 @@ "label": "Crystalline Material", "description": "Is this material the type that breaks off cleanly when heated, or is it the type that produces long intertwined polymer chains?", "type": "bool", - "default_value": true, + "default_value": false, "enabled": false, "settable_per_mesh": false, "settable_per_extruder": true From 1ae8011cf7df0caedde2a6a7b10b407e2fb30b2f Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 12 Jun 2019 14:02:37 +0200 Subject: [PATCH 09/18] Clarify crystalline description (crystal clear?). [CURA-6329] --- resources/definitions/fdmprinter.def.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index bba2caedbb..4f99a5be5d 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2237,7 +2237,7 @@ "material_crystallinity": { "label": "Crystalline Material", - "description": "Is this material the type that breaks off cleanly when heated, or is it the type that produces long intertwined polymer chains?", + "description": "Is this material the type that breaks off cleanly when heated (crystalline), or is it the type that produces long intertwined polymer chains (non-crystalline)?", "type": "bool", "default_value": false, "enabled": false, From faf256b2f0326bd04933352becff9109faf82a11 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 26 Jun 2019 16:41:51 +0200 Subject: [PATCH 10/18] Rename deprime settings with the new name These have been renamed for greater clarity. We also have to rename them on this side now. Contributes to issue CURA-6329. --- plugins/XmlMaterialProfile/XmlMaterialProfile.py | 6 +++--- resources/definitions/fdmprinter.def.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/XmlMaterialProfile/XmlMaterialProfile.py b/plugins/XmlMaterialProfile/XmlMaterialProfile.py index 27201b8eed..241d1a954f 100644 --- a/plugins/XmlMaterialProfile/XmlMaterialProfile.py +++ b/plugins/XmlMaterialProfile/XmlMaterialProfile.py @@ -1196,11 +1196,11 @@ class XmlMaterialProfile(InstanceContainer): "surface energy": "material_surface_energy", "shrinkage percentage": "material_shrinkage_percentage", "build volume temperature": "build_volume_temperature", - "anti ooze retract position": "material_anti_ooze_retraction_distance", + "anti ooze retracted position": "material_anti_ooze_retracted_position", "anti ooze retract speed": "material_anti_ooze_retraction_speed", - "break preparation position": "material_break_preparation_distance", + "break preparation retracted position": "material_break_preparation_retracted_position", "break preparation speed": "material_break_preparation_speed", - "break position": "material_break_distance", + "break retracted position": "material_break_retracted_position", "break speed": "material_break_speed", "break temperature": "material_break_temperature" } diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index 0621c6e2d0..b013851cef 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2244,7 +2244,7 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_anti_ooze_retraction_distance": + "material_anti_ooze_retracted_position": { "label": "Anti-ooze Retraction Distance", "description": "How far the material needs to be retracted before it stops oozing.", @@ -2270,7 +2270,7 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_break_preparation_distance": + "material_break_preparation_retracted_position": { "label": "Break Preparation Retraction Distance", "description": "How far the filament can be stretched before it breaks, while heated.", @@ -2296,7 +2296,7 @@ "settable_per_mesh": false, "settable_per_extruder": true }, - "material_break_distance": + "material_break_retracted_position": { "label": "Break Retraction Distance", "description": "How far to retract the filament in order to break it cleanly.", From fe0fcc6eec6d5718b9479d0346673d9898874a70 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Wed, 26 Jun 2019 16:43:11 +0200 Subject: [PATCH 11/18] Change human-readable names of renamed settings too Forgot about those. Contributes to issue CURA-6329. --- resources/definitions/fdmprinter.def.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/definitions/fdmprinter.def.json b/resources/definitions/fdmprinter.def.json index b013851cef..dbdc9cc798 100644 --- a/resources/definitions/fdmprinter.def.json +++ b/resources/definitions/fdmprinter.def.json @@ -2246,7 +2246,7 @@ }, "material_anti_ooze_retracted_position": { - "label": "Anti-ooze Retraction Distance", + "label": "Anti-ooze Retracted Position", "description": "How far the material needs to be retracted before it stops oozing.", "type": "float", "unit": "mm", @@ -2272,7 +2272,7 @@ }, "material_break_preparation_retracted_position": { - "label": "Break Preparation Retraction Distance", + "label": "Break Preparation Retracted Position", "description": "How far the filament can be stretched before it breaks, while heated.", "type": "float", "unit": "mm", @@ -2298,7 +2298,7 @@ }, "material_break_retracted_position": { - "label": "Break Retraction Distance", + "label": "Break Retracted Position", "description": "How far to retract the filament in order to break it cleanly.", "type": "float", "unit": "mm", From efc6ef2905aa97c65590c8f64a9a30faf12d7e13 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 13:44:47 +0200 Subject: [PATCH 12/18] Add missing typing --- cura/BuildVolume.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index b21efc93f3..e8b077eae6 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -908,9 +908,12 @@ class BuildVolume(SceneNode): # for. # \return A dictionary with for each used extruder ID the disallowed areas # where that extruder may not print. - def _computeDisallowedAreasStatic(self, border_size, used_extruders): - #Convert disallowed areas to polygons and dilate them. + def _computeDisallowedAreasStatic(self, border_size:float, used_extruders: List["ExtruderStack"]) -> Dict[str, List[Polygon]]: + # Convert disallowed areas to polygons and dilate them. machine_disallowed_polygons = [] + if self._global_container_stack is None: + return {} + for area in self._global_container_stack.getProperty("machine_disallowed_areas", "value"): polygon = Polygon(numpy.array(area, numpy.float32)) polygon = polygon.getMinkowskiHull(Polygon.approximatedCircle(border_size)) @@ -921,7 +924,7 @@ class BuildVolume(SceneNode): nozzle_offsetting_for_disallowed_areas = self._global_container_stack.getMetaDataEntry( "nozzle_offsetting_for_disallowed_areas", True) - result = {} + result = {} # type: Dict[str, List[Polygon]] for extruder in used_extruders: extruder_id = extruder.getId() offset_x = extruder.getProperty("machine_nozzle_offset_x", "value") @@ -930,13 +933,13 @@ class BuildVolume(SceneNode): offset_y = extruder.getProperty("machine_nozzle_offset_y", "value") if offset_y is None: offset_y = 0 - offset_y = -offset_y #Y direction of g-code is the inverse of Y direction of Cura's scene space. + offset_y = -offset_y # Y direction of g-code is the inverse of Y direction of Cura's scene space. result[extruder_id] = [] for polygon in machine_disallowed_polygons: - result[extruder_id].append(polygon.translate(offset_x, offset_y)) #Compensate for the nozzle offset of this extruder. + result[extruder_id].append(polygon.translate(offset_x, offset_y)) # Compensate for the nozzle offset of this extruder. - #Add the border around the edge of the build volume. + # Add the border around the edge of the build volume. left_unreachable_border = 0 right_unreachable_border = 0 top_unreachable_border = 0 @@ -944,7 +947,8 @@ class BuildVolume(SceneNode): # Only do nozzle offsetting if needed if nozzle_offsetting_for_disallowed_areas: - #The build volume is defined as the union of the area that all extruders can reach, so we need to know the relative offset to all extruders. + # The build volume is defined as the union of the area that all extruders can reach, so we need to know + # the relative offset to all extruders. for other_extruder in ExtruderManager.getInstance().getActiveExtruderStacks(): other_offset_x = other_extruder.getProperty("machine_nozzle_offset_x", "value") if other_offset_x is None: @@ -1028,8 +1032,8 @@ class BuildVolume(SceneNode): [ half_machine_width - border_size, 0] ], numpy.float32))) result[extruder_id].append(Polygon(numpy.array([ - [ half_machine_width,-half_machine_depth], - [-half_machine_width,-half_machine_depth], + [ half_machine_width, -half_machine_depth], + [-half_machine_width, -half_machine_depth], [ 0, -half_machine_depth + border_size] ], numpy.float32))) From b240ede21c28c9bbd1090e69c9b4ed6fb6981c6f Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 13:45:05 +0200 Subject: [PATCH 13/18] Add test for computing the static disallowed areas --- tests/TestBuildVolume.py | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/TestBuildVolume.py b/tests/TestBuildVolume.py index 51a5f7e9e2..7095179a95 100644 --- a/tests/TestBuildVolume.py +++ b/tests/TestBuildVolume.py @@ -43,6 +43,50 @@ def test_buildGridMesh(build_volume): assert numpy.array_equal(result_vertices, mesh.getVertices()) +class TestComputeDisallowedAreasStatic: + setting_property_dict = {"machine_disallowed_areas": {"value": [[[-200, 112.5], [ -82, 112.5], [ -84, 102.5], [-115, 102.5]]]}, + "machine_width": {"value": 200}, + "machine_depth": {"value": 200}, + } + + def getPropertySideEffect(*args, **kwargs): + properties = TestComputeDisallowedAreasStatic.setting_property_dict.get(args[1]) + if properties: + return properties.get(args[2]) + + def test_computeDisallowedAreasStaticNoExtruder(self, build_volume: BuildVolume): + mocked_stack = MagicMock() + mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + + build_volume._global_container_stack = mocked_stack + assert build_volume._computeDisallowedAreasStatic(0, []) == {} + + def test_computeDisalowedAreasStaticSingleExtruder(self, build_volume: BuildVolume): + mocked_stack = MagicMock() + mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + + mocked_extruder = MagicMock() + mocked_extruder.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + mocked_extruder.getId = MagicMock(return_value = "zomg") + + build_volume._global_container_stack = mocked_stack + with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"): + result = build_volume._computeDisallowedAreasStatic(0, [mocked_extruder]) + assert result == {"zomg": [Polygon([[-84.0, 102.5], [-115.0, 102.5], [-200.0, 112.5], [-82.0, 112.5]])]} + + def test_computeDisalowedAreasMutliExtruder(self, build_volume): + mocked_stack = MagicMock() + mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + + mocked_extruder = MagicMock() + mocked_extruder.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + mocked_extruder.getId = MagicMock(return_value="zomg") + extruder_manager = MagicMock() + extruder_manager.getActiveExtruderStacks = MagicMock(return_value = [mocked_stack]) + build_volume._global_container_stack = mocked_stack + with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance", MagicMock(return_value = extruder_manager)): + result = build_volume._computeDisallowedAreasStatic(0, [mocked_extruder]) + assert result == {"zomg": [Polygon([[-84.0, 102.5], [-115.0, 102.5], [-200.0, 112.5], [-82.0, 112.5]])]} class TestUpdateRaftThickness: setting_property_dict = {"raft_base_thickness": {"value": 1}, From 47cc87ec471c607210d455e813e754b8f90ecac8 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 14:17:18 +0200 Subject: [PATCH 14/18] Add tests for calculating the bed adhesion size --- tests/TestBuildVolume.py | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/TestBuildVolume.py b/tests/TestBuildVolume.py index 7095179a95..902d8a839c 100644 --- a/tests/TestBuildVolume.py +++ b/tests/TestBuildVolume.py @@ -43,6 +43,65 @@ def test_buildGridMesh(build_volume): assert numpy.array_equal(result_vertices, mesh.getVertices()) +def test_clamp(build_volume): + assert build_volume._clamp(0, 0, 200) == 0 + assert build_volume._clamp(0, -200, 200) == 0 + assert build_volume._clamp(300, -200, 200) == 200 + + +class TestCalculateBedAdhesionSize: + setting_property_dict = {"adhesion_type": {"value": "brim"}, + "skirt_brim_line_width": {"value": 0}, + "initial_layer_line_width_factor": {"value": 0}, + "brim_line_count": {"value": 0}, + "machine_width": {"value": 200}, + "machine_depth": {"value": 200}, + "skirt_line_count": {"value": 0}, + "skirt_gap": {"value": 0}, + "raft_margin": {"value": 0} + } + + def getPropertySideEffect(*args, **kwargs): + properties = TestCalculateBedAdhesionSize.setting_property_dict.get(args[1]) + if properties: + return properties.get(args[2]) + + def createAndSetGlobalStack(self, build_volume): + mocked_stack = MagicMock() + mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect) + + build_volume._global_container_stack = mocked_stack + + def test_noGlobalStack(self, build_volume: BuildVolume): + assert build_volume._calculateBedAdhesionSize([]) is None + + @pytest.mark.parametrize("setting_dict, result", [ + ({}, 0), + ({"adhesion_type": {"value": "skirt"}}, 0), + ({"adhesion_type": {"value": "raft"}}, 0), + ({"adhesion_type": {"value": "none"}}, 0), + ({"adhesion_type": {"value": "skirt"}, "skirt_line_count": {"value": 2}, "initial_layer_line_width_factor": {"value": 1}, "skirt_brim_line_width": {"value": 2}}, 0.02), + # Even though it's marked as skirt, it should behave as a brim as the prime tower has a brim (skirt line count is still at 0!) + ({"adhesion_type": {"value": "skirt"}, "prime_tower_brim_enable": {"value": True}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, -0.06), + ({"brim_line_count": {"value": 1}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, 0), + ({"brim_line_count": {"value": 2}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, 0.06), + ({"brim_line_count": {"value": 9000000}, "skirt_brim_line_width": {"value": 90000}, "initial_layer_line_width_factor": {"value": 9000}}, 100), # Clamped at half the max size of buildplate + ]) + def test_singleExtruder(self, build_volume: BuildVolume, setting_dict, result): + self.createAndSetGlobalStack(build_volume) + patched_dictionary = self.setting_property_dict.copy() + patched_dictionary.update(setting_dict) + with patch.dict(self.setting_property_dict, patched_dictionary): + assert build_volume._calculateBedAdhesionSize([]) == result + + def test_unknownBedAdhesion(self, build_volume: BuildVolume): + self.createAndSetGlobalStack(build_volume) + patched_dictionary = self.setting_property_dict.copy() + patched_dictionary.update({"adhesion_type": {"value": "OMGZOMGBBQ"}}) + with patch.dict(self.setting_property_dict, patched_dictionary): + with pytest.raises(Exception): + build_volume._calculateBedAdhesionSize([]) + class TestComputeDisallowedAreasStatic: setting_property_dict = {"machine_disallowed_areas": {"value": [[[-200, 112.5], [ -82, 112.5], [ -84, 102.5], [-115, 102.5]]]}, "machine_width": {"value": 200}, From 2133fc78e041bf6080824609ccd664d2f398fa79 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 15:01:09 +0200 Subject: [PATCH 15/18] Remove unused code --- cura/BuildVolume.py | 42 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index e8b077eae6..c89768b122 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -738,37 +738,14 @@ class BuildVolume(SceneNode): else: used_extruders = [self._global_container_stack] - result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added. + result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) # Normal machine disallowed areas can always be added. prime_areas = self._computeDisallowedAreasPrimeBlob(disallowed_border_size, used_extruders) - result_areas_no_brim = self._computeDisallowedAreasStatic(0, used_extruders) #Where the priming is not allowed to happen. This is not added to the result, just for collision checking. - prime_disallowed_areas = copy.deepcopy(result_areas_no_brim) + result_areas_no_brim = self._computeDisallowedAreasStatic(0, used_extruders) # Where the priming is not allowed to happen. This is not added to the result, just for collision checking. - #Check if prime positions intersect with disallowed areas. + # Check if prime positions intersect with disallowed areas. for extruder in used_extruders: extruder_id = extruder.getId() - collision = False - for prime_polygon in prime_areas[extruder_id]: - for disallowed_polygon in prime_disallowed_areas[extruder_id]: - if prime_polygon.intersectsPolygon(disallowed_polygon) is not None: - collision = True - break - if collision: - break - - #Also check other prime positions (without additional offset). - for other_extruder_id in prime_areas: - if extruder_id == other_extruder_id: #It is allowed to collide with itself. - continue - for other_prime_polygon in prime_areas[other_extruder_id]: - if prime_polygon.intersectsPolygon(other_prime_polygon): - collision = True - break - if collision: - break - if collision: - break - result_areas[extruder_id].extend(prime_areas[extruder_id]) result_areas_no_brim[extruder_id].extend(prime_areas[extruder_id]) @@ -776,14 +753,13 @@ class BuildVolume(SceneNode): for area in nozzle_disallowed_areas: polygon = Polygon(numpy.array(area, numpy.float32)) polygon_disallowed_border = polygon.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size)) - result_areas[extruder_id].append(polygon_disallowed_border) #Don't perform the offset on these. - #polygon_minimal_border = polygon.getMinkowskiHull(5) - result_areas_no_brim[extruder_id].append(polygon) # no brim + result_areas[extruder_id].append(polygon_disallowed_border) # Don't perform the offset on these. + result_areas_no_brim[extruder_id].append(polygon) # No brim # Add prime tower location as disallowed area. - if len(used_extruders) > 1: #No prime tower in single-extrusion. + if len(used_extruders) > 1: # No prime tower in single-extrusion. - if len([x for x in used_extruders if x.isEnabled]) > 1: #No prime tower if only one extruder is enabled + if len([x for x in used_extruders if x.isEnabled]) > 1: # No prime tower if only one extruder is enabled prime_tower_collision = False prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders) for extruder_id in prime_tower_areas: @@ -792,7 +768,7 @@ class BuildVolume(SceneNode): if prime_tower_area.intersectsPolygon(area) is not None: prime_tower_collision = True break - if prime_tower_collision: #Already found a collision. + if prime_tower_collision: # Already found a collision. break if (ExtruderManager.getInstance().getResolveOrValue("prime_tower_brim_enable") and ExtruderManager.getInstance().getResolveOrValue("adhesion_type") != "raft"): @@ -806,7 +782,7 @@ class BuildVolume(SceneNode): self._has_errors = len(self._error_areas) > 0 - self._disallowed_areas = [] + self._disallowed_areas = [] # type: List[Polygon] for extruder_id in result_areas: self._disallowed_areas.extend(result_areas[extruder_id]) self._disallowed_areas_no_brim = [] From f329d7aed90d86e663dc3cce69d029b4f8e105de Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 15:08:46 +0200 Subject: [PATCH 16/18] Made typing hint a bit more specific --- cura/Settings/ExtruderManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index 53c0a54f85..7674aa05b9 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -205,7 +205,7 @@ class ExtruderManager(QObject): # list. # # \return A list of extruder stacks. - def getUsedExtruderStacks(self) -> List["ContainerStack"]: + def getUsedExtruderStacks(self) -> List["ExtruderStack"]: global_stack = self._application.getGlobalContainerStack() container_registry = ContainerRegistry.getInstance() From 691d10671917e39314ff0ec061c4febabc74c434 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 15:09:08 +0200 Subject: [PATCH 17/18] Remove old unused code --- cura/BuildVolume.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index c89768b122..ce7a5461bc 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -727,17 +727,9 @@ class BuildVolume(SceneNode): self._error_areas = [] - extruder_manager = ExtruderManager.getInstance() - used_extruders = extruder_manager.getUsedExtruderStacks() + used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks() disallowed_border_size = self.getEdgeDisallowedSize() - if not used_extruders: - # If no extruder is used, assume that the active extruder is used (else nothing is drawn) - if extruder_manager.getActiveExtruderStack(): - used_extruders = [extruder_manager.getActiveExtruderStack()] - else: - used_extruders = [self._global_container_stack] - result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) # Normal machine disallowed areas can always be added. prime_areas = self._computeDisallowedAreasPrimeBlob(disallowed_border_size, used_extruders) result_areas_no_brim = self._computeDisallowedAreasStatic(0, used_extruders) # Where the priming is not allowed to happen. This is not added to the result, just for collision checking. From 6136f5a2f2586da4b5d232b125032219471af42a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Fri, 28 Jun 2019 15:22:58 +0200 Subject: [PATCH 18/18] Further simplify the build volume code --- cura/BuildVolume.py | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index ce7a5461bc..3358fe8b85 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -749,28 +749,24 @@ class BuildVolume(SceneNode): result_areas_no_brim[extruder_id].append(polygon) # No brim # Add prime tower location as disallowed area. - if len(used_extruders) > 1: # No prime tower in single-extrusion. - - if len([x for x in used_extruders if x.isEnabled]) > 1: # No prime tower if only one extruder is enabled - prime_tower_collision = False - prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders) - for extruder_id in prime_tower_areas: - for i_area, prime_tower_area in enumerate(prime_tower_areas[extruder_id]): - for area in result_areas[extruder_id]: - if prime_tower_area.intersectsPolygon(area) is not None: - prime_tower_collision = True - break - if prime_tower_collision: # Already found a collision. + if len([x for x in used_extruders if x.isEnabled]) > 1: # No prime tower if only one extruder is enabled + prime_tower_collision = False + prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders) + for extruder_id in prime_tower_areas: + for area_index, prime_tower_area in enumerate(prime_tower_areas[extruder_id]): + for area in result_areas[extruder_id]: + if prime_tower_area.intersectsPolygon(area) is not None: + prime_tower_collision = True break - if (ExtruderManager.getInstance().getResolveOrValue("prime_tower_brim_enable") and - ExtruderManager.getInstance().getResolveOrValue("adhesion_type") != "raft"): - prime_tower_areas[extruder_id][i_area] = prime_tower_area.getMinkowskiHull( - Polygon.approximatedCircle(disallowed_border_size)) - if not prime_tower_collision: - result_areas[extruder_id].extend(prime_tower_areas[extruder_id]) - result_areas_no_brim[extruder_id].extend(prime_tower_areas[extruder_id]) - else: - self._error_areas.extend(prime_tower_areas[extruder_id]) + if prime_tower_collision: # Already found a collision. + break + if self._global_container_stack.getProperty("prime_tower_brim_enable", "value") and self._global_container_stack.getProperty("adhesion_type", "value") != "raft": + prime_tower_areas[extruder_id][area_index] = prime_tower_area.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size)) + if not prime_tower_collision: + result_areas[extruder_id].extend(prime_tower_areas[extruder_id]) + result_areas_no_brim[extruder_id].extend(prime_tower_areas[extruder_id]) + else: + self._error_areas.extend(prime_tower_areas[extruder_id]) self._has_errors = len(self._error_areas) > 0 @@ -794,8 +790,8 @@ class BuildVolume(SceneNode): for extruder in used_extruders: result[extruder.getId()] = [] - #Currently, the only normally printed object is the prime tower. - if ExtruderManager.getInstance().getResolveOrValue("prime_tower_enable"): + # Currently, the only normally printed object is the prime tower. + if self._global_container_stack.getProperty("prime_tower_enable"): 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") @@ -805,8 +801,7 @@ 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 (ExtruderManager.getInstance().getResolveOrValue("prime_tower_brim_enable") and - ExtruderManager.getInstance().getResolveOrValue("adhesion_type") != "raft"): + if 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 *