Вот решил я написать о MapKit в iOS. Почему-то большинство статей и уроков раскрывают только вопрос отображения каких-либо точек на карте и своего местоположения. Я тоже так делал, например, вот тут. Со временем я осознал, что начинать работу с картой стоит совсем не с «пинов». Начнем с другого.

При работе с картой нам доступно три проекции:

  • Проекция поинтов карты
  • Проекция координат GPS
  • Экран, на котором видно карту

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

Точка, размер, область

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

Размеры карты выражаются в специальных единицах — поинтах (map points). Поинт на той карте, которую мы себе представили равен одному поинту на экране устройства. Для выражения точек в этой проекции существует специальная структура — MKMapPoint. Объявлена она так:

typedef struct {

double x;
double y;
} MKMapPoint;

Для выражения размера существует структура — MKMapSize:

typedef struct {

double width;
double height;
} MKMapSize;

И, наконец, для выражения какой-либо области есть структура MKMapRect:

typedef struct {

MKMapPoint origin;
MKMapSize size;
} MKMapRect;

Чем-то напоминает Core Graphics с CGRect, CGSize и CGPoint, не правда ли?

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

Существует три метода, которые приводят эти структуры к строкам NSString. Это очень удобно использовать при отладке:

NSString *MKStringFromMapPoint(MKMapPoint point);

NSString *MKStringFromMapSize(MKMapSize size);
NSString *MKStringFromMapRect(MKMapRect rect)

Можем использовать, например, так:


MKMapSize size = ...;
NSLog(@"%@", MKStringFromMapSize(size));

Размеры мира и видимой части

Карта имеет абсолютные размеры, которые выражаются через MKMapSize и область MKMapRect. Размер и область содержаться в константах MKMapSizeWorld и MKMapRectWorld. Они равны:

Size: {268435456.0, 268435456.0}

Rect: {{0.0, 0.0}, {268435456.0, 268435456.0}}

Вспомним, что один поинт карты равен одному поинту экрана. Глядя на размеры, понимаем, что размер карты очень большой. Если учитывать что размер экрана в поинтах — (320, 480), то по площади в ней поместится 469124961184 экранов iPhone; Размер iPad в поинтах — (1024, 768), тогда на этой карте поместится 91625968981 экранов iPad.

Когда мы смотрим на карту, мы видим не всю ее часть, а какую-либо область, которая так же выражается через MKMapRect. Такое свойство есть у MKMapView и называется visibleMapRect. Чаще всего размеры видимой области кратны размерам frame у MKMapView. Во сколько раз размеры видимой области больше размеров frame зависит от уровня зума (о котором мы забыли специально :) ).

Все это напоминает UIScrollView. Видимая область «скользит» по большой области, показывая лишь ее часть.

Функции работы со структурами

Сравнивает две точки на равенство:

BOOL MKMapPointEqualToPoint(MKMapPoint point1, MKMapPoint point2)

Сравнивает размеры на равенство:

BOOL MKMapSizeEqualToSize(MKMapSize size1, MKMapSize size2);

Сравнивает области на равенство:

BOOL MKMapRectEqualToRect(MKMapRect rect1, MKMapRect rect2);

Возвращает область, являющуюся пересечением двух областей:

MKMapRect MKMapRectIntersection(MKMapRect rect1, MKMapRect rect2);

Увеличивает область по x на dx, по y на dy

MKMapRect MKMapRectInset(MKMapRect rect, double dx, double dy);

Уменьшает область на dx и dy

MKMapRect MKMapRectOffset(MKMapRect rect, double dx, double dy);

Определяет, принадлежит ли точка области:

BOOL MKMapRectContainsPoint(MKMapRect rect, MKMapPoint point);

Определяет, содержит ли область другую область:

BOOL MKMapRectContainsRect(MKMapRect rect1, MKMapRect rect2);

Определяет, пересекаются ли области:

BOOL MKMapRectIntersectsRect(MKMapRect rect1, MKMapRect rect2);

Разбивает область на две области. Направление разреза — edge, сколько нужно «отрезать» — amount:

void MKMapRectDivide(MKMapRect rect, MKMapRect *slice, MKMapRect *remainder, double amount, CGRectEdge edge)

В итоге

Для чего нам это было нужно? Я бы сказал для общего понимания, как работает карта. Геометрия карты используется чаще всего в случае наложения сложных оверлеев на карту, о которых мы с вами обязательно поговорим. Например, мы можем накладывать свои альтернативные тайлы поверх тайлов Google. Так же можем выделить для себя какую-либо специфичную область и определять, видит ли ее пользователь.

В следующей части мы познакомимся со второй проекцией и узнаем как переводить GPS-координаты в map-points.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *