Skip to content

Commit

Permalink
v4.4.1
Browse files Browse the repository at this point in the history
- (Add) Pixel Editor: Fill tool and merge into Erase section, left click fills and right click erases
- (Improvement) SL1: Implement missing material override properties
- (Fix) File formats: Error while trying to generate a thumbnail for a file that have a empty first layer (#912)
- (Upgrade) AvaloniaUI from 11.1.1 to 11.1.3
- (Upgrade) .NET from 6.0.32 to 6.0.33
  • Loading branch information
sn4k3 committed Aug 19, 2024
1 parent 3ad3524 commit c116aff
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 308 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 19/08/2024 - v4.4.1

- (Add) Pixel Editor: Fill tool and merge into Erase section, left click fills and right click erases
- (Improvement) SL1: Implement missing material override properties
- (Fix) File formats: Error while trying to generate a thumbnail for a file that have a empty first layer (#912)
- (Upgrade) AvaloniaUI from 11.1.1 to 11.1.3
- (Upgrade) .NET from 6.0.32 to 6.0.33

## 30/07/2024 - v4.4.0

- **File formats:**
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@

<CommonPublishDir>$(MSBuildThisFileDirectory)publish</CommonPublishDir>

<UVtoolsVersion>4.4.0</UVtoolsVersion>
<AvaloniaVersion>11.1.1</AvaloniaVersion>
<UVtoolsVersion>4.4.1</UVtoolsVersion>
<AvaloniaVersion>11.1.3</AvaloniaVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,13 @@ The following commands are the old way and commands under the UI executable, the
## Windows
1. Windows 7 SP1 or greater
1. Windows 10 or greater
1. If on Windows 10/11 N or NK:
- [Media Feature Pack](https://www.microsoft.com/download/details.aspx?id=48231) must be installed
- Press Windows + R
- Type: appwiz.cpl (and press Enter key)
- Click on: Turn Windows features on or off
- Check the "Media Extensions" and click Ok
<!-- 1. [.NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0) installed (Comes pre-installed on Windows 10 with last updates)!-->
1. 8GB RAM or higher + 512MB per CPU core
2. 64 bit System
3. 1920 x 1080 @ 100% scale as minimum resolution
Expand Down Expand Up @@ -302,8 +301,7 @@ If you downloaded the **.AppImage** package variant you must set run permissions
1. macOS 10.15 Catalina or higher
1. 8GB RAM or higher + 512MB per CPU core
3. **For Mac M1/M2 (ARM):**
1. Install via the [auto installer](https://github.com/sn4k3/UVtools#to-auto-install-on-macos-homebrew)
3. Install UVtools via the [auto installer](https://github.com/sn4k3/UVtools#to-auto-install-on-macos)
To run UVtools open it folder on a terminal and call one of:
Expand Down
52 changes: 5 additions & 47 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,6 @@
- **File formats:**
- (Add) File format: Klipper zip
- (Add) Properties:
- `Pause` and `ChangeResin` to layers
- `BottomLiftAcceleration`
- `BottomLiftAcceleration2`
- `LiftAcceleration`
- `LiftAcceleration2`
- `BottomRetractAcceleration`
- `BottomRetractAcceleration2`
- `RetractAcceleration`
- `RetractAcceleration2`
- (Add) PrusaSlicer Keywords:
- `FILECLASS_xxx` to define the file class directly instead of a file extension
- `BottomLiftAcceleration`
- `BottomLiftAcceleration2`
- `BottomRetractAcceleration`
- `BottomRetractAcceleration2`
- `LiftAcceleration`
- `LiftAcceleration2`
- `RetractAcceleration`
- `RetractAcceleration2`
- (Add) Property `HaveTiltingVat` to know if the printer have a tilting vat
- (Add) Compatibility with tilting vat Saturn 4 Ultra which also fixes print time estimate (#906)
- (Add) Encrypted CTB: Tries to predict tilting vat printers from set parameters
- (Change) CWS: Append `;<Slice>` as first line in the layer instead when required
- (Change) VDT: Move FTL previews to top to be used as first in conversion
- (Improvement) Anycubic: Write the image color table based on the AntiAliasing level (#899)
- (Improvement) Encrypted CTB: Implement the `ModifiedTimestampMinutes` and `AntiAliasLevel` field
- (Fix) nanoDLP `slicer.json` deserialize problem on some files
- (Fix) SL1: The keyword `TransitionLayerCount_xxx` not being set on the file (#902)
- (Fix) PHZ: Generated invalid thumbnail data (#903)
- **Tools:**
- (Improvement) Pixel arithmetic: Add extra checks to ignore empty size and layers
- (Change) Edit print parameters: Allow set lift and retract speeds to 0 (#906)
- **UI:**
- (Add) Menu - File - Copy parameters to files: Allow to copy parameters from current file to another file(s) (#852)
- (Improvement) Menu - File - Reset layer properties: Hold SHIFT key to also rebuild layers position with the file layer height (#870)
- (Improvement) Save as and convert file save dialog: Force the correct file extension if been tampered (#909)
- (Improvement) Exposure time finder: Disable incompatible panels instead of hide them
- (Add) Layer preview shortcuts: A/W/S/D to pan the layer image and Q/E to go to previous/next layer (#871)
- (Fix) Prevent CTRL + SHIFT + Up/Down (Issue navigation shortcut) from change layer
- (Add) PrusaSlicer printer: Elegoo Saturn 4 Ultra
- (Fix) Linux AppImage: Failed to change to directory "~" (No such file of directory) (#891)
- (Upgrade) OpenCV from 4.8.0 to 4.9.0
- (Upgrade) AvaloniaUI from 11.0.10 to 11.1.1 (Fixes #872)
- (Upgrade) .NET from 6.0.29 to 6.0.32
- (Add) Pixel Editor: Fill tool and merge into Erase section, left click fills and right click erases
- (Improvement) SL1: Implement missing material override properties
- (Fix) File formats: Error while trying to generate a thumbnail for a file that have a empty first layer (#912)
- (Upgrade) AvaloniaUI from 11.1.1 to 11.1.3
- (Upgrade) .NET from 6.0.32 to 6.0.33

11 changes: 11 additions & 0 deletions UVtools.Core/EmguCV/EmguContours.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ private EmguContourFamily ArrangeFamily(ref int loopIndex, int depth, EmguContou

return family;
}

/// <summary>
/// Gets contours inside a point
/// </summary>
/// <param name="location"></param>
/// <param name="includeLimitingArea">If true it will include all limiting area, otherwise only outer contour will be returned</param>
/// <returns></returns>
public VectorOfVectorOfPoint GetContoursInside(Point location, bool includeLimitingArea = true)
{
return GetContoursInside(Vector, Hierarchy, location, includeLimitingArea);
}
#endregion

#region Indexers
Expand Down
195 changes: 31 additions & 164 deletions UVtools.Core/FileFormats/FileFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4234,7 +4234,7 @@ public bool SanitizeThumbnails(bool trimToFileSpec = false)
if (bestThumbnail is null)
{
using var matRoi = DecodeType == FileDecodeType.Partial ? null : FirstLayer?.LayerMatModelBoundingRectangle;
if (matRoi is null || matRoi.SourceMat.IsEmpty)
if (matRoi is null || matRoi.RoiMat.IsEmpty)
{
var genMat = EmguExtensions.InitMat(new Size(200, 100), 3);
CvInvoke.PutText(genMat, About.Software, new Point(40, 60), FontFace.HersheyDuplex, 1, EmguExtensions.WhiteColor, 2);
Expand Down Expand Up @@ -7602,7 +7602,7 @@ public void DrawModifications(IList<PixelOperation> drawings, OperationProgress?
.Where(operation => operation.OperationType
is PixelOperation.PixelOperationType.Drawing
or PixelOperation.PixelOperationType.Text
or PixelOperation.PixelOperationType.Eraser)
or PixelOperation.PixelOperationType.Fill)
.GroupBy(operation => operation.LayerIndex);

Parallel.ForEach(group1, CoreSettings.GetParallelOptions(progress), layerOperationGroup =>
Expand All @@ -7615,46 +7615,49 @@ or PixelOperation.PixelOperationType.Text
{
if (operation.OperationType == PixelOperation.PixelOperationType.Drawing)
{
var operationDrawing = (PixelDrawing)operation;
if (operation is not PixelDrawing operationDrawing) continue;
if (operationDrawing.BrushSize == 1)
{
mat.SetByte(operation.Location.X, operation.Location.Y, operationDrawing.Brightness);
continue;
}
mat.DrawPolygon((byte)operationDrawing.BrushShape, operationDrawing.BrushSize, operationDrawing.Location,
new MCvScalar(operationDrawing.Brightness), operationDrawing.RotationAngle, operationDrawing.Thickness, operationDrawing.LineType);
mat.DrawPolygon((byte)operationDrawing.BrushShape, operationDrawing.BrushSize,
operationDrawing.Location,
new MCvScalar(operationDrawing.Brightness), operationDrawing.RotationAngle,
operationDrawing.Thickness, operationDrawing.LineType);
/*switch (operationDrawing.BrushShape)
{
case PixelDrawing.BrushShapeType.Square:
CvInvoke.Rectangle(mat, operationDrawing.Rectangle, new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
break;
case PixelDrawing.BrushShapeType.Circle:
CvInvoke.Circle(mat, operation.Location, operationDrawing.BrushSize / 2,
new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
break;
default:
throw new ArgumentOutOfRangeException();
}*/
{
case PixelDrawing.BrushShapeType.Square:
CvInvoke.Rectangle(mat, operationDrawing.Rectangle, new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
break;
case PixelDrawing.BrushShapeType.Circle:
CvInvoke.Circle(mat, operation.Location, operationDrawing.BrushSize / 2,
new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
break;
default:
throw new ArgumentOutOfRangeException();
}*/
}
else if (operation.OperationType == PixelOperation.PixelOperationType.Text)
{
var operationText = (PixelText)operation;
mat.PutTextRotated(operationText.Text, operationText.Location, operationText.Font, operationText.FontScale, new MCvScalar(operationText.Brightness), operationText.Thickness, operationText.LineType, operationText.Mirror, operationText.LineAlignment, (double)operationText.Angle);
if (operation is not PixelText operationText) continue;
mat.PutTextRotated(operationText.Text, operationText.Location, operationText.Font,
operationText.FontScale, new MCvScalar(operationText.Brightness), operationText.Thickness,
operationText.LineType, operationText.Mirror, operationText.LineAlignment,
(double)operationText.Angle);
}
else if (operation.OperationType == PixelOperation.PixelOperationType.Eraser)
else if (operation.OperationType == PixelOperation.PixelOperationType.Fill)
{
using var layerContours = mat.FindContours(out var hierarchy, RetrType.Tree);
if (operation is not PixelFill operationFill) continue;
var pixel = mat.GetByte(operation.Location);
if (!operationFill.IsAdd && pixel == 0) continue;
if (mat.GetByte(operation.Location) >= 10)
{
using var vec = EmguContours.GetContoursInside(layerContours, hierarchy, operation.Location);
using var vec = layer.Contours.GetContoursInside(operation.Location);
if (vec.Size > 0)
{
CvInvoke.DrawContours(mat, vec, -1, new MCvScalar(operation.PixelBrightness), -1);
}
if (vec.Size > 0)
{
CvInvoke.DrawContours(mat, vec, -1, new MCvScalar(operationFill.Brightness), -1);
}
}
}
Expand Down Expand Up @@ -7768,142 +7771,6 @@ is PixelOperation.PixelOperationType.Supports
progress += (uint)layerOperationGroup.Count();
}
}

/*
// Old and memory hunger code
ConcurrentDictionary<uint, Mat> modifiedLayers = new();
for (var i = 0; i < drawings.Count; i++)
{
var operation = drawings[i];
if (operation.OperationType == PixelOperation.PixelOperationType.Drawing)
{
var operationDrawing = (PixelDrawing)operation;
var mat = modifiedLayers.GetOrAdd(operation.LayerIndex, u => this[operation.LayerIndex].LayerMat);
if (operationDrawing.BrushSize == 1)
{
mat.SetByte(operation.Location.X, operation.Location.Y, operationDrawing.Brightness);
continue;
}
mat.DrawPolygon((byte)operationDrawing.BrushShape, operationDrawing.BrushSize / 2, operationDrawing.Location,
new MCvScalar(operationDrawing.Brightness), operationDrawing.RotationAngle, operationDrawing.Thickness, operationDrawing.LineType);
//switch (operationDrawing.BrushShape)
//{
// case PixelDrawing.BrushShapeType.Square:
// CvInvoke.Rectangle(mat, operationDrawing.Rectangle, new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
// break;
// case PixelDrawing.BrushShapeType.Circle:
// CvInvoke.Circle(mat, operation.Location, operationDrawing.BrushSize / 2,
// new MCvScalar(operationDrawing.Brightness), operationDrawing.Thickness, operationDrawing.LineType);
// break;
// default:
// throw new ArgumentOutOfRangeException();
//}
}
else if (operation.OperationType == PixelOperation.PixelOperationType.Text)
{
var operationText = (PixelText)operation;
var mat = modifiedLayers.GetOrAdd(operation.LayerIndex, u => this[operation.LayerIndex].LayerMat);
mat.PutTextRotated(operationText.Text, operationText.Location, operationText.Font, operationText.FontScale, new MCvScalar(operationText.Brightness), operationText.Thickness, operationText.LineType, operationText.Mirror, operationText.LineAlignment, operationText.Angle);
}
else if (operation.OperationType == PixelOperation.PixelOperationType.Eraser)
{
var mat = modifiedLayers.GetOrAdd(operation.LayerIndex, u => this[operation.LayerIndex].LayerMat);
using var layerContours = mat.FindContours(out var hierarchy, RetrType.Tree);
if (mat.GetByte(operation.Location) >= 10)
{
using var vec = EmguContours.GetContoursInside(layerContours, hierarchy, operation.Location);
if (vec.Size > 0)
{
CvInvoke.DrawContours(mat, vec, -1, new MCvScalar(operation.PixelBrightness), -1);
}
}
}
else if (operation.OperationType == PixelOperation.PixelOperationType.Supports)
{
var operationSupport = (PixelSupport)operation;
int drawnLayers = 0;
for (int operationLayer = (int)operation.LayerIndex - 1; operationLayer >= 0; operationLayer--)
{
var mat = modifiedLayers.GetOrAdd((uint)operationLayer, u => this[operationLayer].LayerMat);
int radius = (operationLayer > 10 ? Math.Min(operationSupport.TipDiameter + drawnLayers, operationSupport.PillarDiameter) : operationSupport.BaseDiameter) / 2;
uint whitePixels;
int yStart = Math.Max(0, operation.Location.Y - operationSupport.TipDiameter / 2);
int xStart = Math.Max(0, operation.Location.X - operationSupport.TipDiameter / 2);
using (var matCircleRoi = new Mat(mat, new Rectangle(xStart, yStart, operationSupport.TipDiameter, operationSupport.TipDiameter)))
{
using var matCircleMask = matCircleRoi.NewBlank();
CvInvoke.Circle(matCircleMask, new Point(operationSupport.TipDiameter / 2, operationSupport.TipDiameter / 2),
operationSupport.TipDiameter / 2, new MCvScalar(operation.PixelBrightness), -1);
CvInvoke.BitwiseAnd(matCircleRoi, matCircleMask, matCircleMask);
whitePixels = (uint)CvInvoke.CountNonZero(matCircleMask);
}
if (whitePixels >= Math.Pow(operationSupport.TipDiameter, 2) / 3)
{
//CvInvoke.Circle(mat, operation.Location, radius, new MCvScalar(255), -1);
if (drawnLayers == 0) continue; // Supports nonexistent, keep digging
break; // White area end supporting
}
CvInvoke.Circle(mat, operation.Location, radius, new MCvScalar(operation.PixelBrightness), -1, operationSupport.LineType);
drawnLayers++;
}
}
else if (operation.OperationType == PixelOperation.PixelOperationType.DrainHole)
{
uint drawnLayers = 0;
var operationDrainHole = (PixelDrainHole)operation;
for (int operationLayer = (int)operation.LayerIndex; operationLayer >= 0; operationLayer--)
{
var mat = modifiedLayers.GetOrAdd((uint)operationLayer, u => this[operationLayer].LayerMat);
int radius = operationDrainHole.Diameter / 2;
uint blackPixels;
int yStart = Math.Max(0, operation.Location.Y - radius);
int xStart = Math.Max(0, operation.Location.X - radius);
using (var matCircleRoi = new Mat(mat, new Rectangle(xStart, yStart, operationDrainHole.Diameter, operationDrainHole.Diameter)))
{
using var matCircleRoiInv = new Mat();
CvInvoke.Threshold(matCircleRoi, matCircleRoiInv, 100, 255, ThresholdType.BinaryInv);
using var matCircleMask = matCircleRoi.NewBlank();
CvInvoke.Circle(matCircleMask, new Point(radius, radius), radius, EmguExtensions.WhiteColor, -1);
CvInvoke.BitwiseAnd(matCircleRoiInv, matCircleMask, matCircleMask);
blackPixels = (uint)CvInvoke.CountNonZero(matCircleMask);
}
if (blackPixels >= Math.Pow(operationDrainHole.Diameter, 2) / 3) // Enough area to drain?
{
if (drawnLayers == 0) continue; // Drill not found a target yet, keep digging
break; // Stop drill drain found!
}
CvInvoke.Circle(mat, operation.Location, radius, EmguExtensions.BlackColor, -1, operationDrainHole.LineType);
drawnLayers++;
}
}
progress++;
}
progress.Reset("Saving", (uint)modifiedLayers.Count);
Parallel.ForEach(modifiedLayers, CoreSettings.GetParallelOptions(progress), modifiedLayer =>
{
this[modifiedLayer.Key].LayerMat = modifiedLayer.Value;
modifiedLayer.Value.Dispose();
progress.LockAndIncrement();
});
*/
}
#endregion

Expand Down
Loading

0 comments on commit c116aff

Please sign in to comment.