2010-08-20 6 views
0

위치가 위도와 경도의 객체가 포함 된 캔버스를 만들어야합니다.캔버스의 원점을 변경하십시오.

내 캔버스 지원 요소의 드래그하고 확대하지만 지금까지 나는 항상 표준

가 지금은 GPS의 좌표를 가지고 GPS의 COORD 45 ° 사이의 예를 들어 있기 때문에 모든 객체가 서로 오버랩 (0,0에서) 좌표 사용했다 11'00'N과 45 ° 11'60N ...이 변환을 해결할 수 없다면 근본적으로 1px입니다. 캔버스는 0,0부터 시작하고 항상 공백 45 픽셀을가집니다.

최소 왼쪽 및 위쪽 값을 검색하고 크기를 다시 계산할 수 있지만 캔버스의 모든 개체를 가운데에 배치하는 방법은 무엇입니까?

답변

0

블로그 게시물을 어느 시점에서 할 예정이며 아직 수행 중입니다. 그러나 간단히 말해서 나는이 문제를 단지 메르카토르 투영법에 따라 어린이를 배치하는 방법을 이해하는 자신의 패널을 작성함으로써 해결했습니다. 사용하기 전에 알아야 할

어떤 것들은 :

  • 당신은 당신의 배경 이미지에서 지원됩니다 어떤 범위로 MaxLatitudeMaxLongitude를 설정해야합니다.
  • 양방향 업데이트가 아직 지원되지 않는다고 생각합니다. 내 블로그 게시물 이전에이 문제를 해결할 계획이었습니다.

는이처럼 사용

<ListBox ItemsSource="{Binding YourItems}"> 
    <ListBox.Template> 
     <ControlTemplate> 
      <Border BorderBrush="Black" BorderThickness="1" Background="#CEE3FF"> 
       <Grid> 
        <Grid.Resources> 
         <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}">Transparent</SolidColorBrush> 
         <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}">Transparent</SolidColorBrush> 
        </Grid.Resources> 
        <Image x:Name="mapImage" Source="YourMap.png"/> 
        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" Width="{Binding ActualWidth, ElementName=mapImage}" Height="{Binding ActualHeight, ElementName=mapImage}" /> 
       </Grid> 
      </Border> 
     </ControlTemplate> 
    </ListBox.Template> 
    <ListBox.ItemsPanel> 
     <ItemsPanelTemplate> 
      <!-- make sure you set these values in line with YourMap.png --> 
      <controls:MercatorProjectionPanel MaxLatitude="81" MinLatitude="-74"/> 
     </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
    <ListBox.ItemContainerStyle> 
     <Style TargetType="ListBoxItem"> 
      <Setter Property="controls:MercatorProjectionPanel.Longitude" Value="{Binding Location.Longitude}"/> 
      <Setter Property="controls:MercatorProjectionPanel.Latitude" Value="{Binding Location.Latitude}"/> 
     </Style> 
    </ListBox.ItemContainerStyle> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <TextBlock>Here's your item</TextBlock> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

여기에 코드입니다 : 내가 블로그 게시물에 주위를 얻는 경우에

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 

