简体   繁体   English

使用C#WPF缩放和平移地图图像

[英]Zoom and Pan a Map Image with C# WPF

I'm trying to make a map from an image using the projection of Robinson. 我正在尝试使用罗宾逊的投影从图像制作地图。 The idea is to give the image the same behaviors of a normal map, so the user should be able to zoom and pan on the map, it should be also able to mark the localisation that he want using a pushpin. 这个想法是使图像具有与普通地图相同的行为,因此用户应该能够在地图上缩放和平移,还应该能够使用图钉标记他想要的位置。

To do this I create a class that manage the zoom and pan behaviors, and a user control that manage the projection. 为此,我创建一个管理缩放和平移行为的类,以及一个管理投影的用户控件。

Th problem that i have now is that i can't fix the pushpin on the image, and it lose it's position when i'm zooming. 我现在遇到的问题是我无法将图钉固定在图像上,并且在缩放时会丢失它的位置。 Also when the map scale is over 1, the push pin is not placed on the right position. 同样,当地图比例超过1时,图钉也不会放置在正确的位置。

If anyone has an idea of how can I fix this problem, please help. 如果有人知道如何解决此问题,请提供帮助。

Here is the code of the class and of the user control. 这是该类和用户控件的代码。

ZoomPan.cs ZoomPan.cs

    #region Properties

    private Canvas m_Map;
    private UIElement m_Pin;

    private Point m_Origin;
    private Point m_Start;
    public bool IsMouseWheel = false;

    #endregion

    #region Method

    /// <summary>
    /// Initialize child Events.
    /// </summary>
    public void Initialize()
    {
        m_Map = this.Children[0] as Canvas;
        m_Pin = this.Children[1];

        if (this.Children.Count >= 0)
        {
            TransformGroup aMapGroup = new TransformGroup();
            ScaleTransform aMapScale = new ScaleTransform();
            aMapGroup.Children.Add(aMapScale);
            TranslateTransform aMapTranslate = new TranslateTransform();
            aMapGroup.Children.Add(aMapTranslate);

            m_Map.RenderTransform = aMapGroup;
            m_Map.RenderTransformOrigin = new Point(0.0, 0.0);

            TransformGroup aPinGroup = new TransformGroup();
            ScaleTransform aPinScale = new ScaleTransform();
            aPinGroup.Children.Add(aPinScale);
            TranslateTransform aPinTranslate = new TranslateTransform();
            aPinGroup.Children.Add(aPinTranslate);

            m_Pin.RenderTransform = aPinGroup;
            m_Pin.RenderTransformOrigin = new Point(0.0, 0.0);

            this.MouseWheel += child_MouseWheel;
            this.MouseLeftButtonDown += child_MouseLeftButtonDown;
            this.MouseLeftButtonUp += child_MouseLeftButtonUp;
            this.MouseMove += child_MouseMove;
        }
    }

    /// <summary>
    /// Get Translate Transform.
    /// </summary>
    private TranslateTransform GetTranslateTransform(UIElement element)
    {
        return (TranslateTransform)((TransformGroup)element.RenderTransform)
          .Children.First(tr => tr is TranslateTransform);
    }

    /// <summary>
    /// Get Scale Transform.
    /// </summary>
    private ScaleTransform GetScaleTransform(UIElement element)
    {
        return (ScaleTransform)((TransformGroup)element.RenderTransform)
          .Children.First(tr => tr is ScaleTransform);
    }

    /// <summary>
    /// Set Translation.
    /// </summary>
    private double SetTranslation(double p_Max, double p_Vector)
    {
        if (p_Vector < -p_Max)
        {
            return -p_Max;
        }
        else
        {
            return p_Vector;
        }
    }

    /// <summary>
    /// Pan Child
    /// </summary>
    private void PanChild(double p_TranslateX, double p_TranslateY)
    {
        var transform = m_Pin.TransformToVisual(m_Map);
        Point p = transform.Transform(new Point(0, 0));

        p.ToString();

        var aMapScale = GetScaleTransform(m_Map);
        var aMapTranslation = GetTranslateTransform(m_Map);

        var aPinScale = GetScaleTransform(m_Pin);
        var aPinTranslation = GetTranslateTransform(m_Pin);

        if (p_TranslateX < 0)
        {
            aMapTranslation.X = SetTranslation(this.ActualWidth * (aMapScale.ScaleX - 1), p_TranslateX);
            aPinTranslation.X = SetTranslation(this.ActualWidth * (aMapScale.ScaleX - 1), p_TranslateX);
        }
        else
        {
            aMapTranslation.X = 0;
            aPinTranslation.X = 0;
        }

        if (p_TranslateY < 0)
        {
            aMapTranslation.Y = SetTranslation(this.ActualHeight * (aMapScale.ScaleY - 1), p_TranslateY);
            aPinTranslation.Y = SetTranslation(this.ActualWidth * (aMapScale.ScaleY - 1), p_TranslateY);
        }
        else
        {
            aMapTranslation.Y = 0;
            aPinTranslation.Y = 0;
        }
    }

    #endregion

    #region Child Events

    /// <summary>
    /// On Mouse Wheele (Zoom).
    /// </summary>
    private void child_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (m_Map != null && m_Pin !=null)
        {
            IsMouseWheel = true;

            var aMapScale = GetScaleTransform(m_Map);
            var aMapTranslation = GetTranslateTransform(m_Map);

            var aPinScale = GetScaleTransform(m_Pin);
            var aPinTranslation = GetTranslateTransform(m_Pin);

            double zoom = e.Delta > 0 ? .5 : -.5;

            if (!(e.Delta > 0) && (aMapScale.ScaleX <= 1 || aMapScale.ScaleY <= 1))
            {
                return;
            }

            Point relative = e.GetPosition(m_Map);

            double abosuluteX;
            double abosuluteY;

            abosuluteX = relative.X * aMapScale.ScaleX + aMapTranslation.X;
            abosuluteY = relative.Y * aMapScale.ScaleY + aMapTranslation.Y;

            if (aMapScale.ScaleX >= 7 || aMapScale.ScaleY >= 7)
            {
                if (e.Delta > 0)
                {
                    return;
                }
            }

            aMapScale.ScaleX += zoom;
            aMapScale.ScaleY += zoom;

            CUserControlMap.m_Zoom = (int)(aMapScale.ScaleX - 1) * 2;

            double X = abosuluteX - relative.X * aMapScale.ScaleX;
            double Y = abosuluteY - relative.Y * aMapScale.ScaleY;

            PanChild(X, Y);
        }
    }

    /// <summary>
    /// Mouse Left Button Down (Translate).
    /// </summary>
    private void child_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (m_Map != null && m_Pin !=null)
        {
            var aMapScale = GetScaleTransform(m_Map);

            if (aMapScale.ScaleX == 1 || aMapScale.ScaleY == 1)
            {
                return;
            }

            var aMapTranslation = GetTranslateTransform(m_Map);
            m_Start = e.GetPosition(this);
            m_Origin = new Point(aMapTranslation.X, aMapTranslation.Y);
            this.Cursor = Cursors.CCursors.CursorHand;
            m_Map.CaptureMouse();
        }
    }


    /// <summary>
    /// Mouse Left Button Up.
    /// </summary>
    private void child_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (m_Map != null && m_Pin !=null)
        {
            m_Map.ReleaseMouseCapture();
            this.Cursor = Cursors.CCursors.CursorArrow;
        }
    }

    /// <summary>
    /// Mouse Move
    /// </summary>
    private void child_MouseMove(object sender, MouseEventArgs e)
    {
        if (m_Map != null && m_Pin != null)
        {
            if (m_Map.IsMouseCaptured)
            {
                var aMapScale = GetScaleTransform(m_Map);
                var aMapTranslation = GetTranslateTransform(m_Map);

                var aPinScale = GetScaleTransform(m_Pin);
                var aPinTranslation = GetTranslateTransform(m_Pin);

                Vector v = m_Start - e.GetPosition(this);

                double X = m_Origin.X - v.X;
                double Y = m_Origin.Y - v.Y;

                PanChild(X, Y);
            }
        }
    }
    #endregion
}

