2026-03-28 20:29:12 +08:00
|
|
|
using OSVersionExtension;
|
2026-03-28 17:40:14 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2026-04-26 03:01:17 +00:00
|
|
|
using System.Threading;
|
2026-03-28 17:40:14 +08:00
|
|
|
using System.Threading.Tasks;
|
2026-03-28 18:30:40 +08:00
|
|
|
using System.Windows;
|
2026-03-28 17:40:14 +08:00
|
|
|
using System.Windows.Ink;
|
2026-03-28 17:52:30 +08:00
|
|
|
using System.Windows.Input;
|
2026-03-28 17:40:14 +08:00
|
|
|
using System.Windows.Media;
|
|
|
|
|
using SysPoint = System.Windows.Point;
|
2026-03-28 20:29:12 +08:00
|
|
|
using WinRtInkAnalyzer = global::Windows.UI.Input.Inking.Analysis.InkAnalyzer;
|
2026-03-28 17:40:14 +08:00
|
|
|
|
|
|
|
|
namespace Ink_Canvas.Helpers
|
|
|
|
|
{
|
2026-04-26 03:01:17 +00:00
|
|
|
internal class ModernInkAnalyzer : IDisposable
|
|
|
|
|
{
|
|
|
|
|
public static readonly Guid ShapeStrokePropertyGuid = new Guid("11111111-2222-3333-4444-555555555555");
|
2026-04-30 14:29:06 +08:00
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
private global::Windows.UI.Input.Inking.Analysis.InkAnalyzer _internalAnalyzer;
|
|
|
|
|
private readonly Dictionary<Stroke, uint> _strokeIdMap = new Dictionary<Stroke, uint>();
|
|
|
|
|
private readonly Dictionary<uint, Stroke> _reverseIdMap = new Dictionary<uint, Stroke>();
|
|
|
|
|
private readonly object _syncLock = new object();
|
|
|
|
|
|
2026-04-26 04:19:30 +00:00
|
|
|
public ModernInkAnalyzer()
|
2026-04-26 03:01:17 +00:00
|
|
|
{
|
|
|
|
|
if (!WinRtInkShapeRecognizer.IsApiAvailable)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_internalAnalyzer = new global::Windows.UI.Input.Inking.Analysis.InkAnalyzer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddStrokeInternal(Stroke stroke)
|
|
|
|
|
{
|
|
|
|
|
if (stroke.ContainsPropertyData(ShapeStrokePropertyGuid))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var inkStroke = WinRtInkShapeRecognizer.CreateInkStrokeFromWpf(stroke);
|
|
|
|
|
if (inkStroke == null) return;
|
|
|
|
|
|
|
|
|
|
_internalAnalyzer.AddDataForStroke(inkStroke);
|
|
|
|
|
_internalAnalyzer.SetStrokeDataKind(
|
|
|
|
|
inkStroke.Id,
|
|
|
|
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
|
2026-04-30 14:29:06 +08:00
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
_strokeIdMap[stroke] = inkStroke.Id;
|
|
|
|
|
_reverseIdMap[inkStroke.Id] = stroke;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private CancellationTokenSource _cts;
|
|
|
|
|
|
2026-04-26 04:19:30 +00:00
|
|
|
public async Task<InkShapeRecognitionResult> AnalyzeAsync(StrokeCollection strokes)
|
2026-04-26 03:01:17 +00:00
|
|
|
{
|
2026-04-26 04:19:30 +00:00
|
|
|
if (_internalAnalyzer == null || strokes == null || strokes.Count == 0)
|
2026-04-26 03:01:17 +00:00
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
_cts?.Cancel();
|
|
|
|
|
_cts = new CancellationTokenSource();
|
|
|
|
|
var token = _cts.Token;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2026-04-26 04:19:30 +00:00
|
|
|
lock (_syncLock)
|
|
|
|
|
{
|
|
|
|
|
_internalAnalyzer.ClearDataForAllStrokes();
|
|
|
|
|
_strokeIdMap.Clear();
|
|
|
|
|
_reverseIdMap.Clear();
|
|
|
|
|
|
|
|
|
|
foreach (var stroke in strokes)
|
|
|
|
|
{
|
|
|
|
|
AddStrokeInternal(stroke);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_strokeIdMap.Count == 0)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
var result = await _internalAnalyzer.AnalyzeAsync().AsTask(token).ConfigureAwait(true);
|
|
|
|
|
|
|
|
|
|
if (token.IsCancellationRequested) return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
// Use the internal method from WinRtInkShapeRecognizer to find the primary drawing
|
|
|
|
|
var drawing = WinRtInkShapeRecognizer.FindPrimaryDrawing(_internalAnalyzer);
|
|
|
|
|
if (drawing == null)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
if (drawing.DrawingKind == global::Windows.UI.Input.Inking.Analysis.InkAnalysisDrawingKind.Drawing)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
var name = WinRtInkShapeRecognizer.MapDrawingKindToShapeName(drawing.DrawingKind);
|
|
|
|
|
if (string.IsNullOrEmpty(name) || name == "Drawing")
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
var winPts = WinRtInkShapeRecognizer.CopyWinRtPoints(drawing);
|
|
|
|
|
var hot = WinRtInkShapeRecognizer.ToWpfPointCollection(winPts);
|
|
|
|
|
var c = drawing.Center;
|
|
|
|
|
var centroid = new SysPoint(c.X, c.Y);
|
|
|
|
|
WinRtInkShapeRecognizer.BoundsFromPoints(winPts, out double w, out double h);
|
|
|
|
|
|
|
|
|
|
var toRemove = new StrokeCollection();
|
|
|
|
|
lock (_syncLock)
|
|
|
|
|
{
|
|
|
|
|
foreach (var id in drawing.GetStrokeIds())
|
|
|
|
|
{
|
|
|
|
|
if (_reverseIdMap.TryGetValue(id, out var stroke))
|
|
|
|
|
{
|
|
|
|
|
toRemove.Add(stroke);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (toRemove.Count == 0)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<StrokeCollection> AnalyzeAndCorrectAsync(
|
|
|
|
|
StrokeCollection strokes,
|
|
|
|
|
string handwritingFontFamilyList)
|
|
|
|
|
{
|
|
|
|
|
return WinRtHandwritingRecognizer.ConvertRecognizedTextToHandwritingInkAsync(
|
|
|
|
|
strokes,
|
|
|
|
|
handwritingFontFamilyList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_internalAnalyzer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 17:40:14 +08:00
|
|
|
/// <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
|
|
|
|
|
{
|
2026-03-28 18:30:40 +08:00
|
|
|
var d = Application.Current?.Dispatcher;
|
|
|
|
|
if (d == null) return;
|
|
|
|
|
d.BeginInvoke(new Action(async () =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2026-04-05 18:52:19 +08:00
|
|
|
// 空 StrokeCollection 在 RecognizeShapeAsync 入口会直接返回,无法预热 WinRT InkAnalyzer。
|
|
|
|
|
await RecognizeShapeAsync(CreateMinimalWarmupStrokeCollection()).ConfigureAwait(true);
|
2026-03-28 18:30:40 +08:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
}));
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 18:30:40 +08:00
|
|
|
/// <summary>由 <see cref="ModernInkProcessor"/> / <see cref="InkRecognitionManager"/> 在 UI 上 await(勿在收笔回调中同步阻塞)。</summary>
|
|
|
|
|
internal static async Task<InkShapeRecognitionResult> RecognizeShapeAsync(StrokeCollection strokes)
|
2026-03-28 17:40:14 +08:00
|
|
|
{
|
2026-03-28 18:40:18 +08:00
|
|
|
if (!IsApiAvailable || strokes == null || strokes.Count == 0)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
try
|
2026-03-28 17:40:14 +08:00
|
|
|
{
|
2026-03-28 18:40:18 +08:00
|
|
|
var analyzer = new WinRtInkAnalyzer();
|
|
|
|
|
var added = 0;
|
|
|
|
|
foreach (Stroke s in strokes)
|
|
|
|
|
{
|
|
|
|
|
var inkStroke = CreateInkStrokeFromWpf(s);
|
|
|
|
|
if (inkStroke == null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
analyzer.AddDataForStroke(inkStroke);
|
|
|
|
|
analyzer.SetStrokeDataKind(
|
|
|
|
|
inkStroke.Id,
|
|
|
|
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisStrokeKind.Drawing);
|
|
|
|
|
added++;
|
|
|
|
|
}
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
if (added == 0)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
await analyzer.AnalyzeAsync().AsTask().ConfigureAwait(true);
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
var drawing = FindPrimaryDrawing(analyzer);
|
|
|
|
|
if (drawing == null)
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
|
|
|
|
|
if (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;
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
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);
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
var toRemove = new StrokeCollection();
|
|
|
|
|
foreach (Stroke s in strokes)
|
|
|
|
|
toRemove.Add(s);
|
2026-03-28 17:40:14 +08:00
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
return new InkShapeRecognitionResult(name, centroid, hot, w, h, toRemove);
|
|
|
|
|
}
|
2026-03-28 19:21:47 +08:00
|
|
|
catch (Exception)
|
2026-03-28 18:40:18 +08:00
|
|
|
{
|
|
|
|
|
return InkShapeRecognitionResult.Empty;
|
|
|
|
|
}
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 18:52:19 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// 极短合成笔画,供 <see cref="Warmup"/> 等场景走完整 WinRT 转换与分析管线(空集合在入口处会被直接返回)。
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal static StrokeCollection CreateMinimalWarmupStrokeCollection()
|
|
|
|
|
{
|
|
|
|
|
var da = new DrawingAttributes { Color = Colors.Black, Width = 2, Height = 2 };
|
|
|
|
|
var pts = new StylusPointCollection
|
|
|
|
|
{
|
|
|
|
|
new StylusPoint(8, 8),
|
|
|
|
|
new StylusPoint(14, 10),
|
|
|
|
|
new StylusPoint(20, 8),
|
|
|
|
|
};
|
|
|
|
|
var col = new StrokeCollection();
|
|
|
|
|
col.Add(new Stroke(pts, da));
|
|
|
|
|
return col;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 12:24:13 +08:00
|
|
|
/// <summary>供 WinRT 手写等模块复用:将 WPF <see cref="Stroke"/> 转为 WinRT <see cref="global::Windows.UI.Input.Inking.InkStroke"/>。</summary>
|
|
|
|
|
internal static global::Windows.UI.Input.Inking.InkStroke CreateInkStrokeFromWpf(Stroke stroke)
|
2026-03-28 17:40:14 +08:00
|
|
|
{
|
|
|
|
|
if (stroke?.StylusPoints == null || stroke.StylusPoints.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var da = stroke.DrawingAttributes;
|
2026-04-19 08:10:45 +08:00
|
|
|
if (da == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
2026-03-28 17:40:14 +08:00
|
|
|
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);
|
|
|
|
|
|
2026-03-28 18:10:28 +08:00
|
|
|
var points = new List<global::Windows.Foundation.Point>(stroke.StylusPoints.Count);
|
2026-03-28 17:40:14 +08:00
|
|
|
foreach (StylusPoint sp in stroke.StylusPoints)
|
|
|
|
|
{
|
|
|
|
|
var pi = sp.ToPoint();
|
2026-03-28 18:10:28 +08:00
|
|
|
points.Add(new global::Windows.Foundation.Point((float)pi.X, (float)pi.Y));
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-28 18:10:28 +08:00
|
|
|
if (points.Count == 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
return builder.CreateStroke(points);
|
2026-03-28 17:40:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
internal static global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing FindPrimaryDrawing(
|
|
|
|
|
global::Windows.UI.Input.Inking.Analysis.InkAnalyzer analyzer)
|
2026-03-28 17:40:14 +08:00
|
|
|
{
|
|
|
|
|
global::Windows.UI.Input.Inking.Analysis.InkAnalysisInkDrawing best = null;
|
|
|
|
|
double bestArea = -1;
|
2026-03-28 18:40:18 +08:00
|
|
|
if (analyzer?.AnalysisRoot != null)
|
|
|
|
|
Visit(analyzer.AnalysisRoot);
|
2026-03-28 17:40:14 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 18:40:18 +08:00
|
|
|
// WinRT IInkAnalysisNode.Children 可能为 null,不可直接 foreach。
|
|
|
|
|
var children = node.Children;
|
|
|
|
|
if (children == null) return;
|
|
|
|
|
|
|
|
|
|
foreach (var child in children)
|
2026-03-28 17:40:14 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
internal static global::Windows.Foundation.Point[] CopyWinRtPoints(
|
2026-03-28 17:40:14 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
internal static void BoundsFromPoints(
|
2026-03-28 17:40:14 +08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
internal static PointCollection ToWpfPointCollection(
|
2026-03-28 17:40:14 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-26 03:01:17 +00:00
|
|
|
internal static string MapDrawingKindToShapeName(
|
2026-03-28 17:40:14 +08:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|