* (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 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> <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 ## Is your feature request related to a problem? Please describe
+4 -4
View File
@@ -6,7 +6,7 @@ labels: question
assignees: sn4k3 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> ## READ THIS
Do not use issues to post questions! Use discussions instead!:
## Describe the question https://github.com/sn4k3/UVtools/discussions/categories/q-a
A clear and concise description of your question. ## READ THIS
+4 -7
View File
@@ -6,10 +6,7 @@ labels: script
assignees: sn4k3 assignees: sn4k3
--- ---
## Describe what your script does ## READ THIS
A clear and concise description of your script, and all it steps. Do not use issues to post scripts! Use discussions instead!:
https://github.com/sn4k3/UVtools/discussions/categories/scripts
## READ THIS
```Powershell
#Paste your code here or attach the .ps1 file
```
+37
View File
@@ -1,5 +1,42 @@
# Changelog # 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 ## 22/01/2021 - v2.3.2
* (Add) Settings - Automations: Change only light-off delay if value is zero (Enabled by default) * (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 ### ### Configuration ###
#################################### ####################################
$enableMSI = $true $enableMSI = $true
$buildOnly = $null
#$buildOnly = ""#"win-x64"
# Profilling # Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
$deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
@@ -83,22 +85,22 @@ $runtimes =
@{ @{
"win-x64" = @{ "win-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true" "extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("libcvextern.so", "libcvextern.dylib", "UVtools.sh") "exclude" = @("UVtools.sh")
"include" = @() "include" = @()
} }
"linux-x64" = @{ "linux-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true" "extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib") "exclude" = @()
"include" = @("libcvextern.so") "include" = @("libcvextern.so")
} }
"arch-x64" = @{ "arch-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true" "extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib", "libcvextern.so") "exclude" = @()
"include" = @("libcvextern.so") "include" = @("libcvextern.so")
} }
"rhel-x64" = @{ "rhel-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true" "extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.dylib") "exclude" = @()
"include" = @("libcvextern.so") "include" = @("libcvextern.so")
} }
#"unix-x64" = @{ #"unix-x64" = @{
@@ -107,12 +109,13 @@ $runtimes =
#} #}
"osx-x64" = @{ "osx-x64" = @{
"extraCmd" = "-p:PublishReadyToRun=true" "extraCmd" = "-p:PublishReadyToRun=true"
"exclude" = @("x86", "x64", "libcvextern.so") "exclude" = @()
"include" = @("libcvextern.dylib") "include" = @("libcvextern.dylib")
} }
} }
foreach ($obj in $runtimes.GetEnumerator()) { foreach ($obj in $runtimes.GetEnumerator()) {
if(![string]::IsNullOrWhiteSpace($buildOnly) -and !$buildOnly.Equals($obj.Name)) {continue}
# Configuration # Configuration
$deployStopWatch.Restart() $deployStopWatch.Restart()
$runtime = $obj.Name; # runtime name $runtime = $obj.Name; # runtime name
+1 -1
View File
@@ -26,7 +26,7 @@ min_exposure_time = 1
min_initial_exposure_time = 1 min_initial_exposure_time = 1
print_host = print_host =
printer_model = SL1 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_settings_id =
printer_technology = SLA printer_technology = SLA
printer_variant = default 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 absolute_correction = 0
area_fill = 50 area_fill = 50
bed_custom_model = bed_custom_model =
@@ -26,7 +26,7 @@ min_exposure_time = 1
min_initial_exposure_time = 1 min_initial_exposure_time = 1
print_host = print_host =
printer_model = SL1 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_settings_id =
printer_technology = SLA printer_technology = SLA
printer_variant = default printer_variant = default
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.01 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.01 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.01 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.02 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.02 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.025 UltraDetail inherits = 0.025 UltraDetail
layer_height = 0.02 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.035 Detail inherits = 0.035 Detail
layer_height = 0.03 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.035 Detail inherits = 0.035 Detail
layer_height = 0.03 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.035 Detail inherits = 0.035 Detail
layer_height = 0.03 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.04 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.04 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.04 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.05 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.05 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.05 Normal inherits = 0.05 Normal
layer_height = 0.05 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.1 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.1 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.1 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.15 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.15 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.15 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.2 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.2 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 pad_brim_size = 1.6
@@ -9,7 +9,7 @@ hollowing_min_thickness = 3
hollowing_quality = 0.5 hollowing_quality = 0.5
inherits = 0.1 Fast inherits = 0.1 Fast
layer_height = 0.2 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 = 0
pad_around_object_everywhere = 0 pad_around_object_everywhere = 0
pad_brim_size = 1.6 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) 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); //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) 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); //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) public static uint DecimalDigits(this decimal val)
{ {
var valStr = val.ToString(CultureInfo.InvariantCulture).TrimEnd('0'); 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('.'); var index = valStr.IndexOf('.');
if (index < 0) return 0; if (index < 0) return 0;
return (uint)(valStr.Substring(index).Length - 1); 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. * of this license document, but changing it is not allowed.
*/ */
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
namespace UVtools.Core.Extensions namespace UVtools.Core.Extensions
@@ -19,5 +20,18 @@ namespace UVtools.Core.Extensions
var splitPath = path.Split('.', 2, StringSplitOptions.TrimEntries); var splitPath = path.Split('.', 2, StringSplitOptions.TrimEntries);
return splitPath.Length == 0 ? string.Empty : splitPath[0]; 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing;
using System.Text; using System.Text;
namespace UVtools.Core.Extensions namespace UVtools.Core.Extensions
@@ -34,5 +35,8 @@ namespace UVtools.Core.Extensions
adjustedSize, adjustedSize,
SizeSuffixes[mag]); 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; 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); //var filename = fileFullPath.EndsWith(TemporaryFileAppend) ? Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(fileFullPath)) : Path.GetFileNameWithoutExtension(fileFullPath);
if (Printer == PrinterType.Unknown) if (Printer == PrinterType.Unknown)
@@ -662,20 +658,14 @@ namespace UVtools.Core.FileFormats
RebuildGCode(); RebuildGCode();
outputFile.PutFileContent($"{filename}.gcode", GCode.ToString(), ZipArchiveMode.Create); 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); using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
if(progress is null) progress = new OperationProgress(OperationProgress.StatusGatherLayers, LayerCount);
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
{ {
var entry = inputFile.GetEntry("manifest.xml"); var entry = inputFile.GetEntry("manifest.xml");
if (!ReferenceEquals(entry, null)) // Wanhao if (entry is not null) // Wanhao
{ {
//DecodeXML(fileFullPath, inputFile, progress); //DecodeXML(fileFullPath, inputFile, progress);
Printer = PrinterType.Wanhao; Printer = PrinterType.Wanhao;
+22 -37
View File
@@ -1336,17 +1336,13 @@ namespace UVtools.Core.FileFormats
LayerDefinitions = null; 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(); LayersHash.Clear();
HeaderSettings.Magic = fileFullPath.EndsWith(".ctb") || fileFullPath.EndsWith($".ctb{TemporaryFileAppend}") ? MAGIC_CBT : MAGIC_CBDDLP; HeaderSettings.Magic = fileFullPath.EndsWith(".ctb") || fileFullPath.EndsWith($".ctb{TemporaryFileAppend}") ? MAGIC_CBT : MAGIC_CBDDLP;
HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings); HeaderSettings.PrintParametersSize = (uint)Helpers.Serializer.SizeOf(PrintParametersSettings);
if (IsCbtFile) if (IsCbtFile)
{ {
if (SlicerInfoSettings.AntiAliasLevel <= 1) if (SlicerInfoSettings.AntiAliasLevel <= 1)
@@ -1380,8 +1376,8 @@ namespace UVtools.Core.FileFormats
} }
else else
{ {
HeaderSettings.Version = 2; //HeaderSettings.Version = 2;
HeaderSettings.EncryptionKey = 0; HeaderSettings.EncryptionKey = 0; // Force disable encryption
SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CBDDLP; SlicerInfoSettings.EncryptionMode = ENCRYPTYION_MODE_CBDDLP;
} }
@@ -1511,8 +1507,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin); outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:"); Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]); Debug.WriteLine(Previews[0]);
@@ -1523,14 +1517,9 @@ 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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
//HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
@@ -1659,38 +1648,34 @@ namespace UVtools.Core.FileFormats
return; 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)
{ {
var layer = new Layer((uint) layerIndex, image, LayerManager) PositionZ = LayerDefinitions[0, layerIndex].LayerPositionZ,
{ ExposureTime = LayerDefinitions[0, layerIndex].LayerExposure,
PositionZ = LayerDefinitions[0, layerIndex].LayerPositionZ, LightOffDelay = LayerDefinitions[0, layerIndex].LightOffSeconds,
ExposureTime = LayerDefinitions[0, layerIndex].LayerExposure, };
LightOffDelay = LayerDefinitions[0, layerIndex].LightOffSeconds,
};
if (LayerDefinitionsEx is not null) if (LayerDefinitionsEx is not null)
{
if (layerIndex == 0)
{ {
if (layerIndex == 0)
{
}
layer.LiftHeight = LayerDefinitionsEx[layerIndex].LiftHeight;
layer.LiftSpeed = LayerDefinitionsEx[layerIndex].LiftSpeed;
layer.RetractSpeed = LayerDefinitionsEx[layerIndex].RetractSpeed;
layer.LightPWM = (byte) LayerDefinitionsEx[layerIndex].LightPWM;
} }
layer.LiftHeight = LayerDefinitionsEx[layerIndex].LiftHeight;
layer.LiftSpeed = LayerDefinitionsEx[layerIndex].LiftSpeed;
layer.RetractSpeed = LayerDefinitionsEx[layerIndex].RetractSpeed;
layer.LightPWM = (byte) LayerDefinitionsEx[layerIndex].LightPWM;
}
this[layerIndex] = layer; this[layerIndex] = layer;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
}
} }
}); });
} }
progress.Token.ThrowIfCancellationRequested();
} }
public override void SaveAs(string filePath = null, OperationProgress progress = null) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+3 -13
View File
@@ -400,11 +400,8 @@ namespace UVtools.Core.FileFormats
#region Methods #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)) using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
{ {
if (Thumbnails.Length > 0 && !ReferenceEquals(Thumbnails[0], null)) if (Thumbnails.Length > 0 && !ReferenceEquals(Thumbnails[0], null))
@@ -448,21 +445,14 @@ namespace UVtools.Core.FileFormats
progress++; 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("run.gcode"); var entry = inputFile.GetEntry("run.gcode");
if (!ReferenceEquals(entry, null)) if (entry is not null)
{ {
//Clear(); //Clear();
//throw new FileLoadException("run.gcode not found", fileFullPath); //throw new FileLoadException("run.gcode not found", fileFullPath);
+2 -12
View File
@@ -999,11 +999,8 @@ namespace UVtools.Core.FileFormats
LayersDefinitions = null; 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(); LayersHash.Clear();
/*if (HeaderSettings.EncryptionKey == 0) /*if (HeaderSettings.EncryptionKey == 0)
@@ -1118,8 +1115,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin); outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:"); Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]); 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)) 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) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+441 -52
View File
@@ -26,7 +26,7 @@ namespace UVtools.Core.FileFormats
/// <summary> /// <summary>
/// Slicer <see cref="FileFormat"/> representation /// Slicer <see cref="FileFormat"/> representation
/// </summary> /// </summary>
public abstract class FileFormat : BindableBase, IFileFormat, IDisposable, IEquatable<FileFormat>, IEnumerable<Layer> public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFormat>, IEnumerable<Layer>
{ {
#region Constants #region Constants
public const string TemporaryFileAppend = ".tmp"; public const string TemporaryFileAppend = ".tmp";
@@ -44,6 +44,9 @@ namespace UVtools.Core.FileFormats
public const float DefaultLightOffDelay = 0; public const float DefaultLightOffDelay = 0;
public const byte DefaultBottomLightPWM = 255; public const byte DefaultBottomLightPWM = 255;
public const byte DefaultLightPWM = 255; public const byte DefaultLightPWM = 255;
public const float MinimumLayerHeight = 0.01f;
public const float MaximumLayerHeight = 0.20f;
#endregion #endregion
#region Enums #region Enums
@@ -190,11 +193,11 @@ namespace UVtools.Core.FileFormats
public static FileFormat[] AvailableFormats { get; } = public static FileFormat[] AvailableFormats { get; } =
{ {
new SL1File(), // Prusa SL1 new SL1File(), // Prusa SL1
new ChituboxZipFile(), // Zip new ChituboxZipFile(), // Zip
new ChituboxFile(), // cbddlp, cbt, photon new ChituboxFile(), // cbddlp, cbt, photon
new PhotonSFile(), // photons
new PHZFile(), // phz new PHZFile(), // phz
new FDGFile(), // fdg new FDGFile(), // fdg
new PhotonSFile(), // photons
new PhotonWorkshopFile(), // PSW new PhotonWorkshopFile(), // PSW
new ZCodexFile(), // zcodex new ZCodexFile(), // zcodex
new CWSFile(), // CWS new CWSFile(), // CWS
@@ -243,18 +246,27 @@ 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> /// <summary>
/// Gets the count of available file extensions /// Gets the count of available file extensions
/// </summary> /// </summary>
public static byte FileExtensionsCount public static byte FileExtensionsCount => AvailableFormats.Aggregate<FileFormat, byte>(0, (current, fileFormat) => (byte) (current + fileFormat.FileExtensions.Length));
{
get
{
return AvailableFormats.Aggregate<FileFormat, byte>(0, (current, fileFormat) => (byte) (current + fileFormat.FileExtensions.Length));
}
}
/// <summary> /// <summary>
/// Find <see cref="FileFormat"/> by an extension /// Find <see cref="FileFormat"/> by an extension
@@ -285,14 +297,54 @@ namespace UVtools.Core.FileFormats
} }
#endregion #endregion
#region Members
private bool _haveModifiedLayers;
private LayerManager _layerManager;
private float _printTime;
private float _maxPrintHeight;
#endregion
#region Properties #region Properties
/// <summary>
/// Gets the file format type
/// </summary>
public abstract FileFormatType FileType { get; } public abstract FileFormatType FileType { get; }
/// <summary>
/// Gets the valid file extensions for this <see cref="FileFormat"/>
/// </summary>
public abstract FileExtension[] FileExtensions { get; } public abstract FileExtension[] FileExtensions { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/>
/// </summary>
public abstract PrintParameterModifier[] PrintParameterModifiers { get; } public abstract PrintParameterModifier[] PrintParameterModifiers { get; }
/// <summary>
/// Gets the available <see cref="FileFormat.PrintParameterModifier"/> per layer
/// </summary>
public virtual PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } = null; 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 { public string FileFilter {
get 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 public List<KeyValuePair<string, List<string>>> FileFilterAvalonia
=> FileExtensions.Select(fileExt => new KeyValuePair<string, List<string>>(fileExt.Description, new List<string> {fileExt.Extension})).ToList(); => 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 public string FileFilterExtensionsOnly
{ {
get 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; } public bool SuppressRebuildProperties { get; set; }
/// <summary>
/// Gets the input file path loaded into this <see cref="FileFormat"/>
/// </summary>
public string FileFullPath { get; set; } public string FileFullPath { get; set; }
/// <summary>
/// Gets the thumbnails count present in this file format
/// </summary>
public abstract byte ThumbnailsCount { get; } public abstract byte ThumbnailsCount { get; }
/// <summary>
/// Gets the number of created thumbnails
/// </summary>
public byte CreatedThumbnailsCount { public byte CreatedThumbnailsCount {
get get
{ {
@@ -355,10 +425,19 @@ namespace UVtools.Core.FileFormats
} }
} }
/// <summary>
/// Gets the original thumbnail sizes
/// </summary>
public abstract Size[] ThumbnailsOriginalSize { get; } public abstract Size[] ThumbnailsOriginalSize { get; }
/// <summary>
/// Gets the thumbnails for this <see cref="FileFormat"/>
/// </summary>
public Mat[] Thumbnails { get; set; } public Mat[] Thumbnails { get; set; }
/// <summary>
/// Gets the cached layers into compressed bytes
/// </summary>
public LayerManager LayerManager public LayerManager LayerManager
{ {
get => _layerManager; get => _layerManager;
@@ -373,10 +452,10 @@ namespace UVtools.Core.FileFormats
} }
} }
private bool _haveModifiedLayers; /// <summary>
private LayerManager _layerManager; /// Gets the bounding rectangle of the object
private float _printTime; /// </summary>
private float _maxPrintHeight; public Rectangle BoundingRectangle => _layerManager?.BoundingRectangle ?? Rectangle.Empty;
/// <summary> /// <summary>
/// Gets or sets if modifications require a full encode to save /// Gets or sets if modifications require a full encode to save
@@ -387,6 +466,9 @@ namespace UVtools.Core.FileFormats
set => _haveModifiedLayers = value; set => _haveModifiedLayers = value;
} // => LayerManager.IsModified; } // => LayerManager.IsModified;
/// <summary>
/// Gets the image width resolution
/// </summary>
public Size Resolution public Size Resolution
{ {
get => new((int)ResolutionX, (int)ResolutionY); get => new((int)ResolutionX, (int)ResolutionY);
@@ -396,12 +478,21 @@ namespace UVtools.Core.FileFormats
ResolutionY = (uint) value.Height; ResolutionY = (uint) value.Height;
RaisePropertyChanged(); RaisePropertyChanged();
} }
} }
/// <summary>
/// Gets the image width resolution
/// </summary>
public abstract uint ResolutionX { get; set; } public abstract uint ResolutionX { get; set; }
/// <summary>
/// Gets the image height resolution
/// </summary>
public abstract uint ResolutionY { get; set; } public abstract uint ResolutionY { get; set; }
/// <summary>
/// Gets the size of display in millimeters
/// </summary>
public SizeF Display public SizeF Display
{ {
get => new(DisplayWidth, DisplayHeight); 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; } public abstract float DisplayWidth { get; set; }
/// <summary>
/// Gets or sets the display height in millimeters
/// </summary>
public abstract float DisplayHeight { get; set; } 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; } public abstract bool MirrorDisplay { get; set; }
/// <summary>
/// Gets or sets the maximum printer build Z volume
/// </summary>
public virtual float MaxPrintHeight public virtual float MaxPrintHeight
{ {
get => _maxPrintHeight > 0 ? _maxPrintHeight : PrintHeight; get => _maxPrintHeight > 0 ? _maxPrintHeight : PrintHeight;
set => RaiseAndSetIfChanged(ref _maxPrintHeight, value); set => RaiseAndSetIfChanged(ref _maxPrintHeight, value);
} }
/// <summary>
/// Gets or sets the pixels per mm on X direction
/// </summary>
public virtual float Xppmm public virtual float Xppmm
{ {
get => DisplayWidth > 0 ? ResolutionX / DisplayWidth : 0; 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 public virtual float Yppmm
{ {
get => DisplayHeight > 0 ? ResolutionY / DisplayHeight : 0; 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 public SizeF Ppmm
{ {
get => new(Xppmm, Yppmm); 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 ? public decimal XYResolution => DisplayWidth > 0 || DisplayHeight > 0 ?
(decimal) Math.Round(Math.Max( (decimal) Math.Round(Math.Max(
DisplayWidth / ResolutionX, DisplayWidth / ResolutionX,
@@ -461,6 +578,9 @@ namespace UVtools.Core.FileFormats
), 3) ), 3)
: 0; : 0;
/// <summary>
/// Gets the printer XY pixel resolution in microns
/// </summary>
public decimal XYResolutionUm => DisplayWidth > 0 || DisplayHeight > 0 ? public decimal XYResolutionUm => DisplayWidth > 0 || DisplayHeight > 0 ?
(decimal)Math.Round(Math.Max( (decimal)Math.Round(Math.Max(
DisplayWidth / ResolutionX, DisplayWidth / ResolutionX,
@@ -468,11 +588,30 @@ namespace UVtools.Core.FileFormats
), 3) * 1000 ), 3) * 1000
: 0; : 0;
/// <summary>
/// Checks if this file have AntiAliasing
/// </summary>
public bool HaveAntiAliasing => AntiAliasing > 1; public bool HaveAntiAliasing => AntiAliasing > 1;
/// <summary>
/// Gets or sets the AntiAliasing level
/// </summary>
public abstract byte AntiAliasing { get; set; } public abstract byte AntiAliasing { get; set; }
/// <summary>
/// Gets Layer Height in mm
/// </summary>
public abstract float LayerHeight { get; set; } 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 public virtual float PrintHeight
{ {
get => LayerCount == 0 ? 0 : this[LayerCount - 1]?.PositionZ ?? 0; 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; 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); public virtual bool SupportPerLayerSettings => !(PrintParameterPerLayerModifiers is null || PrintParameterPerLayerModifiers.Length == 0);
/// <summary>
/// Gets or sets the layer count
/// </summary>
public virtual uint LayerCount public virtual uint LayerCount
{ {
get => LayerManager?.Count ?? 0; get => LayerManager?.Count ?? 0;
set { } set { }
} }
#region Universal Properties
/// <summary>
/// Gets or sets the number of initial layer count
/// </summary>
public virtual ushort BottomLayerCount { get; set; } public virtual ushort BottomLayerCount { get; set; }
/// <summary>
/// Gets the number of normal layer count
/// </summary>
public uint NormalLayerCount => LayerCount - BottomLayerCount; 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; } public virtual float BottomExposureTime { get; set; }
/// <summary>
/// Gets or sets the normal layer exposure time in seconds
/// </summary>
public virtual float ExposureTime { get; set; } 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; 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; 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; public virtual float BottomLiftHeight { get; set; } = DefaultBottomLiftHeight;
/// <summary>
/// Gets or sets the lift height in mm
/// </summary>
public virtual float LiftHeight { get; set; } = DefaultLiftHeight; 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; public virtual float BottomLiftSpeed { get; set; } = DefaultBottomLiftSpeed;
/// <summary>
/// Gets or sets the speed in mm/min
/// </summary>
public virtual float LiftSpeed { get; set; } = DefaultLiftSpeed; 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; 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; 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; public virtual byte LightPWM { get; set; } = DefaultLightPWM;
#endregion
/// <summary>
/// Gets the estimate print time in seconds
/// </summary>
public virtual float PrintTime public virtual float PrintTime
{ {
get => _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; public float PrintTimeOrComputed => PrintTime > 0 ? PrintTime : PrintTimeComputed;
/// <summary>
/// Gets the calculated estimate print time in seconds
/// </summary>
public float PrintTimeComputed public float PrintTimeComputed
{ {
get 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); 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"); 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; } public virtual float MaterialMilliliters { get; set; }
/// <summary>
/// Gets the estimate material in grams
/// </summary>
public virtual float MaterialGrams { get; set; } public virtual float MaterialGrams { get; set; }
/// <summary>
/// Gets the estimate material cost
/// </summary>
public virtual float MaterialCost { get; set; } public virtual float MaterialCost { get; set; }
/// <summary>
/// Gets the material name
/// </summary>
public virtual string MaterialName { get; set; } public virtual string MaterialName { get; set; }
/// <summary>
/// Gets the machine name
/// </summary>
public virtual string MachineName { get; set; } = "Unknown"; public virtual string MachineName { get; set; } = "Unknown";
/// <summary>
/// Gets the GCode, returns null if not supported
/// </summary>
public StringBuilder GCode { get; set; } public StringBuilder GCode { get; set; }
/// <summary>
/// Gets the GCode, returns null if not supported
/// </summary>
public string GCodeStr => GCode?.ToString(); 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 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 #endregion
#region Constructor #region Constructor
@@ -675,7 +924,7 @@ namespace UVtools.Core.FileFormats
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;
return FileFullPath.Equals(other.FileFullPath); return FileFullPath == other.FileFullPath;
} }
public override int GetHashCode() public override int GetHashCode()
@@ -691,26 +940,31 @@ namespace UVtools.Core.FileFormats
#endregion #endregion
#region Methods #region Methods
/// <summary>
/// Clears all definitions and properties, it also dispose valid candidates
/// </summary>
public virtual void Clear() public virtual void Clear()
{ {
FileFullPath = null; FileFullPath = null;
LayerManager = null; LayerManager = null;
GCode = null; GCode = null;
if (!ReferenceEquals(Thumbnails, null)) if (Thumbnails is not null)
{ {
for (int i = 0; i < ThumbnailsCount; i++) for (int i = 0; i < ThumbnailsCount; i++)
{ {
Thumbnails[i]?.Dispose(); 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) 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 (!File.Exists(fileFullPath)) throw new FileNotFoundException("The specified file does not exists.", fileFullPath);
if (IsExtensionValid(fileFullPath, true)) if (IsExtensionValid(fileFullPath, true))
@@ -721,12 +975,21 @@ namespace UVtools.Core.FileFormats
throw new FileLoadException($"The specified file is not valid.", fileFullPath); 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) public bool IsExtensionValid(string extension, bool isFilePath = false)
{ {
extension = isFilePath ? Path.GetExtension(extension)?.Remove(0, 1) : extension; extension = isFilePath ? Path.GetExtension(extension)?.Remove(0, 1) : extension;
return FileExtensions.Any(fileExtension => fileExtension.Equals(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 = ", ") public string GetFileExtensions(string prepend = ".", string separator = ", ")
{ {
var result = string.Empty; var result = string.Empty;
@@ -743,6 +1006,11 @@ namespace UVtools.Core.FileFormats
return result; 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) public Mat GetThumbnail(uint maxHeight = 400)
{ {
for (int i = 0; i < ThumbnailsCount; i++) for (int i = 0; i < ThumbnailsCount; i++)
@@ -754,6 +1022,11 @@ namespace UVtools.Core.FileFormats
return null; 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) public Mat GetThumbnail(bool largest)
{ {
switch (CreatedThumbnailsCount) 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) public void SetThumbnails(Mat[] images)
{ {
for (var i = 0; i < ThumbnailsCount; i++) 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) public void SetThumbnails(Mat image)
{ {
for (var i = 0; i < ThumbnailsCount; i++) 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) public void SetThumbnail(int index, string filePath)
{ {
Thumbnails[index] = CvInvoke.Imread(filePath, ImreadModes.AnyColor); 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; FileFullPath = fileFullPath;
if (File.Exists(fileFullPath)) if (File.Exists(fileFullPath))
@@ -822,25 +1123,69 @@ namespace UVtools.Core.FileFormats
if(Thumbnails[i].Size == ThumbnailsOriginalSize[i]) continue; if(Thumbnails[i].Size == ThumbnailsOriginalSize[i]) continue;
CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height)); CvInvoke.Resize(Thumbnails[i], Thumbnails[i], new Size(ThumbnailsOriginalSize[i].Width, ThumbnailsOriginalSize[i].Height));
} }
}
public void AfterEncode() EncodeInternally(fileFullPath, progress);
{
LayerManager.Desmodify(); LayerManager.Desmodify();
RequireFullEncode = false; 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(); Clear();
FileValidation(fileFullPath); FileValidation(fileFullPath);
FileFullPath = 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, public virtual void Extract(string path, bool genericConfigExtract = true, bool genericLayersExtract = true,
OperationProgress progress = null) OperationProgress progress = null)
{ {
if (ReferenceEquals(progress, null)) progress = new OperationProgress(); progress ??= new OperationProgress();
progress.ItemName = OperationProgress.StatusExtracting; progress.ItemName = OperationProgress.StatusExtracting;
/*if (emptyFirst) /*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) public float GetHeightFromLayer(uint layerIndex, bool realHeight = true)
{ {
return (float)Math.Round((layerIndex+(realHeight ? 1 : 0)) * LayerHeight, 2); 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) public T GetInitialLayerValueOrNormal<T>(uint layerIndex, T initialLayerValue, T normalLayerValue)
{ {
return layerIndex < BottomLayerCount ? initialLayerValue : normalLayerValue; return layerIndex < BottomLayerCount ? initialLayerValue : normalLayerValue;
} }
/// <summary>
/// Refresh print parameters globals with this file settings
/// </summary>
public void RefreshPrintParametersModifiersValues() public void RefreshPrintParametersModifiersValues()
{ {
if (PrintParameterModifiers is null) return; 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) public void RefreshPrintParametersPerLayerModifiersValues(uint layerIndex)
{ {
if (PrintParameterPerLayerModifiers is null) return; 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) public object GetValueFromPrintParameterModifier(PrintParameterModifier modifier)
{ {
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount)) if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount))
@@ -1098,6 +1468,12 @@ namespace UVtools.Core.FileFormats
return null; 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) public bool SetValueFromPrintParameterModifier(PrintParameterModifier modifier, decimal value)
{ {
if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount)) if (ReferenceEquals(modifier, PrintParameterModifier.BottomLayerCount))
@@ -1167,6 +1543,10 @@ namespace UVtools.Core.FileFormats
return false; return false;
} }
/// <summary>
/// Sets properties from print parameters
/// </summary>
/// <returns>Number of affected parameters</returns>
public byte SetValuesFromPrintParametersModifiers() public byte SetValuesFromPrintParametersModifiers()
{ {
if (PrintParameterModifiers is null) return 0; if (PrintParameterModifiers is null) return 0;
@@ -1182,36 +1562,34 @@ namespace UVtools.Core.FileFormats
return changed; return changed;
} }
public void EditPrintParameters(OperationEditParameters operation) /// <summary>
{ /// Rebuilds GCode based on current settings
if (operation.PerLayerOverride) /// </summary>
{
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();
}
}
public virtual void RebuildGCode() { } public virtual void RebuildGCode() { }
/// <summary>
/// Saves current configuration on input file
/// </summary>
/// <param name="progress"></param>
public void Save(OperationProgress progress = null) public void Save(OperationProgress progress = null)
{ {
SaveAs(null, progress); 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); 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) public virtual FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null)
{ {
if (!IsValid) return null; if (!IsValid) return null;
@@ -1270,9 +1648,20 @@ namespace UVtools.Core.FileFormats
return slicerFile; 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) public FileFormat Convert(FileFormat to, string fileFullPath, OperationProgress progress = null)
=> Convert(to.GetType(), fileFullPath, progress); => Convert(to.GetType(), fileFullPath, progress);
/// <summary>
/// Validate AntiAlias Level
/// </summary>
public byte ValidateAntiAliasingLevel() public byte ValidateAntiAliasingLevel()
{ {
if (AntiAliasing < 2) return 1; 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; } 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); ImageMat = CvInvoke.Imread(fileFullPath, ImreadModes.Grayscale);
const byte startDivisor = 2; const byte startDivisor = 2;
for (int i = 0; i < ThumbnailsCount; i++) 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) public override FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null)
{ {
throw new NotImplementedException(); throw new NotSupportedException();
} }
+8 -23
View File
@@ -450,12 +450,9 @@ namespace UVtools.Core.FileFormats
return bytes; 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 if (ResolutionY >= 2560) // Longer Orange 30
{ {
HeaderSettings.Float_94 = 170; HeaderSettings.Float_94 = 170;
@@ -495,8 +492,6 @@ namespace UVtools.Core.FileFormats
} }
} }
AfterEncode();
Debug.WriteLine("Encode Results:"); Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-"); Debug.WriteLine("-End-");
@@ -522,10 +517,8 @@ namespace UVtools.Core.FileFormats
return mat; 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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
HeaderSettings = Helpers.Deserialize<Header>(inputFile); HeaderSettings = Helpers.Deserialize<Header>(inputFile);
@@ -570,25 +563,17 @@ namespace UVtools.Core.FileFormats
{ {
if (progress.Token.IsCancellationRequested) return; 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);
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager);
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
}
} }
}); });
LayerManager.RebuildLayersProperties(); LayerManager.RebuildLayersProperties();
FileFullPath = fileFullPath;
} }
progress.Token.ThrowIfCancellationRequested();
} }
public override void SaveAs(string filePath = null, OperationProgress progress = null) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+3 -15
View File
@@ -150,10 +150,8 @@ namespace UVtools.Core.FileFormats
#endregion #endregion
#region Methods #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); uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write)) using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write))
{ {
@@ -164,19 +162,15 @@ namespace UVtools.Core.FileFormats
} }
AfterEncode();
Debug.WriteLine("Encode Results:"); Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-"); Debug.WriteLine("-End-");
} }
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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
//HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile); //HeaderSettings = Helpers.ByteToType<CbddlpFile.Header>(InputFile);
@@ -186,13 +180,7 @@ namespace UVtools.Core.FileFormats
{ {
throw new FileLoadException("Not a valid Makerfile file!", fileFullPath); throw new FileLoadException("Not a valid Makerfile file!", fileFullPath);
} }
FileFullPath = fileFullPath;
} }
progress.Token.ThrowIfCancellationRequested();
} }
public override void SaveAs(string filePath = null, OperationProgress progress = null) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+2 -15
View File
@@ -1017,11 +1017,8 @@ namespace UVtools.Core.FileFormats
LayersDefinitions = null; 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(); LayersHash.Clear();
/*if (HeaderSettings.EncryptionKey == 0) /*if (HeaderSettings.EncryptionKey == 0)
@@ -1139,8 +1136,6 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin); outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, HeaderSettings); Helpers.SerializeWriteFileStream(outputFile, HeaderSettings);
AfterEncode();
Debug.WriteLine("Encode Results:"); Debug.WriteLine("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine(Previews[0]); 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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
@@ -1167,9 +1159,6 @@ namespace UVtools.Core.FileFormats
HeaderSettings.AntiAliasLevel = 1; HeaderSettings.AntiAliasLevel = 1;
FileFullPath = fileFullPath;
progress.Reset(OperationProgress.StatusDecodeThumbnails, ThumbnailsCount); progress.Reset(OperationProgress.StatusDecodeThumbnails, ThumbnailsCount);
Debug.Write("Header -> "); Debug.Write("Header -> ");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
@@ -1256,8 +1245,6 @@ namespace UVtools.Core.FileFormats
} }
}); });
} }
progress.Token.ThrowIfCancellationRequested();
} }
public override void SaveAs(string filePath = null, OperationProgress progress = null) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+12 -25
View File
@@ -125,11 +125,12 @@ namespace UVtools.Core.FileFormats
for (int i = 0; i < imageLength; i++) for (int i = 0; i < imageLength; i++)
{ {
color = color <= 127 ? 0 : 255; // Sanitize no AA //color = color <= 127 ? 0 : 255; // Sanitize no AA
if (spanMat[i] != color) byte thisColor = spanMat[i] <= 127 ? 0 : 255; // Sanitize no AA
if (thisColor != color)
{ {
AddRep(); AddRep();
color = spanMat[i]; color = thisColor; // Sanitize no AA
rep = 1; rep = 1;
} }
else else
@@ -420,12 +421,10 @@ namespace UVtools.Core.FileFormats
return bytes; 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); //uint currentOffset = (uint)Helpers.Serializer.SizeOf(HeaderSettings);
using (var outputFile = new FileStream(fileFullPath, FileMode.Create, FileAccess.Write)) 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("Encode Results:");
Debug.WriteLine(HeaderSettings); Debug.WriteLine(HeaderSettings);
Debug.WriteLine("-End-"); Debug.WriteLine("-End-");
@@ -495,10 +492,8 @@ namespace UVtools.Core.FileFormats
return mat; 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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
HeaderSettings = Helpers.Deserialize<Header>(inputFile); HeaderSettings = Helpers.Deserialize<Header>(inputFile);
@@ -546,24 +541,16 @@ namespace UVtools.Core.FileFormats
{ {
if (progress.Token.IsCancellationRequested) return; 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)
{ {
this[layerIndex] = new Layer((uint) layerIndex, image, LayerManager); progress++;
lock (progress.Mutex)
{
progress++;
}
} }
}); });
LayerManager.RebuildLayersProperties(); LayerManager.RebuildLayersProperties();
FileFullPath = fileFullPath;
} }
progress.Token.ThrowIfCancellationRequested();
} }
public override void SaveAs(string filePath = null, OperationProgress progress = null) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+2 -11
View File
@@ -1048,11 +1048,8 @@ namespace UVtools.Core.FileFormats
LayersDefinition = null; 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(); LayersHash.Clear();
LayersDefinition = new LayerDefinition(LayerCount); LayersDefinition = new LayerDefinition(LayerCount);
@@ -1124,14 +1121,10 @@ namespace UVtools.Core.FileFormats
outputFile.Seek(0, SeekOrigin.Begin); outputFile.Seek(0, SeekOrigin.Begin);
Helpers.SerializeWriteFileStream(outputFile, FileMarkSettings); 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)) using (var inputFile = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
{ {
FileMarkSettings = Helpers.Deserialize<FileMark>(inputFile); 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) public override void SaveAs(string filePath = null, OperationProgress progress = null)
+31 -32
View File
@@ -252,22 +252,30 @@ namespace UVtools.Core.FileFormats
public class OutputConfig public class OutputConfig
{ {
public string Action { get; set; } public string Action { get; set; } = "print";
public string JobDir { get; set; } public string JobDir { get; set; }
public float ExpTime { get; set; } public float ExpTime { get; set; }
public float ExpTimeFirst { 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 float LayerHeight { get; set; }
public string MaterialName { get; set; } public string MaterialName { get; set; } = About.Software;
public ushort NumFade { get; set; } public ushort NumFade { get; set; }
public ushort NumFast { get; set; } public ushort NumFast { get; set; }
public ushort NumSlow { 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 float PrintTime { get; set; }
public string PrinterModel { get; set; } public string PrinterModel { get; set; } = "SL1";
public string PrinterProfile { get; set; } public string PrinterProfile { get; set; } = About.Software;
public string PrinterVariant { get; set; } public string PrinterVariant { get; set; } = "default";
public string PrusaSlicerVersion { get; set; } public string PrusaSlicerVersion { get; set; } = "PrusaSlicer-2.3.0+win64-202101111315";
public float UsedMaterial { get; set; } public float UsedMaterial { get; set; }
public override string ToString() public override string ToString()
@@ -519,10 +527,12 @@ namespace UVtools.Core.FileFormats
Statistics.Clear(); 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)) using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
{ {
var entry = outputFile.CreateEntry("config.ini"); var entry = outputFile.CreateEntry("config.ini");
@@ -562,39 +572,28 @@ namespace UVtools.Core.FileFormats
foreach (var thumbnail in Thumbnails) foreach (var thumbnail in Thumbnails)
{ {
if (ReferenceEquals(thumbnail, null)) continue; 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();
var vec = new VectorOfByte(); CvInvoke.Imencode(".png", thumbnail, vec);
CvInvoke.Imencode(".png", thumbnail, vec); stream.WriteBytes(vec.ToArray());
stream.WriteBytes(vec.ToArray()); stream.Close();
stream.Close();
}
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
progress.Token.ThrowIfCancellationRequested(); progress.Token.ThrowIfCancellationRequested();
Layer layer = this[layerIndex]; Layer layer = this[layerIndex];
var layerImagePath = $"{Path.GetFileNameWithoutExtension(fileFullPath)}{layerIndex:D5}.png"; var layerImagePath = $"{filename}{layerIndex:D5}.png";
//layer.Filename = layerImagePath; //layer.Filename = layerImagePath;
outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create); outputFile.PutFileContent(layerImagePath, layer.CompressedBytes, ZipArchiveMode.Create);
progress++; 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(); PrinterSettings = new Printer();
MaterialSettings = new Material(); MaterialSettings = new Material();
PrintSettings = new Print(); PrintSettings = new Print();
@@ -602,7 +601,7 @@ namespace UVtools.Core.FileFormats
Statistics.ExecutionTime.Restart(); Statistics.ExecutionTime.Restart();
using (var inputFile = ZipFile.OpenRead(FileFullPath)) using (var inputFile = ZipFile.OpenRead(fileFullPath))
{ {
List<string> iniFiles = new(); List<string> iniFiles = new();
foreach (ZipArchiveEntry entity in inputFile.Entries) foreach (ZipArchiveEntry entity in inputFile.Entries)
@@ -625,7 +624,7 @@ namespace UVtools.Core.FileFormats
foreach (var obj in Configs) foreach (var obj in Configs)
{ {
var attribute = obj.GetType().GetProperty(fieldName); var attribute = obj.GetType().GetProperty(fieldName);
if (ReferenceEquals(attribute, null)) continue; if (attribute is null || !attribute.CanWrite) continue;
//Debug.WriteLine(attribute.Name); //Debug.WriteLine(attribute.Name);
Helpers.SetPropertyValue(attribute, obj, keyValue[1]); Helpers.SetPropertyValue(attribute, obj, keyValue[1]);
+10 -23
View File
@@ -360,13 +360,8 @@ namespace UVtools.Core.FileFormats
JsonSettings.Layers = new List<LayerData>(); 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 // Redo layer data
JsonSettings.Layers.Clear(); JsonSettings.Layers.Clear();
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
@@ -430,17 +425,11 @@ namespace UVtools.Core.FileFormats
progress++; progress++;
} }
} }
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 = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
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(FileConfigName); var entry = inputFile.GetEntry(FileConfigName);
if (ReferenceEquals(entry, null)) if (ReferenceEquals(entry, null))
@@ -466,21 +455,19 @@ namespace UVtools.Core.FileFormats
} }
entry = inputFile.GetEntry(FilePreviewHugeName); entry = inputFile.GetEntry(FilePreviewHugeName);
if (!ReferenceEquals(entry, null)) if (entry is not null)
{ {
using (Stream stream = entry.Open()) using Stream stream = entry.Open();
{ Mat image = new Mat();
Mat image = new Mat(); CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image);
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, image); Thumbnails[1] = image;
Thumbnails[1] = image; stream.Close();
stream.Close();
}
} }
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
{ {
entry = inputFile.GetEntry($"{FolderImageName}/{layerIndex:D8}.png"); 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) this[layerIndex] = new Layer(layerIndex, entry.Open(), LayerManager)
{ {
+11 -22
View File
@@ -382,12 +382,8 @@ namespace UVtools.Core.FileFormats
LayersSettings.Clear(); 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; float usedMaterial = MaterialMilliliters / LayerCount;
ResinMetadataSettings.Layers.Clear(); ResinMetadataSettings.Layers.Clear();
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
@@ -471,18 +467,14 @@ namespace UVtools.Core.FileFormats
outputFile.PutFileContent("ResinGCodeData", GCode.ToString(), ZipArchiveMode.Create); 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); using (var inputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Read))
FileFullPath = fileFullPath;
using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read))
{ {
var entry = inputFile.GetEntry("ResinMetadata"); var entry = inputFile.GetEntry("ResinMetadata");
if (ReferenceEquals(entry, null)) if (entry is null)
{ {
Clear(); Clear();
throw new FileLoadException("ResinMetadata not found", fileFullPath); throw new FileLoadException("ResinMetadata not found", fileFullPath);
@@ -491,7 +483,7 @@ namespace UVtools.Core.FileFormats
ResinMetadataSettings = Helpers.JsonDeserializeObject<ResinMetadata>(entry.Open()); ResinMetadataSettings = Helpers.JsonDeserializeObject<ResinMetadata>(entry.Open());
entry = inputFile.GetEntry("UserSettingsData"); entry = inputFile.GetEntry("UserSettingsData");
if (ReferenceEquals(entry, null)) if (entry is null)
{ {
Clear(); Clear();
throw new FileLoadException("UserSettingsData not found", fileFullPath); throw new FileLoadException("UserSettingsData not found", fileFullPath);
@@ -500,7 +492,7 @@ namespace UVtools.Core.FileFormats
UserSettings = Helpers.JsonDeserializeObject<UserSettingsdata>(entry.Open()); UserSettings = Helpers.JsonDeserializeObject<UserSettingsdata>(entry.Open());
entry = inputFile.GetEntry("ZCodeMetadata"); entry = inputFile.GetEntry("ZCodeMetadata");
if (ReferenceEquals(entry, null)) if (entry is null)
{ {
Clear(); Clear();
throw new FileLoadException("ZCodeMetadata not found", fileFullPath); throw new FileLoadException("ZCodeMetadata not found", fileFullPath);
@@ -509,7 +501,7 @@ namespace UVtools.Core.FileFormats
ZCodeMetadataSettings = Helpers.JsonDeserializeObject<ZCodeMetadata>(entry.Open()); ZCodeMetadataSettings = Helpers.JsonDeserializeObject<ZCodeMetadata>(entry.Open());
entry = inputFile.GetEntry("ResinGCodeData"); entry = inputFile.GetEntry("ResinGCodeData");
if (ReferenceEquals(entry, null)) if (entry is null)
{ {
Clear(); Clear();
throw new FileLoadException("ResinGCodeData not found", fileFullPath); throw new FileLoadException("ResinGCodeData not found", fileFullPath);
@@ -615,12 +607,9 @@ M106 S0
entry = inputFile.GetEntry("Preview.png"); entry = inputFile.GetEntry("Preview.png");
if (!ReferenceEquals(entry, null)) if (!ReferenceEquals(entry, null))
{ {
using (Stream stream = entry.Open()) using Stream stream = entry.Open();
{ CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
stream.Close();
CvInvoke.Imdecode(stream.ToArray(), ImreadModes.AnyColor, Thumbnails[0]);
stream.Close();
}
} }
} }
+49 -22
View File
@@ -7,17 +7,15 @@
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.IO.Compression;
using System.Linq; using System.Linq;
using Emgu.CV; using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util; using Emgu.CV.Util;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
using UVtools.Core.Objects; using UVtools.Core.Objects;
using UVtools.Core.Operations;
using Stream = System.IO.Stream; using Stream = System.IO.Stream;
namespace UVtools.Core namespace UVtools.Core
@@ -27,9 +25,24 @@ namespace UVtools.Core
/// </summary> /// </summary>
public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint> 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 #region Properties
public object Mutex = new object(); public object Mutex = new();
/// <summary> /// <summary>
/// Gets the parent layer manager /// Gets the parent layer manager
@@ -152,21 +165,35 @@ namespace UVtools.Core
public float PositionZ public float PositionZ
{ {
get => _positionZ; get => _positionZ;
set => RaiseAndSetIfChanged(ref _positionZ, value); set
{
if(!RaiseAndSetIfChanged(ref _positionZ, value)) return;
RaisePropertyChanged(nameof(LayerHeight));
}
} }
private byte[] _compressedBytes; /// <summary>
private uint _nonZeroPixelCount; /// Gets the layer height in millimeters of this layer
private Rectangle _boundingRectangle = Rectangle.Empty; /// </summary>
private bool _isModified; public float LayerHeight
private uint _index; {
private float _positionZ; get
private float _exposureTime; {
private float _lightOffDelay = FileFormat.DefaultLightOffDelay; if (_index == 0) return _positionZ;
private float _liftHeight = FileFormat.DefaultLiftHeight; Layer previousLayer = this;
private float _liftSpeed = FileFormat.DefaultLiftSpeed;
private float _retractSpeed = FileFormat.DefaultRetractSpeed; while ((previousLayer = previousLayer.PreviousLayer()) is not null) // This cycle returns the correct layer height if two or more layers have the same position z
private byte _lightPwm = FileFormat.DefaultLightPWM; {
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> /// <summary>
/// Gets or sets layer image compressed data /// Gets or sets layer image compressed data
@@ -348,7 +375,7 @@ namespace UVtools.Core
public override string ToString() 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 #endregion
@@ -388,18 +415,18 @@ namespace UVtools.Core
public Layer PreviousLayer() public Layer PreviousLayer()
{ {
if (ReferenceEquals(ParentLayerManager, null) || Index == 0) if (ParentLayerManager is null || _index == 0)
return null; return null;
return ParentLayerManager[Index - 1]; return ParentLayerManager[_index - 1];
} }
public Layer NextLayer() public Layer NextLayer()
{ {
if (ReferenceEquals(ParentLayerManager, null) || Index >= ParentLayerManager.Count - 1) if (ParentLayerManager is null || _index >= ParentLayerManager.Count - 1)
return null; return null;
return ParentLayerManager[Index + 1]; return ParentLayerManager[_index + 1];
} }
public bool SetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier, decimal value) 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; private Rectangle _boundingRectangle = Rectangle.Empty;
/// <summary>
/// Gets the bounding rectangle of the object
/// </summary>
public Rectangle BoundingRectangle public Rectangle BoundingRectangle
{ {
get => GetBoundingRectangle(); get => GetBoundingRectangle();
@@ -79,7 +85,7 @@ namespace UVtools.Core
} }
} }
public float LayerHeight => Layers[0].PositionZ; //public float LayerHeight => Layers[0].PositionZ;
#endregion #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 #endregion
} }
} }
+1 -1
View File
@@ -30,7 +30,7 @@ namespace UVtools.Core.Objects
public string TagString public string TagString
{ {
get => Tag.ToString(); get => Tag?.ToString();
set => Tag = value; set => Tag = value;
} }
+148 -28
View File
@@ -8,7 +8,6 @@
using System; using System;
using System.Drawing; using System.Drawing;
using System.Reflection.Metadata.Ecma335;
using System.Xml.Serialization; using System.Xml.Serialization;
using Emgu.CV; using Emgu.CV;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
@@ -19,13 +18,31 @@ namespace UVtools.Core.Operations
[Serializable] [Serializable]
public abstract class Operation : BindableBase, IDisposable public abstract class Operation : BindableBase, IDisposable
{ {
#region Members
private Rectangle _roi = Rectangle.Empty; private Rectangle _roi = Rectangle.Empty;
private uint _layerIndexEnd; private uint _layerIndexEnd;
private uint _layerIndexStart; private uint _layerIndexStart;
private string _profileName; private string _profileName;
private bool _profileIsDefault; private bool _profileIsDefault;
private Enumerations.LayerRangeSelection _layerRangeSelection = Enumerations.LayerRangeSelection.All; private Enumerations.LayerRangeSelection _layerRangeSelection = Enumerations.LayerRangeSelection.All;
private FileFormat _slicerFile;
public const byte ClassNameLength = 9; 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> /// <summary>
/// Gets the ID name of this operation, this comes from class name with "Operation" removed /// 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); set => RaiseAndSetIfChanged(ref _layerRangeSelection, value);
} }
public virtual string LayerRangeString
{
get
{
if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
{
return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
}
return $" [Layers: {LayerRangeSelection}]";
}
}
/// <summary> /// <summary>
/// Gets if this operation should set layer range to the actual layer index on layer preview /// Gets if this operation should set layer range to the actual layer index on layer preview
/// </summary> /// </summary>
@@ -95,18 +125,6 @@ namespace UVtools.Core.Operations
public bool HaveAction => !string.IsNullOrEmpty(ProgressAction); 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> /// <summary>
/// Gets the start layer index where operation will starts in /// Gets the start layer index where operation will starts in
/// </summary> /// </summary>
@@ -153,6 +171,105 @@ namespace UVtools.Core.Operations
} }
public bool HaveROI => !ROI.IsEmpty; 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) public Mat GetRoiOrDefault(Mat defaultMat)
{ {
@@ -161,7 +278,9 @@ namespace UVtools.Core.Operations
public virtual Operation Clone() public virtual Operation Clone()
{ {
return MemberwiseClone() as Operation; var operation = MemberwiseClone() as Operation;
operation.SlicerFile = _slicerFile;
return operation;
} }
public override string ToString() public override string ToString()
@@ -171,30 +290,31 @@ namespace UVtools.Core.Operations
var result = $"{Title}: {LayerRangeString}"; var result = $"{Title}: {LayerRangeString}";
return result; return result;
} }
public virtual string LayerRangeString protected virtual bool ExecuteInternally(OperationProgress progress)
{
get
{
if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
{
return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
}
return $" [Layers: {LayerRangeSelection}]";
}
}
public virtual bool Execute(FileFormat slicerFile, OperationProgress progress = null)
{ {
throw new NotImplementedException(); 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) public virtual bool Execute(Mat mat, params object[] arguments)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual void Dispose() { } 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; public bool IsValid => SetLayers.Count > 0 & Operations.Count > 0;
#endregion #endregion
#region Constructor
public OperationArithmetic() { }
public OperationArithmetic(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods #region Methods
public bool Parse() public bool Parse()
@@ -205,17 +213,16 @@ namespace UVtools.Core.Operations
return true; return true;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
if (!IsValid) return false; 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); Mat resultRoi = GetRoiOrDefault(result);
for (int i = 1; i < Operations.Count; i++) 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); Mat imageRoi = GetRoiOrDefault(image);
switch (Operations[i - 1].Operator) switch (Operations[i - 1].Operator)
{ {
@@ -245,18 +252,19 @@ namespace UVtools.Core.Operations
Parallel.ForEach(SetLayers, layerIndex => Parallel.ForEach(SetLayers, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
if (Operations.Count == 1 && HaveROI) if (Operations.Count == 1 && HaveROI)
{ {
var mat = slicerFile[layerIndex].LayerMat; var mat = SlicerFile[layerIndex].LayerMat;
var matRoi = GetRoiOrDefault(mat); var matRoi = GetRoiOrDefault(mat);
resultRoi.CopyTo(matRoi); resultRoi.CopyTo(matRoi);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
return; return;
} }
slicerFile[layerIndex].LayerMat = result; SlicerFile[layerIndex].LayerMat = result;
}); });
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
+13 -8
View File
@@ -124,28 +124,33 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Constructor
public OperationBlur() { }
public OperationBlur(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
} }
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+19 -1
View File
@@ -8,6 +8,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects; using UVtools.Core.Objects;
namespace UVtools.Core.Operations namespace UVtools.Core.Operations
@@ -15,6 +16,7 @@ namespace UVtools.Core.Operations
[Serializable] [Serializable]
public class OperationCalculator : Operation public class OperationCalculator : Operation
{ {
#region Overrides
public override string Title => "Calculator"; public override string Title => "Calculator";
public override string Description => null; public override string Description => null;
@@ -28,15 +30,31 @@ namespace UVtools.Core.Operations
public override bool CanROI => false; public override bool CanROI => false;
public override bool CanHaveProfiles => false; public override bool CanHaveProfiles => false;
#endregion
#region Properties
public MillimetersToPixels CalcMillimetersToPixels { get; set; } public MillimetersToPixels CalcMillimetersToPixels { get; set; }
public LightOffDelayC CalcLightOffDelay { get; set; } public LightOffDelayC CalcLightOffDelay { get; set; }
public OptimalModelTilt CalcOptimalModelTilt { 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 class Calculation : BindableBase
{ {
public abstract string Description { get; } public abstract string Description { get; }
@@ -26,7 +26,6 @@ namespace UVtools.Core.Operations
public sealed class OperationCalibrateElephantFoot : Operation public sealed class OperationCalibrateElephantFoot : Operation
{ {
#region Members #region Members
private Size _resolution = Size.Empty;
private decimal _layerHeight = 0.05M; private decimal _layerHeight = 0.05M;
private bool _syncLayers; private bool _syncLayers;
private ushort _bottomLayers = 10; private ushort _bottomLayers = 10;
@@ -112,14 +111,6 @@ namespace UVtools.Core.Operations
#region Properties #region Properties
[XmlIgnore]
public Size Resolution
{
get => _resolution;
set => RaiseAndSetIfChanged(ref _resolution, value);
}
public decimal LayerHeight public decimal LayerHeight
{ {
get => _layerHeight; get => _layerHeight;
@@ -347,6 +338,21 @@ namespace UVtools.Core.Operations
#endregion #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 #region Equality
private bool Equals(OperationCalibrateElephantFoot other) private bool Equals(OperationCalibrateElephantFoot other)
@@ -400,7 +406,7 @@ namespace UVtools.Core.Operations
var anchor = new Point(-1, -1); var anchor = new Point(-1, -1);
var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor); 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; LineType lineType = _enableAntiAliasing ? LineType.AntiAlias : LineType.EightConnected;
int length = (int) (250 * _partScale); int length = (int) (250 * _partScale);
int triangleLength = (int) (50 * _partScale); int triangleLength = (int) (50 * _partScale);
@@ -633,32 +639,25 @@ namespace UVtools.Core.Operations
return thumbnail; return thumbnail;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = 3;
progress.Reset(ProgressAction, 3);
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount]; var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers(); var layers = GetLayers();
progress++; progress++;
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager) var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
{ {
IsModified = true IsModified = true
}; };
var layer = new Layer(0, layers[1], slicerFile.LayerManager) var layer = new Layer(0, layers[1], SlicerFile.LayerManager)
{ {
IsModified = true 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[0]);
moveOp.Execute(layers[1]); moveOp.Execute(layers[1]);
@@ -671,7 +670,7 @@ namespace UVtools.Core.Operations
layerIndex < LayerCount; layerIndex < LayerCount;
layerIndex++) layerIndex++)
{ {
newLayers[layerIndex] = slicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone()); newLayers[layerIndex] = SlicerFile.GetInitialLayerValueOrNormal(layerIndex, bottomLayer.Clone(), layer.Clone());
} }
foreach (var mat in layers) foreach (var mat in layers)
@@ -680,16 +679,22 @@ namespace UVtools.Core.Operations
} }
if (slicerFile.ThumbnailsCount > 0) if (SlicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail()); SlicerFile.SetThumbnails(GetThumbnail());
progress++; progress++;
slicerFile.LayerManager.Layers = newLayers; SlicerFile.SuppressRebuildProperties = true;
slicerFile.SuppressRebuildProperties = false; SlicerFile.LayerHeight = (float)LayerHeight;
slicerFile.LayerManager.RebuildLayersProperties(); 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 #endregion
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,8 @@
*/ */
using UVtools.Core.FileFormats;
namespace UVtools.Core.Operations namespace UVtools.Core.Operations
{ {
public class OperationCalibrateExternalTests : Operation public class OperationCalibrateExternalTests : Operation
@@ -29,7 +31,15 @@ namespace UVtools.Core.Operations
public override string ProgressTitle => null; public override string ProgressTitle => null;
public override string ProgressAction => null; public override string ProgressAction => null;
#endregion
#region Constructor
public OperationCalibrateExternalTests() { }
public OperationCalibrateExternalTests(FileFormat slicerFile) : base(slicerFile) { }
#endregion #endregion
#region Properties #region Properties
@@ -37,7 +47,7 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Equality #region Equality
#endregion #endregion
#region Methods #region Methods
@@ -10,7 +10,6 @@ using System;
using System.Drawing; using System.Drawing;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV; using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using Emgu.CV.Structure; using Emgu.CV.Structure;
@@ -25,7 +24,6 @@ namespace UVtools.Core.Operations
public sealed class OperationCalibrateGrayscale : Operation public sealed class OperationCalibrateGrayscale : Operation
{ {
#region Members #region Members
private Size _resolution = Size.Empty;
private decimal _layerHeight = 0.05M; private decimal _layerHeight = 0.05M;
private ushort _bottomLayers = 10; private ushort _bottomLayers = 10;
private ushort _interfaceLayers = 5; private ushort _interfaceLayers = 5;
@@ -100,15 +98,21 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Properties #region Constructor
[XmlIgnore] public OperationCalibrateGrayscale() { }
public Size Resolution
public OperationCalibrateGrayscale(FileFormat slicerFile) : base(slicerFile)
{ {
get => _resolution; _layerHeight = (decimal)slicerFile.LayerHeight;
set => RaiseAndSetIfChanged(ref _resolution, value); _bottomLayers = slicerFile.BottomLayerCount;
_bottomExposure = (decimal)slicerFile.BottomExposureTime;
_normalExposure = (decimal)slicerFile.ExposureTime;
_mirrorOutput = slicerFile.MirrorDisplay;
} }
#endregion
#region Properties
public decimal LayerHeight public decimal LayerHeight
{ {
@@ -340,10 +344,10 @@ namespace UVtools.Core.Operations
{ {
Mat[] layers = new Mat[3]; 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 ; int radius = Math.Max(100, Math.Min(SlicerFile.Resolution.Width, SlicerFile.Resolution.Height) - _outerMargin * 2) / 2 ;
Point center = new Point(Resolution.Width / 2, Resolution.Height / 2); Point center = new Point(SlicerFile.Resolution.Width / 2, SlicerFile.Resolution.Height / 2);
int innerRadius = Math.Max(100, radius - _innerMargin); int innerRadius = Math.Max(100, radius - _innerMargin);
double topLineLength = 0; double topLineLength = 0;
@@ -452,32 +456,22 @@ namespace UVtools.Core.Operations
return thumbnail; return thumbnail;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = LayerCount;
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount]; var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers(); var layers = GetLayers();
progress++;
var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager)
{ {
IsModified = true 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 IsModified = true
} : null; } : null;
var layer = new Layer(0, layers[2], slicerFile.LayerManager) var layer = new Layer(0, layers[2], SlicerFile.LayerManager)
{ {
IsModified = true IsModified = true
}; };
@@ -511,17 +505,20 @@ namespace UVtools.Core.Operations
} }
if (slicerFile.ThumbnailsCount > 0) if (SlicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail()); 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; return !progress.Token.IsCancellationRequested;
slicerFile.SuppressRebuildProperties = false;
slicerFile.LayerManager.RebuildLayersProperties();
return true;
} }
#endregion #endregion
@@ -10,7 +10,6 @@ using System;
using System.Drawing; using System.Drawing;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV; using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using Emgu.CV.Structure; using Emgu.CV.Structure;
@@ -98,10 +97,31 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Properties #region Constructor
[XmlIgnore] public OperationCalibrateStressTower() { }
public Size Resolution { get; set; } = Size.Empty;
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 public decimal DisplayWidth
{ {
@@ -294,8 +314,8 @@ namespace UVtools.Core.Operations
{ {
var layers = new Mat[LayerCount]; var layers = new Mat[LayerCount];
Slicer slicer = new(Resolution, new SizeF((float) DisplayWidth, (float) DisplayHeight)); Slicer slicer = new(SlicerFile.Resolution, new SizeF((float) DisplayWidth, (float) DisplayHeight));
Point center = new Point(Resolution.Width / 2, Resolution.Height / 2); Point center = new Point(SlicerFile.Resolution.Width / 2, SlicerFile.Resolution.Height / 2);
uint baseRadius = slicer.PixelsFromMillimeters(_baseDiameter) / 2; uint baseRadius = slicer.PixelsFromMillimeters(_baseDiameter) / 2;
uint baseLayers = (ushort) Math.Floor(_baseHeight / _layerHeight); uint baseLayers = (ushort) Math.Floor(_baseHeight / _layerHeight);
uint bodyLayers = (ushort) Math.Floor(_bodyHeight / _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);*/ var kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3), anchor);*/
Parallel.For(0, LayerCount, layerIndex => Parallel.For(0, LayerCount, layerIndex =>
{ {
layers[layerIndex] = EmguExtensions.InitMat(Resolution); layers[layerIndex] = EmguExtensions.InitMat(SlicerFile.Resolution);
}); });
Parallel.For(0, baseLayers, layerIndex => Parallel.For(0, baseLayers, layerIndex =>
@@ -389,24 +409,16 @@ namespace UVtools.Core.Operations
return thumbnail; return thumbnail;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = LayerCount;
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount]; var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers(); var layers = GetLayers();
Parallel.For(0, LayerCount, layerIndex => 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(); layers[layerIndex].Dispose();
lock (progress) lock (progress)
{ {
@@ -414,22 +426,21 @@ 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) SlicerFile.SuppressRebuildProperties = true;
{ SlicerFile.LayerHeight = (float)LayerHeight;
IsCutMove = true, SlicerFile.BottomExposureTime = (float)BottomExposure;
LayerIndexEnd = slicerFile.LayerCount - 1 SlicerFile.ExposureTime = (float)NormalExposure;
}; SlicerFile.BottomLayerCount = BottomLayers;
moveOp.Execute(slicerFile, progress);*/ SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
if (slicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail());
slicerFile.SuppressRebuildProperties = false; return !progress.Token.IsCancellationRequested;
return true;
} }
#endregion #endregion
@@ -128,9 +128,6 @@ namespace UVtools.Core.Operations
#region Properties #region Properties
[XmlIgnore]
public Size Resolution { get; set; } = Size.Empty;
public decimal DisplayWidth public decimal DisplayWidth
{ {
get => _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 Xppmm => DisplayWidth > 0 ? Math.Round(SlicerFile.Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(Resolution.Height / DisplayHeight, 2) : 0; public decimal Yppmm => DisplayHeight > 0 ? Math.Round(SlicerFile.Resolution.Height / DisplayHeight, 2) : 0;
public decimal LayerHeight public decimal LayerHeight
{ {
@@ -425,8 +422,32 @@ namespace UVtools.Core.Operations
*/ */
#endregion #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 #region Enums
public enum Shapes : byte public enum Shapes : byte
{ {
Circle, Circle,
@@ -483,7 +504,7 @@ namespace UVtools.Core.Operations
public Mat[] GetLayers() public Mat[] GetLayers()
{ {
var layers = new Mat[LayerCount]; var layers = new Mat[LayerCount];
var layer = EmguExtensions.InitMat(Resolution); var layer = EmguExtensions.InitMat(SlicerFile.Resolution);
ushort startX = Math.Max((ushort)2, _leftRightMargin); ushort startX = Math.Max((ushort)2, _leftRightMargin);
ushort startY = Math.Max((ushort)2, _topBottomMargin); ushort startY = Math.Max((ushort)2, _topBottomMargin);
@@ -534,13 +555,13 @@ namespace UVtools.Core.Operations
if (_fuseParts) if (_fuseParts)
{ {
if (xPixels >= FemaleHoleDiameterXPixels || yPixels >= FemaleHoleDiameterYPixels) return false; if (xPixels >= FemaleHoleDiameterXPixels || yPixels >= FemaleHoleDiameterYPixels) return false;
if (currentX + FemaleDiameterXPixels + _leftRightMargin >= Resolution.Width) if (currentX + FemaleDiameterXPixels + _leftRightMargin >= SlicerFile.Resolution.Width)
{ {
currentX = startX; currentX = startX;
currentY += (int)FemaleDiameterYPixels + PartMargin; currentY += (int)FemaleDiameterYPixels + PartMargin;
} }
if (currentY + FemaleDiameterYPixels + _topBottomMargin >= Resolution.Height) if (currentY + FemaleDiameterYPixels + _topBottomMargin >= SlicerFile.Resolution.Height)
{ {
return false; // Insufficient size return false; // Insufficient size
} }
@@ -571,13 +592,13 @@ namespace UVtools.Core.Operations
} }
else else
{ {
if (currentX + xPixels + _leftRightMargin >= Resolution.Width) if (currentX + xPixels + _leftRightMargin >= SlicerFile.Resolution.Width)
{ {
currentX = startX; currentX = startX;
currentY += yPixels + PartMargin; currentY += yPixels + PartMargin;
} }
if (currentY + yPixels + _topBottomMargin >= Resolution.Height) if (currentY + yPixels + _topBottomMargin >= SlicerFile.Resolution.Height)
{ {
return false; // Insufficient size return false; // Insufficient size
} }
@@ -704,24 +725,17 @@ namespace UVtools.Core.Operations
return thumbnail; return thumbnail;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = LayerCount;
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount]; var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers(); var layers = GetLayers();
Parallel.For(0, LayerCount, layerIndex => 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(); layers[layerIndex].Dispose();
lock (progress) lock (progress)
{ {
@@ -729,22 +743,23 @@ namespace UVtools.Core.Operations
} }
}); });
slicerFile.LayerManager.Layers = newLayers; if (SlicerFile.ThumbnailsCount > 0)
slicerFile.LayerManager.RebuildLayersProperties(); SlicerFile.SetThumbnails(GetThumbnail());
var moveOp = new OperationMove(slicerFile.LayerManager.BoundingRectangle, slicerFile.Resolution) SlicerFile.SuppressRebuildProperties = true;
{ SlicerFile.LayerHeight = (float)LayerHeight;
IsCutMove = true, SlicerFile.BottomExposureTime = (float)BottomExposure;
LayerIndexEnd = slicerFile.LayerCount - 1 SlicerFile.ExposureTime = (float)NormalExposure;
}; SlicerFile.BottomLayerCount = BottomLayers;
moveOp.Execute(slicerFile, progress); SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
if (slicerFile.ThumbnailsCount > 0) var moveOp = new OperationMove(SlicerFile);
slicerFile.SetThumbnails(GetThumbnail()); moveOp.Execute(progress);
slicerFile.SuppressRebuildProperties = false;
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
@@ -118,9 +118,6 @@ namespace UVtools.Core.Operations
#region Properties #region Properties
[XmlIgnore]
public Size Resolution { get; set; } = Size.Empty;
public decimal DisplayWidth public decimal DisplayWidth
{ {
get => _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 Xppmm => DisplayWidth > 0 ? Math.Round(SlicerFile.Resolution.Width / DisplayWidth, 2) : 0;
public decimal Yppmm => DisplayHeight > 0 ? Math.Round(Resolution.Height / DisplayHeight, 2) : 0; public decimal Yppmm => DisplayHeight > 0 ? Math.Round(SlicerFile.Resolution.Height / DisplayHeight, 2) : 0;
public decimal LayerHeight public decimal LayerHeight
{ {
@@ -447,6 +444,30 @@ namespace UVtools.Core.Operations
#endregion #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 #region Enums
#endregion #endregion
@@ -465,7 +486,7 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Equality #region Equality
private bool Equals(OperationCalibrateXYZAccuracy other) private bool Equals(OperationCalibrateXYZAccuracy other)
{ {
return _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _xSize == other._xSize && _ySize == other._ySize && _zSize == other._zSize && _centerHoleRelief == other._centerHoleRelief && _hollowModel == other._hollowModel && _wallThickness == other._wallThickness && _observedXSize == other._observedXSize && _observedYSize == other._observedYSize && _observedZSize == other._observedZSize && _outputTLObject == other._outputTLObject && _outputTCObject == other._outputTCObject && _outputTRObject == other._outputTRObject && _outputMLObject == other._outputMLObject && _outputMCObject == other._outputMCObject && _outputMRObject == other._outputMRObject && _outputBLObject == other._outputBLObject && _outputBCObject == other._outputBCObject && _outputBRObject == other._outputBRObject && _mirrorOutput == other._mirrorOutput; return _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _xSize == other._xSize && _ySize == other._ySize && _zSize == other._zSize && _centerHoleRelief == other._centerHoleRelief && _hollowModel == other._hollowModel && _wallThickness == other._wallThickness && _observedXSize == other._observedXSize && _observedYSize == other._observedYSize && _observedZSize == other._observedZSize && _outputTLObject == other._outputTLObject && _outputTCObject == other._outputTCObject && _outputTRObject == other._outputTRObject && _outputMLObject == other._outputMLObject && _outputMCObject == other._outputMCObject && _outputMRObject == other._outputMRObject && _outputBLObject == other._outputBLObject && _outputBCObject == other._outputBCObject && _outputBRObject == other._outputBRObject && _mirrorOutput == other._mirrorOutput;
@@ -586,7 +607,7 @@ namespace UVtools.Core.Operations
var layers = new Mat[2]; var layers = new Mat[2];
for (byte i = 0; i < layers.Length; i++) 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"; positionYStr = "T";
break; break;
case 1: case 1:
currentY = (int)(Resolution.Height / 2 - YPixels / 2); currentY = (int)(SlicerFile.Resolution.Height / 2 - YPixels / 2);
positionYStr = "M"; positionYStr = "M";
break; break;
case 2: case 2:
currentY = (int)(Resolution.Height - YPixels - _topBottomMargin); currentY = (int)(SlicerFile.Resolution.Height - YPixels - _topBottomMargin);
positionYStr = "B"; positionYStr = "B";
break; break;
} }
@@ -627,11 +648,11 @@ namespace UVtools.Core.Operations
positionStr = $"{positionYStr}L"; positionStr = $"{positionYStr}L";
break; break;
case 1: case 1:
currentX = (int)(Resolution.Width / 2 - XPixels / 2); currentX = (int)(SlicerFile.Resolution.Width / 2 - XPixels / 2);
positionStr = $"{positionYStr}C"; positionStr = $"{positionYStr}C";
break; break;
case 2: case 2:
currentX = (int)(Resolution.Width - XPixels - _leftRightMargin); currentX = (int)(SlicerFile.Resolution.Width - XPixels - _leftRightMargin);
positionStr = $"{positionYStr}R"; positionStr = $"{positionYStr}R";
break; break;
} }
@@ -716,34 +737,27 @@ namespace UVtools.Core.Operations
return thumbnail; return thumbnail;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = LayerCount;
progress.Reset(ProgressAction, LayerCount);
slicerFile.SuppressRebuildProperties = true;
var newLayers = new Layer[LayerCount]; var newLayers = new Layer[LayerCount];
slicerFile.LayerHeight = (float)LayerHeight;
slicerFile.BottomExposureTime = (float)BottomExposure;
slicerFile.ExposureTime = (float)NormalExposure;
slicerFile.BottomLayerCount = BottomLayers;
var layers = GetLayers(); var layers = GetLayers();
var bottomLayer = new Layer(0, layers[0], slicerFile.LayerManager) var bottomLayer = new Layer(0, layers[0], SlicerFile.LayerManager)
{ {
IsModified = true IsModified = true
}; };
var layer = new Layer(0, layers[1], slicerFile.LayerManager) var layer = new Layer(0, layers[1], SlicerFile.LayerManager)
{ {
IsModified = true IsModified = true
}; };
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++) 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++; progress++;
} }
@@ -752,13 +766,19 @@ namespace UVtools.Core.Operations
mat.Dispose(); mat.Dispose();
} }
if (slicerFile.ThumbnailsCount > 0) if (SlicerFile.ThumbnailsCount > 0)
slicerFile.SetThumbnails(GetThumbnail()); SlicerFile.SetThumbnails(GetThumbnail());
slicerFile.LayerManager.Layers = newLayers; SlicerFile.SuppressRebuildProperties = true;
slicerFile.LayerManager.RebuildLayersProperties(); SlicerFile.LayerHeight = (float)LayerHeight;
slicerFile.SuppressRebuildProperties = false; SlicerFile.BottomExposureTime = (float)BottomExposure;
return true; SlicerFile.ExposureTime = (float)NormalExposure;
SlicerFile.BottomLayerCount = BottomLayers;
SlicerFile.LayerManager.Layers = newLayers;
SlicerFile.LayerManager.RebuildLayersProperties();
SlicerFile.SuppressRebuildProperties = false;
return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
@@ -64,25 +64,25 @@ namespace UVtools.Core.Operations
public override string ConfirmationText => public override string ConfirmationText =>
"change print resolution " + "change print resolution " +
$"from {OldResolution.Width}x{OldResolution.Height} " + $"from {SlicerFile.ResolutionX}x{SlicerFile.ResolutionY} " +
$"to {NewResolutionX}x{NewResolutionY}?"; $"to {NewResolutionX}x{NewResolutionY}?";
public override string ProgressTitle => 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 string ProgressAction => "Changed layers";
public override StringTag Validate(params object[] parameters) public override StringTag Validate(params object[] parameters)
{ {
var sb = new StringBuilder(); 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."); 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 #endregion
#region Properties #region Properties
public Size OldResolution { get; }
public uint NewResolutionX public uint NewResolutionX
{ {
get => _newResolutionX; get => _newResolutionX;
@@ -113,25 +111,20 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _newResolutionY, value); set => RaiseAndSetIfChanged(ref _newResolutionY, value);
} }
public Rectangle VolumeBonds { get; } public Size VolumeBondsSize => SlicerFile.BoundingRectangle.Size;
public Size VolumeBondsSize => VolumeBonds.Size;
#endregion #endregion
#region Constructor #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 #endregion
#region Methods #region Methods
@@ -159,25 +152,24 @@ namespace UVtools.Core.Operations
public static Resolution[] Presets => GetResolutions(); public static Resolution[] Presets => GetResolutions();
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = SlicerFile.LayerCount;
progress.Reset(ProgressAction, slicerFile.LayerCount);
Parallel.For(0, slicerFile.LayerCount, layerIndex => Parallel.For(0, SlicerFile.LayerCount, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
using var matRoi = new Mat(mat, VolumeBonds); 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 matDst = new Mat(new Size((int)NewResolutionX, (int)NewResolutionY), mat.Depth, mat.NumberOfChannels);
using var matDstRoi = new Mat(matDst, using var matDstRoi = new Mat(matDst,
new Rectangle((int)(NewResolutionX / 2 - VolumeBonds.Width / 2), new Rectangle((int)(NewResolutionX / 2 - SlicerFile.BoundingRectangle.Width / 2),
(int)NewResolutionY / 2 - VolumeBonds.Height / 2, (int)NewResolutionY / 2 - SlicerFile.BoundingRectangle.Height / 2,
VolumeBonds.Width, VolumeBonds.Height)); SlicerFile.BoundingRectangle.Width, SlicerFile.BoundingRectangle.Height));
matRoi.CopyTo(matDstRoi); matRoi.CopyTo(matDstRoi);
//Execute(mat); //Execute(mat);
slicerFile[layerIndex].LayerMat = matDst; SlicerFile[layerIndex].LayerMat = matDst;
lock (progress.Mutex) lock (progress.Mutex)
{ {
@@ -187,10 +179,10 @@ namespace UVtools.Core.Operations
progress.Token.ThrowIfCancellationRequested(); progress.Token.ThrowIfCancellationRequested();
slicerFile.ResolutionX = NewResolutionX; SlicerFile.ResolutionX = NewResolutionX;
slicerFile.ResolutionY = NewResolutionY; SlicerFile.ResolutionY = NewResolutionY;
return true; return !progress.Token.IsCancellationRequested;
} }
/*public override bool Execute(Mat mat, params object[] arguments) /*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 #region Members
private bool _perLayerOverride; private bool _perLayerOverride;
private uint _setNumberOfLayer = 1;
private uint _skipNumberOfLayer = 0;
#endregion #endregion
#region Overrides #region Overrides
@@ -92,23 +95,73 @@ namespace UVtools.Core.Operations
get => _perLayerOverride; get => _perLayerOverride;
set => RaiseAndSetIfChanged(ref _perLayerOverride, value); 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 #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) #endregion
{
Modifiers = modifiers;
}
#region Methods #region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
slicerFile.EditPrintParameters(this); if (PerLayerOverride)
return true; {
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 #endregion
+13 -7
View File
@@ -87,6 +87,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationFlip() { }
public OperationFlip(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality #region Equality
protected bool Equals(OperationFlip other) protected bool Equals(OperationFlip other)
@@ -113,24 +121,22 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+27 -7
View File
@@ -97,24 +97,44 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Constructor
public OperationInfill() { }
public OperationInfill(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality #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 #endregion
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex); Execute(mat, layerIndex);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) 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) public override bool Execute(Mat mat, params object[] arguments)
+12 -6
View File
@@ -76,11 +76,19 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Constructor
public OperationLayerClone() { }
public OperationLayerClone(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods #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 totalClones = (LayerIndexEnd - LayerIndexStart + 1) * Clones;
uint newLayerCount = (uint) (oldLayers.Length + totalClones); uint newLayerCount = (uint) (oldLayers.Length + totalClones);
@@ -107,11 +115,9 @@ namespace UVtools.Core.Operations
newLayerIndex++; newLayerIndex++;
} }
slicerFile.LayerManager.Layers = layers; SlicerFile.LayerManager.Layers = layers;
progress.Token.ThrowIfCancellationRequested(); return !progress.Token.IsCancellationRequested;
return true;
} }
#endregion #endregion
+61 -65
View File
@@ -39,12 +39,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Members
private ImportTypes _importType = ImportTypes.Stack; private ImportTypes _importType = ImportTypes.Stack;
private uint _startLayerIndex; private uint _startLayerIndex;
private bool _extendBeyondLayerCount = true; private bool _extendBeyondLayerCount = true;
private bool _discardUnmodifiedLayers; private bool _discardUnmodifiedLayers;
private ushort _stackMargin = 50; private ushort _stackMargin = 50;
private ObservableCollection<StringTag> _files = new(); private ObservableCollection<StringTag> _files = new();
#endregion
#region Overrides #region Overrides
@@ -115,9 +117,6 @@ namespace UVtools.Core.Operations
#region Properties #region Properties
[XmlIgnore]
public Size FileResolution { get; }
public ImportTypes ImportType public ImportTypes ImportType
{ {
get => _importType; get => _importType;
@@ -172,14 +171,11 @@ namespace UVtools.Core.Operations
#region Constructor #region Constructor
public OperationLayerImport() public OperationLayerImport() { }
{
} public OperationLayerImport(FileFormat slicerFile) : base(slicerFile) { }
public OperationLayerImport(Size fileResolution)
{
FileResolution = fileResolution;
}
#endregion #endregion
#region Methods #region Methods
@@ -224,10 +220,10 @@ namespace UVtools.Core.Operations
return result; return result;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = 0;
slicerFile.SuppressRebuildProperties = true; SlicerFile.SuppressRebuildProperties = true;
List<FileFormat> fileFormats = new(); List<FileFormat> fileFormats = new();
List<KeyValuePair<uint, string>> keyImage = new(); List<KeyValuePair<uint, string>> keyImage = new();
@@ -289,7 +285,7 @@ namespace UVtools.Core.Operations
if (_importType == ImportTypes.Stack) 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) foreach (var fileFormat in fileFormats)
@@ -299,7 +295,7 @@ namespace UVtools.Core.Operations
fileFormat.Decode(fileFormat.FileFullPath, progress); fileFormat.Decode(fileFormat.FileFullPath, progress);
} }
var boundingRectangle = slicerFile.LayerManager.GetBoundingRectangle(progress); var boundingRectangle = SlicerFile.LayerManager.GetBoundingRectangle(progress);
var fileFormatBoundingRectangle = fileFormat.LayerManager.GetBoundingRectangle(progress); var fileFormatBoundingRectangle = fileFormat.LayerManager.GetBoundingRectangle(progress);
var roiRectangle = Rectangle.Empty; var roiRectangle = Rectangle.Empty;
@@ -307,26 +303,26 @@ namespace UVtools.Core.Operations
switch (_importType) switch (_importType)
{ {
case ImportTypes.Insert: case ImportTypes.Insert:
if (slicerFile.Resolution != fileFormat.Resolution && if (SlicerFile.Resolution != fileFormat.Resolution &&
(slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || (SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; SlicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
slicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount); SlicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount);
break; break;
case ImportTypes.Replace: case ImportTypes.Replace:
case ImportTypes.Stack: case ImportTypes.Stack:
if (slicerFile.Resolution != fileFormat.Resolution && if (SlicerFile.Resolution != fileFormat.Resolution &&
(slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width || (SlicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue; 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; continue;
int x = 0; int x = 0;
int y = 0; int y = 0;
if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width < if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width <
slicerFile.ResolutionX) SlicerFile.ResolutionX)
{ {
x = boundingRectangle.Right + _stackMargin; x = boundingRectangle.Right + _stackMargin;
} }
@@ -335,29 +331,29 @@ namespace UVtools.Core.Operations
y = boundingRectangle.Bottom + _stackMargin; y = boundingRectangle.Bottom + _stackMargin;
} }
if (y >= slicerFile.ResolutionY) if (y >= SlicerFile.ResolutionY)
continue; continue;
roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height); roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height);
if (_extendBeyondLayerCount) if (_extendBeyondLayerCount)
{ {
int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount); int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - SlicerFile.LayerCount);
if (layerCountDifference > 0) if (layerCountDifference > 0)
{ {
slicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack); SlicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack);
} }
} }
break; break;
case ImportTypes.Merge: case ImportTypes.Merge:
if (slicerFile.Resolution != fileFormat.Resolution) continue; if (SlicerFile.Resolution != fileFormat.Resolution) continue;
if (_extendBeyondLayerCount) if (_extendBeyondLayerCount)
{ {
int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount); int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - SlicerFile.LayerCount);
if (layerCountDifference > 0) if (layerCountDifference > 0)
{ {
slicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true); SlicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true);
} }
} }
break; break;
@@ -365,7 +361,7 @@ namespace UVtools.Core.Operations
case ImportTypes.BitwiseAnd: case ImportTypes.BitwiseAnd:
case ImportTypes.BitwiseOr: case ImportTypes.BitwiseOr:
case ImportTypes.BitwiseXOr: case ImportTypes.BitwiseXOr:
if (slicerFile.Resolution != fileFormat.Resolution) continue; if (SlicerFile.Resolution != fileFormat.Resolution) continue;
break; break;
} }
@@ -381,88 +377,88 @@ namespace UVtools.Core.Operations
{ {
case ImportTypes.Insert: case ImportTypes.Insert:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
if (slicerFile.Resolution == fileFormat.Resolution) if (SlicerFile.Resolution == fileFormat.Resolution)
{ {
slicerFile[layerIndex] = fileFormat[i]; SlicerFile[layerIndex] = fileFormat[i];
break; break;
} }
using var layer = fileFormat[i].LayerMat; using var layer = fileFormat[i].LayerMat;
using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution); using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution);
slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile); SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile);
break; break;
} }
case ImportTypes.Replace: case ImportTypes.Replace:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
if (slicerFile.Resolution == fileFormat.Resolution) if (SlicerFile.Resolution == fileFormat.Resolution)
{ {
slicerFile[layerIndex] = fileFormat[i]; SlicerFile[layerIndex] = fileFormat[i];
break; break;
} }
using var layer = fileFormat[i].LayerMat; using var layer = fileFormat[i].LayerMat;
using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution); using var layerRoi = layer.RoiFromCenter(SlicerFile.Resolution);
slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile); SlicerFile[layerIndex] = new Layer(layerIndex, layerRoi, SlicerFile);
break; break;
} }
case ImportTypes.Stack: case ImportTypes.Stack:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
using var importMat = fileFormat[i].LayerMat; using var importMat = fileFormat[i].LayerMat;
var matRoi = new Mat(mat, roiRectangle); var matRoi = new Mat(mat, roiRectangle);
var importMatRoi = new Mat(importMat, fileFormatBoundingRectangle); var importMatRoi = new Mat(importMat, fileFormatBoundingRectangle);
importMatRoi.CopyTo(matRoi); importMatRoi.CopyTo(matRoi);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
break; break;
} }
case ImportTypes.Merge: case ImportTypes.Merge:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat; using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat; using var newMat = fileFormat[i].LayerMat;
CvInvoke.Add(originalMat, newMat, newMat); CvInvoke.Add(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat; SlicerFile[layerIndex].LayerMat = newMat;
break; break;
} }
case ImportTypes.Subtract: case ImportTypes.Subtract:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat; using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat; using var newMat = fileFormat[i].LayerMat;
CvInvoke.Subtract(originalMat, newMat, newMat); CvInvoke.Subtract(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat; SlicerFile[layerIndex].LayerMat = newMat;
break; break;
} }
case ImportTypes.BitwiseAnd: case ImportTypes.BitwiseAnd:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat; using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat; using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseAnd(originalMat, newMat, newMat); CvInvoke.BitwiseAnd(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat; SlicerFile[layerIndex].LayerMat = newMat;
break; break;
} }
case ImportTypes.BitwiseOr: case ImportTypes.BitwiseOr:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat; using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat; using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseOr(originalMat, newMat, newMat); CvInvoke.BitwiseOr(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat; SlicerFile[layerIndex].LayerMat = newMat;
break; break;
} }
case ImportTypes.BitwiseXOr: case ImportTypes.BitwiseXOr:
{ {
if (layerIndex >= slicerFile.LayerCount) return; if (layerIndex >= SlicerFile.LayerCount) return;
using var originalMat = slicerFile[layerIndex].LayerMat; using var originalMat = SlicerFile[layerIndex].LayerMat;
using var newMat = fileFormat[i].LayerMat; using var newMat = fileFormat[i].LayerMat;
CvInvoke.BitwiseXor(originalMat, newMat, newMat); CvInvoke.BitwiseXor(originalMat, newMat, newMat);
slicerFile[layerIndex].LayerMat = newMat; SlicerFile[layerIndex].LayerMat = newMat;
break; break;
} }
default: default:
@@ -483,20 +479,20 @@ namespace UVtools.Core.Operations
if (_importType == ImportTypes.Stack) 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) 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.LayerManager.RebuildLayersProperties();
slicerFile.SuppressRebuildProperties = false; SlicerFile.SuppressRebuildProperties = false;
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
@@ -99,6 +99,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationLayerReHeight() { }
public OperationLayerReHeight(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Subclasses #region Subclasses
public class OperationLayerReHeightItem public class OperationLayerReHeightItem
{ {
@@ -124,12 +132,11 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Methods #region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); progress.ItemCount = Item.LayerCount;
progress.Reset(ProgressAction, Item.LayerCount);
var oldLayers = slicerFile.LayerManager.Layers; var oldLayers = SlicerFile.LayerManager.Layers;
var layers = new Layer[Item.LayerCount]; var layers = new Layer[Item.LayerCount];
@@ -171,10 +178,10 @@ namespace UVtools.Core.Operations
} }
} }
slicerFile.LayerManager.Layers = layers; SlicerFile.LayerManager.Layers = layers;
slicerFile.LayerHeight = (float)Item.LayerHeight; SlicerFile.LayerHeight = (float)Item.LayerHeight;
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
} }
@@ -45,20 +45,28 @@ namespace UVtools.Core.Operations
#region Properties #region Properties
#endregion
#region Constructor
public OperationLayerRemove() { }
public OperationLayerRemove(FileFormat slicerFile) : base(slicerFile) { }
#endregion #endregion
#region Methods #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>(); var layersRemove = new List<uint>();
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++) for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{ {
layersRemove.Add(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) 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); progress.Reset("removed layers", (uint)layersRemove.Count);
var oldLayers = slicerFile.LayerManager.Layers; var oldLayers = slicerFile.LayerManager.Layers;
float layerHeight = slicerFile.LayerHeight; var layerHeight = slicerFile.LayerHeight;
var layers = new Layer[oldLayers.Length - layersRemove.Count]; var layers = new Layer[oldLayers.Length - layersRemove.Count];
@@ -92,7 +100,7 @@ namespace UVtools.Core.Operations
} }
else 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); public bool HaveMask => !(Mask is null);
#endregion #endregion
#region Constructor
public OperationMask() { }
public OperationMask(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods #region Methods
public void InvertMask() public void InvertMask()
@@ -65,25 +73,21 @@ namespace UVtools.Core.Operations
CvInvoke.BitwiseNot(Mask, Mask); 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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested(); return !progress.Token.IsCancellationRequested;
return true;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+13 -8
View File
@@ -109,6 +109,14 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Constructor
public OperationMorph() { }
public OperationMorph(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality #region Equality
private bool Equals(OperationMorph other) private bool Equals(OperationMorph other)
@@ -137,11 +145,8 @@ namespace UVtools.Core.Operations
#region Methods #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; var isFade = Chamfer;
LayerManager.MutateGetVarsIterationChamfer( LayerManager.MutateGetVarsIterationChamfer(
LayerIndexStart, LayerIndexStart,
@@ -160,17 +165,17 @@ namespace UVtools.Core.Operations
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
int iterations = LayerManager.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex); 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); Execute(mat, iterations);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+37 -44
View File
@@ -170,6 +170,31 @@ namespace UVtools.Core.Operations
#endregion #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 #region Methods
public void CalculateDstRoi() public void CalculateDstRoi()
{ {
@@ -214,42 +239,15 @@ namespace UVtools.Core.Operations
_dstRoi.Y += MarginTop; _dstRoi.Y += MarginTop;
_dstRoi.Y -= MarginBottom; _dstRoi.Y -= MarginBottom;
IsWithinBoundary = !(DstRoi.IsEmpty || DstRoi.X < 0 || DstRoi.Y < 0 || IsWithinBoundary = !(_dstRoi.IsEmpty || _dstRoi.X < 0 || _dstRoi.Y < 0 ||
DstRoi.Width == 0 || DstRoi.Right > ImageWidth || _dstRoi.Width == 0 || _dstRoi.Right > ImageWidth ||
DstRoi.Height == 0 || DstRoi.Bottom > ImageHeight); _dstRoi.Height == 0 || _dstRoi.Bottom > ImageHeight);
RaisePropertyChanged(nameof(DstRoi)); RaisePropertyChanged(nameof(DstRoi));
RaisePropertyChanged(nameof(LocationXStr)); RaisePropertyChanged(nameof(LocationXStr));
RaisePropertyChanged(nameof(LocationYStr)); 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() public void Reset()
{ {
@@ -271,21 +269,19 @@ namespace UVtools.Core.Operations
return IsWithinBoundary; return IsWithinBoundary;
} }
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress(); if (ROI.IsEmpty) ROI = SlicerFile.LayerManager.GetBoundingRectangle(progress);
progress.Reset(ProgressAction, LayerRangeCount); CalculateDstRoi();
if (ROI == Rectangle.Empty) ROI = slicerFile.LayerManager.GetBoundingRectangle(progress);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
} }
lock (progress.Mutex) 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 !progress.Token.IsCancellationRequested;
return true;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
{ {
if (_imageWidth == 0) _imageWidth = (uint) mat.Width;
if (ImageWidth == 0) ImageWidth = (uint) mat.Width; if (_imageHeight == 0) _imageHeight = (uint) mat.Height;
if (ImageHeight == 0) ImageHeight = (uint) mat.Height;
using var srcRoi = new Mat(mat, ROI); using var srcRoi = new Mat(mat, ROI);
using var dstRoi = new Mat(mat, DstRoi); 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); public Size GetPatternVolume => new(Cols * ROI.Width + (Cols - 1) * ColSpacing, Rows * ROI.Height + (Rows - 1) * RowSpacing);
#endregion #endregion
public OperationPattern() #region Constructor
{
}
public OperationPattern(Rectangle srcRoi, Size resolution) public OperationPattern() { }
{
ImageWidth = (uint) resolution.Width;
ImageHeight = (uint) resolution.Height;
SetRoi(srcRoi); public OperationPattern(FileFormat slicerFile, Rectangle srcRoi = default) : base(slicerFile)
{
ImageWidth = slicerFile.ResolutionX;
ImageHeight = slicerFile.ResolutionY;
SetRoi(srcRoi.IsEmpty ? slicerFile.BoundingRectangle : srcRoi);
Fill(); Fill();
} }
#endregion
#region Methods #region Methods
public void SetAnchor(byte value) public void SetAnchor(byte value)
{ {
@@ -272,16 +274,13 @@ namespace UVtools.Core.Operations
return result; 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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; 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 layerRoi = new Mat(mat, ROI);
using var dstLayer = mat.CloneBlank(); using var dstLayer = mat.CloneBlank();
for (ushort col = 0; col < Cols; col++) for (ushort col = 0; col < Cols; col++)
@@ -292,7 +291,7 @@ namespace UVtools.Core.Operations
layerRoi.CopyTo(dstRoi); layerRoi.CopyTo(dstRoi);
} }
//Execute(mat); //Execute(mat);
slicerFile[layerIndex].LayerMat = dstLayer; SlicerFile[layerIndex].LayerMat = dstLayer;
lock (progress.Mutex) lock (progress.Mutex)
{ {
@@ -300,19 +299,19 @@ namespace UVtools.Core.Operations
} }
}); });
slicerFile.LayerManager.BoundingRectangle = Rectangle.Empty; SlicerFile.LayerManager.BoundingRectangle = Rectangle.Empty;
progress.Token.ThrowIfCancellationRequested(); progress.Token.ThrowIfCancellationRequested();
if (Anchor == Enumerations.Anchor.None) return true; 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, LayerIndexStart = LayerIndexStart,
LayerIndexEnd = LayerIndexEnd LayerIndexEnd = LayerIndexEnd
}; };
operationMove.Execute(slicerFile, progress); operationMove.Execute(progress);
return true; return !progress.Token.IsCancellationRequested;
} }
/*public override bool Execute(Mat mat, params object[] arguments) /*public override bool Execute(Mat mat, params object[] arguments)
@@ -138,6 +138,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationPixelDimming() { }
public OperationPixelDimming(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
public uint WallThicknessStart 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) if (Pattern is null)
{ {
Pattern = new Matrix<byte>(2, 2) Pattern = new Matrix<byte>(2, 2)
@@ -560,7 +565,7 @@ namespace UVtools.Core.Operations
AlternatePattern ??= Pattern; AlternatePattern ??= Pattern;
using var blankMat = EmguExtensions.InitMat(slicerFile.Resolution); using var blankMat = EmguExtensions.InitMat(SlicerFile.Resolution);
using var matPattern = blankMat.CloneBlank(); using var matPattern = blankMat.CloneBlank();
using var matAlternatePattern = blankMat.CloneBlank(); using var matAlternatePattern = blankMat.CloneBlank();
var target = GetRoiOrDefault(blankMat); var target = GetRoiOrDefault(blankMat);
@@ -573,9 +578,9 @@ namespace UVtools.Core.Operations
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, layerIndex, patternMask, alternatePatternMask); Execute(mat, layerIndex, patternMask, alternatePatternMask);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
@@ -583,8 +588,7 @@ namespace UVtools.Core.Operations
} }
}); });
progress.Token.ThrowIfCancellationRequested(); return !progress.Token.IsCancellationRequested;
return true;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+14 -8
View File
@@ -58,7 +58,7 @@ namespace UVtools.Core.Operations
_canCancel = canCancel; _canCancel = canCancel;
} }
public Stopwatch StopWatch { get; } = new Stopwatch(); public Stopwatch StopWatch { get; } = new ();
/// <summary> /// <summary>
/// Gets or sets if operation can be cancelled /// Gets or sets if operation can be cancelled
@@ -82,7 +82,8 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _title, value); 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> /// <summary>
/// Gets or sets the item name for the operation /// 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> /// <summary>
/// Gets the remaining items to be processed /// Gets the remaining items to be processed
/// </summary> /// </summary>
public uint RemainingItems => ItemCount - ProcessedItems; public uint RemainingItems => _itemCount - _processedItems;
public int ProgressStep => (int)ProgressPercent; public int ProgressStep => (int)ProgressPercent;
public string Description => ToString(); public string Description => ToString();
public bool IsIndeterminate => ItemCount == 0; public bool IsIndeterminate => _itemCount == 0;
/// <summary> /// <summary>
/// Gets the progress from 0 to 100% /// Gets the progress from 0 to 100%
/// </summary> /// </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) public static OperationProgress operator +(OperationProgress progress, uint value)
{ {
@@ -167,9 +173,9 @@ namespace UVtools.Core.Operations
public override string ToString() public override string ToString()
{ {
return ItemCount == 0 ? return _itemCount == 0 ?
$"{ProcessedItems}/? {ItemName}" : $"{_processedItems}/? {_itemName}" :
$"{ProcessedItems}/{ItemCount} {ItemName} | {ProgressPercent:0.00}%"; $"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_itemCount} {_itemName} | {ProgressPercent:0.00}%";
} }
public void TriggerRefresh() public void TriggerRefresh()
+19 -11
View File
@@ -63,6 +63,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationRaftRelief() { }
public OperationRaftRelief(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
public static Array RaftReliefItems => Enum.GetValues(typeof(RaftReliefTypes)); public static Array RaftReliefItems => Enum.GetValues(typeof(RaftReliefTypes));
@@ -149,11 +157,10 @@ namespace UVtools.Core.Operations
#region Methods #region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress.ItemCount = 0;
const uint minLength = 5; const uint minLength = 5;
progress ??= new OperationProgress();
//progress.Reset(operation.ProgressAction);
Mat supportsMat = null; Mat supportsMat = null;
var anchor = new Point(-1, -1); var anchor = new Point(-1, -1);
@@ -161,11 +168,11 @@ namespace UVtools.Core.Operations
uint firstSupportLayerIndex = 0; 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; 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); var circles = CvInvoke.HoughCircles(supportsMat, HoughModes.Gradient, 1, 20, 100, 30, 5, 200);
if (circles.Length >= minLength) break; if (circles.Length >= minLength) break;
@@ -187,7 +194,7 @@ namespace UVtools.Core.Operations
switch (ReliefType) switch (ReliefType)
{ {
case OperationRaftRelief.RaftReliefTypes.Relief: case RaftReliefTypes.Relief:
patternMat = EmguExtensions.InitMat(supportsMat.Size); patternMat = EmguExtensions.InitMat(supportsMat.Size);
int shapeSize = HoleDiameter + HoleSpacing; int shapeSize = HoleDiameter + HoleSpacing;
using (var shape = EmguExtensions.InitMat(new Size(shapeSize, shapeSize))) using (var shape = EmguExtensions.InitMat(new Size(shapeSize, shapeSize)))
@@ -208,7 +215,7 @@ namespace UVtools.Core.Operations
} }
break; break;
case OperationRaftRelief.RaftReliefTypes.Dimming: case RaftReliefTypes.Dimming:
patternMat = EmguExtensions.InitMat(supportsMat.Size, color); patternMat = EmguExtensions.InitMat(supportsMat.Size, color);
break; break;
} }
@@ -216,7 +223,8 @@ namespace UVtools.Core.Operations
progress.Reset(ProgressAction, firstSupportLayerIndex); progress.Reset(ProgressAction, firstSupportLayerIndex);
Parallel.For(IgnoreFirstLayers, firstSupportLayerIndex, layerIndex => 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); var target = GetRoiOrDefault(dst);
@@ -242,7 +250,7 @@ namespace UVtools.Core.Operations
} }
slicerFile[layerIndex].LayerMat = dst; SlicerFile[layerIndex].LayerMat = dst;
} }
lock (progress.Mutex) lock (progress.Mutex)
@@ -255,7 +263,7 @@ namespace UVtools.Core.Operations
supportsMat.Dispose(); supportsMat.Dispose();
patternMat?.Dispose(); patternMat?.Dispose();
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
@@ -81,6 +81,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationRedrawModel() { }
public OperationRedrawModel(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
[XmlIgnore] [XmlIgnore]
@@ -151,21 +159,20 @@ namespace UVtools.Core.Operations
public FileFormat IsFileValid(bool returnNewInstance = false) => public FileFormat IsFileValid(bool returnNewInstance = false) =>
FileFormat.FindByExtension(_filePath, true, returnNewInstance); 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); var otherFile = IsFileValid(true);
otherFile.Decode(_filePath, progress); otherFile.Decode(_filePath, progress);
progress.Reset(ProgressAction, otherFile.LayerCount); progress.Reset(ProgressAction, otherFile.LayerCount);
int startLayerIndex = (int)(slicerFile.LayerCount - otherFile.LayerCount); int startLayerIndex = (int)(SlicerFile.LayerCount - otherFile.LayerCount);
if (startLayerIndex < 0) return false; if (startLayerIndex < 0) return false;
Parallel.For(0, otherFile.LayerCount, layerIndex => Parallel.For(0, otherFile.LayerCount, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return;
var fullMatLayerIndex = startLayerIndex + layerIndex; var fullMatLayerIndex = startLayerIndex + layerIndex;
using var fullMat = slicerFile[fullMatLayerIndex].LayerMat; using var fullMat = SlicerFile[fullMatLayerIndex].LayerMat;
using var bodyMat = otherFile[layerIndex].LayerMat; using var bodyMat = otherFile[layerIndex].LayerMat;
using var fullMatRoi = GetRoiOrDefault(fullMat); using var fullMatRoi = GetRoiOrDefault(fullMat);
using var bodyMatRoi = GetRoiOrDefault(bodyMat); using var bodyMatRoi = GetRoiOrDefault(bodyMat);
@@ -232,7 +239,7 @@ namespace UVtools.Core.Operations
if (modified) if (modified)
{ {
slicerFile[fullMatLayerIndex].LayerMat = fullMat; SlicerFile[fullMatLayerIndex].LayerMat = fullMat;
} }
lock (progress.Mutex) lock (progress.Mutex)
@@ -241,7 +248,7 @@ namespace UVtools.Core.Operations
} }
}); });
return true; return !progress.Token.IsCancellationRequested;
} }
#endregion #endregion
@@ -16,7 +16,6 @@ using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Emgu.CV; using Emgu.CV;
using Emgu.CV.CvEnum; using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util; using Emgu.CV.Util;
using UVtools.Core.Extensions; using UVtools.Core.Extensions;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
@@ -64,6 +63,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationRepairLayers() { }
public OperationRepairLayers(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
public bool RepairIslands public bool RepairIslands
{ {
@@ -116,10 +123,8 @@ namespace UVtools.Core.Operations
#region Methods #region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
progress ??= new OperationProgress();
// Remove islands // Remove islands
if (!ReferenceEquals(Issues, null) if (!ReferenceEquals(Issues, null)
&& !ReferenceEquals(IslandDetectionConfig, null) && !ReferenceEquals(IslandDetectionConfig, null)
@@ -127,7 +132,7 @@ namespace UVtools.Core.Operations
&& RemoveIslandsBelowEqualPixelCount > 0 && RemoveIslandsBelowEqualPixelCount > 0
&& RemoveIslandsRecursiveIterations != 1) && RemoveIslandsRecursiveIterations != 1)
{ {
progress.Reset("Removed recursive islands", 0); progress.Reset("Removed recursive islands");
ushort limit = RemoveIslandsRecursiveIterations == 0 ushort limit = RemoveIslandsRecursiveIterations == 0
? ushort.MaxValue ? ushort.MaxValue
: RemoveIslandsRecursiveIterations; : RemoveIslandsRecursiveIterations;
@@ -152,7 +157,7 @@ namespace UVtools.Core.Operations
.Select(grp => grp.First()) .Select(grp => grp.First())
.ToList();*/ .ToList();*/
islandConfig.WhiteListLayers = islandsToRecompute.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); //Debug.WriteLine(i);
} }
@@ -167,7 +172,7 @@ namespace UVtools.Core.Operations
Parallel.ForEach(issuesGroup, group => Parallel.ForEach(issuesGroup, group =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
Layer layer = slicerFile[group.Key]; Layer layer = SlicerFile[group.Key];
Mat image = layer.LayerMat; Mat image = layer.LayerMat;
Span<byte> bytes = image.GetPixelSpan<byte>(); Span<byte> bytes = image.GetPixelSpan<byte>();
foreach (var issue in group) foreach (var issue in group)
@@ -184,7 +189,7 @@ namespace UVtools.Core.Operations
} }
var nextLayerIndex = group.Key + 1; var nextLayerIndex = group.Key + 1;
if (nextLayerIndex < slicerFile.LayerCount) if (nextLayerIndex < SlicerFile.LayerCount)
islandsToRecompute.Add(nextLayerIndex); islandsToRecompute.Add(nextLayerIndex);
layer.LayerMat = image; layer.LayerMat = image;
@@ -200,7 +205,7 @@ namespace UVtools.Core.Operations
Parallel.For(LayerIndexStart, LayerIndexEnd, layerIndex => Parallel.For(LayerIndexStart, LayerIndexEnd, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
Layer layer = slicerFile[layerIndex]; Layer layer = SlicerFile[layerIndex];
Mat image = null; Mat image = null;
void initImage() void initImage()
@@ -294,7 +299,7 @@ namespace UVtools.Core.Operations
List<uint> removeLayers = new List<uint>(); List<uint> removeLayers = new List<uint>();
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++) for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{ {
if (slicerFile[layerIndex].NonZeroPixelCount == 0) if (SlicerFile[layerIndex].NonZeroPixelCount == 0)
{ {
removeLayers.Add(layerIndex); removeLayers.Add(layerIndex);
} }
@@ -302,13 +307,11 @@ namespace UVtools.Core.Operations
if (removeLayers.Count > 0) if (removeLayers.Count > 0)
{ {
OperationLayerRemove.RemoveLayers(slicerFile, removeLayers, progress); OperationLayerRemove.RemoveLayers(SlicerFile, removeLayers, progress);
} }
} }
progress.Token.ThrowIfCancellationRequested(); return !progress.Token.IsCancellationRequested;
return true;
} }
#endregion #endregion
+12 -10
View File
@@ -103,9 +103,13 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
public OperationResize() #region Constructor
{
} public OperationResize() { }
public OperationResize(FileFormat slicerFile) : base(slicerFile) { }
#endregion
public override string ToString() public override string ToString()
{ {
@@ -145,11 +149,9 @@ namespace UVtools.Core.Operations
#region Methods #region Methods
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null) protected override bool ExecuteInternally(OperationProgress progress)
{ {
if (X == 1m && Y == 1m) return false; if (X == 1m && Y == 1m) return false;
progress ??= new OperationProgress();
progress.Reset(ProgressAction, LayerRangeCount);
decimal xSteps = Math.Abs(X - 1) / (LayerIndexEnd - LayerIndexStart); decimal xSteps = Math.Abs(X - 1) / (LayerIndexEnd - LayerIndexStart);
decimal ySteps = Math.Abs(Y - 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; 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); 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) public override bool Execute(Mat mat, params object[] arguments)
+12 -7
View File
@@ -42,6 +42,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationRotate() { }
public OperationRotate(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
public decimal AngleDegrees public decimal AngleDegrees
{ {
@@ -74,24 +82,21 @@ namespace UVtools.Core.Operations
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+18 -7
View File
@@ -20,13 +20,18 @@ namespace UVtools.Core.Operations
[Serializable] [Serializable]
public sealed class OperationSolidify : Operation public sealed class OperationSolidify : Operation
{ {
#region Enums
public enum AreaCheckTypes public enum AreaCheckTypes
{ {
More, More,
Less Less
} }
#endregion
#region Members
private uint _minimumArea = 1; private uint _minimumArea = 1;
private AreaCheckTypes _areaCheckType = AreaCheckTypes.More; private AreaCheckTypes _areaCheckType = AreaCheckTypes.More;
#endregion
#region Overrides #region Overrides
@@ -70,25 +75,31 @@ namespace UVtools.Core.Operations
#endregion #endregion
#region Constructor
public OperationSolidify() { }
public OperationSolidify(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using var mat = slicerFile[layerIndex].LayerMat; using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
lock (progress.Mutex) lock (progress.Mutex)
{ {
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+12 -7
View File
@@ -47,6 +47,14 @@ namespace UVtools.Core.Operations
} }
#endregion #endregion
#region Constructor
public OperationThreshold() { }
public OperationThreshold(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Properties #region Properties
public byte Threshold public byte Threshold
{ {
@@ -71,17 +79,15 @@ namespace UVtools.Core.Operations
#region Methods #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 => Parallel.For(LayerIndexStart, LayerIndexEnd + 1, layerIndex =>
{ {
if (progress.Token.IsCancellationRequested) return; if (progress.Token.IsCancellationRequested) return;
using (var mat = slicerFile[layerIndex].LayerMat) using (var mat = SlicerFile[layerIndex].LayerMat)
{ {
Execute(mat); Execute(mat);
slicerFile[layerIndex].LayerMat = mat; SlicerFile[layerIndex].LayerMat = mat;
} }
lock (progress.Mutex) lock (progress.Mutex)
@@ -89,9 +95,8 @@ namespace UVtools.Core.Operations
progress++; progress++;
} }
}); });
progress.Token.ThrowIfCancellationRequested();
return true; return !progress.Token.IsCancellationRequested;
} }
public override bool Execute(Mat mat, params object[] arguments) public override bool Execute(Mat mat, params object[] arguments)
+2 -2
View File
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl> <RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl> <PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description> <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> <Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon> <PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms> <Platforms>AnyCPU;x64</Platforms>
@@ -45,7 +45,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BinarySerializer" Version="8.5.3" /> <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="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Memory" Version="4.5.4" /> <PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" /> <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"> <Component Id="owc27A5D1506739847D9D7688256879A937" Guid="30f2e89f-1e95-77b9-1c3b-90bd4d875160">
<File Id="owf27A5D1506739847D9D7688256879A937" Source="$(var.SourceDir)\Avalonia.DesktopRuntime.dll" KeyPath="yes" /> <File Id="owf27A5D1506739847D9D7688256879A937" Source="$(var.SourceDir)\Avalonia.DesktopRuntime.dll" KeyPath="yes" />
</Component> </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"> <Component Id="owc6C15ADD7A5EE7A0CBEFD35B0027BBEB7" Guid="9c4a8ab3-598c-8e7c-0295-5c068334ab67">
<File Id="owf6C15ADD7A5EE7A0CBEFD35B0027BBEB7" Source="$(var.SourceDir)\Avalonia.Dialogs.dll" KeyPath="yes" /> <File Id="owf6C15ADD7A5EE7A0CBEFD35B0027BBEB7" Source="$(var.SourceDir)\Avalonia.Dialogs.dll" KeyPath="yes" />
</Component> </Component>
@@ -227,12 +230,18 @@
<Component Id="owc80EC8AEA1BFB8077812CDD06F9128A53" Guid="afbd2d79-629c-90a1-57a9-d68edc2d1437"> <Component Id="owc80EC8AEA1BFB8077812CDD06F9128A53" Guid="afbd2d79-629c-90a1-57a9-d68edc2d1437">
<File Id="owf80EC8AEA1BFB8077812CDD06F9128A53" Source="$(var.SourceDir)\clrjit.dll" KeyPath="yes" /> <File Id="owf80EC8AEA1BFB8077812CDD06F9128A53" Source="$(var.SourceDir)\clrjit.dll" KeyPath="yes" />
</Component> </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"> <Component Id="owc6135A13B8E29883ED57BF3FE20578EED" Guid="cd1aae2e-a4de-1bd1-9680-014bccf80e32">
<File Id="owf6135A13B8E29883ED57BF3FE20578EED" Source="$(var.SourceDir)\coreclr.dll" KeyPath="yes" /> <File Id="owf6135A13B8E29883ED57BF3FE20578EED" Source="$(var.SourceDir)\coreclr.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc5E8FBF42F9BCF40914849582C19906B8" Guid="f7a08052-6afc-fe5e-291c-07137533ab79"> <Component Id="owc5E8FBF42F9BCF40914849582C19906B8" Guid="f7a08052-6afc-fe5e-291c-07137533ab79">
<File Id="owf5E8FBF42F9BCF40914849582C19906B8" Source="$(var.SourceDir)\createdump.exe" KeyPath="yes" /> <File Id="owf5E8FBF42F9BCF40914849582C19906B8" Source="$(var.SourceDir)\createdump.exe" KeyPath="yes" />
</Component> </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"> <Component Id="owc3883419A2BFFE7013C2194A99728AB11" Guid="dd137337-4b74-c76b-c87e-6b5f42697dd4">
<File Id="owf3883419A2BFFE7013C2194A99728AB11" Source="$(var.SourceDir)\dbgshim.dll" KeyPath="yes" /> <File Id="owf3883419A2BFFE7013C2194A99728AB11" Source="$(var.SourceDir)\dbgshim.dll" KeyPath="yes" />
</Component> </Component>
@@ -263,6 +272,18 @@
<Component Id="owc6262D65DF7B3DF80C034B72467CAE882" Guid="4941cd5b-5666-87fe-5a6a-5ebdd5ee2524"> <Component Id="owc6262D65DF7B3DF80C034B72467CAE882" Guid="4941cd5b-5666-87fe-5a6a-5ebdd5ee2524">
<File Id="owf6262D65DF7B3DF80C034B72467CAE882" Source="$(var.SourceDir)\MessageBox.Avalonia.dll" KeyPath="yes" /> <File Id="owf6262D65DF7B3DF80C034B72467CAE882" Source="$(var.SourceDir)\MessageBox.Avalonia.dll" KeyPath="yes" />
</Component> </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"> <Component Id="owc27AE8A53D94DD8A3E4AEAF6F7C27FB60" Guid="80e5ef0e-84a5-2bce-9923-0fd54d243e45">
<File Id="owf27AE8A53D94DD8A3E4AEAF6F7C27FB60" Source="$(var.SourceDir)\Microsoft.CSharp.dll" KeyPath="yes" /> <File Id="owf27AE8A53D94DD8A3E4AEAF6F7C27FB60" Source="$(var.SourceDir)\Microsoft.CSharp.dll" KeyPath="yes" />
</Component> </Component>
@@ -299,12 +320,30 @@
<Component Id="owcE382B0CF482F0E7C3AF33E6EEEBD26B0" Guid="7433845c-c763-9b7e-e2c9-7b06986570bf"> <Component Id="owcE382B0CF482F0E7C3AF33E6EEEBD26B0" Guid="7433845c-c763-9b7e-e2c9-7b06986570bf">
<File Id="owfE382B0CF482F0E7C3AF33E6EEEBD26B0" Source="$(var.SourceDir)\mscorrc.dll" KeyPath="yes" /> <File Id="owfE382B0CF482F0E7C3AF33E6EEEBD26B0" Source="$(var.SourceDir)\mscorrc.dll" KeyPath="yes" />
</Component> </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"> <Component Id="owc79156F385239CEA4DEA3C87C1DA3E1D8" Guid="68380c80-6708-5eb6-415d-10e278417679">
<File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" /> <File Id="owf79156F385239CEA4DEA3C87C1DA3E1D8" Source="$(var.SourceDir)\netstandard.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b"> <Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b">
<File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" /> <File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" />
</Component> </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"> <Component Id="owcBFCA0BB8CBE4A68414FA088B4F7F3D22" Guid="babeb74f-9861-b222-a49a-ec268c3cd3ca">
<File Id="owfBFCA0BB8CBE4A68414FA088B4F7F3D22" Source="$(var.SourceDir)\ReactiveUI.dll" KeyPath="yes" /> <File Id="owfBFCA0BB8CBE4A68414FA088B4F7F3D22" Source="$(var.SourceDir)\ReactiveUI.dll" KeyPath="yes" />
</Component> </Component>
@@ -811,9 +850,9 @@
</Component> </Component>
<Component Id="owc21B8C8C0F69E3CD1398B9A0674DF07BD" Guid="1e472543-e636-904d-da5b-cddaac2d36b1"> <Component Id="owc21B8C8C0F69E3CD1398B9A0674DF07BD" Guid="1e472543-e636-904d-da5b-cddaac2d36b1">
<File Id="owf21B8C8C0F69E3CD1398B9A0674DF07BD" Source="$(var.SourceDir)\UVtools.exe" KeyPath="yes"> <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="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> </File>
</Component> </Component>
<Component Id="owc0C1077539E2B54F2460D2C0993613EFB" Guid="fc6ae2db-2865-9eb4-5753-4f2f941fdf16"> <Component Id="owc0C1077539E2B54F2460D2C0993613EFB" Guid="fc6ae2db-2865-9eb4-5753-4f2f941fdf16">
@@ -825,6 +864,15 @@
<Component Id="owc1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Guid="545300b7-5398-2ce2-788f-02287a83e8a7"> <Component Id="owc1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Guid="545300b7-5398-2ce2-788f-02287a83e8a7">
<File Id="owf1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Source="$(var.SourceDir)\UVtools_demo_file.sl1" KeyPath="yes" /> <File Id="owf1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Source="$(var.SourceDir)\UVtools_demo_file.sl1" KeyPath="yes" />
</Component> </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"> <Component Id="owc9AF7D2C52438BF24F3FA3132D7C0E6A9" Guid="892f88e7-cf94-fad1-08d3-b26c1b5913d3">
<File Id="owf9AF7D2C52438BF24F3FA3132D7C0E6A9" Source="$(var.SourceDir)\WindowsBase.dll" KeyPath="yes" /> <File Id="owf9AF7D2C52438BF24F3FA3132D7C0E6A9" Source="$(var.SourceDir)\WindowsBase.dll" KeyPath="yes" />
</Component> </Component>
@@ -1090,59 +1138,186 @@
</Component> </Component>
</Directory> </Directory>
</Directory> </Directory>
<Directory Id="owd37EA32A018DF9B31395A1FCE42233062" Name="x64"> <Directory Id="owd799F60633DE3314CD962556CD118A45D" Name="cs">
<Component Id="owcCD1854F2CC6C7F17F61397E23B6C598A" Guid="0a98d274-6f18-ee97-f14c-410e8fd2060d"> <Component Id="owc99CE72FDB30C8FD0902CE01843ED4D88" Guid="c4c2d2ce-4eae-325d-f83e-f5d17907fa7d">
<File Id="owfCD1854F2CC6C7F17F61397E23B6C598A" Source="$(var.SourceDir)\x64\concrt140.dll" KeyPath="yes" /> <File Id="owf99CE72FDB30C8FD0902CE01843ED4D88" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcE1790624963D540C427806C2B2809EBA" Guid="00de945a-e306-4840-1dd3-b8e968184b74"> <Component Id="owc5A8A23B0047B0D17D2E388C7647E2495" Guid="0bc611bd-4c59-08df-c64a-8fa2236aa7a5">
<File Id="owfE1790624963D540C427806C2B2809EBA" Source="$(var.SourceDir)\x64\cvextern.dll" KeyPath="yes" /> <File Id="owf5A8A23B0047B0D17D2E388C7647E2495" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc5F1F538D5D53D69031C503A5A647FA86" Guid="4e9e9fdc-8d0c-3ba0-a240-9e6ef5842194"> <Component Id="owc86B8E7B458701723CB9EC03C1690DC6E" Guid="cdd72de0-864d-fb89-212f-4bd06f0dcd10">
<File Id="owf5F1F538D5D53D69031C503A5A647FA86" Source="$(var.SourceDir)\x64\msvcp140.dll" KeyPath="yes" /> <File Id="owf86B8E7B458701723CB9EC03C1690DC6E" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc8F40E3E29777D025A9F18E5B6042F30D" Guid="e05981f2-643b-ca90-e066-2434e056751a"> <Component Id="owc8370BED3D17A58E88E193350B14A5450" Guid="cc521992-26e9-bf12-e777-68f8e2102405">
<File Id="owf8F40E3E29777D025A9F18E5B6042F30D" Source="$(var.SourceDir)\x64\msvcp140_1.dll" KeyPath="yes" /> <File Id="owf8370BED3D17A58E88E193350B14A5450" Source="$(var.SourceDir)\cs\Microsoft.CodeAnalysis.Scripting.resources.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> </Component>
</Directory> </Directory>
<Directory Id="owd3BCA71FC1DDF940F5FD535BAC750E17B" Name="x86"> <Directory Id="owd17C6A2D314297F8FF3C608803909F7BE" Name="de">
<Component Id="owcFBC3B4CD533BC131080BCB572CEE8474" Guid="8b12ad7e-4019-3cca-c71d-82e5f3e6a080"> <Component Id="owc6A8D7823467C066EA1EC2F740C66084D" Guid="82c152c6-97bf-f75d-44fc-294474d9a7cb">
<File Id="owfFBC3B4CD533BC131080BCB572CEE8474" Source="$(var.SourceDir)\x86\concrt140.dll" KeyPath="yes" /> <File Id="owf6A8D7823467C066EA1EC2F740C66084D" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.CSharp.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc326B123F4EAB21E3B400B7357CCFCB69" Guid="7acba6ad-3e71-b056-9a79-7e53f7d4585b"> <Component Id="owc9116F5B9D0D06FDD8B9116F3E0951A24" Guid="05d40bda-9c56-78d7-90ac-dd3c0b6e32c8">
<File Id="owf326B123F4EAB21E3B400B7357CCFCB69" Source="$(var.SourceDir)\x86\cvextern.dll" KeyPath="yes" /> <File Id="owf9116F5B9D0D06FDD8B9116F3E0951A24" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcEBF7D14133500BEDB79449CCE2A5B412" Guid="3cfe7baa-8f60-50d4-0c7c-41e7f7409b69"> <Component Id="owc201B77F8A5FFED898E7D6ABA98A1C719" Guid="db330e27-4a94-1662-79dc-50425953f203">
<File Id="owfEBF7D14133500BEDB79449CCE2A5B412" Source="$(var.SourceDir)\x86\msvcp140.dll" KeyPath="yes" /> <File Id="owf201B77F8A5FFED898E7D6ABA98A1C719" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcA62A9E2DCF3C1092572B9BA8A90AF2CC" Guid="a5901167-af03-d482-e4a2-55e2fd2dab37"> <Component Id="owcF790A17350C2437C0E1E354B9D980161" Guid="627f2dc4-5b88-d3f7-3acf-7630111e30e8">
<File Id="owfA62A9E2DCF3C1092572B9BA8A90AF2CC" Source="$(var.SourceDir)\x86\msvcp140_1.dll" KeyPath="yes" /> <File Id="owfF790A17350C2437C0E1E354B9D980161" Source="$(var.SourceDir)\de\Microsoft.CodeAnalysis.Scripting.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owc4E55EDBDDABF300437BC351C60EA1BBB" Guid="253ff45b-49b3-cf8c-4b98-7ac426bdb997"> </Directory>
<File Id="owf4E55EDBDDABF300437BC351C60EA1BBB" Source="$(var.SourceDir)\x86\msvcp140_2.dll" KeyPath="yes" /> <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>
<Component Id="owcDE8398D0FE76287635F64D20414A83A9" Guid="b3a19e5c-5f5b-984b-06fc-91ec029138fe"> <Component Id="owcAF0B9E9C8764DB03240C3233FA91FC3F" Guid="61f4d403-eb00-dd15-8880-b8ae920ff3b3">
<File Id="owfDE8398D0FE76287635F64D20414A83A9" Source="$(var.SourceDir)\x86\msvcp140_codecvt_ids.dll" KeyPath="yes" /> <File Id="owfAF0B9E9C8764DB03240C3233FA91FC3F" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.CSharp.Scripting.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcB3105100F274DC6C121EB91815CE430E" Guid="17155558-2ffd-5452-640e-b77c2e2b86e5"> <Component Id="owcA9E6FC4859E34CE57D4623D60AB82100" Guid="6e39d6b9-6efc-9ed5-3392-971358498061">
<File Id="owfB3105100F274DC6C121EB91815CE430E" Source="$(var.SourceDir)\x86\opencv_videoio_ffmpeg440.dll" KeyPath="yes" /> <File Id="owfA9E6FC4859E34CE57D4623D60AB82100" Source="$(var.SourceDir)\es\Microsoft.CodeAnalysis.resources.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="owcFE2AD2B6C739ABAFD86DE40F4D5B83C9" Guid="30610dbe-339b-b1be-a4a6-626e8fc07490"> <Component Id="owcB59CB618361B113CFA57D75E883608EA" Guid="ddc56db3-e6a2-c7aa-dc21-3b247964758c">
<File Id="owfFE2AD2B6C739ABAFD86DE40F4D5B83C9" Source="$(var.SourceDir)\x86\vcruntime140.dll" KeyPath="yes" /> <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> </Component>
</Directory> </Directory>
</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 # Morph bottom erode
Write-Output "Eroding bottoms with ${iterations} iterations, please wait..." 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.MorphOperation = [Emgu.CV.CvEnum.MorphOp]::Erode
$morph.IterationsStart = $iterations $morph.IterationsStart = $iterations
$morph.LayerIndexEnd = $slicerFile.BottomLayerCount - 1 $morph.SelectBottomLayers()
if(!$morph.Execute($slicerFile, $progress)){ return; } if(!$morph.Execute($progress)){ return; }
############## ##############
# Dont touch # # Dont touch #
############## ##############
# Save file with _modified name appended # Save file with _modified name appended
$filePath = [System.IO.Path]::GetDirectoryName($inputFile); $filePath = [System.IO.Path]::GetDirectoryName($inputFile)
$fileExt = [System.IO.Path]::GetExtension($inputFile); $fileExt = [System.IO.Path]::GetExtension($inputFile)
$fileNoExt = [System.IO.Path]::GetFileNameWithoutExtension($inputFile) $fileNoExt = [System.IO.Path]::GetFileNameWithoutExtension($inputFile)
$fileOutput = "${filePath}${dirSeparator}${fileNoExt}_modified${fileExt}" $fileOutput = "${filePath}${dirSeparator}${fileNoExt}_modified${fileExt}"
Write-Output "Saving as ${fileNoExt}_modified${fileExt}, please wait..." 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: * Example:
```Powershell ```Powershell
# Erode bottom layers # 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.MorphOperation = [Emgu.CV.CvEnum.MorphOp]::Erode
$morph.IterationsStart = $iterations $morph.IterationsStart = $iterations
$morph.LayerIndexEnd = $slicerFile.BottomLayerCount - 1 $morph.SelectBottomLayers()
if(!$morph.Execute($slicerFile, $progress)){ return; } if(!$morph.Execute($progress)){ return }
# Reuse object and erode normal layers with 1 less iteration # Reuse object and erode normal layers with 1 less iteration
$morph.IterationsStart = $iterations - 1 $morph.IterationsStart = $iterations - 1
$morph.LayerIndexStart = $slicerFile.BottomLayerCount $morph.SelectNormalLayers()
$morph.LayerIndexEnd = $slicerFile.LayerCount - 1 if(!$morph.Execute($progress)){ return }
if(!$morph.Execute($slicerFile, $progress)){ return }
# Rotate layer 0, 45º # Rotate all layers, 45º
$rotate = New-Object UVtools.Core.Operations.OperationRotate $rotate = [UVtools.Core.Operations.OperationRotate]::new($slicerFile)
$rotate.AngleDegrees = 45; $rotate.AngleDegrees = 45;
if(!$rotate.Execute($slicerFile, $progress)){ return } if(!$rotate.Execute($progress)){ return }
# Rotate layer 1, 90º # Rotate layer 1, 90º
$rotate.LayerIndexStart = 1 $rotate.LayerIndexStart = 1
$rotate.LayerIndexEnd = 1 $rotate.LayerIndexEnd = 1
$rotate.AngleDegrees = 90 $rotate.AngleDegrees = 90
if(!$rotate.Execute($slicerFile, $progress)){ return } if(!$rotate.Execute($progress)){ return }
``` ```
## Contribute with your scripts ## 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 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" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UVtools.WPF.App"> x:Class="UVtools.WPF.App">
<Application.Styles> <Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/> <FluentTheme Mode="Light"/>
<StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/> <StyleInclude Source="avares://ThemeEditor.Controls.ColorPicker/ColorPicker.axaml"/>
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/> <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
<StyleInclude Source="avares://ThemeEditor.Controls.ColorPicker/ColorPicker.xaml"/> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
<StyleInclude Source="/Assets/Styles/StylesLight.xaml" />
</Application.Styles> </Application.Styles>
</Application> </Application>
+12 -9
View File
@@ -24,13 +24,12 @@ using UVtools.Core;
using UVtools.Core.FileFormats; using UVtools.Core.FileFormats;
using UVtools.WPF.Extensions; using UVtools.WPF.Extensions;
using UVtools.WPF.Structures; using UVtools.WPF.Structures;
using Size = System.Drawing.Size;
namespace UVtools.WPF namespace UVtools.WPF
{ {
public class App : Application public class App : Application
{ {
public static IThemeSelector? ThemeSelector { get; set; } public static ThemeSelector ThemeSelector { get; set; }
public static MainWindow MainWindow; public static MainWindow MainWindow;
public static FileFormat SlicerFile = null; public static FileFormat SlicerFile = null;
@@ -53,7 +52,7 @@ namespace UVtools.WPF
OperationProfiles.Load(); 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")); ThemeSelector.LoadSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
if (ThemeSelector.SelectedTheme.Name == "UVtoolsDark" || ThemeSelector.SelectedTheme.Name == "Light") if (ThemeSelector.SelectedTheme.Name == "UVtoolsDark" || ThemeSelector.SelectedTheme.Name == "Light")
{ {
@@ -63,13 +62,16 @@ namespace UVtools.WPF
theme.ApplyTheme(); theme.ApplyTheme();
break; break;
} }
} }*/
MainWindow = new MainWindow();
MainWindow = new MainWindow();
try 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) catch (Exception e)
{ {
@@ -82,8 +84,7 @@ namespace UVtools.WPF
} }
desktop.MainWindow = MainWindow; desktop.MainWindow = MainWindow;
desktop.Exit += (sender, e) //desktop.Exit += (sender, e) => ThemeSelector.SaveSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
=> ThemeSelector.SaveSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
} }
base.OnFrameworkInitializationCompleted(); base.OnFrameworkInitializationCompleted();
@@ -191,6 +192,8 @@ namespace UVtools.WPF
if (OperatingSystem.IsLinux()) 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"; 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"> <StackPanel Spacing="10">
<Grid <Grid
RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto" 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" <TextBlock Grid.Row="0" Grid.Column="0"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="Layer height:"/> Text="Layer height:"/>
<NumericUpDown Grid.Row="0" Grid.Column="2" <NumericUpDown Grid.Row="0" Grid.Column="2"
ClipValueToMinMax="True"
Increment="0.01" Increment="0.01"
Minimum="0.01" Minimum="0.01"
Maximum="0.30" Maximum="0.30"
FormatString="\{0:0.00\}" FormatString="F02"
Value="{Binding Operation.LayerHeight}" Value="{Binding Operation.LayerHeight}"
/> />
<TextBlock Grid.Row="0" Grid.Column="4" <TextBlock Grid.Row="0" Grid.Column="4"
@@ -41,7 +40,7 @@
Increment="1" Increment="1"
Minimum="1" Minimum="1"
Maximum="1000" Maximum="1000"
FormatString="\{0:0.00\}" FormatString="F02"
Value="{Binding Operation.BottomLayers}" Value="{Binding Operation.BottomLayers}"
/> />
<TextBlock Grid.Row="2" Grid.Column="4" <TextBlock Grid.Row="2" Grid.Column="4"
@@ -60,7 +59,7 @@
Increment="1" Increment="1"
Minimum="1" Minimum="1"
Maximum="1000" Maximum="1000"
FormatString="\{0:0.00\}" FormatString="F02"
Value="{Binding Operation.NormalLayers}" Value="{Binding Operation.NormalLayers}"
/> />
<TextBlock Grid.Row="2" Grid.Column="10" <TextBlock Grid.Row="2" Grid.Column="10"
@@ -181,7 +180,7 @@
<Grid <Grid
Margin="0,10,0,0" Margin="0,10,0,0"
RowDefinitions="Auto,10,Auto" 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" <CheckBox Grid.Row="0" Grid.Column="2"
@@ -265,7 +264,7 @@
<Grid <Grid
Margin="0,10,0,0" Margin="0,10,0,0"
RowDefinitions="Auto,10,Auto,10,Auto,5,Auto" 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" <CheckBox Grid.Row="0" Grid.Column="2"
@@ -29,16 +29,10 @@ namespace UVtools.WPF.Controls.Calibrators
public CalibrateElephantFootControl() public CalibrateElephantFootControl()
{ {
this.InitializeComponent(); InitializeComponent();
BaseOperation = new OperationCalibrateElephantFoot();
BaseOperation = new OperationCalibrateElephantFoot(SlicerFile);
if(App.SlicerFile is not null)
{
Operation.LayerHeight = (decimal) App.SlicerFile.LayerHeight;
Operation.BottomExposure = (decimal) App.SlicerFile.BottomExposureTime;
Operation.NormalExposure = (decimal) App.SlicerFile.ExposureTime;
}
_kernelCtrl = this.Find<KernelControl>("KernelCtrl"); _kernelCtrl = this.Find<KernelControl>("KernelCtrl");
_timer = new Timer(20) _timer = new Timer(20)
@@ -60,7 +54,6 @@ namespace UVtools.WPF.Controls.Calibrators
{ {
case ToolWindow.Callbacks.Init: case ToolWindow.Callbacks.Init:
case ToolWindow.Callbacks.ProfileLoaded: case ToolWindow.Callbacks.ProfileLoaded:
Operation.Resolution = App.SlicerFile.Resolution;
Operation.PropertyChanged += (sender, e) => Operation.PropertyChanged += (sender, e) =>
{ {
_timer.Stop(); _timer.Stop();

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