Подтвердить что ты не робот

Определить, находится ли точка внутри наложения MKPolygon

Я хочу, чтобы узнать, находится ли кран в 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];

его просто базовый план штата Колорадо.

Я получил настройку для настройки lat/long:

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

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

но я не уверен, как использовать технологию, если моя точка перехода находится внутри MKPolygon. похоже, нет способа выполнить эту проверку, поэтому я предполагаю, что мне нужно преобразовать MKPolygon в CGRect и использовать CGRectContainsPoint.

У MKPolygon есть свойство .points, но я не могу заставить их отступить.

любые предложения?

EDIT:

Оба решения ниже работают в iOS 6 или ниже, но прерываются в iOS 7. В iOS 7 свойство polygon.path всегда возвращает NULL. Г-жа Анна была достаточно любезна, чтобы предоставить решение в другом SO-вопросе здесь. Он включает в себя создание собственного пути из точек многоугольника, чтобы перейти в CGPathContainsPoint().

изображение моего многоугольника:

enter image description here

4b9b3361

Ответ 1

Я создал эту категорию 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

Ответ 2

Ваш метод 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;
        }
}

Ответ 3

Я получаю точки данных MKPolygon Data из файла xml в строке. Я разбираю строку данных в массиве точек и использую подход в 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"

Ответ 4

Определение того, является ли точка в произвольном многоугольнике нетривиальным, и неудивительно, что Apple не предоставляет его как часть MKPolygon. Вы можете получить доступ к точкам, которые позволяют выполнять итерацию по краям.

Чтобы определить, находится ли точка p внутри многоугольника s, рассмотрим каждое ребро как ориентированный отрезок в s. Если луч из p в любом фиксированном направлении (обычно параллельный оси X или Y) пересекает сегмент, возьмите знак Z-составляющей поперечного произведения луча с этим направленным отрезком. Если компонент Z > 0, добавьте 1 к счетчику. Если это & ​​lt; 0, вычесть 1. Трюк в реализации этого заключается в том, чтобы избежать проблем, когда край почти параллелен лучу, или когда луч проходит через вершину (он должен засчитываться только один раз, а не один раз для каждого ребра).

Если вы сделали это для всех ребер в s, вы посчитали бы количество раз, когда ваш луч пересекает контур многоугольника, где, если ребро идет слева направо, вы добавили, и если бы он шел от справа налево, вы вычитаете. Если итоговая сумма равна нулю, вы находитесь за пределами многоугольника. В противном случае вы находитесь внутри него.

Возможны многочисленные оптимизации. Один из них - сделать тест с ограничивающей коробкой перед более полным тестом. Другим является наличие структуры данных с границами на всех ребрах для тривиально отбрасываемых ребер, которые не пересекают луч.

Редактирование: Z-компонента A X B (крестообразное произведение A с B) задается следующим образом:

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

так как все, о чем вы заботитесь, это знак, вы можете проверить

a.x * b.y > a.y * b.x

Ответ 5

вот обновленная версия с быстрым 3 благодаря @Steve Stomp

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

Ответ 6

Это работало для меня в Swift:

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
    }
}