2008-10-31 103 views
17

我正在編寫一個使用Canvas定位元素的地圖應用程序。對於每個元素,我都必須以編程方式將元素的緯/長轉換爲畫布的座標,然後設置Canvas.Top和Canvas.Left屬性。更改WPF中Canvas的座標系

如果我有一個360x180畫布,我可以將畫布上的座標轉換爲X軸上的-180到180而不是0到360,Y軸上的90到90而不是0到180?

縮放要求:

  • 畫布可以是任意大小,所以如果它是360x180或5000x100應該仍然工作。 Lat/Long區域可能並不總是(-90,-180)x(90,180),它可以是任何東西(即(5,-175)x(89,-174))。
  • 諸如PathGeometry之類的元素是基於點的,而不是基於Canvas.Top/Left的元素需要工作。

回答

0

我敢肯定,你不能那樣做,但它有一個從lat/long轉換爲Canvas座標的方法非常簡單。

Point ToCanvas(double lat, double lon) { 
    double x = ((lon * myCanvas.ActualWidth)/360.0) - 180.0; 
    double y = ((lat * myCanvas.ActualHeight)/180.0) - 90.0; 
    return new Point(x,y); 
} 

(或者類似的規定)

+0

我有一個功能,我只是希望不需要始終將畫布點和畫布之間進行轉換。 – Dylan 2008-10-31 16:48:39

+0

這樣做確實具有使畫布更加美觀和可伸縮的優點。 – MojoFilter 2008-10-31 17:13:57

0

我想另一個辦法是延長帆布和覆蓋措施/安排,使之表現,你想要的方式。

+0

這更符合我的想法,但我不知道如何實現它。 – Dylan 2008-10-31 16:51:53

+0

這不是太簡單。這個想法是你重寫ArrangeOverride()和MeasureOverride()。 – MojoFilter 2008-10-31 17:11:31

1

我能夠通過創建自己的自定義帆布和重寫ArrangeOverride功能,像這樣得到它:

public class CustomCanvas : Canvas 
    { 
     protected override Size ArrangeOverride(Size arrangeSize) 
     { 
      foreach (UIElement child in InternalChildren) 
      { 
       double left = Canvas.GetLeft(child); 
       double top = Canvas.GetTop(child); 
       Point canvasPoint = ToCanvas(top, left); 
       child.Arrange(new Rect(canvasPoint, child.DesiredSize)); 
      } 
      return arrangeSize; 
     } 
     Point ToCanvas(double lat, double lon) 
     { 
      double x = this.Width/360; 
      x *= (lon - -180); 
      double y = this.Height/180; 
      y *= -(lat + -90); 
      return new Point(x, y); 
     } 
    } 

這對我的描述問題的作品,但它可能不會再需要我有工作,這是一個PathGeometry。它不起作用,因爲這些點不是定義爲Top和Left,而是定義爲實際點。

6

這是一個全XAML解決方案。那麼,主要是XAML,因爲你必須在代碼中使用IValueConverter。所以:創建一個新的WPF項目並向它添加一個類。該類是MultiplyConverter:

namespace YourProject 
{ 
    public class MultiplyConverter : System.Windows.Data.IValueConverter 
    { 
     public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return AsDouble(value)* AsDouble(parameter); 
     } 
     double AsDouble(object value) 
     { 
      var valueText = value as string; 
      if (valueText != null) 
       return double.Parse(valueText); 
      else 
       return (double)value; 
     } 

     public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      throw new System.NotSupportedException(); 
     } 
    } 
} 

然後使用此XAML爲您的窗口。現在,您應該可以在XAML預覽窗口中看到結果。

編輯:您可以通過將Canvas放入另一個Canvas中來解決Background問題。有點奇怪,但它的作品。另外,我添加了一個ScaleTransform,它可以翻轉Y軸,這樣正Y就會上升,負值會下降。仔細注意哪些名字去的地方:

<Canvas Name="canvas" Background="Moccasin"> 
    <Canvas Name="innerCanvas"> 
     <Canvas.RenderTransform> 
      <TransformGroup> 
       <TranslateTransform x:Name="translate"> 
        <TranslateTransform.X> 
         <Binding ElementName="canvas" Path="ActualWidth" 
           Converter="{StaticResource multiplyConverter}" ConverterParameter="0.5" /> 
        </TranslateTransform.X> 
        <TranslateTransform.Y> 
         <Binding ElementName="canvas" Path="ActualHeight" 
           Converter="{StaticResource multiplyConverter}" ConverterParameter="0.5" /> 
        </TranslateTransform.Y> 
       </TranslateTransform> 
       <ScaleTransform ScaleX="1" ScaleY="-1" CenterX="{Binding ElementName=translate,Path=X}" 
         CenterY="{Binding ElementName=translate,Path=Y}" /> 
      </TransformGroup> 
     </Canvas.RenderTransform> 
     <Rectangle Canvas.Top="-50" Canvas.Left="-50" Height="100" Width="200" Fill="Blue" /> 
     <Rectangle Canvas.Top="0" Canvas.Left="0" Height="200" Width="100" Fill="Green" /> 
     <Rectangle Canvas.Top="-25" Canvas.Left="-25" Height="50" Width="50" Fill="HotPink" /> 
    </Canvas> 
</Canvas> 

至於你需要改變你的範圍內的新要求,更復雜的ValueConverter可能會做的伎倆。

0

您可以使用transform在座標系之間進行轉換,也可以使用TranslateTranform的TransformGroup將(0,0)移動到畫布的中心,並使用ScaleTransform將座標移至正確的範圍。

通過數據綁定和一個或兩個值轉換器,您可以根據畫布大小自動更新變換。

這樣做的好處是,它可以用於任何元素(包括PathGeometry),可能的缺點是它可以縮放一切,而不僅僅是點 - 因此它會改變地圖上圖標和文本的大小。

0

另一種可能的解決方案:

嵌入自定義畫布(拉伸到帆布)在另一個畫布(背景畫布),並設置拉伸到帆布,以便它是透明的,不會夾到界限。用一個使y翻轉的矩陣(M22 = -1)轉換繪製到畫布,並翻譯/縮放父畫布內的畫布以查看您正在查看的世界的範圍。

實際上,如果您在繪製畫布上繪製-115,42,則您繪製的項目將「關閉」畫布,但無論如何都會顯示,因爲畫布未裁剪到邊界。然後,您將繪製到畫布轉換爲在背景畫布上的正確位置顯示該點。

這是我很快就會嘗試自己的事情。希望能幫助到你。

0

這是an answer其中描述了一個Canvas擴展方法,允許您應用笛卡爾座標系。即:

canvas.SetCoordinateSystem(-10, 10, -10, 10) 

將設置的canvas的座標系,使x去從-10到10 y去從-10到10