2009-10-19 19 views
13

पर एनोटेशन को समेकित करें जो मैं करना चाहता हूं उसके बारे में जाने के कई बुरे तरीके हैं, लेकिन ऐसा लगता है कि "एक बेहतर तरीका होना चाहिए"।ज़ूम किए गए MKMapView

मैं एक आईफोन ऐप में एक एमकेमैप व्यू का उपयोग कर रहा हूं जो कई एनोटेशन प्रदर्शित करता है। वैचारिक चर्चा के लिए नाटक करें कि अमेरिकी राज्य के प्रत्येक शहर में एनोटेशन है, इसलिए स्क्रीन पर एनोटेशन की काफी घनी ढेर है। चूंकि उपयोगकर्ता मानचित्र को ज़ूम आउट करता है, वे एनोटेशन एक-दूसरे पर क्रंच करना शुरू करते हैं, जब तक कि वे ओवरलैप नहीं हो जाते हैं और अलग-अलग चुनने में कठोर हो जाते हैं।

मैं क्या करना चाहता हूं, एनोटेशन के किसी विशेष घनत्व पर (कहें कि जब कोई एनोटेशन ओवरलैप होता है), उन एनोटेशन को एक एनोटेशन में समेकित करें जो इंगित करता है कि इसमें कई उप-एनोटेशन (कुछ दृश्य संकेतक कहने के लिए संलग्न हैं) , "ज़ूम इन करें और आपको और एनोटेशन दिखाई देंगे")।

मैं एनोटेशन विचारों पर CGRectIntersectsRect कह सकते हैं, लेकिन उस का उपयोग कर एक एन^2 समस्या प्रतीत होता है - मैं प्रत्येक एनोटेशन के लिए प्रत्येक एनोटेशन से अधिक पुनरावृति करना होगा। इस स्यूडोकोड पर विचार करें:

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

आप देख सकते हैं क्यों कि धीमी गति से होगा, और यह हर बार नक्शा या बाहर में ज़ूम इन किया गया था चलाना होगा!

तो आप मानचित्र में ओवरलैपिंग एनोटेशन का पता कैसे लगाएंगे, और प्रदर्शन-समझदार फैशन में, उन्हें समझदारी से समेकित करेंगे?

+0

अपनी खोज को अंतरिक्ष पर विचार करें। क्या आपके बाहरी लूप में सभी एनोटेशन पर विचार करना आवश्यक है? वर्तमान में देखने वाले एनोटेशन का मूल्यांकन करने के बारे में क्या? –

उत्तर

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 के लिए मान अधिकतम दूरी है कि आप जब मजबूत खोज करने का इरादा होगा: मूल विचार यह कुछ ऐसा दिखाई देगा। एक बार सब कुछ डिब्बे में है तो आपकी खोज समस्या में केवल उम्मीदवारों के लिए आसन्न डिब्बे में मूल्यों की सूची खोजना शामिल है। साथ ही, चूंकि आप समेकन के दौरान सरणी स्कैन कर रहे हैं, इसलिए आपको वास्तव में केवल प्रत्येक बिन के लिए आसन्न डिब्बे की जांच करने की आवश्यकता है - बिन पर (कॉलम + 1, पंक्ति), बिन पर (कॉलम, पंक्ति + 1), और बिन पर (कॉलम + 1, पंक्ति + 1)।

आप डिब्बे के लिए std :: वेक्टर के बजाय एनएसएमयूटेबलएरे का उपयोग कर सकते हैं, लेकिन ऐसा लगता है कि आपके पास प्रक्रिया करने के लिए बड़ी संख्या में आइटम हैं और मुझे संदेह है कि std :: वेक्टर तेज होगा। हालांकि यह सिर्फ मेरी वरीयता है, यह भी ध्यान देने के लिए पर्याप्त नहीं हो सकता है। यदि आप ObjC++ के बजाय ओबीजेसी का उपयोग करते हैं तो आप पाठ्यक्रम के std :: वेक्टर का उपयोग नहीं कर सकते हैं।

0

आप अपनी टिप्पणियों को विभाजित करने के लिए Geohash का उपयोग कर सकते हैं। आपकी एनोटेशन को "समेकित" करने का प्रयास करते समय यह खोज स्थान को कम करेगा।

संबंधित मुद्दे