Skip to content

Commit

Permalink
v4.2.1
Browse files Browse the repository at this point in the history
- **UI:**
  - **Pixel editor:**
    - (Add) Shortcut: Ctrl/⌘+E to de/activate pixel editor
    - (Add) Profiles (#604, #831)
    - (Improvement) Use DataGrid row header to show the operation count instead of process and store indexes for the objects
    - (Fix) Drawings and Text controls are not stretched to fill the available space to the right
  - (Improvement) macOS: Shortcuts Ctrl+0, Ctrl+R, Ctrl+F changed to use command key(⌘) instead of control key
- (Improvement) Dynamic layer height, Lithophane, PCB exposure and Phased exposure: Use better performant `HasNonZero` instead of `CountNonZero` to check if there are any pixels to process
- (Improvement) Update demo file with the newest version of the format and use SL1S printer instead
- (Change) Extract file contents shortcut: From Ctrl+E to Ctrl+Shift+E
- (Fix) Files with different resolution information from empty layers were generating wrong image creation for such layers (#833)
- (Fix) Possible throw an exception about invalid roi when using Roi and/or masks under some tools
- (Fix) Skeletonize memory leak
- (Fix) System.NullReferenceException when accessing reallocated layers (#835)
- (Fix) Unable to save profiles for "Light bleed compensation", "Phased exposure"
- (Fix) PrusaSlicer printer "UVtools Prusa SL1S SPEED": Fix the display width and height, they were flipped
- (Upgrade) AvaloniaUI from 11.0.7 to 11.0.9
  • Loading branch information
sn4k3 committed Feb 10, 2024
1 parent 8dc38c9 commit 115ee06
Show file tree
Hide file tree
Showing 46 changed files with 1,063 additions and 303 deletions.
30 changes: 22 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
# Changelog

## 31/01/2024 - v4.2.1
## 10/02/2024 - v4.2.1

- **UI:**
- **Pixel editor:**
- (Add) Shortcut: Ctrl/⌘+E to de/activate pixel editor
- (Add) Profiles (#604, #831)
- (Improvement) Use DataGrid row header to show the operation count instead of process and store indexes for the objects
- (Fix) Drawings and Text controls are not stretched to fill the available space to the right
- (Improvement) macOS: Shortcuts Ctrl+0, Ctrl+R, Ctrl+F changed to use command key(⌘) instead of control key
- (Improvement) Dynamic layer height, Lithophane, PCB exposure and Phased exposure: Use better performant `HasNonZero` instead of `CountNonZero` to check if there are any pixels to process
- (Improvement) Update demo file with the newest version of the format and use SL1S printer instead
- (Change) Extract file contents shortcut: From Ctrl+E to Ctrl+Shift+E
- (Fix) Files with different resolution information from empty layers were generating wrong image creation for such layers (#833)
- (Fix) Possible throw an exception about invalid roi when using Roi and/or masks under some tools
- (Fix) Skeletonize memory leak
- (Fix) System.NullReferenceException when accessing reallocated layers (#835)
- (Fix) Unable to save profiles for "Light bleed compensation", "Phased exposure"
- (Fix) PrusaSlicer printer "UVtools Prusa SL1S SPEED": Fix the display width and height, they were flipped
- (Upgrade) AvaloniaUI from 11.0.7 to 11.0.9

## 29/01/2024 - v4.2.0

Expand Down Expand Up @@ -272,7 +286,7 @@
## 23/04/2023 - v3.13.0

- **Benchmark tool:**
- (Add) Reference machine Intel® Core™ i9-13900K @ 5.5 GHz
- (Add) Reference machine Intel® Core i9-13900K @ 5.5 GHz
- (Improvement) Layout and arrangement
- **Windows MSI:**
- (Improvement) Move registry keys from HKCU to HKLM
Expand Down Expand Up @@ -811,7 +825,7 @@
## 02/05/2022 - v3.4.1

- (Add) Suggestion - Wait time before cure: Allow to set the number of layers to smooth transition from bottom to normal wait time (Defaults to 8)
- (Fix) Tool - PCB Exposure: Pixels per millimeter was been set to fixed value instead of use printer lcd pitch, causing wrong dimentions on different from 50µm pitch
- (Fix) Tool - PCB Exposure: Pixels per millimeter was been set to fixed value instead of use printer lcd pitch, causing wrong dimentions on different from 50µm pitch
- (Fix) Tool - PCB Exposure: Unable to run the tool when the display size information isn't available

## 02/05/2022 - v3.4.0
Expand Down Expand Up @@ -1144,7 +1158,7 @@

- **Pixel Arithmetic:**
- (Add) Corrode: Number of passes
- (Change) Corrode: Noise area default from 3px² to 1px²
- (Change) Corrode: Noise area default from 3px² to 1px²
- (Change) Fuzzy skin preset: Wall thickness from 6px to 4px
- (Change) Fuzzy skin preset: Max noise offset: 64
- (Add) Core: More helper functions: Area, Volume, LastBottomLayer, BottomLayersHeight, SetNoDelays, SetWaitTimeBeforeCureOrLightOffDelay
Expand All @@ -1165,7 +1179,7 @@
## 05/01/2022 - v2.27.5

- **Pixel Arithmetic:**
- (Add) Corrode: Noise pixel area, defaulting to 3px²
- (Add) Corrode: Noise pixel area, defaulting to 3px²
- (Change) Corrode: Cryptonumeric random to normal random to speed up calculation
- (Change) Fuzzy skin preset: Set a ignore threshold area of 5000px2
- (Improvement) Masking performance and auto crop the layer to speed up the processing when using an "Apply to" other than "All"
Expand Down Expand Up @@ -2212,7 +2226,7 @@
* Add option to clear ROI when adding masks
* Add option "Auto flip on load": Auto flip the layer preview on file load if the file is marked to print mirrored on the printer LCD
* **Layer preview:**
* Add selectable rotation directions 90º (CW and CCW)
* Add selectable rotation directions 90º (CW and CCW)
* Add preview flip (CTRL+F) horizontally and/or vertically
* Add maskable regions to process on a layer (SHIFT + Alt + Right-Click) on a area
* ROI: Shortcut "Shift + left click" now also selects hollow black areas inside a white perimeter
Expand Down Expand Up @@ -2668,7 +2682,7 @@ This release bump the major version due the introduction of .NET 5.0, the discon

* (Add) Changelog description to the new version update dialog
* (Add) Tool - Infill: Proper configurable infills
* (Add) Pixel area as "px²" to the layer bounds and ROI at layer bottom information bar
* (Add) Pixel area as "px²" to the layer bounds and ROI at layer bottom information bar
* (Add) Pixel dimming: Alternate pattern every x layers
* (Add) Pixel dimming: Lattice infill
* (Add) Solidify: Required minimum/maximum area to solidify found areas (Default values will produce the old behavior)
Expand Down Expand Up @@ -3149,7 +3163,7 @@ Less frequently used settings for gap and noise removal iterations have been mov
* (Add) Pixel Editor: Double click items will track and position over the draw
* (Fix) Pixel Editor: Label "Operations" was not reset to 0 after apply the modifications
* (Fix) Pixel Editor: Button "Remove" tooltip
* (Fix) Pixel Editor: Drawing - Brush Area - px to px²
* (Fix) Pixel Editor: Drawing - Brush Area - px to px²

## 19/07/2020 - v0.6.3.0

Expand Down
3 changes: 2 additions & 1 deletion CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,5 @@
- Sylvain Chartrand
- Michael Pullen
- Albeck Károly
- Mark Johnston
- Mark Johnston
- Ivan Ivanov
16 changes: 11 additions & 5 deletions PrusaSlicer/printer/UVtools Prusa SL1S SPEED.ini
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
# generated by PrusaSlicer 2.3.1+win64 on 2021-07-02 at 10:34:03 UTC
# generated by PrusaSlicer 2.7.1+win64 on 2024-02-08 at 19:49:31 UTC
absolute_correction = 0
area_fill = 45
bed_custom_model =
bed_custom_texture =
bed_shape = 0.5x0.5,127.5x0.5,127.5x80.5,0.5x80.5
bed_shape = 0.5x0.5,80.5x0.5,80.5x127.5,0.5x127.5
default_sla_material_profile = Prusa Orange Tough @0.05 SL1S
default_sla_print_profile = 0.05 Normal @SL1S
display_height = 81
display_height = 128
display_mirror_x = 1
display_mirror_y = 0
display_orientation = landscape
display_pixels_x = 1620
display_pixels_y = 2560
display_width = 128
display_width = 81
elefant_foot_compensation = 0.2
elefant_foot_min_width = 0.2
fast_tilt_time = 2.5
gamma_correction = 1
high_viscosity_tilt_time = 10
host_type = octoprint
inherits = Original Prusa SL1S SPEED
max_exposure_time = 120
Expand All @@ -34,5 +35,10 @@ printer_vendor =
printhost_apikey =
printhost_cafile =
relative_correction = 1,1
relative_correction_x = 1
relative_correction_y = 1
relative_correction_z = 1
sla_archive_format = SL1
sla_output_precision = 0.001
slow_tilt_time = 5
thumbnails = 400x400,800x480
thumbnails = 400x400/PNG, 800x480/PNG
34 changes: 17 additions & 17 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
- **Layers:**
- (Add) Brotli compression codec with good performance and compression ratio (Choose it if you have low available RAM)
- (Improvement) Use `ResizableMemory` instead of `MemoryStream` for `GZip` and `Deflate` compressions, this results in faster compressions and less memory pressure
- (Improvement) Changed how layers are cached into the memory, before they were compressed and save for the whole image. Now it crops the bitmap to the bounding rectangle of the current layer and save only that portion with pixels.
For example, if the image is empty the cached size will be 0 bytes, and in a 12K image but with a 100 x 100 usable area it will save only that area instead of requiring a 12K buffer.
The size of the buffer is now dynamic and will depends on layer data, as so, this method can reduce the memory usage greatly, specially when using large images with a lot of empty space, but also boosts the overall performance by relief the allocations and the required memory footprint.
Only in few special cases can have drawbacks, however they are very minimal and the performance impact is minimal in that case.
When decompressing, the full resolution image is still created and then the cached area is imported to the corresponding position, composing the final and original image. This is still faster than the old method because decompress a larger buffer is more costly.
In the end both writes/compresses and reads/decompresses are now faster and using less memory.
Note: When printing multiple objects it is recommended to place them close to each other as you can to take better advantage of this new method.
- **Issues Detection:**
- (Fix) When detecting for Islands but not overhangs it will throw an exception about invalid roi
- (Fix) Huge memory leak when detecting resin traps (#830)
- (Improvement) Core: Changed the way "Roi" method is returned and try to dispose all it instances
- (Fix) EncryptedCTB, GOO, SVGX: Huge memory leak when decoding files that caused the program to crash (#830)
- (Fix) UI: Missing theme styles
- (Fix) PrusaSlicer profiles for Creality Halot Mage's: Enable the "Horizontal" mirror under the "Printer" tab to produce the correct orientation when printing (#827)
- **UI:**
- **Pixel editor:**
- (Add) Shortcut: Ctrl/⌘+E to de/activate pixel editor
- (Add) Profiles (#604, #831)
- (Improvement) Use DataGrid row header to show the operation count instead of process and store indexes for the objects
- (Fix) Drawings and Text controls are not stretched to fill the available space to the right
- (Improvement) macOS: Shortcuts Ctrl+0, Ctrl+R, Ctrl+F changed to use command key(⌘) instead of control key
- (Improvement) Dynamic layer height, Lithophane, PCB exposure and Phased exposure: Use better performant `HasNonZero` instead of `CountNonZero` to check if there are any pixels to process
- (Improvement) Update demo file with the newest version of the format and use SL1S printer instead
- (Change) Extract file contents shortcut: From Ctrl+E to Ctrl+Shift+E
- (Fix) Files with different resolution information from empty layers were generating wrong image creation for such layers (#833)
- (Fix) Possible throw an exception about invalid roi when using Roi and/or masks under some tools
- (Fix) Skeletonize memory leak
- (Fix) System.NullReferenceException when accessing reallocated layers (#835)
- (Fix) Unable to save profiles for "Light bleed compensation", "Phased exposure"
- (Fix) PrusaSlicer printer "UVtools Prusa SL1S SPEED": Fix the display width and height, they were flipped
- (Upgrade) AvaloniaUI from 11.0.7 to 11.0.9

Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="{TemplateBinding CornerRadius}"
IsTabStop="False"
Padding="0"
MinWidth="0"
HorizontalContentAlignment="Stretch"
Expand Down
2 changes: 1 addition & 1 deletion UVtools.AvaloniaControls/UVtools.AvaloniaControls.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.7" />
<PackageReference Include="Avalonia" Version="11.0.9" />
</ItemGroup>

</Project>
Binary file modified UVtools.CAD/UVtools_demo_file.3mf
Binary file not shown.
Binary file removed UVtools.CAD/UVtools_demo_file.sl1
Binary file not shown.
Binary file added UVtools.CAD/UVtools_demo_file.sl1s
Binary file not shown.
2 changes: 1 addition & 1 deletion UVtools.Cmd/Symbols/ExtractCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal static Command CreateCommand()
if (contentType == ExtractContentType.Layers)
{
if (slicerFile.LayerCount == 0)
if (!slicerFile.HaveLayers)
{
Program.WriteLineWarning("File have no valid layers to extract.");
return;
Expand Down
4 changes: 2 additions & 2 deletions UVtools.Cmd/Symbols/SetThumbnailCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal static Command CreateCommand()
if (string.Equals(source, RandomLayerArg, StringComparison.OrdinalIgnoreCase))
{
var slicerFile = Program.OpenInputFile(inputFile);
if (slicerFile.LayerCount == 0) Program.WriteLineError("The file have no valid layers");
if (!slicerFile.HaveLayers) Program.WriteLineError("The file have no valid layers");
using var matRoi = slicerFile[Random.Shared.Next((int)slicerFile.LayerCount)].GetLayerMatBoundingRectangle(50, 100);
Expand All @@ -97,7 +97,7 @@ internal static Command CreateCommand()
if (uint.TryParse(source, out var layerIndex))
{
var slicerFile = Program.OpenInputFile(inputFile);
if (slicerFile.LayerCount == 0) Program.WriteLineError("The file have no valid layers");
if (!slicerFile.HaveLayers) Program.WriteLineError("The file have no valid layers");
slicerFile.SanitizeLayerIndex(ref layerIndex);
using var matRoi = slicerFile[layerIndex].GetLayerMatBoundingRectangle(50, 100);
Expand Down
2 changes: 1 addition & 1 deletion UVtools.Core/About.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,6 @@ public static bool IsBirthday
}
}

public const string DemoFile = "UVtools_demo_file.sl1";
public const string DemoFile = "UVtools_demo_file.sl1s";

}
58 changes: 30 additions & 28 deletions UVtools.Core/EmguCV/CMat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,10 @@ public Task<bool> ChangeCompressorAsync(MatCompressor compressor, bool reEncodeW
/// </summary>
public void SetEmptyCompressedBytes()
{
if (_compressedBytes.Length == 0) return; // Already empty
_compressedBytes = Array.Empty<byte>();
IsCompressed = false;
Roi = Rectangle.Empty;
}

/// <summary>
Expand All @@ -303,46 +305,46 @@ public void SetEmptyCompressedBytes(bool isInitialized)
}

/// <summary>
/// Sets the <see cref="CompressedBytes"/> and <see cref="Compressor"/> and <see cref="Decompressor"/>.
/// Sets the <see cref="CompressedBytes"/> to an empty byte array, sets <see cref="IsCompressed"/> to false and extract size, depth and channels from a <see cref="Mat"/>.
/// </summary>
/// <param name="compressedBytes"></param>
/// <param name="decompressor"></param>
/// <param name="setCompressor"></param>
public void SetCompressedBytes(byte[] compressedBytes, MatCompressor decompressor, bool setCompressor = true)
{
CompressedBytes = compressedBytes;
if (setCompressor) Compressor = decompressor;
Decompressor = decompressor;
}

/*
public void SetUncompressed(Mat src)
/// <param name="src">Source Mat to extract Size, Depth and Channels</param>
public void SetEmptyCompressedBytes(Mat src)
{
SetEmptyCompressedBytes();
Width = src.Width;
Height = src.Height;
Depth = src.Depth;
Channels = src.NumberOfChannels;
Roi = Rectangle.Empty;
CompressedBytes = src.GetBytes();
IsCompressed = false;
Decompressor = MatCompressorNone.Instance;
}

public void SetUncompressed(MatRoi src)
/// <summary>
/// Sets the <see cref="CompressedBytes"/> to an empty byte array, sets <see cref="IsCompressed"/> to false and extract size, depth and channels from a <see cref="Mat"/>.
/// </summary>
/// <param name="src">Source Mat to extract Size, Depth and Channels</param>
/// <param name="isInitialized">Sets the <see cref="IsInitialized"/> to a known state.</param>
public void SetEmptyCompressedBytes(Mat src, bool isInitialized)
{
Width = src.RoiMat.Width;
Height = src.RoiMat.Height;
Depth = src.RoiMat.Depth;
Channels = src.RoiMat.NumberOfChannels;
Roi = src.Roi;
SetEmptyCompressedBytes(src);
IsInitialized = isInitialized;
}

CompressedBytes = src.RoiMat.GetBytes();
IsCompressed = false;
Decompressor = MatCompressorNone.Instance;
/// <summary>
/// Sets the <see cref="CompressedBytes"/> and <see cref="Compressor"/> and <see cref="Decompressor"/>.
/// </summary>
/// <param name="compressedBytes"></param>
/// <param name="decompressor"></param>
/// <param name="setCompressor"></param>
public void SetCompressedBytes(byte[] compressedBytes, MatCompressor decompressor, bool setCompressor = true)
{
CompressedBytes = compressedBytes;
if (setCompressor) Compressor = decompressor;
Decompressor = decompressor;
}
*/

/// <summary>
/// Sets the <see cref="CompressedBytes"/> to uncompressed bitmap data.
/// </summary>
/// <param name="src"></param>
private void SetUncompressed(Mat src)
{
CompressedBytes = src.GetBytes();
Expand Down
32 changes: 23 additions & 9 deletions UVtools.Core/Extensions/DrawingExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Drawing;
using Emgu.CV.Structure;

namespace UVtools.Core.Extensions;

Expand Down Expand Up @@ -44,7 +45,20 @@ public static Point[] GetPolygonVertices(int sides, int radius, Point center, do

var vertices = new Point[sides];

double deg = 360.0 / sides;//calculate the rotation angle
/*if (sides == 4)
{
var rotatedRect = new RotatedRect(center, new SizeF(radius * 2, radius * 2), (float)startingAngle);
var verticesF = rotatedRect.GetVertices();
for (var i = 0; i < verticesF.Length; i++)
{
vertices[i] = verticesF[i].ToPoint();
}
return vertices;
}*/



var deg = 360.0 / sides;//calculate the rotation angle
var rad = Math.PI / 180.0;

var x0 = center.X + radius * Math.Cos(-(((180 - deg) / 2) + startingAngle) * rad);
Expand All @@ -54,23 +68,23 @@ public static Point[] GetPolygonVertices(int sides, int radius, Point center, do
var y1 = center.Y - radius * Math.Sin(-(((180 - deg) / 2) + deg + startingAngle) * rad);

vertices[0] = new(
(int) Math.Round(x0),
(int) Math.Round(y0)
(int) Math.Round(x0, MidpointRounding.AwayFromZero),
(int) Math.Round(y0, MidpointRounding.AwayFromZero)
);

vertices[1] = new(
(int) Math.Round(x1),
(int) Math.Round(y1)
(int) Math.Round(x1, MidpointRounding.AwayFromZero),
(int) Math.Round(y1, MidpointRounding.AwayFromZero)
);

for (int i = 0; i < sides - 2; i++)
{
double dsinrot = Math.Sin((deg * (i + 1)) * rad);
double dcosrot = Math.Cos((deg * (i + 1)) * rad);
var dsinrot = Math.Sin(deg * (i + 1) * rad);
var dcosrot = Math.Cos(deg * (i + 1) * rad);

vertices[i + 2] = new(
(int)Math.Round(center.X + dcosrot * (x1 - center.X) - dsinrot * (y1 - center.Y)),
(int)Math.Round(center.Y + dsinrot * (x1 - center.X) + dcosrot * (y1 - center.Y))
(int)Math.Round(center.X + dcosrot * (x1 - center.X) - dsinrot * (y1 - center.Y), MidpointRounding.AwayFromZero),
(int)Math.Round(center.Y + dsinrot * (x1 - center.X) + dcosrot * (y1 - center.Y), MidpointRounding.AwayFromZero)
);
}

Expand Down
Loading

0 comments on commit 115ee06

Please sign in to comment.