2012-04-11 10 views
16

के अंदर है या नहीं, मैं यह बताने में सक्षम होना चाहता हूं कि टैप MKPolygon के भीतर है या नहीं।पता लगाएं कि कोई बिंदु MKPolygon ओवरले

CLLocationCoordinate2D points[4]; 

points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116); 
points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066); 
points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981); 
points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267); 

MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4]; 

[self.mapView addOverlay:poly]; 

//create UIGestureRecognizer to detect a tap 
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(foundTap:)]; 
tapRecognizer.numberOfTapsRequired = 1; 
tapRecognizer.numberOfTouchesRequired = 1; 
[self.mapView addGestureRecognizer:tapRecognizer]; 

इसकी सिर्फ एक राज्य कोलोराडो के बुनियादी रूपरेखा:

मैं एक MKPolygon है।

मैं की स्थापना अक्षांश/देशांतर रूपांतरण के लिए नल है:

-(IBAction)foundTap:(UITapGestureRecognizer *)recognizer 
{ 
    CGPoint point = [recognizer locationInView:self.mapView]; 

    CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view]; 
} 

लेकिन मैं कैसे तकनीक को लेकर अनिश्चित हूं कि मेरा नल बिंदु MKPolygon के भीतर है। इस चेक को करने का कोई तरीका प्रतीत नहीं होता है, इसलिए मुझे लगता है कि मुझे एमके पॉलीगॉन को एक सीजीईजीईटी में परिवर्तित करने और सीजीआरईटीकंटेंसपॉइंट का उपयोग करने की आवश्यकता है।

एमकेपोलीगॉन में एक पॉइंट संपत्ति है लेकिन मुझे उन्हें वापस नहीं मिल रहा है।

कोई सुझाव?

संपादित करें:

दोनों आईओएस 7 में iOS 6 या कम में काम के लिए निम्न उपाय है, लेकिन टूट जाता है आईओएस 7 में polygon.path संपत्ति allways NULL देता है। एमएस अन्ना a solution in another SO question here प्रदान करने के लिए काफी दयालु थी। इसमें बहुभुज बिंदुओं से CGPathContainsPoint() में अपना रास्ता बनाना शामिल है। मेरी बहुभुज के

छवि:

enter image description here

उत्तर

11

मैं इस MKPolygon श्रेणी मामले में किसी को भी इसका इस्तेमाल करना चाहता है बनाया। अच्छी तरह से काम करने लगता है। आप आंतरिक बहुभुज (बहुभुज में अर्थात छेद) के लिए खाते में करने के लिए है:

@interface MKPolygon (PointInPolygon) 
    -(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView; 
@end 

@implementation MKPolygon (PointInPolygon) 

-(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { 
    MKMapPoint mapPoint = MKMapPointForCoordinate(point); 
    MKPolygonView * polygonView = (MKPolygonView*)[mapView viewForOverlay:self]; 
    CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint]; 
    return CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO) && 
     ![self pointInInteriorPolygons:point mapView:mapView]; 
} 

-(BOOL) pointInInteriorPolygons:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { 
    return [self pointInInteriorPolygonIndex:0 point:point mapView:mapView]; 
} 

-(BOOL) pointInInteriorPolygonIndex:(int) index point:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView { 
    if(index >= [self.interiorPolygons count]) 
     return NO; 
    return [[self.interiorPolygons objectAtIndex:index] pointInPolygon:point mapView:mapView] || [self pointInInteriorPolygonIndex:(index+1) point:point mapView:mapView]; 
} 

@end 
+0

मैंने अभी श्रेणी को कार्यान्वित किया है और मेरे सरल बहुभुज (कोई छेद) पर काम करता है। आप कहते हैं कि इसे ध्यान में रखना चाहिए? क्या इसका मतलब यह नहीं होगा कि टैप एक छेद के अंदर है या नहीं? – Padin215

+0

ठीक है, यह कोड आईओएस 7 में टूटता है। 'CGPathContainsPoint (polygonView.path, NULL, polygonViewPoint, NO) के साथ कुछ करने के लिए हमेशा 'FALSE' वापस आता है। – Padin215

4

निर्धारित करता है कि एक बिंदु एक मनमाना बहुभुज में है गैर तुच्छ है और यह unsurprising है कि एप्पल MKPolygon के हिस्से के रूप में यह आपूर्ति नहीं करता है। आप अंक तक पहुंच सकते हैं, जो आपको किनारों पर फिर से चलाने की अनुमति देता है।

