Содержание
Вот решил я написать о 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.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: