Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md19
-rw-r--r--CREDITS.md3
-rw-r--r--Scripts/010 Editor/ctb.bt (renamed from Scripts/ctb.bt)0
-rw-r--r--Scripts/010 Editor/cxdlp_v1.bt (renamed from Scripts/cxdlp_v1.bt)0
-rw-r--r--Scripts/010 Editor/cxdlp_v2.bt (renamed from Scripts/cxdlp_v2.bt)0
-rw-r--r--Scripts/010 Editor/gr1.bt (renamed from Scripts/gr1.bt)0
-rw-r--r--Scripts/010 Editor/lgs.bt (renamed from Scripts/lgs.bt)0
-rw-r--r--Scripts/010 Editor/mdlp.bt (renamed from Scripts/mdlp.bt)0
-rw-r--r--Scripts/010 Editor/photons.bt (renamed from Scripts/photons.bt)0
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs37
-rw-r--r--UVtools.Core/FileFormats/ChituboxZipFile.cs4
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs9
-rw-r--r--UVtools.Core/FileFormats/ZCodeFile.cs4
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs197
-rw-r--r--UVtools.Core/Layer/LayerManager.cs13
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExposureFinder.cs137
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.InstallerMM/UVtools.InstallerMM.wxs7
-rw-r--r--UVtools.ScriptSample/ScriptCustomGCode.cs154
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml91
-rw-r--r--UVtools.WPF/ErrorLog.cs4
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj2
-rw-r--r--build/CreateRelease.WPF.ps16
23 files changed, 512 insertions, 177 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b3f2ca7..69d5756 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,22 @@
# Changelog
+## 11/06/2021 - v2.14.2
+
+- **Exposure time finder:**
+ - (Add) [ME] Option: 'Use different settings for layers with same Z positioning'
+ - (Add) [ME] Option: 'Lift height' for same Z positioned layers
+ - (Add) [ME] Option: 'Light-off delay' for same Z positioned layers
+ - (Improvement) Auto-detect and optimize the 'multiple exposures' test to decrease the print time, by set a minimal lift to almost none
+ - (Improvement) Better information on the thumbnail
+ - (Fix) Importing a profile would crash the application
+ - (Fix) Error with 'Pattern loaded model' fails when generating more models than build plate can afford (#239)
+- **GCode:**
+ - (Fix) When the last layer have no lifts and a move to top command is set on end, that value were being set incorrectly as last layer position
+ - (Fix) Layer parsing from mm/s to mm/m bad convertion
+- (Add) File formats: Setter `SuppressRebuildGCode` to disable or enable the gcode auto rebuild when needed, set this to false to manually write your own gcode
+- (Add) UVtools version to error logs
+- (Fix) ZCode: Some test files come with layer height of 0mm on a property, in that case lookup layer height on the second property as fallback
+
## 07/06/2021 - v2.14.1
- (Upgrade) EmguCV from 4.5.1 to 4.5.2
@@ -11,7 +28,7 @@
- (Fix) Division by 0 when start layer is equal to end layer
- (Fix) Calculations when using the option "Increase or decrease towards 100%"
- (Add) About window: OpenCV build number and a button to copy build information to clipboard
-- (Improvement) Exposure exposure finder: Improve the **Multiple brightness** section to auto fill with correct values for file formats that use time fractions to emulate AntiAliasing, this can be used to replace the **Multiple exposures** section
+- (Improvement) Exposure time finder: Improve the **Multiple brightness** section to auto fill with correct values for file formats that use time fractions to emulate AntiAliasing, this can be used to replace the **Multiple exposures** section
- (Fix) UVJ: Error when using a null or empty layer array on manifest `config.json` file (#232)
- (Fix) GCode parser: When only a G4/wait command is present on a layer it was setting the global exposure time and discard the this value per layer
diff --git a/CREDITS.md b/CREDITS.md
index 5975c5b..3127e5a 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -56,4 +56,5 @@
- James Kao
- Finn Newick
- Thomas Wilbert
-- Gary Kyle \ No newline at end of file
+- Gary Kyle
+- Peter Csaki \ No newline at end of file
diff --git a/Scripts/ctb.bt b/Scripts/010 Editor/ctb.bt
index 88ddc4b..88ddc4b 100644
--- a/Scripts/ctb.bt
+++ b/Scripts/010 Editor/ctb.bt
diff --git a/Scripts/cxdlp_v1.bt b/Scripts/010 Editor/cxdlp_v1.bt
index bc43eda..bc43eda 100644
--- a/Scripts/cxdlp_v1.bt
+++ b/Scripts/010 Editor/cxdlp_v1.bt
diff --git a/Scripts/cxdlp_v2.bt b/Scripts/010 Editor/cxdlp_v2.bt
index 3a33f30..3a33f30 100644
--- a/Scripts/cxdlp_v2.bt
+++ b/Scripts/010 Editor/cxdlp_v2.bt
diff --git a/Scripts/gr1.bt b/Scripts/010 Editor/gr1.bt
index c55b088..c55b088 100644
--- a/Scripts/gr1.bt
+++ b/Scripts/010 Editor/gr1.bt
diff --git a/Scripts/lgs.bt b/Scripts/010 Editor/lgs.bt
index 1f9e630..1f9e630 100644
--- a/Scripts/lgs.bt
+++ b/Scripts/010 Editor/lgs.bt
diff --git a/Scripts/mdlp.bt b/Scripts/010 Editor/mdlp.bt
index 501b06e..501b06e 100644
--- a/Scripts/mdlp.bt
+++ b/Scripts/010 Editor/mdlp.bt
diff --git a/Scripts/photons.bt b/Scripts/010 Editor/photons.bt
index bc04d37..bc04d37 100644
--- a/Scripts/photons.bt
+++ b/Scripts/010 Editor/photons.bt
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index 1a6cd42..d53b283 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -681,6 +681,8 @@ namespace UVtools.Core.Extensions
}
public static Size GetTextSizeExtended(string text, FontFace fontFace, double fontScale, int thickness, ref int baseLine, PutTextLineAlignment lineAlignment = default)
+ => GetTextSizeExtended(text, fontFace, fontScale, thickness, 0, ref baseLine, lineAlignment);
+ public static Size GetTextSizeExtended(string text, FontFace fontFace, double fontScale, int thickness, int lineGapOffset, ref int baseLine, PutTextLineAlignment lineAlignment = default)
{
text = text.TrimEnd('\n', '\r', ' ');
var lines = text.Split(StaticObjects.LineBreakCharacters, StringSplitOptions.None);
@@ -688,7 +690,7 @@ namespace UVtools.Core.Extensions
if (lines.Length is 0 or 1) return textSize;
- var lineGap = textSize.Height / 3;
+ var lineGap = textSize.Height / 3 + lineGapOffset;
var width = 0;
var height = lines.Length * (lineGap + textSize.Height) - lineGap;
@@ -706,11 +708,16 @@ namespace UVtools.Core.Extensions
return new(width, height);
}
- /// <summary>
- /// Extended OpenCV PutText to accepting line breaks and line alignment
- /// </summary>
public static void PutTextExtended(this Mat src, string text, Point org, FontFace fontFace, double fontScale,
- MCvScalar color, int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default)
+ MCvScalar color, int thickness = 1, LineType lineType = LineType.EightConnected,
+ bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default)
+ => src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, 0, lineType, bottomLeftOrigin, lineAlignment);
+
+ /// <summary>
+ /// Extended OpenCV PutText to accepting line breaks and line alignment
+ /// </summary>
+ public static void PutTextExtended(this Mat src, string text, Point org, FontFace fontFace, double fontScale,
+ MCvScalar color, int thickness = 1, int lineGapOffset = 0, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default)
{
text = text.TrimEnd('\n', '\r', ' ');
var lines = text.Split(StaticObjects.LineBreakCharacters, StringSplitOptions.None);
@@ -727,7 +734,7 @@ namespace UVtools.Core.Extensions
// Get height of text lines in pixels (height of all lines is the same)
int baseLine = 0;
var textSize = CvInvoke.GetTextSize(text, fontFace, fontScale, thickness, ref baseLine);
- var lineGap = textSize.Height / 3;
+ var lineGap = textSize.Height / 3 + lineGapOffset;
var linesSize = new Size[lines.Length];
int width = 0;
@@ -769,15 +776,25 @@ namespace UVtools.Core.Extensions
}
}
+ /// <summary>
+ /// Extended OpenCV PutText to accepting line breaks, line alignment and rotation
+ /// </summary>
+ public static void PutTextRotated(this Mat src, string text, Point org, FontFace fontFace, double fontScale,
+ MCvScalar color,
+ int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false,
+ PutTextLineAlignment lineAlignment = default, double angle = 0)
+ => src.PutTextRotated(text, org, fontFace, fontScale, color, thickness, 0, lineType, bottomLeftOrigin,
+ lineAlignment, angle);
+
/// <summary>
/// Extended OpenCV PutText to accepting line breaks, line alignment and rotation
/// </summary>
public static void PutTextRotated(this Mat src, string text, Point org, FontFace fontFace, double fontScale, MCvScalar color,
- int thickness = 1, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default, double angle = 0)
+ int thickness = 1, int lineGapOffset = 0, LineType lineType = LineType.EightConnected, bool bottomLeftOrigin = false, PutTextLineAlignment lineAlignment = default, double angle = 0)
{
if (angle % 360 == 0) // No rotation needed, cheaper cycle
{
- src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin, lineAlignment);
+ src.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment);
return;
}
@@ -786,10 +803,10 @@ namespace UVtools.Core.Extensions
var sizeDifference = (rotatedSrc.Size - src.Size).Half();
org.Offset(sizeDifference.ToPoint());
org = org.Rotate(-angle, new Point(rotatedSrc.Size.Width / 2, rotatedSrc.Size.Height / 2));
- rotatedSrc.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin, lineAlignment);
+ rotatedSrc.PutTextExtended(text, org, fontFace, fontScale, color, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment);
using var mask = rotatedSrc.NewBlank();
- mask.PutTextExtended(text, org, fontFace, fontScale, WhiteColor, thickness, lineType, bottomLeftOrigin, lineAlignment);
+ mask.PutTextExtended(text, org, fontFace, fontScale, WhiteColor, thickness, lineGapOffset, lineType, bottomLeftOrigin, lineAlignment);
rotatedSrc.Rotate(angle, src.Size);
mask.Rotate(angle, src.Size);
diff --git a/UVtools.Core/FileFormats/ChituboxZipFile.cs b/UVtools.Core/FileFormats/ChituboxZipFile.cs
index a3bd7bb..4f5c972 100644
--- a/UVtools.Core/FileFormats/ChituboxZipFile.cs
+++ b/UVtools.Core/FileFormats/ChituboxZipFile.cs
@@ -349,7 +349,7 @@ namespace UVtools.Core.FileFormats
{
using (ZipArchive outputFile = ZipFile.Open(fileFullPath, ZipArchiveMode.Create))
{
- if (Thumbnails.Length > 0 && !ReferenceEquals(Thumbnails[0], null))
+ if (Thumbnails.Length > 0 && Thumbnails[0] is not null)
{
using (Stream stream = outputFile.CreateEntry("preview.png").Open())
{
@@ -358,7 +358,7 @@ namespace UVtools.Core.FileFormats
}
}
- if (Thumbnails.Length > 1 && !ReferenceEquals(Thumbnails[1], null))
+ if (Thumbnails.Length > 1 && Thumbnails[1] is not null)
{
using (Stream stream = outputFile.CreateEntry("preview_cropping.png").Open())
{
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index e10e4e7..3b271b8 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -39,7 +39,7 @@ namespace UVtools.Core.FileFormats
private const string ExtractConfigFileExtension = "ini";
- public const float DefaultLayerHeight = 0.5f;
+ public const float DefaultLayerHeight = 0.05f;
public const ushort DefaultBottomLayerCount = 4;
public const float DefaultBottomExposureTime = 30;
@@ -1217,6 +1217,11 @@ namespace UVtools.Core.FileFormats
public bool HaveGCode => SupportsGCode && !GCode.IsEmpty;
/// <summary>
+ /// Disable or enable the gcode auto rebuild when needed, set this to false to manually write your own gcode
+ /// </summary>
+ public bool SuppressRebuildGCode { get; set; }
+
+ /// <summary>
/// Get all configuration objects with properties and values
/// </summary>
public abstract object[] Configs { get; }
@@ -2024,7 +2029,7 @@ namespace UVtools.Core.FileFormats
/// </summary>
public virtual void RebuildGCode()
{
- if (!SupportsGCode) return;
+ if (!SupportsGCode || SuppressRebuildGCode) return;
GCode.RebuildGCode(this);
}
diff --git a/UVtools.Core/FileFormats/ZCodeFile.cs b/UVtools.Core/FileFormats/ZCodeFile.cs
index ffff100..417ecc1 100644
--- a/UVtools.Core/FileFormats/ZCodeFile.cs
+++ b/UVtools.Core/FileFormats/ZCodeFile.cs
@@ -125,7 +125,7 @@ namespace UVtools.Core.FileFormats
public float VolumeMl { get; set; }
[XmlElement("thickness")]
- public float LayerHeight { get; set; }
+ public float LayerHeight { get; set; } = FileFormat.DefaultLayerHeight;
[XmlElement("price")]
public float Price { get; set; }
@@ -276,7 +276,7 @@ namespace UVtools.Core.FileFormats
public override float LayerHeight
{
- get => ManifestFile.Job.LayerHeight;
+ get => ManifestFile.Job.LayerHeight > 0 ? ManifestFile.Job.LayerHeight : ManifestFile.Profile.Slice.LayerHeight;
set
{
ManifestFile.Job.LayerHeight = ManifestFile.Profile.Slice.LayerHeight = Layer.RoundHeight(value);
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index 03c1d75..5e3d8a2 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -15,6 +15,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
+using Org.BouncyCastle.Asn1.Cms;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
@@ -29,8 +30,8 @@ namespace UVtools.Core.GCode
public GCodeCommand CommandPositioningAbsoluteG90 { get; } = new("G90", null, "Absolute positioning");
public GCodeCommand CommandPositioningPartialG91 { get; } = new("G91", null, "Partial positioning");
- public GCodeCommand CommandTurnMotorsOnM17 { get; } = new("M17", null, "Enable motors");
- public GCodeCommand CommandTurnMotorsOffM18 { get; } = new("M18", null, "Disable motors");
+ public GCodeCommand CommandMotorsOnM17 { get; } = new("M17", null, "Enable motors");
+ public GCodeCommand CommandMotorsOffM18 { get; } = new("M18", null, "Disable motors");
public GCodeCommand CommandHomeG28 { get; } = new("G28", "Z0", "Home Z");
@@ -289,7 +290,7 @@ namespace UVtools.Core.GCode
AppendUnitsMmG21();
AppendPositioningType();
AppendLightOffM106();
- AppendEnableMotors();
+ AppendMotorsOn();
AppendClearImage();
AppendHomeZG28();
AppendLineIfCanComment(EndStartGCodeComments);
@@ -305,7 +306,7 @@ namespace UVtools.Core.GCode
AppendMoveG0(raiseZ, feedRate);
}
- AppendDisableMotors();
+ AppendMotorsOff();
AppendLineIfCanComment(EndEndGCodeComments);
}
@@ -329,22 +330,22 @@ namespace UVtools.Core.GCode
}
}
- public void AppendEnableMotors()
+ public void AppendMotorsOn()
{
- AppendLine(CommandTurnMotorsOnM17);
+ AppendLine(CommandMotorsOnM17);
}
- public void AppendDisableMotors()
+ public void AppendMotorsOff()
{
- AppendLine(CommandTurnMotorsOffM18);
+ AppendLine(CommandMotorsOffM18);
}
public void AppendTurnMotors(bool enable)
{
if (enable)
- AppendEnableMotors();
+ AppendMotorsOn();
else
- AppendDisableMotors();
+ AppendMotorsOff();
}
public void AppendHomeZG28()
@@ -434,18 +435,13 @@ namespace UVtools.Core.GCode
AppendLine(CommandShowImageM6054, layerIndex);
}
- /*public void AppendLayer(Layer layer)
- {
-
- }*/
-
public string GetShowImageString(uint layerIndex) => _gCodeShowImageType switch
{
GCodeShowImageTypes.FilenameZeroPNG => $"{layerIndex}.png",
GCodeShowImageTypes.FilenameNonZeroPNG => $"{layerIndex + 1}.png",
GCodeShowImageTypes.LayerIndexZero => $"{layerIndex}",
GCodeShowImageTypes.LayerIndexNonZero => $"{layerIndex + 1}",
- _ => throw new ArgumentOutOfRangeException()
+ _ => throw new InvalidExpressionException($"Unhandled image type for {_gCodeShowImageType}")
};
public void RebuildGCode(FileFormat slicerFile, StringBuilder header) => RebuildGCode(slicerFile, header?.ToString());
@@ -470,14 +466,14 @@ namespace UVtools.Core.GCode
for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++)
{
var layer = slicerFile[layerIndex];
- float exposureTime = layer.ExposureTime;
+ float exposureTime = ConvertFromSeconds(layer.ExposureTime);
float liftHeight = layer.LiftHeight;
float liftZPos = Layer.RoundHeight(liftHeight + layer.PositionZ);
float liftZPosAbs = liftZPos;
- float liftSpeed = layer.LiftSpeed;
+ float liftSpeed = ConvertFromMillimetersPerMinute(layer.LiftSpeed);
float retractPos = layer.PositionZ;
- float retractSpeed = layer.RetractSpeed;
- float lightOffDelay = layer.LightOffDelay;
+ float retractSpeed = ConvertFromMillimetersPerMinute(layer.RetractSpeed);
+ float lightOffDelay = ConvertFromSeconds(layer.LightOffDelay);
ushort pwmValue = layer.LightPWM;
if (_maxLedPower != byte.MaxValue)
{
@@ -492,26 +488,6 @@ namespace UVtools.Core.GCode
break;
}
- switch (GCodeTimeUnit)
- {
- case GCodeTimeUnits.Milliseconds:
- exposureTime *= 1000;
- lightOffDelay *= 1000;
- break;
- }
-
- switch (GCodeSpeedUnit)
- {
- case GCodeSpeedUnits.MillimetersPerSecond:
- liftSpeed = (float)Math.Round(liftSpeed / 60, 2);
- retractSpeed = (float)Math.Round(retractSpeed / 60, 2);
- break;
- case GCodeSpeedUnits.CentimetersPerMinute:
- liftSpeed = (float)Math.Round(liftSpeed / 10, 2);
- retractSpeed = (float)Math.Round(retractSpeed / 10);
- break;
- }
-
AppendLineIfCanComment(BeginLayerComments, layerIndex, layer.PositionZ);
//if (layer.CanExpose)
@@ -555,15 +531,8 @@ namespace UVtools.Core.GCode
break;
}
- float endFeedRate = GCodeSpeedUnit switch
- {
- GCodeSpeedUnits.MillimetersPerMinute => slicerFile.RetractSpeed,
- GCodeSpeedUnits.MillimetersPerSecond => (float) Math.Round(slicerFile.RetractSpeed / 60, 2),
- GCodeSpeedUnits.CentimetersPerMinute => (float) Math.Round(slicerFile.RetractSpeed / 10, 2),
- _ => throw new InvalidExpressionException($"Unhandled feedrate unit for {GCodeSpeedUnit}")
- };
- AppendEndGCode(finalRaiseZPosition, endFeedRate);
+ AppendEndGCode(finalRaiseZPosition, ConvertFromMillimetersPerMinute(slicerFile.RetractSpeed));
}
public void RebuildGCode(FileFormat slicerFile, object[] configs, string separator = ":")
@@ -633,7 +602,7 @@ namespace UVtools.Core.GCode
var endStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex+1));
gcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length + 1);
var endStrIndex = gcode.IndexOf(endStr, StringComparison.Ordinal);
- var stripGcode = endStrIndex > 0 ? gcode.Substring(0, endStrIndex) : gcode;/*.Trim(' ', '\n', '\r', '\t');*/
+ var stripGcode = endStrIndex > 0 ? gcode[..endStrIndex] : gcode;/*.Trim(' ', '\n', '\r', '\t');*/
float liftHeight = 0;// this allow read back no lifts slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftHeight, slicerFile.LiftHeight);
float liftSpeed = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftSpeed, slicerFile.LiftSpeed);
@@ -650,26 +619,12 @@ namespace UVtools.Core.GCode
if (moveRegex.Count >= 1 && moveRegex[0].Success)
{
float liftPosTemp = float.Parse(moveRegex[0].Groups[1].Value, CultureInfo.InvariantCulture);
- float liftSpeedTemp = float.Parse(moveRegex[0].Groups[3].Value, CultureInfo.InvariantCulture);
-
- switch (GCodeSpeedUnit)
- {
- case GCodeSpeedUnits.MillimetersPerSecond:
- liftSpeedTemp = (float) Math.Round(liftSpeedTemp / 60, 2);
- break;
- case GCodeSpeedUnits.MillimetersPerMinute:
- break;
- case GCodeSpeedUnits.CentimetersPerMinute:
- liftSpeedTemp *= 10;
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
+ float liftSpeedTemp = ConvertToMillimetersPerMinute(float.Parse(moveRegex[0].Groups[3].Value, CultureInfo.InvariantCulture));
if (moveRegex.Count >= 2 && moveRegex[1].Success)
{
float retractPos = float.Parse(moveRegex[1].Groups[1].Value, CultureInfo.InvariantCulture);
- retractSpeed = float.Parse(moveRegex[1].Groups[3].Value, CultureInfo.InvariantCulture);
+ retractSpeed = ConvertToMillimetersPerMinute(float.Parse(moveRegex[1].Groups[3].Value, CultureInfo.InvariantCulture));
liftSpeed = liftSpeedTemp;
switch (positionType)
@@ -683,33 +638,21 @@ namespace UVtools.Core.GCode
positionZ = Layer.RoundHeight(positionZ + liftPosTemp + retractPos);
break;
}
-
- switch (GCodeSpeedUnit)
- {
- case GCodeSpeedUnits.MillimetersPerSecond:
- retractSpeed = (float)Math.Round(retractSpeed / 60, 2);
- break;
- case GCodeSpeedUnits.MillimetersPerMinute:
- break;
- case GCodeSpeedUnits.CentimetersPerMinute:
- retractSpeed *= 10;
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
}
else
{
- switch (positionType)
+ if (liftPosTemp - positionZ <= FileFormat.MaximumLayerHeight)
{
- case GCodePositioningTypes.Absolute:
- positionZ = liftPosTemp;
- break;
- case GCodePositioningTypes.Partial:
- positionZ = Layer.RoundHeight(positionZ + liftPosTemp);
- break;
+ switch (positionType)
+ {
+ case GCodePositioningTypes.Absolute:
+ positionZ = liftPosTemp;
+ break;
+ case GCodePositioningTypes.Partial:
+ positionZ = Layer.RoundHeight(positionZ + liftPosTemp);
+ break;
+ }
}
-
}
}
@@ -728,23 +671,11 @@ namespace UVtools.Core.GCode
if (waitG4Regex.Count >= 1 && waitG4Regex[0].Success)
{
- lightOffDelay = float.Parse(waitG4Regex[0].Groups[1].Value, CultureInfo.InvariantCulture);
- switch (GCodeTimeUnit)
- {
- case GCodeTimeUnits.Milliseconds:
- lightOffDelay = TimeExtensions.MillisecondsToSeconds(lightOffDelay);
- break;
- }
+ lightOffDelay = ConvertToSeconds(float.Parse(waitG4Regex[0].Groups[1].Value, CultureInfo.InvariantCulture));
if (waitG4Regex.Count >= 2 && waitG4Regex[1].Success)
{
- exposureTime = float.Parse(waitG4Regex[1].Groups[1].Value, CultureInfo.InvariantCulture);
- switch (GCodeTimeUnit)
- {
- case GCodeTimeUnits.Milliseconds:
- exposureTime = TimeExtensions.MillisecondsToSeconds(exposureTime);
- break;
- }
+ exposureTime = ConvertToSeconds(float.Parse(waitG4Regex[1].Groups[1].Value, CultureInfo.InvariantCulture));
}
else // Only one match, meaning light off delay is not present and the only time is the cure time
{
@@ -766,7 +697,7 @@ namespace UVtools.Core.GCode
{
slicerFile.SuppressRebuildPropertiesWork(() =>
{
- var bottomLayer = slicerFile[0];
+ var bottomLayer = slicerFile.FirstLayer;
if (bottomLayer is not null)
{
if (bottomLayer.ExposureTime > 0) slicerFile.BottomExposureTime = bottomLayer.ExposureTime;
@@ -795,6 +726,68 @@ namespace UVtools.Core.GCode
{
return new(_gcode.ToString());
}
+
+ /// <summary>
+ /// Converts seconds to current gcode norm
+ /// </summary>
+ /// <param name="seconds"></param>
+ /// <returns></returns>
+ public float ConvertFromSeconds(float seconds)
+ {
+ return _gCodeTimeUnit switch
+ {
+ GCodeTimeUnits.Seconds => seconds,
+ GCodeTimeUnits.Milliseconds => TimeExtensions.SecondsToMilliseconds(seconds),
+ _ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}")
+ };
+ }
+
+ /// <summary>
+ /// Converts speed in mm/min to current gcode norm
+ /// </summary>
+ /// <param name="mmMin">Millimeters per minute</param>
+ /// <returns></returns>
+ public float ConvertFromMillimetersPerMinute(float mmMin)
+ {
+ return _gCodeSpeedUnit switch
+ {
+ GCodeSpeedUnits.MillimetersPerMinute => mmMin,
+ GCodeSpeedUnits.MillimetersPerSecond => (float) Math.Round(mmMin / 60, 2),
+ GCodeSpeedUnits.CentimetersPerMinute => (float) Math.Round(mmMin / 10, 2),
+ _ => throw new InvalidExpressionException($"Unhandled speed unit for {_gCodeSpeedUnit}")
+ };
+ }
+
+ /// <summary>
+ /// Converts time from current gcode norm in <see cref="GCodeTimeUnit"/> to s
+ /// </summary>
+ /// <param name="time">Time in <see cref="GCodeTimeUnit"/></param>
+ /// <returns></returns>
+ public float ConvertToSeconds(float time)
+ {
+ return _gCodeTimeUnit switch
+ {
+ GCodeTimeUnits.Seconds => time,
+ GCodeTimeUnits.Milliseconds => TimeExtensions.MillisecondsToSeconds(time),
+ _ => throw new InvalidExpressionException($"Unhandled time unit for {_gCodeTimeUnit}")
+ };
+ }
+
+ /// <summary>
+ /// Converts speed from current gcode norm in <see cref="GCodeSpeedUnit"/> to mm/min
+ /// </summary>
+ /// <param name="speed">Speed in <see cref="GCodeSpeedUnit"/></param>
+ /// <returns></returns>
+ public float ConvertToMillimetersPerMinute(float speed)
+ {
+ return _gCodeSpeedUnit switch
+ {
+ GCodeSpeedUnits.MillimetersPerMinute => speed,
+ GCodeSpeedUnits.MillimetersPerSecond => (float)Math.Round(speed * 60, 2),
+ GCodeSpeedUnits.CentimetersPerMinute => (float)Math.Round(speed * 10, 2),
+ _ => throw new InvalidExpressionException($"Unhandled speed unit for {_gCodeSpeedUnit}")
+ };
+ }
}
#endregion
}
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index b9585c3..08d342c 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -585,6 +585,19 @@ namespace UVtools.Core
SlicerFile?.UpdatePrintTime();
}
+ public IEnumerable<Layer> GetSamePositionedLayers()
+ {
+ var layers = new List<Layer>();
+ for (int layerIndex = 1; layerIndex < LayerCount; layerIndex++)
+ {
+ var layer = this[layerIndex];
+ if (this[layerIndex - 1].PositionZ != layer.PositionZ) continue;
+ layers.Add(layer);
+ }
+
+ return layers;
+ }
+
public Rectangle GetBoundingRectangle(OperationProgress progress = null)
{
if (!_boundingRectangle.IsEmpty || LayerCount == 0 || this[0] is null) return _boundingRectangle;
diff --git a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
index c515538..72ba3d7 100644
--- a/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
+++ b/UVtools.Core/Operations/OperationCalibrateExposureFinder.cs
@@ -110,8 +110,11 @@ namespace UVtools.Core.Operations
private decimal _multipleLayerHeightMaximum = 0.1m;
private decimal _multipleLayerHeightStep = 0.01m;
- private bool _dontLiftSamePositionedLayers;
- private bool _zeroLightOffSamePositionedLayers;
+ private bool _differentSettingsForSamePositionedLayers;
+ private bool _samePositionedLayersLiftHeightEnabled = true;
+ private decimal _samePositionedLayersLiftHeight;
+ private bool _samePositionedLayersLightOffDelayEnabled = true;
+ private decimal _samePositionedLayersLightOffDelay;
private bool _multipleExposures;
private ExposureGenTypes _exposureGenType = ExposureGenTypes.Linear;
private bool _exposureGenIgnoreBaseExposure;
@@ -136,7 +139,6 @@ namespace UVtools.Core.Operations
private byte _bullsEyeFenceThickness = 10;
private sbyte _bullsEyeFenceOffset;
private bool _patternModelGlueBottomLayers = true;
-
#endregion
#region Overrides
@@ -755,15 +757,17 @@ namespace UVtools.Core.Operations
get
{
List<byte> values = new();
-
- var split = _multipleBrightnessValues.Split(',', StringSplitOptions.TrimEntries);
- foreach (var brightnessStr in split)
+ if (!string.IsNullOrWhiteSpace(_multipleBrightnessValues))
{
- if (string.IsNullOrWhiteSpace(brightnessStr)) continue;
- if (!byte.TryParse(brightnessStr, out var brightness)) continue;
- if (brightness is <= 0 or > 255) continue;
- if (values.Contains(brightness)) continue;
- values.Add(brightness);
+ var split = _multipleBrightnessValues.Split(',', StringSplitOptions.TrimEntries);
+ foreach (var brightnessStr in split)
+ {
+ if (string.IsNullOrWhiteSpace(brightnessStr)) continue;
+ if (!byte.TryParse(brightnessStr, out var brightness)) continue;
+ if (brightness is <= 0 or > 255) continue;
+ if (values.Contains(brightness)) continue;
+ values.Add(brightness);
+ }
}
return values.OrderByDescending(brightness => brightness).ToArray();
@@ -801,16 +805,34 @@ namespace UVtools.Core.Operations
}
}
- public bool DontLiftSamePositionedLayers
+ public bool DifferentSettingsForSamePositionedLayers
+ {
+ get => _differentSettingsForSamePositionedLayers;
+ set => RaiseAndSetIfChanged(ref _differentSettingsForSamePositionedLayers, value);
+ }
+
+ public bool SamePositionedLayersLiftHeightEnabled
+ {
+ get => _samePositionedLayersLiftHeightEnabled;
+ set => RaiseAndSetIfChanged(ref _samePositionedLayersLiftHeightEnabled, value);
+ }
+
+ public decimal SamePositionedLayersLiftHeight
+ {
+ get => _samePositionedLayersLiftHeight;
+ set => RaiseAndSetIfChanged(ref _samePositionedLayersLiftHeight, Math.Round(value, 2));
+ }
+
+ public bool SamePositionedLayersLightOffDelayEnabled
{
- get => _dontLiftSamePositionedLayers;
- set => RaiseAndSetIfChanged(ref _dontLiftSamePositionedLayers, value);
+ get => _samePositionedLayersLightOffDelayEnabled;
+ set => RaiseAndSetIfChanged(ref _samePositionedLayersLightOffDelayEnabled, value);
}
- public bool ZeroLightOffSamePositionedLayers
+ public decimal SamePositionedLayersLightOffDelay
{
- get => _zeroLightOffSamePositionedLayers;
- set => RaiseAndSetIfChanged(ref _zeroLightOffSamePositionedLayers, value);
+ get => _samePositionedLayersLightOffDelay;
+ set => RaiseAndSetIfChanged(ref _samePositionedLayersLightOffDelay, Math.Round(value, 2));
}
public bool MultipleExposures
@@ -1027,7 +1049,23 @@ namespace UVtools.Core.Operations
public OperationCalibrateExposureFinder() { }
public OperationCalibrateExposureFinder(FileFormat slicerFile) : base(slicerFile)
- { }
+ {
+ if (SlicerFile.SupportPerLayerSettings)
+ {
+ _differentSettingsForSamePositionedLayers = true;
+ if (SlicerFile.SupportsGCode)
+ {
+ _samePositionedLayersLiftHeight = 0;
+ _samePositionedLayersLightOffDelay = 2;
+ }
+ else
+ {
+ _samePositionedLayersLiftHeight = 0.1m;
+ _samePositionedLayersLightOffDelay = 0;
+ }
+ }
+
+ }
public override void InitWithSlicerFile()
{
@@ -1107,7 +1145,7 @@ namespace UVtools.Core.Operations
private bool Equals(OperationCalibrateExposureFinder other)
{
- return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThickness == other._staircaseThickness && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _dontLiftSamePositionedLayers == other._dontLiftSamePositionedLayers && _zeroLightOffSamePositionedLayers == other._zeroLightOffSamePositionedLayers && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers;
+ return _displayWidth == other._displayWidth && _displayHeight == other._displayHeight && _layerHeight == other._layerHeight && _bottomLayers == other._bottomLayers && _bottomExposure == other._bottomExposure && _normalExposure == other._normalExposure && _topBottomMargin == other._topBottomMargin && _leftRightMargin == other._leftRightMargin && _chamferLayers == other._chamferLayers && _erodeBottomIterations == other._erodeBottomIterations && _partMargin == other._partMargin && _enableAntiAliasing == other._enableAntiAliasing && _mirrorOutput == other._mirrorOutput && _baseHeight == other._baseHeight && _featuresHeight == other._featuresHeight && _featuresMargin == other._featuresMargin && _staircaseThickness == other._staircaseThickness && _holesEnabled == other._holesEnabled && _holeShape == other._holeShape && _unitOfMeasure == other._unitOfMeasure && _holeDiametersPx == other._holeDiametersPx && _holeDiametersMm == other._holeDiametersMm && _barsEnabled == other._barsEnabled && _barSpacing == other._barSpacing && _barLength == other._barLength && _barVerticalSplitter == other._barVerticalSplitter && _barFenceThickness == other._barFenceThickness && _barFenceOffset == other._barFenceOffset && _barThicknessesPx == other._barThicknessesPx && _barThicknessesMm == other._barThicknessesMm && _textEnabled == other._textEnabled && _textFont == other._textFont && _textScale.Equals(other._textScale) && _textThickness == other._textThickness && _text == other._text && _multipleBrightness == other._multipleBrightness && _multipleBrightnessExcludeFrom == other._multipleBrightnessExcludeFrom && _multipleBrightnessValues == other._multipleBrightnessValues && _multipleBrightnessGenExposureTime == other._multipleBrightnessGenExposureTime && _multipleBrightnessGenEmulatedAALevel == other._multipleBrightnessGenEmulatedAALevel && _multipleBrightnessGenExposureFractions == other._multipleBrightnessGenExposureFractions && _multipleLayerHeight == other._multipleLayerHeight && _multipleLayerHeightMaximum == other._multipleLayerHeightMaximum && _multipleLayerHeightStep == other._multipleLayerHeightStep && _differentSettingsForSamePositionedLayers == other._differentSettingsForSamePositionedLayers && _samePositionedLayersLiftHeightEnabled == other._samePositionedLayersLiftHeightEnabled && _samePositionedLayersLiftHeight == other._samePositionedLayersLiftHeight && _samePositionedLayersLightOffDelayEnabled == other._samePositionedLayersLightOffDelayEnabled && _samePositionedLayersLightOffDelay == other._samePositionedLayersLightOffDelay && _multipleExposures == other._multipleExposures && _exposureGenType == other._exposureGenType && _exposureGenIgnoreBaseExposure == other._exposureGenIgnoreBaseExposure && _exposureGenBottomStep == other._exposureGenBottomStep && _exposureGenNormalStep == other._exposureGenNormalStep && _exposureGenTests == other._exposureGenTests && _exposureGenManualLayerHeight == other._exposureGenManualLayerHeight && _exposureGenManualBottom == other._exposureGenManualBottom && _exposureGenManualNormal == other._exposureGenManualNormal && Equals(_exposureTable, other._exposureTable) && _bullsEyeEnabled == other._bullsEyeEnabled && _bullsEyeConfigurationPx == other._bullsEyeConfigurationPx && _bullsEyeConfigurationMm == other._bullsEyeConfigurationMm && _bullsEyeInvertQuadrants == other._bullsEyeInvertQuadrants && _counterTrianglesEnabled == other._counterTrianglesEnabled && _counterTrianglesTipOffset == other._counterTrianglesTipOffset && _counterTrianglesFence == other._counterTrianglesFence && _patternModel == other._patternModel && _bullsEyeFenceThickness == other._bullsEyeFenceThickness && _bullsEyeFenceOffset == other._bullsEyeFenceOffset && _patternModelGlueBottomLayers == other._patternModelGlueBottomLayers;
}
public override bool Equals(object obj)
@@ -1157,11 +1195,16 @@ namespace UVtools.Core.Operations
hashCode.Add((int) _multipleBrightnessExcludeFrom);
hashCode.Add(_multipleBrightnessValues);
hashCode.Add(_multipleBrightnessGenExposureTime);
+ hashCode.Add(_multipleBrightnessGenEmulatedAALevel);
+ hashCode.Add(_multipleBrightnessGenExposureFractions);
hashCode.Add(_multipleLayerHeight);
hashCode.Add(_multipleLayerHeightMaximum);
hashCode.Add(_multipleLayerHeightStep);
- hashCode.Add(_dontLiftSamePositionedLayers);
- hashCode.Add(_zeroLightOffSamePositionedLayers);
+ hashCode.Add(_differentSettingsForSamePositionedLayers);
+ hashCode.Add(_samePositionedLayersLiftHeightEnabled);
+ hashCode.Add(_samePositionedLayersLiftHeight);
+ hashCode.Add(_samePositionedLayersLightOffDelayEnabled);
+ hashCode.Add(_samePositionedLayersLightOffDelay);
hashCode.Add(_multipleExposures);
hashCode.Add((int) _exposureGenType);
hashCode.Add(_exposureGenIgnoreBaseExposure);
@@ -1681,8 +1724,43 @@ namespace UVtools.Core.Operations
CvInvoke.Line(thumbnail, new Point(xSpacing, 0), new Point(xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3);
CvInvoke.Line(thumbnail, new Point(xSpacing, ySpacing + 5), new Point(thumbnail.Width - xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3);
CvInvoke.Line(thumbnail, new Point(thumbnail.Width - xSpacing, 0), new Point(thumbnail.Width - xSpacing, ySpacing + 5), new MCvScalar(255, 27, 245), 3);
- CvInvoke.PutText(thumbnail, "Exposure Time Cal.", new Point(xSpacing, ySpacing * 2), fontFace, fontScale, new MCvScalar(0, 255, 255), fontThickness);
- CvInvoke.PutText(thumbnail, $"{Microns}um @ {BottomExposure}s/{NormalExposure}s", new Point(xSpacing, ySpacing * 3), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness);
+ CvInvoke.PutText(thumbnail, "Exposure Time Cal.", new Point(xSpacing, ySpacing * 2 - 10), fontFace, fontScale, new MCvScalar(0, 255, 255), fontThickness);
+
+
+ string text = string.Empty;
+
+ if (_multipleLayerHeight)
+ {
+ text += $"{Microns}um-{(ushort)(_multipleLayerHeightMaximum *1000)}um/{(ushort)(_multipleLayerHeightStep *1000)}um\n";
+ }
+ else
+ {
+ text += $"Layer height: {Microns}um\n";
+ }
+
+ if (_multipleExposures)
+ {
+ text += $"{_exposureTable[0].Exposure}s-{_exposureTable[^1].Exposure}s/{_exposureGenNormalStep}s";
+ if (!_patternModel)
+ {
+ text += $"\nObjects: {_exposureTable.Count}";
+ }
+ }
+ else
+ {
+ text += $"{_bottomExposure}s/{_normalExposure}s";
+ }
+
+ if (_patternModel)
+ {
+ text += "\nPatterned Model";
+ }
+
+
+ thumbnail.PutTextExtended(text, new Point(xSpacing, ySpacing * 3 - 20), fontFace, 0.8, EmguExtensions.WhiteColor, 2, 10);
+
+
+ /*CvInvoke.PutText(thumbnail, $"{Microns}um @ {BottomExposure}s/{NormalExposure}s", new Point(xSpacing, ySpacing * 3), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness);
if (_patternModel)
{
CvInvoke.PutText(thumbnail, $"Patterned Model", new Point(xSpacing, ySpacing * 4), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness);
@@ -1690,7 +1768,7 @@ namespace UVtools.Core.Operations
else
{
CvInvoke.PutText(thumbnail, $"Features: {(_staircaseThickness > 0 ? 1 : 0) + Holes.Length + Bars.Length + BullsEyes.Length + (_counterTrianglesEnabled ? 1 : 0)}", new Point(xSpacing, ySpacing * 4), fontFace, fontScale, EmguExtensions.WhiteColor, fontThickness);
- }
+ }*/
return thumbnail;
@@ -1732,7 +1810,7 @@ namespace UVtools.Core.Operations
currentY += boundingRectangle.Height + partMarginYPx;
}
- if (currentY + topBottomMarginPx >= SlicerFile.ResolutionY) break;
+ if (currentY + boundingRectangle.Height + topBottomMarginPx >= SlicerFile.ResolutionY) break;
var item = multipleExposure.Clone();
item.Brightness = brightness;
@@ -2098,9 +2176,14 @@ namespace UVtools.Core.Operations
if (SlicerFile.ThumbnailsCount > 0)
SlicerFile.SetThumbnails(GetThumbnail());
- if (_dontLiftSamePositionedLayers)
+ if (_differentSettingsForSamePositionedLayers)
{
- SlicerFile.LayerManager.SetNoLiftForSamePositionedLayers(_zeroLightOffSamePositionedLayers);
+ var layers = SlicerFile.LayerManager.GetSamePositionedLayers();
+ foreach (var layer in layers)
+ {
+ if(_samePositionedLayersLiftHeightEnabled) layer.LiftHeight = (float) _samePositionedLayersLiftHeight;
+ if(_samePositionedLayersLightOffDelayEnabled) layer.LightOffDelay = (float) _samePositionedLayersLightOffDelay;
+ }
}
new OperationMove(SlicerFile).Execute(progress);
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index b9b9c4f..0f89f35 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -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>2.14.1</Version>
+ <Version>2.14.2</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
index 4e2602a..ee8d38e 100644
--- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs
+++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
@@ -341,8 +341,8 @@
<Component Id="owc3FC8434C1A84605AEEBC6A100CA2F3E1" Guid="47d7e276-db6d-424e-d797-1a69e1e24b3b">
<File Id="owf3FC8434C1A84605AEEBC6A100CA2F3E1" Source="$(var.SourceDir)\Newtonsoft.Json.dll" KeyPath="yes" />
</Component>
- <Component Id="owc29161E83FC02784120326979FF285358" Guid="a8d30e75-1063-4d27-60b6-13d4bd4f52eb">
- <File Id="owf29161E83FC02784120326979FF285358" Source="$(var.SourceDir)\opencv_videoio_ffmpeg451_64.dll" KeyPath="yes" />
+ <Component Id="owcC8F0982CA6FC282C6992A07EAF832954" Guid="eca80656-9710-cdb8-cb7f-c54f35b4b913">
+ <File Id="owfC8F0982CA6FC282C6992A07EAF832954" Source="$(var.SourceDir)\opencv_videoio_ffmpeg452_64.dll" KeyPath="yes" />
</Component>
<Component Id="owc363CAFE6342F1E71AB07D13BAEEE5FF0" Guid="8e946fdc-ea52-7c4b-a8b3-69e1ecf51086">
<File Id="owf363CAFE6342F1E71AB07D13BAEEE5FF0" Source="$(var.SourceDir)\SkiaSharp.dll" KeyPath="yes" />
@@ -867,9 +867,6 @@
<Component Id="owc1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Guid="545300b7-5398-2ce2-788f-02287a83e8a7">
<File Id="owf1FE1E0B70F7D880A2FB9AFA8E0E36EF5" Source="$(var.SourceDir)\UVtools_demo_file.sl1" KeyPath="yes" />
</Component>
- <Component Id="owc507468650B23000B702AAAE48E658343" Guid="dba8edf4-02a3-c04a-50fc-896025548077">
- <File Id="owf507468650B23000B702AAAE48E658343" Source="$(var.SourceDir)\vccorlib140.dll" KeyPath="yes" />
- </Component>
<Component Id="owcEB2D9343E9BF3366381E9864468EFB9A" Guid="c4f85169-dfa6-1369-3b95-34e28199fa0f">
<File Id="owfEB2D9343E9BF3366381E9864468EFB9A" Source="$(var.SourceDir)\vcruntime140.dll" KeyPath="yes" />
</Component>
diff --git a/UVtools.ScriptSample/ScriptCustomGCode.cs b/UVtools.ScriptSample/ScriptCustomGCode.cs
new file mode 100644
index 0000000..c5e7565
--- /dev/null
+++ b/UVtools.ScriptSample/ScriptCustomGCode.cs
@@ -0,0 +1,154 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using UVtools.Core.Scripting;
+using System.IO;
+using UVtools.Core;
+using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
+
+namespace UVtools.ScriptSample
+{
+ /// <summary>
+ /// Change layer properties to random values
+ /// </summary>
+ public class ScriptCustomGCode : ScriptGlobals
+ {
+ /// <summary>
+ /// Set configurations here, this function trigger just after load a script
+ /// </summary>
+ public void ScriptInit()
+ {
+ Script.Name = "Custo gcode generator";
+ Script.Description = "Generates custom gcode and saves the file";
+ Script.Author = "Tiago Conceição";
+ Script.Version = new Version(0, 1);
+ }
+
+ /// <summary>
+ /// Validate user inputs here, this function trigger when user click on execute
+ /// </summary>
+ /// <returns>A error message, empty or null if validation passes.</returns>
+ public string ScriptValidate()
+ {
+ return SlicerFile.SupportsGCode ? null : "GCode is not supported on this file";
+ }
+
+ /// <summary>
+ /// Execute the script, this function trigger when when user click on execute and validation passes
+ /// </summary>
+ /// <returns>True if executes successfully to the end, otherwise false.</returns>
+ public bool ScriptExecute()
+ {
+ var gcode = SlicerFile.GCode;
+ gcode.Clear();
+
+ float pos = 1;
+ float layerHeight = 0.025f;
+ float liftHeight = 4.5f;
+ float feedrate = gcode.ConvertFromMillimetersPerMinute(150);
+ float lightoff = gcode.ConvertFromSeconds(1f);
+
+ gcode.AppendStartGCode();
+ //gcode.AppendShowImageM6054(gcode.GetShowImageString(0));
+ //gcode.AppendWaitG4(gcode.ConvertFromSeconds(2));
+ //gcode.AppendTurnLightM106(255);
+ gcode.AppendWaitG4(gcode.ConvertFromSeconds(1));
+ //gcode.AppendTurnLightM106(0);
+ gcode.AppendLiftMoveG0(20, feedrate, pos, feedrate);
+ gcode.AppendWaitG4(gcode.ConvertFromSeconds(5));
+
+ // 0.025 test
+ /*gcode.AppendComment("0.025 layer height simulated print test");
+ for (int i = 0; i < 50; i++)
+ {
+ pos = Layer.RoundHeight(pos + layerHeight);
+ var liftPos = Layer.RoundHeight(pos + liftHeight);
+ gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff);
+ }*/
+
+ // 0.01 test
+ gcode.AppendComment("0.01 layer height simulated print test");
+ pos = 1;
+ layerHeight = 0.01f;
+
+
+ gcode.AppendMoveG0(pos, feedrate);
+ gcode.AppendWaitG4(gcode.ConvertFromSeconds(5));
+ for (int i = 0; i < 50; i++)
+ {
+ pos = Layer.RoundHeight(pos + layerHeight);
+ var liftPos = Layer.RoundHeight(pos + liftHeight);
+ gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff);
+ }
+
+ // 0.001 test
+ /*gcode.AppendComment("0.001 layer height simulated print test");
+ pos = 1;
+ layerHeight = 0.001f;
+ liftHeight = 1;
+
+ gcode.AppendMoveG0(pos, feedrate);
+ gcode.AppendWaitG4(gcode.ConvertFromSeconds(5));
+ for (int i = 0; i < 50; i++)
+ {
+ pos = Layer.RoundHeight(pos + layerHeight);
+ var liftPos = Layer.RoundHeight(pos + liftHeight);
+ gcode.AppendLiftMoveG0(liftPos, feedrate, pos, feedrate, lightoff);
+ }*/
+
+
+ /*// 0.05 backlash test
+ gcode.AppendComment("0.05 backlash test");
+ pos = 1;
+ layerHeight = 0.02f;
+
+ gcode.AppendMoveG0(pos, feedrate);
+ //gcode.AppendWaitG4(gcode.ConvertFromSeconds(5));
+ for (int i = 0; i < 50; i++)
+ {
+ var liftPos = Layer.RoundHeight(pos + layerHeight);
+ gcode.AppendMoveG0(liftPos, feedrate);
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(pos, feedrate);
+ gcode.AppendWaitG4(lightoff);
+ }
+ */
+
+ /*gcode.AppendMoveG0(2, gcode.ConvertFromMillimetersPerMinute(150));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(2.5f, gcode.ConvertFromMillimetersPerMinute(160));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(3f, gcode.ConvertFromMillimetersPerMinute(170));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(3.5f, gcode.ConvertFromMillimetersPerMinute(180));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(4.0f, gcode.ConvertFromMillimetersPerMinute(190));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(4.5f, gcode.ConvertFromMillimetersPerMinute(195));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(5f, gcode.ConvertFromMillimetersPerMinute(199));
+ gcode.AppendWaitG4(lightoff);
+ gcode.AppendMoveG0(5.5f, gcode.ConvertFromMillimetersPerMinute(205));
+ gcode.AppendWaitG4(lightoff);*/
+
+ gcode.AppendMoveG0(100, feedrate);
+ //gcode.AppendTurnMotors(false);
+
+
+
+ SlicerFile.SuppressRebuildGCode = true;
+ SlicerFile.Save(Progress);
+ SlicerFile.SuppressRebuildGCode = false;
+
+ // return true if not cancelled by user
+ return !Progress.Token.IsCancellationRequested;
+ }
+ }
+} \ No newline at end of file
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
index dd221a6..f15720a 100644
--- a/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateExposureFinderControl.axaml
@@ -896,24 +896,6 @@
Content="Enable - For advanced users only!"
IsChecked="{Binding Operation.MultipleExposures}"/>
- <StackPanel Orientation="Horizontal" Spacing="20"
- IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}">
-
- <CheckBox
- ToolTip.Tip="The lift height will be set to 0 for sequential layers that share same z position, saving moves and time.
-&#x0a;Some printers may not support this and always require a lift after each layer, in that case turning this on will not affect the print."
- Content="Do not perform the lifting sequence for layers with same Z positioning"
- IsEnabled="{Binding Operation.MultipleExposures}"
- IsChecked="{Binding Operation.DontLiftSamePositionedLayers}"/>
-
- <CheckBox
- ToolTip.Tip="Sets the light-off delay to zero for each sequential layers with no lift's to save that additional time.
-&#x0a;Note that without a lift and a delay the UV LED and LCD will be almost always ON, that can lead to overheat and wear the LCD faster."
- Content="Also set light-off delay to zero"
- IsEnabled="{Binding Operation.DontLiftSamePositionedLayers}"
- IsChecked="{Binding Operation.ZeroLightOffSamePositionedLayers}"/>
- </StackPanel>
-
<TextBlock Text="Automatic exposure generation:"
IsEnabled="{Binding Operation.MultipleExposures}"
FontWeight="Bold"/>
@@ -1114,6 +1096,79 @@
</DataGrid>
+
+ <StackPanel Orientation="Vertical" Spacing="10"
+ IsEnabled="{Binding Operation.MultipleExposures}"
+ IsVisible="{Binding SlicerFile.SupportPerLayerSettings}">
+
+ <CheckBox
+ ToolTip.Tip="Change some defined settings for sequential layers that share same z position"
+ Content="Use different settings for layers with same Z positioning:"
+ FontWeight="Bold"
+ IsChecked="{Binding Operation.DifferentSettingsForSamePositionedLayers}"/>
+
+ <Grid RowDefinitions="Auto,10,Auto" ColumnDefinitions="Auto,10,Auto,5,Auto" IsEnabled="{Binding Operation.DifferentSettingsForSamePositionedLayers}">
+ <CheckBox Grid.Row="0" Grid.Column="0"
+ ToolTip.Tip="Use a low value to speed up layers with same Z position, lift is not really required here.
+&#x0a;Set no lift height (0mm) will not work on most of the printers, so far, only gcode printers are known/able to use no lifts.
+&#x0a;However set 0mm on a not compatible printer will cause no harm, value will be contained inside a min-max inside firmware."
+ Content="Lift height:"
+ IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}"
+ IsChecked="{Binding Operation.SamePositionedLayersLiftHeightEnabled}"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="0" Grid.Column="2"
+ Increment="0.5"
+ Minimum="0"
+ Maximum="1000"
+ FormatString="F2"
+ IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}"
+ IsEnabled="{Binding Operation.SamePositionedLayersLiftHeightEnabled}"
+ Value="{Binding Operation.SamePositionedLayersLiftHeight}"/>
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ Text="mm"
+ IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight}"
+ VerticalAlignment="Center"/>
+
+ <CheckBox Grid.Row="2" Grid.Column="0"
+ ToolTip.Tip="Use a low value to speed up layers with same Z position, a delay is not really required here.
+&#x0a;Set no delay (0s) is not recommended for gcode printers, as most need some time to render the image before move to the next command, 2s is recommended as a safe-guard."
+ Content="Light-off delay:"
+ IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}"
+ IsChecked="{Binding Operation.SamePositionedLayersLightOffDelayEnabled}"
+ VerticalAlignment="Center"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ Increment="0.5"
+ Minimum="0"
+ Maximum="1000"
+ FormatString="F2"
+ IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}"
+ IsEnabled="{Binding Operation.SamePositionedLayersLightOffDelayEnabled}"
+ Value="{Binding Operation.SamePositionedLayersLightOffDelay}"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ Text="s"
+ IsVisible="{Binding SlicerFile.CanUseLayerLightOffDelay}"
+ VerticalAlignment="Center"/>
+
+ </Grid>
+
+
+ <!--
+ <CheckBox
+ ToolTip.Tip="The lift height will be set to 0 for sequential layers that share same z position, saving moves and time.
+&#x0a;Some printers may not support this and always require a lift after each layer, in that case turning this on will not affect the print."
+ Content="Do not perform the lifting sequence for layers with same Z positioning"
+ IsEnabled="{Binding Operation.MultipleExposures}"
+ IsChecked="{Binding Operation.DontLiftSamePositionedLayers}"/>
+
+ <CheckBox
+ ToolTip.Tip="Sets the light-off delay to zero for each sequential layers with no lift's to save that additional time.
+&#x0a;Note that without a lift and a delay the UV LED and LCD will be almost always ON, that can lead to overheat and wear the LCD faster."
+ Content="Also set light-off delay to zero"
+ IsEnabled="{Binding Operation.DontLiftSamePositionedLayers}"
+ IsChecked="{Binding Operation.ZeroLightOffSamePositionedLayers}"/>
+ !-->
+ </StackPanel>
+
</StackPanel>
</Expander>
diff --git a/UVtools.WPF/ErrorLog.cs b/UVtools.WPF/ErrorLog.cs
index d918064..7e2f229 100644
--- a/UVtools.WPF/ErrorLog.cs
+++ b/UVtools.WPF/ErrorLog.cs
@@ -15,7 +15,7 @@ namespace UVtools.WPF
try
{
File.AppendAllText(FullPath,
- $"({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}");
+ $"[v{App.VersionStr}] ({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}");
}
catch (Exception exception)
{
@@ -23,7 +23,7 @@ namespace UVtools.WPF
}
}
- public static StreamWriter AppendText()
+ public static StreamWriter GetStreamWriter()
{
return File.AppendText(FullPath);
}
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index d78fbe3..37b9bfc 100644
--- a/UVtools.WPF/UVtools.WPF.csproj
+++ b/UVtools.WPF/UVtools.WPF.csproj
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
- <Version>2.14.1</Version>
+ <Version>2.14.2</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1
index f3d3827..422a593 100644
--- a/build/CreateRelease.WPF.ps1
+++ b/build/CreateRelease.WPF.ps1
@@ -32,10 +32,10 @@ Set-Location $PSScriptRoot\..
####################################
### Configuration ###
####################################
-$enableMSI = $true
+#$enableMSI = $true
#$buildOnly = 'linux-x64'
-#$buildOnly = 'win-x64'
-$enableNugetPublish = $true
+$buildOnly = 'win-x64'
+#$enableNugetPublish = $true
# Profilling
$stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
$deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch