diff --git a/MatterControl.Printing/Settings/IObjectSlicer.cs b/MatterControl.Printing/Settings/IObjectSlicer.cs index 005bc0f0d..c8ad6f4f7 100644 --- a/MatterControl.Printing/Settings/IObjectSlicer.cs +++ b/MatterControl.Printing/Settings/IObjectSlicer.cs @@ -36,12 +36,20 @@ using MatterHackers.DataConverters3D; namespace MatterHackers.MatterControl.SlicerConfiguration { + public enum PrinterType + { + FFF, + SLA + } + public interface IObjectSlicer { Task Slice(IEnumerable itemsOnBed, PrinterSettings printerSettings, string filePath, IProgress progressReporter, CancellationToken cancellationToken); Dictionary Exports { get; } + PrinterType PrinterType { get; } + bool ValidateFile(string filePath); } } diff --git a/MatterControl.Printing/Settings/PrinterSettings.cs b/MatterControl.Printing/Settings/PrinterSettings.cs index a4fdc0e0e..b2ca5e6c6 100644 --- a/MatterControl.Printing/Settings/PrinterSettings.cs +++ b/MatterControl.Printing/Settings/PrinterSettings.cs @@ -88,7 +88,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration /// in this list ensures they show up for all slice engines and the lack of a MappedSetting for the engine guarantees that it won't pass /// through into the slicer config file. /// - public static readonly HashSet ApplicationLevelSettings = new HashSet() + public static readonly HashSet DefaultFFFSettings = new HashSet() { SettingsKey.auto_connect, SettingsKey.auto_release_motors, @@ -182,7 +182,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.selector_ip_address, SettingsKey.send_with_checksum, SettingsKey.show_reset_connection, - SettingsKey.sla_printer, SettingsKey.slice_engine, SettingsKey.solid_shell, SettingsKey.t0_inset, @@ -826,7 +825,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public bool IsActive(string canonicalSettingsName) { return this.Slicer.Exports.ContainsKey(canonicalSettingsName) - || PrinterSettings.ApplicationLevelSettings.Contains(canonicalSettingsName); + || (this.Slicer.PrinterType == PrinterType.FFF && PrinterSettings.DefaultFFFSettings.Contains(canonicalSettingsName)); } public bool IsOverride(string sliceSetting, IEnumerable layers) diff --git a/MatterControl.Printing/Settings/SettingsKey.cs b/MatterControl.Printing/Settings/SettingsKey.cs index c695c3ff9..c0b65f57e 100644 --- a/MatterControl.Printing/Settings/SettingsKey.cs +++ b/MatterControl.Printing/Settings/SettingsKey.cs @@ -66,8 +66,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string cool_extruder_lift = nameof(cool_extruder_lift); public const string cooling = nameof(cooling); public const string create_brim = nameof(create_brim); - public const string create_per_layer_support = nameof(create_per_layer_support); public const string create_per_layer_internal_support = nameof(create_per_layer_internal_support); + public const string create_per_layer_support = nameof(create_per_layer_support); public const string create_raft = nameof(create_raft); public const string create_skirt = nameof(create_skirt); public const string created_date = nameof(created_date); @@ -101,9 +101,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string filament_diameter = nameof(filament_diameter); public const string filament_has_been_loaded = nameof(filament_has_been_loaded); public const string filament_runout_sensor = nameof(filament_runout_sensor); - public const string runout_sensor_check_distance = nameof(runout_sensor_check_distance); - public const string runout_sensor_trigger_ratio = nameof(runout_sensor_trigger_ratio); - public const string report_runout_sensor_data = nameof(report_runout_sensor_data); public const string fill_angle = nameof(fill_angle); public const string fill_density = nameof(fill_density); public const string fill_pattern = nameof(fill_pattern); @@ -200,8 +197,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string recover_position_before_z_home = nameof(recover_position_before_z_home); public const string repair_outlines_extensive_stitching = nameof(repair_outlines_extensive_stitching); public const string repair_outlines_keep_open = nameof(repair_outlines_keep_open); + public const string report_runout_sensor_data = nameof(report_runout_sensor_data); public const string reset_long_extrusion = nameof(reset_long_extrusion); - public const string resolution = nameof(resolution); + public const string resin_cost = nameof(resin_cost); + public const string resin_density = nameof(resin_density); public const string resume_gcode = nameof(resume_gcode); public const string retract_before_travel = nameof(retract_before_travel); public const string retract_before_travel_avoid = nameof(retract_before_travel_avoid); @@ -215,6 +214,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string retract_when_changing_islands = nameof(retract_when_changing_islands); public const string running_clean_1_markdown = nameof(running_clean_1_markdown); public const string running_clean_markdown2 = nameof(running_clean_markdown2); + public const string runout_sensor_check_distance = nameof(runout_sensor_check_distance); + public const string runout_sensor_trigger_ratio = nameof(runout_sensor_trigger_ratio); public const string seconds_to_reheat = nameof(seconds_to_reheat); public const string selector_ip_address = nameof(selector_ip_address); public const string send_with_checksum = nameof(send_with_checksum); @@ -222,7 +223,23 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string skirt_distance = nameof(skirt_distance); public const string skirt_height = nameof(skirt_height); public const string skirts = nameof(skirts); - public const string sla_printer = nameof(sla_printer); + public const string sla_auto_support = nameof(sla_auto_support); + public const string sla_base_exposure_time = nameof(sla_base_exposure_time); + public const string sla_base_min_off_time = nameof(sla_base_min_off_time); + public const string sla_min_off_time = nameof(sla_min_off_time); + public const string sla_mirror_mode = nameof(sla_mirror_mode); + public const string sla_base_layers = nameof(sla_base_layers); + public const string sla_base_lift_distance = nameof(sla_base_lift_distance); + public const string sla_lift_distance = nameof(sla_lift_distance); + public const string sla_base_lift_speed = nameof(sla_base_lift_speed); + public const string sla_lift_speed = nameof(sla_lift_speed); + public const string sla_decend_speed = nameof(sla_decend_speed); + public const string sla_create_raft = nameof(sla_create_raft); + public const string sla_exposure_time = nameof(sla_exposure_time); + public const string sla_layer_height = nameof(sla_layer_height); + public const string sla_printable_area_inset = nameof(sla_printable_area_inset); + public const string sla_resolution = nameof(sla_resolution); + public const string slice_engine = nameof(slice_engine); public const string slowdown_below_layer_time = nameof(slowdown_below_layer_time); public const string small_perimeter_speed = nameof(small_perimeter_speed); public const string solid_fill_pattern = nameof(solid_fill_pattern); @@ -246,7 +263,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string support_material_xy_distance = nameof(support_material_xy_distance); public const string support_percent = nameof(support_percent); public const string support_type = nameof(support_type); + public const string t0_inset = nameof(t0_inset); public const string t1_extrusion_move_speed_multiplier = nameof(t1_extrusion_move_speed_multiplier); + public const string t1_inset = nameof(t1_inset); public const string temperature = nameof(temperature); public const string temperature1 = nameof(temperature1); public const string temperature2 = nameof(temperature2); @@ -269,8 +288,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string validate_layer_height = nameof(validate_layer_height); public const string validate_leveling = nameof(validate_leveling); public const string validation_threshold = nameof(validation_threshold); - public const string vibration_limit = nameof(vibration_limit); - public const string windows_driver = nameof(windows_driver); public const string wipe_shield_distance = nameof(wipe_shield_distance); public const string wipe_tower_size = nameof(wipe_tower_size); public const string write_regex = nameof(write_regex); @@ -280,8 +297,5 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string z_probe_samples = nameof(z_probe_samples); public const string z_servo_depolyed_angle = nameof(z_servo_depolyed_angle); public const string z_servo_retracted_angle = nameof(z_servo_retracted_angle); - public const string t0_inset = nameof(t0_inset); - public const string t1_inset = nameof(t1_inset); - public const string slice_engine = nameof(slice_engine); } } diff --git a/MatterControl.Printing/Settings/SliceSettingsFields.cs b/MatterControl.Printing/Settings/SliceSettingsFields.cs index 0cc554dc2..23a29aa4a 100644 --- a/MatterControl.Printing/Settings/SliceSettingsFields.cs +++ b/MatterControl.Printing/Settings/SliceSettingsFields.cs @@ -71,11 +71,20 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Avoid Crossing Perimeters".Localize().Localize(), HelpText = "Forces the slicer to attempt to avoid having the perimeter line cross over existing perimeter lines. This can help with oozing or strings.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", Converter = new MappedToBoolString(), }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_mirror_mode, + PresentationName = "Mirror Mode".Localize(), + HelpText = "Set how the printed output should be altered to compensate for the printers mirror.".Localize(), + DataEditType = DataEditTypes.LIST, + ListValues = "None,Mirror X,Mirror Y", + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + DefaultValue = "None", + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.bed_shape, PresentationName = "Bed Shape".Localize(), @@ -97,6 +106,15 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DefaultValue = "200,200" }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_resolution, + PresentationName = "Resolution".Localize(), + HelpText = "The X and Y resolution of the print bed in pixels.".Localize(), + DataEditType = DataEditTypes.VECTOR2, + Units = "px".Localize(), + DefaultValue = "1024,800" + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.bed_temperature, PresentationName = "Bed Temperature".Localize(), @@ -125,7 +143,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "°C".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "0" }, new SliceSettingData() @@ -136,7 +154,47 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.SLICE_ENGINE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, DefaultValue = "MatterSlice", - UiUpdate = UiUpdateRequired.SliceSettings, + UiUpdate = UiUpdateRequired.Application, + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_exposure_time, + PresentationName = "Exposure Time".Localize(), + HelpText = "The time in seconds to expose the normal layers of the print.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + DefaultValue = "5", + Units = "s", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_base_exposure_time, + PresentationName = "Base Exposure Time".Localize(), + HelpText = "The number of seconds to expose the base layers. This can increase the bonding to the build plate.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "s".Localize(), + DefaultValue = "45", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_base_min_off_time, + PresentationName = "Base Min Off Time".Localize(), + HelpText = "The minimum amount of time the light must be off between exposures.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "s".Localize(), + DefaultValue = "0", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_min_off_time, + PresentationName = "Base Min Off Time".Localize(), + HelpText = "The minimum amount of time the light must be off between exposures.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "s".Localize(), + DefaultValue = "0", }, new SliceSettingData() { @@ -146,7 +204,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "s".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "0" }, new SliceSettingData() @@ -156,7 +214,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The amount of filament to insert into the printer when loading.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "20" }, new SliceSettingData() @@ -167,7 +224,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm/s".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "80" }, new SliceSettingData() @@ -177,7 +233,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The amount of filament to remove from the printer while unloading.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "70" }, new SliceSettingData() @@ -187,7 +242,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The Markdown that will be shown on the Trim Filament page.".Localize(), DataEditType = DataEditTypes.MARKDOWN_TEXT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "Trim the end of the filament to ensure a good load. \n![](https://www.matterhackers.com/r/c3zLyf) \nMake sure you trim it at a slight angle" }, new SliceSettingData() @@ -197,7 +251,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The Markdown that will be shown on the Insert Filament page.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MARKDOWN_TEXT, - ShowIfSet = "!sla_printer", DefaultValue = "* Insert filament into the extruder until you feel it start to feed\\n * Make sure the filament is all the way into the extruder\\n * Hold the filament for several seconds until it catches\\n * Test that it is inserted by gently pulling down, there should be some resistance \\n* Click 'Next' \\n![Load Filament](https://www.matterhackers.com/r/Ipj4Bb)" }, new SliceSettingData() @@ -207,7 +260,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The Markdown that will be shown on the second extruders Insert Filament page.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MARKDOWN_TEXT, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "* Insert filament into extruder 2 until you feel it start to feed\\n * Make sure the filament is all the way into the extruder\\n * Hold the filament for several seconds until it catches\\n * Test that it is inserted by gently pulling down, there should be some resistance \\n* Click 'Next' \\n![Load Filament](https://www.matterhackers.com/r/Ipj4Bb)" }, new SliceSettingData() @@ -217,7 +270,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The Markdown that will be shown on the Clean Filament page.".Localize(), DataEditType = DataEditTypes.MARKDOWN_TEXT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "In a few seconds filament should be coming out of the extruder\\n* Wait for the new filament to be coming out with no trace of the previous filament\\n* Click 'Next' when the new filament is running cleanly" }, new SliceSettingData() @@ -227,7 +279,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The Markdown that will be shown on the second extruders Clean Filament page.".Localize(), DataEditType = DataEditTypes.MARKDOWN_TEXT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "In a few seconds filament should be coming out of the second extruder\\n* Wait for the new filament to be coming out with no trace of the previous filament\\n* Click 'Next' when the new filament is running cleanly" }, new SliceSettingData() @@ -241,12 +293,71 @@ namespace MatterHackers.MatterControl.SlicerConfiguration Converter = new AsCountOrDistance(SettingsKey.layer_height), }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_base_layers, + PresentationName = "Base Layers".Localize(), + HelpText = "The number of layers or the distance in millimeters to print bottom layers. Bottom layers help adhere parts to the build plate. Add mm to the end of the number to specify distance in millimeters.".Localize(), + DataEditType = DataEditTypes.INT_OR_MM, + Units = "count or mm".Localize(), + DefaultValue = ".25mm", + Converter = new AsCountOrDistance(SettingsKey.sla_layer_height), + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_base_lift_distance, + PresentationName = "Base Lift Distance".Localize(), + HelpText = "The distance to move the build plate after each base layer prints.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "mm".Localize(), + DefaultValue = "5", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_lift_distance, + PresentationName = "Lift Distance".Localize(), + HelpText = "The distance to move the build plate after each layer prints.".Localize(), + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + Units = "mm".Localize(), + DefaultValue = "5", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_base_lift_speed, + PresentationName = "Base Lift Speed".Localize(), + HelpText = "The speed to move the build plate after each base layer prints.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "mm/min".Localize(), + DefaultValue = "90", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_lift_speed, + PresentationName = "Lift Speed".Localize(), + HelpText = "The speed to move the build plate after each layer prints.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "mm/min".Localize(), + DefaultValue = "90", + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_decend_speed, + PresentationName = "Decend Speed".Localize(), + HelpText = "The speed to move the build plate back down after lifting.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "mm/min".Localize(), + DefaultValue = "150", + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.layer_to_pause, PresentationName = "Layer(s) To Pause".Localize(), HelpText = "The layer(s) at which the print will pause, allowing for a change in filament. Printer is paused before starting the given layer. Leave blank to disable. To pause on multiple layers, separate the layer numbers with semicolons. For example: \"16; 37\".".Localize(), DataEditType = DataEditTypes.STRING, - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Simple, ResetAtEndOfPrint = true, DefaultValue = "" @@ -258,9 +369,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The speed at which bridging between walls will print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm/s".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "20", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -270,9 +379,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm/s".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "15", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -281,9 +388,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The speed at which the bottom solid layers will print. Can be set explicitly or as a percentage of the Infill speed. Use 0 to match infill speed.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "mm/s or %".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "0", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -302,7 +407,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Cancel G-Code".Localize(), HelpText = "G-Code to run when a print is canceled.".Localize(), DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer", DefaultValue = "", RebuildGCodeOnChange = false }, @@ -312,7 +416,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Complete Individual Objects".Localize(), HelpText = "Each individual part is printed to completion then the nozzle is lowered back to the bed and the next part is printed.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0" }, new SliceSettingData() @@ -321,7 +424,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "On Connect G-Code".Localize(), HelpText = "G-Code to run upon successful connection to a printer. This can be useful to set settings specific to a given printer.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "" }, @@ -331,7 +433,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Enable Extruder Lift".Localize(), HelpText = "Moves the nozzle up and off the part to allow cooling.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0" }, new SliceSettingData() @@ -340,7 +441,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Enable Auto Cooling".Localize(), HelpText = "Turns on and off all cooling settings (all settings below this one).".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1" }, new SliceSettingData() @@ -355,6 +455,17 @@ namespace MatterHackers.MatterControl.SlicerConfiguration Converter = new MappedToBoolString(), }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_create_raft, + PresentationName = "Create Raft".Localize(), + HelpText = "Creates a raft under the printed part. Useful to help parts stick to the build plate.".Localize(), + DataEditType = DataEditTypes.CHECK_BOX, + DefaultValue = "0", + UiUpdate = UiUpdateRequired.SliceSettings, + RequiredDisplayDetail = DisplayDetailRequired.Simple, + Converter = new MappedToBoolString(), + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.raft_extra_distance_around_part, PresentationName = "Expand Distance".Localize(), @@ -362,7 +473,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", EnableIfSet = "create_raft", DefaultValue = "5", Converter = new AsCountOrDistance(SettingsKey.nozzle_diameter), @@ -374,7 +484,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The distance between the top of the raft and the bottom of the model. 0.6 mm is a good starting point for PLA and 0.4 mm is a good starting point for ABS. Lower values give a smoother surface, higher values make the print easier to remove.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, EnableIfSet = "create_raft", DefaultValue = ".2", @@ -388,7 +497,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm/s or %".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "100%", Converter = new AsPercentOfReferenceOrDirect(SettingsKey.infill_speed), }, @@ -419,10 +527,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Outside Perimeter".Localize(), HelpText = "The speed at which outside, external, or the otherwise visible perimeters will print.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, - ShowIfSet = "!sla_printer", Units = "mm/s or %".Localize(), DefaultValue = "70%", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.perimeter_speed), }, new SliceSettingData() { @@ -431,7 +537,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Forces external perimeters to be printed first. By default, they will print last.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "0", Converter = new MappedToBoolString(), }, @@ -442,7 +547,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The number of extruders the printer has.".Localize(), DataEditType = DataEditTypes.INT, DefaultValue = "1", - ShowIfSet = "!sla_printer", UiUpdate = UiUpdateRequired.Application, Converter = new ValueConverter(), }, @@ -454,7 +558,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.OFFSET3, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "0x0,0x0,0x0,0x0" }, new SliceSettingData() @@ -465,7 +569,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE, Units = "mm".Localize(), DefaultValue = "0", - ShowIfSet = "!sla_printer", RebuildGCodeOnChange = false, PerToolName = (toolIndex) => $"{SettingsKey.baby_step_z_offset}_{toolIndex}" }, @@ -477,7 +580,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, DefaultValue = "0", - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", UiUpdate = UiUpdateRequired.Application }, new SliceSettingData() @@ -486,7 +589,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Heat Before Homing".Localize(), HelpText = "Forces the printer to heat the nozzle before homing.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0" }, new SliceSettingData() @@ -496,7 +598,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Detect perimeters that cross over themselves and combine them.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "1", Converter = new MappedToBoolString(), }, @@ -507,7 +608,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Detects sections of the model that would be too thin to print and expands them to make them printable.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "1", Converter = new MappedToBoolString(), }, @@ -518,7 +618,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "All extrusions are multiplied by this value. Increasing it above 1 will increase the amount of filament being extruded (1.1 is a good max value); decreasing it will decrease the amount being extruded (.9 is a good minimum value).".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "Ratio or %".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "100%", Converter = new AsPercentOrDirect(), }, @@ -529,7 +628,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The maximum amount that an avoid crossing travel can exceed the direct distance. If the avoid travel is too long, a direct move will be executed.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "Ratio or %".Localize(), - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DefaultValue = "3", Converter = new AsPercentOrDirect(), @@ -558,6 +656,28 @@ namespace MatterHackers.MatterControl.SlicerConfiguration QuickMenuSettings = { { "PLA", "1.24" }, { "PET", "1.27" }, { "ABS", "1.04" } }, }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.resin_cost, + PresentationName = "Cost".Localize(), + HelpText = "The price of one kilogram of resin. Used for estimating the cost of a print in the Layer View.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "$/kg".Localize(), + DefaultValue = "0", + RebuildGCodeOnChange = false, + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.resin_density, + PresentationName = "Density".Localize(), + HelpText = "Resin density. Only used for estimating mass in the Layer View.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + Units = "g/cm³".Localize(), + DefaultValue = "1.24", + RebuildGCodeOnChange = false, + }, + new SliceSettingData() { QuickMenuSettings = { { "Standard 1.75", "1.75" }, { "Wide 2.85", "2.85" } }, SlicerConfigName = SettingsKey.filament_diameter, @@ -565,7 +685,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The actual diameter of the filament used for printing.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", Units = "mm".Localize(), DefaultValue = "3", Converter = new ValueConverter(), @@ -597,7 +716,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Fill Thin Gaps".Localize(), HelpText = "Detect gaps between perimeters that are too thin to fill with normal infill and attempt to fill them.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", Converter = new MappedToBoolString(), }, @@ -609,7 +727,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm or %".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "100%", Converter = new AsPercentOfReferenceOrDirect(SettingsKey.nozzle_diameter), }, @@ -620,7 +737,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The thickness of the first layer. A first layer taller than the default layer thickness can ensure good adhesion to the build plate.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "mm or %".Localize(), - RequiredDisplayDetail = DisplayDetailRequired.Simple, DefaultValue = "0.3", Converter = new AsPercentOfReferenceOrDirect(SettingsKey.layer_height), }, @@ -642,7 +758,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.INT_OR_MM, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "layers or mm".Localize(), - ShowIfSet = "sla_printer", DefaultValue = "1", Converter = new AsCountOrDistance(SettingsKey.layer_height), }, @@ -678,7 +793,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration RequiredDisplayDetail = DisplayDetailRequired.Simple, ShowAsOverride = true, DefaultValue = "1", - ShowIfSet = "!sla_printer", RebuildGCodeOnChange = false }, new SliceSettingData() @@ -710,7 +824,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The temperature to which the nozzle will be heated before printing the first layer of a part. The printer will wait until this temperature has been reached before printing.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "°C".Localize().Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "205" }, new SliceSettingData() @@ -719,7 +832,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Auto Release Motors".Localize(), HelpText = "Turn off motor current at end of print or after cancel print.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1" }, new SliceSettingData() @@ -729,7 +841,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Use G0 for moves rather than G1.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "0" }, new SliceSettingData() @@ -757,7 +868,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The printer has a z probe for measuring bed level.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, ShowAsOverride = true, - ShowIfSet = "!sla_printer", DefaultValue = "0", UiUpdate = UiUpdateRequired.SliceSettings, RebuildGCodeOnChange = false @@ -770,7 +880,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.CHECK_BOX, ShowAsOverride = true, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "0", UiUpdate = UiUpdateRequired.SliceSettings, RebuildGCodeOnChange = false @@ -793,7 +902,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Has Hardware Leveling".Localize(), HelpText = "The printer has its own auto bed leveling probe and procedure which can be called using a G29 command during Start G-Code.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0", UiUpdate = UiUpdateRequired.SliceSettings }, @@ -803,22 +911,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Has Heated Bed".Localize(), HelpText = "The printer has a heated bed.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", UiUpdate = UiUpdateRequired.Application }, new SliceSettingData() - { - SlicerConfigName = SettingsKey.sla_printer, - PresentationName = "Printer is SLA".Localize(), - HelpText = "Switch the settings interface to one intended for SLA printers.".Localize(), - DataEditType = DataEditTypes.CHECK_BOX, - RequiredDisplayDetail = DisplayDetailRequired.Advanced, - DefaultValue = "0", - UiUpdate = UiUpdateRequired.Application, - RebuildGCodeOnChange = false - }, - new SliceSettingData() { SlicerConfigName = SettingsKey.include_firmware_updater, PresentationName = "Show Firmware Updater".Localize(), @@ -827,7 +923,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration ListValues = "None,Simple Arduino", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DefaultValue = "None", - ShowIfSet = "!sla_printer", UiUpdate = UiUpdateRequired.SliceSettings, RebuildGCodeOnChange = false }, @@ -839,7 +934,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "1", RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&!include_firmware_updater=None", + ShowIfSet = "!include_firmware_updater=None", RebuildGCodeOnChange = false }, new SliceSettingData() @@ -850,7 +945,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "0", RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", UiUpdate = UiUpdateRequired.Application, RebuildGCodeOnChange = false }, @@ -862,7 +956,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.CHECK_BOX, Units = "", DefaultValue = "0", - ShowIfSet = "!sla_printer", UiUpdate = UiUpdateRequired.Application, RebuildGCodeOnChange = false }, @@ -872,7 +965,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Show Reset Connection".Localize(), HelpText = "Shows a button at the right side of the Printer Connection Bar used to reset the USB connection to the printer. This can be used on printers that support it as an emergency stop.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", UiUpdate = UiUpdateRequired.Application, DefaultValue = "0" }, @@ -889,35 +981,13 @@ namespace MatterHackers.MatterControl.SlicerConfiguration QuickMenuSettings = { { "Light", "20%" }, { "Standard", "35%" }, { "Heavy", "75%" } } }, new SliceSettingData() - { - SlicerConfigName = SettingsKey.laser_speed_025, - PresentationName = "Speed at 0.025 Height".Localize(), - HelpText = "The speed to move the laser when the layer height is 0.025mm. Speed will be adjusted linearly at other heights.".Localize(), - DataEditType = DataEditTypes.POSITIVE_DOUBLE, - Units = "mm/s".Localize(), - ShowIfSet = "sla_printer", - DefaultValue = "100" - }, - new SliceSettingData() - { - SlicerConfigName = SettingsKey.laser_speed_100, - PresentationName = "Speed at 0.1 Height".Localize(), - HelpText = "The speed to move the laser when the layer height is 0.1mm. Speed will be adjusted linearly at other heights.".Localize(), - DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "sla_printer", - Units = "mm/s".Localize(), - DefaultValue = "85" - }, - new SliceSettingData() { SlicerConfigName = SettingsKey.infill_speed, PresentationName = "Infill".Localize(), HelpText = "The speed at which infill will print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", Units = "mm/s".Localize(), DefaultValue = "60", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -925,7 +995,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Infill Type".Localize(), HelpText = "The geometric shape of the support structure for the inside of parts.".Localize(), DataEditType = DataEditTypes.LIST, - ShowIfSet = "!sla_printer", ListValues = "GRID,TRIANGLES,HEXAGON,GYROID,LINES,CONCENTRIC", DefaultValue = "TRIANGLES", Converter = new ValueConverter(), @@ -937,7 +1006,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The firmware being used by the printer. Allows for improvements based on firmware such as optimized G-Code output.".Localize(), DataEditType = DataEditTypes.LIST, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", ListValues = "Unknown,Marlin,Smoothie", DefaultValue = "Unknown", Converter = new ValueConverter(), @@ -963,7 +1031,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "A comma separated list of sample points to probe the bed at. You must specify an x and y position for each point. For example: '20,20,100,180,180,20' will sample the bad at 3 points.".Localize(), DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "20,20,100,180,180,20", - ShowIfSet = "!sla_printer&!has_hardware_leveling&print_leveling_solution=Custom Points", + ShowIfSet = "!has_hardware_leveling&print_leveling_solution=Custom Points", RebuildGCodeOnChange = false }, new SliceSettingData() @@ -974,7 +1042,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration Units = "mm".Localize(), DataEditType = DataEditTypes.VECTOR2, DefaultValue = "100,100", - ShowIfSet = "!sla_printer&!has_hardware_leveling&print_leveling_solution=Custom Points&use_z_probe", + ShowIfSet = "!has_hardware_leveling&print_leveling_solution=Custom Points&use_z_probe", RebuildGCodeOnChange = false }, new SliceSettingData() @@ -997,7 +1065,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Specifies that the firmware has support for ros_0 endstop reporting on M119. TRIGGERED state defines filament has runout. If runout is detected the printers pause G-Code is run.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, ShowAsOverride = true, - ShowIfSet = "!sla_printer", DefaultValue = "0", UiUpdate = UiUpdateRequired.SliceSettings, RebuildGCodeOnChange = false @@ -1011,7 +1078,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration Units = "mm".Localize(), ShowAsOverride = true, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&filament_runout_sensor", + ShowIfSet = "filament_runout_sensor", RebuildGCodeOnChange = false, DefaultValue = "1" }, @@ -1023,7 +1090,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, ShowAsOverride = true, - ShowIfSet = "!sla_printer&filament_runout_sensor", + ShowIfSet = "filament_runout_sensor", RebuildGCodeOnChange = false, DefaultValue = "2" }, @@ -1034,7 +1101,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Report the data analysis of the run out sensor data each time it is read.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, ShowAsOverride = true, - ShowIfSet = "!sla_printer&filament_runout_sonsor", + ShowIfSet = "filament_runout_sonsor", DefaultValue = "0", RebuildGCodeOnChange = false @@ -1065,7 +1132,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Filament Has Been Loaded".Localize(), HelpText = "Flag for the state of our filament loaded.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0", RebuildGCodeOnChange = false }, @@ -1075,7 +1141,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Filament 2 Has Been Loaded".Localize(), HelpText = "Flag for the state of our filament loaded on extruder 2.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "0", RebuildGCodeOnChange = false }, @@ -1122,7 +1187,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), ShowAsOverride = true, - ShowIfSet = "!sla_printer&!has_hardware_leveling&has_z_probe&use_z_probe&validate_leveling", + ShowIfSet = "!has_hardware_leveling&has_z_probe&use_z_probe&validate_leveling", RebuildGCodeOnChange = false, DefaultValue = ".05" }, @@ -1134,7 +1199,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.OFFSET3, Units = "mm".Localize(), ShowAsOverride = true, - ShowIfSet = "!sla_printer&!has_hardware_leveling&has_z_probe&use_z_probe", + ShowIfSet = "!has_hardware_leveling&has_z_probe&use_z_probe", RebuildGCodeOnChange = false, DefaultValue = "0,0,0" }, @@ -1192,10 +1257,22 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The thickness of each layer of the print, except the first layer. A smaller number will create more layers and more vertical accuracy but also a slower print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), + RequiredDisplayDetail = DisplayDetailRequired.Simple, DefaultValue = "0.4", Converter = new ValueConverter(), }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_layer_height, + PresentationName = "Layer Thickness".Localize(), + HelpText = "The thickness of each layer of the print, except the base layers. A smaller number will create more layers and more vertical accuracy but also a slower print.".Localize(), + DataEditType = DataEditTypes.POSITIVE_DOUBLE, + Units = "mm".Localize(), + RequiredDisplayDetail = DisplayDetailRequired.Simple, + DefaultValue = "0.05", + Converter = new ValueConverter(), + }, + new SliceSettingData() { QuickMenuSettings = { { "Minimum", "0.3" }, { "Standard", "0.6" }, { "Full", "1" } }, SetSettingsOnChange = new List> @@ -1232,7 +1309,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration Units = "mm".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, EnableIfSet = SettingsKey.enable_retractions, - ShowIfSet = "!sla_printer", DefaultValue = ".1", Converter = new ValueConverter(), }, @@ -1242,7 +1318,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Has Fan".Localize(), HelpText = "The printer has a layer-cooling fan.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", UiUpdate = UiUpdateRequired.Application }, @@ -1252,7 +1327,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Each Extruder Has Fan".Localize(), HelpText = "Each extruder has a separate part cooling fan that is controlled independently.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer&has_fan&extruder_count>1", + ShowIfSet = "has_fan&extruder_count>1", DefaultValue = "0", UiUpdate = UiUpdateRequired.SliceSettings }, @@ -1263,7 +1338,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Turn the fan on and off regardless of settings.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, UiUpdate = UiUpdateRequired.SliceSettings, - ShowIfSet = "!sla_printer&has_fan", + ShowIfSet = "has_fan", DefaultValue = "1" }, new SliceSettingData() @@ -1362,7 +1437,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The minimum speed to which the printer will reduce to in order to attempt to make the layer print time long enough to satisfy the minimum layer time.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm/s".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "10", Converter = new ValueConverter(), }, @@ -1373,7 +1447,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The minimum length of filament to use printing the skirt loops. Enough skirt loops will be drawn to use this amount of filament, overriding the value set in Loops if the value in Loops will produce a skirt shorter than this value.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.create_skirt, Units = "mm".Localize(), DefaultValue = "0", @@ -1432,7 +1505,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Output only the first layer of the print. Especially useful for outputting gcode data for applications like engraving or cutting.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "0", Converter = new MappedToBoolString(), }, @@ -1442,7 +1514,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Pause G-Code".Localize(), HelpText = "G-Code to run when the printer is paused.".Localize(), DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer", DefaultValue = "", RebuildGCodeOnChange = false }, @@ -1463,7 +1534,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "A modifier of the width of the extrusion when printing outside perimeters. Can be useful to fine-adjust actual print size when objects print larger or smaller than specified in the digital model.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "mm or %".Localize(), - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DefaultValue = "100%", Converter = new AsPercentOfReferenceOrDirect(SettingsKey.nozzle_diameter), @@ -1474,10 +1544,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Inside Perimeters".Localize(), HelpText = "The speed at which inside perimeters will print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", Units = "mm/s".Localize(), DefaultValue = "30", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -1486,7 +1554,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The acceleration that the printer will be set to for perimeters, will not be changed if set to 0. A typical perimeter acceleration is 800.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", Units = "mm/s^2".Localize(), DefaultValue = "0", }, @@ -1497,7 +1564,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The acceleration that the printer will be set to by default, will not be changed if set to 0. A typical default acceleration is 1500.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", Units = "mm/s^2".Localize(), DefaultValue = "0", }, @@ -1556,7 +1622,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Resume G-Code".Localize(), HelpText = "G-Code to be run when the print resumes after a pause.".Localize(), DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer", DefaultValue = "", RebuildGCodeOnChange = false }, @@ -1568,7 +1633,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "5", Converter = new MapFirstValue(), @@ -1581,7 +1645,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "20", Converter = new MapFirstValue(), @@ -1594,7 +1657,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "3", Converter = new ValueConverter(), }, @@ -1604,7 +1666,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Enable Retractions".Localize(), HelpText = "Turn retractions on and off.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", UiUpdate = UiUpdateRequired.SliceSettings }, @@ -1616,7 +1677,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), DefaultValue = "1", - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, Converter = new ConditionalField(SettingsKey.enable_retractions, new ValueConverter()) }, @@ -1627,7 +1687,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "When using multiple extruders, the distance filament will reverse before changing to a different extruder.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", Units = "mm".Localize(), EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "10", @@ -1640,7 +1700,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Force a retraction when moving between islands (distinct parts on the layer).".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "1", Converter = new MappedToBoolString(), @@ -1652,7 +1711,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The distance the nozzle will lift after each retraction.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "0", Converter = new MapFirstValue(), @@ -1664,7 +1722,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Length of extra filament to extrude after a complete tool change (in addition to the re-extrusion of the tool change retraction distance).".Localize(), DataEditType = DataEditTypes.DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", EnableIfSet = SettingsKey.enable_retractions, Units = "mm zero to disable".Localize(), DefaultValue = "0", @@ -1677,7 +1735,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "If the extruder has been running for a long time, it may be reporting values that are too large, this will periodically reset it.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", DefaultValue = "1", Converter = new MappedToBoolString(), }, @@ -1688,7 +1745,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "Calculate and transmit a standard rep-rap checksum for all commands.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DefaultValue = "1" }, new SliceSettingData() @@ -1699,7 +1755,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "0", Converter = new MapFirstValue(), @@ -1712,7 +1767,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE, Units = "s".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "0", Converter = new MapFirstValue(), @@ -1725,7 +1779,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm/s".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.enable_retractions, DefaultValue = "30", Converter = new MapFirstValue(), @@ -1747,22 +1800,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DefaultValue = "0" }, new SliceSettingData() - { - SlicerConfigName = SettingsKey.resolution, - PresentationName = "Resolution".Localize(), - HelpText = "The minimum feature size to consider from the model. Leave at 0 to use all the model detail.".Localize(), - DataEditType = DataEditTypes.POSITIVE_DOUBLE, - Units = "mm".Localize(), - DefaultValue = "0" - }, - new SliceSettingData() { QuickMenuSettings = { { "Touching", "0" }, { "Standard", "3" }, { "Far", "10" } }, SlicerConfigName = SettingsKey.skirt_distance, PresentationName = "Distance From Object".Localize(), HelpText = "The distance from the model at which the first skirt loop is drawn.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, EnableIfSet = SettingsKey.create_skirt, Units = "mm".Localize(), @@ -1784,7 +1827,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Distance or Loops".Localize(), HelpText = "The number of loops to draw around all the parts on the bed before starting on the parts. Used mostly to prime the nozzle so the flow is even when the actual print begins.".Localize(), DataEditType = DataEditTypes.INT_OR_MM, - ShowIfSet = "!sla_printer", EnableIfSet = SettingsKey.create_skirt, Units = "count or mm".Localize(), DefaultValue = "1", @@ -1808,7 +1850,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The minimum amount of time a layer must take to print. If a layer will take less than this amount of time, the movement speed is reduced so the layer print time will match this value, down to the minimum print speed at the slowest.".Localize(), DataEditType = DataEditTypes.INT, Units = "seconds".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "30", Converter = new ValueConverter(), }, @@ -1848,7 +1889,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Spiral Vase".Localize(), HelpText = "Forces the print to have only one extrusion and gradually increase the Z height during the print. Only one part will print at a time with this feature.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, - ShowIfSet = "!sla_printer", ResetAtEndOfPrint = true, RequiredDisplayDetail = DisplayDetailRequired.Simple, DefaultValue = "0", @@ -1919,7 +1959,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Air Gap".Localize(), HelpText = "The distance between the top of the support and the bottom of the model. A good value depends on the type of material. For ABS and PLA a value between 0.4 and 0.6 works well, respectively.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), DefaultValue = ".3", @@ -1931,7 +1970,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Infill Angle".Localize(), HelpText = "The angle at which the support material lines will be drawn.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", Units = "°".Localize(), DefaultValue = "45", Converter = new ValueConverter(), @@ -1941,7 +1979,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.support_material_create_perimeter, PresentationName = "Create Perimeter".Localize(), HelpText = "Generates an outline around the support material to improve strength and hold up interface layers.".Localize(), - ShowIfSet = "!sla_printer", DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "1", Converter = new MappedToBoolString(), @@ -1951,7 +1988,17 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.create_per_layer_support, PresentationName = "Create Supports".Localize(), HelpText = "Evaluate every layer for support requirements. NOTE: If there are any support columns, this setting is ignored.".Localize(), - ShowIfSet = "!sla_printer", + DataEditType = DataEditTypes.CHECK_BOX, + DefaultValue = "0", + RequiredDisplayDetail = DisplayDetailRequired.Simple, + Converter = new MappedToBoolString(), + UiUpdate = UiUpdateRequired.SliceSettings + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_auto_support, + PresentationName = "Auto Support".Localize(), + HelpText = "Before exporting evaluate and add automatic support material. NOTE: If there is already support, no additional support will be added.".Localize(), DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "0", RequiredDisplayDetail = DisplayDetailRequired.Simple, @@ -1963,7 +2010,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.create_per_layer_internal_support, PresentationName = "Generate Everywhere".Localize(), HelpText = "When generating per layer support, evaluate all surfaces rather than only those above the bed.".Localize(), - ShowIfSet = "!sla_printer&create_per_layer_support", + ShowIfSet = "create_per_layer_support", DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "1", Converter = new MappedToBoolString(), @@ -1976,7 +2023,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "%".Localize(), - ShowIfSet = "!sla_printer&create_per_layer_support", + ShowIfSet = "create_per_layer_support", DefaultValue = "50", Converter = new ValueConverter(), }, @@ -1988,7 +2035,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), - ShowIfSet = "!sla_printer&create_per_layer_support", + ShowIfSet = "create_per_layer_support", DefaultValue = "1", Converter = new ValueConverter(), }, @@ -1996,7 +2043,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { SlicerConfigName = SettingsKey.support_material_extruder, PresentationName = "Support Material Extruder".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", HelpText = "The index of the extruder to use for printing support material. Applicable only when Extruder Count is set to a value more than 1.".Localize(), DataEditType = DataEditTypes.INT, DefaultValue = "1", @@ -2007,7 +2054,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.raft_extruder, PresentationName = "Raft Extruder".Localize(), HelpText = "The index of the extruder to use to print the raft. Set to 0 to use the support extruder index.".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", EnableIfSet = "create_raft", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.INT, @@ -2019,7 +2066,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.support_material_interface_extruder, PresentationName = "Support Interface Extruder".Localize(), HelpText = "The index of the extruder to use for support material interface layer(s).".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DataEditType = DataEditTypes.INT, DefaultValue = "1", Converter = new ValuePlusConstant(-1), @@ -2030,7 +2077,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Interface Layers".Localize(), HelpText = "The number of layers or the distance to print solid material between the supports and the part. Add mm to the end of the number to specify distance.".Localize(), DataEditType = DataEditTypes.INT_OR_MM, - ShowIfSet = "!sla_printer", Units = "layers or mm".Localize(), DefaultValue = ".9mm", Converter = new AsCountOrDistance(SettingsKey.layer_height), @@ -2043,7 +2089,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, Units = "mm".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "2.5", Converter = new ValueConverter(), }, @@ -2053,10 +2098,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Support Material".Localize(), HelpText = "The speed at which support material structures will print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", Units = "mm/s".Localize(), DefaultValue = "60", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -2064,10 +2107,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Interface Layer".Localize(), HelpText = "The speed at which interface layers will print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer", Units = "mm/s".Localize(), DefaultValue = "60", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -2076,7 +2117,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The distance the support material will be from the object in the X and Y directions.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", Units = "mm".Localize(), DefaultValue = "0.7", Converter = new ValueConverter(), @@ -2088,7 +2128,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The pattern to draw for the generation of support material.".Localize(), DataEditType = DataEditTypes.LIST, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", ListValues = "GRID,LINES", DefaultValue = "LINES", Converter = new ValueConverter(), @@ -2110,7 +2149,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The color of the second material (extruder 2).".Localize(), DataEditType = DataEditTypes.COLOR, RequiredDisplayDetail = DisplayDetailRequired.Simple, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", RebuildGCodeOnChange = false, DefaultValue = ColorF.FromHSL(1 / 10.0, .99, .49).ToColor().Html, }, @@ -2121,7 +2160,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The color of the third material (extruder 3).".Localize(), DataEditType = DataEditTypes.COLOR, RequiredDisplayDetail = DisplayDetailRequired.Simple, - ShowIfSet = "!sla_printer&extruder_count>2", + ShowIfSet = "extruder_count>2", RebuildGCodeOnChange = false, DefaultValue = ColorF.FromHSL(2 / 10.0, .99, .49).ToColor().Html, }, @@ -2132,7 +2171,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The color of the forth material (extruder 4).".Localize(), DataEditType = DataEditTypes.COLOR, RequiredDisplayDetail = DisplayDetailRequired.Simple, - ShowIfSet = "!sla_printer&extruder_count>3", + ShowIfSet = "extruder_count>3", RebuildGCodeOnChange = false, DefaultValue = ColorF.FromHSL(3 / 10.0, .99, .49).ToColor().Html, }, @@ -2144,7 +2183,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "°C".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Simple, - ShowIfSet = "!sla_printer", DefaultValue = "200" }, new SliceSettingData() @@ -2154,7 +2192,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The target temperature the extruder will attempt to reach during the print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "°C".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "200" }, new SliceSettingData() @@ -2165,7 +2203,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "Ratio or %".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "100%", Converter = new AsPercentOrDirect() }, @@ -2176,17 +2214,26 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The target temperature the extruder will attempt to reach during the print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "°C".Localize(), - ShowIfSet = "!sla_printer&extruder_count>2", + ShowIfSet = "extruder_count>2", DefaultValue = "200" }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.sla_printable_area_inset, + PresentationName = "Printable Area Inset".Localize(), + HelpText = "The inset amount from the edges of the bed. Defines the printable area of the bed. Leave as 0s if the entire bed can be printed to.".Localize(), + DataEditType = DataEditTypes.BOUNDS, + RequiredDisplayDetail = DisplayDetailRequired.Advanced, + DefaultValue = "" + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.t0_inset, PresentationName = "Nozzle 1 Inset".Localize(), HelpText = "The inset amount for nozzle 1 from the bed".Localize(), DataEditType = DataEditTypes.BOUNDS, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "" }, new SliceSettingData() @@ -2196,7 +2243,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The inset amount for nozzle 2 from the bed".Localize(), DataEditType = DataEditTypes.BOUNDS, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "" }, new SliceSettingData() @@ -2206,7 +2253,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The target temperature the extruder will attempt to reach during the print.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "°C".Localize(), - ShowIfSet = "!sla_printer&extruder_count>3", + ShowIfSet = "extruder_count>3", DefaultValue = "200" }, new SliceSettingData() @@ -2216,7 +2263,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The temperature at which the extruder will wipe the nozzle, as specified by Custom G-Code.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", Units = "°C".Localize(), DefaultValue = "0" }, @@ -2255,7 +2301,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "G-Code to be run before every tool change. You can use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), DataEditType = DataEditTypes.MULTI_LINE_TEXT, RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "" }, new SliceSettingData() @@ -2263,7 +2309,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.toolchange_gcode, PresentationName = "After Tool Change G-Code".Localize(), HelpText = "G-Code to be run after every tool change. You can use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "" @@ -2275,7 +2321,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "G-Code to be run before switching to extruder 2. Will use standard before G-Code if not set. You can use [wipe_tower_x] [wipe_tower_y] & [wipe_tower_z] to set the extruder position if needed. You can also use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "" }, new SliceSettingData() @@ -2283,7 +2329,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.toolchange_gcode_1, PresentationName = "After Tool Change G-Code 2".Localize(), HelpText = "G-Code to be run after switching to extruder 2. Will use standard after G-Code if not set. You can use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "" @@ -2295,7 +2341,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "G-Code to be run before switching to extruder 3. Will use standard before G-Code if not set. You can use [wipe_tower_x] [wipe_tower_y] & [wipe_tower_z] to set the extruder position if needed. You can also use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer&extruder_count>2", + ShowIfSet = "extruder_count>2", DefaultValue = "" }, new SliceSettingData() @@ -2304,7 +2350,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "After Tool Change G-Code 3".Localize(), HelpText = "G-Code to be run after switching to extruder 3. Will use standard after G-Code if not set. You can use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>2", + ShowIfSet = "extruder_count>2", DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "" }, @@ -2315,7 +2361,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "G-Code to be run before switching to extruder 3. Will use standard before G-Code if not set. You can use [wipe_tower_x] [wipe_tower_y] & [wipe_tower_z] to set the extruder position if needed. You can also use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.MULTI_LINE_TEXT, - ShowIfSet = "!sla_printer&extruder_count>3", + ShowIfSet = "extruder_count>3", DefaultValue = "" }, new SliceSettingData() @@ -2324,7 +2370,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "After Tool Change G-Code 4".Localize(), HelpText = "G-Code to be run after switching to extruder 2. Will use standard after G-Code if not set. You can use '; WRITE_RAW' to skip checksums or '; NO_PROCESSING' to skip position offsetting.".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer&extruder_count>3", + ShowIfSet = "extruder_count>3", DataEditType = DataEditTypes.MULTI_LINE_TEXT, DefaultValue = "" }, @@ -2345,9 +2391,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The speed at which the top solid layers will print. Can be set explicitly or as a percentage of the Infill speed.".Localize(), DataEditType = DataEditTypes.DOUBLE_OR_PERCENT, Units = "mm/s or %".Localize(), - ShowIfSet = "!sla_printer", DefaultValue = "50", - Converter = new OverrideSpeedOnSlaPrinters(SettingsKey.infill_speed), }, new SliceSettingData() { @@ -2404,7 +2448,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration DataEditType = DataEditTypes.INT, ShowAsOverride = false, RequiredDisplayDetail = DisplayDetailRequired.Simple, - ShowIfSet = null, DefaultValue = "250000", RebuildGCodeOnChange = false }, @@ -2441,21 +2484,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration RebuildGCodeOnChange = false }, new SliceSettingData() - { - SlicerConfigName = SettingsKey.vibration_limit, - PresentationName = "Vibration Limit".Localize(), - HelpText = "This is to help reduce vibrations during printing. If your printer has a resonance frequency that is causing trouble you can set this to try and reduce printing at that frequency.".Localize(), - DataEditType = DataEditTypes.INT, - Units = "Hz".Localize(), - DefaultValue = "0" - }, - new SliceSettingData() { SlicerConfigName = SettingsKey.wipe_shield_distance, PresentationName = "Wipe Shield Distance".Localize(), HelpText = "Creates a perimeter around the part on which to wipe the other nozzle when printing using dual extrusion. Set to 0 to disable.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", Units = "mm".Localize(), DefaultValue = "0", Converter = new ValueConverter(), @@ -2467,7 +2501,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "The length and width of a tower created at the back left of the print used for wiping the next nozzle when changing between multiple extruders. Set to 0 to disable.".Localize(), DataEditType = DataEditTypes.POSITIVE_DOUBLE, Units = "mm".Localize(), - ShowIfSet = "!sla_printer&extruder_count>1", + ShowIfSet = "extruder_count>1", DefaultValue = "0", Converter = new ValueConverter(), }, @@ -2483,7 +2517,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.enable_network_printing, PresentationName = "Networked Printing".Localize(), HelpText = "Sets MatterControl to attempt to connect to a printer over the network. (You must disconnect and reconnect for this to take effect)".Localize(), - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.CHECK_BOX, SetSettingsOnChange = new List> @@ -2504,7 +2537,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.enable_line_splitting, PresentationName = "Enable Line Splitting".Localize(), HelpText = "Allow MatterControl to split long lines to improve leveling and print canceling. Critical for printers that are significantly out of level.".Localize(), - ShowIfSet = "!sla_printer", DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "1", RebuildGCodeOnChange = false @@ -2514,7 +2546,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SlicerConfigName = SettingsKey.emulate_endstops, PresentationName = "Emulate Endstops".Localize(), HelpText = "Make MatterControl emulate bed limits and endstops in software and prevent the printer from moving to invalid locations.".Localize(), - ShowIfSet = "!sla_printer", RequiredDisplayDetail = DisplayDetailRequired.Advanced, DataEditType = DataEditTypes.CHECK_BOX, DefaultValue = "0", @@ -2526,7 +2557,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration PresentationName = "Sailfish Communication".Localize(), HelpText = "Sets MatterControl to use s3g communication method. (You must disconnect and reconnect for this to take effect)".Localize(), RequiredDisplayDetail = DisplayDetailRequired.Advanced, - ShowIfSet = "!sla_printer", DataEditType = DataEditTypes.CHECK_BOX, SetSettingsOnChange = new List> { @@ -2548,7 +2578,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration HelpText = "List of IP's discovered on the network".Localize(), DataEditType = DataEditTypes.IP_LIST, ShowAsOverride = false, - ShowIfSet = "enable_network_printing", + ShowIfSet = "!enable_network_printing", DefaultValue = "Manual", RebuildGCodeOnChange = false, UiUpdate = UiUpdateRequired.SliceSettings diff --git a/MatterControl.Printing/Settings/SliceSettingsLayouts.cs b/MatterControl.Printing/Settings/SliceSettingsLayouts.cs index 50d4ebb15..28a572287 100644 --- a/MatterControl.Printing/Settings/SliceSettingsLayouts.cs +++ b/MatterControl.Printing/Settings/SliceSettingsLayouts.cs @@ -47,7 +47,25 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.top_solid_layers, SettingsKey.bottom_solid_layers, SettingsKey.fill_density, - SettingsKey.infill_type + SettingsKey.infill_type, + // add settings specific to SLA + SettingsKey.sla_layer_height, + SettingsKey.sla_decend_speed, + }), + ("Normal Layers", new[] // this is for SLA resin printing + { + SettingsKey.sla_exposure_time, + SettingsKey.sla_lift_distance, + SettingsKey.sla_lift_speed, + SettingsKey.sla_min_off_time, + }), + ("Base Layers", new[] // this is for SLA resin printing + { + SettingsKey.sla_base_layers, + SettingsKey.sla_base_exposure_time, + SettingsKey.sla_base_lift_distance, + SettingsKey.sla_base_lift_speed, + SettingsKey.sla_base_min_off_time, }), ("Layers / Surface", new[] { @@ -129,6 +147,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.raft_extra_distance_around_part, SettingsKey.raft_air_gap, SettingsKey.raft_extruder, + // add settings specific to SLA + SettingsKey.sla_create_raft, }), ("Brim", new[] { @@ -156,11 +176,21 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.create_per_layer_internal_support, SettingsKey.support_percent, SettingsKey.support_grab_distance, + // add settings specific to SLA + SettingsKey.sla_auto_support, + }), + }), + ("Resin", new[] + { + ("Properties", new [] + { + SettingsKey.resin_density, + SettingsKey.resin_cost, }), }), ("Filament", new[] { - ("Filament", new[] + ("Properties", new[] { SettingsKey.material_color, SettingsKey.material_color_1, @@ -240,6 +270,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.print_center, SettingsKey.build_height, SettingsKey.bed_shape, + // add settings specific to SLA + SettingsKey.sla_resolution, + SettingsKey.sla_printable_area_inset, + SettingsKey.sla_mirror_mode, }), ("Extruders", new[] { @@ -315,7 +349,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.has_c_axis, SettingsKey.enable_network_printing, SettingsKey.enable_sailfish_communication, - SettingsKey.sla_printer, SettingsKey.max_acceleration, SettingsKey.max_velocity, SettingsKey.jerk_velocity, diff --git a/MatterControl.SLA/MatterControl.SLA.csproj b/MatterControl.SLA/MatterControl.SLA.csproj new file mode 100644 index 000000000..e01aa291d --- /dev/null +++ b/MatterControl.SLA/MatterControl.SLA.csproj @@ -0,0 +1,34 @@ + + + + netstandard2.0 + MatterHackers Inc. + true + 2.20.12 + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MatterControl.SLA/Photon/Parts/ArraysEmulation.cs b/MatterControl.SLA/Photon/Parts/ArraysEmulation.cs new file mode 100644 index 000000000..87b6dba5b --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/ArraysEmulation.cs @@ -0,0 +1,71 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System; + +public static class ArraysEmulation +{ + public static void Arraycopy(byte[] emptyRow, int v1, byte[] vs, int v2, int width) + { + throw new NotImplementedException(); + } + + public static byte[] CopyOfRange(byte[] src, int start, int end) + { + int len = end - start; + var dest = new byte[len]; + // note i is always from 0 + for (int i = 0; i < len; i++) + { + dest[i] = src[start + i]; // so 0..n = 0+x..n+x + } + return dest; + } + + public static void Fill(T[] array, int start, int end, T value) + { + if (array == null) + { + throw new ArgumentNullException("array is null"); + } + + if (start < 0 || start >= end) + { + throw new ArgumentOutOfRangeException("fromIndex"); + } + if (end >= array.Length) + { + throw new ArgumentOutOfRangeException("toIndex"); + } + for (int i = start; i < end; i++) + { + array[i] = value; + } + } + + internal static void Arraycopy(int[] emptyCol, int v1, int[] pixels, int v2, int height) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/BitArrayExtensions.cs b/MatterControl.SLA/Photon/Parts/BitArrayExtensions.cs new file mode 100644 index 000000000..3c02ad6c0 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/BitArrayExtensions.cs @@ -0,0 +1,77 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.Collections; + +/** +* by bn on 01/07/2018. +*/ + +namespace Photon.Parts +{ + public static class BitArrayExtensions + { + /// + /// returns the next set bit or -1 if no more set bits + /// + /// The array to check + /// The index to start checking from + /// The next set bit or -1 + public static int NextSetBit(this BitArray bitArray, int startIndex) + { + int offset = startIndex >> 6; + long mask = 1L << startIndex; + while (offset < bitArray.Length) + { + var h = bitArray[offset] ? 1 : 0; + do + { + if ((h & mask) != 0) + { + return startIndex; + } + + mask <<= 1; + startIndex++; + } + while (mask != 0); + + mask = 1; + offset++; + } + + return -1; + } + + public static void Set(this BitArray bitArray, int start, int end) + { + for (int i = start; i < end; i++) + { + bitArray[i] = true; + } + } + } + + +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/IFileHeader.cs b/MatterControl.SLA/Photon/Parts/IFileHeader.cs new file mode 100644 index 000000000..b06855cbe --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/IFileHeader.cs @@ -0,0 +1,81 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.Collections.Generic; + +namespace Photon.Parts +{ + public interface IFileHeader + { + int GetAALevels(); + + float GetBottomExposureTimeSeconds(); + + int GetBottomLayers(); + + float GetBuildAreaX(); + + float GetBuildAreaY(); + + int GetByteSize(); + + float GetExposureTimeSeconds(); + + string GetInformation(); + + float GetLayerHeight(); + + float GetNormalExposure(); + + int GetNumberOfLayers(); + + float GetOffTimeSeconds(); + + int GetPrintTimeSeconds(); + + int GetResolutionX(); + + int GetResolutionY(); + + int GetVersion(); + + bool HasAA(); + + bool IsMirrored(); + + void SetAALevels(int levels, List layers); + + void SetBottomLayers(int bottomLayers); + + void SetExposureBottomTimeSeconds(float exposureBottomTimeSeconds); + + void SetExposureTimeSeconds(float exposureTimeSeconds); + + void SetFileVersion(int i); + + void SetOffTimeSeconds(float offTimeSeconds); + + void UnLink(); + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonAaMatrix.cs b/MatterControl.SLA/Photon/Parts/PhotonAaMatrix.cs new file mode 100644 index 000000000..e42f26b2d --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonAaMatrix.cs @@ -0,0 +1,118 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Photon.Parts +{ + public class PhotonAaMatrix + { + public int[,] aaMatrix = new int[5, 5]; + private readonly bool[] hasDivisor = new bool[5]; + + public int[,] Calc(int[,] source) + { + int[,] target = null; + + if (source != null) + { + target = (int[,])source.Clone(); + + int divisor = 0; + for (int y = 0; y < 5; y++) + { + int rowDivistor = 0; + for (int x = 0; x < 5; x++) + { + rowDivistor += aaMatrix[y, x]; + } + hasDivisor[y] = (rowDivistor > 0); + divisor += rowDivistor; + } + + if (divisor > 0) + { + int height = source.Length; + if (height > 0) + { + int width = source.GetLength(0); + if (width > 0) + { + int sum; ; + int dy; + int dx; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + sum = 0; + for (int cy = -2; cy <= 2; cy++) + { + if (hasDivisor[2 + cy]) + for (int cx = -2; cx <= 2; cx++) + { + dy = y + cy; + dx = x + cx; + if (dy >= 0 && dy < height) + { + if (dx >= 0 && dx < width) + { + sum += source[dy, dx] * aaMatrix[2 + cy, 2 + cx]; + } + else + { + sum += source[y, x] * aaMatrix[2 + cy, 2 + cx]; + } + } + else + { + sum += source[y, x] * aaMatrix[2 + cy, 2 + cx]; + } + } + } + target[y, x] = sum / divisor; + } + } + } + } + } + } + return target; + } + + public void Clear() + { + for (int y = 0; y < 5; y++) + { + for (int x = 0; x < 5; x++) + { + aaMatrix[y, x] = 0; + } + } + } + + public void Set(int x, int y, int val) + { + aaMatrix[y - 1, x - 1] = val; + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonDot.cs b/MatterControl.SLA/Photon/Parts/PhotonDot.cs new file mode 100644 index 000000000..8504a6491 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonDot.cs @@ -0,0 +1,66 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * by bn on 02/07/2018. + */ + +namespace Photon.Parts +{ + public class PhotonDot + { + public int x; + public int y; + + public PhotonDot(int x, int y) + { + this.x = x; + this.y = y; + } + + override public bool Equals(object o) + { + if (this == o) + { + return true; + } + + if (!(o is PhotonDot)) + { + return false; + } + + var photonDot = (PhotonDot)o; + + return x == photonDot.x && y == photonDot.y; + } + + public override int GetHashCode() + { + int result = x; + result = 31 * result + y; + return result; + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonFileHeader.cs b/MatterControl.SLA/Photon/Parts/PhotonFileHeader.cs new file mode 100644 index 000000000..00737f5b7 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonFileHeader.cs @@ -0,0 +1,401 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.Collections.Generic; +using System.IO; + +/** +* by bn on 30/06/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonFileHeader : IFileHeader + { + public PhotonFileMachineInfo photonFileMachineInfo; + public PhotonFilePrintParameters photonFilePrintParameters; + private int antiAliasingLevel; + private readonly float bedXmm; + private readonly float bedYmm; + private readonly float bedZmm; + private int bottomLayers; + private short bottomLightPWM; + private float exposureBottomTimeSeconds; + private float exposureTimeSeconds; + private readonly int header1; + private readonly float layerHeightMilimeter; + private int layersDefinitionOffsetAddress; + private short lightPWM; + private int machineInfoOffsetAddress; + private readonly int machineInfoSize; + private readonly int numberOfLayers; + private float offTimeSeconds; + private int previewOneOffsetAddress; + private int previewTwoOffsetAddress; + private int printParametersOffsetAddress; + private readonly int printParametersSize; + private readonly int printTimeSeconds; + private readonly PhotonProjectType projectType; + private readonly int resolutionX; + private readonly int resolutionY; + private readonly int unknown1; + private readonly int unknown2; + private readonly int unknown3; + private readonly int unknown4; + private int version; + + public PhotonFileHeader(byte[] fileContent) + { + var reader = new BinaryReader(new MemoryStream(fileContent)); + + header1 = reader.ReadInt32(); + version = reader.ReadInt32(); + + bedXmm = reader.ReadSingle(); + bedYmm = reader.ReadSingle(); + bedZmm = reader.ReadSingle(); + + unknown1 = reader.ReadInt32(); + unknown2 = reader.ReadInt32(); + unknown3 = reader.ReadInt32(); + + layerHeightMilimeter = reader.ReadSingle(); + exposureTimeSeconds = reader.ReadSingle(); + exposureBottomTimeSeconds = reader.ReadSingle(); + + offTimeSeconds = reader.ReadSingle(); + bottomLayers = reader.ReadInt32(); + + resolutionX = reader.ReadInt32(); + resolutionY = reader.ReadInt32(); + + previewOneOffsetAddress = reader.ReadInt32(); + layersDefinitionOffsetAddress = reader.ReadInt32(); + + numberOfLayers = reader.ReadInt32(); + + previewTwoOffsetAddress = reader.ReadInt32(); + printTimeSeconds = reader.ReadInt32(); + + projectType = (PhotonProjectType)reader.ReadInt32(); + + printParametersOffsetAddress = reader.ReadInt32(); + printParametersSize = reader.ReadInt32(); + antiAliasingLevel = reader.ReadInt32(); + + lightPWM = reader.ReadInt16(); + bottomLightPWM = reader.ReadInt16(); + + unknown4 = reader.ReadInt32(); + machineInfoOffsetAddress = reader.ReadInt32(); + if (version > 1) + { + machineInfoSize = reader.ReadInt32(); + } + } + + public int GetAALevels() + { + if (GetVersion() > 1) + { + return GetAntiAliasingLevel(); + } + return 1; + } + + public int GetAntiAliasingLevel() + { + return antiAliasingLevel; + } + + public float GetBottomExposureTimeSeconds() + { + return exposureBottomTimeSeconds; + } + + public int GetBottomLayers() + { + return bottomLayers; + } + + public float GetBuildAreaX() + { + return bedXmm; + } + + public float GetBuildAreaY() + { + return bedYmm; + } + + public int GetByteSize() + { + return 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 2 + 2 + 4 + 4 + (version > 1 ? 4 : 0); + } + + public float GetExposureTimeSeconds() + { + return exposureTimeSeconds; + } + + public string GetInformation() + { + return string.Format("T: %.3f", layerHeightMilimeter) + + ", E: " + exposureTimeSeconds + + ", O: " + offTimeSeconds + + ", BE: " + exposureBottomTimeSeconds + + string.Format(", BL: %d", bottomLayers); + } + + public float GetLayerHeight() + { + return layerHeightMilimeter; + } + + public int GetLayersDefinitionOffsetAddress() + { + return layersDefinitionOffsetAddress; + } + + public int GetMachineInfoOffsetAddress() + { + return machineInfoOffsetAddress; + } + + public int GetMachineInfoSize() + { + return machineInfoSize; + } + + public float GetNormalExposure() + { + return exposureTimeSeconds; + } + + public int GetNumberOfLayers() + { + return numberOfLayers; + } + + public float GetOffTime() + { + return offTimeSeconds; + } + + public float GetOffTimeSeconds() + { + return offTimeSeconds; + } + + public int GetPreviewOneOffsetAddress() + { + return previewOneOffsetAddress; + } + + public int GetPreviewTwoOffsetAddress() + { + return previewTwoOffsetAddress; + } + + public int GetPrintParametersOffsetAddress() + { + return printParametersOffsetAddress; + } + + public int GetPrintParametersSize() + { + return printParametersSize; + } + + public int GetPrintTimeSeconds() + { + return printTimeSeconds; + } + + public int GetResolutionX() + { + return resolutionX; + } + + public int GetResolutionY() + { + return resolutionY; + } + + public int GetVersion() + { + return version; + } + + public bool HasAA() + { + return (GetVersion() > 1 && GetAntiAliasingLevel() > 1); + } + + public bool IsMirrored() + { + return projectType == PhotonProjectType.lcdMirror; + } + + public void ReadParameters(byte[] file) + { + photonFilePrintParameters = new PhotonFilePrintParameters(GetPrintParametersOffsetAddress(), file); + photonFileMachineInfo = new PhotonFileMachineInfo(GetMachineInfoOffsetAddress(), GetMachineInfoSize(), file); + } + + public void Save(BinaryWriter os, int previewOnePos, int previewTwoPos, int layerDefinitionPos, int parametersPos, int machineInfoPos) + { + previewOneOffsetAddress = previewOnePos; + previewTwoOffsetAddress = previewTwoPos; + layersDefinitionOffsetAddress = layerDefinitionPos; + printParametersOffsetAddress = parametersPos; + machineInfoOffsetAddress = machineInfoPos; + + os.Write(header1); + os.Write(version); + + os.Write(bedXmm); + os.Write(bedYmm); + os.Write(bedZmm); + + os.Write(unknown1); + os.Write(unknown2); + os.Write(unknown3); + + os.Write(layerHeightMilimeter); + os.Write(exposureTimeSeconds); + os.Write(exposureBottomTimeSeconds); + + os.Write(offTimeSeconds); + os.Write(bottomLayers); + + os.Write(resolutionX); + os.Write(resolutionY); + + os.Write(previewOneOffsetAddress); + os.Write(layersDefinitionOffsetAddress); + + os.Write(numberOfLayers); + + os.Write(previewTwoOffsetAddress); + os.Write(printTimeSeconds); + + os.Write((int)projectType); + + os.Write(printParametersOffsetAddress); + os.Write(printParametersSize); + os.Write(antiAliasingLevel); + + os.Write(lightPWM); + os.Write(bottomLightPWM); + + os.Write(unknown4); + os.Write(machineInfoOffsetAddress); + if (version > 1) + { + os.Write(machineInfoSize); + } + } + + public void SetAALevels(int levels, List layers) + { + if (GetVersion() > 1) + { + if (levels < GetAntiAliasingLevel()) + { + ReduceAaLevels(levels, layers); + } + if (levels > GetAntiAliasingLevel()) + { + IncreaseAaLevels(levels, layers); + } + } + } + + public void SetAntiAliasingLevel(int antiAliasingLevel) + { + this.antiAliasingLevel = antiAliasingLevel; + } + + public void SetBottomLayers(int bottomLayers) + { + this.bottomLayers = bottomLayers; + } + + public void SetExposureBottomTimeSeconds(float exposureBottomTimeSeconds) + { + this.exposureBottomTimeSeconds = exposureBottomTimeSeconds; + } + + public void SetExposureTimeSeconds(float exposureTimeSeconds) + { + this.exposureTimeSeconds = exposureTimeSeconds; + } + + public void SetFileVersion(int i) + { + version = i; + antiAliasingLevel = 1; + lightPWM = 255; + bottomLightPWM = 255; + + photonFilePrintParameters = new PhotonFilePrintParameters(GetBottomLayers()); + } + + public void SetOffTimeSeconds(float offTimeSeconds) + { + this.offTimeSeconds = offTimeSeconds; + } + + public void UnLink() + { + } + + private void IncreaseAaLevels(int levels, List layers) + { + // insert base layer to the correct count, as we are to recalculate the AA anyway + foreach (var photonFileLayer in layers) + { + while (photonFileLayer.GetAntiAlias().Count < (levels - 1)) + { + photonFileLayer.GetAntiAlias().Add(new PhotonFileLayer(photonFileLayer, this)); + } + } + SetAntiAliasingLevel(levels); + } + + private void ReduceAaLevels(int levels, List layers) + { + // delete any layers to the correct count, as we are to recalculate the AA anyway + foreach (var photonFileLayer in layers) + { + while (photonFileLayer.GetAntiAlias().Count > (levels - 1)) + { + photonFileLayer.GetAntiAlias().RemoveAt(0); + } + } + SetAntiAliasingLevel(levels); + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonFileLayer.cs b/MatterControl.SLA/Photon/Parts/PhotonFileLayer.cs new file mode 100644 index 000000000..5547d9fcd --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonFileLayer.cs @@ -0,0 +1,593 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; + +/** +* by bn on 01/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonFileLayer + { + public bool isCalculated; + private readonly List antiAliasLayers = new List(); + private int dataAddress; + private int dataSize; + private bool extendsMargin; + private byte[] imageData; + private List islandRows; + private int isLandsCount; + private float layerExposure; + private float layerOffTimeSeconds; + private float layerPositionZ; + private byte[] packedLayerImage; + private PhotonFileHeader photonFileHeader; + private long pixels; + private readonly int unknown1; + private readonly int unknown2; + private readonly int unknown3; + private readonly int unknown4; + + public PhotonFileLayer(PhotonFileLayer photonFileLayer, PhotonFileHeader photonFileHeader) + { + layerPositionZ = photonFileLayer.layerPositionZ; + layerExposure = photonFileLayer.layerExposure; + layerOffTimeSeconds = photonFileLayer.layerOffTimeSeconds; + dataAddress = photonFileLayer.dataAddress; + dataAddress = photonFileLayer.dataSize; + + this.photonFileHeader = photonFileHeader; + + // Dont copy data, we are building new AA layers anyway + //this.imageData = copy(); + //this.packedLayerImage = copy(); + } + + private PhotonFileLayer(BinaryReader ds) + { + layerPositionZ = ds.ReadSingle(); + layerExposure = ds.ReadSingle(); + layerOffTimeSeconds = ds.ReadSingle(); + + dataAddress = ds.ReadInt32(); + dataSize = ds.ReadInt32(); + + unknown1 = ds.ReadInt32(); + unknown2 = ds.ReadInt32(); + unknown3 = ds.ReadInt32(); + unknown4 = ds.ReadInt32(); + } + + public static void CalculateAALayers(PhotonFileHeader photonFileHeader, List layers, PhotonAaMatrix photonAaMatrix, Action reportProgress) + { + var photonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + int[,] source = new int[photonFileHeader.GetResolutionY(), photonFileHeader.GetResolutionX()]; + + int i = 0; + foreach (var layer in layers) + { + List unpackedImage = layer.UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + + reportProgress?.Invoke("Calculating AA for photon file layer " + i + "/" + photonFileHeader.GetNumberOfLayers()); + + for (int y = 0; y < photonFileHeader.GetResolutionY(); y++) + { + for (int x = 0; x < photonFileHeader.GetResolutionX(); x++) + { + source[y, x] = 0; + } + } + + for (int y = 0; y < unpackedImage.Count; y++) + { + BitArray currentRow = unpackedImage[y]; + if (currentRow != null) + { + for (int x = 0; x < currentRow.Length; x++) + { + if (currentRow[x]) + { + source[y, x] = 255; + } + } + } + } + + // Calc + int[,] target = photonAaMatrix.Calc(source); + + int aaTresholdDiff = 255 / photonFileHeader.GetAntiAliasingLevel(); + int aaTreshold = 0; + foreach (var aaFileLayer in layer.antiAliasLayers) + { + photonLayer.Clear(); + aaTreshold += aaTresholdDiff; + + for (int y = 0; y < photonFileHeader.GetResolutionY(); y++) + { + for (int x = 0; x < photonFileHeader.GetResolutionX(); x++) + { + if (target[y, x] >= aaTreshold) + { + photonLayer.Supported(x, y); + } + } + } + + aaFileLayer.SaveLayer(photonLayer); + } + + i++; + } + photonLayer.UnLink(); + } + + public static void CalculateLayers(PhotonFileHeader photonFileHeader, List layers, int margin, Action reportProgress) + { + var photonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + List previousUnpackedImage = null; + for (int i=0; i unpackedImage = layer.UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + + reportProgress?.Invoke("Calculating photon file layer " + i + "/" + photonFileHeader.GetNumberOfLayers()); + + if (margin > 0) + { + layer.extendsMargin = layer.CheckMargin(unpackedImage, margin); + } + + layer.UnknownPixels(unpackedImage, photonLayer); + + layer.Calculate(unpackedImage, previousUnpackedImage, photonLayer); + + if (previousUnpackedImage != null) + { + previousUnpackedImage.Clear(); + } + previousUnpackedImage = unpackedImage; + + layer.packedLayerImage = photonLayer.PackLayerImage(); + layer.isCalculated = true; + + if (photonFileHeader.GetVersion() > 1) + { + foreach (var aaFileLayer in layer.antiAliasLayers) + { + List aaUnpackedImage = aaFileLayer.UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + var aaPhotonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + aaFileLayer.UnknownPixels(aaUnpackedImage, aaPhotonLayer); + aaFileLayer.packedLayerImage = aaPhotonLayer.PackLayerImage(); + aaFileLayer.isCalculated = false; + } + } + } + photonLayer.UnLink(); + } + + public static void CalculateLayers(PhotonFileHeader photonFileHeader, List layers, int margin, int layerIndex) + { + var photonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + List previousUnpackedImage = null; + + if (layerIndex > 0) + { + previousUnpackedImage = layers[layerIndex - 1].UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + } + + for (int i = 0; i < 2; i++) + { + PhotonFileLayer layer = layers[layerIndex + i]; + List unpackedImage = layer.UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + + if (margin > 0) + { + layer.extendsMargin = layer.CheckMargin(unpackedImage, margin); + } + + layer.UnknownPixels(unpackedImage, photonLayer); + + layer.Calculate(unpackedImage, previousUnpackedImage, photonLayer); + + if (previousUnpackedImage != null) + { + previousUnpackedImage.Clear(); + } + previousUnpackedImage = unpackedImage; + + layer.packedLayerImage = photonLayer.PackLayerImage(); + layer.isCalculated = true; + + i++; + } + photonLayer.UnLink(); + } + + public static int GetByteSize() + { + return 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4; + } + + public static List ReadLayers(PhotonFileHeader photonFileHeader, byte[] fileContent, int margin, Action reportProgress) + { + var photonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + + var layers = new List(); + + int antiAliasLevel = 1; + if (photonFileHeader.GetVersion() > 1) + { + antiAliasLevel = photonFileHeader.GetAntiAliasingLevel(); + } + + int layerCount = photonFileHeader.GetNumberOfLayers(); + + var start = photonFileHeader.GetLayersDefinitionOffsetAddress(); + var ds = new BinaryReader(new MemoryStream(fileContent, start, fileContent.Length - start)); + { + var layerMap = new Dictionary(); + for (int i = 0; i < layerCount; i++) + { + reportProgress?.Invoke("Reading photon file layer " + (i + 1) + "/" + photonFileHeader.GetNumberOfLayers()); + + var layer = new PhotonFileLayer(ds) + { + photonFileHeader = photonFileHeader + }; + layer.imageData = ArraysEmulation.CopyOfRange(fileContent, layer.dataAddress, layer.dataAddress + layer.dataSize); + layers.Add(layer); + layerMap[i] = layer; + } + + if (antiAliasLevel > 1) + { + for (int a = 0; a < (antiAliasLevel - 1); a++) + { + for (int i = 0; i < layerCount; i++) + { + reportProgress?.Invoke("Reading photon file AA " + (2 + a) + "/" + antiAliasLevel + " layer " + (i + 1) + "/" + photonFileHeader.GetNumberOfLayers()); + + var layer = new PhotonFileLayer(ds) + { + photonFileHeader = photonFileHeader + }; + layer.imageData = ArraysEmulation.CopyOfRange(fileContent, layer.dataAddress, layer.dataAddress + layer.dataSize); + + layerMap[i].AddAntiAliasLayer(layer); + } + } + } + } + + photonLayer.UnLink(); + + return layers; + } + + public bool DoExtendMargin() + { + return extendsMargin; + } + + public PhotonFileLayer GetAntiAlias(int a) + { + if (antiAliasLayers.Count > a) + { + return antiAliasLayers[a]; + } + return null; + } + + public List GetAntiAlias() + { + return antiAliasLayers; + } + + public List GetIslandRows() + { + return islandRows; + } + + public int GetIsLandsCount() + { + return isLandsCount; + } + + public PhotonLayer GetLayer() + { + var photonLayer = new PhotonLayer(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + photonLayer.UnpackLayerImage(packedLayerImage); + return photonLayer; + } + + public float GetLayerExposure() + { + return layerExposure; + } + + public float GetLayerOffTime() + { + return layerOffTimeSeconds; + } + + public float GetLayerPositionZ() + { + return layerPositionZ; + } + + public long GetPixels() + { + return pixels; + } + + public List GetRows() + { + return PhotonLayer.GetRows(packedLayerImage, photonFileHeader.GetResolutionX(), isCalculated); + } + + public List GetUnknownRows() + { + return UnpackImage(photonFileHeader.GetResolutionX(), photonFileHeader.GetResolutionY()); + } + + public void GetUpdateLayer(PhotonLayer photonLayer) + { + photonLayer.UnpackLayerImage(packedLayerImage); + } + + public void Save(BinaryWriter writer) + { + writer.Write(layerPositionZ); + writer.Write(layerExposure); + writer.Write(layerOffTimeSeconds); + + writer.Write(dataAddress); + writer.Write(dataSize); + + writer.Write(unknown1); + writer.Write(unknown2); + writer.Write(unknown3); + writer.Write(unknown4); + } + + public void SaveData(BinaryWriter writer) + { + writer.Write(imageData, 0, dataSize); + } + + public void SaveLayer(PhotonLayer photonLayer) + { + this.packedLayerImage = photonLayer.PackLayerImage(); + this.imageData = photonLayer.PackImageData(); + this.dataSize = imageData.Length; + islandRows = new List(); + isLandsCount = photonLayer.SetIslands(islandRows); + } + + public int SavePos(int dataPosition) + { + dataAddress = dataPosition; + return dataPosition + dataSize; + } + + public void SetLayerExposure(float layerExposure) + { + this.layerExposure = layerExposure; + } + + public void SetLayerOffTimeSeconds(float layerOffTimeSeconds) + { + this.layerOffTimeSeconds = layerOffTimeSeconds; + } + + public void SetLayerPositionZ(float layerPositionZ) + { + this.layerPositionZ = layerPositionZ; + } + + public void UnLink() + { + imageData = null; + packedLayerImage = null; + if (islandRows != null) + { + islandRows.Clear(); + } + photonFileHeader = null; + } + + public List UnpackImage(int resolutionX, int resolutionY) + { + pixels = 0; + resolutionX -= 1; + var unpackedImage = new List(resolutionY); + var currentRow = new BitArray(resolutionX); + unpackedImage.Add(currentRow); + int x = 0; + foreach (var rle in imageData) + { + int length = rle & 0x7F; + bool color = (rle & 0x80) == 0x80; + if (color) + { + pixels += length; + } + int endPosition = x + (length - 1); + int lineEnd = Math.Min(endPosition, resolutionX); + if (color) + { + currentRow.Set(x, 1 + lineEnd); + } + if (endPosition > resolutionX) + { + currentRow = new BitArray(resolutionX); + unpackedImage.Add(currentRow); + lineEnd = endPosition - (resolutionX + 1); + if (color) + { + currentRow.Set(0, 1 + lineEnd); + } + } + x = lineEnd + 1; + if (x > resolutionX) + { + currentRow = new BitArray(resolutionX); + unpackedImage.Add(currentRow); + x = 0; + } + } + return unpackedImage; + } + + public void UpdateLayerIslands(PhotonLayer photonLayer) + { + islandRows = new List(); + isLandsCount = photonLayer.SetIslands(islandRows); + } + + private void AaPixels(List unpackedImage, PhotonLayer photonLayer) + { + photonLayer.Clear(); + + for (int y = 0; y < unpackedImage.Count; y++) + { + BitArray currentRow = unpackedImage[y]; + if (currentRow != null) + { + for (int x = 0; x < currentRow.Length; x++) + { + if (currentRow[x]) + { + photonLayer.UnSupported(x, y); + } + } + } + } + } + + private void AddAntiAliasLayer(PhotonFileLayer layer) + { + antiAliasLayers.Add(layer); + } + + private void Calculate(List unpackedImage, List previousUnpackedImage, PhotonLayer photonLayer) + { + islandRows = new List(); + isLandsCount = 0; + + photonLayer.Clear(); + + for (int y = 0; y < unpackedImage.Count; y++) + { + BitArray currentRow = unpackedImage[y]; + BitArray prevRow = previousUnpackedImage?[y]; + if (currentRow != null) + { + int x = 0; + while ((x = currentRow.NextSetBit(x)) >= 0) + { + if (prevRow == null || prevRow[x]) + { + photonLayer.Supported(x, y); + } + else + { + photonLayer.Island(x, y); + } + ++x; + } + } + } + + photonLayer.Reduce(); + + isLandsCount = photonLayer.SetIslands(islandRows); + } + + private bool CheckMargin(List unpackedImage, int margin) + { + if (unpackedImage.Count > margin) + { + // check top margin rows + for (int i = 0; i < margin; i++) + { + if (unpackedImage[i].Count > 0) + { + return true; + } + } + // check bottom margin rows + for (int i = unpackedImage.Count - margin; i < unpackedImage.Count; i++) + { + if (unpackedImage[i].Count > 0) + { + return true; + } + } + + for (int i = margin; i < unpackedImage.Count - margin; i++) + { + BitArray row = unpackedImage[i]; + int nextBit = row.NextSetBit(0); + if (nextBit >= 0 && nextBit < margin) + { + return true; + } + nextBit = row.NextSetBit(photonFileHeader.GetResolutionX() - margin); + if (nextBit > photonFileHeader.GetResolutionX() - margin) + { + return true; + } + } + } + return false; + } + + private void UnknownPixels(List unpackedImage, PhotonLayer photonLayer) + { + photonLayer.Clear(); + + for (int y = 0; y < unpackedImage.Count; y++) + { + BitArray currentRow = unpackedImage[y]; + if (currentRow != null) + { + int x = 0; + while ((x = currentRow.NextSetBit(x)) >= 0) + { + photonLayer.Supported(x, y); + ++x; + } + } + } + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonFileMachineInfo.cs b/MatterControl.SLA/Photon/Parts/PhotonFileMachineInfo.cs new file mode 100644 index 000000000..961b37d66 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonFileMachineInfo.cs @@ -0,0 +1,115 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.IO; + +/** +* by bn on 01/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonFileMachineInfo + { + private readonly int infoByteSize; + private readonly byte[] machineName = { }; + private readonly int machineNameAddress; + private readonly int machineNameSize; + private readonly int u1, u2, u3, u4, u5, u6, u7; + private readonly int u8, u9, u10, u11, u12, u13, u14, u15, u16, u17; + + public PhotonFileMachineInfo(int address, int byteSize, byte[] file) + { + this.infoByteSize = byteSize; + + if (byteSize > 0) + { + byte[] data = ArraysEmulation.CopyOfRange(file, address, address + byteSize); + + var ds = new BinaryReader(new MemoryStream(data)); + { + u1 = ds.ReadInt32(); + u2 = ds.ReadInt32(); + u3 = ds.ReadInt32(); + u4 = ds.ReadInt32(); + u5 = ds.ReadInt32(); + u6 = ds.ReadInt32(); + u7 = ds.ReadInt32(); + + machineNameAddress = ds.ReadInt32(); + machineNameSize = ds.ReadInt32(); + + u8 = ds.ReadInt32(); + u9 = ds.ReadInt32(); + u10 = ds.ReadInt32(); + u11 = ds.ReadInt32(); + u12 = ds.ReadInt32(); + u13 = ds.ReadInt32(); + u14 = ds.ReadInt32(); + u15 = ds.ReadInt32(); + u16 = ds.ReadInt32(); + u17 = ds.ReadInt32(); + } + + machineName = ArraysEmulation.CopyOfRange(file, machineNameAddress, machineNameAddress + machineNameSize); + } + } + + public int GetByteSize() + { + return infoByteSize + machineName.Length; + } + + public void Save(BinaryWriter os, int startAddress) + { + if (infoByteSize > 0) + { + os.Write(u1); + os.Write(u2); + os.Write(u3); + os.Write(u4); + os.Write(u5); + os.Write(u6); + os.Write(u7); + os.Write(startAddress + infoByteSize); + os.Write(machineName.Length); + os.Write(u8); + os.Write(u9); + os.Write(u10); + os.Write(u11); + os.Write(u12); + os.Write(u13); + os.Write(u14); + os.Write(u15); + os.Write(u16); + os.Write(u17); + os.Write(machineName); + } + } + + public void UnLink() + { + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonFilePreview.cs b/MatterControl.SLA/Photon/Parts/PhotonFilePreview.cs new file mode 100644 index 000000000..7480efe04 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonFilePreview.cs @@ -0,0 +1,133 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.IO; + +/** +* by bn on 01/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonFilePreview + { + private readonly int dataSize; + private readonly int imageAddress; + private int[] imageData; + private readonly int p1; + private readonly int p2; + private readonly int p3; + private readonly int p4; + private byte[] rawImageData; + private readonly int resolutionX; + private readonly int resolutionY; + + public PhotonFilePreview(int previewAddress, byte[] file) + { + byte[] data = ArraysEmulation.CopyOfRange(file, previewAddress, previewAddress + 32); + var ds = new BinaryReader(new MemoryStream(data)); + + resolutionX = ds.ReadInt32(); + resolutionY = ds.ReadInt32(); + imageAddress = ds.ReadInt32(); + dataSize = ds.ReadInt32(); + p1 = ds.ReadInt32(); + p2 = ds.ReadInt32(); + p3 = ds.ReadInt32(); + p4 = ds.ReadInt32(); + + rawImageData = ArraysEmulation.CopyOfRange(file, imageAddress, imageAddress + dataSize); + + DecodeImageData(); + } + + public int GetByteSize() + { + return 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + dataSize; + } + + public int[] GetImageData() + { + return imageData; + } + + public int GetResolutionX() + { + return resolutionX; + } + + public int GetResolutionY() + { + return resolutionY; + } + + public void Save(BinaryWriter os, int startAddress) + { + os.Write(resolutionX); + os.Write(resolutionY); + os.Write(startAddress + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4); + os.Write(dataSize); + os.Write(p1); + os.Write(p2); + os.Write(p3); + os.Write(p4); + os.Write(rawImageData, 0, dataSize); + } + + public void UnLink() + { + rawImageData = null; + imageData = null; + } + + private void DecodeImageData() + { + imageData = new int[resolutionX * resolutionY]; + int d = 0; + for (int i = 0; i < dataSize; i++) + { + int dot = rawImageData[i] & 0xFF | ((rawImageData[++i] & 0xFF) << 8); + + int color = ((dot & 0xF800) << 8) | ((dot & 0x07C0) << 5) | ((dot & 0x001F) << 3); + + // int red = ((dot >> 11) & 0x1F) << 3; + // int green = ((dot >> 6) & 0x1F) << 3; + // int blue = (dot & 0x1F) << 3; + // color = red<<16 | green<<8 | blue; + + int repeat = 1; + if ((dot & 0x0020) == 0x0020) + { + repeat += rawImageData[++i] & 0xFF | ((rawImageData[++i] & 0x0F) << 8); + } + + while (repeat > 0) + { + imageData[d++] = color; + repeat--; + } + } + } + } +} diff --git a/MatterControl.SLA/Photon/Parts/PhotonFilePrintParameters.cs b/MatterControl.SLA/Photon/Parts/PhotonFilePrintParameters.cs new file mode 100644 index 000000000..348cba6e7 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonFilePrintParameters.cs @@ -0,0 +1,108 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.IO; + +namespace Photon.Parts +{ + public class PhotonFilePrintParameters + { + public int bottomLayerCount; + public float bottomLiftDistance = 5.0f; + public float bottomLiftSpeed = 300.0f; + + public float bottomLightOffDelay = 0.0f; + public float costDollars = 0; + public float liftingDistance = 5.0f; + public float liftingSpeed = 300.0f; + public float lightOffDelay = 0.0f; + public int p1; + public int p2; + public int p3; + public int p4; + public float retractSpeed = 300.0f; + + public float volumeMl = 0; + public float weightG = 0; + + public PhotonFilePrintParameters(int bottomLayerCount) + { + this.bottomLayerCount = bottomLayerCount; + } + + public PhotonFilePrintParameters(int parametersPos, byte[] file) + { + byte[] data = ArraysEmulation.CopyOfRange(file, parametersPos, parametersPos + GetByteSize()); + var ds = new BinaryReader(new MemoryStream(data)); + + bottomLiftDistance = ds.ReadSingle(); + bottomLiftSpeed = ds.ReadSingle(); + + liftingDistance = ds.ReadSingle(); + liftingSpeed = ds.ReadSingle(); + retractSpeed = ds.ReadSingle(); + + volumeMl = ds.ReadSingle(); + weightG = ds.ReadSingle(); + costDollars = ds.ReadSingle(); + + bottomLightOffDelay = ds.ReadSingle(); + lightOffDelay = ds.ReadSingle(); + bottomLayerCount = ds.ReadInt32(); + + p1 = ds.ReadInt32(); + p2 = ds.ReadInt32(); + p3 = ds.ReadInt32(); + p4 = ds.ReadInt32(); + } + + public int GetByteSize() + { + return 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4; + } + + public void Save(BinaryWriter os) + { + os.Write(bottomLiftDistance); + os.Write(bottomLiftSpeed); + + os.Write(liftingDistance); + os.Write(liftingSpeed); + os.Write(retractSpeed); + + os.Write(volumeMl); + os.Write(weightG); + os.Write(costDollars); + + os.Write(bottomLightOffDelay); + os.Write(lightOffDelay); + os.Write(bottomLayerCount); + + os.Write(p1); + os.Write(p2); + os.Write(p3); + os.Write(p4); + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonLayer.cs b/MatterControl.SLA/Photon/Parts/PhotonLayer.cs new file mode 100644 index 000000000..51465a2c7 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonLayer.cs @@ -0,0 +1,536 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using MatterHackers.Agg; +using System.Collections; +using System.Collections.Generic; + +/** +* by bn on 02/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonLayer + { + public static readonly byte CONNECTED = 0x03; + public static readonly byte ISLAND = 0x02; + public static readonly byte OFF = 0x00; + public static readonly byte SUPPORTED = 0x01; + private static int[] emptyCol; + private static byte[] emptyRow; + private static byte[] scratchPad; + private readonly int height; + private byte[][] iArray; + private int islandCount = 0; + private int[] pixels; + private int[] rowIslands; + private readonly int width; + + public PhotonLayer(int width, int height) + { + this.width = width; + this.height = height; + + iArray = new byte[height][]; + for (int i = 0; i < height; i++) + { + iArray[i] = new byte[width]; + } + pixels = new int[height]; + rowIslands = new int[height]; + + if (emptyRow == null || emptyRow.Length < width) + { + emptyRow = new byte[width]; + } + + if (emptyCol == null || emptyCol.Length < height) + { + emptyCol = new int[height]; + } + + if (scratchPad == null || scratchPad.Length < width * height) + { + scratchPad = new byte[width * height]; + } + } + + public static List GetRows(byte[] packedLayerImage, int width, bool isCalculated) + { + var colors = new Dictionary + { + { OFF, Color.Black } + }; + if (isCalculated) + { + colors.Add(SUPPORTED, new Color("#008800")); + } + else + { + colors.Add(SUPPORTED, new Color("#000088")); + } + colors.Add(CONNECTED, new Color("#FFFF00")); + colors.Add(ISLAND, new Color("#FF0000")); + var rows = new List(); + int resolutionX = width - 1; + var currentRow = new PhotonRow(); + rows.Add(currentRow); + int x = 0; + if (packedLayerImage != null) + { // when user tries to show a layer before its calculated + for (int i = 0; i < packedLayerImage.Length; i++) + { + byte rle = packedLayerImage[i]; + byte colorCode = (byte)((rle & 0x60) >> 5); + Color color = colors[colorCode]; + bool extended = (rle & 0x80) == 0x80; + int length = rle & 0x1F; + if (extended) + { + i++; + length = (length << 8) | packedLayerImage[i] & 0x00ff; + } + currentRow.lines.Add(new PhotonLine(color, length)); + x += length; + + if (x >= resolutionX) + { + currentRow = new PhotonRow(); + rows.Add(currentRow); + x = 0; + } + } + } + return rows; + } + + public void Clear() + { + for (int y = 0; y < height; y++) + { + ArraysEmulation.Arraycopy(emptyRow, 0, iArray[y], 0, width); + } + ArraysEmulation.Arraycopy(emptyCol, 0, pixels, 0, height); + ArraysEmulation.Arraycopy(emptyCol, 0, rowIslands, 0, height); + } + + public int Fixlayer() + { + var photonMatix = new PhotonMatix(); + var dots = new List(); + if (islandCount > 0) + { + for (int y = 0; y < height; y++) + { + if (rowIslands[y] > 0) + { + for (int x = 0; x < width; x++) + { + if (iArray[y][x] == ISLAND) + { + photonMatix.Clear(); + int blanks = photonMatix.Set(x, y, iArray, width, height); + if (blanks > 0) + { // one or more neighbor pixels are OFF + photonMatix.Calc(); + photonMatix.Level(); + photonMatix.Calc(); + + for (int ry = 0; ry < 3; ry++) + { + for (int rx = 0; rx < 3; rx++) + { + int iy = y - 1 + ry; + int ix = x - 1 + rx; + if (iArray[iy][ix] == OFF) + { + if (photonMatix.calcMatrix[1 + ry, 1 + rx] > 3) + { + dots.Add(new PhotonDot(ix, iy)); + } + } + } + } + } + } + } + } + } + } + foreach (var dot in dots) + { + Island(dot.x, dot.y); + } + return dots.Count; + } + + public byte Get(int x, int y) + { + return iArray[y][x]; + } + + public void Island(int x, int y) + { + iArray[y][x] = ISLAND; + rowIslands[y]++; + islandCount++; + pixels[y]++; + } + + public byte[] PackImageData() + { + int ptr = 0; + + for (int y = 0; y < height; y++) + { + if (pixels[y] == 0) + { + ptr = AddPhotonRLE(ptr, true, width); + } + else + { + byte current = OFF; + int length = 0; + for (int x = 0; x < width; x++) + { + byte next = iArray[y][x]; + if (next != current) + { + if (length > 0) + { + ptr = AddPhotonRLE(ptr, current == OFF, length); + } + current = next; + length = 1; + } + else + { + length++; + } + } + if (length > 0) + { + ptr = AddPhotonRLE(ptr, current == OFF, length); + } + } + } + byte[] img = new byte[ptr]; + ArraysEmulation.Arraycopy(scratchPad, 0, img, 0, ptr); + return img; + } + + public byte[] PackLayerImage() + { + int ptr = 0; + for (int y = 0; y < height; y++) + { + if (pixels[y] == 0) + { + ptr = Add(ptr, OFF, width); + } + else + { + byte current = OFF; + int length = 0; + for (int x = 0; x < width; x++) + { + byte next = iArray[y][x]; + if (next != current) + { + if (length > 0) + { + ptr = Add(ptr, current, length); + } + current = next; + length = 1; + } + else + { + length++; + } + } + if (length > 0) + { + ptr = Add(ptr, current, length); + } + } + } + byte[] img = new byte[ptr]; + ArraysEmulation.Arraycopy(scratchPad, 0, img, 0, ptr); + return img; + } + + public void Reduce() + { + // Double reduce to handle single line connections. + for (int i = 0; i < 2; i++) + { + if (islandCount > 0) + { + for (int y = 0; y < height; y++) + { + if (rowIslands[y] > 0) + { + for (int x = 0; x < width; x++) + { + if (iArray[y][x] == ISLAND) + { + if (Connected(x, y)) + { + MakeConnected(x, y); + CheckUp(x, y); + if (rowIslands[y] == 0) + { + break; + } + } + } + } + } + } + } + } + } + + public void Remove(int x, int y, byte type) + { + iArray[y][x] = OFF; + if (type == ISLAND) + { + rowIslands[y]--; + islandCount--; + } + + pixels[y]--; + } + + public int RemoveIslands() + { + int count = 0; + if (islandCount > 0) + { + for (int y = 0; y < height; y++) + { + if (rowIslands[y] > 0) + { + for (int x = 0; x < width; x++) + { + if (iArray[y][x] == ISLAND) + { + Remove(x, y, ISLAND); + ++count; + } + } + } + } + } + return count; + } + + public int SetIslands(List islandRows) + { + int islands = 0; + for (int y = 0; y < height; y++) + { + var bitSet = new BitArray(width - 1); + if (rowIslands[y] > 0) + { + for (int x = 0; x < width; x++) + { + if (iArray[y][x] == ISLAND) + { + bitSet[x] = true; + } + } + } + islandRows.Add(bitSet); + islands += rowIslands[y]; + } + return islands; + } + + public void Supported(int x, int y) + { + iArray[y][x] = SUPPORTED; + pixels[y]++; + } + + public void UnLink() + { + iArray = null; + pixels = null; + rowIslands = null; + } + + public void UnpackLayerImage(byte[] packedLayerImage) + { + Clear(); + int x = 0; + int y = 0; + int imageLength = packedLayerImage.Length; + for (int i = 0; i < imageLength; i++) + { + byte rle = packedLayerImage[i]; + byte colorCode = (byte)((rle & 0x60) >> 5); + + bool extended = (rle & 0x80) == 0x80; + int length = rle & 0x1F; + if (extended) + { + i++; + length = (length << 8) | packedLayerImage[i] & 0x00ff; + } + + ArraysEmulation.Fill(iArray[y], x, x + length, colorCode); + + if (colorCode == SUPPORTED) + { + pixels[y] += length; + } + else if (colorCode == CONNECTED) + { + pixels[y] += length; + } + else if (colorCode == ISLAND) + { + rowIslands[y] += length; + islandCount += length; + pixels[y] += length; + } + + x += length; + if (x >= width) + { + y++; + x = 0; + } + } + } + + public void UnSupported(int x, int y) + { + iArray[y][x] = CONNECTED; + pixels[y]++; + } + + private int Add(int ptr, byte current, int length) + { + if (length < 32) + { + scratchPad[ptr++] = (byte)((current << 5) | (length & 0x1f)); + } + else + { + scratchPad[ptr++] = (byte)(0x80 | (current << 5) | (length >> 8 & 0x00FF)); + scratchPad[ptr++] = (byte)(length & 0x00FF); + } + return ptr; + } + + private int AddPhotonRLE(int ptr, bool off, int length) + { + while (length > 0) + { + int lineLength = length < 125 ? length : 125; // max storage length of 0x7D (125) ?? Why not 127? + scratchPad[ptr++] = (byte)((off ? 0x00 : 0x80) | (lineLength & 0x7f)); + length -= lineLength; + } + + return ptr; + } + + private void CheckBackUp(int x, int y) + { + if (y > 0 && rowIslands[y - 1] > 0 && iArray[y - 1][x] == ISLAND) + { + MakeConnected(x, y - 1); + CheckBackUp(x, y - 1); + } + if (x > 0 && rowIslands[y] > 0 && iArray[y][x - 1] == ISLAND) + { + MakeConnected(x - 1, y); + CheckBackUp(x - 1, y); + } + } + + private void CheckFrontUp(int x, int y) + { + if (y > 0 && rowIslands[y - 1] > 0 && iArray[y - 1][x] == ISLAND) + { + MakeConnected(x, y - 1); + CheckFrontUp(x, y - 1); + } + if (x < (width - 1) && rowIslands[y] > 0 && iArray[y][x + 1] == ISLAND) + { + MakeConnected(x + 1, y); + CheckFrontUp(x + 1, y); + } + } + + private void CheckUp(int x, int y) + { + if (y > 0 && rowIslands[y - 1] > 0 && iArray[y - 1][x] == ISLAND) + { + MakeConnected(x, y - 1); + CheckUp(x, y - 1); + } + if (x > 0 && rowIslands[y] > 0 && iArray[y][x - 1] == ISLAND) + { + MakeConnected(x - 1, y); + CheckBackUp(x - 1, y); + } + if (x < (width - 1) && rowIslands[y] > 0 && iArray[y][x + 1] == ISLAND) + { + MakeConnected(x + 1, y); + CheckFrontUp(x + 1, y); + } + } + + private bool Connected(int x, int y) + { + return x > 0 && (iArray[y][x - 1] & 0x01) == SUPPORTED + || x < (width - 1) && (iArray[y][x + 1] & 0x01) == SUPPORTED + || y > 0 && (iArray[y - 1][x] & 0x01) == SUPPORTED + || (y < (height - 1) && (iArray[y + 1][x] & 0x01) == SUPPORTED); + } + + private void MakeConnected(int x, int y) + { + iArray[y][x] = CONNECTED; + rowIslands[y]--; + islandCount--; + } + + /** + * Get a layer image for drawing. + *

