Проверьте, пересекается ли MKCircle с MKPolygon

Я ищу некоторые рекомендации по тестированию, если MKPolygon пересекает MKCircle. В настоящее время я использую:

if ([circle intersectsMapRect:[poly boundingMapRect]]) {
                    //they do intersect
   }

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

Поиск по теме привел меня к проекту Чеда Саксона о пересечении многоугольников. Это могло бы быть полезно, если бы я мог каким-то образом преобразовать свой MKCircle в многосторонний многоугольник - что возможно, но в конечном итоге я считаю, что это обходной способ решить эту проблему.

В конечном итоге мне интересно, есть ли простое решение, которое я упустил из виду, прежде чем углубляться в портирование моей собственной реализации алгоритма тестирования геометрического луча.


person capikaw    schedule 06.09.2013    source источник


Ответы (2)


Пара мыслей:

  1. Если вы используете этот проект пересечения полигонов, имейте в виду, что в нем есть несколько утечек. Я отправил запрос на включение, который исправляет некоторые из них (и несколько других случайных наблюдений). Я бы с осторожностью относился к принятию любого кода этого контроллера представления (поскольку у него есть и другие проблемы), но эта категория кажется приемлемой, если вы согласны с различными ограничениями, которые она влечет за собой (в частности, ограничение по часовой стрелке, которое на самом деле не является проблема, если вы только определяете, пересекаются ли они).

  2. Вместо того, чтобы преобразовывать круг в серию многоугольников, а затем использовать этот класс пересечения многоугольников, я мог бы рассмотреть альтернативный подход, основанный на том, что вы можете обнаружить пересечение с кругом, используя тот факт, что вы можете посмотреть на расстояние между соответствующими точками в многоугольник и радиус окружности. Представляется, что есть три аспекта проблемы:

    • Если расстояние между любой из вершин многоугольника и центром окружности меньше радиуса окружности, то многоугольник и окружность пересекаются.

      вершина внутри круга

    • Охватывает ли многоугольник круг (это тот особый случай, когда расстояние от всех сторон многоугольника будет больше, чем радиус круга, но круг и многоугольник по-прежнему явно пересекаются). Этого легко добиться, проверив, охватывает ли CGPath вида многоугольника центр круга, используя CGPathContainsPoint.

      введите здесь описание изображения

    • Единственная сложная часть состоит в том, чтобы проверить, пересекает ли какая-либо сторона многоугольника окружность, а именно, что минимальное расстояние между сторонами многоугольника и центром окружности меньше радиуса окружности;

      сторона внутри круга

    Поэтому, чтобы вычислить расстояние каждой стороны от центра круга, я мог бы выполнить итерацию по каждой стороне многоугольника и для тех сторон, которые обращены к центру круга (т. е. для которых центр круга перпендикулярен сегменту, что означает, что воображаемая линия перпендикулярно стороне многоугольника, которая проходит через центр круга, фактически пересекает отрезок линии), вы можете:

    • Вычисление констант a, b и c для этой стороны многоугольника для уравнения ax + by + c = 0 для отрезка, проходящего между вершинами многоугольника (x1, y1) и (x 2, у2):

    • а = (y1 – y2)

    • б = (х2 – х1)

    • c = (x1y2 – x2y1)

    • Рассчитать расстояние от точки до линии, используя (x0, y0) в качестве центра круга:

      abs(ax0+by0+c)/sqrt(a^2+b^2)

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

Я разместил пример проекта, использующий эту технику, на github.

person Rob    schedule 07.09.2013
comment
вот что у него есть .. многоугольник не прямоугольник. - person Daij-Djan; 07.09.2013
comment
@Daij-Djan Мое использование прямоугольников было просто для иллюстрации трех сценариев алгоритма, но ничто в этом ответе не зависит от того, является ли многоугольник прямоугольником. - person Rob; 07.09.2013
comment
Привет Роб - какой отличный ответ. Спасибо. С тех пор я вычислил расстояние до многоугольника-вершины. Я зацикливаю каждую точку многоугольника, а затем в основном проверяю расстояние до центра круга: если оно меньше радиуса, прерываю и возвращаю да. Я предполагаю, что вычисление меньшего количества точек для SIDE по сравнению со многими точками для POINT просто быстрее? Я проверю производительность обоих на этой неделе и опубликую результаты здесь. - person capikaw; 07.09.2013
comment
@capikaw Нет, я не использую логику между центрами и полигонами из соображений производительности. Я делаю это из-за моего третьего сценария, где они пересекаются, хотя ни один из углов многоугольника не находится внутри круга. Возможно, это сценарий, о котором вы не беспокоитесь, и в этом случае все намного проще. Но я думаю, что точная логика пересечения многоугольника и круга, вероятно, требует этого. - person Rob; 07.09.2013
comment
Конечно, теперь это имеет смысл - еще раз спасибо, @Rob! - person capikaw; 08.09.2013

Просто для тех, кто хочет немного разобраться в решении, вот полезное расширение MKCircle, которое я написал, которое проверяет, находится ли точка (в данном случае точка многоугольника) внутри круга или нет. Наслаждаться!

//MKCircle+PointInCircle.h

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MKCircle (PointInCircle)

-(BOOL)coordInCircle:(CLLocationCoordinate2D)coord;

@end

//MKCircle+PointInCircle.m

#import "MKCircle+PointInCircle.h"

@implementation MKCircle (PointInCircle)

-(BOOL)coordInCircle:(CLLocationCoordinate2D)coord {

    CLLocation *locFrom = [[CLLocation alloc] initWithLatitude:self.coordinate.latitude longitude:self.coordinate.longitude];
    CLLocation *locTo = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];

    double distance = [locFrom distanceFromLocation:locTo];
    BOOL isInside = (distance <= self.radius);

    return isInside;
}

@end
person capikaw    schedule 09.09.2013