diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 48d2436482..d494a79327 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -40,7 +40,7 @@ class ArrangeObjectsJob(Job): found_solution_for_all = False try: - found_solution_for_all = arranger.arrange() + found_solution_for_all = arranger.arrange(only_if_full_success = True) except: # If the thread crashes, the message should still close Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") diff --git a/cura/Arranging/Arranger.py b/cura/Arranging/Arranger.py index fd93ab1846..d0a78431f6 100644 --- a/cura/Arranging/Arranger.py +++ b/cura/Arranging/Arranger.py @@ -16,12 +16,16 @@ class Arranger: """ raise NotImplementedError - def arrange(self, add_new_nodes_in_scene: bool = False) -> bool: + def arrange(self, add_new_nodes_in_scene: bool = False, only_if_full_success: bool = False) -> bool: """ Find placement for a set of scene nodes, and move them by using a single grouped operation. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects """ grouped_operation, not_fit_count = self.createGroupOperationForArrange(add_new_nodes_in_scene) - grouped_operation.push() - return not_fit_count == 0 + full_success = not_fit_count == 0 + + if full_success or not only_if_full_success: + grouped_operation.push() + + return full_success diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index 968522d5a3..5f34cb21a0 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -54,22 +54,6 @@ class Nest2DArrange(Arranger): machine_depth = self._build_volume.getDepth() - (edge_disallowed_size * 2) build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor)) - if self._fixed_nodes is None: - self._fixed_nodes = [] - - # Add all the items we want to arrange - node_items = [] - for node in self._nodes_to_arrange: - hull_polygon = node.callDecoration("getConvexHull") - if not hull_polygon or hull_polygon.getPoints is None: - Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName())) - continue - converted_points = [] - for point in hull_polygon.getPoints(): - converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) - item = Item(converted_points) - node_items.append(item) - # Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas) half_machine_width = 0.5 * machine_width - 1 half_machine_depth = 0.5 * machine_depth - 1 @@ -80,40 +64,66 @@ class Nest2DArrange(Arranger): [half_machine_width, half_machine_depth] ], numpy.float32)) - disallowed_areas = self._build_volume.getDisallowedAreas() - for area in disallowed_areas: - converted_points = [] + def _convert_points(points): + if points is not None and len(points) > 2: # numpy array has to be explicitly checked against None + converted_points = [] + for point in points: + converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) + return [converted_points] + else: + return [] + polygons_nodes_to_arrange = [] + for node in self._nodes_to_arrange: + hull_polygon = node.callDecoration("getConvexHull") + if not hull_polygon or hull_polygon.getPoints is None: + Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName())) + continue + + polygons_nodes_to_arrange += _convert_points(hull_polygon.getPoints()) + + polygons_disallowed_areas = [] + for area in self._build_volume.getDisallowedAreas(): # Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise) clipped_area = area.intersectionConvexHulls(build_plate_polygon) - if clipped_area.getPoints() is not None and len( - clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None - for point in clipped_area.getPoints(): - converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) + polygons_disallowed_areas += _convert_points(clipped_area.getPoints()) - disallowed_area = Item(converted_points) + polygons_fixed_nodes = [] + if self._fixed_nodes is None: + self._fixed_nodes = [] + for node in self._fixed_nodes: + hull_polygon = node.callDecoration("getConvexHull") + + if hull_polygon is not None: + polygons_fixed_nodes += _convert_points(hull_polygon.getPoints()) + + strategies = [NfpConfig.Alignment.CENTER, + NfpConfig.Alignment.BOTTOM_LEFT, + NfpConfig.Alignment.BOTTOM_RIGHT, + NfpConfig.Alignment.TOP_LEFT, + NfpConfig.Alignment.TOP_RIGHT] + found_solution_for_all = False + while not found_solution_for_all and len(strategies) > 0: + + # Add all the items we want to arrange + node_items = [] + for polygon in polygons_nodes_to_arrange: + node_items.append(Item(polygon)) + + for polygon in polygons_disallowed_areas: + disallowed_area = Item(polygon) disallowed_area.markAsDisallowedAreaInBin(0) node_items.append(disallowed_area) - for node in self._fixed_nodes: - converted_points = [] - hull_polygon = node.callDecoration("getConvexHull") - - if hull_polygon is not None and hull_polygon.getPoints() is not None and len( - hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None - for point in hull_polygon.getPoints(): - converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) - item = Item(converted_points) + for polygon in polygons_fixed_nodes: + item = Item(polygon) item.markAsFixedInBin(0) node_items.append(item) - strategies = [NfpConfig.Alignment.CENTER] * 3 + [NfpConfig.Alignment.BOTTOM_LEFT] * 3 - found_solution_for_all = False - while not found_solution_for_all and len(strategies) > 0: config = NfpConfig() config.accuracy = 1.0 - config.alignment = NfpConfig.Alignment.CENTER + config.alignment = NfpConfig.Alignment.DONT_ALIGN config.starting_point = strategies[0] strategies = strategies[1:] diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 889b6f5d1a..024baa50f5 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -84,6 +84,7 @@ class MultiplyObjectsJob(Job): arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000) group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True) + found_solution_for_all = not_fit_count == 0 if nodes_to_add_without_arrange: for nested_node in nodes_to_add_without_arrange: diff --git a/cura/UI/PrintInformation.py b/cura/UI/PrintInformation.py index 936e646946..6826c34e43 100644 --- a/cura/UI/PrintInformation.py +++ b/cura/UI/PrintInformation.py @@ -449,6 +449,6 @@ class PrintInformation(QObject): """If this is a sort of output 'device' (like local or online file storage, rather than a printer), the user could have altered the file-name, and thus the project name should be altered as well.""" if isinstance(output_device, ProjectOutputDevice): - new_name = output_device.getLastOutputName() + new_name = output_device.popLastOutputName() if new_name is not None: self.setJobName(os.path.splitext(os.path.basename(new_name))[0]) diff --git a/plugins/SimulationView/SimulationPass.py b/plugins/SimulationView/SimulationPass.py index 080b02bd9e..436d5b8723 100644 --- a/plugins/SimulationView/SimulationPass.py +++ b/plugins/SimulationView/SimulationPass.py @@ -67,39 +67,40 @@ class SimulationPass(RenderPass): if not self._compatibility_mode: self._layer_shader.setUniformValue("u_starts_color", Color(*Application.getInstance().getTheme().getColor("layerview_starts").getRgb())) - if self._layer_view: - self._layer_shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate()) - self._layer_shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate()) - self._layer_shader.setUniformValue("u_max_thickness", self._layer_view.getMaxThickness()) - self._layer_shader.setUniformValue("u_min_thickness", self._layer_view.getMinThickness()) - self._layer_shader.setUniformValue("u_max_line_width", self._layer_view.getMaxLineWidth()) - self._layer_shader.setUniformValue("u_min_line_width", self._layer_view.getMinLineWidth()) - self._layer_shader.setUniformValue("u_max_flow_rate", self._layer_view.getMaxFlowRate()) - self._layer_shader.setUniformValue("u_min_flow_rate", self._layer_view.getMinFlowRate()) - self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getSimulationViewType()) - self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities()) - self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves()) - self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers()) - self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) - self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill()) - self._layer_shader.setUniformValue("u_show_starts", self._layer_view.getShowStarts()) - else: - #defaults - self._layer_shader.setUniformValue("u_max_feedrate", 1) - self._layer_shader.setUniformValue("u_min_feedrate", 0) - self._layer_shader.setUniformValue("u_max_thickness", 1) - self._layer_shader.setUniformValue("u_min_thickness", 0) - self._layer_shader.setUniformValue("u_max_flow_rate", 1) - self._layer_shader.setUniformValue("u_min_flow_rate", 0) - self._layer_shader.setUniformValue("u_max_line_width", 1) - self._layer_shader.setUniformValue("u_min_line_width", 0) - self._layer_shader.setUniformValue("u_layer_view_type", 1) - self._layer_shader.setUniformValue("u_extruder_opacity", [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) - self._layer_shader.setUniformValue("u_show_travel_moves", 0) - self._layer_shader.setUniformValue("u_show_helpers", 1) - self._layer_shader.setUniformValue("u_show_skin", 1) - self._layer_shader.setUniformValue("u_show_infill", 1) - self._layer_shader.setUniformValue("u_show_starts", 1) + for shader in [self._layer_shader, self._layer_shadow_shader]: + if self._layer_view: + shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate()) + shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate()) + shader.setUniformValue("u_max_thickness", self._layer_view.getMaxThickness()) + shader.setUniformValue("u_min_thickness", self._layer_view.getMinThickness()) + shader.setUniformValue("u_max_line_width", self._layer_view.getMaxLineWidth()) + shader.setUniformValue("u_min_line_width", self._layer_view.getMinLineWidth()) + shader.setUniformValue("u_max_flow_rate", self._layer_view.getMaxFlowRate()) + shader.setUniformValue("u_min_flow_rate", self._layer_view.getMinFlowRate()) + shader.setUniformValue("u_layer_view_type", self._layer_view.getSimulationViewType()) + shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities()) + shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves()) + shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers()) + shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin()) + shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill()) + shader.setUniformValue("u_show_starts", self._layer_view.getShowStarts()) + else: + #defaults + shader.setUniformValue("u_max_feedrate", 1) + shader.setUniformValue("u_min_feedrate", 0) + shader.setUniformValue("u_max_thickness", 1) + shader.setUniformValue("u_min_thickness", 0) + shader.setUniformValue("u_max_flow_rate", 1) + shader.setUniformValue("u_min_flow_rate", 0) + shader.setUniformValue("u_max_line_width", 1) + shader.setUniformValue("u_min_line_width", 0) + shader.setUniformValue("u_layer_view_type", 1) + shader.setUniformValue("u_extruder_opacity", [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) + shader.setUniformValue("u_show_travel_moves", 0) + shader.setUniformValue("u_show_helpers", 1) + shader.setUniformValue("u_show_skin", 1) + shader.setUniformValue("u_show_infill", 1) + shader.setUniformValue("u_show_starts", 1) if not self._tool_handle_shader: self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader")) diff --git a/resources/definitions/ultimaker_s8.def.json b/resources/definitions/ultimaker_s8.def.json index cc9c97aebd..fd758f6e2a 100644 --- a/resources/definitions/ultimaker_s8.def.json +++ b/resources/definitions/ultimaker_s8.def.json @@ -92,10 +92,10 @@ "cool_min_temperature": { "value": "material_print_temperature-15" }, "default_material_print_temperature": { "maximum_value_warning": 320 }, "extra_infill_lines_to_support_skins": { "value": "'walls_and_lines'" }, - "flooring_layer_count": { "value": "1" }, + "flooring_layer_count": { "value": 0 }, "gradual_flow_enabled": { "value": false }, "hole_xy_offset": { "value": 0.075 }, - "infill_material_flow": { "value": "1.1*material_flow" }, + "infill_material_flow": { "value": "material_flow" }, "infill_overlap": { "value": 10 }, "infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'grid'" }, "infill_sparse_density": { "value": 15 }, @@ -374,7 +374,7 @@ "speed_travel": { "maximum_value": 500, - "value": 500 + "value": 400 }, "speed_travel_layer_0": { @@ -427,7 +427,6 @@ "support_tree_bp_diameter": { "value": 15 }, "support_tree_tip_diameter": { "value": 1.0 }, "support_tree_top_rate": { "value": 20 }, - "support_wall_count": { "value": 2 }, "support_xy_distance_overhang": { "value": "machine_nozzle_size" }, "support_z_distance": { "value": "0.4*material_shrinkage_percentage_z/100.0" }, "top_bottom_thickness": { "value": "round(4*layer_height, 2)" }, diff --git a/resources/definitions/ultimaker_sketch_sprint.def.json b/resources/definitions/ultimaker_sketch_sprint.def.json index d0991231bc..529abc0940 100644 --- a/resources/definitions/ultimaker_sketch_sprint.def.json +++ b/resources/definitions/ultimaker_sketch_sprint.def.json @@ -397,8 +397,6 @@ "z_seam_corner": { "value": "'z_seam_corner_inner'" }, "z_seam_position": { "value": "'backleft'" }, "z_seam_type": { "value": "'sharpest_corner'" }, - "z_seam_x": { "value": 150 }, - "z_seam_y": { "value": 180 }, "zig_zaggify_infill": { "value": true } } } \ No newline at end of file diff --git a/resources/texts/change_log.txt b/resources/texts/change_log.txt index 97c2da39b0..9f0a2c563a 100644 --- a/resources/texts/change_log.txt +++ b/resources/texts/change_log.txt @@ -1,3 +1,64 @@ +[5.10] + +* New features and improvements: +- UltiMaker S8 Support: Added compatibility for the UltiMaker S8 printer. +- Cheetah Gcode Flavor: Introduced a new Marlin-like Gcode flavor called Cheetah. +- SpaceMouse support: Navigate the view seamlessly with a 3D mouse, thanks to a collaboration with 3Dconnexion. +- Cloud Printing for Sketch Sprint: Enabled printing over cloud with Digital Factory for Sketch Sprint users. +- Interlocking Settings: Moved Interlocking settings out of experimental into expert +- Build System Upgrade: Upgraded the build system from Conan 1 to Conan 2. Updated documentation is available. +- Preview Looping: When the last layer is played in the preview, the first layer will now play again instead of stopping. +- Updated About Page: The About Page now shows the used sources, their licenses, and their versions in a clearer way +- Flip Y-axis Translate Tool Handle: Added an option to flip the Y-axis translate tool handle in preferences contributed by @GregValiant. +- Rotation by Input & Snap Angle Input: Introduced rotation by input & snap angle input contributed by @HellAholic and @GregValiant. +- Purge Lines And Unload Filament Post Processing Script: Added a Purge Lines and Unload Filament Post Processing Script contributed by @GregValiant and @HellAholic +- Thingiverse "Open in Cura" Button Linux Support: Enabled the "Open in Cura" button from Thingiverse to open files in Linux contributed by @hadess. +- Multitool Printer Configuration Options: Introduced 3 new configuration options in machine settings for multitool printers contributed by @TheSin-. +- Search and Replace Post-Processing Plug-In: Significantly improved the Search and Replace post-processing plug-in with features like replacing only the first instance, limiting search to a layer range, and ignoring start-up or ending G-code contributed by @GregValiant +- Enabled Relative extrusion (M82 and M83 commands) for Marlin-flavored GCode, contributed by @EmJay276 + + +* New settings: +- Overhanging Wall Speeds, now gives you the ability to tune multiple values. Don’t forget to adjust the Overhanging Wall Angle to start using the setting. +- Minimum Layer Time with Overhang and Minimum Overhang Segment Length: Fine-tune the minimum layer time for overhangs. +- Inside Travel Avoid Distance: Finetune combing movements. +- Pressure Advance Factor Setting: New setting for machine definitions. +- You can now tune the Bottom Surface Skin, like you can tune the Top Surface Skin! You can now tune Extruder, Layers, Line Width, Pattern, Line Directions, Outer Wall Flow, Inner Wall(s) Flow, Flow, Outer Wall Speed, Inner Wall Speed, Skin Speed, Inner Wall Acceleration, Skin Acceleration, Outer Wall Jerk, Inner Wall Jerk, Skin Jerk, and Monotonic Bottom Surface Order +- Enable/Disable USB Printing: A hidden preference setting to indicate that you are using the printer over USB functionality. This setting lays the groundwork for automatically disabling USB printing in the next release when it’s not being used. + +* Bug fixes: +- Resolved a crash that occurred when switching materials on Sovol printers. +- Random Seam no longer favors one side and not is truly random again +- Reduced the slicing time when no support needs to be generated +- Fixed a bug where Seam on Vertex with a User Defined seam position was not working correctly. +- Gcode replacement with a single line of code no longer produces values in separate lines +- Setting names that become too long after translation are now truncated. +- Updated UltiMaker printer logos to align with the current style. +- The number of decimal places displayed for layer height in the top bar has been reduced. +- Fixed a bug that caused incorrect retracting and hopping on printers with more than 2 extruders. +- Improved how fast the settings are loaded in the Settings Visibility window when scrolling +- Improved how disallowed areas and other models are taken into account when arranging models on the buildplate +- Preview playback now only shows visible parts. Infill lines, shell, and helpers are always hidden if disabled in preview's color scheme + +* Printer definitions, profiles, and materials: +- Introduced Visual Intents for the Sketch Sprint +- Introduced new Extra Fast and Draft profiles for the Sketch Sprint +- Introduced profiles for Sketch printers for Metallic PLA with improved surface quality (matte vs shiny) +- Introduce High Speed and High Speed Solid intents for Method, Method X, and Method XL +- Introduced PC ABS and PC ABS FR materials for Method X and Method XL +- Introduced Nylon Slide for UltiMaker S Series Printers +- Updated the Breakaway Build Volume Temperature for UltiMaker Factor 4 +- Introduced Makerbot Replicator + +- Updated Voron2 printers to include TPU ASA and PVA, contributed by @WCEngineer +- Enabled Relative extrusion (M82 and M83 commands) for Marlin-flavored GCode, contributed by @EmJay276 + +Cura 5.10 supports macOS 12 Monterey or higher. This is because the tools that we use to create Cura builds no longer support previous versions of macOS. + +[5.9.1] + +* New features and improvements: +The About Page now shows some of the used sources, their licenses, and their versions in a clearer way. This will be even more complete in Cura 5.10. + [5.9] * New features and improvements: