2009-10-19 33 views
13

Có một số cách xấu để đi về những gì tôi muốn làm, nhưng điều này có vẻ giống như một trong những trường hợp "phải có một cách tốt hơn".Hợp nhất các chú thích trên một MKMapView thu nhỏ

Tôi đang sử dụng MKMapView trong ứng dụng iPhone hiển thị một số chú thích. Giả vờ thảo luận khái niệm rằng mỗi thị trấn ở một tiểu bang của Hoa Kỳ có chú thích, vì vậy có một đống chú thích khá dày đặc trên màn hình. Khi người dùng thu nhỏ bản đồ, các chú thích đó bắt đầu đan xen với nhau, cho đến khi chúng chồng lên nhau và trở nên khó chọn riêng lẻ. Những gì tôi muốn làm là, ở mật độ cụ thể của chú thích (nói khi có chú thích trùng lặp), hãy hợp nhất các chú thích đó thành một chú thích cho biết nó bao gồm một số chú thích phụ (một số chỉ báo trực quan để nói). , "phóng to và bạn sẽ thấy nhiều chú thích hơn").

Tôi có thể gọi CGRectIntersectsRect trên chế độ xem chú thích, nhưng việc sử dụng đó có vẻ là vấn đề N^2 - tôi sẽ phải lặp qua từng chú thích cho mỗi chú thích. Xem xét giả này:

 
FOR firstAnnotationView IN allAnnotationViews 
    FOR secondAnnotationView in allAnnotationViews 
     IF CGRectIntersectsRect(firstAnnotationView.frame, secondAnnotationView.frame) 
      // found two overlapping annotations, consolidate them 
     ENDIF 
    ENDFOR 
ENDFOR

Bạn có thể thấy lý do tại sao điều đó sẽ chậm, và nó sẽ phải chạy mỗi khi bản đồ được phóng to hoặc ra!

Vậy tất cả các bạn sẽ phát hiện các chú thích chồng chéo trên bản đồ và theo cách hiểu biết về hiệu suất, hãy hợp nhất chúng một cách thông minh?

+0

Hãy xem xét không gian tìm kiếm của bạn. Có cần phải xem xét tất cả các chú thích trong vòng lặp bên ngoài của bạn không? Điều gì về chỉ đơn giản là đánh giá các chú thích hiện đang xem? –

Trả lời

1

Tôi sẽ chia các chú thích của bạn dựa trên kinh độ/vĩ độ và sau đó hợp nhất sử dụng các thùng đó. Ý tưởng cơ bản sẽ trông giống như sau:

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

Giá trị cho kinh độBinSize và vĩ độBinSize sẽ là khoảng cách tối đa mà bạn định tìm kiếm khi hợp nhất. Khi mọi thứ đã ở trong thùng thì vấn đề tìm kiếm của bạn chỉ liên quan đến việc tìm kiếm danh sách các giá trị trong các thùng liền kề cho các ứng cử viên. Ngoài ra, vì bạn sẽ quét mảng trong quá trình hợp nhất, bạn thực sự chỉ cần kiểm tra ba thùng liền kề cho mỗi thùng bạn xử lý - thùng tại (cột + 1, hàng), thùng tại (cột, hàng + 1) và thùng ở (cột + 1, hàng + 1). Bạn có thể sử dụng NSMutableArrays thay vì std :: vector cho các thùng, nhưng có vẻ như bạn có một số lượng lớn các mục cần xử lý và tôi nghi ngờ std :: vector sẽ nhanh hơn. Đó chỉ là sở thích của tôi mặc dù, nó có thể không quan trọng, đủ để thậm chí quan tâm. Nếu bạn sử dụng ObjC thay vì ObjC++ thì bạn không thể sử dụng std :: vector của khóa học.

0

Bạn có thể sử dụng Geohash để phân vùng chú thích của mình. Điều này sẽ giảm không gian tìm kiếm khi cố gắng "hợp nhất" chú thích của bạn.

Các vấn đề liên quan