add:WinRT墨迹识别
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Ink;
|
using System.Windows.Ink;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -7,8 +7,8 @@ namespace Ink_Canvas.Helpers
|
|||||||
{
|
{
|
||||||
public class InkRecognizeHelper
|
public class InkRecognizeHelper
|
||||||
{
|
{
|
||||||
//识别形状
|
/// <summary>IACore / IAWinFX 形状识别(典型用于 32 位进程)。</summary>
|
||||||
public static ShapeRecognizeResult RecognizeShape(StrokeCollection strokes)
|
public static ShapeRecognizeResult RecognizeShapeIACore(StrokeCollection strokes)
|
||||||
{
|
{
|
||||||
if (strokes == null || strokes.Count == 0)
|
if (strokes == null || strokes.Count == 0)
|
||||||
return default;
|
return default;
|
||||||
@@ -52,6 +52,66 @@ namespace Ink_Canvas.Helpers
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>兼容旧调用:等价于 <see cref="RecognizeShapeIACore"/>。</summary>
|
||||||
|
public static ShapeRecognizeResult RecognizeShape(StrokeCollection strokes) =>
|
||||||
|
RecognizeShapeIACore(strokes);
|
||||||
|
|
||||||
|
/// <summary>按设置选择 WinRT 或 IACore,返回统一识别结果。</summary>
|
||||||
|
public static InkShapeRecognitionResult RecognizeShapeUnified(
|
||||||
|
StrokeCollection strokes,
|
||||||
|
ShapeRecognitionEngineMode mode)
|
||||||
|
{
|
||||||
|
if (strokes == null || strokes.Count == 0)
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
|
||||||
|
if (ShapeRecognitionRouter.ResolveUseWinRt(mode))
|
||||||
|
return WinRtInkShapeRecognizer.RecognizeShape(strokes);
|
||||||
|
|
||||||
|
var legacy = RecognizeShapeIACore(strokes);
|
||||||
|
return FromIACoreOrEmpty(legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WarmupShapeRecognition(ShapeRecognitionEngineMode mode)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ShapeRecognitionRouter.ResolveUseWinRt(mode))
|
||||||
|
WinRtInkShapeRecognizer.Warmup();
|
||||||
|
else
|
||||||
|
RecognizeShapeIACore(new StrokeCollection());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 预热失败不影响启动
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InkShapeRecognitionResult FromIACoreOrEmpty(ShapeRecognizeResult legacy)
|
||||||
|
{
|
||||||
|
if (legacy?.InkDrawingNode == null)
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
|
||||||
|
var node = legacy.InkDrawingNode;
|
||||||
|
var shape = node.GetShape();
|
||||||
|
var hot = ClonePointCollection(node.HotPoints);
|
||||||
|
return new InkShapeRecognitionResult(
|
||||||
|
node.GetShapeName(),
|
||||||
|
legacy.Centroid,
|
||||||
|
hot,
|
||||||
|
shape.Width,
|
||||||
|
shape.Height,
|
||||||
|
node.Strokes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PointCollection ClonePointCollection(PointCollection src)
|
||||||
|
{
|
||||||
|
var dst = new PointCollection();
|
||||||
|
if (src == null) return dst;
|
||||||
|
foreach (System.Windows.Point p in src)
|
||||||
|
dst.Add(p);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsContainShapeType(string name)
|
public static bool IsContainShapeType(string name)
|
||||||
{
|
{
|
||||||
if (name.Contains("Triangle") || name.Contains("Circle") ||
|
if (name.Contains("Triangle") || name.Contains("Circle") ||
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Ink;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using OSVersionExtension;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>墨迹形状识别后端:自动 / IACore / WinRT。</summary>
|
||||||
|
public enum ShapeRecognitionEngineMode
|
||||||
|
{
|
||||||
|
Auto = 0,
|
||||||
|
IACore = 1,
|
||||||
|
WinRT = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ShapeRecognitionRouter
|
||||||
|
{
|
||||||
|
public static bool ResolveUseWinRt(ShapeRecognitionEngineMode mode)
|
||||||
|
{
|
||||||
|
if (mode == ShapeRecognitionEngineMode.WinRT) return true;
|
||||||
|
if (mode == ShapeRecognitionEngineMode.IACore) return false;
|
||||||
|
return Environment.Is64BitProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldRunShapeRecognition(bool inkToShapeEnabled, ShapeRecognitionEngineMode mode)
|
||||||
|
{
|
||||||
|
if (!inkToShapeEnabled) return false;
|
||||||
|
if (ResolveUseWinRt(mode))
|
||||||
|
return OSVersion.GetOperatingSystem() >= OSVersionExtension.OperatingSystem.Windows10;
|
||||||
|
return !Environment.Is64BitProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapeRecognitionEngineMode FromSettingsInt(int value)
|
||||||
|
{
|
||||||
|
if (value == (int)ShapeRecognitionEngineMode.IACore) return ShapeRecognitionEngineMode.IACore;
|
||||||
|
if (value == (int)ShapeRecognitionEngineMode.WinRT) return ShapeRecognitionEngineMode.WinRT;
|
||||||
|
return ShapeRecognitionEngineMode.Auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>与具体识别后端无关的形状识别结果,供统一纠正模块消费。</summary>
|
||||||
|
public sealed class InkShapeRecognitionResult
|
||||||
|
{
|
||||||
|
public static readonly InkShapeRecognitionResult Empty = new InkShapeRecognitionResult();
|
||||||
|
|
||||||
|
private InkShapeRecognitionResult()
|
||||||
|
{
|
||||||
|
IsSuccess = false;
|
||||||
|
ShapeName = string.Empty;
|
||||||
|
Centroid = new Point();
|
||||||
|
HotPoints = new PointCollection();
|
||||||
|
StrokesToRemove = new StrokeCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InkShapeRecognitionResult(
|
||||||
|
string shapeName,
|
||||||
|
Point centroid,
|
||||||
|
PointCollection hotPoints,
|
||||||
|
double shapeWidth,
|
||||||
|
double shapeHeight,
|
||||||
|
StrokeCollection strokesToRemove)
|
||||||
|
{
|
||||||
|
ShapeName = shapeName ?? string.Empty;
|
||||||
|
Centroid = centroid;
|
||||||
|
HotPoints = hotPoints ?? new PointCollection();
|
||||||
|
ShapeWidth = shapeWidth;
|
||||||
|
ShapeHeight = shapeHeight;
|
||||||
|
StrokesToRemove = strokesToRemove ?? new StrokeCollection();
|
||||||
|
IsSuccess = StrokesToRemove.Count > 0
|
||||||
|
&& !string.IsNullOrEmpty(ShapeName)
|
||||||
|
&& ShapeName != "Drawing";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSuccess { get; }
|
||||||
|
public string ShapeName { get; }
|
||||||
|
public Point Centroid { get; set; }
|
||||||
|
public PointCollection HotPoints { get; }
|
||||||
|
public double ShapeWidth { get; }
|
||||||
|
public double ShapeHeight { get; }
|
||||||
|
public StrokeCollection StrokesToRemove { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices.WindowsRuntime;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Ink;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using OSVersionExtension;
|
||||||
|
using WinRtInkAnalyzer = global::Windows.UI.Input.Inking.Analysis.InkAnalyzer;
|
||||||
|
using SysPoint = System.Windows.Point;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>基于 Windows.UI.Input.Inking.Analysis 的形状识别(适用于 64 位进程等场景)。</summary>
|
||||||
|
internal static class WinRtInkShapeRecognizer
|
||||||
|
{
|
||||||
|
public static bool IsApiAvailable =>
|
||||||
|
OSVersion.GetOperatingSystem() >= OSVersionExtension.OperatingSystem.Windows10;
|
||||||
|
|
||||||
|
public static void Warmup()
|
||||||
|
{
|
||||||
|
if (!IsApiAvailable) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RecognizeShape(new StrokeCollection());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InkShapeRecognitionResult RecognizeShape(StrokeCollection strokes)
|
||||||
|
{
|
||||||
|
if (!IsApiAvailable || strokes == null || strokes.Count == 0)
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return RecognizeShapeAsync(strokes).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.WriteLine(ex);
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<InkShapeRecognitionResult> RecognizeShapeAsync(StrokeCollection strokes)
|
||||||
|
{
|
||||||
|
var analyzer = new WinRtInkAnalyzer();
|
||||||
|
foreach (Stroke s in strokes)
|
||||||
|
{
|
||||||
|
var inkStroke = CreateInkStrokeFromWpf(s);
|
||||||
|
if (inkStroke != null)
|
||||||
|
analyzer.AddDataForStroke(inkStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var drawing = FindPrimaryDrawing(analyzer);
|
||||||
|
if (drawing == null ||
|
||||||
|
drawing.DrawingKind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
|
||||||
|
var name = MapDrawingKindToShapeName(drawing.DrawingKind);
|
||||||
|
if (string.IsNullOrEmpty(name) || name == "Drawing")
|
||||||
|
return InkShapeRecognitionResult.Empty;
|
||||||
|
|
||||||
|
var winPts = CopyWinRtPoints(drawing);
|
||||||
|
var hot = ToWpfPointCollection(winPts);
|
||||||
|
var c = drawing.Center;
|
||||||
|
var centroid = new SysPoint(c.X, c.Y);
|
||||||
|
BoundsFromPoints(winPts, out double w, out double h);
|
||||||
|
|
||||||
|
var toRemove = new StrokeCollection();
|
||||||
|
foreach (Stroke s in strokes)
|
||||||
|
toRemove.Add(s);
|
||||||
|
|
||||||
|
return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static global::Windows.UI.Input.Inking.InkStroke CreateInkStrokeFromWpf(Stroke stroke)
|
||||||
|
{
|
||||||
|
if (stroke?.StylusPoints == null || stroke.StylusPoints.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var da = stroke.DrawingAttributes;
|
||||||
|
var wda = new global::Windows.UI.Input.Inking.InkDrawingAttributes
|
||||||
|
{
|
||||||
|
PenTip = global::Windows.UI.Input.Inking.PenTipShape.Circle,
|
||||||
|
Color = global::Windows.UI.Color.FromArgb(da.Color.A, da.Color.R, da.Color.G, da.Color.B),
|
||||||
|
Size = new global::Windows.Foundation.Size((float)da.Width, (float)da.Height)
|
||||||
|
};
|
||||||
|
|
||||||
|
var builder = new global::Windows.UI.Input.Inking.InkStrokeBuilder();
|
||||||
|
builder.SetDefaultDrawingAttributes(wda);
|
||||||
|
|
||||||
|
var inkPoints = new List<global::Windows.UI.Input.Inking.InkPoint>(stroke.StylusPoints.Count);
|
||||||
|
foreach (StylusPoint sp in stroke.StylusPoints)
|
||||||
|
{
|
||||||
|
var pi = sp.ToPoint();
|
||||||
|
inkPoints.Add(new global::Windows.UI.Input.Inking.InkPoint(
|
||||||
|
new global::Windows.Foundation.Point((float)pi.X, (float)pi.Y), (float)sp.PressureFactor));
|
||||||
|
}
|
||||||
|
|
||||||
|
var transform = global::Windows.Foundation.Numerics.Matrix3x2.Identity;
|
||||||
|
return builder.CreateStrokeFromInkPoints(inkPoints, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing FindPrimaryDrawing(
|
||||||
|
WinRtInkAnalyzer analyzer)
|
||||||
|
{
|
||||||
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing best = null;
|
||||||
|
double bestArea = -1;
|
||||||
|
Visit(analyzer.AnalysisRoot);
|
||||||
|
return best;
|
||||||
|
|
||||||
|
void Visit(global::Windows.UI.Input.Inking.Analysis.IInkAnalysisNode node)
|
||||||
|
{
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
|
if (node is global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing d &&
|
||||||
|
d.DrawingKind != global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
|
||||||
|
{
|
||||||
|
double area = EstimateDrawingArea(d);
|
||||||
|
if (area > bestArea)
|
||||||
|
{
|
||||||
|
bestArea = area;
|
||||||
|
best = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
Visit(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double EstimateDrawingArea(global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing drawing)
|
||||||
|
{
|
||||||
|
var pts = CopyWinRtPoints(drawing);
|
||||||
|
BoundsFromPoints(pts, out double w, out double h);
|
||||||
|
return w * h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static global::Windows.Foundation.Point[] CopyWinRtPoints(
|
||||||
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing drawing)
|
||||||
|
{
|
||||||
|
var src = drawing?.Points;
|
||||||
|
if (src == null)
|
||||||
|
return Array.Empty<global::Windows.Foundation.Point>();
|
||||||
|
|
||||||
|
var n = src.Count;
|
||||||
|
if (n == 0)
|
||||||
|
return Array.Empty<global::Windows.Foundation.Point>();
|
||||||
|
|
||||||
|
var arr = new global::Windows.Foundation.Point[n];
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
arr[i] = src[i];
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BoundsFromPoints(
|
||||||
|
System.Collections.Generic.IReadOnlyList<global::Windows.Foundation.Point> points,
|
||||||
|
out double w,
|
||||||
|
out double h)
|
||||||
|
{
|
||||||
|
if (points == null || points.Count == 0)
|
||||||
|
{
|
||||||
|
w = h = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double minX = double.MaxValue, maxX = double.MinValue, minY = double.MaxValue, maxY = double.MinValue;
|
||||||
|
for (int i = 0; i < points.Count; i++)
|
||||||
|
{
|
||||||
|
var pt = points[i];
|
||||||
|
minX = Math.Min(minX, pt.X);
|
||||||
|
maxX = Math.Max(maxX, pt.X);
|
||||||
|
minY = Math.Min(minY, pt.Y);
|
||||||
|
maxY = Math.Max(maxY, pt.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
w = Math.Max(0, maxX - minX);
|
||||||
|
h = Math.Max(0, maxY - minY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PointCollection ToWpfPointCollection(
|
||||||
|
System.Collections.Generic.IReadOnlyList<global::Windows.Foundation.Point> points)
|
||||||
|
{
|
||||||
|
var hot = new PointCollection();
|
||||||
|
if (points == null) return hot;
|
||||||
|
for (int i = 0; i < points.Count; i++)
|
||||||
|
{
|
||||||
|
var pt = points[i];
|
||||||
|
hot.Add(new SysPoint(pt.X, pt.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
return hot;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MapDrawingKindToShapeName(
|
||||||
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Circle:
|
||||||
|
return "Circle";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Ellipse:
|
||||||
|
return "Ellipse";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Triangle:
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.IsoscelesTriangle:
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.EquilateralTriangle:
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.RightTriangle:
|
||||||
|
return "Triangle";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Rectangle:
|
||||||
|
return "Rectangle";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Square:
|
||||||
|
return "Square";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Diamond:
|
||||||
|
return "Diamond";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Trapezoid:
|
||||||
|
return "Trapezoid";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Parallelogram:
|
||||||
|
return "Parallelogram";
|
||||||
|
case global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Quadrilateral:
|
||||||
|
return "Quadrilateral";
|
||||||
|
default:
|
||||||
|
return kind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing
|
||||||
|
? "Drawing"
|
||||||
|
: kind.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1112,6 +1112,19 @@
|
|||||||
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||||
Toggled="ToggleSwitchEnableInkToShape_Toggled" />
|
Toggled="ToggleSwitchEnableInkToShape_Toggled" />
|
||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
|
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
|
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=InkRecog_ShapeEngine}" VerticalAlignment="Center"
|
||||||
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
|
<ComboBox Name="ComboBoxShapeRecognitionEngine" Width="160"
|
||||||
|
SelectionChanged="ComboBoxShapeRecognitionEngine_SelectionChanged"
|
||||||
|
FontFamily="Microsoft YaHei UI" VerticalAlignment="Center">
|
||||||
|
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineAuto}" />
|
||||||
|
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineIACore}" />
|
||||||
|
<ComboBoxItem Content="{i18n:I18n Key=InkRecog_ShapeEngineWinRT}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ikw:SimpleStackPanel>
|
||||||
|
<TextBlock Text="{i18n:I18n Key=InkRecog_ShapeEngineHint}" TextWrapping="Wrap"
|
||||||
|
Foreground="#a1a1aa" MaxWidth="520" HorizontalAlignment="Left" />
|
||||||
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
<ikw:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=InkRecog_InkStrokePrediction}" VerticalAlignment="Center"
|
<TextBlock Foreground="#fafafa" Text="{i18n:I18n Key=InkRecog_InkStrokePrediction}" VerticalAlignment="Center"
|
||||||
FontSize="14" Margin="0,0,16,0" />
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
|
|||||||
@@ -1322,11 +1322,13 @@ namespace Ink_Canvas
|
|||||||
BtnWhiteBoardSwitchPrevious.IsEnabled = CurrentWhiteboardIndex != 1;
|
BtnWhiteBoardSwitchPrevious.IsEnabled = CurrentWhiteboardIndex != 1;
|
||||||
BorderInkReplayToolBox.Visibility = Visibility.Collapsed;
|
BorderInkReplayToolBox.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
// 提前加载IA库,优化第一笔等待时间
|
// 提前加载识别后端,优化第一笔等待时间
|
||||||
if (Settings.InkToShape.IsInkToShapeEnabled && !Environment.Is64BitProcess)
|
if (ShapeRecognitionRouter.ShouldRunShapeRecognition(
|
||||||
|
Settings.InkToShape.IsInkToShapeEnabled,
|
||||||
|
ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine)))
|
||||||
{
|
{
|
||||||
var strokeEmpty = new StrokeCollection();
|
InkRecognizeHelper.WarmupShapeRecognition(
|
||||||
InkRecognizeHelper.RecognizeShape(strokeEmpty);
|
ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine));
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemEvents.DisplaySettingsChanged += SystemEventsOnDisplaySettingsChanged;
|
SystemEvents.DisplaySettingsChanged += SystemEventsOnDisplaySettingsChanged;
|
||||||
|
|||||||
@@ -3952,6 +3952,16 @@ namespace Ink_Canvas
|
|||||||
SaveSettingsToFile();
|
SaveSettingsToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ComboBoxShapeRecognitionEngine_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!isLoaded || ComboBoxShapeRecognitionEngine == null) return;
|
||||||
|
int idx = ComboBoxShapeRecognitionEngine.SelectedIndex;
|
||||||
|
if (idx < 0) idx = 0;
|
||||||
|
if (idx > 2) idx = 2;
|
||||||
|
Settings.InkToShape.ShapeRecognitionEngine = idx;
|
||||||
|
SaveSettingsToFile();
|
||||||
|
}
|
||||||
|
|
||||||
private void ToggleSwitchEnableInkToShapeNoFakePressureTriangle_Toggled(object sender, RoutedEventArgs e)
|
private void ToggleSwitchEnableInkToShapeNoFakePressureTriangle_Toggled(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!isLoaded) return;
|
if (!isLoaded) return;
|
||||||
|
|||||||
@@ -1040,6 +1040,13 @@ namespace Ink_Canvas
|
|||||||
{
|
{
|
||||||
ToggleSwitchEnableInkToShape.IsOn = Settings.InkToShape.IsInkToShapeEnabled;
|
ToggleSwitchEnableInkToShape.IsOn = Settings.InkToShape.IsInkToShapeEnabled;
|
||||||
|
|
||||||
|
if (ComboBoxShapeRecognitionEngine != null)
|
||||||
|
{
|
||||||
|
int eng = Settings.InkToShape.ShapeRecognitionEngine;
|
||||||
|
if (eng < 0 || eng > 2) eng = 0;
|
||||||
|
ComboBoxShapeRecognitionEngine.SelectedIndex = eng;
|
||||||
|
}
|
||||||
|
|
||||||
ToggleSwitchEnableInkToShapeNoFakePressureRectangle.IsOn =
|
ToggleSwitchEnableInkToShapeNoFakePressureRectangle.IsOn =
|
||||||
Settings.InkToShape.IsInkToShapeNoFakePressureRectangle;
|
Settings.InkToShape.IsInkToShapeNoFakePressureRectangle;
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace Ink_Canvas
|
|||||||
/// 5. 根据墨水风格设置模拟压感
|
/// 5. 根据墨水风格设置模拟压感
|
||||||
/// 6. 应用高级贝塞尔曲线平滑(仅在未进行直线拉直时)
|
/// 6. 应用高级贝塞尔曲线平滑(仅在未进行直线拉直时)
|
||||||
/// <para>
|
/// <para>
|
||||||
/// 注意:形状识别(圆形、椭圆、三角形、矩形等)仅在32位进程中可用。当 Environment.Is64BitProcess 为 true 时,形状识别功能会被禁用。
|
/// 形状识别:IACore 典型用于 32 位进程;64 位可选用 WinRT(Windows 10+),详见设置「识别引擎」。
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void inkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
|
private void inkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
|
||||||
@@ -384,7 +384,9 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.InkToShape.IsInkToShapeEnabled && !Environment.Is64BitProcess)
|
if (ShapeRecognitionRouter.ShouldRunShapeRecognition(
|
||||||
|
Settings.InkToShape.IsInkToShapeEnabled,
|
||||||
|
ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine)))
|
||||||
{
|
{
|
||||||
void InkToShapeProcess()
|
void InkToShapeProcess()
|
||||||
{
|
{
|
||||||
@@ -403,32 +405,33 @@ namespace Ink_Canvas
|
|||||||
// 处理矩形参考线系统
|
// 处理矩形参考线系统
|
||||||
ProcessRectangleGuideLines(e.Stroke);
|
ProcessRectangleGuideLines(e.Stroke);
|
||||||
|
|
||||||
|
var shapeMode = ShapeRecognitionRouter.FromSettingsInt(Settings.InkToShape.ShapeRecognitionEngine);
|
||||||
var strokeReco = new StrokeCollection();
|
var strokeReco = new StrokeCollection();
|
||||||
var result = InkRecognizeHelper.RecognizeShape(newStrokes);
|
var result = InkRecognizeHelper.RecognizeShapeUnified(newStrokes, shapeMode);
|
||||||
for (var i = newStrokes.Count - 1; i >= 0; i--)
|
for (var i = newStrokes.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
strokeReco.Add(newStrokes[i]);
|
strokeReco.Add(newStrokes[i]);
|
||||||
var newResult = InkRecognizeHelper.RecognizeShape(strokeReco);
|
var newResult = InkRecognizeHelper.RecognizeShapeUnified(strokeReco, shapeMode);
|
||||||
if (newResult.InkDrawingNode.GetShapeName() == "Circle" ||
|
if (newResult.IsSuccess &&
|
||||||
newResult.InkDrawingNode.GetShapeName() == "Ellipse")
|
(newResult.ShapeName == "Circle" || newResult.ShapeName == "Ellipse"))
|
||||||
{
|
{
|
||||||
result = newResult;
|
result = newResult;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//Label.Visibility = Visibility.Visible;
|
|
||||||
//Label.Content = circles.Count.ToString() + "\n" + newResult.InkDrawingNode.GetShapeName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.InkDrawingNode.GetShapeName() == "Circle" &&
|
if (!result.IsSuccess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (result.ShapeName == "Circle" &&
|
||||||
Settings.InkToShape.IsInkToShapeRounded)
|
Settings.InkToShape.IsInkToShapeRounded)
|
||||||
{
|
{
|
||||||
var shape = result.InkDrawingNode.GetShape();
|
if (result.ShapeWidth > 75)
|
||||||
if (shape.Width > 75)
|
|
||||||
{
|
{
|
||||||
foreach (var circle in circles)
|
foreach (var circle in circles)
|
||||||
//判断是否画同心圆
|
//判断是否画同心圆
|
||||||
if (Math.Abs(result.Centroid.X - circle.Centroid.X) / shape.Width < 0.12 &&
|
if (Math.Abs(result.Centroid.X - circle.Centroid.X) / result.ShapeWidth < 0.12 &&
|
||||||
Math.Abs(result.Centroid.Y - circle.Centroid.Y) / shape.Width < 0.12)
|
Math.Abs(result.Centroid.Y - circle.Centroid.Y) / result.ShapeWidth < 0.12)
|
||||||
{
|
{
|
||||||
result.Centroid = circle.Centroid;
|
result.Centroid = circle.Centroid;
|
||||||
break;
|
break;
|
||||||
@@ -441,8 +444,8 @@ namespace Ink_Canvas
|
|||||||
(result.Centroid.Y - circle.Centroid.Y);
|
(result.Centroid.Y - circle.Centroid.Y);
|
||||||
d = Math.Sqrt(d);
|
d = Math.Sqrt(d);
|
||||||
//判断是否画外切圆
|
//判断是否画外切圆
|
||||||
var x = shape.Width / 2.0 + circle.R - d;
|
var x = result.ShapeWidth / 2.0 + circle.R - d;
|
||||||
if (Math.Abs(x) / shape.Width < 0.1)
|
if (Math.Abs(x) / result.ShapeWidth < 0.1)
|
||||||
{
|
{
|
||||||
var sinTheta = (result.Centroid.Y - circle.Centroid.Y) / d;
|
var sinTheta = (result.Centroid.Y - circle.Centroid.Y) / d;
|
||||||
var cosTheta = (result.Centroid.X - circle.Centroid.X) / d;
|
var cosTheta = (result.Centroid.X - circle.Centroid.X) / d;
|
||||||
@@ -452,8 +455,8 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//判断是否画外切圆
|
//判断是否画外切圆
|
||||||
x = Math.Abs(circle.R - shape.Width / 2.0) - d;
|
x = Math.Abs(circle.R - result.ShapeWidth / 2.0) - d;
|
||||||
if (Math.Abs(x) / shape.Width < 0.1)
|
if (Math.Abs(x) / result.ShapeWidth < 0.1)
|
||||||
{
|
{
|
||||||
var sinTheta = (result.Centroid.Y - circle.Centroid.Y) / d;
|
var sinTheta = (result.Centroid.Y - circle.Centroid.Y) / d;
|
||||||
var cosTheta = (result.Centroid.X - circle.Centroid.X) / d;
|
var cosTheta = (result.Centroid.X - circle.Centroid.X) / d;
|
||||||
@@ -463,33 +466,29 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var iniP = new Point(result.Centroid.X - shape.Width / 2,
|
var iniP = new Point(result.Centroid.X - result.ShapeWidth / 2,
|
||||||
result.Centroid.Y - shape.Height / 2);
|
result.Centroid.Y - result.ShapeHeight / 2);
|
||||||
var endP = new Point(result.Centroid.X + shape.Width / 2,
|
var endP = new Point(result.Centroid.X + result.ShapeWidth / 2,
|
||||||
result.Centroid.Y + shape.Height / 2);
|
result.Centroid.Y + result.ShapeHeight / 2);
|
||||||
var pointList = GenerateEllipseGeometry(iniP, endP);
|
var pointList = GenerateEllipseGeometry(iniP, endP);
|
||||||
var point = new StylusPointCollection(pointList);
|
var point = new StylusPointCollection(pointList);
|
||||||
var stroke = new Stroke(point)
|
var stroke = new Stroke(point)
|
||||||
{
|
{
|
||||||
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
|
DrawingAttributes = inkCanvas.DefaultDrawingAttributes.Clone()
|
||||||
};
|
};
|
||||||
circles.Add(new Circle(result.Centroid, shape.Width / 2.0, stroke));
|
circles.Add(new Circle(result.Centroid, result.ShapeWidth / 2.0, stroke));
|
||||||
SetNewBackupOfStroke();
|
SetNewBackupOfStroke();
|
||||||
_currentCommitType = CommitReason.ShapeRecognition;
|
_currentCommitType = CommitReason.ShapeRecognition;
|
||||||
inkCanvas.Strokes.Remove(result.InkDrawingNode.Strokes);
|
inkCanvas.Strokes.Remove(result.StrokesToRemove);
|
||||||
inkCanvas.Strokes.Add(stroke);
|
inkCanvas.Strokes.Add(stroke);
|
||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
newStrokes = new StrokeCollection();
|
newStrokes = new StrokeCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (result.InkDrawingNode.GetShapeName().Contains("Ellipse") &&
|
else if (result.ShapeName.Contains("Ellipse") &&
|
||||||
Settings.InkToShape.IsInkToShapeRounded)
|
Settings.InkToShape.IsInkToShapeRounded)
|
||||||
{
|
{
|
||||||
var shape = result.InkDrawingNode.GetShape();
|
var p = result.HotPoints;
|
||||||
//var shape1 = result.InkDrawingNode.GetShape();
|
|
||||||
//shape1.Fill = Brushes.Gray;
|
|
||||||
//Canvas.Children.Add(shape1);
|
|
||||||
var p = result.InkDrawingNode.HotPoints;
|
|
||||||
var a = GetDistance(p[0], p[2]) / 2; //长半轴
|
var a = GetDistance(p[0], p[2]) / 2; //长半轴
|
||||||
var b = GetDistance(p[1], p[3]) / 2; //短半轴
|
var b = GetDistance(p[1], p[3]) / 2; //短半轴
|
||||||
if (a < b)
|
if (a < b)
|
||||||
@@ -502,12 +501,12 @@ namespace Ink_Canvas
|
|||||||
result.Centroid = new Point((p[0].X + p[2].X) / 2, (p[0].Y + p[2].Y) / 2);
|
result.Centroid = new Point((p[0].X + p[2].X) / 2, (p[0].Y + p[2].Y) / 2);
|
||||||
var needRotation = true;
|
var needRotation = true;
|
||||||
|
|
||||||
if (shape.Width > 75 || (shape.Height > 75 && p.Count == 4))
|
if (result.ShapeWidth > 75 || (result.ShapeHeight > 75 && p.Count == 4))
|
||||||
{
|
{
|
||||||
var iniP = new Point(result.Centroid.X - shape.Width / 2,
|
var iniP = new Point(result.Centroid.X - result.ShapeWidth / 2,
|
||||||
result.Centroid.Y - shape.Height / 2);
|
result.Centroid.Y - result.ShapeHeight / 2);
|
||||||
var endP = new Point(result.Centroid.X + shape.Width / 2,
|
var endP = new Point(result.Centroid.X + result.ShapeWidth / 2,
|
||||||
result.Centroid.Y + shape.Height / 2);
|
result.Centroid.Y + result.ShapeHeight / 2);
|
||||||
|
|
||||||
foreach (var circle in circles)
|
foreach (var circle in circles)
|
||||||
//判断是否画同心椭圆
|
//判断是否画同心椭圆
|
||||||
@@ -515,15 +514,15 @@ namespace Ink_Canvas
|
|||||||
Math.Abs(result.Centroid.Y - circle.Centroid.Y) / a < 0.2)
|
Math.Abs(result.Centroid.Y - circle.Centroid.Y) / a < 0.2)
|
||||||
{
|
{
|
||||||
result.Centroid = circle.Centroid;
|
result.Centroid = circle.Centroid;
|
||||||
iniP = new Point(result.Centroid.X - shape.Width / 2,
|
iniP = new Point(result.Centroid.X - result.ShapeWidth / 2,
|
||||||
result.Centroid.Y - shape.Height / 2);
|
result.Centroid.Y - result.ShapeHeight / 2);
|
||||||
endP = new Point(result.Centroid.X + shape.Width / 2,
|
endP = new Point(result.Centroid.X + result.ShapeWidth / 2,
|
||||||
result.Centroid.Y + shape.Height / 2);
|
result.Centroid.Y + result.ShapeHeight / 2);
|
||||||
|
|
||||||
//再判断是否与圆相切
|
//再判断是否与圆相切
|
||||||
if (Math.Abs(a - circle.R) / a < 0.2)
|
if (Math.Abs(a - circle.R) / a < 0.2)
|
||||||
{
|
{
|
||||||
if (shape.Width >= shape.Height)
|
if (result.ShapeWidth >= result.ShapeHeight)
|
||||||
{
|
{
|
||||||
iniP.X = result.Centroid.X - circle.R;
|
iniP.X = result.Centroid.X - circle.R;
|
||||||
endP.X = result.Centroid.X + circle.R;
|
endP.X = result.Centroid.X + circle.R;
|
||||||
@@ -559,7 +558,7 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
SetNewBackupOfStroke();
|
SetNewBackupOfStroke();
|
||||||
_currentCommitType = CommitReason.ShapeRecognition;
|
_currentCommitType = CommitReason.ShapeRecognition;
|
||||||
inkCanvas.Strokes.Remove(result.InkDrawingNode.Strokes);
|
inkCanvas.Strokes.Remove(result.StrokesToRemove);
|
||||||
newStrokes = new StrokeCollection();
|
newStrokes = new StrokeCollection();
|
||||||
|
|
||||||
var _pointList = GenerateEllipseGeometry(iniP, endP, false);
|
var _pointList = GenerateEllipseGeometry(iniP, endP, false);
|
||||||
@@ -623,23 +622,23 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
SetNewBackupOfStroke();
|
SetNewBackupOfStroke();
|
||||||
_currentCommitType = CommitReason.ShapeRecognition;
|
_currentCommitType = CommitReason.ShapeRecognition;
|
||||||
inkCanvas.Strokes.Remove(result.InkDrawingNode.Strokes);
|
inkCanvas.Strokes.Remove(result.StrokesToRemove);
|
||||||
inkCanvas.Strokes.Add(stroke);
|
inkCanvas.Strokes.Add(stroke);
|
||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
||||||
newStrokes = new StrokeCollection();
|
newStrokes = new StrokeCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (result.InkDrawingNode.GetShapeName().Contains("Triangle") &&
|
else if (result.ShapeName.Contains("Triangle") &&
|
||||||
Settings.InkToShape.IsInkToShapeTriangle)
|
Settings.InkToShape.IsInkToShapeTriangle)
|
||||||
{
|
{
|
||||||
var shape = result.InkDrawingNode.GetShape();
|
var shape = result.InkDrawingNode.GetShape();
|
||||||
var p = result.InkDrawingNode.HotPoints;
|
var p = result.HotPoints;
|
||||||
if ((Math.Max(Math.Max(p[0].X, p[1].X), p[2].X) -
|
if ((Math.Max(Math.Max(p[0].X, p[1].X), p[2].X) -
|
||||||
Math.Min(Math.Min(p[0].X, p[1].X), p[2].X) >= 100 ||
|
Math.Min(Math.Min(p[0].X, p[1].X), p[2].X) >= 100 ||
|
||||||
Math.Max(Math.Max(p[0].Y, p[1].Y), p[2].Y) -
|
Math.Max(Math.Max(p[0].Y, p[1].Y), p[2].Y) -
|
||||||
Math.Min(Math.Min(p[0].Y, p[1].Y), p[2].Y) >= 100) &&
|
Math.Min(Math.Min(p[0].Y, p[1].Y), p[2].Y) >= 100) &&
|
||||||
result.InkDrawingNode.HotPoints.Count == 3)
|
result.HotPoints.Count == 3)
|
||||||
{
|
{
|
||||||
//纠正垂直与水平关系
|
//纠正垂直与水平关系
|
||||||
var newPoints = FixPointsDirection(p[0], p[1]);
|
var newPoints = FixPointsDirection(p[0], p[1]);
|
||||||
@@ -661,27 +660,27 @@ namespace Ink_Canvas
|
|||||||
};
|
};
|
||||||
SetNewBackupOfStroke();
|
SetNewBackupOfStroke();
|
||||||
_currentCommitType = CommitReason.ShapeRecognition;
|
_currentCommitType = CommitReason.ShapeRecognition;
|
||||||
inkCanvas.Strokes.Remove(result.InkDrawingNode.Strokes);
|
inkCanvas.Strokes.Remove(result.StrokesToRemove);
|
||||||
inkCanvas.Strokes.Add(stroke);
|
inkCanvas.Strokes.Add(stroke);
|
||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
||||||
newStrokes = new StrokeCollection();
|
newStrokes = new StrokeCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((result.InkDrawingNode.GetShapeName().Contains("Rectangle") ||
|
else if ((result.ShapeName.Contains("Rectangle") ||
|
||||||
result.InkDrawingNode.GetShapeName().Contains("Diamond") ||
|
result.ShapeName.Contains("Diamond") ||
|
||||||
result.InkDrawingNode.GetShapeName().Contains("Parallelogram") ||
|
result.ShapeName.Contains("Parallelogram") ||
|
||||||
result.InkDrawingNode.GetShapeName().Contains("Square") ||
|
result.ShapeName.Contains("Square") ||
|
||||||
result.InkDrawingNode.GetShapeName().Contains("Trapezoid")) &&
|
result.ShapeName.Contains("Trapezoid")) &&
|
||||||
Settings.InkToShape.IsInkToShapeRectangle)
|
Settings.InkToShape.IsInkToShapeRectangle)
|
||||||
{
|
{
|
||||||
var shape = result.InkDrawingNode.GetShape();
|
var shape = result.InkDrawingNode.GetShape();
|
||||||
var p = result.InkDrawingNode.HotPoints;
|
var p = result.HotPoints;
|
||||||
if ((Math.Max(Math.Max(Math.Max(p[0].X, p[1].X), p[2].X), p[3].X) -
|
if ((Math.Max(Math.Max(Math.Max(p[0].X, p[1].X), p[2].X), p[3].X) -
|
||||||
Math.Min(Math.Min(Math.Min(p[0].X, p[1].X), p[2].X), p[3].X) >= 100 ||
|
Math.Min(Math.Min(Math.Min(p[0].X, p[1].X), p[2].X), p[3].X) >= 100 ||
|
||||||
Math.Max(Math.Max(Math.Max(p[0].Y, p[1].Y), p[2].Y), p[3].Y) -
|
Math.Max(Math.Max(Math.Max(p[0].Y, p[1].Y), p[2].Y), p[3].Y) -
|
||||||
Math.Min(Math.Min(Math.Min(p[0].Y, p[1].Y), p[2].Y), p[3].Y) >= 100) &&
|
Math.Min(Math.Min(Math.Min(p[0].Y, p[1].Y), p[2].Y), p[3].Y) >= 100) &&
|
||||||
result.InkDrawingNode.HotPoints.Count == 4)
|
result.HotPoints.Count == 4)
|
||||||
{
|
{
|
||||||
//纠正垂直与水平关系
|
//纠正垂直与水平关系
|
||||||
var newPoints = FixPointsDirection(p[0], p[1]);
|
var newPoints = FixPointsDirection(p[0], p[1]);
|
||||||
@@ -706,7 +705,7 @@ namespace Ink_Canvas
|
|||||||
};
|
};
|
||||||
SetNewBackupOfStroke();
|
SetNewBackupOfStroke();
|
||||||
_currentCommitType = CommitReason.ShapeRecognition;
|
_currentCommitType = CommitReason.ShapeRecognition;
|
||||||
inkCanvas.Strokes.Remove(result.InkDrawingNode.Strokes);
|
inkCanvas.Strokes.Remove(result.StrokesToRemove);
|
||||||
inkCanvas.Strokes.Add(stroke);
|
inkCanvas.Strokes.Add(stroke);
|
||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
||||||
|
|||||||
@@ -224,6 +224,11 @@
|
|||||||
<data name="Gesture_PalmHint" xml:space="preserve"><value># Low: larger area/more touches required (less false positive); High: easier to trigger but may mis-detect fingers.</value></data>
|
<data name="Gesture_PalmHint" xml:space="preserve"><value># Low: larger area/more touches required (less false positive); High: easier to trigger but may mis-detect fingers.</value></data>
|
||||||
<data name="InkRecog_Title" xml:space="preserve"><value>Ink correction</value></data>
|
<data name="InkRecog_Title" xml:space="preserve"><value>Ink correction</value></data>
|
||||||
<data name="InkRecog_EnableInkRecognition" xml:space="preserve"><value>Enable ink recognition</value></data>
|
<data name="InkRecog_EnableInkRecognition" xml:space="preserve"><value>Enable ink recognition</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngine" xml:space="preserve"><value>Recognition engine</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineHint" xml:space="preserve"><value># Auto: WinRT on 64-bit (Windows 10+), IACore on 32-bit. You can force IACore or WinRT.</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineAuto" xml:space="preserve"><value>Auto</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineIACore" xml:space="preserve"><value>IACore</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineWinRT" xml:space="preserve"><value>WinRT</value></data>
|
||||||
<data name="InkRecog_InkStrokePrediction" xml:space="preserve"><value>Ink stroke prediction</value></data>
|
<data name="InkRecog_InkStrokePrediction" xml:space="preserve"><value>Ink stroke prediction</value></data>
|
||||||
<data name="InkRecog_InkStrokePredictionHint" xml:space="preserve"><value># When on, shows a short ahead-of-stroke hint while inking. Choose Auto (speed-based), 25 ms, or 50 ms lead.</value></data>
|
<data name="InkRecog_InkStrokePredictionHint" xml:space="preserve"><value># When on, shows a short ahead-of-stroke hint while inking. Choose Auto (speed-based), 25 ms, or 50 ms lead.</value></data>
|
||||||
<data name="InkRecog_BlockRectFakePressure" xml:space="preserve"><value>Block fake pressure on corrected rectangles</value></data>
|
<data name="InkRecog_BlockRectFakePressure" xml:space="preserve"><value>Block fake pressure on corrected rectangles</value></data>
|
||||||
|
|||||||
@@ -239,6 +239,11 @@
|
|||||||
<data name="Gesture_PalmHint" xml:space="preserve"><value># 低敏感度:需要更大的触摸面积和更多触摸点,减少误判;高敏感度:更容易触发手掌擦,但可能误判手指。</value></data>
|
<data name="Gesture_PalmHint" xml:space="preserve"><value># 低敏感度:需要更大的触摸面积和更多触摸点,减少误判;高敏感度:更容易触发手掌擦,但可能误判手指。</value></data>
|
||||||
<data name="InkRecog_Title" xml:space="preserve"><value>墨迹纠正</value></data>
|
<data name="InkRecog_Title" xml:space="preserve"><value>墨迹纠正</value></data>
|
||||||
<data name="InkRecog_EnableInkRecognition" xml:space="preserve"><value>启用墨迹识别</value></data>
|
<data name="InkRecog_EnableInkRecognition" xml:space="preserve"><value>启用墨迹识别</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngine" xml:space="preserve"><value>识别引擎</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineHint" xml:space="preserve"><value># 自动:64 位进程使用 WinRT(Windows 10+),32 位使用 IACore。可强制指定 IACore 或 WinRT。</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineAuto" xml:space="preserve"><value>自动</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineIACore" xml:space="preserve"><value>IACore</value></data>
|
||||||
|
<data name="InkRecog_ShapeEngineWinRT" xml:space="preserve"><value>WinRT</value></data>
|
||||||
<data name="InkRecog_InkStrokePrediction" xml:space="preserve"><value>墨迹预测</value></data>
|
<data name="InkRecog_InkStrokePrediction" xml:space="preserve"><value>墨迹预测</value></data>
|
||||||
<data name="InkRecog_InkStrokePredictionHint" xml:space="preserve"><value># 开启后可在书写时显示短暂外推预览线。打开开关后可选择:自动(随速度调整)、固定 25ms 或 50ms 提前量。</value></data>
|
<data name="InkRecog_InkStrokePredictionHint" xml:space="preserve"><value># 开启后可在书写时显示短暂外推预览线。打开开关后可选择:自动(随速度调整)、固定 25ms 或 50ms 提前量。</value></data>
|
||||||
<data name="InkRecog_BlockRectFakePressure" xml:space="preserve"><value>阻止矫正后的矩形带有模拟压感值</value></data>
|
<data name="InkRecog_BlockRectFakePressure" xml:space="preserve"><value>阻止矫正后的矩形带有模拟压感值</value></data>
|
||||||
|
|||||||
@@ -762,6 +762,12 @@ namespace Ink_Canvas
|
|||||||
public double LineStraightenSensitivity { get; set; } = 0.20;
|
public double LineStraightenSensitivity { get; set; } = 0.20;
|
||||||
[JsonProperty("lineNormalizationThreshold")]
|
[JsonProperty("lineNormalizationThreshold")]
|
||||||
public double LineNormalizationThreshold { get; set; } = 0.5;
|
public double LineNormalizationThreshold { get; set; } = 0.5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 形状识别后端:0=自动(x64 用 WinRT,x86 用 IACore),1=IACore,2=WinRT。
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("shapeRecognitionEngine")]
|
||||||
|
public int ShapeRecognitionEngine { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RandSettings
|
public class RandSettings
|
||||||
|
|||||||
Reference in New Issue
Block a user