mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
v3.5.1
- **PCB Exposure:** - (Fix) Able to omit X or Y coordinate and use last known value in place - (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name - (Fix) Implement the inch measurement (%MOIN*%) - (Fix) Crash when redo the operation (Ctrl + Shift + Z) - **UI - Issue list:** - (Add) Context menu when right click issues to select an action - (Add) Option to solidify suction cups when right click on the issue - (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
This commit is contained in:
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## 24/06/2022 - v3.5.1
|
||||
|
||||
- **PCB Exposure:**
|
||||
- (Fix) Able to omit X or Y coordinate and use last known value in place
|
||||
- (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name
|
||||
- (Fix) Implement the inch measurement (%MOIN*%)
|
||||
- (Fix) Crash when redo the operation (Ctrl + Shift + Z)
|
||||
- **UI - Issue list:**
|
||||
- (Add) Context menu when right click issues to select an action
|
||||
- (Add) Option to solidify suction cups when right click on the issue
|
||||
- (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
|
||||
|
||||
## 19/06/2022 - v3.5.0
|
||||
|
||||
- **PCB Exposure:**
|
||||
|
||||
+8
-15
@@ -1,17 +1,10 @@
|
||||
- **PCB Exposure:**
|
||||
- (Add) Able to select multiple files and create a layer per file or merge them into one layer
|
||||
- (Add) Able to import files from a zip file
|
||||
- (Improvement) Round pixel coordinates and line thickness
|
||||
- (Improvement) Better position precision for primitives
|
||||
- (Improvement) Disable the ok button if no files were selected
|
||||
- (Change) Do not auto mirror based on printer lcd mirror type
|
||||
- (Fix) Limit line thickness to 1px minimum
|
||||
- (Fix) Allow leading zero omit from XY coordinates (#492)
|
||||
- (Fix) Mirror option was shifting the board position
|
||||
- (Add) Calibrate - Blooming effect: Generates test models with various strategies and increments to measure the blooming effect
|
||||
- (Add) Setting: Issues - Default order by, changes the default order on the issues list (#482)
|
||||
- (Improvement) CTBv4 and encrypted: Fetch `BottomWaitTimes` virtual property from first bottom layer that has at least 2 pixels (#483)
|
||||
- (Fix) Linux: Enable desktop integration for AppImages (#490)
|
||||
- (Fix) Extracting zip contents inside folders would cause a error and not extract those contents
|
||||
- (Upgrade) AvaloniaUI from 0.10.14 to 0.10.15 [Fixes auto-size problems]
|
||||
- (Fix) Able to omit X or Y coordinate and use last known value in place
|
||||
- (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name
|
||||
- (Fix) Implement the inch measurement (%MOIN*%)
|
||||
- (Fix) Crash when redo the operation (Ctrl + Shift + Z)
|
||||
- **UI - Issue list:**
|
||||
- (Add) Context menu when right click issues to select an action
|
||||
- (Add) Option to solidify suction cups when right click on the issue
|
||||
- (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Apertures;
|
||||
|
||||
@@ -29,13 +30,24 @@ public abstract class Aperture
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public GerberDocument Document { get; set; } = null!;
|
||||
|
||||
#endregion
|
||||
|
||||
protected Aperture() { }
|
||||
|
||||
protected Aperture(int index) { Index = index; }
|
||||
protected Aperture(string name) { Name = name; }
|
||||
protected Aperture(int index, string name) : this(index) { Name = name; }
|
||||
protected Aperture(GerberDocument document, int index)
|
||||
{
|
||||
Document = document;
|
||||
Index = index;
|
||||
}
|
||||
|
||||
protected Aperture(GerberDocument document, string name)
|
||||
{
|
||||
Document = document;
|
||||
Name = name;
|
||||
}
|
||||
protected Aperture(GerberDocument document, int index, string name) : this(document, index) { Name = name; }
|
||||
|
||||
public abstract void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected);
|
||||
|
||||
@@ -47,13 +59,12 @@ public abstract class Aperture
|
||||
if (!int.TryParse(match.Groups[1].Value, out var index)) return null;
|
||||
//if (!char.TryParse(match.Groups[2].Value, out var type)) return null;
|
||||
|
||||
|
||||
switch (match.Groups[2].Value)
|
||||
{
|
||||
case "C":
|
||||
{
|
||||
if (!double.TryParse(match.Groups[3].Value, out var diameter)) return null;
|
||||
return new CircleAperture(index, diameter);
|
||||
return new CircleAperture(document, index, diameter);
|
||||
}
|
||||
case "O":
|
||||
{
|
||||
@@ -62,7 +73,7 @@ public abstract class Aperture
|
||||
if (!float.TryParse(split[0], out var width)) return null;
|
||||
if (!float.TryParse(split[1], out var height)) return null;
|
||||
|
||||
return new EllipseAperture(index, width, height);
|
||||
return new EllipseAperture(document, index, width, height);
|
||||
}
|
||||
case "R":
|
||||
{
|
||||
@@ -71,7 +82,7 @@ public abstract class Aperture
|
||||
if (!float.TryParse(split[0], out var width)) return null;
|
||||
if (!float.TryParse(split[1], out var height)) return null;
|
||||
|
||||
return new RectangleAperture(index, width, height);
|
||||
return new RectangleAperture(document, index, width, height);
|
||||
}
|
||||
case "P":
|
||||
{
|
||||
@@ -80,11 +91,12 @@ public abstract class Aperture
|
||||
if (!double.TryParse(split[0], out var diameter)) return null;
|
||||
if (!ushort.TryParse(split[1], out var vertices)) return null;
|
||||
|
||||
return new PolygonAperture(index, diameter, vertices);
|
||||
return new PolygonAperture(document, index, diameter, vertices);
|
||||
}
|
||||
default: // macro
|
||||
{
|
||||
if (!document.Macros.TryGetValue(match.Groups[2].Value, out var macro)) return null;
|
||||
macro = macro.Clone();
|
||||
var parseLine = line.TrimEnd('%', '*');
|
||||
var commaIndex = parseLine.IndexOf(',')+1;
|
||||
if (commaIndex == 0) return null;
|
||||
@@ -92,10 +104,10 @@ public abstract class Aperture
|
||||
var args = new[] {"0"}.Concat(parseLine.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)).ToArray();
|
||||
foreach (var primitive in macro)
|
||||
{
|
||||
primitive.ParseExpressions(args);
|
||||
primitive.ParseExpressions(document, args);
|
||||
}
|
||||
|
||||
return new MacroAperture(index, macro);
|
||||
return new MacroAperture(document, index, macro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
@@ -22,11 +21,11 @@ public class CircleAperture : Aperture
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public CircleAperture() : base("Circle") { }
|
||||
public CircleAperture(GerberDocument document) : base(document, "Circle") { }
|
||||
|
||||
public CircleAperture(int index, double diameter) : base(index, "Circle")
|
||||
public CircleAperture(GerberDocument document, int index, double diameter) : base(document, index, "Circle")
|
||||
{
|
||||
Diameter = diameter;
|
||||
Diameter = document.GetMillimeters(diameter);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -20,16 +20,16 @@ public class EllipseAperture : Aperture
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public EllipseAperture() : base("Ellipse") { }
|
||||
public EllipseAperture(GerberDocument document) : base(document, "Ellipse") { }
|
||||
|
||||
public EllipseAperture(int index, float width, float height) : base(index, "Ellipse")
|
||||
public EllipseAperture(GerberDocument document, int index, float width, float height) : this(document, index, new SizeF(width, height))
|
||||
{
|
||||
Axes = new SizeF(width, height);
|
||||
|
||||
}
|
||||
|
||||
public EllipseAperture(int index, SizeF axes) : base(index, "Ellipse")
|
||||
public EllipseAperture(GerberDocument document, int index, SizeF axes) : base(document, index, "Ellipse")
|
||||
{
|
||||
Axes = axes;
|
||||
Axes = document.GetMillimeters(axes);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ public class MacroAperture : Aperture
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public MacroAperture() : base("Macro") { }
|
||||
public MacroAperture(GerberDocument document) : base(document, "Macro") { }
|
||||
|
||||
public MacroAperture(int index, Macro macro) : base(index, "Macro")
|
||||
public MacroAperture(GerberDocument document, int index, Macro macro) : base(document, index, "Macro")
|
||||
{
|
||||
Macro = macro;
|
||||
}
|
||||
@@ -31,9 +31,10 @@ public class MacroAperture : Aperture
|
||||
|
||||
public override void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
foreach (var macro in Macro)
|
||||
foreach (var primitive in Macro)
|
||||
{
|
||||
macro.DrawFlashD3(mat, xyPpmm, at, color, lineType);
|
||||
//if(primitive.Name == "Comment") continue;
|
||||
primitive.DrawFlashD3(mat, xyPpmm, at, color, lineType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,11 @@ public class PolygonAperture : Aperture
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public PolygonAperture() : base("Polygon") { }
|
||||
public PolygonAperture(GerberDocument document) : base(document, "Polygon") { }
|
||||
|
||||
public PolygonAperture(int index, double diameter, ushort vertices) : base(index, "Polygon")
|
||||
public PolygonAperture(GerberDocument document, int index, double diameter, ushort vertices) : base(document, index, "Polygon")
|
||||
{
|
||||
Diameter = diameter;
|
||||
Diameter = document.GetMillimeters(diameter);
|
||||
Vertices = vertices;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -21,16 +21,14 @@ public class RectangleAperture : Aperture
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public RectangleAperture() : base("Rectangle") { }
|
||||
public RectangleAperture(GerberDocument document) : base(document, "Rectangle") { }
|
||||
|
||||
public RectangleAperture(int index, float width, float height) : base(index, "Rectangle")
|
||||
{
|
||||
Size = new SizeF(width, height);
|
||||
}
|
||||
public RectangleAperture(GerberDocument document, int index, float width, float height) : this(document, index, new SizeF(width, height))
|
||||
{ }
|
||||
|
||||
public RectangleAperture(int index, SizeF size) : base(index, "Rectangle")
|
||||
public RectangleAperture(GerberDocument document, int index, SizeF size) : base(document, index, "Rectangle")
|
||||
{
|
||||
Size = size;
|
||||
Size = document.GetMillimeters(size);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Gerber.Apertures;
|
||||
@@ -166,6 +167,8 @@ public class GerberDocument
|
||||
using var vec = new VectorOfPoint(regionPoints.ToArray());
|
||||
CvInvoke.FillPoly(mat, vec, document.Polarity == GerberPolarityType.Dark ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor, enableAntialiasing ? LineType.AntiAlias : LineType.EightConnected);
|
||||
}
|
||||
//CvInvoke.Imshow("G37", mat);
|
||||
//CvInvoke.WaitKey();
|
||||
regionPoints.Clear();
|
||||
continue;
|
||||
}
|
||||
@@ -228,9 +231,15 @@ public class GerberDocument
|
||||
var fraction = matchX.Groups[1].Value.Substring(matchX.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits);
|
||||
double.TryParse($"{integers}.{fraction}", out nowX);
|
||||
}
|
||||
|
||||
nowX = document.GetMillimeters(nowX);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nowX = currentX;
|
||||
}
|
||||
|
||||
if (matchY.Success && matchY.Groups.Count >= 2)
|
||||
{
|
||||
@@ -248,9 +257,14 @@ public class GerberDocument
|
||||
var fraction = matchY.Groups[1].Value.Substring(matchY.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits);
|
||||
double.TryParse($"{integers}.{fraction}", out nowY);
|
||||
}
|
||||
nowY = document.GetMillimeters(nowY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nowY = currentY;
|
||||
}
|
||||
|
||||
if (insideRegion)
|
||||
{
|
||||
@@ -294,7 +308,7 @@ public class GerberDocument
|
||||
var fraction = matchI.Groups[1].Value.Substring(matchI.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits);
|
||||
double.TryParse($"{integers}.{fraction}", out xOffset);
|
||||
}
|
||||
|
||||
xOffset = document.GetMillimeters(xOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,6 +326,7 @@ public class GerberDocument
|
||||
var fraction = matchJ.Groups[1].Value.Substring(matchJ.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits);
|
||||
double.TryParse($"{integers}.{fraction}", out yOffset);
|
||||
}
|
||||
yOffset = document.GetMillimeters(yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,6 +369,8 @@ public class GerberDocument
|
||||
{
|
||||
currentAperture.DrawFlashD3(mat, xyPpmm, new PointF((float) nowX, (float) nowY),
|
||||
document.Polarity == GerberPolarityType.Dark ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor, enableAntialiasing ? LineType.AntiAlias : LineType.EightConnected);
|
||||
//CvInvoke.Imshow("G37", mat);
|
||||
//CvInvoke.WaitKey();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,6 +383,30 @@ public class GerberDocument
|
||||
return document;
|
||||
}
|
||||
|
||||
public float GetMillimeters(float size)
|
||||
{
|
||||
if (UnitType == GerberUnitType.Millimeter) return size;
|
||||
return size * 25.4f;
|
||||
}
|
||||
|
||||
public double GetMillimeters(double size)
|
||||
{
|
||||
if (UnitType == GerberUnitType.Millimeter) return size;
|
||||
return size * 25.4;
|
||||
}
|
||||
|
||||
public SizeF GetMillimeters(SizeF size)
|
||||
{
|
||||
if (UnitType == GerberUnitType.Millimeter) return size;
|
||||
return new SizeF(size.Width * 25.4f, size.Height * 25.4f);
|
||||
}
|
||||
|
||||
public PointF GetMillimeters(PointF point)
|
||||
{
|
||||
if (UnitType == GerberUnitType.Millimeter) return point;
|
||||
return new PointF(point.X * 25.4f, point.Y * 25.4f);
|
||||
}
|
||||
|
||||
public static Point PositionMmToPx(PointF atMm, SizeF xyPpmm)
|
||||
=> new((int)Math.Round(atMm.X * xyPpmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round(atMm.Y * xyPpmm.Height, MidpointRounding.AwayFromZero));
|
||||
|
||||
|
||||
@@ -89,6 +89,17 @@ public class Macro : IReadOnlyList<Primitive>
|
||||
}
|
||||
}
|
||||
|
||||
public Macro Clone()
|
||||
{
|
||||
var macro = new Macro(Name);
|
||||
foreach (var primitive in Primitives)
|
||||
{
|
||||
macro.Primitives.Add(primitive.Clone());
|
||||
}
|
||||
|
||||
return macro;
|
||||
}
|
||||
|
||||
|
||||
public static Macro? Parse(string line)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -104,7 +103,7 @@ public class CenterLinePrimitive : Primitive
|
||||
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
float num;
|
||||
@@ -126,6 +125,7 @@ public class CenterLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) Width = val;
|
||||
}
|
||||
Width = document.GetMillimeters(Width);
|
||||
|
||||
if (float.TryParse(HeightExpression, out num)) Height = num;
|
||||
else
|
||||
@@ -135,6 +135,7 @@ public class CenterLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) Height = val;
|
||||
}
|
||||
Height = document.GetMillimeters(Height);
|
||||
|
||||
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
|
||||
else
|
||||
@@ -144,6 +145,7 @@ public class CenterLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
else
|
||||
@@ -153,6 +155,7 @@ public class CenterLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
else
|
||||
|
||||
@@ -92,7 +92,7 @@ public class CirclePrimitive : Primitive
|
||||
GerberDocument.SizeMmToPx(Diameter / 2, xyPpmm.Max()), color, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
float num;
|
||||
@@ -114,6 +114,7 @@ public class CirclePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Diameter = num;
|
||||
}
|
||||
Diameter = document.GetMillimeters(Diameter);
|
||||
|
||||
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
|
||||
else
|
||||
@@ -123,6 +124,7 @@ public class CirclePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
else
|
||||
@@ -132,6 +134,7 @@ public class CirclePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
|
||||
@@ -50,7 +50,7 @@ public class CommentPrimitive : Primitive
|
||||
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
@@ -94,7 +95,7 @@ public class OutlinePrimitive : Primitive
|
||||
CvInvoke.FillPoly(mat, vec, color, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
float num;
|
||||
@@ -125,7 +126,7 @@ public class OutlinePrimitive : Primitive
|
||||
}
|
||||
else
|
||||
{
|
||||
coordinates.Add(new PointF(x.Value, num));
|
||||
coordinates.Add(document.GetMillimeters(new PointF(x.Value, num)));
|
||||
x = null;
|
||||
}
|
||||
}
|
||||
@@ -143,4 +144,12 @@ public class OutlinePrimitive : Primitive
|
||||
|
||||
IsParsed = true;
|
||||
}
|
||||
|
||||
public override Primitive Clone()
|
||||
{
|
||||
var primitive = MemberwiseClone() as OutlinePrimitive;
|
||||
primitive!.CoordinatesExpression = primitive.CoordinatesExpression.ToArray();
|
||||
primitive.Coordinates = primitive.Coordinates.ToArray();
|
||||
return primitive;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -101,7 +100,7 @@ public class PolygonPrimitive : Primitive
|
||||
color, 0, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
float num;
|
||||
@@ -132,6 +131,7 @@ public class PolygonPrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
else
|
||||
@@ -141,6 +141,7 @@ public class PolygonPrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
|
||||
if (float.TryParse(DiameterExpression, out num)) Diameter = num;
|
||||
else
|
||||
@@ -150,7 +151,7 @@ public class PolygonPrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Diameter = num;
|
||||
}
|
||||
|
||||
Diameter = document.GetMillimeters(Diameter);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
else
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
@@ -26,5 +27,7 @@ public abstract class Primitive
|
||||
|
||||
public abstract void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected);
|
||||
|
||||
public abstract void ParseExpressions(params string[] args);
|
||||
public abstract void ParseExpressions(GerberDocument document, params string[] args);
|
||||
|
||||
public virtual Primitive Clone() => (Primitive)MemberwiseClone();
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -112,7 +111,7 @@ public class VectorLinePrimitive : Primitive
|
||||
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(params string[] args)
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
float num;
|
||||
@@ -134,6 +133,7 @@ public class VectorLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) LineWidth = val;
|
||||
}
|
||||
LineWidth = document.GetMillimeters(LineWidth);
|
||||
|
||||
if (float.TryParse(StartXExpression, out num)) StartX = num;
|
||||
else
|
||||
@@ -143,6 +143,7 @@ public class VectorLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) StartX = num;
|
||||
}
|
||||
StartX = document.GetMillimeters(StartX);
|
||||
|
||||
if (float.TryParse(EndXExpression, out num)) EndX = num;
|
||||
else
|
||||
@@ -152,6 +153,7 @@ public class VectorLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) EndX = num;
|
||||
}
|
||||
EndX = document.GetMillimeters(EndX);
|
||||
|
||||
if (float.TryParse(StartYExpression, out num)) StartY = num;
|
||||
else
|
||||
@@ -161,6 +163,7 @@ public class VectorLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) StartY = num;
|
||||
}
|
||||
StartY = document.GetMillimeters(StartY);
|
||||
|
||||
if (float.TryParse(EndYExpression, out num)) EndY = num;
|
||||
else
|
||||
@@ -170,7 +173,7 @@ public class VectorLinePrimitive : Primitive
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) EndY = num;
|
||||
}
|
||||
|
||||
EndY = document.GetMillimeters(EndY);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
else
|
||||
|
||||
@@ -30,6 +30,15 @@ public class MainIssue : IReadOnlyList<Issue>
|
||||
//HoleSandwich,
|
||||
}
|
||||
|
||||
public bool IsIsland => Type == IssueType.Island;
|
||||
public bool IsOverhang => Type == IssueType.Overhang;
|
||||
public bool IsResinTrap => Type == IssueType.ResinTrap;
|
||||
public bool IsSuctionCup => Type == IssueType.SuctionCup;
|
||||
public bool IsTouchingBound => Type == IssueType.TouchingBound;
|
||||
public bool IsPrintHeight => Type == IssueType.PrintHeight;
|
||||
public bool IsEmptyLayer => Type == IssueType.EmptyLayer;
|
||||
public bool IsDebug => Type == IssueType.Debug;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the issue type associated
|
||||
/// </summary>
|
||||
|
||||
@@ -313,6 +313,12 @@ public class OperationPCBExposure : Operation
|
||||
if (mergeMat is not null)
|
||||
{
|
||||
using var croppedMat = mergeMat.CropByBounds(20);
|
||||
/*if (_mirror)
|
||||
{
|
||||
var flip = SlicerFile.DisplayMirror;
|
||||
if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
|
||||
CvInvoke.Flip(croppedMat, croppedMat, (FlipType)flip);
|
||||
}*/
|
||||
using var bgrMat = new Mat();
|
||||
CvInvoke.CvtColor(croppedMat, bgrMat, ColorConversion.Gray2Bgr);
|
||||
SlicerFile.SetThumbnails(bgrMat);
|
||||
|
||||
@@ -34,7 +34,7 @@ public sealed class OperationSolidify : Operation
|
||||
|
||||
#region Overrides
|
||||
|
||||
public override string IconClass => "fa-solid fa-circle";
|
||||
public override string IconClass => "fa-solid fa-diamond";
|
||||
public override string Title => "Solidify";
|
||||
|
||||
public override string Description =>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
|
||||
<Version>3.5.0</Version>
|
||||
<Version>3.5.1</Version>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<?define ComponentRules="OneToOne"?>
|
||||
<!-- SourceDir instructs IsWiX the location of the directory that contains files for this merge module -->
|
||||
<?define SourceDir="..\publish\UVtools_win-x64_v3.5.0"?>
|
||||
<?define SourceDir="..\publish\UVtools_win-x64_v3.5.1"?>
|
||||
<Module Id="UVtools" Language="1033" Version="1.0.0.0">
|
||||
<Package Id="12aaa1cf-ff06-4a02-abd5-2ac01ac4f83b" Manufacturer="PTRTECH" InstallerVersion="200" Keywords="MSLA, DLP" Description="MSLA/DLP, file analysis, repair, conversion and manipulation" InstallScope="perMachine" Platform="x64" />
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace UVtools.WPF.Controls.Tools
|
||||
};
|
||||
_timer.Stop();
|
||||
_timer.Start();
|
||||
ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
|
||||
if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
|
||||
Operation.Files.CollectionChanged += (sender, e) => ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -115,20 +115,65 @@ public partial class MainWindow
|
||||
return retValue;
|
||||
}*/
|
||||
|
||||
public async void OnClickIssueRemove()
|
||||
public async void RemoveRepairIssues(IEnumerable<MainIssue> issues, bool promptConfirmation = true, bool suctionCupDrill = true)
|
||||
{
|
||||
if (IssuesGrid.SelectedItems.Count == 0) return;
|
||||
if (!issues.Any()) return;
|
||||
|
||||
if (await this.MessageBoxQuestion($"Are you sure you want to remove all selected {IssuesGrid.SelectedItems.Count} issues?\n\n" +
|
||||
"Warning: Removing an island can cause other issues to appear if there is material present in the layers above it.\n" +
|
||||
"Always check previous and next layers before performing an island removal.", $"Remove {IssuesGrid.SelectedItems.Count} Issues?") != ButtonResult.Yes) return;
|
||||
uint emptyLayers = 0;
|
||||
uint islands = 0;
|
||||
uint resinTraps = 0;
|
||||
uint suctionCups = 0;
|
||||
foreach (MainIssue mainIssue in issues)
|
||||
{
|
||||
switch (mainIssue.Type)
|
||||
{
|
||||
case MainIssue.IssueType.Island:
|
||||
islands++;
|
||||
break;
|
||||
case MainIssue.IssueType.Overhang:
|
||||
// No action
|
||||
break;
|
||||
case MainIssue.IssueType.ResinTrap:
|
||||
resinTraps++;
|
||||
break;
|
||||
case MainIssue.IssueType.SuctionCup:
|
||||
suctionCups++;
|
||||
break;
|
||||
case MainIssue.IssueType.TouchingBound:
|
||||
// No action
|
||||
break;
|
||||
case MainIssue.IssueType.PrintHeight:
|
||||
// No action
|
||||
break;
|
||||
case MainIssue.IssueType.EmptyLayer:
|
||||
emptyLayers++;
|
||||
break;
|
||||
case MainIssue.IssueType.Debug:
|
||||
// No action
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
if (emptyLayers == 0 && islands == 0 && resinTraps == 0 && suctionCups == 0) return;
|
||||
|
||||
if (promptConfirmation && await this.MessageBoxQuestion(
|
||||
$"Are you sure you want to remove and/or repair all selected {issues.Count()} issues?\n\n" +
|
||||
"If any, this option will:\n" +
|
||||
(emptyLayers > 0 ? $"- Remove {emptyLayers} empty layer(s)\n" : string.Empty) +
|
||||
(islands > 0 ? $"- Remove {emptyLayers} island(s)\n" : string.Empty) +
|
||||
(resinTraps > 0 ? $"- Fill/solidify {resinTraps} resin trap(s)\n" : string.Empty) +
|
||||
(suctionCups > 0 ? $"- Drill {suctionCups} suction cup(s) at it's center\n" : string.Empty) +
|
||||
"\nWarning: Removing an island can cause other issues to appear if there is material present in the layers above it.\n" +
|
||||
"Always check previous and next layers before performing an island removal.", $"Remove {issues.Count()} Issues?") != ButtonResult.Yes) return;
|
||||
|
||||
var processParallelIssues = new Dictionary<uint, List<Issue>>();
|
||||
var processSuctionCups = new List<MainIssue>();
|
||||
var layersToRemove = new List<uint>();
|
||||
|
||||
|
||||
foreach (MainIssue mainIssue in IssuesGrid.SelectedItems)
|
||||
foreach (MainIssue mainIssue in issues)
|
||||
{
|
||||
switch (mainIssue.Type)
|
||||
{
|
||||
@@ -148,6 +193,22 @@ public partial class MainWindow
|
||||
}
|
||||
continue;
|
||||
case MainIssue.IssueType.SuctionCup:
|
||||
if (!suctionCupDrill)
|
||||
{
|
||||
foreach (var issue in mainIssue)
|
||||
{
|
||||
// Islands and resin traps
|
||||
if (!processParallelIssues.TryGetValue(issue.LayerIndex, out var issueList))
|
||||
{
|
||||
issueList = new List<Issue>();
|
||||
processParallelIssues.Add(issue.LayerIndex, issueList);
|
||||
}
|
||||
|
||||
issueList.Add(issue);
|
||||
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(mainIssue.StartLayerIndex == 0) continue;
|
||||
processSuctionCups.Add(mainIssue);
|
||||
continue;
|
||||
@@ -192,7 +253,7 @@ public partial class MainWindow
|
||||
|
||||
edited = true;
|
||||
}
|
||||
else if (issue.Type == MainIssue.IssueType.ResinTrap)
|
||||
else if (issue.Type == MainIssue.IssueType.ResinTrap || (issue.Type == MainIssue.IssueType.SuctionCup && !suctionCupDrill))
|
||||
{
|
||||
var issueOfContours = (IssueOfContours)issue;
|
||||
using var contours = new VectorOfVectorOfPoint(issueOfContours.Contours);
|
||||
@@ -219,13 +280,13 @@ public partial class MainWindow
|
||||
OperationLayerRemove.RemoveLayers(SlicerFile, layersToRemove);
|
||||
}
|
||||
|
||||
issueRemoveList.AddRange(SlicerFile.IssueManager.DrillSuctionCupsForIssues(processSuctionCups, UserSettings.Instance.LayerRepair.SuctionCupsVentHole, Progress));
|
||||
if(suctionCupDrill) issueRemoveList.AddRange(SlicerFile.IssueManager.DrillSuctionCupsForIssues(processSuctionCups, UserSettings.Instance.LayerRepair.SuctionCupsVentHole, Progress));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
await this.MessageBoxError(ex.ToString(), "Removal failed"));
|
||||
await this.MessageBoxError(ex.ToString(), "Removal/repair failed"));
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -245,8 +306,14 @@ public partial class MainWindow
|
||||
|
||||
// Update GUI
|
||||
|
||||
foreach (MainIssue issue in IssuesGrid.SelectedItems)
|
||||
foreach (MainIssue issue in issues)
|
||||
{
|
||||
if (issue.IsSuctionCup && !suctionCupDrill)
|
||||
{
|
||||
issueRemoveList.Add(issue);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (issue.Type
|
||||
is not MainIssue.IssueType.Island
|
||||
and not MainIssue.IssueType.ResinTrap
|
||||
@@ -256,7 +323,7 @@ public partial class MainWindow
|
||||
issueRemoveList.Add(issue);
|
||||
|
||||
|
||||
if (issue.Type == MainIssue.IssueType.Island)
|
||||
if (issue.IsIsland)
|
||||
{
|
||||
var nextLayer = issue.StartLayerIndex + 1;
|
||||
if (nextLayer >= SlicerFile.LayerCount) continue;
|
||||
@@ -289,6 +356,41 @@ public partial class MainWindow
|
||||
CanSave = true;
|
||||
}
|
||||
|
||||
public void OnClickIssueRemove()
|
||||
{
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>(), true);
|
||||
}
|
||||
|
||||
public void SelectedIssuesIslandRemove()
|
||||
{
|
||||
if (IssuesGrid.SelectedItem is null) return;
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsIsland), false);
|
||||
}
|
||||
|
||||
public void SelectedIssuesResinTrapSolidify()
|
||||
{
|
||||
if (IssuesGrid.SelectedItem is null) return;
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsResinTrap), false);
|
||||
}
|
||||
|
||||
public void SelectedIssuesSuctionCupDrill()
|
||||
{
|
||||
if (IssuesGrid.SelectedItem is null) return;
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsSuctionCup), false);
|
||||
}
|
||||
|
||||
public void SelectedIssuesSuctionCupSolidify()
|
||||
{
|
||||
if (IssuesGrid.SelectedItem is null) return;
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsSuctionCup), false, false);
|
||||
}
|
||||
|
||||
public void SelectedIssuesEmptyLayerRemove()
|
||||
{
|
||||
if (IssuesGrid.SelectedItem is null) return;
|
||||
RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsEmptyLayer), false);
|
||||
}
|
||||
|
||||
public async void OnClickIssueIgnore()
|
||||
{
|
||||
if ((_globalModifiers & KeyModifiers.Alt) != 0)
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
<WrapPanel
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding SlicerFile.LayerHeight, StringFormat=Layer height: \{0\}mm}"/>
|
||||
<TextBlock Text="{Binding SlicerFile.LayerHeight, StringFormat=Layer height: {0}mm}"/>
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.CanUseBottomLayerCount}" Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.CanUseBottomLayerCount}"
|
||||
@@ -266,28 +266,28 @@
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}" Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}"
|
||||
Text="{Binding SlicerFile.PrintTimeString, StringFormat=Print time: \{0\}}"/>
|
||||
Text="{Binding SlicerFile.PrintTimeString, StringFormat=Print time: {0}}"/>
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialMilliliters}" Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialMilliliters}"
|
||||
Text="{Binding SlicerFile.MaterialMilliliters, StringFormat=Used material: \{0\}ml}"/>
|
||||
Text="{Binding SlicerFile.MaterialMilliliters, StringFormat=Used material: {0}ml}"/>
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: \{0\}€}"/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: {0}€}"/>
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Text="{Binding SlicerFile.MaterialName, StringFormat=Material: \{0\}}"/>
|
||||
Text="{Binding SlicerFile.MaterialName, StringFormat=Material: {0}}"/>
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MachineName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MachineName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Text="{Binding SlicerFile.MachineName, StringFormat=Machine: \{0\}}"/>
|
||||
Text="{Binding SlicerFile.MachineName, StringFormat=Machine: {0}}"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
|
||||
@@ -385,13 +385,13 @@
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding SlicerProperties.Count, StringFormat=Properties: \{0\}}"/>
|
||||
Text="{Binding SlicerProperties.Count, StringFormat=Properties: {0}}"/>
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Text="|"/>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding SlicerFile.Configs.Length, StringFormat=Groups: \{0\}}"/>
|
||||
Text="{Binding SlicerFile.Configs.Length, StringFormat=Groups: {0}}"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
@@ -510,12 +510,12 @@
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="5">
|
||||
<TextBlock
|
||||
Text="{Binding GCodeLines, StringFormat=Lines: \{0\}}"
|
||||
Text="{Binding GCodeLines, StringFormat=Lines: {0}}"
|
||||
VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Text="|" VerticalAlignment="Center"/>
|
||||
|
||||
<TextBlock Text="{Binding #GCodeText.Text.Length, StringFormat=Chars: \{0\}}"
|
||||
<TextBlock Text="{Binding #GCodeText.Text.Length, StringFormat=Chars: {0}}"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
@@ -640,19 +640,17 @@
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
<StackPanel Grid.Row="0"
|
||||
Orientation="Horizontal"
|
||||
Spacing="2"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
|
||||
<Button
|
||||
IsEnabled="{Binding IsFileLoaded}"
|
||||
ToolTip.Tip="Attempt to repair issues"
|
||||
VerticalAlignment="Stretch"
|
||||
i:Attached.Icon="fa-solid fa-toolbox"
|
||||
Command="{Binding OnClickRepairIssues}"/>
|
||||
<Button IsEnabled="{Binding IsFileLoaded}"
|
||||
ToolTip.Tip="Attempt to repair issues"
|
||||
VerticalAlignment="Stretch"
|
||||
i:Attached.Icon="fa-solid fa-toolbox"
|
||||
Command="{Binding OnClickRepairIssues}"/>
|
||||
|
||||
<uc:ButtonWithIcon VerticalAlignment="Stretch"
|
||||
ToolTip.Tip="Compute Issues.
|
||||
@@ -736,7 +734,18 @@
|
||||
IsReadOnly="True"
|
||||
ClipboardCopyMode="None"
|
||||
Items="{Binding IssuesGridItems}">
|
||||
<DataGrid.Columns>
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu IsVisible="{Binding #IssuesGrid.SelectedItem, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-eye-slash" Command="{Binding OnClickIssueIgnore}" Header="Ignore issue(s)"/>
|
||||
<Separator/>
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-trash-can" Command="{Binding SelectedIssuesIslandRemove}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsIsland}" Header="Remove island(s)"/>
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-diamond" Command="{Binding SelectedIssuesResinTrapSolidify}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsResinTrap}" Header="Fill/solidify resin trap(s)"/>
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-circle-dot" Command="{Binding SelectedIssuesSuctionCupDrill}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsSuctionCup}" Header="Drill suction cup(s)"/>
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-diamond" Command="{Binding SelectedIssuesSuctionCupSolidify}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsSuctionCup}" Header="Fill/solidify suction cup(s)"/>
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-trash-can" Command="{Binding SelectedIssuesEmptyLayerRemove}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsEmptyLayer}" Header="Remove empty layer(s)"/>
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTextColumn Header="Type"
|
||||
Binding="{Binding Type}"
|
||||
@@ -1003,7 +1012,7 @@
|
||||
Grid.Row="10"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelDrawing.RemovePixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelDrawing.RemovePixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
@@ -1022,7 +1031,7 @@
|
||||
Grid.Row="12"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelDrawing.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelDrawing.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="14"
|
||||
@@ -1187,7 +1196,7 @@
|
||||
Grid.Row="16"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelText.RemovePixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelText.RemovePixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="18"
|
||||
@@ -1205,7 +1214,7 @@
|
||||
Grid.Row="18"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelText.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelText.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
|
||||
<TextBlock
|
||||
@@ -1269,7 +1278,7 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelEraser.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelEraser.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
@@ -1365,7 +1374,7 @@
|
||||
Grid.Row="6"
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding DrawingPixelSupport.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
|
||||
Text="{Binding DrawingPixelSupport.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
|
||||
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
@@ -1434,7 +1443,7 @@
|
||||
<uc:ButtonWithIcon IsEnabled="{Binding Drawings.Count}"
|
||||
Icon="fa-solid fa-check"
|
||||
Spacing="5"
|
||||
Text="{Binding Drawings.Count, StringFormat=Apply \{0\} operations}"
|
||||
Text="{Binding Drawings.Count, StringFormat=Apply {0} operations}"
|
||||
Command="{Binding DrawModifications}"
|
||||
CommandParameter="false"/>
|
||||
</StackPanel>
|
||||
@@ -2072,7 +2081,7 @@
|
||||
<TextBlock
|
||||
ToolTip.Tip="Layer preview computation time."
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center" Text="{Binding ShowLayerRenderMs, StringFormat=\{0\}ms}"/>
|
||||
VerticalAlignment="Center" Text="{Binding ShowLayerRenderMs, StringFormat={}{0}ms}"/>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -2095,7 +2104,7 @@
|
||||
Margin="10" Text="{Binding Progress.Title}"/>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="10,0,10,10" Text="{Binding Progress.ElapsedTimeStr, StringFormat=Elapsed Time: \{0\}}"/>
|
||||
Margin="10,0,10,10" Text="{Binding Progress.ElapsedTimeStr, StringFormat=Elapsed Time: {0}}"/>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="10,0,10,10" Text="{Binding Progress.Description}" HorizontalAlignment="Center"/>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<Version>3.5.0</Version>
|
||||
<Version>3.5.1</Version>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
|
||||
Reference in New Issue
Block a user