private PointShape GetSnappingPoint(Vertex originVertex, Feature affectedFeature, bool preventSameVertex = true)
        {
            PolygonShape            affectedPolygon   = affectedFeature.GetShape() as PolygonShape;
            Collection <PointShape> tmpSnappingPoints = new Collection <PointShape>();

            if (editOverlay != null && snappingLayers.Count != 0)
            {
                //we only snaps to selected features when the selected features are from the EditTargetLayer
                IEnumerable <FeatureLayer> currentSnappingLayers = snappingLayers;
                if (editOverlay.SnappingLayers.Any(snappingLayer => snappingLayer == editOverlay.EditTargetLayer))
                {
                    currentSnappingLayers = currentSnappingLayers.Concat(new FeatureLayer[] { editOverlay.EditShapesLayer });
                }

                foreach (var snappingLayer in currentSnappingLayers)
                {
                    lock (snappingLayer)
                    {
                        if (!snappingLayer.IsOpen)
                        {
                            snappingLayer.Open();
                        }

                        var     boundingBox     = MapArguments.CurrentExtent;
                        var     screenWidth     = MapArguments.ActualWidth;
                        Feature snappingFeature = null;
                        try
                        {
                            SnappingAdapter calc = SnappingAdapter.Convert(snappingDistance, snappingDistanceUnit, MapArguments, originVertex);
                            snappingFeature = snappingLayer.QueryTools.
                                              GetFeaturesWithinDistanceOf(new Feature(originVertex), MapArguments.MapUnit, calc.DistanceUnit, calc.Distance, ReturningColumnsType.NoColumns).FirstOrDefault(f => f.Id != affectedFeature.Id);
                        }
                        catch { }
                        BaseShape snappingShape = null;
                        if (snappingFeature != null && (snappingShape = snappingFeature.GetShape()) != null)
                        {
                            SnappingAdapter calc          = SnappingAdapter.Convert(snappingDistance, snappingDistanceUnit, MapArguments, originVertex);
                            PointShape      snappingPoint = GisEditorEditInteractiveOverlay.GetSnappingPoint(snappingShape, new PointShape(originVertex), MapArguments.MapUnit, calc.Distance, calc.DistanceUnit);

                            if (preventSameVertex && (affectedPolygon != null && !affectedPolygon.OuterRing.Vertices.Any(v => v.X == snappingPoint.X && v.Y == snappingPoint.Y)))
                            {
                                return(snappingPoint);
                            }
                            else
                            {
                                return(snappingPoint);
                            }
                        }
                    }
                }
            }

            PointShape originPoint = new PointShape(originVertex);

            return(originPoint);
        }
        private Vertex GetClosestVertex(List <Vertex> vertices, PointShape point)
        {
            Vertex result = vertices.FirstOrDefault();

            if (vertices.Count > 0)
            {
                result = vertices.OrderBy(v => (v.X - point.X) * (v.X - point.X) + (v.Y - point.Y) * (v.Y - point.Y)).First();
            }

            if (result != default(Vertex))
            {
                double          distanceInMeter = point.GetDistanceTo(new PointShape(result), MapArguments.MapUnit, DistanceUnit.Meter);
                SnappingAdapter calc            = SnappingAdapter.Convert(SnappingDistance, SnappingDistanceUnit, MapArguments, point);
                double          radiusInMeter   = Conversion.ConvertMeasureUnits(calc.Distance, calc.DistanceUnit, DistanceUnit.Meter);
                if (distanceInMeter > radiusInMeter)
                {
                    result = new Vertex(point);
                }
            }

            return(result);
        }
        protected override InteractiveResult MouseMoveCore(InteractionArguments interactionArguments)
        {
            if (isShiftKeyDown)
            {
                var circle = OverlayCanvas.Children.OfType <System.Windows.Shapes.Ellipse>().FirstOrDefault();
                if (circle != null)
                {
                    OverlayCanvas.Children.Remove(circle);
                }
            }

            if (IsDirty && TrackMode != TrackMode.None)
            {
                CollectionVertices(interactionArguments);
            }

            UpdateArguments(interactionArguments);

            if (TrackMode != TrackMode.None &&
                MouseDownCount < 1 &&
                SnappingLayers.Count > 0)
            {
                lock (OverlayCanvas.Children)
                {
                    Vertex currentPosition = new Vertex(interactionArguments.WorldX, interactionArguments.WorldY);

                    var snappingCircle = OverlayCanvas.Children.OfType <System.Windows.Shapes.Ellipse>().FirstOrDefault();
                    if (snappingCircle == null)
                    {
                        snappingCircle = new System.Windows.Shapes.Ellipse();
                        snappingCircle.IsHitTestVisible    = false;
                        snappingCircle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                        snappingCircle.VerticalAlignment   = System.Windows.VerticalAlignment.Top;
                        snappingCircle.Stroke          = new SolidColorBrush(Colors.Black);
                        snappingCircle.StrokeThickness = 1;
                        OverlayCanvas.Children.Add(snappingCircle);
                    }

                    var snappingDistance     = SnappingDistance;
                    var snappingDistanceUnit = SnappingDistanceUnit;
                    var snappingScreenPoint  = ExtentHelper.ToScreenCoordinate(MapArguments.CurrentExtent, currentPosition.X, currentPosition.Y, (float)MapArguments.ActualWidth, (float)MapArguments.ActualHeight);

                    try
                    {
                        SnappingAdapter calc         = SnappingAdapter.Convert(snappingDistance, snappingDistanceUnit, MapArguments, currentPosition);
                        var             snappingArea = new PointShape(currentPosition.X, currentPosition.Y)
                                                       .Buffer(calc.Distance, MapArguments.MapUnit, calc.DistanceUnit)
                                                       .GetBoundingBox();

                        var snappingScreenSize = Math.Max(snappingArea.Width, snappingArea.Height) / MapArguments.CurrentResolution;
                        snappingCircle.Width  = snappingScreenSize;
                        snappingCircle.Height = snappingScreenSize;
                        snappingCircle.Margin = new System.Windows.Thickness(snappingScreenPoint.X - snappingScreenSize * .5, snappingScreenPoint.Y - snappingScreenSize * .5, 0, 0);
                    }
                    catch
                    { }
                }
            }
            else
            {
                lock (OverlayCanvas.Children)
                {
                    var circle = OverlayCanvas.Children.OfType <System.Windows.Shapes.Ellipse>().FirstOrDefault();
                    if (circle != null)
                    {
                        OverlayCanvas.Children.Remove(circle);
                    }
                }
            }


            var interactiveResult = base.MouseMoveCore(interactionArguments);

            return(interactiveResult);
        }
        protected override void OnMouseMoved(MouseMovedTrackInteractiveOverlayEventArgs e)
        {
            base.OnMouseMoved(e);

            var trackShape = GetTrackingShape();

            if (!isShiftKeyDown && trackShape != null && (TrackMode == TrackMode.Polygon || TrackMode == TrackMode.Line) &&
                editOverlay != null && editOverlay.SnappingLayers.Count > 0)
            {
                lock (OverlayCanvas.Children)
                {
                    var snappingCircle = OverlayCanvas.Children.OfType <System.Windows.Shapes.Ellipse>().FirstOrDefault();
                    if (snappingCircle == null)
                    {
                        snappingCircle = new System.Windows.Shapes.Ellipse();
                        snappingCircle.IsHitTestVisible    = false;
                        snappingCircle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                        snappingCircle.VerticalAlignment   = System.Windows.VerticalAlignment.Top;
                        snappingCircle.Stroke          = new SolidColorBrush(Colors.Black);
                        snappingCircle.StrokeThickness = 1;
                        OverlayCanvas.Children.Add(snappingCircle);
                    }

                    var snappingDistance     = editOverlay.SnappingDistance;
                    var snappingDistanceUnit = editOverlay.SnappingDistanceUnit;
                    var snappingScreenPoint  = ExtentHelper.ToScreenCoordinate(MapArguments.CurrentExtent, e.MovedVertex.X, e.MovedVertex.Y, (float)MapArguments.ActualWidth, (float)MapArguments.ActualHeight);

                    try
                    {
                        SnappingAdapter calc         = SnappingAdapter.Convert(snappingDistance, snappingDistanceUnit, MapArguments, e.MovedVertex);
                        var             snappingArea = new PointShape(e.MovedVertex.X, e.MovedVertex.Y)
                                                       .Buffer(calc.Distance, editOverlay.MapArguments.MapUnit, calc.DistanceUnit)
                                                       .GetBoundingBox();

                        var snappingScreenSize = Math.Max(snappingArea.Width, snappingArea.Height) / MapArguments.CurrentResolution;
                        snappingCircle.Width  = snappingScreenSize;
                        snappingCircle.Height = snappingScreenSize;
                        snappingCircle.Margin = new System.Windows.Thickness(snappingScreenPoint.X - snappingScreenSize * .5, snappingScreenPoint.Y - snappingScreenSize * .5, 0, 0);
                    }
                    catch
                    { }
                }

                //PointShape snappedPoint = GetSnappingPoint(e.MovedVertex, e.AffectedFeature);
                //if (snappedPoint != null)
                //{
                //    e.MovedVertex = new Vertex(snappedPoint);
                //    lock (OverlayCanvas.Children)
                //    {
                //        var snappingCircle = OverlayCanvas.Children.OfType<System.Windows.Shapes.Ellipse>().FirstOrDefault();
                //        if (snappingCircle == null)
                //        {
                //            snappingCircle = new System.Windows.Shapes.Ellipse();
                //            snappingCircle.IsHitTestVisible = false;
                //            snappingCircle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                //            snappingCircle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
                //            snappingCircle.Stroke = new SolidColorBrush(Colors.Black);
                //            snappingCircle.StrokeThickness = 1;
                //            OverlayCanvas.Children.Add(snappingCircle);
                //        }

                //        var snappingDistance = editOverlay.SnappingDistance;
                //        var snappingDistanceUnit = editOverlay.SnappingDistanceUnit;
                //        var snappingScreenPoint = ExtentHelper.ToScreenCoordinate(MapArguments.CurrentExtent, snappedPoint, (float)MapArguments.ActualWidth, (float)MapArguments.ActualHeight);

                //        SnappingAdapter calc = SnappingAdapter.Convert(snappingDistance, snappingDistanceUnit, MapArguments, e.MovedVertex);
                //        var snappingArea = snappedPoint.Buffer(calc.Distance, editOverlay.MapArguments.MapUnit, calc.DistanceUnit).GetBoundingBox();
                //        var snappingScreenSize = Math.Max(snappingArea.Width, snappingArea.Height) / MapArguments.CurrentResolution;
                //        snappingCircle.Width = snappingScreenSize;
                //        snappingCircle.Height = snappingScreenSize;
                //        snappingCircle.Margin = new System.Windows.Thickness(snappingScreenPoint.X - snappingScreenSize * .5, snappingScreenPoint.Y - snappingScreenSize * .5, 0, 0);
                //    }
                //}
            }
        }