/// <summary> 
/// Implements a panel that lays out children according to the mercator projection. 
/// </summary> 
public class MercatorProjectionPanel : Panel 
{ 
    /// <summary> 
    /// Identifies the <see cref="MinLatitude"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty MinLatitudeProperty = DependencyProperty.Register(
     "MinLatitude", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(DefaultMinLatitude, OnLatitudeRangeChanged)); 

    /// <summary> 
    /// Identifies the <see cref="MaxLatitude"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty MaxLatitudeProperty = DependencyProperty.Register(
     "MaxLatitude", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(DefaultMaxLatitude, OnLatitudeRangeChanged)); 

    /// <summary> 
    /// Identifies the <c>Longitude</c> attached dependency property. 
    /// </summary> 
    public static readonly DependencyProperty LongitudeProperty = DependencyProperty.RegisterAttached(
     "Longitude", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN, OnGeographicalCoordinateChanged)); 

    /// <summary> 
    /// Identifies the <c>Latitude</c> attached dependency property. 
    /// </summary> 
    public static readonly DependencyProperty LatitudeProperty = DependencyProperty.RegisterAttached(
     "Latitude", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN, OnGeographicalCoordinateChanged)); 

    /// <summary> 
    /// Identifies the <c>Left</c> attached dependency property. 
    /// </summary> 
    public static readonly DependencyProperty LeftProperty = DependencyProperty.RegisterAttached(
     "Left", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN, OnCoordinateChanged)); 

    /// <summary> 
    /// Identifies the <c>Top</c> attached dependency property. 
    /// </summary> 
    public static readonly DependencyProperty TopProperty = DependencyProperty.RegisterAttached(
     "Top", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN, OnCoordinateChanged)); 

    private static readonly DependencyProperty XRatioProperty = DependencyProperty.RegisterAttached(
     "XRatio", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN)); 

    private static readonly DependencyProperty YRatioProperty = DependencyProperty.RegisterAttached(
     "YRatio", 
     typeof(double), 
     typeof(MercatorProjectionPanel), 
     new FrameworkPropertyMetadata(double.NaN)); 

    private const double DefaultMinLatitude = -80; 
    private const double DefaultMaxLatitude = 80; 
    private const double DegreesPerRadian = 57.2957; 

    private double minY = CalculateYRelative(DefaultMinLatitude); 
    private double maxY = CalculateYRelative(DefaultMaxLatitude); 

    /// <summary> 
    /// Initializes a new instance of the MercatorProjectionPanel class. 
    /// </summary> 
    public MercatorProjectionPanel() 
    { 
     SizeChanged += delegate 
     { 
      InvalidateArrange(); 
     }; 
    } 

    /// <summary> 
    /// Gets or sets the minimum latitude displayed by this mercator projection panel. 
    /// </summary> 
    public double MinLatitude 
    { 
     get { return (double)GetValue(MinLatitudeProperty); } 
     set { SetValue(MinLatitudeProperty, value); } 
    } 

    /// <summary> 
    /// Gets or sets the maximum latitude displayed by this mercator projection panel. 
    /// </summary> 
    public double MaxLatitude 
    { 
     get { return (double)GetValue(MaxLatitudeProperty); } 
     set { SetValue(MaxLatitudeProperty, value); } 
    } 

    /// <summary> 
    /// Gets the longitude for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The longitude. 
    /// </returns> 
    public static double GetLongitude(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(LongitudeProperty); 
    } 

    /// <summary> 
    /// Sets the longitude for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="longitude"> 
    /// The longitude. 
    /// </param> 
    public static void SetLongitude(DependencyObject dependencyObject, double longitude) 
    { 
     dependencyObject.SetValue(LongitudeProperty, longitude); 
    } 

    /// <summary> 
    /// Gets the latitude for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The latitude. 
    /// </returns> 
    public static double GetLatitude(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(LatitudeProperty); 
    } 

    /// <summary> 
    /// Sets the latitude for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="latitude"> 
    /// The latitude. 
    /// </param> 
    public static void SetLatitude(DependencyObject dependencyObject, double latitude) 
    { 
     dependencyObject.SetValue(LatitudeProperty, latitude); 
    } 

    /// <summary> 
    /// Gets the left offset for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The left offset. 
    /// </returns> 
    public static double GetLeft(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(LeftProperty); 
    } 

    /// <summary> 
    /// Sets the left offset for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="left"> 
    /// The left offset. 
    /// </param> 
    public static void SetLeft(DependencyObject dependencyObject, double left) 
    { 
     dependencyObject.SetValue(LeftProperty, left); 
    } 

    /// <summary> 
    /// Gets the top offset for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The top offset. 
    /// </returns> 
    public static double GetTop(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(TopProperty); 
    } 

    /// <summary> 
    /// Sets the top offset for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="top"> 
    /// The top offset. 
    /// </param> 
    public static void SetTop(DependencyObject dependencyObject, double top) 
    { 
     dependencyObject.SetValue(TopProperty, top); 
    } 

    /// <summary> 
    /// Gets the horizontal alignment for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The horizontal alignment. 
    /// </returns> 
    public static HorizontalAlignment GetHorizontalAlignment(DependencyObject dependencyObject) 
    { 
     return (HorizontalAlignment)dependencyObject.GetValue(HorizontalAlignmentProperty); 
    } 

    /// <summary> 
    /// Sets the horizontal alignment for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="horizontalAlignment"> 
    /// The horizontal alignment. 
    /// </param> 
    public static void SetHorizontalAlignment(DependencyObject dependencyObject, HorizontalAlignment horizontalAlignment) 
    { 
     dependencyObject.SetValue(HorizontalAlignmentProperty, horizontalAlignment); 
    } 

    /// <summary> 
    /// Gets the vertical alignment for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <returns> 
    /// The vertical alignment. 
    /// </returns> 
    public static VerticalAlignment GetVerticalAlignment(DependencyObject dependencyObject) 
    { 
     return (VerticalAlignment)dependencyObject.GetValue(VerticalAlignmentProperty); 
    } 

    /// <summary> 
    /// Sets the vertical alignment for a specified dependency object. 
    /// </summary> 
    /// <param name="dependencyObject"> 
    /// The dependency object. 
    /// </param> 
    /// <param name="verticalAlignment"> 
    /// The vertical alignment. 
    /// </param> 
    public static void SetVerticalAlignment(DependencyObject dependencyObject, VerticalAlignment verticalAlignment) 
    { 
     dependencyObject.SetValue(VerticalAlignmentProperty, verticalAlignment); 
    } 

    /// <summary> 
    /// Measures all child controls, imposing no restrictions on their size. 
    /// </summary> 
    /// <param name="availableSize"> 
    /// The available size. 
    /// </param> 
    /// <returns> 
    /// The measured size. 
    /// </returns> 
    protected override Size MeasureOverride(Size availableSize) 
    { 
     availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity); 

     foreach (UIElement child in this.InternalChildren) 
     { 
      if (child != null) 
      { 
       child.Measure(availableSize); 
      } 
     } 

     return new Size(); 
    } 

    /// <summary> 
    /// Arranges all child controls. 
    /// </summary> 
    /// <param name="finalSize"> 
    /// The final size. 
    /// </param> 
    /// <returns> 
    /// The size of the content. 
    /// </returns> 
    protected override Size ArrangeOverride(Size finalSize) 
    { 
     foreach (FrameworkElement child in this.InternalChildren) 
     { 
      if (child == null) 
      { 
       continue; 
      } 

      var xRatio = GetXRatio(child); 
      var yRatio = GetYRatio(child); 
      var x = xRatio * ActualWidth; 
      var y = yRatio * ActualHeight; 

      switch (child.HorizontalAlignment) 
      { 
       case HorizontalAlignment.Center: 
        x -= child.DesiredSize.Width/2; 
        break; 
       case HorizontalAlignment.Right: 
        x -= child.DesiredSize.Width; 
        break; 
      } 

      switch (child.VerticalAlignment) 
      { 
       case VerticalAlignment.Center: 
        y -= child.DesiredSize.Height/2; 
        break; 
       case VerticalAlignment.Bottom: 
        y -= child.DesiredSize.Height; 
        break; 
      } 

      child.Arrange(new Rect(new Point(x, y), child.DesiredSize)); 
     } 

     return finalSize; 
    } 

    private static double GetXRatio(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(XRatioProperty); 
    } 

    private static void SetXRatio(DependencyObject dependencyObject, double xRatio) 
    { 
     dependencyObject.SetValue(XRatioProperty, xRatio); 
    } 

    private static double GetYRatio(DependencyObject dependencyObject) 
    { 
     return (double)dependencyObject.GetValue(YRatioProperty); 
    } 

    private static void SetYRatio(DependencyObject dependencyObject, double yRatio) 
    { 
     dependencyObject.SetValue(YRatioProperty, yRatio); 
    } 

    private static double CalculateYRelative(double latitude) 
    { 
     return Math.Log(Math.Tan(((latitude/360d) * Math.PI) + (Math.PI/4))); 
    } 

    private static void OnLatitudeRangeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var reference = dependencyObject as MercatorProjectionPanel; 

     if (reference != null) 
     { 
      reference.minY = CalculateYRelative(reference.MinLatitude); 
      reference.maxY = CalculateYRelative(reference.MaxLatitude); 
     } 
    } 

    private static void OnGeographicalCoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var reference = dependencyObject as FrameworkElement; 

     if (reference != null) 
     { 
      var parent = VisualTreeHelper.GetParent(reference) as MercatorProjectionPanel; 

      if (parent != null) 
      { 
       SetLeft(reference, ConvertLongitudeToX(parent, GetLongitude(reference))); 
       SetTop(reference, ConvertLatitudeToY(parent, GetLatitude(reference))); 

       parent.InvalidateArrange(); 
      } 
     } 
    } 

    private static void OnCoordinateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     var reference = dependencyObject as FrameworkElement; 

     if (reference != null) 
     { 
      var parent = VisualTreeHelper.GetParent(reference) as MercatorProjectionPanel; 

      if (parent != null) 
      { 
       ////SetLongitude(reference, ConvertXToLongitude(parent, GetLeft(reference))); 
       ////SetLatitude(reference, ConvertYToLatitude(parent, GetTop(reference))); 

       ////parent.InvalidateArrange(); 

       var left = GetLeft(reference); 
       var top = GetTop(reference); 

       SetXRatio(reference, left/parent.ActualWidth); 
       SetYRatio(reference, top/parent.ActualHeight); 
      } 
     } 
    } 

    private static double ConvertXToLongitude(MercatorProjectionPanel panel, double left) 
    { 
     return ((left/panel.ActualWidth) * 360) - 180; 
    } 

    private static double ConvertYToLatitude(MercatorProjectionPanel panel, double top) 
    { 
     var input = panel.maxY - ((top/panel.ActualHeight) * (panel.maxY - panel.minY)); 
     return Math.Atan(Math.Sinh(input)) * DegreesPerRadian; 
    } 

    private static double ConvertLongitudeToX(MercatorProjectionPanel panel, double longitude) 
    { 
     return ((longitude + 180)/360) * panel.ActualWidth; 
    } 

    private static double ConvertLatitudeToY(MercatorProjectionPanel panel, double latitude) 
    { 
     return panel.ActualHeight - (panel.ActualHeight * (CalculateYRelative(latitude) - panel.minY)/(panel.maxY - panel.minY)); 
    } 
} 

, 나는이 대답을 업데이트 할 수 있습니다.

+0

내 모델을 기반으로 코드를 테스트하려고하는데 MinLongitude 및 MaxLongitude도 만들었으니 이제는 그 값을 자식으로부터 얻는 방법을 찾고 있습니다 (패널이 필요 이상으로 커지지는 않음). 그러나 모든 하위 항목에 액세스 할 수있는 "렌더링"워크 플로에서 엔트리 포인트를 찾을 수 없으며 최대 및 최소 위도 및 경도를 설정할 수 있습니다. –

0

캔버스에 표시 할 위도/경도 및 최대 값 (확대/축소 수준에서 계산할 수 있음) 또는 하드 코드 할 수있는 최대/최소값이 필요합니다. 그런 다음 RelX = (ObjectLong-MinLong)/(MaxLong-MinLong) 및 RelY = (ObjectLat-MinLat)/(MaxLat-MinLat) 과 같은 객체의 상대 좌표를 결정할 수 있습니다. MeasureOverride() 메소드에서 상대 좌표.

관련 문제