Skip to content

Commit c86fd5d

Browse files
committed
v5.0.6
- **PCB Exposure:** - (Fix) When importing gerber files via drag and drop to the main window the file was created with 0mm layer height and no exposure set - (Fix) Merging multiple gerber files with mirror active was mirroring the image in each draw causing the wrong output (#980) - (Fix) Excellon drill format does not load tools when they have spindle parameters [F/C] (#980) - (Fix) Excellon drill format to respect the integer and decimal digit count when specifying them (#980) - **Stress Tower:** - (Improvement) Allow to pause and cancel the operation - (Improvement) Process layers in a more efficient way to reduce allocations and be able to produce the test without RAM hogging - (Upgrade) .NET from 9.0.0 to 9.0.1 - (Upgrade) OpenCV from 4.9.0 to 4.10.0
1 parent 27f46ff commit c86fd5d

File tree

76 files changed

+821
-799
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+821
-799
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## 31/01/2025 - v5.0.6
4+
5+
- **PCB Exposure:**
6+
- (Fix) When importing gerber files via drag and drop to the main window the file was created with 0mm layer height and no exposure set
7+
- (Fix) Merging multiple gerber files with mirror active was mirroring the image in each draw causing the wrong output (#980)
8+
- (Fix) Excellon drill format does not load tools when they have spindle parameters [F/C] (#980)
9+
- (Fix) Excellon drill format to respect the integer and decimal digit count when specifying them (#980)
10+
- **Stress Tower:**
11+
- (Improvement) Allow to pause and cancel the operation
12+
- (Improvement) Process layers in a more efficient way to reduce allocations and be able to produce the test without RAM hogging
13+
- (Upgrade) .NET from 9.0.0 to 9.0.1
14+
- (Upgrade) OpenCV from 4.9.0 to 4.10.0
15+
316
## 09/01/2025 - v5.0.5
417

518
- (Add) PrusaSlicer printer: Elegoo Saturn 4 Ultra 16K

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
3838

3939
<!-- Versions -->
40-
<UVtoolsVersion>5.0.5</UVtoolsVersion>
40+
<UVtoolsVersion>5.0.6</UVtoolsVersion>
4141
<AvaloniaVersion>11.2.3</AvaloniaVersion>
4242

4343
<!-- MvvmToolkit -->

RELEASE_NOTES.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
- (Add) PrusaSlicer printer: Elegoo Saturn 4 Ultra 16K
2-
- (Improvement) Goo: Implement and support the tilting vat printers
3-
- (Improvement) All shapes in pixel editor will now respect the non-equal pixel pitch and compensate the lower side to print a regular shape, this also affects the polygons on PCB exposure tool and other tools as well
4-
- (Fix) PCB Exposure: Use raw polygons instead of angle aligned polygons to respect the gerber implementation (#976)
1+
- **PCB Exposure:**
2+
- (Fix) When importing gerber files via drag and drop to the main window the file was created with 0mm layer height and no exposure set
3+
- (Fix) Merging multiple gerber files with mirror active was mirroring the image in each draw causing the wrong output (#980)
4+
- (Fix) Excellon drill format does not load tools when they have spindle parameters [F/C] (#980)
5+
- (Fix) Excellon drill format to respect the integer and decimal digit count when specifying them (#980)
6+
- **Stress Tower:**
7+
- (Improvement) Allow to pause and cancel the operation
8+
- (Improvement) Process layers in a more efficient way to reduce allocations and be able to produce the test without RAM hogging
9+
- (Upgrade) .NET from 9.0.0 to 9.0.1
10+
- (Upgrade) OpenCV from 4.9.0 to 4.10.0
511

Scripts/UVtools.ScriptSample/ScriptTimelapseSample.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ public void ScriptInit()
9393
Script.Version = new Version(0, 1);
9494
Script.MinimumVersionToRun = new Version(3, 0, 0);
9595

96-
InputPositionZ.Value = (float)Math.Round(SlicerFile.PrintHeight + 1, 2);
97-
InputPositionZ.Minimum = (float) Math.Round(SlicerFile.PrintHeight + 0.1, 2);
96+
InputPositionZ.Value = MathF.Round(SlicerFile.PrintHeight + 1, 2);
97+
InputPositionZ.Minimum = MathF.Round(SlicerFile.PrintHeight + 0.1f, 2);
9898
Script.UserInputs.Add(InputPositionZ);
9999
Script.UserInputs.Add(InputRaiseEveryLayerN);
100100
Script.UserInputs.Add(InputWaitTime);

UVtools.Core/Converters/SpeedConverter.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@ public static float Convert(float value, SpeedUnit from, SpeedUnit to, byte roun
3131
SpeedUnit.MillimetersPerSecond => to switch
3232
{
3333
SpeedUnit.MillimetersPerSecond => value,
34-
SpeedUnit.MillimetersPerMinute => (float) Math.Round(value * 60, rounding, MidpointRounding.AwayFromZero),
35-
SpeedUnit.CentimetersPerMinute => (float) Math.Round(value * 6, rounding, MidpointRounding.AwayFromZero),
34+
SpeedUnit.MillimetersPerMinute => MathF.Round(value * 60, rounding, MidpointRounding.AwayFromZero),
35+
SpeedUnit.CentimetersPerMinute => MathF.Round(value * 6, rounding, MidpointRounding.AwayFromZero),
3636
_ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
3737
},
3838
SpeedUnit.MillimetersPerMinute => to switch
3939
{
40-
SpeedUnit.MillimetersPerSecond => (float) Math.Round(value / 60, rounding, MidpointRounding.AwayFromZero),
40+
SpeedUnit.MillimetersPerSecond => MathF.Round(value / 60, rounding, MidpointRounding.AwayFromZero),
4141
SpeedUnit.MillimetersPerMinute => value,
42-
SpeedUnit.CentimetersPerMinute => (float) Math.Round(value / 10, rounding, MidpointRounding.AwayFromZero),
42+
SpeedUnit.CentimetersPerMinute => MathF.Round(value / 10, rounding, MidpointRounding.AwayFromZero),
4343
_ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
4444
},
4545
SpeedUnit.CentimetersPerMinute => to switch
4646
{
47-
SpeedUnit.MillimetersPerSecond => (float) Math.Round(value * (1.0/6.0), rounding, MidpointRounding.AwayFromZero),
48-
SpeedUnit.MillimetersPerMinute => (float)Math.Round(value * 10, rounding, MidpointRounding.AwayFromZero),
47+
SpeedUnit.MillimetersPerSecond => MathF.Round(value * (1.0f/6.0f), rounding, MidpointRounding.AwayFromZero),
48+
SpeedUnit.MillimetersPerMinute => MathF.Round(value * 10, rounding, MidpointRounding.AwayFromZero),
4949
SpeedUnit.CentimetersPerMinute => value,
5050
_ => throw new ArgumentOutOfRangeException(nameof(to), to, null)
5151
},

UVtools.Core/Converters/TimeConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static class TimeConverter
1919
/// <param name="value"></param>
2020
/// <param name="rounding"></param>
2121
/// <returns></returns>
22-
public static float SecondsToMilliseconds(float value, byte rounding = 2) => (float)Math.Round(value * 1000f, rounding);
22+
public static float SecondsToMilliseconds(float value, byte rounding = 2) => MathF.Round(value * 1000f, rounding);
2323

2424
/// <summary>
2525
/// Converts seconds to milliseconds
@@ -34,5 +34,5 @@ public static class TimeConverter
3434
/// <param name="value"></param>
3535
/// <param name="rounding"></param>
3636
/// <returns></returns>
37-
public static float MillisecondsToSeconds(float value, byte rounding = 2) => (float)Math.Round(value / 1000f, rounding);
37+
public static float MillisecondsToSeconds(float value, byte rounding = 2) => MathF.Round(value / 1000f, rounding);
3838
}

UVtools.Core/EmguCV/CMat.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public float CompressionRatio
142142
var uncompressedLength = UncompressedLength;
143143
if (uncompressedLength == 0 || Length == uncompressedLength) return 1;
144144
if (Length == 0) return uncompressedLength;
145-
return (float)Math.Round((float)uncompressedLength / Length, 2, MidpointRounding.AwayFromZero);
145+
return MathF.Round((float)uncompressedLength / Length, 2, MidpointRounding.AwayFromZero);
146146
}
147147
}
148148

@@ -156,7 +156,7 @@ public float CompressionPercentage
156156
var uncompressedLength = UncompressedLength;
157157
if (uncompressedLength == 0 || Length == uncompressedLength) return 0;
158158
if (Length == 0) return 100f;
159-
return (float)Math.Round(100 - (Length * 100f / uncompressedLength), 2, MidpointRounding.AwayFromZero);
159+
return MathF.Round(100 - (Length * 100f / uncompressedLength), 2, MidpointRounding.AwayFromZero);
160160
}
161161
}
162162

@@ -170,7 +170,7 @@ public float CompressionEfficiency
170170
var uncompressedLength = UncompressedLength;
171171
if (uncompressedLength == 0) return 0;
172172
if (Length == 0) return uncompressedLength;
173-
return (float)Math.Round(uncompressedLength * 100f / Length, 2, MidpointRounding.AwayFromZero);
173+
return MathF.Round(uncompressedLength * 100f / Length, 2, MidpointRounding.AwayFromZero);
174174
}
175175
}
176176

UVtools.Core/Excellon/ExcellonDrillFormat.cs

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System;
1212
using System.Collections.Generic;
1313
using System.Drawing;
14+
using System.Globalization;
1415
using System.IO;
1516
using System.Text.RegularExpressions;
1617
using UVtools.Core.Extensions;
@@ -21,7 +22,7 @@ namespace UVtools.Core.Excellon;
2122
/// <summary>
2223
/// <para>The Excellon drill format is a subset of RS274D and is used by the drilling and routing machines made by the Excellon corporation.
2324
/// Because of Excellon's long history and dominance of the PCB drilling business for many years their format is a defacto industry standard.</para>
24-
/// <para>Almost every PCB layout software can produce this format.However we have noticed that many PCB layout tools do not take
25+
/// <para>Almost every PCB layout software can produce this format. However we have noticed that many PCB layout tools do not take
2526
/// full advantage of the header information which makes reading the drill file more difficult than it should be.</para>
2627
/// <para>https://www.artwork.com/gerber/drl2laser/excellon/index.htm</para>
2728
/// <para>https://gist.github.com/katyo/5692b935abc085b1037e</para>
@@ -49,7 +50,7 @@ public Tool(uint index, float diameter)
4950

5051
public override string ToString()
5152
{
52-
return $"T{Index}C{nameof(Diameter)}";
53+
return $"T{Index}C{Diameter}";
5354
}
5455
}
5556

@@ -188,6 +189,8 @@ private void Load(string filePath)
188189
uint selectedToolIndex = 0;
189190

190191
float x = 0, y = 0;
192+
int integerDigits = 0;
193+
int fractionDigits = 0;
191194

192195
while ((line = tr.ReadLine()?.Trim()) is not null)
193196
{
@@ -224,6 +227,15 @@ private void Load(string filePath)
224227
continue;
225228
}
226229

230+
if (integerDigits == 0 && line.StartsWith(";FILE_FORMAT="))
231+
{
232+
line = line.Remove(0, 13);
233+
var split = line.Split(':', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
234+
if (split.Length < 2) continue;
235+
int.TryParse(split[0], out integerDigits);
236+
int.TryParse(split[0], out fractionDigits);
237+
}
238+
227239
if (line is "ICI" or "ICI,ON")
228240
{
229241
throw new NotImplementedException("ICI (Incremental input of program coordinates) is not yet implemented, please use absolute coordinate system.");
@@ -246,15 +258,15 @@ private void Load(string filePath)
246258
{
247259
if (!endOfHeader)
248260
{
249-
var match = Regex.Match(line, @"^T([0-9]+)C(([0-9]*[.])?[0-9]+)");
261+
var match = Regex.Match(line, @"^T([0-9]+).*C(([0-9]*[.])?[0-9]+)");
250262
if (match is
251263
{
252264
Success: true,
253265
Groups.Count: >= 4
254266
})
255267
{
256268
var index = uint.Parse(match.Groups[1].Value);
257-
var diameter = float.Parse(match.Groups[2].Value);
269+
var diameter = float.Parse(match.Groups[2].Value, CultureInfo.InvariantCulture);
258270
var tool = new Tool(index, diameter);
259271
Tools.Add(index, tool);
260272
}
@@ -280,22 +292,40 @@ private void Load(string filePath)
280292
Groups.Count: >= 2
281293
})
282294
{
283-
if (match.Groups[1].Value.Contains('.') || ZerosIncludeType == ExcellonDrillZerosIncludeType.None)
295+
if (match.Groups[1].Value.Contains('.'))
284296
{
285-
x = float.Parse(match.Groups[1].Value);
297+
x = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
286298
}
287299
else
288300
{
289301
switch (ZerosIncludeType)
290302
{
303+
case ExcellonDrillZerosIncludeType.None:
291304
case ExcellonDrillZerosIncludeType.Leading:
292-
x = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadRight(PaddingZeros, '0')));
305+
if (integerDigits > 0)
306+
{
307+
var number = match.Groups[1].Value.Insert(integerDigits, ".");
308+
x = float.Parse(number, CultureInfo.InvariantCulture);
309+
}
310+
else
311+
{
312+
x = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadRight(PaddingZeros, '0'), CultureInfo.InvariantCulture));
313+
}
293314
break;
294315
case ExcellonDrillZerosIncludeType.Trail:
295-
x = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadLeft(PaddingZeros, '0')));
316+
if (fractionDigits > 0)
317+
{
318+
var number = match.Groups[1].Value.Insert(match.Groups[1].Value.Length - fractionDigits, ".");
319+
x = float.Parse(number, CultureInfo.InvariantCulture);
320+
}
321+
else
322+
{
323+
x = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadLeft(PaddingZeros, '0'), CultureInfo.InvariantCulture));
324+
}
296325
break;
297326
}
298327
}
328+
299329

