* (Upgrade) EmguCV/OpenCV to v4.5.1
* (Upgrade) AvaloniaUI to 1.0
* (Improvement) GUI re-touched
* (Improvement) Make pixel editor tab to disappear when pixel editor is disabled
* (Improvement) Simplify the output filename from PrusaSlicer profiles
* (Improvement) All operations require a slicer file at constructor rather than on execute, this allow exposure the open file to the operation before run it
* (Improvement) Calibrations: Auto set "Mirror Output" if open file have MirrorDisplay set
* (Change) Tool - Redraw model/supports icon
* (Change) photon and cbddlp to use version 3 by default
* (Add) Tool - Dynamic layer height: Analyze and optimize the model with dynamic layer heights, larger angles will slice at lower layer height
        while more straight angles will slice larger layer height. (#131)
* (Add) Calibration - Exposure time finder: Generates test models with various strategies and increments to verify the best exposure time for a given layer height
* (Add) File load checks, trigger error when a file have critical errors and attempt to fix non-critical errors
  * Layers must have an valid image, otherwise trigger an error
  * Layers must have a incremental or equal position Z than it previous, otherwise trigger an error
  * If layer 0 starts at 0mm it will auto fix all layers, it will add Layer Height to the current z at every layer
* (Add) Tool - Edit print parameters: Allow set parameters to each x layers and skip n layers inside the given range.
        This allow the use of optimizations in a layer pattern, for example, to set 3s for a layer but 2.5s for the next.
* (Add) Layer height property to "Layer Data" table: Shows layer height for the slice
* (Fix) When automations applied and file is saved, it will not warn user about file overwrite for the first time save
* (Fix) Tool - Redraw model/supports: Disable apply button when no file selected
* (Fix) Tool - Infill: Lack of equality member to test if same infill profile already exists
* (Fix) Auto converted files from SL1 where clipping filename at first dot (.), now it only strips known extensions
* (Fix) SL1 encoded files wasn't generating the right information and lead to printer crash
* (Fix) PrusaSlicer printer "Anycubic Photon S" LiftSpeed was missing and contains a typo (#135)
* (Fix) PrusaSlicer profile manager wasnt marking missing profiles to be installed (#135)
* (Fix) PrusaSlicer folder search on linux to also look at %HOME%/.config/PrusaSlicer (#135, #136)
* (Fix) Operations were revised and some bug fixed, most about can't cancel the progress
* (Fix) Some typos on tooltips
* (Fix) Prevent PhotonS from enconding, it will trigger error now as this format is read-only
* **(Fix) Ctrl + Shift + Z to redo the last operation:**
  * The layer range is reseted instead of pull the used values
  * Tool - Arithmetic always disabled
  * Action - Layer import didn't generate info and always disabled
This commit is contained in:
Tiago Conceição
2021-02-06 22:09:55 +00:00
parent 98df5c37f8
commit 0ba61780b7
179 changed files with 5825 additions and 2678 deletions
@@ -6,6 +6,8 @@ labels: enhancement
assignees: sn4k3
---
Also look at: https://github.com/sn4k3/UVtools/discussions/categories/ideas
<span style="color:red">**! Before continue, please look/search on closed topics if your case was already been discussed, if yes and related, comment there instead.**</span>
## Is your feature request related to a problem? Please describe
+4 -4
View File
@@ -6,7 +6,7 @@ labels: question
assignees: sn4k3
---
<span style="color:red">**! Before continue, please look/search on closed topics if your case was already been discussed, if yes and related, comment there instead.**</span>
## Describe the question
A clear and concise description of your question.
## READ THIS
Do not use issues to post questions! Use discussions instead!:
https://github.com/sn4k3/UVtools/discussions/categories/q-a
## READ THIS
+4 -7
View File
@@ -6,10 +6,7 @@ labels: script
assignees: sn4k3
---
## Describe what your script does
A clear and concise description of your script, and all it steps.
```Powershell
#Paste your code here or attach the .ps1 file
```
## READ THIS
Do not use issues to post scripts! Use discussions instead!:
https://github.com/sn4k3/UVtools/discussions/categories/scripts
## READ THIS
+37
View File
@@ -1,5 +1,42 @@
# Changelog
## 06/02/2021 - v2.4.0
* (Upgrade) EmguCV/OpenCV to v4.5.1
* (Upgrade) AvaloniaUI to 1.0
* (Improvement) GUI re-touched
* (Improvement) Make pixel editor tab to disappear when pixel editor is disabled
* (Improvement) Simplify the output filename from PrusaSlicer profiles
* (Improvement) All operations require a slicer file at constructor rather than on execute, this allow exposure the open file to the operation before run it
* (Improvement) Calibrations: Auto set "Mirror Output" if open file have MirrorDisplay set
* (Change) Tool - Redraw model/supports icon
* (Change) photon and cbddlp to use version 3 by default
* (Add) Tool - Dynamic layer height: Analyze and optimize the model with dynamic layer heights, larger angles will slice at lower layer height
while more straight angles will slice larger layer height. (#131)
* (Add) Calibration - Exposure time finder: Generates test models with various strategies and increments to verify the best exposure time for a given layer height
* (Add) File load checks, trigger error when a file have critical errors and attempt to fix non-critical errors
* Layers must have an valid image, otherwise trigger an error
* Layers must have a incremental or equal position Z than it previous, otherwise trigger an error
* If layer 0 starts at 0mm it will auto fix all layers, it will add Layer Height to the current z at every layer
* (Add) Tool - Edit print parameters: Allow set parameters to each x layers and skip n layers inside the given range.
This allow the use of optimizations in a layer pattern, for example, to set 3s for a layer but 2.5s for the next.
* (Add) Layer height property to "Layer Data" table: Shows layer height for the slice
* (Fix) When automations applied and file is saved, it will not warn user about file overwrite for the first time save
* (Fix) Tool - Redraw model/supports: Disable apply button when no file selected
* (Fix) Tool - Infill: Lack of equality member to test if same infill profile already exists
* (Fix) Auto converted files from SL1 where clipping filename at first dot (.), now it only strips known extensions
* (Fix) SL1 encoded files wasn't generating the right information and lead to printer crash
* (Fix) PrusaSlicer printer "Anycubic Photon S" LiftSpeed was missing and contains a typo (#135)
* (Fix) PrusaSlicer profile manager wasnt marking missing profiles to be installed (#135)
* (Fix) PrusaSlicer folder search on linux to also look at %HOME%/.config/PrusaSlicer (#135, #136)
* (Fix) Operations were revised and some bug fixed, most about can't cancel the progress
* (Fix) Some typos on tooltips
* (Fix) Prevent PhotonS from enconding, it will trigger error now as this format is read-only
* **(Fix) Ctrl + Shift + Z to redo the last operation:**
* The layer range is reseted instead of pull the used values
* Tool - Arithmetic always disabled
* Action - Layer import didn't generate info and always disabled
## 22/01/2021 - v2.3.2
* (Add) Settings - Automations: Change only light-off delay if value is zero (Enabled by default)
+8 -5
View File
@@ -30,6 +30,8 @@ class FixedEncoder : System.Text.UTF8Encoding {
### Configuration ###
####################################
$enableMSI = $true
$buildOnly = $null
#$buildOnly = ""#"win-x64"
# Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
$deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
@@ -83,22 +85,22 @@ $runtimes =
@{
"win-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("libcvextern.so", "libcvextern.dylib", "UVtools.sh")
"exclude" = @("UVtools.sh")
"include" = @()
}
"linux-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib")
"exclude" = @()
"include" = @("libcvextern.so")
}
"arch-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib", "libcvextern.so")
"exclude" = @()
"include" = @("libcvextern.so")
}
"rhel-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib")
"exclude" = @()
"include" = @("libcvextern.so")
}
#"unix-x64" = @{
@@ -107,12 +109,13 @@ $runtimes =
#}
"osx-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.so")
"exclude" = @()
"include" = @("libcvextern.dylib")
}
}
foreach ($obj in $runtimes.GetEnumerator()) {
if(![string]::IsNullOrWhiteSpace($buildOnly) -and !$buildOnly.Equals($obj.Name)) {continue}
# Configuration
$deployStopWatch.Restart()
$runtime = $obj.Name; # runtime name
+1 -1
View File
@@ -26,7 +26,7 @@ min_exposure_time = 1
min_initial_exposure_time = 1
print_host =
printer_model = SL1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON_S\nFILEFORMAT_PWS\n\nSTART_CUSTOM_VALUES\nLightOffDelay_1\nLiftHeight_6\nLiftingSpeed_60\nRetractSpeed_150\nEND_CUSTOM_VALUES
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_ANYCUBIC\nPRINTER_MODEL_PHOTON_S\nFILEFORMAT_PWS\n\nSTART_CUSTOM_VALUES\nLightOffDelay_1\nLiftHeight_6\nLiftSpeed_60\nRetractSpeed_150\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
+2 -2
View File
@@ -1,4 +1,4 @@
# generated by PrusaSlicer 2.3.0+win64 on 2021-01-13 at 02:30:16 UTC
# generated by PrusaSlicer 2.3.0+win64 on 2021-02-06 at 03:35:53 UTC
absolute_correction = 0
area_fill = 50
bed_custom_model =
@@ -26,7 +26,7 @@ min_exposure_time = 1
min_initial_exposure_time = 1
print_host =
printer_model = SL1
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_I-BOX_MONO\nFILEFORMAT_CTB\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_6\nLiftHeight_6\nBottomLiftSpeed_65\nLiftSpeed_65\nRetractSpeed_100\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\nPRINTER_VENDOR_QIDI\nPRINTER_MODEL_I-BOX_MONO\nFILEFORMAT_CTB\n\nSTART_CUSTOM_VALUES\nLightOffDelay_0\nBottomLightOffDelay_0\nBottomLiftHeight_7\nLiftHeight_7\nBottomLiftSpeed_80\nLiftSpeed_80\nRetractSpeed_120\nBottomLightPWM_255\nLightPWM_255\nEND_CUSTOM_VALUES
printer_settings_id =
printer_technology = SLA
printer_variant = default
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.01
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.01
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.01
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.02
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.02
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.025 UltraDetail
layer_height = 0.02
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.035 Detail
layer_height = 0.03
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.035 Detail
layer_height = 0.03
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.035 Detail
layer_height = 0.03
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.04
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.04
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.04
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.05
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.05
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.05 Normal
layer_height = 0.05
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.1
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.1
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.1
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.15
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.15
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.15
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.2
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.2
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5
inherits = 0.1 Fast
layer_height = 0.2
output_filename_format = {input_filename_base}_{material_type}{layer_height}mm_{printer_model}_{print_time}.sl1
output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.sl1
pad_around_object = 0
pad_around_object_everywhere = 0
pad_brim_size = 1.6
Binary file not shown.
+18 -1
View File
@@ -63,10 +63,27 @@ namespace UVtools.Core.Extensions
public static unsafe Span<T> GetPixelRowSpan<T>(this Mat mat, int y, int length = 0, int offset = 0)
{
return new Span<T>(IntPtr.Add(mat.DataPointer, y * mat.Step + offset).ToPointer(), length == 0 ? mat.Step : length);
return new(IntPtr.Add(mat.DataPointer, y * mat.Step + offset).ToPointer(), length == 0 ? mat.Step : length);
//return mat.GetPixelSpan<T>().Slice(offset, mat.Step);
}
/// <summary>
/// Gets if a <see cref="Mat"/> is all zeroed
/// </summary>
/// <param name="mat"></param>
/// <param name="threshold">Pixel brightness threshold</param>
/// <returns></returns>
public static unsafe bool IsZeroed(this Mat mat, byte threshold = 0)
{
var ptr = mat.GetBytePointer();
for (int i = 0; i < mat.GetLength(); i++)
{
if (ptr[i] > threshold) return false;
}
return true;
}
public static void Transform(this Mat src, double xScale, double yScale, double xTrans = 0, double yTrans = 0, Size dstSize = default, Inter interpolation = Inter.Linear)
{
//var dst = new Mat(src.Size, src.Depth, src.NumberOfChannels);
+5 -1
View File
@@ -103,12 +103,16 @@ namespace UVtools.Core.Extensions
public static uint DecimalDigits(this decimal val)
{
var valStr = val.ToString(CultureInfo.InvariantCulture).TrimEnd('0');
if (string.IsNullOrEmpty(valStr) || valStr[valStr.Length-1] == '.') return 0;
if (string.IsNullOrEmpty(valStr) || valStr[^1] == '.') return 0;
var index = valStr.IndexOf('.');
if (index < 0) return 0;
return (uint)(valStr.Substring(index).Length - 1);
}
public static bool IsInteger(this float val, float tolerance = 0.0001f) => Math.Abs(val - Math.Floor(val)) < tolerance;
public static bool IsInteger(this double val, double tolerance = 0.0001) => Math.Abs(val - Math.Floor(val)) < tolerance;
public static bool IsInteger(this decimal val) => val == Math.Floor(val);
}
}
+14
View File
@@ -6,6 +6,7 @@
* of this license document, but changing it is not allowed.
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace UVtools.Core.Extensions
@@ -19,5 +20,18 @@ namespace UVtools.Core.Extensions
var splitPath = path.Split('.', 2, StringSplitOptions.TrimEntries);
return splitPath.Length == 0 ? string.Empty : splitPath[0];
}
public static string GetFileNameStripExtensions(string path, List<string> extensions)
{
path = Path.GetFileName(path);
if (string.IsNullOrEmpty(path)) return string.Empty;
foreach (var extension in extensions)
{
var dotExtension = $".{extension}";
if (path.EndsWith(dotExtension)) return path.Remove(path.Length - dotExtension.Length);
}
return path;
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
namespace UVtools.Core.Extensions
@@ -34,5 +35,8 @@ namespace UVtools.Core.Extensions
adjustedSize,
SizeSuffixes[mag]);
}
public static Size Inflate(this Size size, int pixels) => new (size.Width + pixels, size.Height + pixels);
public static Size Inflate(this Size size, int width, int height) => new (size.Width + width, size.Height + height);
}
}
+4 -14
View File
@@ -540,12 +540,8 @@ namespace UVtools.Core.FileFormats
GCode = null;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
//var filename = fileFullPath.EndsWith(TemporaryFileAppend) ? Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(fileFullPath)) : Path.GetFileNameWithoutExtension(fileFullPath);
if (Printer == PrinterType.Unknown)
@@ -662,20 +658,14 @@ namespace UVtools.Core.FileFormats
RebuildGCode();
outputFile.PutFileContent($"{filename}.gcode", GCode.ToString(), ZipArchiveMode.Create);
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress(OperationProgress.StatusGatherLayers, LayerCount);
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
{
var entry = inputFile.GetEntry("manifest.xml");
if (!ReferenceEquals(entry, null)) // Wanhao
if (entry is not null) // Wanhao
{
//DecodeXML(fileFullPath, inputFile, progress);
Printer = PrinterType.Wanhao;
+5 -20
View File
@@ -1336,17 +1336,13 @@ namespace UVtools.Core.FileFormats
LayerDefinitions = null;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
LayersHash.Clear();
HeaderSettings.Magic = fileFullPath.EndsWith(".ctb") || fileFullPath.EndsWith($".ctb{TemporaryFileAppend}") ? MAGIC_CBT : MAGIC_CBDDLP;
HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
if (IsCbtFile)
{
if (SlicerInfoSettings.AntiAliasLevel <= 1)
@@ -1380,8 +1376,8 @@ namespace UVtools.Core.FileFormats
}
else
{
HeaderSettings.Version = 2;
HeaderSettings.EncryptionKey = 0;
//HeaderSettings.Version = 2;
HeaderSettings.EncryptionKey = 0; // Force disable encryption
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CBDDLP;
}
@@ -1511,8 +1507,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]);
@@ -1524,13 +1518,8 @@ namespace UVtools.Core.FileFormats
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
//HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
@@ -1659,8 +1648,7 @@ namespace UVtools.Core.FileFormats
return;
}
using (var image = LayerDefinitions[0, layerIndex].Decode((uint) layerIndex))
{
using var image = LayerDefinitions[0, layerIndex].Decode((uint) layerIndex);
var layer = new Layer((uint) layerIndex, image, LayerManager)
{
PositionZ = LayerDefinitions[0, layerIndex].LayerPositionZ,
@@ -1686,11 +1674,8 @@ namespace UVtools.Core.FileFormats
{
progress++;
}
}
});
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+3 -13
View File
@@ -400,11 +400,8 @@ namespace UVtools.Core.FileFormats
#region Methods
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
{
if (Thumbnails.Length > 0 && !ReferenceEquals(Thumbnails[0], null))
@@ -448,21 +445,14 @@ namespace UVtools.Core.FileFormats
progress++;
}
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
{
var entry = inputFile.GetEntry("run.gcode");
if (!ReferenceEquals(entry, null))
if (entry is not null)
{
//Clear();
//throw new FileLoadException("run.gcode not found", fileFullPath);
+2 -12
View File
@@ -999,11 +999,8 @@ namespace UVtools.Core.FileFormats
LayersDefinitions = null;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
LayersHash.Clear();
/*if (HeaderSettings.EncryptionKey == 0)
@@ -1118,8 +1115,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]);
@@ -1128,11 +1123,8 @@ namespace UVtools.Core.FileFormats
}
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress(OperationProgress.StatusGatherLayers, LayerCount);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
@@ -1235,8 +1227,6 @@ namespace UVtools.Core.FileFormats
}
});
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+437 -48
View File
@@ -26,7 +26,7 @@ namespace UVtools.Core.FileFormats
/// <summary>
/// Slicer <see cref="FileFormat"/> representation
/// </summary>
public abstract class FileFormat : BindableBase, IFileFormat, IDisposable, IEquatable<FileFormat>, IEnumerable<Layer>
public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFormat>, IEnumerable<Layer>
{
#region Constants
public const string TemporaryFileAppend = ".tmp";
@@ -44,6 +44,9 @@ namespace UVtools.Core.FileFormats
public const float DefaultLightOffDelay = 0;
public const byte DefaultBottomLightPWM = 255;
public const byte DefaultLightPWM = 255;
public const float MinimumLayerHeight = 0.01f;
public const float MaximumLayerHeight = 0.20f;
#endregion
#region Enums
@@ -192,9 +195,9 @@ namespace UVtools.Core.FileFormats
new SL1File(), // Prusa SL1
new ChituboxZipFile(), // Zip
new ChituboxFile(), // cbddlp, cbt, photon
new PhotonSFile(), // photons
new PHZFile(), // phz
new FDGFile(), // fdg
new PhotonSFile(), // photons
new PhotonWorkshopFile(), // PSW
new ZCodexFile(), // zcodex
new CWSFile(), // CWS
@@ -244,17 +247,26 @@ namespace UVtools.Core.FileFormats
}
public static List<FileExtension> AllFileExtensions
{
get
{
List<FileExtension> extensions = new();
foreach (var slicerFile in AvailableFormats)
{
extensions.AddRange(slicerFile.FileExtensions);
}
return extensions;
}
}
public static List<string> AllFileExtensionsString => (from slicerFile in AvailableFormats from extension in slicerFile.FileExtensions select extension.Extension).ToList();
/// <summary>
/// Gets the count of available file extensions
/// </summary>
public static byte FileExtensionsCount
{
get
{
return AvailableFormats.Aggregate<FileFormat, byte>(0, (current, fileFormat) => (byte) (current + fileFormat.FileExtensions.Length));
}
}
public static byte FileExtensionsCount => AvailableFormats.Aggregate<FileFormat, byte>(0, (current, fileFormat) => (byte) (current + fileFormat.FileExtensions.Length));
/// <summary>
/// Find <see cref="FileFormat"/> by an extension
@@ -285,14 +297,54 @@ namespace UVtools.Core.FileFormats
}
#endregion
#region Members
private bool _haveModifiedLayers;
private LayerManager _layerManager;
private float _printTime;
private float _maxPrintHeight;
#endregion
#region Properties
/// <summary>
/// Gets the file format type
/// </summary>
public abstract FileFormatType FileType { get; }
/// <summary>
/// Gets the valid file extensions for this <see cref="FileFormat"/>
/// </summary>
public abstract FileExtension[] FileExtensions { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
public abstract PrintParameterModifier[] PrintParameterModifiers { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/> per layer
/// </summary>
public virtual PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = null;
/// <summary>
/// Checks if a <see cref="PrintParameterModifier"/> exists on print parameters
/// </summary>
/// <param name="modifier"></param>
/// <returns>True if exists, otherwise false</returns>
public bool HavePrintParameterModifier(PrintParameterModifier modifier) =>
PrintParameterModifiers is not null && PrintParameterModifiers.Contains(modifier);
/// <summary>
/// Checks if a <see cref="PrintParameterModifier"/> exists on print parameters
/// </summary>
/// <param name="modifier"></param>
/// <returns>True if exists, otherwise false</returns>
public bool HavePrintParameterPerLayerModifier(PrintParameterModifier modifier) =>
PrintParameterPerLayerModifiers is not null && PrintParameterPerLayerModifiers.Contains(modifier);
/// <summary>
/// Gets the file filter for open and save dialogs
/// </summary>
public string FileFilter {
get
{
@@ -311,9 +363,15 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets all valid file extensions for Avalonia file dialog
/// </summary>
public List<KeyValuePair<string, List<string>>> FileFilterAvalonia
=> FileExtensions.Select(fileExt => new KeyValuePair<string, List<string>>(fileExt.Description, new List<string> {fileExt.Extension})).ToList();
/// <summary>
/// Gets all valid file extensions in "*.extension1;*.extension2" format
/// </summary>
public string FileFilterExtensionsOnly
{
get
@@ -333,12 +391,24 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets or sets if change a global property should rebuild every layer data based on them
/// </summary>
public bool SuppressRebuildProperties { get; set; }
/// <summary>
/// Gets the input file path loaded into this <see cref="FileFormat"/>
/// </summary>
public string FileFullPath { get; set; }
/// <summary>
/// Gets the thumbnails count present in this file format
/// </summary>
public abstract byte ThumbnailsCount { get; }
/// <summary>
/// Gets the number of created thumbnails
/// </summary>
public byte CreatedThumbnailsCount {
get
{
@@ -355,10 +425,19 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets the original thumbnail sizes
/// </summary>
public abstract Size[] ThumbnailsOriginalSize { get; }
/// <summary>
/// Gets the thumbnails for this <see cref="FileFormat"/>
/// </summary>
public Mat[] Thumbnails { get; set; }
/// <summary>
/// Gets the cached layers into compressed bytes
/// </summary>
public LayerManager LayerManager
{
get => _layerManager;
@@ -373,10 +452,10 @@ namespace UVtools.Core.FileFormats
}
}
private bool _haveModifiedLayers;
private LayerManager _layerManager;
private float _printTime;
private float _maxPrintHeight;
/// <summary>
/// Gets the bounding rectangle of the object
/// </summary>
public Rectangle BoundingRectangle => _layerManager?.BoundingRectangle ?? Rectangle.Empty;
/// <summary>
/// Gets or sets if modifications require a full encode to save
@@ -387,6 +466,9 @@ namespace UVtools.Core.FileFormats
set => _haveModifiedLayers = value;
} // => LayerManager.IsModified;
/// <summary>
/// Gets the image width resolution
/// </summary>
public Size Resolution
{
get => new((int)ResolutionX, (int)ResolutionY);
@@ -398,10 +480,19 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets the image width resolution
/// </summary>
public abstract uint ResolutionX { get; set; }
/// <summary>
/// Gets the image height resolution
/// </summary>
public abstract uint ResolutionY { get; set; }
/// <summary>
/// Gets the size of display in millimeters
/// </summary>
public SizeF Display
{
get => new(DisplayWidth, DisplayHeight);
@@ -413,16 +504,33 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets or sets the display width in millimeters
/// </summary>
public abstract float DisplayWidth { get; set; }
/// <summary>
/// Gets or sets the display height in millimeters
/// </summary>
public abstract float DisplayHeight { get; set; }
/// <summary>
/// Gets or sets if images need to be mirrored on lcd to print on the correct orientation
/// </summary>
public abstract bool MirrorDisplay { get; set; }
/// <summary>
/// Gets or sets the maximum printer build Z volume
/// </summary>
public virtual float MaxPrintHeight
{
get => _maxPrintHeight > 0 ? _maxPrintHeight : PrintHeight;
set => RaiseAndSetIfChanged(ref _maxPrintHeight, value);
}
/// <summary>
/// Gets or sets the pixels per mm on X direction
/// </summary>
public virtual float Xppmm
{
get => DisplayWidth > 0 ? ResolutionX / DisplayWidth : 0;
@@ -433,6 +541,9 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets or sets the pixels per mm on Y direction
/// </summary>
public virtual float Yppmm
{
get => DisplayHeight > 0 ? ResolutionY / DisplayHeight : 0;
@@ -443,6 +554,9 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets or sets the pixels per mm
/// </summary>
public SizeF Ppmm
{
get => new(Xppmm, Yppmm);
@@ -454,6 +568,9 @@ namespace UVtools.Core.FileFormats
}
/// <summary>
/// Gets the printer XY pixel resolution
/// </summary>
public decimal XYResolution => DisplayWidth > 0 || DisplayHeight > 0 ?
(decimal) Math.Round(Math.Max(
DisplayWidth / ResolutionX,
@@ -461,6 +578,9 @@ namespace UVtools.Core.FileFormats
), 3)
: 0;
/// <summary>
/// Gets the printer XY pixel resolution in microns
/// </summary>
public decimal XYResolutionUm => DisplayWidth > 0 || DisplayHeight > 0 ?
(decimal)Math.Round(Math.Max(
DisplayWidth / ResolutionX,
@@ -468,11 +588,30 @@ namespace UVtools.Core.FileFormats
), 3) * 1000
: 0;
/// <summary>
/// Checks if this file have AntiAliasing
/// </summary>
public bool HaveAntiAliasing => AntiAliasing > 1;
/// <summary>
/// Gets or sets the AntiAliasing level
/// </summary>
public abstract byte AntiAliasing { get; set; }
/// <summary>
/// Gets Layer Height in mm
/// </summary>
public abstract float LayerHeight { get; set; }
/// <summary>
/// Gets Layer Height in um
/// </summary>
public ushort LayerHeightUm => (ushort) (LayerHeight * 1000);
/// <summary>
/// Gets or sets the print height in mm
/// </summary>
public virtual float PrintHeight
{
get => LayerCount == 0 ? 0 : this[LayerCount - 1]?.PositionZ ?? 0;
@@ -482,30 +621,97 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets the last layer index
/// </summary>
public uint LastLayerIndex => LayerCount - 1;
/// <summary>
/// Checks if this file format supports per layer settings
/// </summary>
public virtual bool SupportPerLayerSettings => !(PrintParameterPerLayerModifiers is null || PrintParameterPerLayerModifiers.Length == 0);
/// <summary>
/// Gets or sets the layer count
/// </summary>
public virtual uint LayerCount
{
get => LayerManager?.Count ?? 0;
set { }
}
#region Universal Properties
/// <summary>
/// Gets or sets the number of initial layer count
/// </summary>
public virtual ushort BottomLayerCount { get; set; }
/// <summary>
/// Gets the number of normal layer count
/// </summary>
public uint NormalLayerCount => LayerCount - BottomLayerCount;
/// <summary>
/// Gets or sets the initial exposure time for <see cref="BottomLayerCount"/> in seconds
/// </summary>
public virtual float BottomExposureTime { get; set; }
/// <summary>
/// Gets or sets the normal layer exposure time in seconds
/// </summary>
public virtual float ExposureTime { get; set; }
/// <summary>
/// Gets or sets the bottom layer off time in seconds
/// </summary>
public virtual float BottomLightOffDelay { get; set; } = DefaultBottomLightOffDelay;
/// <summary>
/// Gets or sets the layer off time in seconds
/// </summary>
public virtual float LightOffDelay { get; set; } = DefaultLightOffDelay;
/// <summary>
/// Gets or sets the bottom lift height in mm
/// </summary>
public virtual float BottomLiftHeight { get; set; } = DefaultBottomLiftHeight;
/// <summary>
/// Gets or sets the lift height in mm
/// </summary>
public virtual float LiftHeight { get; set; } = DefaultLiftHeight;
/// <summary>
/// Gets or sets the bottom lift speed in mm/min
/// </summary>
public virtual float BottomLiftSpeed { get; set; } = DefaultBottomLiftSpeed;
/// <summary>
/// Gets or sets the speed in mm/min
/// </summary>
public virtual float LiftSpeed { get; set; } = DefaultLiftSpeed;
/// <summary>
/// Gets the speed in mm/min for the retracts
/// </summary>
public virtual float RetractSpeed { get; set; } = DefaultRetractSpeed;
/// <summary>
/// Gets or sets the bottom pwm value from 0 to 255
/// </summary>
public virtual byte BottomLightPWM { get; set; } = DefaultBottomLightPWM;
/// <summary>
/// Gets or sets the pwm value from 0 to 255
/// </summary>
public virtual byte LightPWM { get; set; } = DefaultLightPWM;
#endregion
/// <summary>
/// Gets the estimate print time in seconds
/// </summary>
public virtual float PrintTime
{
get => _printTime;
@@ -520,9 +726,14 @@ namespace UVtools.Core.FileFormats
}
}
//(header.numberOfLayers - header.bottomLayers) * (double) header.exposureTimeSeconds + (double) header.bottomLayers * (double) header.exposureBottomTimeSeconds + (double) header.offTimeSeconds * (double) header.numberOfLayers);
/// <summary>
/// Gets the estimate print time in seconds, if print doesn't support it it will be calculated
/// </summary>
public float PrintTimeOrComputed => PrintTime > 0 ? PrintTime : PrintTimeComputed;
/// <summary>
/// Gets the calculated estimate print time in seconds
/// </summary>
public float PrintTimeComputed
{
get
@@ -562,27 +773,65 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets the estimate print time in hours
/// </summary>
public float PrintTimeHours => (float) Math.Round(PrintTimeOrComputed / 3600, 2);
/// <summary>
/// Gets the estimate print time in hours and minutes formatted
/// </summary>
public string PrintTimeString => TimeSpan.FromSeconds(PrintTimeOrComputed).ToString("hh\\hmm\\m");
/// <summary>
/// Gets the estimate used material in ml
/// </summary>
public virtual float MaterialMilliliters { get; set; }
/// <summary>
/// Gets the estimate material in grams
/// </summary>
public virtual float MaterialGrams { get; set; }
/// <summary>
/// Gets the estimate material cost
/// </summary>
public virtual float MaterialCost { get; set; }
/// <summary>
/// Gets the material name
/// </summary>
public virtual string MaterialName { get; set; }
/// <summary>
/// Gets the machine name
/// </summary>
public virtual string MachineName { get; set; } = "Unknown";
/// <summary>
/// Gets the GCode, returns null if not supported
/// </summary>
public StringBuilder GCode { get; set; }
/// <summary>
/// Gets the GCode, returns null if not supported
/// </summary>
public string GCodeStr => GCode?.ToString();
public bool HaveGCode => !(GCode is null);
/// <summary>
/// Gets if this file have available gcode
/// </summary>
public bool HaveGCode => GCode is not null;
/// <summary>
/// Get all configuration objects with properties and values
/// </summary>
public abstract object[] Configs { get; }
public bool IsValid => !ReferenceEquals(FileFullPath, null);
/// <summary>
/// Gets if this file is valid to read
/// </summary>
public bool IsValid => FileFullPath is not null;
#endregion
#region Constructor
@@ -675,7 +924,7 @@ namespace UVtools.Core.FileFormats
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FileFullPath.Equals(other.FileFullPath);
return FileFullPath == other.FileFullPath;
}
public override int GetHashCode()
@@ -691,26 +940,31 @@ namespace UVtools.Core.FileFormats
#endregion
#region Methods
/// <summary>
/// Clears all definitions and properties, it also dispose valid candidates
/// </summary>
public virtual void Clear()
{
FileFullPath = null;
LayerManager = null;
GCode = null;
if (!ReferenceEquals(Thumbnails, null))
if (Thumbnails is not null)
{
for (int i = 0; i < ThumbnailsCount; i++)
{
Thumbnails[i]?.Dispose();
}
}
}
/// <summary>
/// Validate if a file is a valid <see cref="FileFormat"/>
/// </summary>
/// <param name="fileFullPath">Full file path</param>
public void FileValidation(string fileFullPath)
{
if (ReferenceEquals(fileFullPath, null)) throw new ArgumentNullException(nameof(FileFullPath), "fullFilePath can't be null.");
if (fileFullPath is null) throw new ArgumentNullException(nameof(FileFullPath), "fullFilePath can't be null.");
if (!File.Exists(fileFullPath)) throw new FileNotFoundException("The specified file does not exists.", fileFullPath);
if (IsExtensionValid(fileFullPath, true))
@@ -721,12 +975,21 @@ namespace UVtools.Core.FileFormats
throw new FileLoadException($"The specified file is not valid.", fileFullPath);
}
/// <summary>
/// Checks if a extension is valid under the <see cref="FileFormat"/>
/// </summary>
/// <param name="extension">Extension to check</param>
/// <param name="isFilePath">True if <see cref="extension"/> is a full file path, otherwise false for extension only</param>
/// <returns>True if valid, otherwise false</returns>
public bool IsExtensionValid(string extension, bool isFilePath = false)
{
extension = isFilePath ? Path.GetExtension(extension)?.Remove(0, 1) : extension;
return FileExtensions.Any(fileExtension => fileExtension.Equals(extension));
}
/// <summary>
/// Gets all valid file extensions in a specified format
/// </summary>
public string GetFileExtensions(string prepend = ".", string separator = ", ")
{
var result = string.Empty;
@@ -743,6 +1006,11 @@ namespace UVtools.Core.FileFormats
return result;
}
/// <summary>
/// Gets a thumbnail by it height or lower
/// </summary>
/// <param name="maxHeight">Max height allowed</param>
/// <returns></returns>
public Mat GetThumbnail(uint maxHeight = 400)
{
for (int i = 0; i < ThumbnailsCount; i++)
@@ -754,6 +1022,11 @@ namespace UVtools.Core.FileFormats
return null;
}
/// <summary>
/// Gets a thumbnail by the largest or smallest
/// </summary>
/// <param name="largest">True to get the largest, otherwise false</param>
/// <returns></returns>
public Mat GetThumbnail(bool largest)
{
switch (CreatedThumbnailsCount)
@@ -774,6 +1047,10 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Sets thumbnails from a list of thumbnails and clone them
/// </summary>
/// <param name="images"></param>
public void SetThumbnails(Mat[] images)
{
for (var i = 0; i < ThumbnailsCount; i++)
@@ -786,6 +1063,10 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Sets all thumbnails the same image
/// </summary>
/// <param name="images">Image to set</param>
public void SetThumbnails(Mat image)
{
for (var i = 0; i < ThumbnailsCount; i++)
@@ -798,6 +1079,11 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Sets a thumbnail from a disk file
/// </summary>
/// <param name="index">Thumbnail index</param>
/// <param name="filePath"></param>
public void SetThumbnail(int index, string filePath)
{
Thumbnails[index] = CvInvoke.Imread(filePath, ImreadModes.AnyColor);
@@ -807,8 +1093,23 @@ namespace UVtools.Core.FileFormats
}
}
public virtual void Encode(string fileFullPath, OperationProgress progress = null)
/// <summary>
/// Encode to an output file
/// </summary>
/// <param name="fileFullPath">Output file</param>
/// <param name="progress"></param>
protected abstract void EncodeInternally(string fileFullPath, OperationProgress progress);
/// <summary>
/// Encode to an output file
/// </summary>
/// <param name="fileFullPath">Output file</param>
/// <param name="progress"></param>
public void Encode(string fileFullPath, OperationProgress progress = null)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
FileFullPath = fileFullPath;
if (File.Exists(fileFullPath))
@@ -822,25 +1123,69 @@ namespace UVtools.Core.FileFormats
if(Thumbnails[i].Size == ThumbnailsOriginalSize[i]) continue;
CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height));
}
}
public void AfterEncode()
{
EncodeInternally(fileFullPath, progress);
LayerManager.Desmodify();
RequireFullEncode = false;
}
public virtual void Decode(string fileFullPath, OperationProgress progress = null)
/// <summary>
/// Decode a slicer file
/// </summary>
/// <param name="fileFullPath"></param>
/// <param name="progress"></param>
protected abstract void DecodeInternally(string fileFullPath, OperationProgress progress);
/// <summary>
/// Decode a slicer file
/// </summary>
/// <param name="fileFullPath"></param>
/// <param name="progress"></param>
public void Decode(string fileFullPath, OperationProgress progress = null)
{
Clear();
FileValidation(fileFullPath);
FileFullPath = fileFullPath;
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
DecodeInternally(fileFullPath, progress);
progress.Token.ThrowIfCancellationRequested();
// Sanitize
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
// Check for null layers
if(this[layerIndex] is null) throw new FileLoadException($"Layer {layerIndex} was defined but doesn't contain a valid image.", fileFullPath);
if(layerIndex <= 0) continue;
// Check for bigger position z than it successor
if(this[layerIndex-1].PositionZ > this[layerIndex].PositionZ) throw new FileLoadException($"Layer {layerIndex-1} ({this[layerIndex - 1].PositionZ}mm) have a higher Z position than the successor layer {layerIndex} ({this[layerIndex].PositionZ}mm).\n", fileFullPath);
}
// Fix 0mm positions at layer 0
if(this[0].PositionZ == 0)
{
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
this[layerIndex].PositionZ += LayerHeight;
}
Save(progress);
}
}
/// <summary>
/// Extract contents to a folder
/// </summary>
/// <param name="path">Path to folder where content will be extracted</param>
/// <param name="genericConfigExtract"></param>
/// <param name="genericLayersExtract"></param>
/// <param name="progress"></param>
public virtual void Extract(string path, bool genericConfigExtract = true, bool genericLayersExtract = true,
OperationProgress progress = null)
{
if (ReferenceEquals(progress, null)) progress = new OperationProgress();
progress ??= new OperationProgress();
progress.ItemName = OperationProgress.StatusExtracting;
/*if (emptyFirst)
{
@@ -955,16 +1300,33 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Get height in mm from layer height
/// </summary>
/// <param name="layerIndex"></param>
/// <param name="realHeight"></param>
/// <returns>The height in mm</returns>
public float GetHeightFromLayer(uint layerIndex, bool realHeight = true)
{
return (float)Math.Round((layerIndex+(realHeight ? 1 : 0)) * LayerHeight, 2);
}
/// <summary>
/// Gets the value for initial layer or normal layers based on layer index
/// </summary>
/// <typeparam name="T">Type of value</typeparam>
/// <param name="layerIndex">Layer index</param>
/// <param name="initialLayerValue">Initial value</param>
/// <param name="normalLayerValue">Normal value</param>
/// <returns></returns>
public T GetInitialLayerValueOrNormal<T>(uint layerIndex, T initialLayerValue, T normalLayerValue)
{
return layerIndex < BottomLayerCount ? initialLayerValue : normalLayerValue;
}
/// <summary>
/// Refresh print parameters globals with this file settings
/// </summary>
public void RefreshPrintParametersModifiersValues()
{
if (PrintParameterModifiers is null) return;
@@ -1029,6 +1391,9 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Refresh print parameters per layer globals with this file settings
/// </summary>
public void RefreshPrintParametersPerLayerModifiersValues(uint layerIndex)
{
if (PrintParameterPerLayerModifiers is null) return;
@@ -1065,6 +1430,11 @@ namespace UVtools.Core.FileFormats
}
}
/// <summary>
/// Gets the value attributed to <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
/// <param name="modifier">Modifier to use</param>
/// <returns>A value</returns>
public object GetValueFromPrintParameterModifier(PrintParameterModifier modifier)
{
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount))
@@ -1098,6 +1468,12 @@ namespace UVtools.Core.FileFormats
return null;
}
/// <summary>
/// Sets a property value attributed to <see cref="modifier"/>
/// </summary>
/// <param name="modifier">Modifier to use</param>
/// <param name="value">Value to set</param>
/// <returns>True if set, otherwise false = <see cref="modifier"/> not found</returns>
public bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, decimal value)
{
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount))
@@ -1167,6 +1543,10 @@ namespace UVtools.Core.FileFormats
return false;
}
/// <summary>
/// Sets properties from print parameters
/// </summary>
/// <returns>Number of affected parameters</returns>
public byte SetValuesFromPrintParametersModifiers()
{
if (PrintParameterModifiers is null) return 0;
@@ -1182,36 +1562,34 @@ namespace UVtools.Core.FileFormats
return changed;
}
public void EditPrintParameters(OperationEditParameters operation)
{
if (operation.PerLayerOverride)
{
for (uint layerIndex = operation.LayerIndexStart; layerIndex <= operation.LayerIndexEnd; layerIndex++)
{
this[layerIndex].SetValuesFromPrintParametersModifiers(operation.Modifiers);
}
foreach (var modifier in operation.Modifiers)
{
modifier.OldValue = modifier.NewValue;
}
RebuildGCode();
}
else
{
SetValuesFromPrintParametersModifiers();
}
}
/// <summary>
/// Rebuilds GCode based on current settings
/// </summary>
public virtual void RebuildGCode() { }
/// <summary>
/// Saves current configuration on input file
/// </summary>
/// <param name="progress"></param>
public void Save(OperationProgress progress = null)
{
SaveAs(null, progress);
}
/// <summary>
/// Saves current configuration on a copy
/// </summary>
/// <param name="filePath">File path to save copy as, use null to overwrite active file (Same as <see cref="Save"/>)</param>
/// <param name="progress"></param>
public abstract void SaveAs(string filePath = null, OperationProgress progress = null);
/// <summary>
/// Converts this file type to another file type
/// </summary>
/// <param name="to">Target file format</param>
/// <param name="fileFullPath">Output path file</param>
/// <param name="progress"></param>
/// <returns>The converted file if successful, otherwise null</returns>
public virtual FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null)
{
if (!IsValid) return null;
@@ -1270,9 +1648,20 @@ namespace UVtools.Core.FileFormats
return slicerFile;
}
/// <summary>
/// Converts this file type to another file type
/// </summary>
/// <param name="to">Target file format</param>
/// <param name="fileFullPath">Output path file</param>
/// <param name="progress"></param>
/// <returns>TThe converted file if successful, otherwise null</returns>
public FileFormat Convert(FileFormat to, string fileFullPath, OperationProgress progress = null)
=> Convert(to.GetType(), fileFullPath, progress);
/// <summary>
/// Validate AntiAlias Level
/// </summary>
public byte ValidateAntiAliasingLevel()
{
if (AntiAliasing < 2) return 1;
-510
View File
@@ -1,510 +0,0 @@
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
using System.Drawing;
using System.Text;
using Emgu.CV;
using UVtools.Core.Operations;
namespace UVtools.Core.FileFormats
{
/// <summary>
/// Slicer file format representation interface
/// </summary>
public interface IFileFormat
{
#region Properties
/// <summary>
/// Gets the file format type
/// </summary>
FileFormat.FileFormatType FileType { get; }
/// <summary>
/// Gets the valid file extensions for this <see cref="FileFormat"/>
/// </summary>
FileExtension[] FileExtensions { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
FileFormat.PrintParameterModifier[] PrintParameterModifiers { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/> per layer
/// </summary>
FileFormat.PrintParameterModifier[] PrintParameterPerLayerModifiers { get; }
/// <summary>
/// Gets the file filter for open and save dialogs
/// </summary>
string FileFilter { get; }
/// <summary>
/// Gets all valid file extensions in "*.extension1;*.extension2" format
/// </summary>
string FileFilterExtensionsOnly { get; }
/// <summary>
/// Gets or sets if change a global property should rebuild every layer data based on them
/// </summary>
bool SuppressRebuildProperties { get; set; }
/// <summary>
/// Gets the input file path loaded into this <see cref="FileFormat"/>
/// </summary>
string FileFullPath { get; set; }
/// <summary>
/// Gets the thumbnails count present in this file format
/// </summary>
byte ThumbnailsCount { get; }
/// <summary>
/// Gets the number of created thumbnails
/// </summary>
byte CreatedThumbnailsCount { get; }
/// <summary>
/// Gets the original thumbnail sizes
/// </summary>
System.Drawing.Size[] ThumbnailsOriginalSize { get; }
/// <summary>
/// Gets the thumbnails for this <see cref="FileFormat"/>
/// </summary>
Mat[] Thumbnails { get; set; }
/// <summary>
/// Gets the cached layers into compressed bytes
/// </summary>
LayerManager LayerManager { get; set; }
Size Resolution { get; set; }
/// <summary>
/// Gets the image width resolution
/// </summary>
uint ResolutionX { get; set; }
/// <summary>
/// Gets the image height resolution
/// </summary>
uint ResolutionY { get; set; }
/// <summary>
/// Gets the size of display in millimeters
/// </summary>
SizeF Display { get; set; }
/// <summary>
/// Gets or sets the display width in millimeters
/// </summary>
float DisplayWidth { get; set; }
/// <summary>
/// Gets or sets the display height in millimeters
/// </summary>
float DisplayHeight { get; set; }
/// <summary>
/// Gets or sets if images need to be mirrored on lcd to print on the correct orientation
/// </summary>
bool MirrorDisplay { get; set; }
/// <summary>
/// Gets or sets the maximum printer build Z volume
/// </summary>
float MaxPrintHeight { get; set; }
/// <summary>
/// Gets or sets the pixels per mm on X direction
/// </summary>
float Xppmm { get; set; }
/// <summary>
/// Gets or sets the pixels per mm on Y direction
/// </summary>
float Yppmm { get; set; }
/// <summary>
/// Gets or sets the pixels per mm
/// </summary>
SizeF Ppmm { get; set; }
/// <summary>
/// Gets the printer XY pixel resolution
/// </summary>
decimal XYResolution { get; }
/// <summary>
/// Gets the printer XY pixel resolution in microns
/// </summary>
decimal XYResolutionUm { get; }
bool HaveAntiAliasing { get; }
/// <summary>
/// Gets or sets the AntiAliasing level
/// </summary>
byte AntiAliasing { get; set; }
/// <summary>
/// Gets Layer Height in mm
/// </summary>
float LayerHeight { get; set; }
/// <summary>
/// Gets or sets the print height in mm
/// </summary>
float PrintHeight { get; set; }
/// <summary>
/// Gets the last layer index
/// </summary>
uint LastLayerIndex { get; }
#region Universal Properties
/// <summary>
/// Gets if this format support per layer override settings
/// </summary>
bool SupportPerLayerSettings { get; }
/// <summary>
/// Gets the number of layers present in this file
/// </summary>
uint LayerCount { get; set; }
/// <summary>
/// Gets or sets the number of initial layer count
/// </summary>
ushort BottomLayerCount { get; set; }
/// <summary>
/// Gets the number of normal layer count
/// </summary>
uint NormalLayerCount { get; }
/// <summary>
/// Gets or sets the initial exposure time for <see cref="BottomLayerCount"/> in seconds
/// </summary>
float BottomExposureTime { get; set; }
/// <summary>
/// Gets or sets the normal layer exposure time in seconds
/// </summary>
float ExposureTime { get; set; }
/// <summary>
/// Gets or sets the bottom layer off time in seconds
/// </summary>
float BottomLightOffDelay { get; set; }
/// <summary>
/// Gets or sets the layer off time in seconds
/// </summary>
float LightOffDelay { get; set; }
/// <summary>
/// Gets or sets the bottom lift height in mm
/// </summary>
float BottomLiftHeight { get; set; }
/// <summary>
/// Gets or sets the lift height in mm
/// </summary>
float LiftHeight { get; set; }
/// <summary>
/// Gets or sets the bottom lift speed in mm/min
/// </summary>
float BottomLiftSpeed { get; set; }
/// <summary>
/// Gets or sets the speed in mm/min
/// </summary>
float LiftSpeed { get; set; }
/// <summary>
/// Gets the speed in mm/min for the retracts
/// </summary>
float RetractSpeed { get; set; }
/// <summary>
/// Gets or sets the bottom pwm value from 0 to 255
/// </summary>
byte BottomLightPWM { get; set; }
/// <summary>
/// Gets or sets the pwm value from 0 to 255
/// </summary>
byte LightPWM { get; set; }
#endregion
/// <summary>
/// Gets the estimate print time in seconds
/// </summary>
float PrintTime { get; set; }
/// <summary>
/// Gets the estimate print time in seconds, if print doesn't support it it will be calculated
/// </summary>
float PrintTimeOrComputed { get; }
/// <summary>
/// Gets the calculated estimate print time in seconds
/// </summary>
float PrintTimeComputed { get; }
/// <summary>
/// Gets the estimate print time in hours
/// </summary>
float PrintTimeHours { get; }
/// <summary>
/// Gets the estimate print time in hours and minutes formatted
/// </summary>
string PrintTimeString { get; }
/// <summary>
/// Gets the estimate used material in ml
/// </summary>
float MaterialMilliliters { get; set; }
/// <summary>
/// Gets the estimate material in grams
/// </summary>
float MaterialGrams { get; set; }
/// <summary>
/// Gets the estimate material cost
/// </summary>
float MaterialCost { get; set; }
/// <summary>
/// Gets the material name
/// </summary>
string MaterialName { get; set; }
/// <summary>
/// Gets the machine name
/// </summary>
string MachineName { get; set; }
/// <summary>
/// Gets the GCode, returns null if not supported
/// </summary>
StringBuilder GCode { get; set; }
string GCodeStr { get; }
/// <summary>
/// Gets if this file have available gcode
/// </summary>
bool HaveGCode { get; }
/// <summary>
/// Get all configuration objects with properties and values
/// </summary>
object[] Configs { get; }
/// <summary>
/// Gets if this file is valid to read
/// </summary>
bool IsValid { get; }
#endregion
#region Methods
/// <summary>
/// Clears all definitions and properties, it also dispose valid candidates
/// </summary>
void Clear();
/// <summary>
/// Validate if a file is a valid <see cref="FileFormat"/>
/// </summary>
/// <param name="fileFullPath">Full file path</param>
void FileValidation(string fileFullPath);
/// <summary>
/// Checks if a extension is valid under the <see cref="FileFormat"/>
/// </summary>
/// <param name="extension">Extension to check</param>
/// <param name="isFilePath">True if <see cref="extension"/> is a full file path, otherwise false for extension only</param>
/// <returns>True if valid, otherwise false</returns>
bool IsExtensionValid(string extension, bool isFilePath = false);
/// <summary>
/// Gets all valid file extensions in a specified format
/// </summary>
string GetFileExtensions(string prepend = ".", string separator = ", ");
/// <summary>
/// Gets a thumbnail by it height or lower
/// </summary>
/// <param name="maxHeight">Max height allowed</param>
/// <returns></returns>
Mat GetThumbnail(uint maxHeight = 400);
/// <summary>
/// Gets a thumbnail by the largest or smallest
/// </summary>
/// <param name="largest">True to get the largest, otherwise false</param>
/// <returns></returns>
Mat GetThumbnail(bool largest);
/// <summary>
/// Sets thumbnails from a list of thumbnails and clone them
/// </summary>
/// <param name="images"></param>
void SetThumbnails(Mat[] images);
/// <summary>
/// Sets all thumbnails the same image
/// </summary>
/// <param name="images">Image to set</param>
void SetThumbnails(Mat images);
/// <summary>
/// Sets a thumbnail from a disk file
/// </summary>
/// <param name="index">Thumbnail index</param>
/// <param name="filePath"></param>
void SetThumbnail(int index, string filePath);
/// <summary>
/// Encode to an output file
/// </summary>
/// <param name="fileFullPath">Output file</param>
/// <param name="progress"></param>
void Encode(string fileFullPath, OperationProgress progress = null);
void AfterEncode();
/*
/// <summary>
/// Begin encode to an output file
/// </summary>
/// <param name="fileFullPath">Output file</param>
//void BeginEncode(string fileFullPath);
/// <summary>
/// Insert a layer image to be encoded
/// </summary>
/// <param name="image"></param>
/// <param name="layerIndex"></param>
//void InsertLayerImageEncode(Image<L8> image, uint layerIndex);
/// <summary>
/// Finish the encoding procedure
/// </summary>
//void EndEncode();*/
/// <summary>
/// Decode a slicer file
/// </summary>
/// <param name="fileFullPath"></param>
/// <param name="progress"></param>
void Decode(string fileFullPath, OperationProgress progress = null);
/// <summary>
/// Extract contents to a folder
/// </summary>
/// <param name="path">Path to folder where content will be extracted</param>
/// <param name="genericConfigExtract"></param>
/// <param name="genericLayersExtract"></param>
/// <param name="progress"></param>
void Extract(string path, bool genericConfigExtract = true, bool genericLayersExtract = true,
OperationProgress progress = null);
/// <summary>
/// Get height in mm from layer height
/// </summary>
/// <param name="layerIndex"></param>
/// <param name="realHeight"></param>
/// <returns>The height in mm</returns>
float GetHeightFromLayer(uint layerIndex, bool realHeight = true);
/// <summary>
/// Gets the value for initial layer or normal layers based on layer index
/// </summary>
/// <typeparam name="T">Type of value</typeparam>
/// <param name="layerIndex">Layer index</param>
/// <param name="initialLayerValue">Initial value</param>
/// <param name="normalLayerValue">Normal value</param>
/// <returns></returns>
T GetInitialLayerValueOrNormal<T>(uint layerIndex, T initialLayerValue, T normalLayerValue);
void RefreshPrintParametersModifiersValues();
void RefreshPrintParametersPerLayerModifiersValues(uint layerIndex);
/// <summary>
/// Gets the value attributed to <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
/// <param name="modifier">Modifier to use</param>
/// <returns>A value</returns>
object GetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier);
/// <summary>
/// Sets a property value attributed to <see cref="modifier"/>
/// </summary>
/// <param name="modifier">Modifier to use</param>
/// <param name="value">Value to set</param>
/// <returns>True if set, otherwise false = <see cref="modifier"/> not found</returns>
bool SetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier, decimal value);
byte SetValuesFromPrintParametersModifiers();
void EditPrintParameters(OperationEditParameters operation);
/// <summary>
/// Rebuilds GCode based on current settings
/// </summary>
void RebuildGCode();
/// <summary>
/// Saves current configuration on input file
/// </summary>
/// <param name="progress"></param>
void Save(OperationProgress progress = null);
/// <summary>
/// Saves current configuration on a copy
/// </summary>
/// <param name="filePath">File path to save copy as, use null to overwrite active file (Same as <see cref="Save"/>)</param>
/// <param name="progress"></param>
void SaveAs(string filePath = null, OperationProgress progress = null);
/// <summary>
/// Converts this file type to another file type
/// </summary>
/// <param name="to">Target file format</param>
/// <param name="fileFullPath">Output path file</param>
/// <param name="progress"></param>
/// <returns>The converted file if successful, otherwise null</returns>
FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null);
/// <summary>
/// Converts this file type to another file type
/// </summary>
/// <param name="to">Target file format</param>
/// <param name="fileFullPath">Output path file</param>
/// <param name="progress"></param>
/// <returns>TThe converted file if successful, otherwise null</returns>
FileFormat Convert(FileFormat to, string fileFullPath, OperationProgress progress = null);
/// <summary>
/// Validate AntiAlias Level
/// </summary>
byte ValidateAntiAliasingLevel();
#endregion
}
}
+6 -3
View File
@@ -76,10 +76,13 @@ namespace UVtools.Core.FileFormats
private Mat ImageMat { get; set; }
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
throw new NotSupportedException();
}
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
ImageMat = CvInvoke.Imread(fileFullPath, ImreadModes.Grayscale);
const byte startDivisor = 2;
for (int i = 0; i < ThumbnailsCount; i++)
@@ -106,7 +109,7 @@ namespace UVtools.Core.FileFormats
public override FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null)
{
throw new NotImplementedException();
throw new NotSupportedException();
}
+4 -19
View File
@@ -450,12 +450,9 @@ namespace UVtools.Core.FileFormats
return bytes;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
if (ResolutionY >= 2560) // Longer Orange 30
{
HeaderSettings.Float_94 = 170;
@@ -495,8 +492,6 @@ namespace UVtools.Core.FileFormats
}
}
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-");
@@ -522,10 +517,8 @@ namespace UVtools.Core.FileFormats
return mat;
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
HeaderSettings = Helpers.Deserialize<Header>(inputFile);
@@ -570,25 +563,17 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
using (var image = layerData[layerIndex].Decode())
{
using var image = layerData[layerIndex].Decode();
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
lock (progress.Mutex)
{
progress++;
}
}
});
LayerManager.RebuildLayersProperties();
FileFullPath = fileFullPath;
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+2 -14
View File
@@ -150,10 +150,8 @@ namespace UVtools.Core.FileFormats
#endregion
#region Methods
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
base.Encode(fileFullPath, progress);
uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
{
@@ -164,8 +162,6 @@ namespace UVtools.Core.FileFormats
}
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-");
@@ -173,10 +169,8 @@ namespace UVtools.Core.FileFormats
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
//HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
@@ -186,13 +180,7 @@ namespace UVtools.Core.FileFormats
{
throw new FileLoadException("Not a valid Makerfile file!", fileFullPath);
}
FileFullPath = fileFullPath;
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+2 -15
View File
@@ -1017,11 +1017,8 @@ namespace UVtools.Core.FileFormats
LayersDefinitions = null;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
LayersHash.Clear();
/*if (HeaderSettings.EncryptionKey == 0)
@@ -1139,8 +1136,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]);
@@ -1149,11 +1144,8 @@ namespace UVtools.Core.FileFormats
}
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress(OperationProgress.StatusGatherLayers, LayerCount);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
@@ -1167,9 +1159,6 @@ namespace UVtools.Core.FileFormats
HeaderSettings.AntiAliasLevel = 1;
FileFullPath = fileFullPath;
progress.Reset(OperationProgress.StatusDecodeThumbnails, ThumbnailsCount);
Debug.Write("Header -> ");
Debug.WriteLine(HeaderSettings);
@@ -1256,8 +1245,6 @@ namespace UVtools.Core.FileFormats
}
});
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+9 -22
View File
@@ -125,11 +125,12 @@ namespace UVtools.Core.FileFormats
for (int i = 0; i < imageLength; i++)
{
color = color <= 127 ? 0 : 255; // Sanitize no AA
if (spanMat[i] != color)
//color = color <= 127 ? 0 : 255; // Sanitize no AA
byte thisColor = spanMat[i] <= 127 ? 0 : 255; // Sanitize no AA
if (thisColor != color)
{
AddRep();
color = spanMat[i];
color = thisColor; // Sanitize no AA
rep = 1;
}
else
@@ -420,12 +421,10 @@ namespace UVtools.Core.FileFormats
return bytes;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
throw new NotSupportedException("PhotonS is read-only format, please use pws instead!");
//uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
{
@@ -463,8 +462,6 @@ namespace UVtools.Core.FileFormats
}
}
AfterEncode();
Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-");
@@ -495,10 +492,8 @@ namespace UVtools.Core.FileFormats
return mat;
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
HeaderSettings = Helpers.Deserialize<Header>(inputFile);
@@ -546,24 +541,16 @@ namespace UVtools.Core.FileFormats
{
if (progress.Token.IsCancellationRequested) return;
using (var image = layerData[layerIndex].Decode())
{
using var image = layerData[layerIndex].Decode();
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
lock (progress.Mutex)
{
progress++;
}
}
});
LayerManager.RebuildLayersProperties();
FileFullPath = fileFullPath;
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+2 -11
View File
@@ -1048,11 +1048,8 @@ namespace UVtools.Core.FileFormats
LayersDefinition = null;
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
LayersHash.Clear();
LayersDefinition = new LayerDefinition(LayerCount);
@@ -1124,14 +1121,10 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, FileMarkSettings);
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{
FileMarkSettings = Helpers.Deserialize<FileMark>(inputFile);
@@ -1235,8 +1228,6 @@ namespace UVtools.Core.FileFormats
}
});
}
progress.Token.ThrowIfCancellationRequested();
}
public override void SaveAs(string filePath = null, OperationProgress progress = null)
+26 -27
View File
@@ -252,22 +252,30 @@ namespace UVtools.Core.FileFormats
public class OutputConfig
{
public string Action { get; set; }
public string Action { get; set; } = "print";
public string JobDir { get; set; }
public float ExpTime { get; set; }
public float ExpTimeFirst { get; set; }
public string FileCreationTimestamp { get; set; }
//public string FileCreationTimestamp { get; set; }
public string FileCreationTimestamp {
get
{
//2021-01-23 at 04:07:36 UTC
var now = DateTime.Now;
return $"{now.Year}-{now.Month:D2}-{now.Day:D2} at {now.Hour:D2}:{now.Minute:D2}:{now.Second:D2} {now.Kind}";
}
}
public float LayerHeight { get; set; }
public string MaterialName { get; set; }
public string MaterialName { get; set; } = About.Software;
public ushort NumFade { get; set; }
public ushort NumFast { get; set; }
public ushort NumSlow { get; set; }
public string PrintProfile { get; set; }
public string PrintProfile { get; set; } = About.Software;
public float PrintTime { get; set; }
public string PrinterModel { get; set; }
public string PrinterProfile { get; set; }
public string PrinterVariant { get; set; }
public string PrusaSlicerVersion { get; set; }
public string PrinterModel { get; set; } = "SL1";
public string PrinterProfile { get; set; } = About.Software;
public string PrinterVariant { get; set; } = "default";
public string PrusaSlicerVersion { get; set; } = "PrusaSlicer-2.3.0+win64-202101111315";
public float UsedMaterial { get; set; }
public override string ToString()
@@ -519,10 +527,12 @@ namespace UVtools.Core.FileFormats
Statistics.Clear();
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
base.Encode(fileFullPath, progress);
var filename = fileFullPath;
if (filename.EndsWith(TemporaryFileAppend)) filename = Path.GetFileNameWithoutExtension(filename); // tmp
filename = Path.GetFileNameWithoutExtension(filename); // sl1
OutputConfigSettings.JobDir = filename;
using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
{
var entry = outputFile.CreateEntry("config.ini");
@@ -562,39 +572,28 @@ namespace UVtools.Core.FileFormats
foreach (var thumbnail in Thumbnails)
{
if (ReferenceEquals(thumbnail, null)) continue;
using (var stream = outputFile.CreateEntry($"thumbnail/thumbnail{thumbnail.Width}x{thumbnail.Height}.png").Open())
{
using var stream = outputFile.CreateEntry($"thumbnail/thumbnail{thumbnail.Width}x{thumbnail.Height}.png").Open();
var vec = new VectorOfByte();
CvInvoke.Imencode(".png", thumbnail, vec);
stream.WriteBytes(vec.ToArray());
stream.Close();
}
}
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
progress.Token.ThrowIfCancellationRequested();
Layer layer = this[layerIndex];
var layerImagePath = $"{Path.GetFileNameWithoutExtension(fileFullPath)}{layerIndex:D5}.png";
var layerImagePath = $"{filename}{layerIndex:D5}.png";
//layer.Filename = layerImagePath;
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++;
}
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
FileFullPath = fileFullPath;
PrinterSettings = new Printer();
MaterialSettings = new Material();
PrintSettings = new Print();
@@ -602,7 +601,7 @@ namespace UVtools.Core.FileFormats
Statistics.ExecutionTime.Restart();
using (var inputFile = ZipFile.OpenRead(FileFullPath))
using (var inputFile = ZipFile.OpenRead(fileFullPath))
{
List<string> iniFiles = new();
foreach (ZipArchiveEntry entity in inputFile.Entries)
@@ -625,7 +624,7 @@ namespace UVtools.Core.FileFormats
foreach (var obj in Configs)
{
var attribute = obj.GetType().GetProperty(fieldName);
if (ReferenceEquals(attribute, null)) continue;
if (attribute is null || !attribute.CanWrite) continue;
//Debug.WriteLine(attribute.Name);
Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
+6 -19
View File
@@ -360,13 +360,8 @@ namespace UVtools.Core.FileFormats
JsonSettings.Layers = new List<LayerData>();
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
// Redo layer data
JsonSettings.Layers.Clear();
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
@@ -430,17 +425,11 @@ namespace UVtools.Core.FileFormats
progress++;
}
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
if(progress is null) progress = new OperationProgress();
progress.Reset(OperationProgress.StatusGatherLayers, LayerCount);
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
{
var entry = inputFile.GetEntry(FileConfigName);
if (ReferenceEquals(entry, null))
@@ -466,21 +455,19 @@ namespace UVtools.Core.FileFormats
}
entry = inputFile.GetEntry(FilePreviewHugeName);
if (!ReferenceEquals(entry, null))
{
using (Stream stream = entry.Open())
if (entry is not null)
{
using Stream stream = entry.Open();
Mat image = new Mat();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
Thumbnails[1] = image;
stream.Close();
}
}
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
entry = inputFile.GetEntry($"{FolderImageName}/{layerIndex:D8}.png");
if (ReferenceEquals(entry, null)) continue;
if (entry is null) continue;
this[layerIndex] = new Layer(layerIndex, entry.Open(), LayerManager)
{
+8 -19
View File
@@ -382,12 +382,8 @@ namespace UVtools.Core.FileFormats
LayersSettings.Clear();
}
public override void Encode(string fileFullPath, OperationProgress progress = null)
protected override void EncodeInternally(string fileFullPath, OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
base.Encode(fileFullPath, progress);
float usedMaterial = MaterialMilliliters / LayerCount;
ResinMetadataSettings.Layers.Clear();
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
@@ -471,18 +467,14 @@ namespace UVtools.Core.FileFormats
outputFile.PutFileContent("ResinGCodeData", GCode.ToString(), ZipArchiveMode.Create);
}
AfterEncode();
}
public override void Decode(string fileFullPath, OperationProgress progress = null)
protected override void DecodeInternally(string fileFullPath, OperationProgress progress)
{
base.Decode(fileFullPath, progress);
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
{
var entry = inputFile.GetEntry("ResinMetadata");
if (ReferenceEquals(entry, null))
if (entry is null)
{
Clear();
throw new FileLoadException("ResinMetadata not found", fileFullPath);
@@ -491,7 +483,7 @@ namespace UVtools.Core.FileFormats
ResinMetadataSettings = Helpers.JsonDeserializeObject<ResinMetadata>(entry.Open());
entry = inputFile.GetEntry("UserSettingsData");
if (ReferenceEquals(entry, null))
if (entry is null)
{
Clear();
throw new FileLoadException("UserSettingsData not found", fileFullPath);
@@ -500,7 +492,7 @@ namespace UVtools.Core.FileFormats
UserSettings = Helpers.JsonDeserializeObject<UserSettingsdata>(entry.Open());
entry = inputFile.GetEntry("ZCodeMetadata");
if (ReferenceEquals(entry, null))
if (entry is null)
{
Clear();
throw new FileLoadException("ZCodeMetadata not found", fileFullPath);
@@ -509,7 +501,7 @@ namespace UVtools.Core.FileFormats
ZCodeMetadataSettings = Helpers.JsonDeserializeObject<ZCodeMetadata>(entry.Open());
entry = inputFile.GetEntry("ResinGCodeData");
if (ReferenceEquals(entry, null))
if (entry is null)
{
Clear();
throw new FileLoadException("ResinGCodeData not found", fileFullPath);
@@ -615,14 +607,11 @@ M106 S0
entry = inputFile.GetEntry("Preview.png");
if (!ReferenceEquals(entry, null))
{
using (Stream stream = entry.Open())
{
using Stream stream = entry.Open();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
stream.Close();
}
}
}
LayerManager.GetBoundingRectangle(progress);
}
+49 -22
View File
@@ -7,17 +7,15 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO.Compression;
using System.Linq;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
using UVtools.Core.Operations;
using Stream = System.IO.Stream;
namespace UVtools.Core
@@ -27,9 +25,24 @@ namespace UVtools.Core
/// </summary>
public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
{
#region Members
private byte[] _compressedBytes;
private uint _nonZeroPixelCount;
private Rectangle _boundingRectangle = Rectangle.Empty;
private bool _isModified;
private uint _index;
private float _positionZ;
private float _exposureTime;
private float _lightOffDelay = FileFormat.DefaultLightOffDelay;
private float _liftHeight = FileFormat.DefaultLiftHeight;
private float _liftSpeed = FileFormat.DefaultLiftSpeed;
private float _retractSpeed = FileFormat.DefaultRetractSpeed;
private byte _lightPwm = FileFormat.DefaultLightPWM;
#endregion
#region Properties
public object Mutex = new object();
public object Mutex = new();
/// <summary>
/// Gets the parent layer manager
@@ -152,21 +165,35 @@ namespace UVtools.Core
public float PositionZ
{
get => _positionZ;
set => RaiseAndSetIfChanged(ref _positionZ, value);
set
{
if(!RaiseAndSetIfChanged(ref _positionZ, value)) return;
RaisePropertyChanged(nameof(LayerHeight));
}
}
private byte[] _compressedBytes;
private uint _nonZeroPixelCount;
private Rectangle _boundingRectangle = Rectangle.Empty;
private bool _isModified;
private uint _index;
private float _positionZ;
private float _exposureTime;
private float _lightOffDelay = FileFormat.DefaultLightOffDelay;
private float _liftHeight = FileFormat.DefaultLiftHeight;
private float _liftSpeed = FileFormat.DefaultLiftSpeed;
private float _retractSpeed = FileFormat.DefaultRetractSpeed;
private byte _lightPwm = FileFormat.DefaultLightPWM;
/// <summary>
/// Gets the layer height in millimeters of this layer
/// </summary>
public float LayerHeight
{
get
{
if (_index == 0) return _positionZ;
Layer previousLayer = this;
while ((previousLayer = previousLayer.PreviousLayer()) is not null) // This cycle returns the correct layer height if two or more layers have the same position z
{
var layerHeight = (float)Math.Round(_positionZ - previousLayer.PositionZ, 2);
//Debug.WriteLine($"Layer {_index}-{previousLayer.Index}: {_positionZ} - {previousLayer.PositionZ}: {layerHeight}");
if (layerHeight == 0f) continue;
if (layerHeight < 0f) break;
return layerHeight;
}
return ParentLayerManager.SlicerFile.LayerHeight;
}
}
/// <summary>
/// Gets or sets layer image compressed data
@@ -348,7 +375,7 @@ namespace UVtools.Core
public override string ToString()
{
return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(IsBottomLayer)}: {IsBottomLayer}, {nameof(IsNormalLayer)}: {IsNormalLayer}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(LightPWM)}: {LightPWM}, {nameof(IsModified)}: {IsModified}";
return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(IsBottomLayer)}: {IsBottomLayer}, {nameof(IsNormalLayer)}: {IsNormalLayer}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(LightPWM)}: {LightPWM}, {nameof(IsModified)}: {IsModified}";
}
#endregion
@@ -388,18 +415,18 @@ namespace UVtools.Core
public Layer PreviousLayer()
{
if (ReferenceEquals(ParentLayerManager, null) || Index == 0)
if (ParentLayerManager is null || _index == 0)
return null;
return ParentLayerManager[Index - 1];
return ParentLayerManager[_index - 1];
}
public Layer NextLayer()
{
if (ReferenceEquals(ParentLayerManager, null) || Index >= ParentLayerManager.Count - 1)
if (ParentLayerManager is null || _index >= ParentLayerManager.Count - 1)
return null;
return ParentLayerManager[Index + 1];
return ParentLayerManager[_index + 1];
}
public bool SetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier, decimal value)
+16 -1
View File
@@ -49,8 +49,14 @@ namespace UVtools.Core
}
}
/// <summary>
/// Gets the bounding rectangle of the object
/// </summary>
private Rectangle _boundingRectangle = Rectangle.Empty;
/// <summary>
/// Gets the bounding rectangle of the object
/// </summary>
public Rectangle BoundingRectangle
{
get => GetBoundingRectangle();
@@ -79,7 +85,7 @@ namespace UVtools.Core
}
}
public float LayerHeight => Layers[0].PositionZ;
//public float LayerHeight => Layers[0].PositionZ;
#endregion
@@ -1293,6 +1299,15 @@ namespace UVtools.Core
}
#endregion
#region Formater
public override string ToString()
{
return $"{nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(Count)}: {Count}, {nameof(IsModified)}: {IsModified}";
}
#endregion
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ namespace UVtools.Core.Objects
public string TagString
{
get => Tag.ToString();
get => Tag?.ToString();
set => Tag = value;
}
+147 -27
View File
@@ -8,7 +8,6 @@
using System;
using System.Drawing;
using System.Reflection.Metadata.Ecma335;
using System.Xml.Serialization;
using Emgu.CV;
using UVtools.Core.FileFormats;
@@ -19,13 +18,31 @@ namespace UVtools.Core.Operations
[Serializable]
public abstract class Operation : BindableBase, IDisposable
{
#region Members
private Rectangle _roi = Rectangle.Empty;
private uint _layerIndexEnd;
private uint _layerIndexStart;
private string _profileName;
private bool _profileIsDefault;
private Enumerations.LayerRangeSelection _layerRangeSelection = Enumerations.LayerRangeSelection.All;
private FileFormat _slicerFile;
public const byte ClassNameLength = 9;
#endregion
#region Properties
[XmlIgnore]
public FileFormat SlicerFile
{
get => _slicerFile;
set
{
if(!RaiseAndSetIfChanged(ref _slicerFile, value)) return;
InitWithSlicerFile();
}
}
[XmlIgnore]
public object Tag { get; set; }
/// <summary>
/// Gets the ID name of this operation, this comes from class name with "Operation" removed
@@ -43,6 +60,19 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _layerRangeSelection, value);
}
public virtual string LayerRangeString
{
get
{
if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
{
return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
}
return $" [Layers: {LayerRangeSelection}]";
}
}
/// <summary>
/// Gets if this operation should set layer range to the actual layer index on layer preview
/// </summary>
@@ -95,18 +125,6 @@ namespace UVtools.Core.Operations
public bool HaveAction => !string.IsNullOrEmpty(ProgressAction);
/// <summary>
/// Validates the operation
/// </summary>
/// <returns>null or empty if validates, or else, return a string with error message</returns>
public virtual StringTag Validate(params object[] parameters) => null;
public bool CanValidate(params object[] parameters)
{
var result = Validate(parameters);
return result is null || string.IsNullOrEmpty(result.Content);
}
/// <summary>
/// Gets the start layer index where operation will starts in
/// </summary>
@@ -153,6 +171,105 @@ namespace UVtools.Core.Operations
}
public bool HaveROI => !ROI.IsEmpty;
#endregion
#region Constructor
protected Operation() { }
protected Operation(FileFormat slicerFile)
{
_slicerFile = slicerFile;
SelectAllLayers();
InitWithSlicerFile();
}
#endregion
#region Methods
/// <summary>
/// Validates the operation
/// </summary>
/// <returns>null or empty if validates, or else, return a string with error message</returns>
public virtual StringTag Validate(params object[] parameters) => null;
public bool CanValidate(params object[] parameters)
{
var result = Validate(parameters);
return result is null || string.IsNullOrEmpty(result.Content);
}
public void SelectAllLayers()
{
LayerIndexStart = 0;
LayerIndexEnd = SlicerFile.LastLayerIndex;
LayerRangeSelection = Enumerations.LayerRangeSelection.All;
}
public void SelectCurrentLayer(uint layerIndex)
{
LayerIndexStart = LayerIndexEnd = layerIndex;
LayerRangeSelection = Enumerations.LayerRangeSelection.Current;
}
public void SelectBottomLayers()
{
LayerIndexStart = 0;
LayerIndexEnd = SlicerFile.BottomLayerCount - 1u;
LayerRangeSelection = Enumerations.LayerRangeSelection.Bottom;
}
public void SelectNormalLayers()
{
LayerIndexStart = SlicerFile.BottomLayerCount;
LayerIndexEnd = SlicerFile.LastLayerIndex;
LayerRangeSelection = Enumerations.LayerRangeSelection.Normal;
}
public void SelectFirstLayer()
{
LayerIndexStart = LayerIndexEnd = 0;
LayerRangeSelection = Enumerations.LayerRangeSelection.First;
}
public void SelectLastLayer()
{
LayerIndexStart = LayerIndexEnd = SlicerFile.LastLayerIndex;
LayerRangeSelection = Enumerations.LayerRangeSelection.Last;
}
public void SelectLayers(Enumerations.LayerRangeSelection range)
{
switch (range)
{
case Enumerations.LayerRangeSelection.None:
break;
case Enumerations.LayerRangeSelection.All:
SelectAllLayers();
break;
case Enumerations.LayerRangeSelection.Current:
//SelectCurrentLayer();
break;
case Enumerations.LayerRangeSelection.Bottom:
SelectBottomLayers();
break;
case Enumerations.LayerRangeSelection.Normal:
SelectNormalLayers();
break;
case Enumerations.LayerRangeSelection.First:
SelectFirstLayer();
break;
case Enumerations.LayerRangeSelection.Last:
SelectLastLayer();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// Called to init the object when <see cref="SlicerFile"/> changes
/// </summary>
public virtual void InitWithSlicerFile() { }
public Mat GetRoiOrDefault(Mat defaultMat)
{
@@ -161,7 +278,9 @@ namespace UVtools.Core.Operations
public virtual Operation Clone()
{
return MemberwiseClone() as Operation;
var operation = MemberwiseClone() as Operation;
operation.SlicerFile = _slicerFile;
return operation;
}
public override string ToString()
@@ -172,29 +291,30 @@ namespace UVtools.Core.Operations
return result;
}
public virtual string LayerRangeString
{
get
{
if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
{
return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
}
return $" [Layers: {LayerRangeSelection}]";
}
}
public virtual bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected virtual bool ExecuteInternally(OperationProgress progress)
{
throw new NotImplementedException();
}
public bool Execute(OperationProgress progress = null)
{
if (_slicerFile is null) throw new InvalidOperationException($"{Title} can't execute due the lacking of file parent.");
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
var result = ExecuteInternally(progress);
progress.Token.ThrowIfCancellationRequested();
return result;
}
public virtual bool Execute(Mat mat, params object[] arguments)
{
throw new NotImplementedException();
}
public virtual void Dispose() { }
#endregion
}
}
+17 -9
View File
@@ -113,6 +113,14 @@ namespace UVtools.Core.Operations
public bool IsValid => SetLayers.Count > 0 & Operations.Count > 0;
#endregion
#region Constructor
public OperationArithmetic() { }
public OperationArithmetic(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public bool Parse()
@@ -205,17 +213,16 @@ namespace UVtools.Core.Operations
return true;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
if (!IsValid) return false;
progress ??= new OperationProgress();
progress.Reset(ProgressAction, (uint)Operations.Count);
using Mat result = slicerFile[Operations[0].LayerIndex].LayerMat;
using Mat result = SlicerFile[Operations[0].LayerIndex].LayerMat;
Mat resultRoi = GetRoiOrDefault(result);
for (int i = 1; i < Operations.Count; i++)
{
using var image = slicerFile[Operations[i].LayerIndex].LayerMat;
progress.Token.ThrowIfCancellationRequested();
using var image = SlicerFile[Operations[i].LayerIndex].LayerMat;
Mat imageRoi = GetRoiOrDefault(image);
switch (Operations[i - 1].Operator)
{
@@ -245,18 +252,19 @@ namespace UVtools.Core.Operations
Parallel.ForEach(SetLayers, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
if (Operations.Count == 1 && HaveROI)
{
var mat = slicerFile[layerIndex].LayerMat;
var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = GetRoiOrDefault(mat);
resultRoi.CopyTo(matRoi);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
return;
}
slicerFile[layerIndex].LayerMat = result;
SlicerFile[layerIndex].LayerMat = result;
});
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
+12 -7
View File
@@ -124,28 +124,33 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationBlur() { }
public OperationBlur(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat)
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
}
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+19 -1
View File
@@ -8,6 +8,7 @@
using System;
using System.Drawing;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
@@ -15,6 +16,7 @@ namespace UVtools.Core.Operations
[Serializable]
public class OperationCalculator : Operation
{
#region Overrides
public override string Title => "Calculator";
public override string Description => null;
@@ -28,15 +30,31 @@ namespace UVtools.Core.Operations
public override bool CanROI => false;
public override bool CanHaveProfiles => false;
#endregion
#region Properties
public MillimetersToPixels CalcMillimetersToPixels { get; set; }
public LightOffDelayC CalcLightOffDelay { get; set; }
public OptimalModelTilt CalcOptimalModelTilt { get; set; }
#endregion
public OperationCalculator()
#region Constructor
public OperationCalculator() { }
public OperationCalculator(FileFormat slicerFile) : base(slicerFile)
{
CalcMillimetersToPixels = new MillimetersToPixels(slicerFile.Resolution, slicerFile.Display);
CalcLightOffDelay = new LightOffDelayC(
(decimal) SlicerFile.LiftHeight, (decimal) slicerFile.BottomLiftHeight,
(decimal) SlicerFile.LiftSpeed, (decimal) slicerFile.BottomLiftSpeed,
(decimal) SlicerFile.RetractSpeed, (decimal) slicerFile.RetractSpeed);
CalcOptimalModelTilt = new OptimalModelTilt(slicerFile.Resolution, slicerFile.Display,
(decimal) slicerFile.LayerHeight);
}
#endregion
public abstract class Calculation : BindableBase
{
public abstract string Description { get; }
@@ -26,7 +26,6 @@ namespace UVtools.Core.Operations
public sealed class OperationCalibrateElephantFoot : Operation
{
#region Members
private Size _resolution = Size.Empty;
private decimal _layerHeight = 0.05M;
private bool _syncLayers;
private ushort _bottomLayers = 10;
@@ -112,14 +111,6 @@ namespace UVtools.Core.Operations
#region Properties
[XmlIgnore]
public Size Resolution
{
get => _resolution;
set => RaiseAndSetIfChanged(ref _resolution, value);
}
public decimal LayerHeight
{
get => _layerHeight;
@@ -347,6 +338,21 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationCalibrateElephantFoot() { }
public OperationCalibrateElephantFoot(FileFormat slicerFile) : base(slicerFile)
{
_layerHeight = (decimal)slicerFile.LayerHeight;
//_bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
}
#endregion
#region Equality
private bool Equals(OperationCalibrateElephantFoot other)
@@ -400,7 +406,7 @@ namespace UVtools.Core.Operations
var anchor = new Point(-1, -1);
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
layers[0] = EmguExtensions.InitMat(Resolution);
layers[0] = EmguExtensions.InitMat(SlicerFile.Resolution);
LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected;
int length = (int) (250 * _partScale);
int triangleLength = (int) (50 * _partScale);
@@ -633,32 +639,25 @@ namespace UVtools.Core.Operations
return thumbnail;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, 3);
slicerFile.SuppressRebuildProperties = true;
progress.ItemCount = 3;
var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers();
progress++;
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager)
var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
{
IsModified = true
};
var layer = new Layer(0, layers[1], slicerFile.LayerManager)
var layer = new Layer(0, layers[1], SlicerFile.LayerManager)
{
IsModified = true
};
var moveOp = new OperationMove(bottomLayer.BoundingRectangle, layers[0].Size);
var moveOp = new OperationMove(SlicerFile, bottomLayer.BoundingRectangle);
moveOp.Execute(layers[0]);
moveOp.Execute(layers[1]);
@@ -671,7 +670,7 @@ namespace UVtools.Core.Operations
layerIndex < LayerCount;
layerIndex++)
{
newLayers[layerIndex] = slicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone());
newLayers[layerIndex] = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone());
}
foreach (var mat in layers)
@@ -680,16 +679,22 @@ namespace UVtools.Core.Operations
}
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
progress++;
slicerFile.LayerManager.Layers = newLayers;
slicerFile.SuppressRebuildProperties = false;
slicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerHeight = (float)LayerHeight;
SlicerFile.BottomExposureTime = (float)BottomExposure;
SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
return true;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
return !progress.Token.IsCancellationRequested;
}
#endregion
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,8 @@
*/
using UVtools.Core.FileFormats;
namespace UVtools.Core.Operations
{
public class OperationCalibrateExternalTests : Operation
@@ -32,6 +34,14 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationCalibrateExternalTests() { }
public OperationCalibrateExternalTests(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
#endregion
@@ -10,7 +10,6 @@ using System;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
@@ -25,7 +24,6 @@ namespace UVtools.Core.Operations
public sealed class OperationCalibrateGrayscale : Operation
{
#region Members
private Size _resolution = Size.Empty;
private decimal _layerHeight = 0.05M;
private ushort _bottomLayers = 10;
private ushort _interfaceLayers = 5;
@@ -100,15 +98,21 @@ namespace UVtools.Core.Operations
#endregion
#region Properties
#region Constructor
[XmlIgnore]
public Size Resolution
public OperationCalibrateGrayscale() { }
public OperationCalibrateGrayscale(FileFormat slicerFile) : base(slicerFile)
{
get => _resolution;
set => RaiseAndSetIfChanged(ref _resolution, value);
_layerHeight = (decimal)slicerFile.LayerHeight;
_bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
}
#endregion
#region Properties
public decimal LayerHeight
{
@@ -340,10 +344,10 @@ namespace UVtools.Core.Operations
{
Mat[] layers = new Mat[3];
layers[0] = EmguExtensions.InitMat(Resolution);
layers[0] = EmguExtensions.InitMat(SlicerFile.Resolution);
int radius = Math.Max(100, Math.Min(Resolution.Width, Resolution.Height) - _outerMargin * 2) / 2 ;
Point center = new Point(Resolution.Width / 2, Resolution.Height / 2);
int radius = Math.Max(100, Math.Min(SlicerFile.Resolution.Width, SlicerFile.Resolution.Height) - _outerMargin * 2) / 2 ;
Point center = new Point(SlicerFile.Resolution.Width / 2, SlicerFile.Resolution.Height / 2);
int innerRadius = Math.Max(100, radius - _innerMargin);
double topLineLength = 0;
@@ -452,32 +456,22 @@ namespace UVtools.Core.Operations
return thumbnail;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
progress.ItemCount = LayerCount;
var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers();
progress++;
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager)
var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
{
IsModified = true
};
var interfaceLayer = InterfaceLayers > 0 && layers[1] is not null ? new Layer(0, layers[1], slicerFile.LayerManager)
var interfaceLayer = InterfaceLayers > 0 && layers[1] is not null ? new Layer(0, layers[1], SlicerFile.LayerManager)
{
IsModified = true
} : null;
var layer = new Layer(0, layers[2], slicerFile.LayerManager)
var layer = new Layer(0, layers[2], SlicerFile.LayerManager)
{
IsModified = true
};
@@ -511,17 +505,20 @@ namespace UVtools.Core.Operations
}
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
progress++;
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerHeight = (float)LayerHeight;
SlicerFile.BottomExposureTime = (float)BottomExposure;
SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
slicerFile.LayerManager.Layers = newLayers;
slicerFile.SuppressRebuildProperties = false;
slicerFile.LayerManager.RebuildLayersProperties();
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -10,7 +10,6 @@ using System;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
@@ -98,10 +97,31 @@ namespace UVtools.Core.Operations
#endregion
#region Properties
#region Constructor
[XmlIgnore]
public Size Resolution { get; set; } = Size.Empty;
public OperationCalibrateStressTower() { }
public OperationCalibrateStressTower(FileFormat slicerFile) : base(slicerFile)
{
_layerHeight = (decimal)slicerFile.LayerHeight;
_bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
}
public override void InitWithSlicerFile()
{
base.InitWithSlicerFile();
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
if (SlicerFile.DisplayHeight > 0)
DisplayHeight = (decimal)SlicerFile.DisplayHeight;
}
#endregion
#region Properties
public decimal DisplayWidth
{
@@ -294,8 +314,8 @@ namespace UVtools.Core.Operations
{
var layers = new Mat[LayerCount];
Slicer slicer = new(Resolution, new SizeF((float) DisplayWidth, (float) DisplayHeight));
Point center = new Point(Resolution.Width / 2, Resolution.Height / 2);
Slicer slicer = new(SlicerFile.Resolution, new SizeF((float) DisplayWidth, (float) DisplayHeight));
Point center = new Point(SlicerFile.Resolution.Width / 2, SlicerFile.Resolution.Height / 2);
uint baseRadius = slicer.PixelsFromMillimeters(_baseDiameter) / 2;
uint baseLayers = (ushort) Math.Floor(_baseHeight / _layerHeight);
uint bodyLayers = (ushort) Math.Floor(_bodyHeight / _layerHeight);
@@ -315,7 +335,7 @@ namespace UVtools.Core.Operations
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);*/
Parallel.For(0, LayerCount, layerIndex =>
{
layers[layerIndex] = EmguExtensions.InitMat(Resolution);
layers[layerIndex] = EmguExtensions.InitMat(SlicerFile.Resolution);
});
Parallel.For(0, baseLayers, layerIndex =>
@@ -389,24 +409,16 @@ namespace UVtools.Core.Operations
return thumbnail;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
progress.ItemCount = LayerCount;
var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers();
Parallel.For(0, LayerCount, layerIndex =>
{
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], slicerFile.LayerManager);
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile.LayerManager);
layers[layerIndex].Dispose();
lock (progress)
{
@@ -414,22 +426,21 @@ namespace UVtools.Core.Operations
}
});
slicerFile.LayerManager.Layers = newLayers;
slicerFile.LayerManager.RebuildLayersProperties();
/*var moveOp = new OperationMove(slicerFile.LayerManager.BoundingRectangle, slicerFile.Resolution)
{
IsCutMove = true,
LayerIndexEnd = slicerFile.LayerCount - 1
};
moveOp.Execute(slicerFile, progress);*/
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerHeight = (float)LayerHeight;
SlicerFile.BottomExposureTime = (float)BottomExposure;
SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
slicerFile.SuppressRebuildProperties = false;
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -128,9 +128,6 @@ namespace UVtools.Core.Operations
#region Properties
[XmlIgnore]
public Size Resolution { get; set; } = Size.Empty;
public decimal DisplayWidth
{
get => _displayWidth;
@@ -151,8 +148,8 @@ namespace UVtools.Core.Operations
}
}
public decimal Xppmm => DisplayWidth > 0 ? Math.Round(Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(Resolution.Height / DisplayHeight, 2) : 0;
public decimal Xppmm => DisplayWidth > 0 ? Math.Round(SlicerFile.Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(SlicerFile.Resolution.Height / DisplayHeight, 2) : 0;
public decimal LayerHeight
{
@@ -425,6 +422,30 @@ namespace UVtools.Core.Operations
*/
#endregion
#region Constructor
public OperationCalibrateTolerance() { }
public OperationCalibrateTolerance(FileFormat slicerFile) : base(slicerFile)
{
_layerHeight = (decimal)slicerFile.LayerHeight;
_bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
}
public override void InitWithSlicerFile()
{
base.InitWithSlicerFile();
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
if (SlicerFile.DisplayHeight > 0)
DisplayHeight = (decimal)SlicerFile.DisplayHeight;
}
#endregion
#region Enums
public enum Shapes : byte
@@ -483,7 +504,7 @@ namespace UVtools.Core.Operations
public Mat[] GetLayers()
{
var layers = new Mat[LayerCount];
var layer = EmguExtensions.InitMat(Resolution);
var layer = EmguExtensions.InitMat(SlicerFile.Resolution);
ushort startX = Math.Max((ushort)2, _leftRightMargin);
ushort startY = Math.Max((ushort)2, _topBottomMargin);
@@ -534,13 +555,13 @@ namespace UVtools.Core.Operations
if (_fuseParts)
{
if (xPixels >= FemaleHoleDiameterXPixels || yPixels >= FemaleHoleDiameterYPixels) return false;
if (currentX + FemaleDiameterXPixels + _leftRightMargin >= Resolution.Width)
if (currentX + FemaleDiameterXPixels + _leftRightMargin >= SlicerFile.Resolution.Width)
{
currentX = startX;
currentY += (int)FemaleDiameterYPixels + PartMargin;
}
if (currentY + FemaleDiameterYPixels + _topBottomMargin >= Resolution.Height)
if (currentY + FemaleDiameterYPixels + _topBottomMargin >= SlicerFile.Resolution.Height)
{
return false; // Insufficient size
}
@@ -571,13 +592,13 @@ namespace UVtools.Core.Operations
}
else
{
if (currentX + xPixels + _leftRightMargin >= Resolution.Width)
if (currentX + xPixels + _leftRightMargin >= SlicerFile.Resolution.Width)
{
currentX = startX;
currentY += yPixels + PartMargin;
}
if (currentY + yPixels + _topBottomMargin >= Resolution.Height)
if (currentY + yPixels + _topBottomMargin >= SlicerFile.Resolution.Height)
{
return false; // Insufficient size
}
@@ -704,24 +725,17 @@ namespace UVtools.Core.Operations
return thumbnail;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
progress.ItemCount = LayerCount;
var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers();
Parallel.For(0, LayerCount, layerIndex =>
{
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], slicerFile.LayerManager);
newLayers[layerIndex] = new Layer((uint)layerIndex, layers[layerIndex], SlicerFile.LayerManager);
layers[layerIndex].Dispose();
lock (progress)
{
@@ -729,22 +743,23 @@ namespace UVtools.Core.Operations
}
});
slicerFile.LayerManager.Layers = newLayers;
slicerFile.LayerManager.RebuildLayersProperties();
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
var moveOp = new OperationMove(slicerFile.LayerManager.BoundingRectangle, slicerFile.Resolution)
{
IsCutMove = true,
LayerIndexEnd = slicerFile.LayerCount - 1
};
moveOp.Execute(slicerFile, progress);
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerHeight = (float)LayerHeight;
SlicerFile.BottomExposureTime = (float)BottomExposure;
SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
var moveOp = new OperationMove(SlicerFile);
moveOp.Execute(progress);
slicerFile.SuppressRebuildProperties = false;
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -118,9 +118,6 @@ namespace UVtools.Core.Operations
#region Properties
[XmlIgnore]
public Size Resolution { get; set; } = Size.Empty;
public decimal DisplayWidth
{
get => _displayWidth;
@@ -141,8 +138,8 @@ namespace UVtools.Core.Operations
}
}
public decimal Xppmm => DisplayWidth > 0 ? Math.Round(Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(Resolution.Height / DisplayHeight, 2) : 0;
public decimal Xppmm => DisplayWidth > 0 ? Math.Round(SlicerFile.Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(SlicerFile.Resolution.Height / DisplayHeight, 2) : 0;
public decimal LayerHeight
{
@@ -447,6 +444,30 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationCalibrateXYZAccuracy() { }
public OperationCalibrateXYZAccuracy(FileFormat slicerFile) : base(slicerFile)
{
_layerHeight = (decimal)slicerFile.LayerHeight;
_bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
}
public override void InitWithSlicerFile()
{
base.InitWithSlicerFile();
if (SlicerFile.DisplayWidth > 0)
DisplayWidth = (decimal)SlicerFile.DisplayWidth;
if (SlicerFile.DisplayHeight > 0)
DisplayHeight = (decimal)SlicerFile.DisplayHeight;
}
#endregion
#region Enums
#endregion
@@ -586,7 +607,7 @@ namespace UVtools.Core.Operations
var layers = new Mat[2];
for (byte i = 0; i < layers.Length; i++)
{
layers[i] = EmguExtensions.InitMat(Resolution);
layers[i] = EmguExtensions.InitMat(SlicerFile.Resolution);
}
@@ -610,11 +631,11 @@ namespace UVtools.Core.Operations
positionYStr = "T";
break;
case 1:
currentY = (int)(Resolution.Height / 2 - YPixels / 2);
currentY = (int)(SlicerFile.Resolution.Height / 2 - YPixels / 2);
positionYStr = "M";
break;
case 2:
currentY = (int)(Resolution.Height - YPixels - _topBottomMargin);
currentY = (int)(SlicerFile.Resolution.Height - YPixels - _topBottomMargin);
positionYStr = "B";
break;
}
@@ -627,11 +648,11 @@ namespace UVtools.Core.Operations
positionStr = $"{positionYStr}L";
break;
case 1:
currentX = (int)(Resolution.Width / 2 - XPixels / 2);
currentX = (int)(SlicerFile.Resolution.Width / 2 - XPixels / 2);
positionStr = $"{positionYStr}C";
break;
case 2:
currentX = (int)(Resolution.Width - XPixels - _leftRightMargin);
currentX = (int)(SlicerFile.Resolution.Width - XPixels - _leftRightMargin);
positionStr = $"{positionYStr}R";
break;
}
@@ -716,34 +737,27 @@ namespace UVtools.Core.Operations
return thumbnail;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerCount);
progress.ItemCount = LayerCount;
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers();
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager)
var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
{
IsModified = true
};
var layer = new Layer(0, layers[1], slicerFile.LayerManager)
var layer = new Layer(0, layers[1], SlicerFile.LayerManager)
{
IsModified = true
};
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{
newLayers[layerIndex] = slicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone());
newLayers[layerIndex] = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone());
progress++;
}
@@ -752,13 +766,19 @@ namespace UVtools.Core.Operations
mat.Dispose();
}
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
slicerFile.LayerManager.Layers = newLayers;
slicerFile.LayerManager.RebuildLayersProperties();
slicerFile.SuppressRebuildProperties = false;
return true;
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerHeight = (float)LayerHeight;
SlicerFile.BottomExposureTime = (float)BottomExposure;
SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -64,25 +64,25 @@ namespace UVtools.Core.Operations
public override string ConfirmationText =>
"change print resolution " +
$"from {OldResolution.Width}x{OldResolution.Height} " +
$"from {SlicerFile.ResolutionX}x{SlicerFile.ResolutionY} " +
$"to {NewResolutionX}x{NewResolutionY}?";
public override string ProgressTitle =>
$"Changing print resolution from ({OldResolution.Width}x{OldResolution.Height}) to ({NewResolutionX}x{NewResolutionY})";
$"Changing print resolution from ({SlicerFile.ResolutionX}x{SlicerFile.ResolutionY}) to ({NewResolutionX}x{NewResolutionY})";
public override string ProgressAction => "Changed layers";
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
if (OldResolution.Width == NewResolutionX && OldResolution.Height == NewResolutionY)
if (SlicerFile.ResolutionX == NewResolutionX && SlicerFile.ResolutionY == NewResolutionY)
{
sb.AppendLine($"The new resolution must be different from current resolution ({OldResolution.Width} x {OldResolution.Height}).");
sb.AppendLine($"The new resolution must be different from current resolution ({SlicerFile.ResolutionX} x {SlicerFile.ResolutionY}).");
}
if (NewResolutionX < VolumeBonds.Width || NewResolutionY < VolumeBonds.Height)
if (NewResolutionX < SlicerFile.BoundingRectangle.Width || NewResolutionY < SlicerFile.BoundingRectangle.Height)
{
sb.AppendLine($"The new resolution ({NewResolutionX} x {NewResolutionY}) is not large enough to hold the model volume ({VolumeBonds.Width} x {VolumeBonds.Height}), continuing operation would clip the model");
sb.AppendLine($"The new resolution ({NewResolutionX} x {NewResolutionY}) is not large enough to hold the model volume ({SlicerFile.BoundingRectangle.Width} x {SlicerFile.BoundingRectangle.Height}), continuing operation would clip the model");
sb.AppendLine("To fix this, try to rotate the object and/or resize to fit on this new resolution.");
}
@@ -99,8 +99,6 @@ namespace UVtools.Core.Operations
#endregion
#region Properties
public Size OldResolution { get; }
public uint NewResolutionX
{
get => _newResolutionX;
@@ -113,25 +111,20 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _newResolutionY, value);
}
public Rectangle VolumeBonds { get; }
public Size VolumeBondsSize => VolumeBonds.Size;
public Size VolumeBondsSize => SlicerFile.BoundingRectangle.Size;
#endregion
#region Constructor
public OperationChangeResolution()
public OperationChangeResolution() { }
public OperationChangeResolution(FileFormat slicerFile) : base(slicerFile)
{
NewResolutionX = SlicerFile.ResolutionX;
NewResolutionY = SlicerFile.ResolutionY;
}
public OperationChangeResolution(Size oldResolution, Rectangle volumeBonds)
{
OldResolution = oldResolution;
VolumeBonds = volumeBonds;
NewResolutionX = (uint) oldResolution.Width;
NewResolutionY = (uint) oldResolution.Height;
}
#endregion
#region Methods
@@ -159,25 +152,24 @@ namespace UVtools.Core.Operations
public static Resolution[] Presets => GetResolutions();
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, slicerFile.LayerCount);
progress.ItemCount = SlicerFile.LayerCount;
Parallel.For(0, slicerFile.LayerCount, layerIndex =>
Parallel.For(0, SlicerFile.LayerCount, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var matRoi = new Mat(mat, VolumeBonds);
using var mat = SlicerFile[layerIndex].LayerMat;
using var matRoi = new Mat(mat, SlicerFile.BoundingRectangle);
using var matDst = new Mat(new Size((int)NewResolutionX, (int)NewResolutionY), mat.Depth, mat.NumberOfChannels);
using var matDstRoi = new Mat(matDst,
new Rectangle((int)(NewResolutionX / 2 - VolumeBonds.Width / 2),
(int)NewResolutionY / 2 - VolumeBonds.Height / 2,
VolumeBonds.Width, VolumeBonds.Height));
new Rectangle((int)(NewResolutionX / 2 - SlicerFile.BoundingRectangle.Width / 2),
(int)NewResolutionY / 2 - SlicerFile.BoundingRectangle.Height / 2,
SlicerFile.BoundingRectangle.Width, SlicerFile.BoundingRectangle.Height));
matRoi.CopyTo(matDstRoi);
//Execute(mat);
slicerFile[layerIndex].LayerMat = matDst;
SlicerFile[layerIndex].LayerMat = matDst;
lock (progress.Mutex)
{
@@ -187,10 +179,10 @@ namespace UVtools.Core.Operations
progress.Token.ThrowIfCancellationRequested();
slicerFile.ResolutionX = NewResolutionX;
slicerFile.ResolutionY = NewResolutionY;
SlicerFile.ResolutionX = NewResolutionX;
SlicerFile.ResolutionY = NewResolutionY;
return true;
return !progress.Token.IsCancellationRequested;
}
/*public override bool Execute(Mat mat, params object[] arguments)
@@ -0,0 +1,760 @@
/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
[Serializable]
public sealed class OperationDynamicLayerHeight : Operation
{
#region Sub Classes
public sealed class Report
{
public uint OldLayerCount { get; set; }
public uint NewLayerCount { get; set; }
public uint StackedLayers { get; set; }
public uint ReusedLayers => OldLayerCount - StackedLayers;
public float MaximumLayerHeight { get; set; }
public float OldPrintTime { get; set; }
public float NewPrintTime { get; set; }
public double SparedPrintTime => Math.Round(OldPrintTime - NewPrintTime, 2);
public double CompressionRatio => Math.Round((double)OldLayerCount / NewLayerCount * 100.0, 2);
public override string ToString()
{
var oldTime = TimeSpan.FromSeconds(OldPrintTime);
var newTime = TimeSpan.FromSeconds(NewPrintTime);
var sparedTime = TimeSpan.FromSeconds(SparedPrintTime);
return
$"From {OldLayerCount} layers, {ReusedLayers} got reused, {StackedLayers} got stacked and optimized with dynamic layer height's\n" +
$"Resultant layers: {NewLayerCount}\n" +
$"Compression ratio: {CompressionRatio}%\n" +
$"Maximum layer height reached: {MaximumLayerHeight}mm\n" +
$"Print time: {oldTime.Hours}h{oldTime.Minutes}m{oldTime.Seconds}s -> {newTime.Hours}h{newTime.Minutes}m{newTime.Seconds}s (- {sparedTime.Hours}h{sparedTime.Minutes}m{sparedTime.Seconds}s)";
}
}
[Serializable]
public sealed class ExposureItem : BindableBase
{
private decimal _layerHeight;
private decimal _bottomExposure;
private decimal _exposure;
/// <summary>
/// Gets or sets the layer height in millimeters
/// </summary>
public decimal LayerHeight
{
get => _layerHeight;
set => RaiseAndSetIfChanged(ref _layerHeight, Math.Round(value, 2));
}
/// <summary>
/// Gets or sets the bottom exposure in seconds
/// </summary>
public decimal BottomExposure
{
get => _bottomExposure;
set => RaiseAndSetIfChanged(ref _bottomExposure, Math.Round(value, 2));
}
/// <summary>
/// Gets or sets the bottom exposure in seconds
/// </summary>
public decimal Exposure
{
get => _exposure;
set => RaiseAndSetIfChanged(ref _exposure, Math.Round(value, 2));
}
public ExposureItem() { }
public ExposureItem(decimal layerHeight, decimal bottomExposure = 0, decimal exposure = 0)
{
_layerHeight = Math.Round(layerHeight, 2);
_bottomExposure = Math.Round(bottomExposure, 2);
_exposure = Math.Round(exposure, 2);
}
public override string ToString()
{
return $"{nameof(LayerHeight)}: {LayerHeight}mm, {nameof(BottomExposure)}: {BottomExposure}s, {nameof(Exposure)}: {Exposure}s";
}
}
#endregion
#region Constants
public const byte ObjectsPerCache = 2;
#endregion
#region Members
//private decimal _displayWidth;
//private decimal _displayHeight;
private decimal _minimumLayerHeight = 0.03m;
private decimal _maximumLayerHeight = 0.10m;
private decimal _cacheRamSize = 1.5m;
private ExposureSetTypes _exposureSetType = ExposureSetTypes.Linear;
private decimal _bottomExposureStep = 0.5m;
private decimal _exposureStep = 0.2m;
private ObservableCollection<ExposureItem> _automaticExposureTable = new();
private ObservableCollection<ExposureItem> _manualExposureTable = new();
#endregion
#region Overrides
public override bool CanROI => false;
public override string Title => "Dynamic layer height";
public override string Description =>
"Analyze and optimize the model with dynamic layer heights, larger angles will slice at lower layer height" +
" while more straight angles will slice larger layer height.\n" +
"Note: The model should be sliced at the lowest layer height possible (0.01mm).\n" +
"After this, do not apply any modification which reconstruct the z positions of the layers. " +
"Only few printers support this, make sure your is supported or else it will print a malformed model.";
public override string ConfirmationText =>
$"dynamic layers from layers {LayerIndexStart} through {LayerIndexEnd}?";
public override string ProgressTitle =>
$"Analyzing and optimizing layers height from layers {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressAction => "Processed layers";
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
/*if (XYResolutionUm <= 0)
{
sb.AppendLine($"Display width and height must be a positive value.");
}*/
decimal layerHeight = (decimal) SlicerFile.LayerHeight;
if (_minimumLayerHeight < layerHeight)
{
sb.AppendLine(
$"Minimum layer height ({_minimumLayerHeight}mm) must be equal or higher than file layer height ({layerHeight}mm)");
}
if (_minimumLayerHeight > _maximumLayerHeight)
{
sb.AppendLine(
$"Minimum layer height ({_minimumLayerHeight}mm) can't be higher than maximum layer height ({_maximumLayerHeight}mm)");
}
if (layerHeight >= _maximumLayerHeight)
{
sb.AppendLine(
$"Maximum layer height ({_maximumLayerHeight}mm) can't be the same or less than current file layer height ({SlicerFile.LayerHeight}mm)");
}
var exposureTable = ExposureTableDictionary;
for (layerHeight = (decimal) SlicerFile.LayerHeight;
layerHeight <= _maximumLayerHeight;
layerHeight = layerHeight + (decimal) SlicerFile.LayerHeight)
{
layerHeight = Math.Round(layerHeight, 2);
if (exposureTable.TryGetValue(layerHeight, out var exposure))
{
if (exposure.BottomExposure <= 0 || exposure.Exposure <= 0)
{
sb.AppendLine($"Layer height {layerHeight}mm exposures must be a positive value, current: {exposure.BottomExposure}s/{exposure.Exposure}s");
}
}
else
{
sb.AppendLine($"Layer height {layerHeight}mm exposures are missing.");
}
}
return new StringTag(sb.ToString());
}
public override string ToString()
{
var result = $"[Layer Height: Min: {_minimumLayerHeight}mm Max: {_maximumLayerHeight}mm] [RAM: {_cacheRamSize}Gb] [Exposure type: {_exposureSetType}, Steps: {_bottomExposureStep}s/{_exposureStep}s]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
#endregion
#region Enums
public enum ExposureSetTypes: byte
{
Linear,
Multiplier,
Manual
}
public static Array ExposureSetTypeItems => Enum.GetValues(typeof(ExposureSetTypes));
#endregion
#region Properties
/*public decimal DisplayWidth
{
get => _displayWidth;
set
{
if (!RaiseAndSetIfChanged(ref _displayWidth, Math.Round(value, 2))) return;
//RaisePropertyChanged(nameof(XYResolutionUm));
}
}
public decimal DisplayHeight
{
get => _displayHeight;
set
{
if (!RaiseAndSetIfChanged(ref _displayHeight, Math.Round(value, 2))) return;
//RaisePropertyChanged(nameof(XYResolutionUm));
}
}
public decimal XYResolutionUm => DisplayWidth > 0 || DisplayHeight > 0 ?
Math.Round(Math.Max(
DisplayWidth / SlicerFile.ResolutionX,
DisplayHeight / SlicerFile.ResolutionY
), 3) * 1000
: 0;
*/
public decimal MinimumLayerHeight
{
get => _minimumLayerHeight;
set
{
if (!RaiseAndSetIfChanged(ref _minimumLayerHeight, Math.Round(value, 2))) return;
//RaisePropertyChanged(nameof(ExposureData));
//if (!IsExposureSetTypeManual) RebuildAutoExposureTable();
}
}
public decimal MaximumLayerHeight
{
get => _maximumLayerHeight;
set
{
if(!RaiseAndSetIfChanged(ref _maximumLayerHeight, Math.Round(value, 2))) return;
//RaisePropertyChanged(nameof(ExposureData));
if(!IsExposureSetTypeManual) RebuildAutoExposureTable();
}
}
public uint CacheObjectCount => (uint) (_cacheRamSize * 1000000000L / SlicerFile.Resolution.GetArea() / ObjectsPerCache);
public decimal CacheRAMSize
{
get => _cacheRamSize;
set
{
if(!RaiseAndSetIfChanged(ref _cacheRamSize, Math.Round(value, 2))) return;
RaisePropertyChanged(nameof(CacheObjectCount));
}
}
public ExposureSetTypes ExposureSetType
{
get => _exposureSetType;
set
{
if(!RaiseAndSetIfChanged(ref _exposureSetType, value)) return;
RaisePropertyChanged(nameof(IsExposureSetTypeManual));
RaisePropertyChanged(nameof(ExposureTable));
RaisePropertyChanged(nameof(ExposureTableDictionary));
//RaisePropertyChanged(nameof(ExposureData));
if (!IsExposureSetTypeManual) RebuildAutoExposureTable();
}
}
public bool IsExposureSetTypeManual => _exposureSetType == ExposureSetTypes.Manual;
public decimal BottomExposureStep
{
get => _bottomExposureStep;
set
{
if(!RaiseAndSetIfChanged(ref _bottomExposureStep, value)) return;
//RaisePropertyChanged(nameof(ExposureData));
if (!IsExposureSetTypeManual) RebuildAutoExposureTable();
}
}
public decimal ExposureStep
{
get => _exposureStep;
set
{
if(!RaiseAndSetIfChanged(ref _exposureStep, value)) return;
//RaisePropertyChanged(nameof(ExposureData));
if (!IsExposureSetTypeManual) RebuildAutoExposureTable();
}
}
[XmlIgnore]
public ObservableCollection<ExposureItem> AutomaticExposureTable
{
get
{
if(_automaticExposureTable.Count == 0) RebuildAutoExposureTable();
return _automaticExposureTable;
}
set => RaiseAndSetIfChanged(ref _automaticExposureTable, value);
}
public ObservableCollection<ExposureItem> ManualExposureTable
{
get => _manualExposureTable;
set => RaiseAndSetIfChanged(ref _manualExposureTable, value);
}
[XmlIgnore]
public ObservableCollection<ExposureItem> ExposureTable => IsExposureSetTypeManual ? _manualExposureTable : AutomaticExposureTable;
/// <summary>
/// Gets the exposure table into a dictionary where key is the layer height
/// </summary>
[XmlIgnore]
public Dictionary<decimal, ExposureItem> ExposureTableDictionary
{
get
{
Dictionary<decimal, ExposureItem> dictionary = new();
foreach (var exposure in ExposureTable)
{
dictionary.TryAdd(exposure.LayerHeight, exposure);
}
return dictionary;
}
}
public string ExposureData
{
get
{
StringBuilder sb = new();
byte count = 0;
for (decimal layerHeight = (decimal) SlicerFile.LayerHeight; layerHeight <= _maximumLayerHeight; layerHeight+= (decimal)SlicerFile.LayerHeight)
{
decimal bottomExposure = 0;
decimal exposure = 0;
switch (_exposureSetType)
{
case ExposureSetTypes.Linear:
bottomExposure = (decimal)SlicerFile.BottomExposureTime + count * _bottomExposureStep;
exposure = (decimal)SlicerFile.ExposureTime + count * _exposureStep;
break;
case ExposureSetTypes.Multiplier:
bottomExposure = (decimal)SlicerFile.BottomExposureTime + (decimal)SlicerFile.BottomExposureTime * count * layerHeight * _bottomExposureStep;
exposure = (decimal)SlicerFile.BottomExposureTime + (decimal)SlicerFile.ExposureTime * count * layerHeight * _exposureStep;
break;
case ExposureSetTypes.Manual:
break;
default:
throw new ArgumentOutOfRangeException();
}
sb.AppendLine($"{layerHeight:F2}mm: {bottomExposure:F2}s / {exposure:F2}s");
count++;
}
return sb.ToString();
}
}
#endregion
#region Constructor
public OperationDynamicLayerHeight()
{
//InitManualTable();
}
public OperationDynamicLayerHeight(FileFormat slicerFile) : base(slicerFile)
{
InitManualTable();
}
public override void InitWithSlicerFile()
{
base.InitWithSlicerFile();
/*if (SlicerFile.DisplayWidth > 0)
_displayWidth = (decimal)SlicerFile.DisplayWidth;
if (SlicerFile.DisplayHeight > 0)
_displayHeight = (decimal)SlicerFile.DisplayHeight;*/
var layerHeight = (decimal)SlicerFile.LayerHeight;
if (_minimumLayerHeight < layerHeight)
{
_minimumLayerHeight = layerHeight;
}
if (layerHeight * 2 > _maximumLayerHeight)
{
_maximumLayerHeight = Math.Min((decimal) FileFormat.MaximumLayerHeight, _maximumLayerHeight*2);
}
}
public void InitManualTable()
{
for (decimal layerHeight = (decimal)FileFormat.MinimumLayerHeight;
layerHeight <= (decimal) FileFormat.MaximumLayerHeight;
layerHeight += (decimal)FileFormat.MinimumLayerHeight)
{
var item = new ExposureItem(layerHeight);
if (layerHeight == (decimal) SlicerFile.LayerHeight)
{
item.BottomExposure = (decimal) SlicerFile.BottomExposureTime;
item.Exposure = (decimal) SlicerFile.ExposureTime;
}
_manualExposureTable.Add(item);
}
}
#endregion
#region Equality
private bool Equals(OperationDynamicLayerHeight other)
{
return _minimumLayerHeight == other._minimumLayerHeight && _maximumLayerHeight == other._maximumLayerHeight && _cacheRamSize == other._cacheRamSize && _exposureSetType == other._exposureSetType && _bottomExposureStep == other._bottomExposureStep && _exposureStep == other._exposureStep && Equals(_manualExposureTable, other._manualExposureTable);
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is OperationDynamicLayerHeight other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(_minimumLayerHeight, _maximumLayerHeight, _cacheRamSize, (int) _exposureSetType, _bottomExposureStep, _exposureStep, _manualExposureTable);
}
#endregion
#region Methods
public void RebuildAutoExposureTable()
{
if (SlicerFile is null) return;
_automaticExposureTable.Clear();
byte count = 0;
for (decimal layerHeight = (decimal)SlicerFile.LayerHeight; layerHeight <= _maximumLayerHeight; layerHeight += (decimal)SlicerFile.LayerHeight)
{
decimal bottomExposure = 0;
decimal exposure = 0;
switch (_exposureSetType)
{
case ExposureSetTypes.Linear:
bottomExposure = (decimal)SlicerFile.BottomExposureTime + count * _bottomExposureStep;
exposure = (decimal)SlicerFile.ExposureTime + count * _exposureStep;
break;
case ExposureSetTypes.Multiplier:
bottomExposure = (decimal)SlicerFile.BottomExposureTime + (decimal)SlicerFile.BottomExposureTime * count * layerHeight * _bottomExposureStep;
exposure = (decimal)SlicerFile.BottomExposureTime + (decimal)SlicerFile.ExposureTime * count * layerHeight * _exposureStep;
break;
case ExposureSetTypes.Manual:
break;
default:
throw new ArgumentOutOfRangeException();
}
_automaticExposureTable.Add(new ExposureItem(layerHeight, Math.Round(bottomExposure, 2), Math.Round(exposure, 2)));
count++;
}
}
protected override bool ExecuteInternally(OperationProgress progress)
{
Report report = new()
{
OldLayerCount = SlicerFile.LayerCount,
OldPrintTime = SlicerFile.PrintTimeOrComputed
};
var anchor = new Point(-1, -1);
using var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);
var matCache = new Mat[SlicerFile.LayerCount];
var matThresholdCache = new Mat[SlicerFile.LayerCount];
List<Layer> layers = new();
using Mat matXor = new();
Mat matXorSum = null;
Mat matSum = null;
const byte _maximumErodes = 10;
//decimal xyResolutionUm = XYResolutionUm;
//const double xyRes = 35;
//var stepAngle = Math.Atan(SlicerFile.LayerHeight*1000 / xyRes) * (180 / Math.PI);
//byte maximumErodes = (byte) (_maximumLayerHeight * 100 - (decimal) (slicerFile.LayerHeight * 100f));
void CacheLayers(uint fromLayerIndex)
{
for (int layerIndex = (int) fromLayerIndex-2; layerIndex >= 0; layerIndex--) // clean up only the required layers
{
if (matCache[layerIndex] is null) break;
matCache[layerIndex].Dispose();
matCache[layerIndex] = null;
matThresholdCache[layerIndex].Dispose();
matThresholdCache[layerIndex] = null;
}
Parallel.For(fromLayerIndex, Math.Min(fromLayerIndex + CacheObjectCount, SlicerFile.LayerCount), layerIndex =>
{
if (matCache[layerIndex] is not null) return; // Already cached
matCache[layerIndex] = SlicerFile[layerIndex].LayerMat;
matThresholdCache[layerIndex] = new Mat();
// Clean AA
CvInvoke.Threshold(matCache[layerIndex], matThresholdCache[layerIndex], 128, 255, ThresholdType.Binary);
});
}
float GetLastPositionZ(float layerHeight) => layers.Count > 0 ? (float)Math.Round(layers[^1].PositionZ + layerHeight, 2) : layerHeight;
(Mat, Mat) GetLayer(uint layerIndex)
{
if (matCache[layerIndex] is null)
{
CacheLayers(layerIndex);
}
return (matCache[layerIndex], matThresholdCache[layerIndex]);
}
void AddNewLayer(Mat mat, float layerHeight)
{
report.MaximumLayerHeight = Math.Max(report.MaximumLayerHeight, layerHeight);
var positionZ = GetLastPositionZ(layerHeight);
var layer = new Layer((uint) layers.Count, mat, SlicerFile)
{
IsModified = true,
PositionZ = positionZ
};
layers.Add(layer);
}
void ReUseLayer(uint layerIndex)
{
SlicerFile[layerIndex].PositionZ = GetLastPositionZ(SlicerFile.LayerHeight);
SlicerFile[layerIndex].Index = (uint) layers.Count;
SlicerFile[layerIndex].IsModified = true;
layers.Add(SlicerFile[layerIndex]);
}
for (uint layerIndex = 0; layerIndex < LayerIndexStart; layerIndex++) // Skip layers and re-use layers
{
ReUseLayer(layerIndex);
}
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; )
{
Debug.WriteLine($"Head Layer: {layerIndex} ({SlicerFile.LayerHeight}mm)");
if (layerIndex == LayerIndexEnd)
{
ReUseLayer(layerIndex);
break;
}
var currentLayerHeight = SlicerFile.LayerHeight;
byte layerSum = 1;
byte erodeCount = 0;
//byte maxErodeCount = 0;
//double maxSlop = 90;
matSum?.Dispose();
matSum = null;
matXorSum?.Dispose();
matXorSum = null;
while (true)
{
progress.Token.ThrowIfCancellationRequested();
progress.ProcessedItems = layerIndex;
if (currentLayerHeight >= (float)_maximumLayerHeight || layerIndex == LayerIndexEnd)
{
// Cant perform any additional stack. Maximum layer height reached!
// Break this cycle and restart from same layer
matSum ??= GetLayer(layerIndex).Item1.Clone(); // This only happen when layer height is already the maximum supported layer height
layerIndex++;
break;
}
var previousLayerHeight = currentLayerHeight;
currentLayerHeight = (float)Math.Round(currentLayerHeight + SlicerFile.LayerHeight, 2);
var (mat1, mat1Threshold) = GetLayer(layerIndex);
var (mat2, mat2Threshold) = GetLayer(++layerIndex);
Debug.Write($" Stacking layer: {layerIndex} ({currentLayerHeight}mm)");
matSum ??= mat1.Clone();
CvInvoke.BitwiseXor(mat1Threshold, mat2Threshold, matXor);
if (matXorSum is null)
{
matXorSum = matXor.Clone();
}
else
{
CvInvoke.Add(matXorSum, matXor, matXorSum);
}
var currentLayerHeigthUm = currentLayerHeight * 1000.0;
if (CvInvoke.CountNonZero(matXorSum) > 0) // Layers are different
{
bool meetRequirement = false;
for (; erodeCount <= _maximumErodes; )
{
erodeCount++;
//maxErodeCount = Math.Max(maxErodeCount, erodeCount);
/*var slope = Math.Atan(currentLayerHeigthUm / (double) (xyResolutionUm * erodeCount)) * (180 / Math.PI);
var stepover = Math.Round(currentLayerHeigthUm / Math.Tan(slope * (Math.PI / 180)));
Debug.Write($" [Slope: {slope:F2} Stepover: {stepover} <= {xyResolutionUm} = {stepover <= (double) xyResolutionUm}]");
if (stepover > (double) xyResolutionUm)
{
meetRequirement = false;
break;
}*/
CvInvoke.Erode(matXorSum, matXor, kernel, anchor, 1, BorderType.Reflect101, default);
if (CvInvoke.CountNonZero(matXor) == 0) // Image pixels exhausted and got empty image, can pack and go next
{
meetRequirement = true;
break;
}
}
//if ((!meetRequirement || erodeCount >= _maximumErodes) && _minimumLayerHeight < (decimal) currentLayerHeight
// To many pixels, image still not blank, pack the previous group and start again from current height
if (!meetRequirement && _minimumLayerHeight < (decimal) currentLayerHeight)
{
currentLayerHeight = previousLayerHeight;
Debug.WriteLine(string.Empty);
break;
}
}
else
{
//erodeCount++; // Safe check
Debug.Write(" [Equal layer]");
}
layerSum++;
CvInvoke.Add(matSum, mat2, matSum);
Debug.WriteLine(string.Empty);
}
if (layerSum > 1) report.StackedLayers += layerSum;
Debug.WriteLine($" Packing {layerSum} layers with {currentLayerHeight}mm");
// Add the result
/*var thisPosZ = Math.Round(layers[^1].PositionZ + currentLayerHeight, 2);
if (layers.Count > 0 && thisPosZ != slicerFile[layerIndex].PositionZ)
{
Debug.WriteLine($"{layerIndex}: ({thisPosZ} != {slicerFile[layerIndex].PositionZ}) Height mismatch!!");
}*/
var positionZ = GetLastPositionZ(currentLayerHeight);
if ((decimal)positionZ != (decimal)SlicerFile[layerIndex-1].PositionZ)
{
Debug.WriteLine($"{layerIndex}: ({positionZ}mm != {SlicerFile[layerIndex-1].PositionZ}mm) Height mismatch!!");
throw new InvalidOperationException($"Model height integrity has been violated at layer {layerIndex}/{layers.Count} ({positionZ}mm != {SlicerFile[layerIndex - 1].PositionZ}mm), this operation will not proceed.");
}
AddNewLayer(matSum, currentLayerHeight);
}
for (int i = (int) LayerIndexEnd; i >= 0; i--)
{
if(matCache[i] is null) break;
matCache[i].Dispose();
matThresholdCache[i].Dispose();
}
for (uint layerIndex = LayerIndexEnd+1; layerIndex < SlicerFile.LayerCount; layerIndex++) // Add left-overs
{
ReUseLayer(layerIndex);
}
SlicerFile.SuppressRebuildProperties = true;
SlicerFile.LayerManager.Layers = layers.ToArray();
SlicerFile.LayerManager.RebuildLayersProperties(false);
// Set exposures times
var exposureDictionary = ExposureTableDictionary;
for (uint layerIndex = 0; layerIndex < SlicerFile.LayerCount; layerIndex++)
{
float bottomExposure = SlicerFile.BottomExposureTime;
float exposure = SlicerFile.ExposureTime;
if(exposureDictionary.TryGetValue((decimal)SlicerFile[layerIndex].LayerHeight, out var item))
{
bottomExposure = (float) item.BottomExposure;
exposure = (float) item.Exposure;
}
SlicerFile[layerIndex].ExposureTime = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomExposure, exposure);
}
//var layer = slicerFile.LayerManager.Layers[^1];
/*Debug.WriteLine(layer.ExposureTime);
Debug.WriteLine(layer.Index);
Debug.WriteLine(layer.Filename);
Debug.WriteLine(layer.IsNormalLayer);
Debug.WriteLine(layer.IsBottomLayer);
Debug.WriteLine(layer.LiftHeight);
Debug.WriteLine(layer.LiftSpeed);
Debug.WriteLine(layer.LightOffDelay);
Debug.WriteLine(layer.LightPWM);
Debug.WriteLine(layer.BoundingRectangle);*/
//Debug.WriteLine(layer.LayerHeight);
//Debug.WriteLine(layer);
/*Debug.WriteLine(slicerFile.LayerManager);
foreach (var layer in slicerFile)
{
Debug.WriteLine(layer.Index);
}*/
SlicerFile.SuppressRebuildProperties = false;
report.NewLayerCount = SlicerFile.LayerCount;
report.NewPrintTime = SlicerFile.PrintTimeOrComputed;
Tag = report;
return true;
}
#endregion
}
}
@@ -19,6 +19,9 @@ namespace UVtools.Core.Operations
{
#region Members
private bool _perLayerOverride;
private uint _setNumberOfLayer = 1;
private uint _skipNumberOfLayer = 0;
#endregion
#region Overrides
@@ -92,23 +95,73 @@ namespace UVtools.Core.Operations
get => _perLayerOverride;
set => RaiseAndSetIfChanged(ref _perLayerOverride, value);
}
/// <summary>
/// Gets or sets the number of sequential layers to set the parameters
/// </summary>
public uint SetNumberOfLayer
{
get => _setNumberOfLayer;
set => RaiseAndSetIfChanged(ref _setNumberOfLayer, value);
}
/// <summary>
/// Gets or sets the number of sequential layers to skip after set a layer
/// </summary>
public uint SkipNumberOfLayer
{
get => _skipNumberOfLayer;
set => RaiseAndSetIfChanged(ref _skipNumberOfLayer, value);
}
#endregion
public OperationEditParameters()
#region Constructor
public OperationEditParameters() { }
public OperationEditParameters(FileFormat slicerFile) : base(slicerFile) { }
public override void InitWithSlicerFile()
{
base.InitWithSlicerFile();
SlicerFile.RefreshPrintParametersModifiersValues();
Modifiers = SlicerFile.PrintParameterModifiers;
}
public OperationEditParameters(FileFormat.PrintParameterModifier[] modifiers)
{
Modifiers = modifiers;
}
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
slicerFile.EditPrintParameters(this);
return true;
if (PerLayerOverride)
{
uint setLayers = 0;
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
SlicerFile[layerIndex].SetValuesFromPrintParametersModifiers(Modifiers);
if (SkipNumberOfLayer <= 0) continue;
setLayers++;
if (setLayers >= SetNumberOfLayer)
{
setLayers = 0;
layerIndex += SkipNumberOfLayer;
}
}
foreach (var modifier in Modifiers)
{
modifier.OldValue = modifier.NewValue;
}
SlicerFile.RebuildGCode();
}
else
{
SlicerFile.SetValuesFromPrintParametersModifiers();
}
return !progress.Token.IsCancellationRequested;
}
#endregion
+13 -7
View File
@@ -87,6 +87,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationFlip() { }
public OperationFlip(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality
protected bool Equals(OperationFlip other)
@@ -113,24 +121,22 @@ namespace UVtools.Core.Operations
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+27 -7
View File
@@ -97,24 +97,44 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationInfill() { }
public OperationInfill(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality
private bool Equals(OperationInfill other)
{
return _infillType == other._infillType && _wallThickness == other._wallThickness && _infillThickness == other._infillThickness && _infillSpacing == other._infillSpacing && _infillBrightness == other._infillBrightness;
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is OperationInfill other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine((int) _infillType, _wallThickness, _infillThickness, _infillSpacing, _infillBrightness);
}
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
@@ -122,7 +142,7 @@ namespace UVtools.Core.Operations
}
});
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+12 -6
View File
@@ -76,11 +76,19 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationLayerClone() { }
public OperationLayerClone(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
var oldLayers = slicerFile.LayerManager.Layers;
var oldLayers = SlicerFile.LayerManager.Layers;
uint totalClones = (LayerIndexEnd - LayerIndexStart + 1) * Clones;
uint newLayerCount = (uint) (oldLayers.Length + totalClones);
@@ -107,11 +115,9 @@ namespace UVtools.Core.Operations
newLayerIndex++;
}
slicerFile.LayerManager.Layers = layers;
SlicerFile.LayerManager.Layers = layers;
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
+61 -65
View File
@@ -39,12 +39,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Members
private ImportTypes _importType = ImportTypes.Stack;
private uint _startLayerIndex;
private bool _extendBeyondLayerCount = true;
private bool _discardUnmodifiedLayers;
private ushort _stackMargin = 50;
private ObservableCollection<StringTag> _files = new();
#endregion
#region Overrides
@@ -115,9 +117,6 @@ namespace UVtools.Core.Operations
#region Properties
[XmlIgnore]
public Size FileResolution { get; }
public ImportTypes ImportType
{
get => _importType;
@@ -172,14 +171,11 @@ namespace UVtools.Core.Operations
#region Constructor
public OperationLayerImport()
{
}
public OperationLayerImport() { }
public OperationLayerImport(FileFormat slicerFile) : base(slicerFile) { }
public OperationLayerImport(Size fileResolution)
{
FileResolution = fileResolution;
}
#endregion
#region Methods
@@ -224,10 +220,10 @@ namespace UVtools.Core.Operations
return result;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
slicerFile.SuppressRebuildProperties = true;
progress.ItemCount = 0;
SlicerFile.SuppressRebuildProperties = true;
List<FileFormat> fileFormats = new();
List<KeyValuePair<uint, string>> keyImage = new();
@@ -289,7 +285,7 @@ namespace UVtools.Core.Operations
if (_importType == ImportTypes.Stack)
{
new OperationMove(slicerFile, Enumerations.Anchor.TopLeft){LayerIndexEnd = slicerFile.LastLayerIndex}.Execute(slicerFile, progress);
new OperationMove(SlicerFile, Enumerations.Anchor.TopLeft).Execute(progress);
}
foreach (var fileFormat in fileFormats)
@@ -299,7 +295,7 @@ namespace UVtools.Core.Operations
fileFormat.Decode(fileFormat.FileFullPath, progress);
}
var boundingRectangle = slicerFile.LayerManager.GetBoundingRectangle(progress);
var boundingRectangle = SlicerFile.LayerManager.GetBoundingRectangle(progress);
var fileFormatBoundingRectangle = fileFormat.LayerManager.GetBoundingRectangle(progress);
var roiRectangle = Rectangle.Empty;
@@ -307,26 +303,26 @@ namespace UVtools.Core.Operations
switch (_importType)
{
case ImportTypes.Insert:
if (slicerFile.Resolution != fileFormat.Resolution &&
(slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
slicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount);
if (SlicerFile.Resolution != fileFormat.Resolution &&
(SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
SlicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
SlicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount);
break;
case ImportTypes.Replace:
case ImportTypes.Stack:
if (slicerFile.Resolution != fileFormat.Resolution &&
(slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
if (SlicerFile.Resolution != fileFormat.Resolution &&
(SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
SlicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
if(fileFormatBoundingRectangle.Width >= slicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= slicerFile.ResolutionY)
if(fileFormatBoundingRectangle.Width >= SlicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= SlicerFile.ResolutionY)
continue;
int x = 0;
int y = 0;
if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width <
slicerFile.ResolutionX)
SlicerFile.ResolutionX)
{
x = boundingRectangle.Right + _stackMargin;
}
@@ -335,29 +331,29 @@ namespace UVtools.Core.Operations
y = boundingRectangle.Bottom + _stackMargin;
}
if (y >= slicerFile.ResolutionY)
if (y >= SlicerFile.ResolutionY)
continue;
roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height);
if (_extendBeyondLayerCount)
{
int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount);
int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - SlicerFile.LayerCount);
if (layerCountDifference > 0)
{
slicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack);
SlicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack);
}
}
break;
case ImportTypes.Merge:
if (slicerFile.Resolution != fileFormat.Resolution) continue;
if (SlicerFile.Resolution != fileFormat.Resolution) continue;
if (_extendBeyondLayerCount)
{
int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount);
int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - SlicerFile.LayerCount);
if (layerCountDifference > 0)
{
slicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true);
SlicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true);
}
}
break;
@@ -365,7 +361,7 @@ namespace UVtools.Core.Operations
case ImportTypes.BitwiseAnd:
case ImportTypes.BitwiseOr:
case ImportTypes.BitwiseXOr:
if (slicerFile.Resolution != fileFormat.Resolution) continue;
if (SlicerFile.Resolution != fileFormat.Resolution) continue;
break;
}
@@ -381,88 +377,88 @@ namespace UVtools.Core.Operations
{
case ImportTypes.Insert:
{
if (layerIndex >= slicerFile.LayerCount) return;
if (slicerFile.Resolution == fileFormat.Resolution)
if (layerIndex >= SlicerFile.LayerCount) return;
if (SlicerFile.Resolution == fileFormat.Resolution)
{
slicerFile[layerIndex] = fileFormat[i];
SlicerFile[layerIndex] = fileFormat[i];
break;
}
using var layer = fileFormat[i].LayerMat;
using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution);
slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile);
using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution);
SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile);
break;
}
case ImportTypes.Replace:
{
if (layerIndex >= slicerFile.LayerCount) return;
if (slicerFile.Resolution == fileFormat.Resolution)
if (layerIndex >= SlicerFile.LayerCount) return;
if (SlicerFile.Resolution == fileFormat.Resolution)
{
slicerFile[layerIndex] = fileFormat[i];
SlicerFile[layerIndex] = fileFormat[i];
break;
}
using var layer = fileFormat[i].LayerMat;
using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution);
slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile);
using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution);
SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile);
break;
}
case ImportTypes.Stack:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var mat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var mat = SlicerFile[layerIndex].LayerMat;
using var importMat = fileFormat[i].LayerMat;
var matRoi = new Mat(mat, roiRectangle);
var importMatRoi = new Mat(importMat, fileFormatBoundingRectangle);
importMatRoi.CopyTo(matRoi);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
break;
}
case ImportTypes.Merge:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat;
CvInvoke.Add(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat;
SlicerFile[layerIndex].LayerMat = newMat;
break;
}
case ImportTypes.Subtract:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat;
CvInvoke.Subtract(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat;
SlicerFile[layerIndex].LayerMat = newMat;
break;
}
case ImportTypes.BitwiseAnd:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseAnd(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat;
SlicerFile[layerIndex].LayerMat = newMat;
break;
}
case ImportTypes.BitwiseOr:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseOr(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat;
SlicerFile[layerIndex].LayerMat = newMat;
break;
}
case ImportTypes.BitwiseXOr:
{
if (layerIndex >= slicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat;
if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseXor(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat;
SlicerFile[layerIndex].LayerMat = newMat;
break;
}
default:
@@ -483,20 +479,20 @@ namespace UVtools.Core.Operations
if (_importType == ImportTypes.Stack)
{
new OperationMove(slicerFile) { LayerIndexEnd = slicerFile.LastLayerIndex }.Execute(slicerFile, progress);
new OperationMove(SlicerFile).Execute(progress);
}
if (lastProcessedLayerIndex <= -1) return false;
if (lastProcessedLayerIndex + 1 < slicerFile.LayerCount && _discardUnmodifiedLayers)
if (lastProcessedLayerIndex + 1 < SlicerFile.LayerCount && _discardUnmodifiedLayers)
{
slicerFile.LayerManager.ReallocateRange(0, (uint) lastProcessedLayerIndex);
SlicerFile.LayerManager.ReallocateRange(0, (uint) lastProcessedLayerIndex);
}
slicerFile.LayerManager.RebuildLayersProperties();
slicerFile.SuppressRebuildProperties = false;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -99,6 +99,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationLayerReHeight() { }
public OperationLayerReHeight(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Subclasses
public class OperationLayerReHeightItem
{
@@ -124,12 +132,11 @@ namespace UVtools.Core.Operations
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, Item.LayerCount);
progress.ItemCount = Item.LayerCount;
var oldLayers = slicerFile.LayerManager.Layers;
var oldLayers = SlicerFile.LayerManager.Layers;
var layers = new Layer[Item.LayerCount];
@@ -171,10 +178,10 @@ namespace UVtools.Core.Operations
}
}
slicerFile.LayerManager.Layers = layers;
slicerFile.LayerHeight = (float)Item.LayerHeight;
SlicerFile.LayerManager.Layers = layers;
SlicerFile.LayerHeight = (float)Item.LayerHeight;
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
}
@@ -45,20 +45,28 @@ namespace UVtools.Core.Operations
#region Properties
#endregion
#region Constructor
public OperationLayerRemove() { }
public OperationLayerRemove(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress(false);
progress.CanCancel = false;
var layersRemove = new List<uint>();
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
layersRemove.Add(layerIndex);
}
return RemoveLayers(slicerFile, layersRemove, progress);
return RemoveLayers(SlicerFile, layersRemove, progress);
}
public static bool RemoveLayers(FileFormat slicerFile, List<uint> layersRemove, OperationProgress progress = null)
@@ -70,7 +78,7 @@ namespace UVtools.Core.Operations
progress.Reset("removed layers", (uint)layersRemove.Count);
var oldLayers = slicerFile.LayerManager.Layers;
float layerHeight = slicerFile.LayerHeight;
var layerHeight = slicerFile.LayerHeight;
var layers = new Layer[oldLayers.Length - layersRemove.Count];
@@ -92,7 +100,7 @@ namespace UVtools.Core.Operations
}
else
{
posZ = (float)Math.Round(layers[newLayerIndex - 1].PositionZ + layerHeight, 2);
posZ = layers[newLayerIndex - 1].PositionZ + layerHeight;
}
}
+12 -8
View File
@@ -57,6 +57,14 @@ namespace UVtools.Core.Operations
public bool HaveMask => !(Mask is null);
#endregion
#region Constructor
public OperationMask() { }
public OperationMask(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public void InvertMask()
@@ -65,25 +73,21 @@ namespace UVtools.Core.Operations
CvInvoke.BitwiseNot(Mask, Mask);
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+13 -8
View File
@@ -109,6 +109,14 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationMorph() { }
public OperationMorph(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality
private bool Equals(OperationMorph other)
@@ -137,11 +145,8 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
var isFade = Chamfer;
LayerManager.MutateGetVarsIterationChamfer(
LayerIndexStart,
@@ -160,17 +165,17 @@ namespace UVtools.Core.Operations
if (progress.Token.IsCancellationRequested) return;
int iterations = LayerManager.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex);
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, iterations);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+37 -44
View File
@@ -170,6 +170,31 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationMove() { }
public OperationMove(FileFormat slicerFile, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) : base(slicerFile)
{
ROI = slicerFile.LayerManager.BoundingRectangle;
_imageWidth = slicerFile.ResolutionX;
_imageHeight = slicerFile.ResolutionY;
_anchor = anchor;
}
public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) : this(slicerFile, anchor)
{
if(!srcRoi.IsEmpty) ROI = srcRoi;
}
/*public OperationMove(FileFormat slicerFile, Rectangle srcRoi, Mat mat, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter) : this(slicerFile, srcRoi, anchor)
{
ImageWidth = (uint) mat.Width;
ImageHeight = (uint) mat.Height;
}*/
#endregion
#region Methods
public void CalculateDstRoi()
{
@@ -214,42 +239,15 @@ namespace UVtools.Core.Operations
_dstRoi.Y += MarginTop;
_dstRoi.Y -= MarginBottom;
IsWithinBoundary = !(DstRoi.IsEmpty || DstRoi.X < 0 || DstRoi.Y < 0 ||
DstRoi.Width == 0 || DstRoi.Right > ImageWidth ||
DstRoi.Height == 0 || DstRoi.Bottom > ImageHeight);
IsWithinBoundary = !(_dstRoi.IsEmpty || _dstRoi.X < 0 || _dstRoi.Y < 0 ||
_dstRoi.Width == 0 || _dstRoi.Right > ImageWidth ||
_dstRoi.Height == 0 || _dstRoi.Bottom > ImageHeight);
RaisePropertyChanged(nameof(DstRoi));
RaisePropertyChanged(nameof(LocationXStr));
RaisePropertyChanged(nameof(LocationYStr));
}
public OperationMove()
{
}
public OperationMove(FileFormat slicerFile, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
{
ROI = slicerFile.LayerManager.BoundingRectangle;
ImageWidth = slicerFile.ResolutionX;
ImageHeight = slicerFile.ResolutionY;
Anchor = anchor;
}
public OperationMove(Rectangle srcRoi, uint imageWidth, uint imageHeight, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
{
ROI = srcRoi;
ImageWidth = imageWidth;
ImageHeight = imageHeight;
Anchor = anchor;
}
public OperationMove(Rectangle srcRoi, Size resolution, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
{
ROI = srcRoi;
ImageWidth = (uint)resolution.Width;
ImageHeight = (uint)resolution.Height;
Anchor = anchor;
}
public void Reset()
{
@@ -271,21 +269,19 @@ namespace UVtools.Core.Operations
return IsWithinBoundary;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
if (ROI == Rectangle.Empty) ROI = slicerFile.LayerManager.GetBoundingRectangle(progress);
if (ROI.IsEmpty) ROI = SlicerFile.LayerManager.GetBoundingRectangle(progress);
CalculateDstRoi();
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat)
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
}
lock (progress.Mutex)
@@ -294,18 +290,15 @@ namespace UVtools.Core.Operations
}
});
slicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
SlicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
{
if (ImageWidth == 0) ImageWidth = (uint) mat.Width;
if (ImageHeight == 0) ImageHeight = (uint) mat.Height;
if (_imageWidth == 0) _imageWidth = (uint) mat.Width;
if (_imageHeight == 0) _imageHeight = (uint) mat.Height;
using var srcRoi = new Mat(mat, ROI);
using var dstRoi = new Mat(mat, DstRoi);
+17 -18
View File
@@ -186,19 +186,21 @@ namespace UVtools.Core.Operations
public Size GetPatternVolume => new(Cols * ROI.Width + (Cols - 1) * ColSpacing, Rows * ROI.Height + (Rows - 1) * RowSpacing);
#endregion
public OperationPattern()
{
}
#region Constructor
public OperationPattern(Rectangle srcRoi, Size resolution)
{
ImageWidth = (uint) resolution.Width;
ImageHeight = (uint) resolution.Height;
public OperationPattern() { }
SetRoi(srcRoi);
public OperationPattern(FileFormat slicerFile, Rectangle srcRoi = default) : base(slicerFile)
{
ImageWidth = slicerFile.ResolutionX;
ImageHeight = slicerFile.ResolutionY;
SetRoi(srcRoi.IsEmpty ? slicerFile.BoundingRectangle : srcRoi);
Fill();
}
#endregion
#region Methods
public void SetAnchor(byte value)
{
@@ -272,16 +274,13 @@ namespace UVtools.Core.Operations
return result;
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
using var layerRoi = new Mat(mat, ROI);
using var dstLayer = mat.CloneBlank();
for (ushort col = 0; col < Cols; col++)
@@ -292,7 +291,7 @@ namespace UVtools.Core.Operations
layerRoi.CopyTo(dstRoi);
}
//Execute(mat);
slicerFile[layerIndex].LayerMat = dstLayer;
SlicerFile[layerIndex].LayerMat = dstLayer;
lock (progress.Mutex)
{
@@ -300,19 +299,19 @@ namespace UVtools.Core.Operations
}
});
slicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
SlicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
progress.Token.ThrowIfCancellationRequested();
if (Anchor == Enumerations.Anchor.None) return true;
var operationMove = new OperationMove(slicerFile.LayerManager.BoundingRectangle, ImageWidth, ImageHeight, Anchor)
var operationMove = new OperationMove(SlicerFile, Anchor)
{
LayerIndexStart = LayerIndexStart,
LayerIndexEnd = LayerIndexEnd
};
operationMove.Execute(slicerFile, progress);
operationMove.Execute(progress);
return true;
return !progress.Token.IsCancellationRequested;
}
/*public override bool Execute(Mat mat, params object[] arguments)
@@ -138,6 +138,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationPixelDimming() { }
public OperationPixelDimming(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
public uint WallThicknessStart
@@ -534,11 +542,8 @@ namespace UVtools.Core.Operations
}
}
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
if (Pattern is null)
{
Pattern = new Matrix<byte>(2, 2)
@@ -560,7 +565,7 @@ namespace UVtools.Core.Operations
AlternatePattern ??= Pattern;
using var blankMat = EmguExtensions.InitMat(slicerFile.Resolution);
using var blankMat = EmguExtensions.InitMat(SlicerFile.Resolution);
using var matPattern = blankMat.CloneBlank();
using var matAlternatePattern = blankMat.CloneBlank();
var target = GetRoiOrDefault(blankMat);
@@ -573,9 +578,9 @@ namespace UVtools.Core.Operations
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, patternMask, alternatePatternMask);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
@@ -583,8 +588,7 @@ namespace UVtools.Core.Operations
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+14 -8
View File
@@ -58,7 +58,7 @@ namespace UVtools.Core.Operations
_canCancel = canCancel;
}
public Stopwatch StopWatch { get; } = new Stopwatch();
public Stopwatch StopWatch { get; } = new ();
/// <summary>
/// Gets or sets if operation can be cancelled
@@ -82,7 +82,8 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _title, value);
}
public string ElapsedTimeStr => $"{StopWatch.Elapsed.Minutes}m {StopWatch.Elapsed.Seconds}s {StopWatch.Elapsed.Milliseconds}ms";
public string ElapsedTimeStr => $"{StopWatch.Elapsed.Minutes}m {StopWatch.Elapsed.Seconds}s";
//{StopWatch.Elapsed.Milliseconds} ms
/// <summary>
/// Gets or sets the item name for the operation
@@ -123,21 +124,26 @@ namespace UVtools.Core.Operations
}
}
/// <summary>
/// Gets or sets an tag
/// </summary>
public object Tag { get; set; }
/// <summary>
/// Gets the remaining items to be processed
/// </summary>
public uint RemainingItems => ItemCount - ProcessedItems;
public uint RemainingItems => _itemCount - _processedItems;
public int ProgressStep => (int)ProgressPercent;
public string Description => ToString();
public bool IsIndeterminate => ItemCount == 0;
public bool IsIndeterminate => _itemCount == 0;
/// <summary>
/// Gets the progress from 0 to 100%
/// </summary>
public double ProgressPercent => ItemCount == 0 ? 0 : Math.Round(ProcessedItems * 100.0 / ItemCount, 2).Clamp(0, 100);
public double ProgressPercent => _itemCount == 0 ? 0 : Math.Round(_processedItems * 100.0 / _itemCount, 2).Clamp(0, 100);
public static OperationProgress operator +(OperationProgress progress, uint value)
{
@@ -167,9 +173,9 @@ namespace UVtools.Core.Operations
public override string ToString()
{
return ItemCount == 0 ?
$"{ProcessedItems}/? {ItemName}" :
$"{ProcessedItems}/{ItemCount} {ItemName} | {ProgressPercent:0.00}%";
return _itemCount == 0 ?
$"{_processedItems}/? {_itemName}" :
$"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_itemCount} {_itemName} | {ProgressPercent:0.00}%";
}
public void TriggerRefresh()
+19 -11
View File
@@ -63,6 +63,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationRaftRelief() { }
public OperationRaftRelief(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
public static Array RaftReliefItems => Enum.GetValues(typeof(RaftReliefTypes));
@@ -149,11 +157,10 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress.ItemCount = 0;
const uint minLength = 5;
progress ??= new OperationProgress();
//progress.Reset(operation.ProgressAction);
Mat supportsMat = null;
var anchor = new Point(-1, -1);
@@ -161,11 +168,11 @@ namespace UVtools.Core.Operations
uint firstSupportLayerIndex = 0;
for (; firstSupportLayerIndex < slicerFile.LayerCount; firstSupportLayerIndex++)
for (; firstSupportLayerIndex < SlicerFile.LayerCount; firstSupportLayerIndex++)
{
progress.Reset("Tracing raft", slicerFile.LayerCount, firstSupportLayerIndex);
progress.Reset("Tracing raft", SlicerFile.LayerCount, firstSupportLayerIndex);
if (progress.Token.IsCancellationRequested) return false;
supportsMat = GetRoiOrDefault(slicerFile[firstSupportLayerIndex].LayerMat);
supportsMat = GetRoiOrDefault(SlicerFile[firstSupportLayerIndex].LayerMat);
var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 20, 100, 30, 5, 200);
if (circles.Length >= minLength) break;
@@ -187,7 +194,7 @@ namespace UVtools.Core.Operations
switch (ReliefType)
{
case OperationRaftRelief.RaftReliefTypes.Relief:
case RaftReliefTypes.Relief:
patternMat = EmguExtensions.InitMat(supportsMat.Size);
int shapeSize = HoleDiameter + HoleSpacing;
using (var shape = EmguExtensions.InitMat(new Size(shapeSize, shapeSize)))
@@ -208,7 +215,7 @@ namespace UVtools.Core.Operations
}
break;
case OperationRaftRelief.RaftReliefTypes.Dimming:
case RaftReliefTypes.Dimming:
patternMat = EmguExtensions.InitMat(supportsMat.Size, color);
break;
}
@@ -216,7 +223,8 @@ namespace UVtools.Core.Operations
progress.Reset(ProgressAction, firstSupportLayerIndex);
Parallel.For(IgnoreFirstLayers, firstSupportLayerIndex, layerIndex =>
{
using (Mat dst = slicerFile[layerIndex].LayerMat)
if (progress.Token.IsCancellationRequested) return;
using (Mat dst = SlicerFile[layerIndex].LayerMat)
{
var target = GetRoiOrDefault(dst);
@@ -242,7 +250,7 @@ namespace UVtools.Core.Operations
}
slicerFile[layerIndex].LayerMat = dst;
SlicerFile[layerIndex].LayerMat = dst;
}
lock (progress.Mutex)
@@ -255,7 +263,7 @@ namespace UVtools.Core.Operations
supportsMat.Dispose();
patternMat?.Dispose();
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -81,6 +81,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationRedrawModel() { }
public OperationRedrawModel(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
[XmlIgnore]
@@ -151,21 +159,20 @@ namespace UVtools.Core.Operations
public FileFormat IsFileValid(bool returnNewInstance = false) =>
FileFormat.FindByExtension(_filePath, true, returnNewInstance);
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
var otherFile = IsFileValid(true);
otherFile.Decode(_filePath, progress);
progress.Reset(ProgressAction, otherFile.LayerCount);
int startLayerIndex = (int)(slicerFile.LayerCount - otherFile.LayerCount);
int startLayerIndex = (int)(SlicerFile.LayerCount - otherFile.LayerCount);
if (startLayerIndex < 0) return false;
Parallel.For(0, otherFile.LayerCount, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
var fullMatLayerIndex = startLayerIndex + layerIndex;
using var fullMat = slicerFile[fullMatLayerIndex].LayerMat;
using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat;
using var bodyMat = otherFile[layerIndex].LayerMat;
using var fullMatRoi = GetRoiOrDefault(fullMat);
using var bodyMatRoi = GetRoiOrDefault(bodyMat);
@@ -232,7 +239,7 @@ namespace UVtools.Core.Operations
if (modified)
{
slicerFile[fullMatLayerIndex].LayerMat = fullMat;
SlicerFile[fullMatLayerIndex].LayerMat = fullMat;
}
lock (progress.Mutex)
@@ -241,7 +248,7 @@ namespace UVtools.Core.Operations
}
});
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
@@ -16,7 +16,6 @@ using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
@@ -64,6 +63,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationRepairLayers() { }
public OperationRepairLayers(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
public bool RepairIslands
{
@@ -116,10 +123,8 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
// Remove islands
if (!ReferenceEquals(Issues, null)
&& !ReferenceEquals(IslandDetectionConfig, null)
@@ -127,7 +132,7 @@ namespace UVtools.Core.Operations
&& RemoveIslandsBelowEqualPixelCount > 0
&& RemoveIslandsRecursiveIterations != 1)
{
progress.Reset("Removed recursive islands", 0);
progress.Reset("Removed recursive islands");
ushort limit = RemoveIslandsRecursiveIterations == 0
? ushort.MaxValue
: RemoveIslandsRecursiveIterations;
@@ -152,7 +157,7 @@ namespace UVtools.Core.Operations
.Select(grp => grp.First())
.ToList();*/
islandConfig.WhiteListLayers = islandsToRecompute.ToList();
recursiveIssues = slicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapsConfig, touchingBoundsConfig, emptyLayersConfig);
recursiveIssues = SlicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapsConfig, touchingBoundsConfig, emptyLayersConfig);
//Debug.WriteLine(i);
}
@@ -167,7 +172,7 @@ namespace UVtools.Core.Operations
Parallel.ForEach(issuesGroup, group =>
{
if (progress.Token.IsCancellationRequested) return;
Layer layer = slicerFile[group.Key];
Layer layer = SlicerFile[group.Key];
Mat image = layer.LayerMat;
Span<byte> bytes = image.GetPixelSpan<byte>();
foreach (var issue in group)
@@ -184,7 +189,7 @@ namespace UVtools.Core.Operations
}
var nextLayerIndex = group.Key + 1;
if (nextLayerIndex < slicerFile.LayerCount)
if (nextLayerIndex < SlicerFile.LayerCount)
islandsToRecompute.Add(nextLayerIndex);
layer.LayerMat = image;
@@ -200,7 +205,7 @@ namespace UVtools.Core.Operations
Parallel.For(LayerIndexStart, LayerIndexEnd, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
Layer layer = slicerFile[layerIndex];
Layer layer = SlicerFile[layerIndex];
Mat image = null;
void initImage()
@@ -294,7 +299,7 @@ namespace UVtools.Core.Operations
List<uint> removeLayers = new List<uint>();
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
if (slicerFile[layerIndex].NonZeroPixelCount == 0)
if (SlicerFile[layerIndex].NonZeroPixelCount == 0)
{
removeLayers.Add(layerIndex);
}
@@ -302,13 +307,11 @@ namespace UVtools.Core.Operations
if (removeLayers.Count > 0)
{
OperationLayerRemove.RemoveLayers(slicerFile, removeLayers, progress);
OperationLayerRemove.RemoveLayers(SlicerFile, removeLayers, progress);
}
}
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
#endregion
+12 -10
View File
@@ -103,9 +103,13 @@ namespace UVtools.Core.Operations
}
#endregion
public OperationResize()
{
}
#region Constructor
public OperationResize() { }
public OperationResize(FileFormat slicerFile) : base(slicerFile) { }
#endregion
public override string ToString()
{
@@ -145,11 +149,9 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
if (X == 1m && Y == 1m) return false;
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
decimal xSteps = Math.Abs(X - 1) / (LayerIndexEnd - LayerIndexStart);
decimal ySteps = Math.Abs(Y - 1) / (LayerIndexEnd - LayerIndexStart);
@@ -195,12 +197,12 @@ namespace UVtools.Core.Operations
if (newX == 1.0m && newY == 1.0m) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, newX / 100m, newY / 100m);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+12 -7
View File
@@ -42,6 +42,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationRotate() { }
public OperationRotate(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
public decimal AngleDegrees
{
@@ -74,24 +82,21 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+18 -7
View File
@@ -20,13 +20,18 @@ namespace UVtools.Core.Operations
[Serializable]
public sealed class OperationSolidify : Operation
{
#region Enums
public enum AreaCheckTypes
{
More,
Less
}
#endregion
#region Members
private uint _minimumArea = 1;
private AreaCheckTypes _areaCheckType = AreaCheckTypes.More;
#endregion
#region Overrides
@@ -70,25 +75,31 @@ namespace UVtools.Core.Operations
#endregion
#region Constructor
public OperationSolidify() { }
public OperationSolidify(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat;
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex)
{
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+12 -7
View File
@@ -47,6 +47,14 @@ namespace UVtools.Core.Operations
}
#endregion
#region Constructor
public OperationThreshold() { }
public OperationThreshold(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties
public byte Threshold
{
@@ -71,17 +79,15 @@ namespace UVtools.Core.Operations
#region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
protected override bool ExecuteInternally(OperationProgress progress)
{
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat)
using (var mat = SlicerFile[layerIndex].LayerMat)
{
Execute(mat);
slicerFile[layerIndex].LayerMat = mat;
SlicerFile[layerIndex].LayerMat = mat;
}
lock (progress.Mutex)
@@ -89,9 +95,8 @@ namespace UVtools.Core.Operations
progress++;
}
});
progress.Token.ThrowIfCancellationRequested();
return true;
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
+2 -2
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
<Version>2.3.2</Version>
<Version>2.4.0</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
@@ -45,7 +45,7 @@
<ItemGroup>
<PackageReference Include="BinarySerializer" Version="8.5.3" />
<PackageReference Include="Emgu.CV" Version="4.4.0.4099" />
<PackageReference Include="Emgu.CV" Version="4.5.1.4349" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
+218 -43
View File
@@ -152,6 +152,9 @@
<Component Id="owc27A5D1506739847D9D7688256879A937" Guid="30f2e89f-1e95-77b9-1c3b-90bd4d875160">
<File Id="owf27A5D1506739847D9D7688256879A937" Source="$(var.SourceDir)\Avalonia.DesktopRuntime.dll" KeyPath="yes" />
</Component>
<Component Id="owcAA73F8E2C0EE78F802BAA8B361043211" Guid="536d2de0-51e7-19c8-3a8e-466146777c64">
<File Id="owfAA73F8E2C0EE78F802BAA8B361043211" Source="$(var.SourceDir)\Avalonia.Diagnostics.dll" KeyPath="yes" />
</Component>
<Component Id="owc6C15ADD7A5EE7A0CBEFD35B0027BBEB7" Guid="9c4a8ab3-598c-8e7c-0295-5c068334ab67">
<File Id="owf6C15ADD7A5EE7A0CBEFD35B0027BBEB7" Source="$(var.SourceDir)\Avalonia.Dialogs.dll" KeyPath="yes" />
</Component>
@@ -227,12 +230,18 @@
<Component Id="owc80EC8AEA1BFB8077812CDD06F9128A53" Guid="afbd2d79-629c-90a1-57a9-d68edc2d1437">
<File Id="owf80EC8AEA1BFB8077812CDD06F9128A53" Source="$(var.SourceDir)\clrjit.dll" KeyPath="yes" />
</Component>
<Component Id="owcD89DA7DE2D69AFC05DD5D46B6072C05C" Guid="ff72b568-c40c-3d50-c5af-049f64b476ea">
<File Id="owfD89DA7DE2D69AFC05DD5D46B6072C05C" Source="$(var.SourceDir)\concrt140.dll" KeyPath="yes" />
</Component>
<Component Id="owc6135A13B8E29883ED57BF3FE20578EED" Guid="cd1aae2e-a4de-1bd1-9680-014bccf80e32">
<File Id="owf6135A13B8E29883ED57BF3FE20578EED" Source="$(var.SourceDir)\coreclr.dll" KeyPath="yes" />
</Component>
<Component Id="owc5E8FBF42F9BCF40914849582C19906B8" Guid="f7a08052-6afc-fe5e-291c-07137533ab79">
<File Id="owf5E8FBF42F9BCF40914849582C19906B8" Source="$(var.SourceDir)\createdump.exe" KeyPath="yes" />
</Component>
<Component Id="owcF9E82F0BAE95DEABBEA8012A0994676C" Guid="edd1fddd-c05b-dc01-33b2-52e715b79615">
<File Id="owfF9E82F0BAE95DEABBEA8012A0994676C" Source="$(var.SourceDir)\cvextern.dll" KeyPath="yes" />
</Component>
<Component Id="owc3883419A2BFFE7013C2194A99728AB11" Guid="dd137337-4b74-c76b-c87e-6b5f42697dd4">
<File Id="owf3883419A2BFFE7013C2194A99728AB11" Source="$(var.SourceDir)\dbgshim.dll" KeyPath="yes" />
</Component>
@@ -263,6 +272,18 @@
<Component Id="owc6262D65DF7B3DF80C034B72467CAE882" Guid="4941cd5b-5666-87fe-5a6a-5ebdd5ee2524">
<File Id="owf6262D65DF7B3DF80C034B72467CAE882" Source="$(var.SourceDir)\MessageBox.Avalonia.dll" KeyPath="yes" />
</Component>
<Component Id="owcBED5500FCECB7551175681E93EC9B191" Guid="e84e4591-8227-e9c2-b052-dc4583553c9a">
<File Id="owfBED5500FCECB7551175681E93EC9B191" Source="$(var.SourceDir)\Microsoft.CodeAnalysis.CSharp.dll" KeyPath="yes" />
</Component>
<Component Id="owcD48DD5DDA2BA4C83F4A98D4BE87BA462" Guid="effc6a72-2186-a73f-ee7f-c05c95de6c6e">
<File Id="owfD48DD5DDA2BA4C83F4A98D4BE87BA462" Source="$(var.SourceDir)\Microsoft.CodeAnalysis.CSharp.Scripting.dll" KeyPath="yes" />
</Component>
<Component Id="owcDC0782CCA5E596145FD1FDFB67EDC2AF" Guid="8bfcc8b6-6693-60fe-2af9-d0e34ab6f421">
<File Id="owfDC0782CCA5E596145FD1FDFB67EDC2AF" Source="$(var.SourceDir)\Microsoft.CodeAnalysis.dll" KeyPath="yes" />
</Component>
<Component Id="owcB9CA98C685BDD7D3E9DD3EBD5C5A3B84" Guid="434ec6c6-a47b-5321-63d1-6d30a2f8a9bf">
<File Id="owfB9CA98C685BDD7D3E9DD3EBD5C5A3B84" Source="$(var.SourceDir)\Microsoft.CodeAnalysis.Scripting.dll" KeyPath="yes" />
</Component>
<Component Id="owc27AE8A53D94DD8A3E4AEAF6F7C27FB60" Guid="80e5ef0e-84a5-2bce-9923-0fd54d243e45">
<File Id="owf27AE8A53D94DD8A3E4AEAF6F7C27FB60" Source="$(var.SourceDir)\Microsoft.CSharp.dll" KeyPath="yes" />
</Component>
@@ -299,12 +320,30 @@
<Component Id="owcE382B0CF482F0E7C3AF33E6EEEBD26B0" Guid="7433845c-c763-9b7e-e2c9-7b06986570bf">
<File Id="owfE382B0CF482F0E7C3AF33E6EEEBD26B0" Source="$(var.SourceDir)\mscorrc.dll" KeyPath="yes" />
</Component>
<Component Id="owc4EDD870826B23A7EFC3FACD1E199E883" Guid="587324f3-ed59-f000-c241-8dc6a66501de">
<File Id="owf4EDD870826B23A7EFC3FACD1E199E883" Source="$(var.SourceDir)\msvcp140.dll" KeyPath="yes" />
</Component>
<Component Id="owc57B8051D45DF8A094B6F6F64CD58D9E6" Guid="b19c1e08-c2ee-ae27-0014-d5180ae56935">
<File Id="owf57B8051D45DF8A094B6F6F64CD58D9E6" Source="$(var.SourceDir)\msvcp140_1.dll" KeyPath="yes" />
</Component>
<Component Id="owcE2F8C74ADC2AF2357936D93D9E417BB4" Guid="01e22654-976b-0b52-7f65-17a93b4d19ab">
<File Id="owfE2F8C74ADC2AF2357936D93D9E417BB4" Source="$(var.SourceDir)\msvcp140_2.dll" KeyPath="yes" />
</Component>
<Component Id="owcD748ECCC1ECBC6ACAF796527AC8E18D3" Guid="53347251-3752-30e8-051d-71050378624d">
<File Id="owfD748ECCC1ECBC6ACAF796527AC8E18D3" Source="$(var.SourceDir)\msvcp140_atomic_wait.dll" KeyPath="yes" />
</Component>
<Component Id="owc3FDD5303B44770B8890DCDE0685AF1EB" Guid="50c83bf3-3054-7dd7-6eda-a39108edb2c2">
<File Id="owf3FDD5303B44770B8890DCDE0685AF1EB" Source="$(var.SourceDir)\msvcp140_codecvt_ids.dll" KeyPath="yes" />
</Component>
<Component Id="owc79156F385239CEA4DEA3C87C1DA3E1D8" Guid="68380c80-6708-5eb6-415d-10e278417679">
<File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" />
</Component>
<Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b">
<File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" />
</Component>
<Component Id="owc29161E83FC02784120326979FF285358" Guid="a8d30e75-1063-4d27-60b6-13d4bd4f52eb">
<File Id="owf29161E83FC02784120326979FF285358" Source="$(var.SourceDir)\opencv_videoio_ffmpeg451_64.dll" KeyPath="yes" />
</Component>
<Component Id="owcBFCA0BB8CBE4A68414FA088B4F7F3D22" Guid="babeb74f-9861-b222-a49a-ec268c3cd3ca">
<File Id="owfBFCA0BB8CBE4A68414FA088B4F7F3D22" Source="$(var.SourceDir)\ReactiveUI.dll" KeyPath="yes" />
</Component>
@@ -811,9 +850,9 @@
</Component>
<Component Id="owc21B8C8C0F69E3CD1398B9A0674DF07BD" Guid="1e472543-e636-904d-da5b-cddaac2d36b1">
<File Id="owf21B8C8C0F69E3CD1398B9A0674DF07BD" Source="$(var.SourceDir)\UVtools.exe" KeyPath="yes">
<Shortcut Id="sc218BF75801887335D1B30BAFB94BA631" Name="UVtools" Directory="scd220707349D4C8FA275285514283F3E2A" WorkingDirectory="MergeRedirectFolder" Description="MSLA/DLP, file analysis, calibration, repair, conversion and manipulation" />
<Shortcut Id="sc2F2092C02FDD8EB21E756F58C31B70A7" Name="UVtools" Directory="StartMenuFolder" WorkingDirectory="MergeRedirectFolder" Description="MSLA/DLP, file analysis, calibration, repair, conversion and manipulation" />
<Shortcut Id="sc6327849DA5C02D2396E91B8B1892E03C" Name="UVtools" Directory="DesktopFolder" Description="MSLA/DLP, file analysis, calibration, repair, conversion and manipulation" WorkingDirectory="MergeRedirectFolder" />
<Shortcut Id="sc218BF75801887335D1B30BAFB94BA631" Name="UVtools" Directory="scd220707349D4C8FA275285514283F3E2A" WorkingDirectory="MergeRedirectFolder" Description="MSLA/DLP, file analysis, calibration, repair, conversion and manipulation" />
<Shortcut Id="sc6327849DA5C02D2396E91B8B1892E03C" Name="UVtools" Directory="DesktopFolder" WorkingDirectory="MergeRedirectFolder" Description="MSLA/DLP, file analysis, calibration, repair, conversion and manipulation" />
</File>
</Component>
<Component Id="owc0C1077539E2B54F2460D2C0993613EFB" Guid="fc6ae2db-2865-9eb4-5753-4f2f941fdf16">
@@ -825,6 +864,15 @@
<Component Id="owc1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Guid="545300b7-5398-2ce2-788f-02287a83e8a7">
<File Id="owf1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Source="$(var.SourceDir)\UVtools_demo_file.sl1" KeyPath="yes" />
</Component>
<Component Id="owc507468650B23000B702AAAE48E658343" Guid="dba8edf4-02a3-c04a-50fc-896025548077">
<File Id="owf507468650B23000B702AAAE48E658343" Source="$(var.SourceDir)\vccorlib140.dll" KeyPath="yes" />
</Component>
<Component Id="owcEB2D9343E9BF3366381E9864468EFB9A" Guid="c4f85169-dfa6-1369-3b95-34e28199fa0f">
<File Id="owfEB2D9343E9BF3366381E9864468EFB9A" Source="$(var.SourceDir)\vcruntime140.dll" KeyPath="yes" />
</Component>
<Component Id="owc41A749EF7C055C135F6C13882684CE39" Guid="d0346e8a-b7e9-6a98-fefd-48957d30e340">
<File Id="owf41A749EF7C055C135F6C13882684CE39" Source="$(var.SourceDir)\vcruntime140_1.dll" KeyPath="yes" />
</Component>
<Component Id="owc9AF7D2C52438BF24F3FA3132D7C0E6A9" Guid="892f88e7-cf94-fad1-08d3-b26c1b5913d3">
<File Id="owf9AF7D2C52438BF24F3FA3132D7C0E6A9" Source="$(var.SourceDir)\WindowsBase.dll" KeyPath="yes" />
</Component>
@@ -1090,59 +1138,186 @@
</Component>
</Directory>
</Directory>
<Directory Id="owd37EA32A018DF9B31395A1FCE42233062" Name="x64">
<Component Id="owcCD1854F2CC6C7F17F61397E23B6C598A" Guid="0a98d274-6f18-ee97-f14c-410e8fd2060d">
<File Id="owfCD1854F2CC6C7F17F61397E23B6C598A" Source="$(var.SourceDir)\x64\concrt140.dll" KeyPath="yes" />
<Directory Id="owd799F60633DE3314CD962556CD118A45D" Name="cs">
<Component Id="owc99CE72FDB30C8FD0902CE01843ED4D88" Guid="c4c2d2ce-4eae-325d-f83e-f5d17907fa7d">
<File Id="owf99CE72FDB30C8FD0902CE01843ED4D88" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcE1790624963D540C427806C2B2809EBA" Guid="00de945a-e306-4840-1dd3-b8e968184b74">
<File Id="owfE1790624963D540C427806C2B2809EBA" Source="$(var.SourceDir)\x64\cvextern.dll" KeyPath="yes" />
<Component Id="owc5A8A23B0047B0D17D2E388C7647E2495" Guid="0bc611bd-4c59-08df-c64a-8fa2236aa7a5">
<File Id="owf5A8A23B0047B0D17D2E388C7647E2495" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc5F1F538D5D53D69031C503A5A647FA86" Guid="4e9e9fdc-8d0c-3ba0-a240-9e6ef5842194">
<File Id="owf5F1F538D5D53D69031C503A5A647FA86" Source="$(var.SourceDir)\x64\msvcp140.dll" KeyPath="yes" />
<Component Id="owc86B8E7B458701723CB9EC03C1690DC6E" Guid="cdd72de0-864d-fb89-212f-4bd06f0dcd10">
<File Id="owf86B8E7B458701723CB9EC03C1690DC6E" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc8F40E3E29777D025A9F18E5B6042F30D" Guid="e05981f2-643b-ca90-e066-2434e056751a">
<File Id="owf8F40E3E29777D025A9F18E5B6042F30D" Source="$(var.SourceDir)\x64\msvcp140_1.dll" KeyPath="yes" />
</Component>
<Component Id="owc0881D1B926887713CEA1FB8CE1244020" Guid="3baf74a4-81ca-d0a7-70ea-912a08d3dc3c">
<File Id="owf0881D1B926887713CEA1FB8CE1244020" Source="$(var.SourceDir)\x64\msvcp140_2.dll" KeyPath="yes" />
</Component>
<Component Id="owc2FF8EDA65751914E3C80D405856A37CE" Guid="283d40b2-5948-d5e0-9173-53dbd88d6e13">
<File Id="owf2FF8EDA65751914E3C80D405856A37CE" Source="$(var.SourceDir)\x64\msvcp140_codecvt_ids.dll" KeyPath="yes" />
</Component>
<Component Id="owcA66BA6B6AE2CB062F1DEE173EBAC6013" Guid="2c9e44cd-17bb-ac7b-b524-b8d94f9cf180">
<File Id="owfA66BA6B6AE2CB062F1DEE173EBAC6013" Source="$(var.SourceDir)\x64\opencv_videoio_ffmpeg440_64.dll" KeyPath="yes" />
</Component>
<Component Id="owc8C50C7464818ADC2267594B33B7B1EE6" Guid="049c0f0d-c410-daa8-b6ec-1c515fdfce03">
<File Id="owf8C50C7464818ADC2267594B33B7B1EE6" Source="$(var.SourceDir)\x64\vcruntime140.dll" KeyPath="yes" />
</Component>
<Component Id="owcBF69387AE1C9C06910622B5629DAAA62" Guid="051ca95f-4aa8-18b1-56da-7788687d06e0">
<File Id="owfBF69387AE1C9C06910622B5629DAAA62" Source="$(var.SourceDir)\x64\vcruntime140_1.dll" KeyPath="yes" />
<Component Id="owc8370BED3D17A58E88E193350B14A5450" Guid="cc521992-26e9-bf12-e777-68f8e2102405">
<File Id="owf8370BED3D17A58E88E193350B14A5450" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owd3BCA71FC1DDF940F5FD535BAC750E17B" Name="x86">
<Component Id="owcFBC3B4CD533BC131080BCB572CEE8474" Guid="8b12ad7e-4019-3cca-c71d-82e5f3e6a080">
<File Id="owfFBC3B4CD533BC131080BCB572CEE8474" Source="$(var.SourceDir)\x86\concrt140.dll" KeyPath="yes" />
<Directory Id="owd17C6A2D314297F8FF3C608803909F7BE" Name="de">
<Component Id="owc6A8D7823467C066EA1EC2F740C66084D" Guid="82c152c6-97bf-f75d-44fc-294474d9a7cb">
<File Id="owf6A8D7823467C066EA1EC2F740C66084D" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc326B123F4EAB21E3B400B7357CCFCB69" Guid="7acba6ad-3e71-b056-9a79-7e53f7d4585b">
<File Id="owf326B123F4EAB21E3B400B7357CCFCB69" Source="$(var.SourceDir)\x86\cvextern.dll" KeyPath="yes" />
<Component Id="owc9116F5B9D0D06FDD8B9116F3E0951A24" Guid="05d40bda-9c56-78d7-90ac-dd3c0b6e32c8">
<File Id="owf9116F5B9D0D06FDD8B9116F3E0951A24" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcEBF7D14133500BEDB79449CCE2A5B412" Guid="3cfe7baa-8f60-50d4-0c7c-41e7f7409b69">
<File Id="owfEBF7D14133500BEDB79449CCE2A5B412" Source="$(var.SourceDir)\x86\msvcp140.dll" KeyPath="yes" />
<Component Id="owc201B77F8A5FFED898E7D6ABA98A1C719" Guid="db330e27-4a94-1662-79dc-50425953f203">
<File Id="owf201B77F8A5FFED898E7D6ABA98A1C719" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcA62A9E2DCF3C1092572B9BA8A90AF2CC" Guid="a5901167-af03-d482-e4a2-55e2fd2dab37">
<File Id="owfA62A9E2DCF3C1092572B9BA8A90AF2CC" Source="$(var.SourceDir)\x86\msvcp140_1.dll" KeyPath="yes" />
<Component Id="owcF790A17350C2437C0E1E354B9D980161" Guid="627f2dc4-5b88-d3f7-3acf-7630111e30e8">
<File Id="owfF790A17350C2437C0E1E354B9D980161" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc4E55EDBDDABF300437BC351C60EA1BBB" Guid="253ff45b-49b3-cf8c-4b98-7ac426bdb997">
<File Id="owf4E55EDBDDABF300437BC351C60EA1BBB" Source="$(var.SourceDir)\x86\msvcp140_2.dll" KeyPath="yes" />
</Directory>
<Directory Id="owdF542F1E9B1CF46F5EC5BF0998941ED93" Name="es">
<Component Id="owcDD2F3A9E1BC6C55110A95C76B075BB2A" Guid="1082627f-113d-241a-abee-cb25d4b696fe">
<File Id="owfDD2F3A9E1BC6C55110A95C76B075BB2A" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcDE8398D0FE76287635F64D20414A83A9" Guid="b3a19e5c-5f5b-984b-06fc-91ec029138fe">
<File Id="owfDE8398D0FE76287635F64D20414A83A9" Source="$(var.SourceDir)\x86\msvcp140_codecvt_ids.dll" KeyPath="yes" />
<Component Id="owcAF0B9E9C8764DB03240C3233FA91FC3F" Guid="61f4d403-eb00-dd15-8880-b8ae920ff3b3">
<File Id="owfAF0B9E9C8764DB03240C3233FA91FC3F" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcB3105100F274DC6C121EB91815CE430E" Guid="17155558-2ffd-5452-640e-b77c2e2b86e5">
<File Id="owfB3105100F274DC6C121EB91815CE430E" Source="$(var.SourceDir)\x86\opencv_videoio_ffmpeg440.dll" KeyPath="yes" />
<Component Id="owcA9E6FC4859E34CE57D4623D60AB82100" Guid="6e39d6b9-6efc-9ed5-3392-971358498061">
<File Id="owfA9E6FC4859E34CE57D4623D60AB82100" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcFE2AD2B6C739ABAFD86DE40F4D5B83C9" Guid="30610dbe-339b-b1be-a4a6-626e8fc07490">
<File Id="owfFE2AD2B6C739ABAFD86DE40F4D5B83C9" Source="$(var.SourceDir)\x86\vcruntime140.dll" KeyPath="yes" />
<Component Id="owcB59CB618361B113CFA57D75E883608EA" Guid="ddc56db3-e6a2-c7aa-dc21-3b247964758c">
<File Id="owfB59CB618361B113CFA57D75E883608EA" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdA426C3729D5D59516430C8F667ED8DE8" Name="fr">
<Component Id="owcFECC4FDE99CBE3816D982D1FF8E5E196" Guid="703ebe68-adaa-3f9c-606b-b42fec5159e8">
<File Id="owfFECC4FDE99CBE3816D982D1FF8E5E196" Source="$(var.SourceDir)\fr\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcDDEF75A5FE4B5C43A5794EC0494F1E2C" Guid="56a9d29d-436d-4319-1a0d-cf5306a85f60">
<File Id="owfDDEF75A5FE4B5C43A5794EC0494F1E2C" Source="$(var.SourceDir)\fr\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcF108244D2CA24AF9CCC6DA95FF283CA3" Guid="8a5a7aca-1013-145f-3a57-49946c024af2">
<File Id="owfF108244D2CA24AF9CCC6DA95FF283CA3" Source="$(var.SourceDir)\fr\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcE8E57F27B5A0C2D7A27A164639AA95F9" Guid="caac4561-da90-4c7b-02cd-bdfca5be1694">
<File Id="owfE8E57F27B5A0C2D7A27A164639AA95F9" Source="$(var.SourceDir)\fr\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owd74DAE01CDA8C981B3918AC92ED360AA1" Name="it">
<Component Id="owc4DD3418A4620DABCBBB6CCAA8ECA2707" Guid="421c92b6-85d7-3733-b9a5-ed10229c89a5">
<File Id="owf4DD3418A4620DABCBBB6CCAA8ECA2707" Source="$(var.SourceDir)\it\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc70A38979F7888C6B171A3C37DBD35061" Guid="d19c3295-b474-4fab-9af6-93c9257dfd18">
<File Id="owf70A38979F7888C6B171A3C37DBD35061" Source="$(var.SourceDir)\it\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcE089DC47E89BFE9044FEC67CE8379D17" Guid="15a0d64c-a68c-9780-ddd0-e40920cd6a68">
<File Id="owfE089DC47E89BFE9044FEC67CE8379D17" Source="$(var.SourceDir)\it\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc8B74032559230C1C0C2B5082475A5CD4" Guid="39eabb54-8dd8-65e8-fe00-359ad09cae2a">
<File Id="owf8B74032559230C1C0C2B5082475A5CD4" Source="$(var.SourceDir)\it\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owd939A7C952EF97FFE1E5F44BC8281E343" Name="ja">
<Component Id="owc51FE3ECF820BD499CDE7DBB22A69167D" Guid="3201321c-b8c7-5cbb-2ad8-f8bf5b451b3d">
<File Id="owf51FE3ECF820BD499CDE7DBB22A69167D" Source="$(var.SourceDir)\ja\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc8549DE5E566B16C0AD0E61BE120D8555" Guid="8b4fc791-bf38-333f-a84f-d78fedc6efe3">
<File Id="owf8549DE5E566B16C0AD0E61BE120D8555" Source="$(var.SourceDir)\ja\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcD50AC7A96B0FC09970B32B3681AF3FF4" Guid="1f8ff321-6287-1fbe-4f8d-86eb390bf641">
<File Id="owfD50AC7A96B0FC09970B32B3681AF3FF4" Source="$(var.SourceDir)\ja\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc0A9733AEBD37AD14413D6F786BB5FA8A" Guid="f57405c2-169e-0504-01db-e115d156226b">
<File Id="owf0A9733AEBD37AD14413D6F786BB5FA8A" Source="$(var.SourceDir)\ja\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owd26824DD7BA688994CEC324C96033C66B" Name="ko">
<Component Id="owc82B969E8D4D535732FCF01718B7E606D" Guid="993f9efe-f89f-7b95-8443-2341e293e7a6">
<File Id="owf82B969E8D4D535732FCF01718B7E606D" Source="$(var.SourceDir)\ko\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcABF888E5C49C7DDDF2FB5AA8071F21D9" Guid="13a4540c-353f-31db-f76e-3017c15fe9df">
<File Id="owfABF888E5C49C7DDDF2FB5AA8071F21D9" Source="$(var.SourceDir)\ko\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc1F4AA2DE2CA82FAFEC017FB9E5159A16" Guid="b96179dd-f81f-6158-e087-b01eeb552325">
<File Id="owf1F4AA2DE2CA82FAFEC017FB9E5159A16" Source="$(var.SourceDir)\ko\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc49136EC48B42F29310D5FAB96EB39C77" Guid="7d59fb12-e36d-3b98-1b54-8182dc102913">
<File Id="owf49136EC48B42F29310D5FAB96EB39C77" Source="$(var.SourceDir)\ko\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdC3B37D0EB36BEDA1B06A324A062DC94D" Name="pl">
<Component Id="owc4D2D720AD4B25046F5C3A8337C58558F" Guid="f9f595eb-39b5-e326-d983-3aca9a6bb500">
<File Id="owf4D2D720AD4B25046F5C3A8337C58558F" Source="$(var.SourceDir)\pl\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc247996509C92190D211D51C687663973" Guid="d3d661d6-e99e-91e3-9512-9a35c05b5d78">
<File Id="owf247996509C92190D211D51C687663973" Source="$(var.SourceDir)\pl\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc75290668850934E95D9C36037C6CA10D" Guid="8be98fcf-1714-97ea-9e3f-6337e8a79c4a">
<File Id="owf75290668850934E95D9C36037C6CA10D" Source="$(var.SourceDir)\pl\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc01C7CE26E845E06F3A50D520FB278BCF" Guid="d1ddafed-c698-3973-d2a4-4c4d00620030">
<File Id="owf01C7CE26E845E06F3A50D520FB278BCF" Source="$(var.SourceDir)\pl\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdE3101CE52C8B10FCC8A2CC81C4C96F39" Name="pt-BR">
<Component Id="owc66101D80AE2357408A5C5CDB0D87BEB0" Guid="9fa0b68e-9b5f-699d-79d5-b93a4344d2eb">
<File Id="owf66101D80AE2357408A5C5CDB0D87BEB0" Source="$(var.SourceDir)\pt-BR\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcFF7C74C94543248FAB00F923E96F0218" Guid="4dbc0468-33ed-1ad7-80c8-e7589d99ef83">
<File Id="owfFF7C74C94543248FAB00F923E96F0218" Source="$(var.SourceDir)\pt-BR\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc537BEF6F05522283FE8F47F86399668A" Guid="960db198-afc4-40f9-f20e-a5d537c5702a">
<File Id="owf537BEF6F05522283FE8F47F86399668A" Source="$(var.SourceDir)\pt-BR\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc233F59943A3FA33488E78259D09163C6" Guid="e99cb644-a268-a6af-face-e2e7834333cb">
<File Id="owf233F59943A3FA33488E78259D09163C6" Source="$(var.SourceDir)\pt-BR\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdEAE4E7B6D44EEB507A9E5B7539B1C34A" Name="ru">
<Component Id="owcB065F45686216D7224FE9E57071535B1" Guid="e96c2dc1-7b2a-91cf-dfb2-add81e62ac2b">
<File Id="owfB065F45686216D7224FE9E57071535B1" Source="$(var.SourceDir)\ru\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc1810998919C2A9C80EFE093BE92CBEF2" Guid="88c73b6a-b6a5-87f8-ffed-c028f0b6c0e4">
<File Id="owf1810998919C2A9C80EFE093BE92CBEF2" Source="$(var.SourceDir)\ru\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc56892873DDC66705A32DD13C1A40B9F3" Guid="b92e9a16-6e47-a12b-354b-4624ba27ebfd">
<File Id="owf56892873DDC66705A32DD13C1A40B9F3" Source="$(var.SourceDir)\ru\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc53575A00E0697BB0E07983D26C103FEA" Guid="64e7fa95-8227-2c96-6a82-e914b6ce047c">
<File Id="owf53575A00E0697BB0E07983D26C103FEA" Source="$(var.SourceDir)\ru\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdFCC3FD9F99A4D5BEDEAC61F3322D2D93" Name="tr">
<Component Id="owcEC06D7EB1988F1B550C8B3569B0261D3" Guid="07379a43-cb0f-ea5f-0cfe-d71fddfe14e6">
<File Id="owfEC06D7EB1988F1B550C8B3569B0261D3" Source="$(var.SourceDir)\tr\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcBA8A623686D1AEABEB47E9B2FB674C3A" Guid="14f5bbbe-61a0-2e13-aa01-612beea284ea">
<File Id="owfBA8A623686D1AEABEB47E9B2FB674C3A" Source="$(var.SourceDir)\tr\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc618B2DBE7EB4D4F7E675C5D04CD64E7E" Guid="197802f2-556a-5b71-650c-faf644c38863">
<File Id="owf618B2DBE7EB4D4F7E675C5D04CD64E7E" Source="$(var.SourceDir)\tr\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc91567B2B4E8154089395D1A78358BE89" Guid="1c327c0f-a510-b334-7130-5c9e6609dc7b">
<File Id="owf91567B2B4E8154089395D1A78358BE89" Source="$(var.SourceDir)\tr\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owd7142663FADDFFB05CCE01DC370DE4995" Name="zh-Hans">
<Component Id="owc28B8853BEB28067D4AB79B73216A3AC8" Guid="f6b6af15-bb3a-3eda-972d-47cb28af6c03">
<File Id="owf28B8853BEB28067D4AB79B73216A3AC8" Source="$(var.SourceDir)\zh-Hans\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owcDA343DBA19E680B537006D75B50A616D" Guid="898f5dc8-48bd-913f-968d-10e37f8347f7">
<File Id="owfDA343DBA19E680B537006D75B50A616D" Source="$(var.SourceDir)\zh-Hans\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc074201B7ECF4E55183EF1FC13FC03B70" Guid="ef2d2267-19a2-0443-6ae4-16cfed6b8091">
<File Id="owf074201B7ECF4E55183EF1FC13FC03B70" Source="$(var.SourceDir)\zh-Hans\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc5371E4C6A9B06D411E8EAC3E5A48E7EA" Guid="a7649dfb-52b9-08d3-6f03-f7aed4d2cce3">
<File Id="owf5371E4C6A9B06D411E8EAC3E5A48E7EA" Source="$(var.SourceDir)\zh-Hans\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
<Directory Id="owdA86DB5E08AB73906A10F69BC4AA81DE2" Name="zh-Hant">
<Component Id="owc18EA70FFACC7303C11A678723F8E1919" Guid="71c1ee6c-af04-89be-a2f7-20205b5f371e">
<File Id="owf18EA70FFACC7303C11A678723F8E1919" Source="$(var.SourceDir)\zh-Hant\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc7B45E327235A25974959071E8D015643" Guid="ebc62531-8adf-6e26-4b07-8c8ae1b1645c">
<File Id="owf7B45E327235A25974959071E8D015643" Source="$(var.SourceDir)\zh-Hant\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc35485D602BBBDC5C5F40469EC390B90C" Guid="48279d95-5026-06e5-350f-7fb5d19fe1c1">
<File Id="owf35485D602BBBDC5C5F40469EC390B90C" Source="$(var.SourceDir)\zh-Hant\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component>
<Component Id="owc505D5854210A555AEF782935C164E813" Guid="778f403b-5deb-df93-7dc7-44b5fa099c25">
<File Id="owf505D5854210A555AEF782935C164E813" Source="$(var.SourceDir)\zh-Hant\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component>
</Directory>
</Directory>
Binary file not shown.
Binary file not shown.
+5 -5
View File
@@ -110,19 +110,19 @@ $slicerFile.Decode($inputFile, $progress);
###################################################
# Morph bottom erode
Write-Output "Eroding bottoms with ${iterations} iterations, please wait..."
$morph = New-Object UVtools.Core.Operations.OperationMorph
$morph = [UVtools.Core.Operations.OperationMorph]::new($slicerFile)
$morph.MorphOperation = [Emgu.CV.CvEnum.MorphOp]::Erode
$morph.IterationsStart = $iterations
$morph.LayerIndexEnd = $slicerFile.BottomLayerCount - 1
if(!$morph.Execute($slicerFile, $progress)){ return; }
$morph.SelectBottomLayers()
if(!$morph.Execute($progress)){ return; }
##############
# Dont touch #
##############
# Save file with _modified name appended
$filePath = [System.IO.Path]::GetDirectoryName($inputFile);
$fileExt = [System.IO.Path]::GetExtension($inputFile);
$filePath = [System.IO.Path]::GetDirectoryName($inputFile)
$fileExt = [System.IO.Path]::GetExtension($inputFile)
$fileNoExt = [System.IO.Path]::GetFileNameWithoutExtension($inputFile)
$fileOutput = "${filePath}${dirSeparator}${fileNoExt}_modified${fileExt}"
Write-Output "Saving as ${fileNoExt}_modified${fileExt}, please wait..."
+10 -11
View File
@@ -79,31 +79,30 @@ Take **[Erode-Bottom.ps1](https://github.com/sn4k3/UVtools/blob/master/UVtools.S
* Example:
```Powershell
# Erode bottom layers
$morph = New-Object UVtools.Core.Operations.OperationMorph
$morph = [UVtools.Core.Operations.OperationMorph]::new($slicerFile)
$morph.MorphOperation = [Emgu.CV.CvEnum.MorphOp]::Erode
$morph.IterationsStart = $iterations
$morph.LayerIndexEnd = $slicerFile.BottomLayerCount - 1
if(!$morph.Execute($slicerFile, $progress)){ return; }
$morph.SelectBottomLayers()
if(!$morph.Execute($progress)){ return }
# Reuse object and erode normal layers with 1 less iteration
$morph.IterationsStart = $iterations - 1
$morph.LayerIndexStart = $slicerFile.BottomLayerCount
$morph.LayerIndexEnd = $slicerFile.LayerCount - 1
if(!$morph.Execute($slicerFile, $progress)){ return }
$morph.SelectNormalLayers()
if(!$morph.Execute($progress)){ return }
# Rotate layer 0, 45º
$rotate = New-Object UVtools.Core.Operations.OperationRotate
# Rotate all layers, 45º
$rotate = [UVtools.Core.Operations.OperationRotate]::new($slicerFile)
$rotate.AngleDegrees = 45;
if(!$rotate.Execute($slicerFile, $progress)){ return }
if(!$rotate.Execute($progress)){ return }
# Rotate layer 1, 90º
$rotate.LayerIndexStart = 1
$rotate.LayerIndexEnd = 1
$rotate.AngleDegrees = 90
if(!$rotate.Execute($slicerFile, $progress)){ return }
if(!$rotate.Execute($progress)){ return }
```
## Contribute with your scripts
If you make a usefull script and want to contribute you can share and publish your script under [github - issues](https://github.com/sn4k3/UVtools/issues/new?assignees=sn4k3&labels=script&template=script.md&title=%5BSCRIPT%5D+).
If you make a usefull script and want to contribute you can share and publish your script under [github - discussions - scripts](https://github.com/sn4k3/UVtools/discussions/categories/scripts).
After analyzation it will be published on the repository
+5 -4
View File
@@ -2,9 +2,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UVtools.WPF.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
<StyleInclude Source="avares://ThemeEditor.Controls.ColorPicker/ColorPicker.xaml"/>
<FluentTheme Mode="Light"/>
<StyleInclude Source="avares://ThemeEditor.Controls.ColorPicker/ColorPicker.axaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
<StyleInclude Source="/Assets/Styles/Styles.xaml" />
<StyleInclude Source="/Assets/Styles/StylesLight.xaml" />
</Application.Styles>
</Application>
+11 -8
View File
@@ -24,13 +24,12 @@ using UVtools.Core;
using UVtools.Core.FileFormats;
using UVtools.WPF.Extensions;
using UVtools.WPF.Structures;
using Size = System.Drawing.Size;
namespace UVtools.WPF
{
public class App : Application
{
public static IThemeSelector? ThemeSelector { get; set; }
public static ThemeSelector ThemeSelector { get; set; }
public static MainWindow MainWindow;
public static FileFormat SlicerFile = null;
@@ -53,7 +52,7 @@ namespace UVtools.WPF
OperationProfiles.Load();
ThemeSelector = Avalonia.ThemeManager.ThemeSelector.Create(Path.Combine(ApplicationPath, "Assets", "Themes"));
/*ThemeSelector = ThemeSelector.Create(Path.Combine(ApplicationPath, "Assets", "Themes"));
ThemeSelector.LoadSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
if (ThemeSelector.SelectedTheme.Name == "UVtoolsDark" || ThemeSelector.SelectedTheme.Name == "Light")
{
@@ -63,13 +62,16 @@ namespace UVtools.WPF
theme.ApplyTheme();
break;
}
}
}*/
MainWindow = new MainWindow();
try
{
CvInvoke.CheckLibraryLoaded();
if(!CvInvoke.Init())
await MainWindow.MessageBoxError("UVtools can not init OpenCV library\n" +
"Please build or install this dependencies in order to run UVtools\n" +
"Check manual or page at 'Requirements' section for help",
"UVtools can not run");
}
catch (Exception e)
{
@@ -82,8 +84,7 @@ namespace UVtools.WPF
}
desktop.MainWindow = MainWindow;
desktop.Exit += (sender, e)
=> ThemeSelector.SaveSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
//desktop.Exit += (sender, e) => ThemeSelector.SaveSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
}
base.OnFrameworkInitializationCompleted();
@@ -191,6 +192,8 @@ namespace UVtools.WPF
if (OperatingSystem.IsLinux())
{
var folder1 = $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}{Path.DirectorySeparatorChar}.config{Path.DirectorySeparatorChar}PrusaSlicer";
if (Directory.Exists(folder1)) return folder1;
return $"{Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)}{Path.DirectorySeparatorChar}.PrusaSlicer";
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

+53
View File
@@ -0,0 +1,53 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20"></Border>
</Design.PreviewWith>
<Style Selector="Expander[IsExpanded=true] /template/ ToggleButton#PART_toggle /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource ToggleButtonForeground}"/>
</Style>
<Style Selector="Border.GroupBox">
<Setter Property="BorderThickness" Value="4" />
</Style>
<Style Selector="TextBlock.GroupBoxHeader">
<Setter Property="Padding" Value="10" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="Border.FooterActions">
<Setter Property="Padding" Value="5,20" />
<Setter Property="Margin" Value="0,10,0, 0" />
</Style>
<Style Selector="TextBox.TransparentReadOnly">
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="CaretBrush" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="AcceptsReturn" Value="True" />
<Setter Property="AcceptsTab" Value="True" />
</Style>
<Style Selector="RadioButton">
<Setter Property="MinWidth" Value="30"></Setter>
</Style>
<Style Selector="CheckBox">
<Setter Property="MinWidth" Value="30"></Setter>
</Style>
<Style Selector="NumericUpDown">
<Setter Property="MinWidth" Value="130"></Setter>
<Setter Property="ClipValueToMinMax" Value="True"></Setter>
</Style>
<Style Selector="TabControl">
<Setter Property="Padding" Value="0"></Setter>
</Style>
</Styles>
@@ -0,0 +1,20 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20"></Border>
</Design.PreviewWith>
<Style Selector="Border.GroupBox">
<Setter Property="BorderBrush" Value="LightBlue" />
</Style>
<Style Selector="TextBlock.GroupBoxHeader">
<Setter Property="Background" Value="LightBlue" />
</Style>
<Style Selector="Border.FooterActions">
<Setter Property="Background" Value="LightGray" />
</Style>
</Styles>
@@ -10,18 +10,17 @@
<StackPanel Spacing="10">
<Grid
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
ColumnDefinitions="Auto,10,100,5,Auto,20,Auto,10,100,5,Auto"
ColumnDefinitions="Auto,10,150,5,Auto,20,Auto,10,150,5,Auto"
>
<TextBlock Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center"
Text="Layer height:"/>
<NumericUpDown Grid.Row="0" Grid.Column="2"
ClipValueToMinMax="True"
Increment="0.01"
Minimum="0.01"
Maximum="0.30"
FormatString="\{0:0.00\}"
FormatString="F02"
Value="{Binding Operation.LayerHeight}"
/>
<TextBlock Grid.Row="0" Grid.Column="4"
@@ -41,7 +40,7 @@
Increment="1"
Minimum="1"
Maximum="1000"
FormatString="\{0:0.00\}"
FormatString="F02"
Value="{Binding Operation.BottomLayers}"
/>
<TextBlock Grid.Row="2" Grid.Column="4"
@@ -60,7 +59,7 @@
Increment="1"
Minimum="1"
Maximum="1000"
FormatString="\{0:0.00\}"
FormatString="F02"
Value="{Binding Operation.NormalLayers}"
/>
<TextBlock Grid.Row="2" Grid.Column="10"
@@ -181,7 +180,7 @@
<Grid
Margin="0,10,0,0"
RowDefinitions="Auto,10,Auto"
ColumnDefinitions="Auto,10,80,5,Auto,5,80,5,Auto,40,Auto,10,80"
ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,30,Auto,10,Auto"
>
<CheckBox Grid.Row="0" Grid.Column="2"
@@ -265,7 +264,7 @@
<Grid
Margin="0,10,0,0"
RowDefinitions="Auto,10,Auto,10,Auto,5,Auto"
ColumnDefinitions="Auto,10,80,5,Auto,5,80,5,Auto,20,Auto,10,80"
ColumnDefinitions="Auto,10,Auto,5,Auto,5,Auto,5,Auto,20,Auto,10,Auto"
>
<CheckBox Grid.Row="0" Grid.Column="2"
@@ -29,15 +29,9 @@ namespace UVtools.WPF.Controls.Calibrators
public CalibrateElephantFootControl()
{
this.InitializeComponent();
BaseOperation = new OperationCalibrateElephantFoot();
InitializeComponent();
if(App.SlicerFile is not null)
{
Operation.LayerHeight = (decimal) App.SlicerFile.LayerHeight;
Operation.BottomExposure = (decimal) App.SlicerFile.BottomExposureTime;
Operation.NormalExposure = (decimal) App.SlicerFile.ExposureTime;
}
BaseOperation = new OperationCalibrateElephantFoot(SlicerFile);
_kernelCtrl = this.Find<KernelControl>("KernelCtrl");
@@ -60,7 +54,6 @@ namespace UVtools.WPF.Controls.Calibrators
{
case ToolWindow.Callbacks.Init:
case ToolWindow.Callbacks.ProfileLoaded:
Operation.Resolution = App.SlicerFile.Resolution;
Operation.PropertyChanged += (sender, e) =>
{
_timer.Stop();

Some files were not shown because too many files have changed in this diff Show More