/// <summary>
        /// Creates the vertical and horizontal Guide Paths
        /// </summary>
        /// <param name="pixel"></param>
        private void SuggestAltGuidePaths(SKPoint pixel)
        {
            float       x        = pixel.X;
            float       y        = pixel.Y;
            var         pathList = new List <BondPath>();
            const float len      = 200;

            var path = new BondPath();

            path.MoveTo(x, y);
            path.LineTo(x, y + len);
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x, y - len);
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x + len, y);
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x - len, y);
            pathList.Add(path);

            guidePaths[pixel].AddRange(pathList);
        }
        /// <summary>
        /// Creates the diagonal Guide Paths
        /// </summary>
        /// <param name="pixel"></param>
        private void SuggestGuidePaths(SKPoint pixel)
        {
            float        x        = pixel.X;
            float        y        = pixel.Y;
            var          pathList = new List <BondPath>();
            const float  len      = 200;
            const double ang      = 0.5235987756; // 30 degrees from horizontal to get 120 deg diagonals for hexagons

            var path = new BondPath();

            path.MoveTo(x, y);
            path.LineTo(x + len * (float)Math.Cos(ang), y + len * (float)Math.Sin(ang));
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x + len * (float)Math.Cos(ang), y - len * (float)Math.Sin(ang));
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x - len * (float)Math.Cos(ang), y + len * (float)Math.Sin(ang));
            pathList.Add(path);

            path = new BondPath();
            path.MoveTo(x, y);
            path.LineTo(x - len * (float)Math.Cos(ang), y - len * (float)Math.Sin(ang));
            pathList.Add(path);

            guidePaths.Add(pixel, pathList);
        }
        private void MakeNewPathFromPoint(TouchActionEventArgs args, SKPoint pt)
        {
            inProgressPaths.Remove(args.Id);
            BondPath newPath = new BondPath();

            newPath.MoveTo(pt);
            inProgressPaths.Add(args.Id, newPath);
        }
        /// <summary>
        /// Processes touch input
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void TouchEffect_OnTouchAction(object sender, TouchActionEventArgs args)
        {
            switch (args.Type)
            {
            // An individual press
            // If canvas is blank then it purely suggests the guide paths
            // If the canvas is not blank then the touch only registers if it hits on an existing atom
            case TouchActionType.Pressed:
                if (!inProgressPaths.ContainsKey(args.Id))
                {
                    guidePaths.Clear();
                    BondPath path  = new BondPath();
                    var      pixel = ConvertToPixel(args.Location);

                    if (completedPaths.Count > 0)
                    {
                        foreach (var pth in completedPaths)
                        {
                            if (SKPoint.Distance(pth[0], pixel) < 50)
                            {
                                pixel = pth[0];
                                SuggestGuidePaths(pixel);
                                SuggestAltGuidePaths(pixel);
                                break;
                            }
                            if (SKPoint.Distance(pth.LastPoint, pixel) < 50)
                            {
                                pixel = pth.LastPoint;
                                SuggestGuidePaths(pixel);
                                SuggestAltGuidePaths(pixel);
                                break;
                            }
                        }
                        GuidePathTrim(pixel);
                    }

                    path.MoveTo(pixel);
                    inProgressPaths.Add(args.Id, path);



                    if (completedPaths.Count == 0)
                    {
                        SuggestGuidePaths(pixel);
                        SuggestAltGuidePaths(pixel);
                    }


                    canvasView.InvalidateSurface();
                }
                break;

            // Drag the line to the end of the template line and then it becomes a 'completed line'
            case TouchActionType.Moved:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    BondPath path       = inProgressPaths[args.Id];
                    var      firstPoint = path[0];
                    path.Rewind();
                    path.MoveTo(firstPoint);
                    path.LineTo(ConvertToPixel(args.Location));

                    if (guidePaths.ContainsKey(firstPoint))
                    {
                        BondPath linqPath = guidePaths[firstPoint]
                                            .FirstOrDefault(pth => SKPoint.Distance(pth.LastPoint, path.LastPoint) < 30);
                        if (linqPath != null)
                        {
                            guidePaths.Remove(linqPath[0]);
                            linqPath.Order = BondOrderFromPicker();
                            completedPaths.Add(linqPath);
                            undoStack.Push("path");
                            MakeNewPathFromPoint(args, linqPath.LastPoint);
                            SuggestGuidePaths(linqPath.LastPoint);
                            SuggestAltGuidePaths(linqPath.LastPoint);
                            GuidePathTrim(linqPath.LastPoint);
                        }
                    }
                    canvasView.InvalidateSurface();
                }

                break;

            case TouchActionType.Released:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    inProgressPaths.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }

                break;

            case TouchActionType.Cancelled:
                if (inProgressPaths.ContainsKey(args.Id))
                {
                    inProgressPaths.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }

                break;
            }
        }