18

要素の配置に Canvas を使用するマッピング アプリを作成しています。要素ごとに、プログラムで要素の緯度/経度をキャンバスの座標に変換し、Canvas.Top および Canvas.Left プロパティを設定する必要があります。

キャンバスが 360x180 の場合、キャンバスの座標を X 軸で 0 から 360 ではなく -180 から 180 に変換し、Y 軸で 0 から 180 ではなく 90 から -90 に変換できますか?

スケーリング要件:

  • キャンバスは任意のサイズにすることができるため、360x180 または 5000x100 の場合でも機能するはずです。
  • 緯度/経度の領域は常に (-90,-180)x(90,180) であるとは限りません。((5,-175)x(89,-174) など) どんな値でもかまいません。
  • Canvas.Top/Left ベースではなく、ポイント ベースである PathGeometry などの要素が機能する必要があります。
4

8 に答える 8

6

これは、すべてが XAML のソリューションです。コードに IValueConverter を含める必要があるため、ほとんどが XAML です。そのため、新しい 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 プレビュー ウィンドウに結果が表示されます。

編集:キャンバスを別のキャンバス内に配置することで、背景の問題を修正できます。ちょっと奇妙ですが、うまくいきます。さらに、Y 軸を反転する 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 がおそらくうまくいくでしょう。

于 2008-10-31T19:59:57.200 に答える
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 という別のニーズにはおそらく機能しません。ポイントが上と左としてではなく、実際のポイントとして定義されているため、機能しません。

于 2008-10-31T19:54:04.323 に答える
0

正確にそれを行うことはできないと確信していますが、緯度/経度からキャンバス座標に変換するメソッドを持つことは非常に簡単です。

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);
}

(またはそれらの線に沿った何か)

于 2008-10-31T16:41:57.770 に答える
0

別の可能な解決策:

カスタム キャンバス (描画先キャンバス) を別のキャンバス (背景キャンバス) に埋め込み、描画先キャンバスを透明にして境界にクリップしないように設定します。y 反転 (M22 = -1) を行うマトリックスを使用して描画先キャンバスを変換し、親キャンバス内でキャンバスを変換/スケーリングして、見ている世界の広がりを表示します。

実際には、描画先キャンバスで -115, 42 で描画すると、描画しているアイテムはキャンバスから「外れて」いますが、キャンバスが境界にクリッピングされていないため、とにかく表示されます。次に、描画先キャンバスを変換して、ポイントが背景キャンバスの適切な場所に表示されるようにします。

これは私がすぐに試してみたいことです。それが役に立てば幸い。

于 2010-06-18T14:17:21.383 に答える
0

私はほぼ同じ問題を抱えています。だから私はオンラインに行きました。そして、この男はマトリックスを使用して「デバイスピクセル」から彼が「世界座標」と呼ぶものに変換します。つまり、「デバイスピクセル」ではなく実際の数値を意味しますリンクを参照してください

http://csharphelper.com/blog/2014/09/use-transformations-draw-graph-wpf-c/

于 2016-12-14T21:11:23.363 に答える
0

変換を使用して座標系間を変換できます。おそらく、TranslateTranform を持つ TransformGroup を使用して (0,0) をキャンバスの中心に移動し、ScaleTransform を使用して座標を適切な範囲に移動できます。

データ バインディングと 1 つまたは 2 つの値コンバーターを使用すると、キャンバス サイズに基づいて変換を自動的に更新できます。

これの利点は、任意の要素 (PathGeometry を含む) に対して機能することです。考えられる欠点は、ポイントだけでなくすべてをスケーリングすることです。そのため、マップ上のアイコンとテキストのサイズが変更されます。

于 2008-11-02T09:52:00.170 に答える
0

これは、デカルト座標系を適用できる拡張メソッドを説明する回答です。Canvasすなわち:

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

-10 から 10 まで、および -10 から 10 までにcanvasなるように の座標系を設定します。xy

于 2012-11-25T00:58:09.153 に答える
0

別のオプションは、キャンバスを拡張し、メジャー/アレンジをオーバーライドして、希望どおりに動作させることだと思います。

于 2008-10-31T16:50:25.943 に答える