300330
}
301331

@@ -306,19 +336,36 @@ private void Load(string filePath)
306336
Groups.Count: >= 2
307337
})
308338
{
309-
if (match.Groups[1].Value.Contains('.') || ZerosIncludeType == ExcellonDrillZerosIncludeType.None)
339+
if (match.Groups[1].Value.Contains('.'))
310340
{
311-
y = float.Parse(match.Groups[1].Value);
341+
y = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
312342
}
313343
else
314344
{
315345
switch (ZerosIncludeType)
316346
{
347+
case ExcellonDrillZerosIncludeType.None:
317348
case ExcellonDrillZerosIncludeType.Leading:
318-
y = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadRight(PaddingZeros, '0')));
349+
if (integerDigits > 0)
350+
{
351+
var number = match.Groups[1].Value.Insert(integerDigits, ".");
352+
y = float.Parse(number, CultureInfo.InvariantCulture);
353+
}
354+
else
355+
{
356+
y = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadRight(PaddingZeros, '0'), CultureInfo.InvariantCulture));
357+
}
319358
break;
320359
case ExcellonDrillZerosIncludeType.Trail:
321-
y = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadLeft(PaddingZeros, '0')));
360+
if (fractionDigits > 0)
361+
{
362+
var number = match.Groups[1].Value.Insert(match.Groups[1].Value.Length - fractionDigits, ".");
363+
y = float.Parse(number, CultureInfo.InvariantCulture);
364+
}
365+
else
366+
{
367+
y = ValueToCoordinate(float.Parse(match.Groups[1].Value.PadLeft(PaddingZeros, '0'), CultureInfo.InvariantCulture));
368+
}
322369
break;
323370
}
324371
}
@@ -336,8 +383,8 @@ private void Load(string filePath)
336383
public float ValueToCoordinate(float value) =>
337384
UnitType switch
338385
{
339-
ExcellonDrillUnitType.Millimeter => (float) Math.Round(value / MillimeterResolution, PaddingZeros),
340-
ExcellonDrillUnitType.Inch => (float) Math.Round(value / InchResolution, PaddingZeros),
386+
ExcellonDrillUnitType.Millimeter => MathF.Round(value / MillimeterResolution, PaddingZeros),
387+
ExcellonDrillUnitType.Inch => MathF.Round(value / InchResolution, PaddingZeros),
341388
_ => throw new ArgumentOutOfRangeException()
342389
};
343390