यह निर्धारित करने के लिए कि कोई बिंदु पी बहुभुज के अंदर है या नहीं, प्रत्येक किनारे को निर्देशित रेखा खंड के रूप में मानें। यदि किसी निश्चित दिशा में पी से एक किरण (आमतौर पर एक्स या वाई अक्ष के समानांतर) सेगमेंट को छेड़छाड़ करती है, तो उस निर्देशित लाइन सेगमेंट के साथ किरण के क्रॉस उत्पाद के जेड घटक का संकेत लें। यदि जेड घटक> 0 है, तो काउंटर पर 1 जोड़ें। यदि यह < 0 है, घटाएं 1. इसे कार्यान्वित करने की चाल मुद्दों से बचने के लिए है जब किनारे किरण के लगभग समानांतर होती है, या जब किरण एक चरम के माध्यम से गुजरती है (इसे केवल एक बार गिनना होता है, प्रत्येक किनारे के लिए एक बार नहीं) ।

जब आपने एस में सभी किनारों के लिए यह किया है, तो आपने बहुभुज की रूपरेखा को पार करने की संख्या की गणना की होगी, जहां किनारे बाएं से दाएं से जा रहे थे, और यदि यह जा रहा था दाएं से बाएं, आप घटाया। यदि परिणामस्वरूप योग शून्य है, तो आप बहुभुज के बाहर हैं। अन्यथा आप इसके अंदर हैं।

कई अनुकूलन संभव हैं। ऐसा एक और अधिक परीक्षण से पहले त्वरित बाध्यकारी बॉक्स परीक्षण करना है। एक और है कि किनारों को छेड़छाड़ न करने वाले किनारों को तुच्छ रूप से त्यागने के लिए सभी किनारों पर सीमाओं के साथ एक डेटा संरचना है।

संपादित करें: AXB के Z घटक (बी के साथ एक के पार उत्पाद) द्वारा दिया जाता है:

a.x * b.y - a.y * b.x 

के बाद से सभी आप के बारे में परवाह संकेत है, आप जाँच कर सकते हैं

a.x * b.y > a.y * b.x 
+0

जेड घटक क्या है? – Padin215

+0

उत्तर देने के लिए परिभाषा जोड़ा गया। – DRVic

+0

ठीक है, गोचा। अब इस पर काम कर रहा है, यह पता लगाने की कोशिश कर रहा है कि कैसे एक रेखा खंड के साथ एक किरण छेड़छाड़ की जाती है। – Padin215

9

आपका foundTap विधि:

-(IBAction)foundTap:(UITapGestureRecognizer *)recognizer 
{ 
    CGPoint point = [recognizer locationInView:self.mapView]; 

    CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view]; 

    [self pointInsideOverlay:tapPoint]; 

    if (isInside) 
    { 
     .... 
    } 
} 

यहाँ पिछले से कॉल करने के लिए बिंदु अगर जाँच करने के लिए एक विधि है ओवरले के अंदर है:

-(void)pointInsideOverlay:(CLLocationCoordinate2D)tapPoint 
{ 
    isInside = FALSE; 

    MKPolygonView *polygonView = (MKPolygonView *)[mapView viewForOverlay:polygonOverlay]; 

    MKMapPoint mapPoint = MKMapPointForCoordinate(tapPoint); 

    CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint]; 

    BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO); 

     if (!mapCoordinateIsInPolygon) 

      //we are finding points that are inside the overlay 
     { 
      isInside = TRUE; 
     } 
} 
+0

यह देखने के लिए मूलभूत जांच करने का एक अच्छा तरीका है कि क्या पॉली पॉइंट बहुभुज के रेक्ट के भीतर है या नहीं। बहुभुज के खींचे गए क्षेत्र में नल का पता लगाने के लिए सटीक नहीं है। – Padin215

+2

@ लॉग 139 आप ऐसा क्यों कहते हैं? 'बहुभुज दृश्य '' एमकेपोलीगॉन व्यू' है, 'पथ' इसका' सीजीपाथआरफ 'है, न कि इसके बाध्य आयत, और' CGPathContainsPoint' उचित पथ/बिंदु नियंत्रण परीक्षण करता है, नहीं? मुझे यहां क्या समझ नहीं आ रहा है? मुझे लगता है कि यदि आप '[polygonView pointInside: polygonViewPoint withEvent: nil] 'का उपयोग करते हैं, तो आप सही हो सकते हैं। लेकिन अगर आपको वास्तविक 'पथ' मिल रहा है और 'CGPathContainsPoint' को कॉल कर रहा है, तो मुझे लगता है कि आप ठीक हैं। – Rob

