15

私がやりたいことについては、いくつかの悪い方法がありますが、これは「もっと良い方法があるに違いない」というケースの 1 つに思えます。

多数の注釈を表示する iPhone アプリで MKMapView を使用しています。米国の州の各町には注釈があるという概念的な議論のふりをして、画面上にかなり密集した注釈の山があるようにします。ユーザーがマップをズームアウトすると、それらの注釈が互いに重なり合い始め、重なり合って個別に選択するのが難しくなります。

私がやりたいのは、特定の密度の注釈 (注釈が重なっている場合など) で、それらの注釈を単一の注釈に統合し、それが多数のサブ注釈を囲んでいることを示すことです (「ズームインより多くの注釈が表示されます」)。

注釈ビューで CGRectIntersectsRect を呼び出すことはできますが、それを使用すると N^2 の問題が発生するようです。各注釈について各注釈を反復処理する必要があります。次の擬似コードを検討してください。

FOR firstAnnotationView IN allAnnotationViews
   FOR secondAnnotationView in allAnnotationViews
       IF CGRectIntersectsRect(firstAnnotationView.frame, secondAnnotationView.frame)
           // 重複する 2 つの注釈が見つかりました。それらを統合します
       ENDIF
   ENDFOR
ENDFOR

なぜそれが遅いのか、そしてマップが拡大または縮小されるたびに実行しなければならないことがわかります!

では、マップ内の重複するアノテーションをどのように検出し、パフォーマンスに精通した方法でそれらをインテリジェントに統合するのでしょうか?

4

3 に答える 3

1

このようなものを検索しますね。

http://www.cocoanetics.com/parts/dtclustermaker/

于 2010-12-18T20:05:50.163 に答える
1

経度/緯度に基づいて注釈をビン化し、それらのビンを使用して統合します。基本的な考え方は次のようになります。

#include <vector>

float minLongitude = 180.0f;
float maxLongitude = -180.0f;
float longitudeBinSize = 0.1; // Degrees
float minLatitude = -90.0f;
float maxLatitude = 90.0f;
float latitudeBinSize = 0.1; // Degrees
int numBinColumns = int((maxLongitude - minLongitude) / longitudeBinSize);
int numBinRows = int((maxLatitude - minLatitude) / latitudeBinSize);

void calcBinCoords(float longitude, float latitude, int &column, int &row) {
    column = int((latitude - minLatitude) / latitudeBinSize);
    row = int((longitude - minLongitude) / longitudeBinSize);
}

typedef std::vector<AnnotationView *> AnnotationViews;

void binAnnotations(NSArray *annotationViews, std::vector<AnnotationViews> &binnedAnnotations) {
    binnedAnnotations.clear();
    binnedAnnotations.resize(numBinColumns * numBinRows);
    for (AnnotationView *annotationView in annotationViews) {
        int column, row;
        calcBinCoords(annotationView.longitude, annotationView.latitude, column, row);
        binnedAnnotations[row * numBinColumns + column].push_back(annotationView);
    }
}

longitudeBinSize と latitudeBinSize の値は、統合時に検索する最大距離になります。すべてがビンに入ったら、検索の問題は、隣接するビンの値のリストを候補として検索することだけです。また、統合中に配列をスキャンするため、処理するビンごとに隣接する 3 つのビン ((列 + 1、行) のビン、(列、行 + 1) のビン) をチェックするだけで済みます。 )、および (列 + 1、行 + 1) のビン。

ビンに std::vector の代わりに NSMutableArrays を使用することもできますが、処理するアイテムが多数あるようで、std::vector の方が高速になると思います。それは私の好みに過ぎませんが、気にするほど問題ではないかもしれません。ObjC++ の代わりに ObjC を使用する場合、もちろん std::vector は使用できません。

于 2010-11-24T21:15:47.287 に答える
0

Geohashを使用して注釈を分割できます。これにより、注釈を「統合」しようとするときに検索スペースが減少します。

于 2010-12-15T12:13:36.093 に答える