6

WinForms を使用するレガシー マップ ビューア アプリケーションがあります。それは遅いです。(以前は速度は許容範囲でしたが、Google マップ、Google Earth が登場し、ユーザーは甘やかされました。今では、より高速であれば作成を許可されています :)

すべての明白な速度の改善 (キャッシング、並列実行、描画する必要のないものを描画しないなど) を行った後、私のプロファイラーは、ポイントをマップ空間からスクリーン空間に変換するときの座標変換が本当のチョーク ポイントであることを示しています。 . 通常、変換コードは次のようになります。

    public Point MapToScreen(PointF input)
    {
        // Note that North is negative!
        var result = new Point(
           (int)((input.X - this.currentView.X) * this.Scale),
           (int)((input.Y - this.currentView.Y) * this.Scale));
        return result;
    }

実際の実装はよりトリッキーです。緯度/経度は整数で表されます。精度が失われないように、2^20 (~ 100 万) を掛けます。座標はこのように表されます。

public struct Position
{
    public const int PrecisionCompensationPower = 20;
    public const int PrecisionCompensationScale = 1048576; // 2^20
    public readonly int LatitudeInt; // North is negative!
    public readonly int LongitudeInt;
}

可能なスケール係数も 2 の累乗に明示的にバインドされていることが重要です。これにより、乗算をビットシフトに置き換えることができます。したがって、実際のアルゴリズムは次のようになります。

    public Point MapToScreen(Position input)
    {
        Point result = new Point();
        result.X = (input.LongitudeInt - this.UpperLeftPosition.LongitudeInt) >>
                     (Position.PrecisionCompensationPower - this.ZoomLevel);
        result.Y = (input.LatitudeInt - this.UpperLeftPosition.LatitudeInt) >> 
                     (Position.PrecisionCompensationPower - this.ZoomLevel);
        return result;
    }

(UpperLeftPosition は、マップ空間の画面の左上隅を表します。) この計算を GPU にオフロードすることを考えています。誰かがそれを行う方法の例を教えてもらえますか?

.NET4.0 を使用していますが、コードはできれば Windows XP でも実行する必要があります。さらに、GPL の下のライブラリは使用できません。

4

4 に答える 4

2

OpenCLとClooを使用してこれを行うことをお勧めします-ベクトル追加の例ComputeBufferを見てから、これを変更して、2つのs(各ポイントに1つずつ)を使用して値を2つの出力LatitudeIntにマップします。OpenCLコードは次のようになると思います。LongitudeIntComputeBuffer

__kernel void CoordTrans(__global int *lat, 
                         __global int *lon, 
                         __constant int ulpLat,
                         __constant int ulpLon,
                         __constant int zl,
                         __global int *outx,
                         __global int *outy)
{
    int i = get_global_id(0);        
    const int pcp = 20;

    outx[i] = (lon[i] - ulpLon) >> (pcp - zl);
    outy[i] = (lat[i] - ulpLat) >> (pcp - zl);
}

ただし、コアごとに複数の座標変換を実行します。私は急いで立ち去る必要があります。これを行う前にopenclを読んでおくことをお勧めします。

また、座標の数が妥当な場合(<100,000 / 1,000,000)、非GPUベースのソリューションの方が高速になる可能性があります。

于 2012-04-04T17:01:15.143 に答える
1

私はCUDAのバックグラウンドを持っており、NVIDIA GPUについてのみ話すことができますが、ここで説明します。

GPUでこれを行う場合の問題は、操作/転送時間です。

要素ごとに実行する操作は1回程度です。実際の速度を向上させるには、要素ごとにこれ以上のことを実行する必要があります。グローバルメモリとGPU上のスレッド間の帯域幅は約100GB/秒です。したがって、1つのFLOPを実行するために1つの4バイト整数をロードする必要がある場合、理論上の最大速度は100/4 =25FLOPSです。これは、宣伝されている何百ものFLOPSからはほど遠いものです。

これは理論上の最大値であり、実際の結果はさらに悪くなる可能性があることに注意してください。また、複数の要素をロードしている場合、これはさらに悪化します。あなたの場合、それは2のように見えるので、最大12.5FLOPSを取得する可能性があります。実際には、それはほぼ確実に低くなります。

これで問題ないように思える場合は、それを実行してください。

于 2012-04-05T01:35:01.093 に答える
1

XNA を使用すると、必要なすべての変換を実行でき、非常に優れたパフォーマンスが得られます。winforms アプリケーション内に表示することもできます: http://create.msdn.com/en-US/education/catalog/sample/winforms_series_1

于 2012-04-05T01:46:56.017 に答える