+1

ठीक है, मैंने अपनी पिछली टिप्पणी वापस ले ली, यह काम करता है। खैर, यह आईओएस 6 या उससे कम में काम करता है, यह आईओएस 7 में टूट जाता है। – Padin215

5

मैं स्ट्रिंग में xml फ़ाइल से MKPolygon डाटा अंक हो रही है। मैं अंक और उपयोग दृष्टिकोण की सरणी के लिए डेटा स्ट्रिंग पार्स http://alienryderflex.com/polygon/

यह मेरे लिए काम करता है में दे ....

-(BOOL)isPoint:(CLLocationCoordinate2D)findLocation inPloygon:(NSArray*)polygon{ 

    NSMutableArray *tempPolygon=[NSMutableArray arrayWithArray:polygon]; 
    int i, j=(int)tempPolygon.count-1 ; 
    bool oddNodes=NO; 
    double x=findLocation.latitude; 
    double y=findLocation.longitude; 

    for (i=0; i<tempPolygon.count; i++) { 
     NSString*coordString=[tempPolygon objectAtIndex:i]; 
     NSArray*pointsOfCoordString=[coordString componentsSeparatedByString:@","]; 
     CLLocationCoordinate2D point=CLLocationCoordinate2DMake([[pointsOfCoordString objectAtIndex:1] doubleValue], [[pointsOfCoordString objectAtIndex:0] doubleValue]); 
     NSString*nextCoordString=[tempPolygon objectAtIndex:j]; 
     NSArray*nextPointsOfCoordString=[nextCoordString componentsSeparatedByString:@","]; 
     CLLocationCoordinate2D nextPoint=CLLocationCoordinate2DMake([[nextPointsOfCoordString objectAtIndex:1] doubleValue], [[nextPointsOfCoordString objectAtIndex:0] doubleValue]); 


     if ((point.longitude<y && nextPoint.longitude>=y) 
      || (nextPoint.longitude<y && point.longitude>=y)) { 
      if (point.latitude+(y-point.longitude)/(nextPoint.longitude-point.longitude)*(nextPoint.latitude-point.latitude)<x) { 
       oddNodes=!oddNodes; }} 
     j=i; } 


    return oddNodes; 

} 

मेरी बहुभुज (NSArray) वस्तुओं जैसे के लिए स्ट्रिंग में हैं @"-89.860021,44.944266,0"

+0

क्या आप अपने समाधान को आपके द्वारा प्रदान किए गए समाधान के बारे में थोड़ा और विवरण जोड़कर विस्तारित कर सकते हैं? – abarisone

+1

यह विधि आपके दिए गए स्थान को डेटा पॉइंट्स द्वारा बनाए गए बहुभुज के अंदर स्थित है (डेटा बिंदु भौगोलिक स्थान की सरणी हैं) की जांच करता है। पूर्ण एल्गोरिदम के लिए कृपया http://alienryderflex.com/polygon/ पर जाएं। –

+0

मेरे लिए बहुत अच्छा काम किया, लेकिन मुझे बहुभुज के घटकों का क्रम बदलना पड़ा: @ "देशांतर, अक्षांश, 0" धन्यवाद! –

2

यह स्विफ्ट में मेरे लिए काम किया:

extension MKPolygon { 

    func isCoordinateInsidePolyon(coordinate: CLLocationCoordinate2D) -> Bool { 

     var inside = false 

     let polygonRenderer = MKPolygonRenderer(polygon: self) 
     let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(coordinate) 
     let polygonViewPoint: CGPoint = polygonRenderer.pointForMapPoint(currentMapPoint) 

     if CGPathContainsPoint(polygonRenderer.path, nil, polygonViewPoint, true) { 
      inside = true 
     } 

     return inside 
    } 
} 
+0

यह काम करता है, और MKMapView की आवश्यकता नहीं है जिसका लाभ अन्य उत्तरों में वर्णित MKPolygonView दृष्टिकोण की तरह है। – oh7lzb

3
यहाँ

तेज है @Steve Stomp करने के लिए 3 अद्यतन संस्करण धन्यवाद

extension MKPolygon { 

    func contains(coordinate: CLLocationCoordinate2D) -> Bool { 

     let polygonRenderer = MKPolygonRenderer(polygon: self) 
     let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(coordinate) 
     let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint) 

     return polygonRenderer.path.contains(polygonViewPoint) 
    } 
} 
संबंधित मुद्दे