The code of MapControl.cs MapControl.cs的代码

    #region Properties

    /// <summary> Latitude</summary>
    public float Latitude = 0;

    /// <summary> Longitude</summary>
    public float Longitude = 0;

    /// <summary> Longitude in Pixels</summary>
    private static double s_kLongitudeInPixel = 0.81;

    /// <summary> Latitude in Pixels</summary>
    private static double s_kLatitudeInPixel = 0.71;

    /// <summary> Middle of the map</summary>
    private static double s_KMiddle = 206;

    /// <summary> Pin Image</summary>
    private Image m_Pin = new Image();

    public static double m_Zoom = 0;

    #endregion

    #region Constructor

    /// <summary>
    /// Constructor
    /// </summary>
    public CUserControlMap()
    {
        InitializeComponent();

        m_Pin.Source = Application.Current.TryFindResource("Pin") as BitmapImage;
        m_Pin.Height = 24;
        m_Pin.Width = 30;

        m_Canvas.Children.Add(m_Pin);
        m_Canvas.Initialize();
    }

    #endregion

    #region Methods

    /// <summary>
    /// Add a pin to the current Localization
    /// </summary>
    public void SetCurrentLocalization(float p_latitude, float p_longitude)
    {
        double pointX = GetXFromLongitude(p_longitude);
        double pointY = GetYFromLatitude(p_latitude);

        m_Pin.Margin = new Thickness(pointX + 97 , pointY - 22, 0, 0);
    }

    /// <summary>
    /// Get X from longitude
    /// </summary>
    private double GetXFromLongitude(float p_longitude)
    {
        return (p_longitude / s_kLongitudeInPixel) + (s_KMiddle / 2);
    }

    /// <summary>
    /// Get Y from latitude
    /// </summary>
    private double GetYFromLatitude(float p_latitude)
    {
        return (m_Image.Height / 2) - (p_latitude / s_kLatitudeInPixel);
    }

    #endregion

    #region Events

    /// <summary>
    /// Image Mouse Right Button Down
    /// </summary>
    private void Image_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        Point point = e.GetPosition(m_Image);

        Longitude = (float)(point.X - s_KMiddle) * (float)s_kLongitudeInPixel;
        Latitude = (float)(m_Image.Height / 2 - point.Y) * (float)s_kLatitudeInPixel;

        SetCurrentLocalization((float)Latitude, (float)Longitude);
    }

    #endregion

Use LayoutTransform instead of RenderTransform. 使用LayoutTransform而不是RenderTransform。 More details here: http://msdn.microsoft.com/en-us/library/ms750596.aspx#layoutTransformsAndRenderTransformsSection 此处有更多详细信息: http : //msdn.microsoft.com/zh-cn/library/ms750596.aspx#layoutTransformsAndRenderTransformsSection

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM