Iphone 在缩放的MKMapView上合并注释

Iphone 在缩放的MKMapView上合并注释,iphone,objective-c,cocoa,annotations,mkmapview,Iphone,Objective C,Cocoa,Annotations,Mkmapview,我想做的事情有很多不好的方法,但这似乎是“一定有更好的方法”的例子之一 我正在iPhone应用程序中使用MKMapView,该应用程序显示了大量注释。假设在概念性讨论中,美国各州的每个城镇都有注释,所以屏幕上有一堆相当密集的注释。当用户缩小地图时,这些注释开始相互挤压,直到它们重叠,难以单独识别 我想做的是,在注释的特定密度下(例如,当任何注释重叠时),将这些注释合并为一个注释,表明它包含许多子注释(一些视觉指示器表示“放大,您将看到更多注释”) 我可以在注释视图上调用CGRectInterse

我想做的事情有很多不好的方法,但这似乎是“一定有更好的方法”的例子之一

我正在iPhone应用程序中使用MKMapView,该应用程序显示了大量注释。假设在概念性讨论中,美国各州的每个城镇都有注释,所以屏幕上有一堆相当密集的注释。当用户缩小地图时,这些注释开始相互挤压,直到它们重叠,难以单独识别

我想做的是,在注释的特定密度下(例如,当任何注释重叠时),将这些注释合并为一个注释,表明它包含许多子注释(一些视觉指示器表示“放大,您将看到更多注释”)

我可以在注释视图上调用CGRectIntersectsRect,但使用它似乎是一个N^2问题——我必须为每个注释迭代每个注释。考虑这个伪代码:

FOR firstAnnotationView IN allAnnotationViews FOR secondAnnotationView in allAnnotationViews IF CGRectIntersectsRect(firstAnnotationView.frame, secondAnnotationView.frame) // found two overlapping annotations, consolidate them ENDIF ENDFOR ENDFOR 对于AllAnnotationView中的firstAnnotationView 用于AllAnnotationView中的第二个AnnotationView 如果CGRectIntersectsRect(第一个AnnotationView.frame,第二个AnnotationView.frame) //找到两个重叠的批注,请合并它们 恩迪夫 结束 结束 你可以看到为什么这会很慢,而且每次放大或缩小地图时它都必须运行


那么,您将如何检测地图中的重叠注释,并以一种精通性能的方式智能地整合它们呢

我会根据经度/纬度对注释进行分类,然后使用这些分类进行合并。基本思想如下所示:

#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);
    }
}
#包括
浮动最小经度=180.0f;
浮点最大经度=-180.0f;
浮点数longitudeBinSize=0.1;//度
浮动最小纬度=-90.0f;
浮动最大纬度=90.0f;
浮点数latitudeBinSize=0.1;//度
int numBinColumns=int((最大经度-最小经度)/longitudeBinSize);
int numBinRows=int((最大纬度-最小纬度)/latitudeBinSize);
void calcBinCoords(浮点经度、浮点纬度、int和column、int和row){
列=int((纬度-最小纬度)/latitudeBinSize);
行=int((经度-最小经度)/longitudeBinSize);
}
typedef std::向量注释视图;
无效二进制注释(NSArray*注释视图、标准::向量和二进制注释){
binnedAnnotations.clear();
调整大小(numBinColumns*numBinRows);
用于(注释视图*注释视图中的注释视图){
int列,行;
CALCBINCORDS(annotationView.longitude、annotationView.latitude、column、row);
binnedAnnotations[行*numBinColumns+列]。向后推(annotationView);
}
}
longitudeBinSize和latitudeBinSize的值是合并时要搜索的最大距离。一旦所有东西都在箱子里,那么你的搜索问题只涉及到在相邻箱子中搜索候选值的列表。此外,由于您将在合并过程中扫描阵列,因此实际上只需要为您处理的每个箱子检查三个相邻的箱子——位于(列+1,行)的箱子、位于(列,行+1)的箱子和位于(列+1,行+1)的箱子


您可以使用NSMutableArray而不是std::vector来处理垃圾箱,但听起来您需要处理大量的项目,我怀疑std::vector会更快。不过这只是我的偏好,可能根本不在乎。如果您使用ObjC而不是ObjC++,那么当然不能使用std::vector。

您可以使用它来划分注释。这将在尝试“整合”注释时减少搜索空间。

您搜索类似的内容,不是吗


考虑一下你的搜索空间。是否需要考虑外环中的所有注释?简单地评估当前视图中的注释怎么样?