+ * This will decode the RLE packed layer information and return a list of rows, with color and length information + * + * @param packedLayerImage The packed layer image information + * @param width The width of the current layer, used to change rows + * @return A list with the + */ + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonLine.cs b/MatterControl.SLA/Photon/Parts/PhotonLine.cs new file mode 100644 index 000000000..62c825240 --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonLine.cs @@ -0,0 +1,44 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using MatterHackers.Agg; + +/** +* by bn on 10/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonLine + { + public Color color; + public int length; + + public PhotonLine(Color color, int length) + { + this.color = color; + this.length = length; + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonMatix.cs b/MatterControl.SLA/Photon/Parts/PhotonMatix.cs new file mode 100644 index 000000000..8e44a3d3c --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonMatix.cs @@ -0,0 +1,124 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * by bn on 14/07/2018. + */ + +namespace Photon.Parts +{ + public class PhotonMatix + { + public int[,] calcMatrix = new int[5, 5]; + + public void Calc() + { + int[,] temp = new int[3, 3]; + for (int yi = 0; yi < 3; yi++) + { + for (int xi = 0; xi < 3; xi++) + { + if (calcMatrix[yi + 1, xi + 1] == PhotonLayer.OFF) + { + temp[yi, xi] = Calc(xi + 1, yi + 1); + } + } + } + for (int yi = 0; yi < 3; yi++) + { + for (int xi = 0; xi < 3; xi++) + { + if (calcMatrix[yi + 1, xi + 1] == PhotonLayer.OFF) + { + calcMatrix[yi + 1, xi + 1] = temp[yi, xi]; + } + } + } + } + + public void Clear() + { + for (int y = 0; y < 5; y++) + { + for (int x = 0; x < 5; x++) + { + calcMatrix[y, x] = 0; + } + } + } + + public void Level() + { + for (int yi = 0; yi < 5; yi++) + { + for (int xi = 0; xi < 5; xi++) + { + if (calcMatrix[yi, xi] < 4) calcMatrix[yi, xi] = 0; + } + } + } + + public int Set(int x, int y, byte[][] iArray, int width, int height) + { + int blanks = 0; + int x0 = x - 2; + int y0 = y - 2; + for (int yi = 0; yi < 5; yi++) + { + for (int xi = 0; xi < 5; xi++) + { + int y2 = y0 + yi; + int x2 = x0 + xi; + if (y2 >= 0 && y2 < height && x2 >= 0 && x2 < width) + { + var value = iArray[y2][x2]; + if (value == PhotonLayer.SUPPORTED + || value == PhotonLayer.CONNECTED) + { + calcMatrix[yi, xi] = 16; + } + else if (value == PhotonLayer.ISLAND) + { + calcMatrix[yi, xi] = 4; + } + else if (value == PhotonLayer.OFF) + { + if (yi > 0 && yi < 4 && xi > 0 && xi < 4) + { + blanks++; + } + } + } + } + } + + return blanks; + } + + private int Calc(int x, int y) + { + return (calcMatrix[y - 1, x] / 4) + (calcMatrix[y, x - 1] / 4) + (calcMatrix[y, x + 1] / 4) + (calcMatrix[y + 1, x] / 4); + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonProjectType.cs b/MatterControl.SLA/Photon/Parts/PhotonProjectType.cs new file mode 100644 index 000000000..29cc9350f --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonProjectType.cs @@ -0,0 +1,36 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * by bn on 30/06/2018. + */ + +namespace Photon.Parts +{ + public enum PhotonProjectType + { + cast = 0, + lcdMirror = 1 + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/Parts/PhotonRow.cs b/MatterControl.SLA/Photon/Parts/PhotonRow.cs new file mode 100644 index 000000000..4baf64cec --- /dev/null +++ b/MatterControl.SLA/Photon/Parts/PhotonRow.cs @@ -0,0 +1,37 @@ +/* + * MIT License + * + * Copyright (c) 2018 Bonosoft, 2021 Lars Brubaker c# port + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.Collections.Generic; + +/** +* by bn on 10/07/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonRow + { + public List lines = new List(); + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Photon/PhotonFile.cs b/MatterControl.SLA/Photon/PhotonFile.cs new file mode 100644 index 000000000..53c7407ab --- /dev/null +++ b/MatterControl.SLA/Photon/PhotonFile.cs @@ -0,0 +1,610 @@ +/* + * MIT License + * + + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +/** +* by bn on 30/06/2018. +*/ + +namespace Photon.Parts +{ + public class PhotonFile + { + private IFileHeader iFileHeader; + private int islandLayerCount; + private List islandLayers; + private StringBuilder islandList; + private List layers; + private int margin; + private List marginLayers; + private PhotonFilePreview previewOne; + private PhotonFilePreview previewTwo; + + public void AdjustLayerSettings() + { + for (int i = 0; i < layers.Count; i++) + { + PhotonFileLayer layer = layers[i]; + if (i < iFileHeader.GetBottomLayers()) + { + layer.SetLayerExposure(iFileHeader.GetBottomExposureTimeSeconds()); + } + else + { + layer.SetLayerExposure(iFileHeader.GetNormalExposure()); + } + layer.SetLayerOffTimeSeconds(iFileHeader.GetOffTimeSeconds()); + } + } + + public void Calculate(Action reportProgress) + { + PhotonFileLayer.CalculateLayers((PhotonFileHeader)iFileHeader, layers, margin, reportProgress); + ResetMarginAndIslandInfo(); + } + + public void Calculate(int layerNo) + { + PhotonFileLayer.CalculateLayers((PhotonFileHeader)iFileHeader, layers, margin, layerNo); + ResetMarginAndIslandInfo(); + } + + public void CalculateAaLayers(Action reportProgress, PhotonAaMatrix photonAaMatrix) + { + PhotonFileLayer.CalculateAALayers((PhotonFileHeader)iFileHeader, layers, photonAaMatrix, reportProgress); + } + + public void ChangeToVersion2() + { + iFileHeader.SetFileVersion(2); + } + + public void FixAll(Action reportProgress) + { + bool layerWasFixed; + do + { + do + { + // Repeatedly fix layers until none are possible to fix + // Fixing some layers can make other layers auto-fixable + layerWasFixed = FixLayers(reportProgress); + } while (layerWasFixed); + if (islandLayers.Count > 0) + { + // Nothing can be done further, just remove all layers left + layerWasFixed = RemoveAllIslands(reportProgress) || layerWasFixed; + } + if (layerWasFixed && islandLayers.Count > 0) + { + // We could've created new islands by removing islands, repeat fixing process + // until everything is fixed or nothing can be done + reportProgress?.Invoke("
Some layers were fixed, but " + islandLayers.Count + " still unsupported, repeating...
"); + } + } while (layerWasFixed); + } + + public void FixLayerHeights() + { + int index = 0; + foreach (var layer in layers) + { + layer.SetLayerPositionZ(index * iFileHeader.GetLayerHeight()); + index++; + } + } + + public bool FixLayers(Action reportProgress) + { + bool layersFixed = false; + PhotonLayer layer = null; + foreach (int layerNo in islandLayers) + { + reportProgress?.Invoke("Checking layer " + layerNo); + + // Unpack the layer data to the layer utility class + PhotonFileLayer fileLayer = layers[layerNo]; + if (layer == null) + { + layer = fileLayer.GetLayer(); + } + else + { + fileLayer.GetUpdateLayer(layer); + } + + int changed = Fixit(reportProgress, layer, fileLayer, 10); + if (changed == 0) + { + reportProgress?.Invoke(", but nothing could be done."); + } + else + { + fileLayer.SaveLayer(layer); + Calculate(layerNo); + if (layerNo < GetLayerCount() - 1) + { + Calculate(layerNo + 1); + } + layersFixed = true; + } + + reportProgress?.Invoke("
"); + } + FindIslands(); + return layersFixed; + } + + public int GetAALevels() + { + return iFileHeader.GetAALevels(); + } + + public int GetHeight() + { + return iFileHeader.GetResolutionX(); + } + + public string GetInformation() + { + if (iFileHeader == null) return ""; + return iFileHeader.GetInformation(); + } + + public int GetIslandLayerCount() + { + if (islandList == null) + { + FindIslands(); + } + return islandLayerCount; + } + + public List GetIslandLayers() + { + if (islandList == null) + { + FindIslands(); + } + return islandLayers; + } + + public PhotonFileLayer GetLayer(int i) + { + if (layers != null && layers.Count > i) + { + return layers[i]; + } + return null; + } + + public int GetLayerCount() + { + return iFileHeader.GetNumberOfLayers(); + } + + public string GetLayerInformation() + { + if (islandList == null) + { + FindIslands(); + } + if (islandLayerCount == 0) + { + return "Whoopee, all is good, no unsupported areas"; + } + else if (islandLayerCount == 1) + { + return "Unsupported islands found in layer " + islandList.ToString(); + } + return "Unsupported islands found in layers " + islandList.ToString(); + } + + public string GetMarginInformation() + { + if (marginLayers == null) + { + return "No safety margin set, printing to the border."; + } + else + { + if (marginLayers.Count == 0) + { + return "The model is within the defined safety margin (" + this.margin + " pixels)."; + } + else if (marginLayers.Count == 1) + { + return "The layer " + marginLayers[0] + " contains model parts that extend beyond the margin."; + } + var marginList = new StringBuilder(); + int count = 0; + foreach (var layer in marginLayers) + { + if (count > 10) + { + marginList.Append(", ..."); + break; + } + else + { + if (marginList.Length > 0) marginList.Append(", "); + marginList.Append(layer); + } + count++; + } + return "The layers " + marginList.ToString() + " contains model parts that extend beyond the margin."; + } + } + + public List GetMarginLayers() + { + if (marginLayers == null) + { + return new List(); + } + return marginLayers; + } + + public IFileHeader GetPhotonFileHeader() + { + return iFileHeader; + } + + public long GetPixels() + { + long total = 0; + if (layers != null) + { + foreach (var layer in layers) + { + total += layer.GetPixels(); + } + } + return total; + } + + public PhotonFilePreview GetPreviewOne() + { + return previewOne; + } + + public PhotonFilePreview GetPreviewTwo() + { + return previewTwo; + } + + public int GetVersion() + { + return iFileHeader.GetVersion(); + } + + public int GetWidth() + { + return iFileHeader.GetResolutionY(); + } + + public float GetZdrift() + { + float expectedHeight = iFileHeader.GetLayerHeight() * (iFileHeader.GetNumberOfLayers() - 1); + float actualHeight = layers[layers.Count - 1].GetLayerPositionZ(); + return expectedHeight - actualHeight; + } + + public bool HasAA() + { + return iFileHeader.HasAA(); + } + + public PhotonFile ReadFile(string fileName, Action reportProgress) + { + using (var file = File.OpenRead(fileName)) + { + return ReadFile(GetBinaryData(file), reportProgress); + } + } + + public bool RemoveAllIslands(Action reportProgress) + { + bool layersFixed = false; + reportProgress?.Invoke("Removing islands from " + islandLayers.Count + " layers...
"); + PhotonLayer layer = null; + foreach (var layerNo in islandLayers) + { + PhotonFileLayer fileLayer = layers[layerNo]; + if (layer == null) + { + layer = fileLayer.GetLayer(); + } + else + { + fileLayer.GetUpdateLayer(layer); + } + reportProgress?.Invoke("Removing islands from layer " + layerNo); + + int removed = layer.RemoveIslands(); + if (removed == 0) + { + reportProgress?.Invoke(", but nothing could be done."); + } + else + { + reportProgress?.Invoke(", " + removed + " islands removed"); + fileLayer.SaveLayer(layer); + Calculate(layerNo); + if (layerNo < GetLayerCount() - 1) + { + Calculate(layerNo + 1); + } + layersFixed = true; + } + reportProgress?.Invoke("
"); + } + FindIslands(); + return layersFixed; + } + + public void SaveFile(string fileName) + { + using (var fileOutputStream = new BinaryWriter(File.OpenWrite(fileName))) + { + WriteFile(fileOutputStream); + } + } + + // only call this when recalculating AA levels + public void SetAALevels(int levels) + { + iFileHeader.SetAALevels(levels, layers); + } + + public void SetMargin(int margin) + { + this.margin = margin; + } + + public void UnLink() + { + while (layers.Count > 0) + { + PhotonFileLayer layer = layers[0]; + layers.RemoveAt(0); + layer.UnLink(); + } + if (islandLayers != null) + { + islandLayers.Clear(); + } + if (marginLayers != null) + { + marginLayers.Clear(); + } + iFileHeader.UnLink(); + iFileHeader = null; + previewOne.UnLink(); + previewOne = null; + previewTwo.UnLink(); + previewTwo = null; + } + + private void FindIslands() + { + if (islandLayers != null) + { + islandLayers.Clear(); + islandList = new StringBuilder(); + islandLayerCount = 0; + if (layers != null) + { + for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++) + { + PhotonFileLayer layer = layers[i]; + if (layer.GetIsLandsCount() > 0) + { + if (islandLayerCount < 11) + { + if (islandLayerCount == 10) + { + islandList.Append(", ..."); + } + else + { + if (islandList.Length > 0) islandList.Append(", "); + islandList.Append(i); + } + } + islandLayerCount++; + islandLayers.Add(i); + } + } + } + } + } + + private int Fixit(Action reportProgress, PhotonLayer layer, PhotonFileLayer fileLayer, int loops) + { + int changed = layer.Fixlayer(); + if (changed > 0) + { + layer.Reduce(); + fileLayer.UpdateLayerIslands(layer); + reportProgress?.Invoke(", " + changed + " pixels changed"); + if (loops > 0) + { + changed += Fixit(reportProgress, layer, fileLayer, loops - 1); + } + } + return changed; + } + + private byte[] GetBinaryData(FileStream entry) + { + int fileSize = (int)entry.Length; + byte[] fileData = new byte[fileSize]; + + var stream = new BinaryReader(entry); + int bytesRead = 0; + while (bytesRead < fileSize) + { + int readCount = stream.Read(fileData, bytesRead, fileSize - bytesRead); + if (readCount < 0) + { + throw new IOException("Could not read all bytes of the file"); + } + bytesRead += readCount; + } + + return fileData; + } + + private PhotonFile ReadFile(byte[] file, Action reportProgress) + { + reportProgress?.Invoke("Reading Photon file header information..."); + var photonFileHeader = new PhotonFileHeader(file); + iFileHeader = photonFileHeader; + + reportProgress?.Invoke("Reading photon large preview image information..."); + previewOne = new PhotonFilePreview(photonFileHeader.GetPreviewOneOffsetAddress(), file); + reportProgress?.Invoke("Reading photon small preview image information..."); + previewTwo = new PhotonFilePreview(photonFileHeader.GetPreviewTwoOffsetAddress(), file); + if (photonFileHeader.GetVersion() > 1) + { + reportProgress?.Invoke("Reading Print parameters information..."); + photonFileHeader.ReadParameters(file); + } + reportProgress?.Invoke("Reading photon layers information..."); + layers = PhotonFileLayer.ReadLayers(photonFileHeader, file, margin, reportProgress); + ResetMarginAndIslandInfo(); + + return this; + } + + private void ResetMarginAndIslandInfo() + { + islandList = null; + islandLayerCount = 0; + islandLayers = new List(); + + if (margin > 0) + { + marginLayers = new List(); + int i = 0; + foreach (PhotonFileLayer layer in layers) + { + if (layer.DoExtendMargin()) + { + marginLayers.Add(i); + } + i++; + } + } + } + + private void WriteFile(BinaryWriter writer) + { + int antiAliasLevel = iFileHeader.GetAALevels(); + + int headerPos = 0; + int previewOnePos = headerPos + iFileHeader.GetByteSize(); + int previewTwoPos = previewOnePos + previewOne.GetByteSize(); + int layerDefinitionPos = previewTwoPos + previewTwo.GetByteSize(); + + int parametersPos = 0; + int machineInfoPos = 0; + if (iFileHeader.GetVersion() > 1) + { + parametersPos = layerDefinitionPos; + if (((PhotonFileHeader)iFileHeader).photonFileMachineInfo.GetByteSize() > 0) + { + machineInfoPos = parametersPos + ((PhotonFileHeader)iFileHeader).photonFilePrintParameters.GetByteSize(); + layerDefinitionPos = machineInfoPos + ((PhotonFileHeader)iFileHeader).photonFileMachineInfo.GetByteSize(); + } + else + { + layerDefinitionPos = parametersPos + ((PhotonFileHeader)iFileHeader).photonFilePrintParameters.GetByteSize(); + } + } + + int dataPosition = layerDefinitionPos + (PhotonFileLayer.GetByteSize() * iFileHeader.GetNumberOfLayers() * antiAliasLevel); + + ((PhotonFileHeader)iFileHeader).Save(writer, previewOnePos, previewTwoPos, layerDefinitionPos, parametersPos, machineInfoPos); + previewOne.Save(writer, previewOnePos); + previewTwo.Save(writer, previewTwoPos); + + if (iFileHeader.GetVersion() > 1) + { + ((PhotonFileHeader)iFileHeader).photonFilePrintParameters.Save(writer); + ((PhotonFileHeader)iFileHeader).photonFileMachineInfo.Save(writer, machineInfoPos); + } + + // Optimize order for speed read on photon + for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++) + { + PhotonFileLayer layer = layers[i]; + dataPosition = layer.SavePos(dataPosition); + if (antiAliasLevel > 1) + { + for (int a = 0; a < (antiAliasLevel - 1); a++) + { + dataPosition = layer.GetAntiAlias(a).SavePos(dataPosition); + } + } + } + + // Order for backward compatibility with photon/cbddlp version 1 + for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++) + { + layers[i].Save(writer); + } + + if (antiAliasLevel > 1) + { + for (int a = 0; a < (antiAliasLevel - 1); a++) + { + for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++) + { + layers[i].GetAntiAlias(a).Save(writer); + } + } + } + + // Optimize order for speed read on photon + for (int i = 0; i < iFileHeader.GetNumberOfLayers(); i++) + { + PhotonFileLayer layer = layers[i]; + layer.SaveData(writer); + if (antiAliasLevel > 1) + { + for (int a = 0; a < (antiAliasLevel - 1); a++) + { + layer.GetAntiAlias(a).SaveData(writer); + } + } + } + } + } +} \ No newline at end of file diff --git a/MatterControl.SLA/Slicer/SlaSlicer.cs b/MatterControl.SLA/Slicer/SlaSlicer.cs new file mode 100644 index 000000000..49fd7282b --- /dev/null +++ b/MatterControl.SLA/Slicer/SlaSlicer.cs @@ -0,0 +1,126 @@ +/* +Copyright (c) 2019, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MatterHackers.Agg; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.VectorMath; + +namespace MatterHackers.gsBundle +{ + public class SlaSlicer : IObjectSlicer + { + public async Task Slice(IEnumerable printableItems, PrinterSettings printerSettings, string filePath, IProgress progressReporter, CancellationToken cancellationToken) + { + using (var outputStream = File.OpenWrite(filePath)) + { + foreach (var item in printableItems.Where(d => d.MeshPath != null)) + { + //string sourceFilePath = await item.ResolveFilePath(null, cancellationToken); + + //// Load Mesh + //if (File.Exists(sourceFilePath)) + //{ + // var mesh = StandardMeshReader.ReadMesh(sourceFilePath); + // if (mesh != null) + // { + // sourceMeshes.Add(mesh); + // } + + // var printCenter = printerSettings.GetValue(SettingsKey.print_center); + // ApplyTransform(mesh, item.WorldMatrix(), printCenter); + //} + } + + //var settings = LoadSettingsForPrinter(printerSettings); + + // Construct slicer + //var slicer = new GeometrySlicer(); + //slicer.SliceMeshes(sourceMeshes, settings); + + //bool valid = slicer.ExtractResultsIfValid(out PrintMeshAssembly meshes, out PlanarSliceStack slices); + + //// Construct GCode generator + //var pathGenerator = new ToolpathGenerator(); + //pathGenerator.CreateToolPaths(meshes, slices, settings); + + //// Write GCode file + //var gcodeWriter = new StandardGCodeWriter(); + + //var streamWriter = new StreamWriter(outputStream); + + //gcodeWriter.WriteFile(pathGenerator.CurrentGCode, streamWriter); + + return true; + } + } + + public Dictionary Exports { get; } = new Dictionary() + { + [SettingsKey.bed_size] = new ExportField(""), + [SettingsKey.build_height] = new ExportField(""), + [SettingsKey.make] = new ExportField(""), + [SettingsKey.model] = new ExportField(""), + [SettingsKey.resin_cost] = new ExportField(""), + [SettingsKey.resin_density] = new ExportField(""), + [SettingsKey.sla_auto_support] = new ExportField(""), + [SettingsKey.sla_base_exposure_time] = new ExportField(""), + [SettingsKey.sla_base_min_off_time] = new ExportField(""), + [SettingsKey.sla_min_off_time] = new ExportField(""), + [SettingsKey.sla_base_lift_distance] = new ExportField(""), + [SettingsKey.sla_lift_distance] = new ExportField(""), + [SettingsKey.sla_base_lift_speed] = new ExportField(""), + [SettingsKey.sla_lift_speed] = new ExportField(""), + [SettingsKey.sla_base_layers] = new ExportField(""), + [SettingsKey.sla_create_raft] = new ExportField(""), + [SettingsKey.sla_exposure_time] = new ExportField(""), + [SettingsKey.sla_layer_height] = new ExportField(""), + [SettingsKey.sla_printable_area_inset] = new ExportField(""), + [SettingsKey.sla_resolution] = new ExportField(""), + [SettingsKey.slice_engine] = new ExportField(""), + [SettingsKey.sla_mirror_mode] = new ExportField(""), + [SettingsKey.sla_decend_speed] = new ExportField(""), + }; + + public bool ValidateFile(string filePath) + { + // TODO: Implement solution + System.Diagnostics.Debugger.Break(); + return true; + } + + public PrinterType PrinterType => PrinterType.SLA; + } +} diff --git a/MatterControl.Printing/MappingClasses/OverrideSpeedOnSlaPrinters.cs b/MatterControl.SLA/Slicer/SlaSlicerPlugin.cs similarity index 59% rename from MatterControl.Printing/MappingClasses/OverrideSpeedOnSlaPrinters.cs rename to MatterControl.SLA/Slicer/SlaSlicerPlugin.cs index 0f0d8fb5f..2ce8431d7 100644 --- a/MatterControl.Printing/MappingClasses/OverrideSpeedOnSlaPrinters.cs +++ b/MatterControl.SLA/Slicer/SlaSlicerPlugin.cs @@ -1,5 +1,5 @@ /* -Copyright (c) 2019, Lars Brubaker, John Lewin +Copyright (c) 2019, John Lewin All rights reserved. Redistribution and use in source and binary forms, with or without @@ -27,35 +27,25 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ -namespace MatterHackers.MatterControl.SlicerConfiguration.MappingClasses +using MatterHackers.MatterControl.Extensibility; +using MatterHackers.MatterControl.SlicerConfiguration; + +namespace MatterHackers.gsBundle { - public class OverrideSpeedOnSlaPrinters : AsPercentOfReferenceOrDirect + public class SlaSlicerPlugin : IApplicationPlugin { - public OverrideSpeedOnSlaPrinters(string originalReference, double scale = 1) - : base(originalReference, scale) + public void Initialize() { + PrinterSettings.SliceEngines["MH-SLA Slicer"] = new SlaSlicer(); } - public override string Convert(string value, PrinterSettings settings) + public PluginInfo MetaData => new PluginInfo() { - if (settings.GetValue(SettingsKey.sla_printer)) - { - // return the speed based on the layer height - var speedAt025 = settings.GetValue(SettingsKey.laser_speed_025); - var speedAt100 = settings.GetValue(SettingsKey.laser_speed_100); - var deltaSpeed = speedAt100 - speedAt025; - - var layerHeight = settings.GetValue(SettingsKey.layer_height); - var deltaHeight = .1 - .025; - var heightRatio = (layerHeight - .025) / deltaHeight; - var ajustedSpeed = speedAt025 + deltaSpeed * heightRatio; - - return ajustedSpeed.ToString(); - } - else - { - return base.Convert(value, settings); - } - } + About = "MatterHackers SLA Slicer for MatterControl", + Developer = "MatterHackers Inc.", + Name = "MH-SLA-Slicer", + Url = "https://www.matterhackers.com/MatterControl", + UUID = "637FD858-1C6A-4B37-B001-6306933DF379" + }; } -} \ No newline at end of file +} diff --git a/MatterControl.csproj b/MatterControl.csproj index d8cccd31b..30d5c7474 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -79,6 +79,10 @@ {97d5ade3-c1b4-4b46-8a3e-718a4f7f079f} MatterControl.Printing + + {e2b1af22-4143-4b33-9781-fc5527e959f6} + MatterControl.SLA + {D6DC2669-7B1F-40FE-89BF-45D4C94473E3} MatterControl.Winforms diff --git a/MatterControlLib/ApplicationView/SettingsValidation.cs b/MatterControlLib/ApplicationView/SettingsValidation.cs index 97bf4a694..620e759b6 100644 --- a/MatterControlLib/ApplicationView/SettingsValidation.cs +++ b/MatterControlLib/ApplicationView/SettingsValidation.cs @@ -49,6 +49,8 @@ namespace MatterHackers.MatterControl /// A list of all warnings and errors. public static List ValidateSettings(this PrinterConfig printer, SettingsContext settings = null, bool validatePrintBed = true) { + var fffPrinter = printer.Settings.Slicer.PrinterType == PrinterType.FFF; + if (settings == null) { settings = new SettingsContext(printer, null, NamedSettingsLayers.All); @@ -433,7 +435,9 @@ namespace MatterHackers.MatterControl }); } - if (printer.Settings?.Helpers.ComPort() == "Emulator") + if (printer.Connection.IsConnected + && printer.Settings?.Helpers.ComPort() == "Emulator" + && fffPrinter) { errors.Add( new SettingsValidationError(SettingsKey.com_port, "Connected to Emulator".Localize()) @@ -548,7 +552,10 @@ namespace MatterHackers.MatterControl { var errors = new List(); - if (!printer.Connection.IsConnected) + var fffPrinter = printer.Settings.Slicer.PrinterType == PrinterType.FFF; + + if (!printer.Connection.IsConnected + && fffPrinter) { errors.Add(new ValidationError(ValidationErrors.PrinterDisconnected) { diff --git a/MatterControlLib/DataStorage/Classic/ClassicSqlitePrinterProfiles.cs b/MatterControlLib/DataStorage/Classic/ClassicSqlitePrinterProfiles.cs index d51f316ff..898785de4 100644 --- a/MatterControlLib/DataStorage/Classic/ClassicSqlitePrinterProfiles.cs +++ b/MatterControlLib/DataStorage/Classic/ClassicSqlitePrinterProfiles.cs @@ -87,7 +87,6 @@ namespace MatterHackers.MatterControl.DataStorage.ClassicDB printerSettings.UserLayer[SettingsKey.baud_rate] = printer.BaudRate ?? ""; printerSettings.UserLayer[SettingsKey.auto_connect] = printer.AutoConnect ? "1" : "0"; printerSettings.UserLayer[SettingsKey.default_material_presets] = printer.MaterialCollectionIds ?? ""; - printerSettings.UserLayer[SettingsKey.windows_driver] = printer.DriverType ?? ""; printerSettings.UserLayer[SettingsKey.device_token] = printer.DeviceToken ?? ""; printerSettings.UserLayer[SettingsKey.device_type] = printer.DeviceType ?? ""; diff --git a/MatterControlLib/PartPreviewWindow/MaterialControls.cs b/MatterControlLib/PartPreviewWindow/MaterialControls.cs index 9ab227913..7c2468894 100644 --- a/MatterControlLib/PartPreviewWindow/MaterialControls.cs +++ b/MatterControlLib/PartPreviewWindow/MaterialControls.cs @@ -68,13 +68,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var scaledButtonSize = 16 * GuiWidget.DeviceScale; - buttonView.AddChild(new ColorButton(MaterialRendering.Color(printer, extruderIndex, theme.BorderColor)) + GuiWidget colorButton; + buttonView.AddChild(colorButton = new ItemColorButton(theme, MaterialRendering.Color(printer, extruderIndex, theme.BorderColor)) { Width = scaledButtonSize, Height = scaledButtonSize, VAnchor = VAnchor.Center, Margin = new BorderDouble(3, 0, 5, 0), - DrawGrid = true, }); buttonView.AddChild(new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) @@ -99,6 +99,35 @@ namespace MatterHackers.MatterControl.PartPreviewWindow materialButtons.Add(radioButton); this.AddChild(radioButton); + radioButton.MouseMove += (s, e) => + { + var screenSpace = radioButton.TransformToScreenSpace(e.Position); + var colorButtonSpace = colorButton.TransformFromScreenSpace(screenSpace); + if (colorButton.LocalBounds.Contains(colorButtonSpace)) + { + var parent = colorButton.Parent; + while (parent != radioButton) + { + parent.Selectable = true; + parent = parent.Parent; + } + } + else + { + var parent = colorButton.Parent; + while (parent != radioButton) + { + parent.Selectable = false; + parent = parent.Parent; + } + } + }; + + radioButton.MouseLeaveBounds += (s, e) => + { + + }; + int localExtruderIndex = extruderIndex; radioButton.Click += (sender, e) => { diff --git a/MatterControlLib/PartPreviewWindow/PrinterTabPage.cs b/MatterControlLib/PartPreviewWindow/PrinterTabPage.cs index 15cbb2a11..c63f99d55 100644 --- a/MatterControlLib/PartPreviewWindow/PrinterTabPage.cs +++ b/MatterControlLib/PartPreviewWindow/PrinterTabPage.cs @@ -580,12 +580,15 @@ namespace MatterHackers.MatterControl.PartPreviewWindow sideBar.RemovePage("Terminal", false); sideBar.RemovePage("Printer", false); - if (Printer.ViewState.ControlsVisible) + var printerType = Printer.Settings.Slicer.PrinterType; + if(Printer.ViewState.ControlsVisible + && printerType == PrinterType.FFF) { sideBar.AddPage("Controls", "Controls".Localize(), new ManualPrinterControls(Printer, theme), false); } - if (Printer.ViewState.TerminalVisible) + if (Printer.ViewState.TerminalVisible + && printerType == PrinterType.FFF) { sideBar.AddPage("Terminal", "Terminal".Localize(), diff --git a/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/ExportSlaPopupMenu.cs b/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/ExportSlaPopupMenu.cs new file mode 100644 index 000000000..262a511ab --- /dev/null +++ b/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/ExportSlaPopupMenu.cs @@ -0,0 +1,243 @@ +/* +Copyright (c) 2019, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.CustomWidgets; +using MatterHackers.MatterControl.Library; +using MatterHackers.MatterControl.Library.Export; +using MatterHackers.MatterControl.Plugins.X3GDriver; +using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.PartPreviewWindow +{ + public class ExportSlaPopupMenu : PopupMenuButton + { + private PrinterConfig printer; + private Dictionary allUiFields = new Dictionary(); + private SettingsContext settingsContext; + + public ExportSlaPopupMenu(PrinterConfig printer, ThemeConfig theme) + : base(theme) + { + this.printer = printer; + this.DrawArrow = true; + this.BackgroundColor = theme.ToolbarButtonBackground; + this.HoverColor = theme.ToolbarButtonHover; + this.MouseDownColor = theme.ToolbarButtonDown; + this.Name = "ExportSlaPopupMenu"; + this.HAnchor = HAnchor.Fit; + this.VAnchor = VAnchor.Fit; + + settingsContext = new SettingsContext(printer, null, NamedSettingsLayers.All); + + this.PopupHAnchor = HAnchor.Fit; + this.PopupVAnchor = VAnchor.Fit; + this.MakeScrollable = false; + + this.DynamicPopupContent = () => + { + var menuTheme = ApplicationController.Instance.MenuTheme; + + int tabIndex = 0; + + allUiFields.Clear(); + + var printPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + Padding = theme.DefaultContainerPadding, + BackgroundColor = menuTheme.BackgroundColor + }; + + printPanel.AddChild(new TextWidget("Options".Localize(), textColor: menuTheme.TextColor, pointSize: theme.DefaultFontSize) + { + HAnchor = HAnchor.Left + }); + + var optionsPanel = new IgnoredFlowLayout() + { + Name = "ExportSlaPopupMenu Panel", + HAnchor = HAnchor.Fit | HAnchor.Left, + VAnchor = VAnchor.Fit, + Padding = 5, + MinimumSize = new Vector2(400 * GuiWidget.DeviceScale, 65 * GuiWidget.DeviceScale), + }; + printPanel.AddChild(optionsPanel); + + var settingsToAdd = new[] + { + SettingsKey.sla_layer_height, + SettingsKey.sla_create_raft, + SettingsKey.sla_auto_support + }; + + foreach (var key in settingsToAdd) + { + var settingsData = PrinterSettings.SettingsData[key]; + var row = SliceSettingsTabView.CreateItemRow(settingsData, settingsContext, printer, menuTheme, ref tabIndex, allUiFields); + + if (row is SliceSettingsRow settingsRow) + { + settingsRow.ArrowDirection = ArrowDirection.Left; + } + + optionsPanel.AddChild(row); + } + + // add the export print button + var setupRow = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch + }; + + // Perform validation before popup + var errors = printer.Validate(); + + var hasErrors = errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Error); + var hasWarnings = errors.Any(e => e.ErrorLevel == ValidationErrorLevel.Warning + && UserSettings.Instance.get($"Ignore_{e.ID}") != "true"); + + var hasErrorsOrWarnings = hasErrors || hasWarnings; + if (hasErrorsOrWarnings) + { + string label = hasErrors ? "Action Required".Localize() : "Action Recommended".Localize(); + + setupRow.AddChild(new TextWidget(label, textColor: hasErrors ? Color.Red : theme.PrimaryAccentColor, pointSize: theme.DefaultFontSize) + { + VAnchor = VAnchor.Bottom, + AutoExpandBoundsToText = true, + }); + } + + setupRow.AddChild(new HorizontalSpacer()); + + // Export button {{ + var exportPlugins = PluginFinder.CreateInstancesOf(); + // set target as SLA export + var targetPluginType = typeof(GCodeExport); + + // Find the first export plugin with the target type + if (exportPlugins.FirstOrDefault(p => p.GetType() == targetPluginType) is IExportPlugin exportPlugin) + { + string exportType = "Export G-Code".Localize(); + + exportPlugin.Initialize(printer); + + var exportGCodeButton = menuTheme.CreateDialogButton("Export".Localize()); + + exportGCodeButton.Name = "Export SLA Button"; + exportGCodeButton.Enabled = exportPlugin.Enabled; + exportGCodeButton.ToolTipText = exportPlugin.Enabled ? exportType : exportPlugin.DisabledReason; + + exportGCodeButton.Click += (s, e) => + { + this.CloseMenu(); + ExportPrintItemPage.DoExport( + new[] { new InMemoryLibraryItem(printer.Bed.Scene) }, + printer, + exportPlugin); + }; + + setupRow.AddChild(exportGCodeButton); + } + + // Export button + + printPanel.AddChild(setupRow); + + if (hasErrorsOrWarnings) + { + var errorsPanel = new ValidationErrorsPanel(errors, menuTheme); + + // Conditional layout for right or bottom errors panel alignment + var layoutStyle = FlowDirection.TopToBottom; + + if (layoutStyle == FlowDirection.LeftToRight) + { + errorsPanel.HAnchor = HAnchor.Absolute; + errorsPanel.VAnchor = VAnchor.Fit | VAnchor.Top; + errorsPanel.BackgroundColor = theme.ResolveColor(menuTheme.BackgroundColor, theme.PrimaryAccentColor.WithAlpha(30)); + errorsPanel.Width = 350; + + errorsPanel.Load += (s, e) => + { + errorsPanel.Parent.BackgroundColor = Color.Transparent; + }; + } + else + { + errorsPanel.HAnchor = HAnchor.Stretch; + errorsPanel.VAnchor = VAnchor.Fit; + errorsPanel.Margin = 3; + } + + // Instead of the typical case where the print panel is returned, wrap and append validation errors panel + var errorsContainer = new FlowLayoutWidget(layoutStyle) + { + HAnchor = HAnchor.Fit, + VAnchor = VAnchor.Fit, + BackgroundColor = layoutStyle == FlowDirection.TopToBottom ? printPanel.BackgroundColor : Color.Transparent + }; + + // Clear bottom padding + printPanel.Padding = printPanel.Padding.Clone(bottom: 2); + + errorsContainer.AddChild(printPanel); + errorsContainer.AddChild(errorsPanel); + + return errorsContainer; + } + + return printPanel; + }; + + this.AddChild(new TextButton("Export".Localize(), theme) + { + Selectable = false, + Padding = theme.TextButtonPadding.Clone(right: 5) + }); + } + + private class IgnoredFlowLayout : FlowLayoutWidget, IIgnoredPopupChild + { + public IgnoredFlowLayout() + : base(FlowDirection.TopToBottom) + { + } + + public bool KeepMenuOpen => false; + } + } +} \ No newline at end of file diff --git a/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/PrinterActionsBar.cs b/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/PrinterActionsBar.cs index 63da9764e..303b31f5f 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/PrinterActionsBar.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/PrinterBar/PrinterActionsBar.cs @@ -73,54 +73,66 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var defaultMargin = theme.ButtonSpacing; - // add the reset button first (if there is one) - if (printer.Settings.GetValue(SettingsKey.show_reset_connection)) + var printerType = printer.Settings.Slicer.PrinterType; + if (printerType == PrinterType.FFF) { - var resetConnectionButton = new TextIconButton( - "Reset".Localize(), - StaticData.Instance.LoadIcon("e_stop.png", 14, 14, theme.InvertIcons), - theme) + // add the reset button first (if there is one) + if (printer.Settings.GetValue(SettingsKey.show_reset_connection)) { - ToolTipText = "Reboots the firmware on the controller".Localize(), - Margin = defaultMargin - }; - resetConnectionButton.Click += (s, e) => - { - UiThread.RunOnIdle(printer.Connection.RebootBoard); - }; - this.AddChild(resetConnectionButton); - } - - this.AddChild(new PrinterConnectButton(printer, theme)); - - // add the start print button - GuiWidget startPrintButton; - this.AddChild(startPrintButton = new PrintPopupMenu(printer, theme) - { - Margin = theme.ButtonSpacing - }); - - void SetPrintButtonStyle(object s, EventArgs e) - { - switch (printer.Connection.CommunicationState) - { - case CommunicationStates.FinishedPrint: - case CommunicationStates.Connected: - theme.ApplyPrimaryActionStyle(startPrintButton); - break; - - default: - theme.RemovePrimaryActionStyle(startPrintButton); - break; + var resetConnectionButton = new TextIconButton( + "Reset".Localize(), + StaticData.Instance.LoadIcon("e_stop.png", 14, 14, theme.InvertIcons), + theme) + { + ToolTipText = "Reboots the firmware on the controller".Localize(), + Margin = defaultMargin + }; + resetConnectionButton.Click += (s, e) => + { + UiThread.RunOnIdle(printer.Connection.RebootBoard); + }; + this.AddChild(resetConnectionButton); } + + this.AddChild(new PrinterConnectButton(printer, theme)); + + // add the start print button + GuiWidget startPrintButton; + this.AddChild(startPrintButton = new PrintPopupMenu(printer, theme) + { + Margin = theme.ButtonSpacing + }); + + void SetPrintButtonStyle(object s, EventArgs e) + { + switch (printer.Connection.CommunicationState) + { + case CommunicationStates.FinishedPrint: + case CommunicationStates.Connected: + theme.ApplyPrimaryActionStyle(startPrintButton); + break; + + default: + theme.RemovePrimaryActionStyle(startPrintButton); + break; + } + } + + // make sure the buttons state is set correctly + printer.Connection.CommunicationStateChanged += SetPrintButtonStyle; + startPrintButton.Closed += (s, e) => printer.Connection.CommunicationStateChanged -= SetPrintButtonStyle; + + // and set the style right now + SetPrintButtonStyle(this, null); + } + else + { + // add the start print button + this.AddChild(new ExportSlaPopupMenu(printer, theme) + { + Margin = theme.ButtonSpacing + }); } - - // make sure the buttons state is set correctly - printer.Connection.CommunicationStateChanged += SetPrintButtonStyle; - startPrintButton.Closed += (s, e) => printer.Connection.CommunicationStateChanged -= SetPrintButtonStyle; - - // and set the style right now - SetPrintButtonStyle(this, null); this.AddChild(new SliceButton(printer, printerTabPage, theme) { @@ -188,9 +200,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow this.AddChild(new HorizontalSpacer()); - int hotendCount = printer.Settings.Helpers.HotendCount(); - if (!printer.Settings.GetValue(SettingsKey.sla_printer)) + if (printerType == PrinterType.FFF) { + int hotendCount = printer.Settings.Helpers.HotendCount(); + for (int extruderIndex = 0; extruderIndex < hotendCount; extruderIndex++) { this.AddChild(new TemperatureWidgetHotend(printer, extruderIndex, theme, hotendCount) @@ -198,11 +211,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow Margin = new BorderDouble(right: 10) }); } - } - if (printer.Settings.GetValue(SettingsKey.has_heated_bed)) - { - this.AddChild(new TemperatureWidgetBed(printer, theme)); + if (printer.Settings.GetValue(SettingsKey.has_heated_bed)) + { + this.AddChild(new TemperatureWidgetBed(printer, theme)); + } + + // Register listeners + printer.Connection.ConnectionSucceeded += CheckForPrintRecovery; + + // if we are already connected than check if there is a print recovery right now + if (printer.Connection.CommunicationState == CommunicationStates.Connected) + { + CheckForPrintRecovery(null, null); + } } this.OverflowButton.Name = "Printer Overflow Menu"; @@ -229,15 +251,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow theme); } }; - - // Register listeners - printer.Connection.ConnectionSucceeded += CheckForPrintRecovery; - - // if we are already connected than check if there is a print recovery right now - if (printer.Connection.CommunicationState == CommunicationStates.Connected) - { - CheckForPrintRecovery(null, null); - } } bool buttonIsBeingClicked; @@ -300,20 +313,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow IsEnabled = () => printer.Connection.IsConnected }, new NamedBoolAction() - { - Title = "Show Controls".Localize(), - Action = () => { }, - GetIsActive = () => printer.ViewState.ControlsVisible, - SetIsActive = (value) => printer.ViewState.ControlsVisible = value - }, - new NamedBoolAction() - { - Title = "Show Terminal".Localize(), - Action = () => { }, - GetIsActive = () => printer.ViewState.TerminalVisible, - SetIsActive = (value) => printer.ViewState.TerminalVisible = value - }, - new NamedBoolAction() { Title = "Show Printer".Localize(), Action = () => { }, @@ -424,6 +423,26 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } }; + var printerType = printer.Settings.Slicer.PrinterType; + if (printerType == PrinterType.FFF) + { + menuActions.Add(new NamedBoolAction() + { + Title = "Show Controls".Localize(), + Action = () => { }, + GetIsActive = () => printer.ViewState.ControlsVisible, + SetIsActive = (value) => printer.ViewState.ControlsVisible = value, + }); + menuActions.Add(new NamedBoolAction() + { + Title = "Show Terminal".Localize(), + Action = () => { }, + GetIsActive = () => printer.ViewState.TerminalVisible, + SetIsActive = (value) => printer.ViewState.TerminalVisible = value, + }); + } + + theme.CreateMenuItems(popupMenu, menuActions); } diff --git a/MatterControlLib/PrinterControls/ManualPrinterControls.cs b/MatterControlLib/PrinterControls/ManualPrinterControls.cs index 0bc4d4670..137407064 100644 --- a/MatterControlLib/PrinterControls/ManualPrinterControls.cs +++ b/MatterControlLib/PrinterControls/ManualPrinterControls.cs @@ -78,16 +78,11 @@ namespace MatterHackers.MatterControl calibrationControlsContainer = this.AddPluginWidget(CalibrationControls.CreateSection(printer, theme)); - if (!printer.Settings.GetValue(SettingsKey.sla_printer)) - { - temperatureControlsContainer = this.AddPluginWidget(TemperatureControls.CreateSection(printer, theme)); - } + temperatureControlsContainer = this.AddPluginWidget(TemperatureControls.CreateSection(printer, theme)); macroControlsContainer = this.AddPluginWidget(MacroControls.CreateSection(printer, theme)); -#if !__ANDROID__ this.AddPluginWidget(PowerControls.CreateSection(printer, theme)); -#endif tuningAdjustmentControlsContainer = this.AddPluginWidget(AdjustmentControls.CreateSection(printer, theme)); diff --git a/MatterControlLib/SlicerConfiguration/EngineMappingsMatterSlice.cs b/MatterControlLib/SlicerConfiguration/EngineMappingsMatterSlice.cs index a2250c738..a79fd5dfe 100644 --- a/MatterControlLib/SlicerConfiguration/EngineMappingsMatterSlice.cs +++ b/MatterControlLib/SlicerConfiguration/EngineMappingsMatterSlice.cs @@ -197,6 +197,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration matterSliceSettingNames = new HashSet(this.Exports.Select(m => m.Key)); } + public PrinterType PrinterType => PrinterType.FFF; + public string Name => "MatterSlice"; public void WriteSliceSettingsFile(string outputFilename, IEnumerable rawLines, PrinterSettings settings) diff --git a/MatterHackers.gsSlicer/BasicSlicer.cs b/MatterHackers.gsSlicer/BasicSlicer.cs index 6528fe875..a335e237f 100644 --- a/MatterHackers.gsSlicer/BasicSlicer.cs +++ b/MatterHackers.gsSlicer/BasicSlicer.cs @@ -148,6 +148,8 @@ namespace MatterHackers.gsBundle [SettingsKey.top_solid_layers] = new ExportField("") }; + public PrinterType PrinterType => PrinterType.FFF; + public bool ValidateFile(string filePath) { // TODO: Implement solution diff --git a/Program.cs b/Program.cs index a9fead498..90f04913e 100644 --- a/Program.cs +++ b/Program.cs @@ -28,6 +28,7 @@ either expressed or implied, of the FreeBSD Project. */ using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -44,6 +45,7 @@ using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.SerialPortCommunication.FrostedSerial; using Microsoft.Extensions.Configuration; using Mindscape.Raygun4Net; +using Photon.Parts; using SQLiteWin32; namespace MatterHackers.MatterControl @@ -90,6 +92,17 @@ namespace MatterHackers.MatterControl [STAThread] public static void Main(string[] args) { +#if false + var test = new PhotonFile(); + void Progress(string message) + { + Debug.WriteLine(message); + } + + test.ReadFile(@"C:\Users\LarsBrubaker\Downloads\10mm-benchy.photon", Progress); + test.SaveFile(@"C:\Users\LarsBrubaker\Downloads\10mm-bench2.photon"); +#endif + // Set the global culture for the app, current thread and all new threads CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index f509bad6c..2c3522274 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit f509bad6c8f66ccb7bec5620c12393aa0385a7ac +Subproject commit 2c35222744ad55c281c24f6c98c4515cff43f577