private void OnPreviewLeftMouseDown(object sender, MouseButtonEventArgs e)
        {
            Point mouseScreenPoint = e.GetPosition(mapControl).ToMapsui();
            var   draggingFeature  = GetFeaturesAtScreenPoint(mouseScreenPoint).OfType <DraggingFeature>().FirstOrDefault();

            if (draggingFeature == null && insertionPreviewFeature != null)
            {
                int   insertedIndex  = insertionPreviewFeature.Index;
                Point insertedVertex = insertionPreviewFeature.Vertex;
                draggingFeature = InsertVertex(insertedIndex, insertedVertex);

                draggingLayer.TryRemove(insertionPreviewFeature);
                insertionPreviewFeature = null;
            }

            if (draggingFeature != null)
            {
                // Preventing map panning
                e.Handled = true;

                this.draggingFeature = draggingFeature;
                Point mouseWorldPoint = ScreenPointToGlobal(mouseScreenPoint);
                draggingOffset = mouseWorldPoint - draggingFeature.Vertex;
                return;
            }
        }
        protected override void EndImpl()
        {
            UnsubscribeMouseEvents();

            draggingLayer.Clear();
            draggingLayer.Refresh();
            insertionPreviewFeature = null;
            editedObject            = null;
        }
        private void OnPreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (draggingFeature != null)
            {
                Point mousePoint = ScreenPointToGlobal(e.GetPosition(mapControl).ToMapsui());
                draggingFeature.Vertex = mousePoint - draggingOffset;
                draggingLayer.Refresh();
                targetLayer.Refresh();
            }
            else
            {
                Point mouseScreenPoint = e.GetPosition(mapControl).ToMapsui();

                if (GetFeaturesAtScreenPoint(mouseScreenPoint).OfType <DraggingFeature>().Any())
                {
                    TryRemoveInsertionPreviewFeature();
                    return;
                }

                Point mouseWorldPoint = ScreenPointToGlobal(mouseScreenPoint);
                Point previewPoint;
                int   index;
                GetInsertionPreviewPoint(mouseScreenPoint, mouseWorldPoint, out previewPoint, out index);

                if (previewPoint != null)
                {
                    UpdateInsertionPreviewFeature(previewPoint, index);
                }
                else
                {
                    TryRemoveInsertionPreviewFeature();
                }
            }

            ///////// Helper local funcs
            void TryRemoveInsertionPreviewFeature()
            {
                if (insertionPreviewFeature != null)
                {
                    draggingLayer.TryRemove(insertionPreviewFeature);
                    insertionPreviewFeature = null;
                    draggingLayer.Refresh();
                }
            }

            void UpdateInsertionPreviewFeature(Point previewPoint, int index)
            {
                if (insertionPreviewFeature == null)
                {
                    insertionPreviewFeature = new InsertionPreviewFeature(editedObject, previewPoint, index);
                    draggingLayer.Add(insertionPreviewFeature);
                }
                insertionPreviewFeature.Update(previewPoint, index);
                draggingLayer.Refresh();
            }

            void GetInsertionPreviewPoint(Point mouseScreenPoint, Point mouseWorldPoint, out Point previewPoint, out int index)
            {
                IList <Point> vertices = editedObject.Vertices;

                previewPoint = null;
                index        = -1;
                double minDistance = double.PositiveInfinity;

                int prevI, i;

                if (editedObject.AreVerticesLooped)
                {
                    prevI = vertices.Count - 1;
                    i     = 0;
                }
                else
                {
                    // The branch above allows to insert points between end and start vertices.
                    // If the shape is not like a ring, we should be able to to this
                    prevI = 0;
                    i     = 1;
                }

                for (; i < vertices.Count; i++)
                {
                    Point  closestPoint   = GetClosestPoint(mouseWorldPoint, vertices[prevI], vertices[i]);
                    Point  screenPerpBase = GlobalPointToScreen(closestPoint);
                    double screenDistance = screenPerpBase.Distance(mouseScreenPoint);
                    if (screenDistance < VertexInsertionDistance && screenDistance < minDistance)
                    {
                        minDistance  = screenDistance;
                        previewPoint = closestPoint;
                        index        = i;
                    }
                    prevI = i;
                }
            }

            ///////// End helper local funcs
        }