UVtools.Core/Extensions/EmguExtensions.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@
2222
using CommunityToolkit.Diagnostics;
2323
using UVtools.Core.EmguCV;
2424
using UVtools.Core.Objects;
25-
using Emgu.CV.Reg;
26-
using static UVtools.Core.FileFormats.UVJFile;
27-
using System.Reflection.Metadata;
2825
using Size = System.Drawing.Size;
2926

3027
namespace UVtools.Core.Extensions;
@@ -1908,7 +1905,7 @@ public static void DrawPolygon(this Mat src, int sides, SizeF diameter, PointF c
19081905
{
19091906
if (sides == 1)
19101907
{
1911-
var point1 = center with { X = (float)Math.Round(center.X - diameter.Width / 2, midpointRounding) };
1908+
var point1 = center with { X = MathF.Round(center.X - diameter.Width / 2, midpointRounding) };
19121909
var point2 = point1 with { X = point1.X + diameter.Width - 1 };
19131910
point1 = point1.Rotate(startingAngle, center);
19141911
point2 = point2.Rotate(startingAngle, center);

UVtools.Core/Extensions/RectangleExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ public static Rectangle OffsetBy(this Rectangle src, int x, int y)
2929

3030
public static int Perimeter(this Rectangle src) => src.Width * 2 + src.Height * 2;
3131
public static float Perimeter(this RectangleF src) => src.Width * 2 + src.Height * 2;
32-
public static float Perimeter(this RectangleF src, int round) => (float)Math.Round(src.Perimeter(), round);
32+
public static float Perimeter(this RectangleF src, int round) => MathF.Round(src.Perimeter(), round);
3333
public static int Area(this Rectangle src) => src.Width * src.Height;
3434
public static float Area(this RectangleF src) => src.Width * src.Height;
35-
public static float Area(this RectangleF src, int round) => (float)Math.Round(src.Area(), round);
35+
public static float Area(this RectangleF src, int round) => MathF.Round(src.Area(), round);
3636

3737
/// <summary>
3838
/// Gets the smallest rectangle among all rectangles

0 commit comments

Comments
 (0)