private void DrawHorizontalLine(InkRecognitionUnit recoUnit, CanvasDrawEventArgs args)
        {
            float height = (float)recoUnit.boundingRectangle.height;
            float width  = (float)recoUnit.boundingRectangle.width;

            // The ink recognizer does not recognize horizontal lines, however this check is used as a heuristic to render horizontal lines on the result canvas
            if (height <= 10 && width >= 20)
            {
                // Bottom left and right corner points of rotated bounding rectangle
                float pointAX = (float)recoUnit.rotatedBoundingRectangle[0].x;
                float pointAY = (float)recoUnit.rotatedBoundingRectangle[0].y;
                float pointBX = (float)recoUnit.rotatedBoundingRectangle[1].x;

                var pointA = new Vector2(pointAX * dipsPerMm, pointAY * dipsPerMm);
                var pointB = new Vector2(pointBX * dipsPerMm, pointAY * dipsPerMm);

                // Color of line
                var color = GetStrokeColor(recoUnit);

                // Stroke thickness
                float strokeWidth = GetStrokeWidth(recoUnit);

                args.DrawingSession.DrawLine(pointA, pointB, color, strokeWidth);
            }
        }
        private Color GetStrokeColor(InkRecognitionUnit recoUnit)
        {
            uint strokeId = (uint)recoUnit.strokeIds[0];
            var  color    = inkCanvas.InkPresenter.StrokeContainer.GetStrokeById(strokeId).DrawingAttributes.Color;

            return(color);
        }
        private void DrawPolygon(InkRecognitionUnit recoUnit, CanvasDrawEventArgs args)
        {
            if (recoUnit.points.Count > 0)
            {
                // Create new list of points for polygon to be drawn
                var pointsList = new List <Vector2>();
                foreach (var inkPoint in recoUnit.points)
                {
                    float x = (float)inkPoint.x;
                    float y = (float)inkPoint.y;

                    var point = new Vector2(x * dipsPerMm, y * dipsPerMm);

                    pointsList.Add(point);
                }

                // Create shape from list of points
                var points = pointsList.ToArray();
                var shape  = CanvasGeometry.CreatePolygon(args.DrawingSession, points);

                // Color of polygon
                var color = GetStrokeColor(recoUnit);

                // Stroke thickness
                float strokeWidth = GetStrokeWidth(recoUnit);

                args.DrawingSession.DrawGeometry(shape, color, strokeWidth);
            }
        }
        private float GetStrokeWidth(InkRecognitionUnit recoUnit)
        {
            uint strokeId = (uint)recoUnit.strokeIds[0];

            Size  size        = inkCanvas.InkPresenter.StrokeContainer.GetStrokeById(strokeId).DrawingAttributes.Size;
            float strokeWidth = (float)size.Width;

            return(strokeWidth);
        }
        private void AddText(InkRecognitionUnit recoUnit)
        {
            string recognizedText = recoUnit.recognizedText;

            if (recognizedText != null)
            {
                int id = recoUnit.id;

                // Color of ink word or ink bullet
                var color = GetStrokeColor(recoUnit);

                var text = new Tuple <string, Color>(recognizedText, color);
                recoText.Add(id, text);
            }
        }
        private void DrawEllipse(InkRecognitionUnit recoUnit, CanvasDrawEventArgs args)
        {
            var initialTransformation = args.DrawingSession.Transform;

            // Rotated bounding rectangle points to get correct angle of ellipse being drawn
            float floatX = (float)recoUnit.boundingRectangle.topX;
            float floatY = (float)recoUnit.boundingRectangle.topY;

            float topLeftX = (float)recoUnit.rotatedBoundingRectangle[0].x;
            float topLeftY = (float)recoUnit.rotatedBoundingRectangle[0].y;

            float topRightX = (float)recoUnit.rotatedBoundingRectangle[1].x;
            float topRightY = (float)recoUnit.rotatedBoundingRectangle[1].y;

            float bottomRightX = (float)recoUnit.rotatedBoundingRectangle[2].x;
            float bottomRightY = (float)recoUnit.rotatedBoundingRectangle[2].y;

            float bottomLeftX = (float)recoUnit.rotatedBoundingRectangle[3].x;
            float bottomLeftY = (float)recoUnit.rotatedBoundingRectangle[3].y;

            // Center point of ellipse
            float centerPointX = (float)recoUnit.center.x;
            float centerPointY = (float)recoUnit.center.y;

            var centerPoint = new Vector2(centerPointX * dipsPerMm, centerPointY * dipsPerMm);

            // X and Y diameter of ellipse
            float diameterX = GetDistanceBetweenPoints(bottomLeftX, bottomRightX, bottomLeftY, bottomRightY) * dipsPerMm;
            float diameterY = GetDistanceBetweenPoints(topRightX, bottomRightX, topRightY, bottomRightY) * dipsPerMm;

            // Transform to get correct angle of ellipse
            float transformCenterPointX = ((topLeftX + topRightX) / 2) * dipsPerMm;
            float transformCenterPointY = ((topLeftY + bottomLeftY) / 2) * dipsPerMm;
            var   transformCenterPoint  = new Vector2(transformCenterPointX, transformCenterPointY);

            Matrix3x2 angle = GetRotationAngle(bottomLeftX, bottomRightX, bottomLeftY, bottomRightY, transformCenterPoint);

            args.DrawingSession.Transform = angle;

            // Color of ellipse
            var color = GetStrokeColor(recoUnit);

            // Stroke thickness
            float strokeWidth = GetStrokeWidth(recoUnit);

            args.DrawingSession.DrawEllipse(centerPoint, diameterX / 2, diameterY / 2, color, strokeWidth);
            args.DrawingSession.Transform = initialTransformation;
        }
        private void DrawCircle(InkRecognitionUnit recoUnit, CanvasDrawEventArgs args)
        {
            // Center point and diameter of circle
            float floatX      = (float)recoUnit.center.x;
            float floatY      = (float)recoUnit.center.y;
            var   centerPoint = new Vector2(floatX * dipsPerMm, floatY * dipsPerMm);

            float diameter = (float)recoUnit.boundingRectangle.width;

            // Color of circle
            var color = GetStrokeColor(recoUnit);

            // Stroke thickness
            var strokeWidth = GetStrokeWidth(recoUnit);

            args.DrawingSession.DrawCircle(centerPoint, (diameter * dipsPerMm) / 2, color, strokeWidth);
        }
        private void DrawShape(InkRecognitionUnit recoUnit, CanvasDrawEventArgs args)
        {
            string recognizedObject = recoUnit.recognizedObject;

            switch (recognizedObject)
            {
            case "circle":
                DrawCircle(recoUnit, args);
                break;

            case "ellipse":
                DrawEllipse(recoUnit, args);
                break;

            case "drawing":
                DrawHorizontalLine(recoUnit, args);
                break;

            default:
                DrawPolygon(recoUnit, args);
                break;
            }
        }
        private List <TreeViewNode> GetChildNodes(InkRecognitionUnit recoUnit)
        {
            var nodes = new List <TreeViewNode>();

            // Iterate over each of the ink recognition unit's children to append them to their parent node
            foreach (int id in recoUnit.childIds)
            {
                InkRecognitionUnit unit = recoTreeNodes[id];
                var node = new TreeViewNode();

                string category = unit.category;
                if (category == "inkWord" || category == "inkBullet")
                {
                    node.Content = new KeyValuePair <string, string>(category, unit.recognizedText);
                }
                else
                {
                    string childCount = $"{unit.childIds.Count} item{(unit.childIds.Count > 1 ? "s" : string.Empty)}";
                    node.Content = new KeyValuePair <string, string>(category, childCount);
                }

                // If the child of the current ink recognition unit also has children recurse to append them to the child node as well
                if (unit.childIds != null)
                {
                    var childNodes = GetChildNodes(unit);
                    foreach (var child in childNodes)
                    {
                        node.Children.Add(child);
                    }
                }

                nodes.Add(node);
            }

            return(nodes);
        }
        private void DrawText(InkRecognitionUnit recoUnit, CanvasControl sender, CanvasDrawEventArgs args)
        {
            var childIds = recoUnit.childIds;
            var initialTransformation = args.DrawingSession.Transform;

            // Points of bounding rectangle to align drawn text
            float floatX = (float)recoUnit.boundingRectangle.topX;
            float floatY = (float)recoUnit.boundingRectangle.topY;

            // Rotated bounding rectangle points to get correct angle of text being drawn
            float topLeftX = (float)recoUnit.rotatedBoundingRectangle[0].x;
            float topLeftY = (float)recoUnit.rotatedBoundingRectangle[0].y;

            float topRightX = (float)recoUnit.rotatedBoundingRectangle[1].x;
            float topRightY = (float)recoUnit.rotatedBoundingRectangle[1].y;

            float bottomRightX = (float)recoUnit.rotatedBoundingRectangle[2].x;
            float bottomRightY = (float)recoUnit.rotatedBoundingRectangle[2].y;

            float bottomLeftX = (float)recoUnit.rotatedBoundingRectangle[3].x;
            float bottomLeftY = (float)recoUnit.rotatedBoundingRectangle[3].y;

            // Height and width of bounding rectangle to get font size and width for text layout
            float height = GetDistanceBetweenPoints(topRightX, bottomRightX, topRightY, bottomRightY) * dipsPerMm;
            float width  = GetDistanceBetweenPoints(bottomLeftX, bottomRightX, bottomLeftY, bottomRightY) * dipsPerMm;

            if (height < 45)
            {
                height = 45;
            }

            // Transform to get correct angle of text
            float centerPointX = ((topLeftX + topRightX) / 2) * dipsPerMm;
            float centerPointY = ((topLeftY + bottomLeftY) / 2) * dipsPerMm;
            var   centerPoint  = new Vector2(centerPointX, centerPointY);

            Matrix3x2 angle = GetRotationAngle(bottomLeftX, bottomRightX, bottomLeftY, bottomRightY, centerPoint);

            args.DrawingSession.Transform = angle;

            var textFormat = new CanvasTextFormat()
            {
                FontSize     = height - 5,
                WordWrapping = CanvasWordWrapping.NoWrap,
                FontFamily   = "Ink Free"
            };

            // Build string to be drawn to canvas
            string textLine = string.Empty;

            foreach (var item in childIds)
            {
                int id = int.Parse(item.ToString());

                // Deconstruct the tuple to get the recognized text from it
                (string text, _) = recoText[id];

                textLine += text + " ";
            }

            var textLayout = new CanvasTextLayout(sender.Device, textLine, textFormat, width, height);

            // Associate correct color with each word in string
            int index = 0;

            foreach (var item in childIds)
            {
                int id = int.Parse(item.ToString());

                // Deconstruct the tuple to get the recognized text and color from it
                (string text, Color color) = recoText[id];

                textLayout.SetColor(index, text.Length, color);

                index += text.Length + 1;
            }

            args.DrawingSession.DrawTextLayout(textLayout, floatX * dipsPerMm, floatY * dipsPerMm, Colors.Black);
            args.DrawingSession.Transform = initialTransformation;
        }