Нанесение точек широты/долготы на изображение

У меня есть следующее:

  • Изображение — нарисованная от руки карта — размером примерно 600x400 метров. Изображение рисуется поверх плиток Google Maps.
  • Широта/долгота (из Google Maps) углов этого изображения. Или, другими словами, у меня есть северная и южная широта и восточная и западная долгота изображения.
  • Координата широты/долготы из CoreLocation iPhone.

Как мне нарисовать точку на этом изображении (или ничего, если она выходит за границы), представляющую координату из CoreLocation?

Дополнительный бонус: рисовать стрелку на краю карты, указывающую на координату, если координата выходит за пределы изображения.

Я хотел бы сделать это без использования библиотеки, такой как proj, чтобы не связывать большую библиотеку и понимать, что я делаю и почему.

Как вы, наверное, догадались, я пишу это на Objective-C. Однако ваш ответ не обязательно должен быть в Objective-C.


person August Lilleaas    schedule 11.09.2010    source источник


Ответы (3)


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

Вам нужны пользовательские наложения, доступный в iOS 4 и более поздних версиях. Лучшее место, где можно узнать о пользовательских оверлеях, — это видео WWDC 2010 под названием "Session 127 - Настройка карт с наложениями". Для видео также доступен пользовательский код. В видео ведущий создает пользовательскую карту и встраивает ее в MKMapView. Он также описывает инструмент, который вы можете использовать для создания своих плиток (чтобы разрезать их, помещать их формы в проекцию Меркатора и правильно называть их). Его карта сканируется с морской карты, а затем помещается поверх обычной карты.

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

Что касается нанесения точки на карту, вы можете сделать это несколькими способами. Проще всего просто использовать пользовательское MKAnnotationView с точкой в ​​качестве изображения. Таким образом, изображение не увеличивается и не уменьшается при увеличении. Если вы хотите, чтобы точка увеличивалась и уменьшалась, вам также следует использовать для этого пользовательское наложение. Вы можете легко использовать MKCircleView, который является подклассом MKOverlayView.

Для стрелки вы можете использовать обычный вид и повернуть ее (и разместить на одной стороне экрана) в соответствии с направлением вашей точки за пределами поля. Используйте MKMapPointForCoordinate, а затем рассчитайте направление от центра вашего вида.

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

person nevan king    schedule 18.09.2010
comment
Поскольку у меня есть только одно изображение, которое хранится в комплекте приложения, было бы глупо загружать фрагменты карты из Google в дополнение к моему собственному изображению. Как я могу запретить MapKit загружать плитки Google? Ничего не могу найти в документах, а видео WWDC показывает непрозрачную карту поверх плиток Google. - person August Lilleaas; 19.09.2010
comment
На самом деле вы получите более одного изображения. Вам нужно запустить инструмент под названием GDAL (gdal.org), чтобы разрезать большое изображение на фрагменты с различным увеличением. уровни. Более высокие масштабы будут иметь больше плиток. Я не уверен, что вы можете запретить MapKit загружать фрагменты, но я предполагаю, что если ваша собственная карта непрозрачна на 100%, он не будет их загружать. На видео его карта на самом деле слегка прозрачна. Он говорит о возможности увидеть корабль на спутнике. Посмотрите на карты Google возле Сан-Франциско, и вы сможете увидеть те же самые корабли. - person nevan king; 20.09.2010

После некоторых исследований я написал свою собственную библиотеку: libPirateMap. Это не очень отполировано, но работает.

Если ссылка не работает, я вставлю сюда соответствующий исходный код.

Использование:

// .h
PirateMap *pirateMap;
PirateMapPoint *pirateMapPoint;

// .m
- (void)viewDidLoad {
    [super viewDidLoad];
    pirateMap = [[PirateMap alloc] initWithNorthLatitude:59.87822
                                        andSouthLatitude:59.87428
                                        andWestLongitude:10.79847
                                        andEastLongitude:10.80375
                                           andImageWidth:640
                                          andImageHeight:960];

    pirateMapPoint = [[PirateMapPoint alloc] init];
    pirateMapPoint.pirateMap = pirateMap;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    pirateMapPoint.coordinate = PirateMapCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude)    
    PirateMapPoint2D point = [pirateMapPoint pointOnImage];
    // use point.x and point.y to place your view.
}

Соответствующий .m-код.

#import "PirateMap.h"

static const double RAD_TO_DEG = 180 / M_PI;
static const double DEG_TO_RAD = M_PI / 180;

PirateMapCoordinate2D PirateMapCoordinate2DMake(double latitude, double longitude) {
    return (PirateMapCoordinate2D) {latitude, longitude};
}

// atan2(y2-y1,x2-x1)

@implementation PirateMap
@synthesize northLatitude, southLatitude, westLongitude, eastLongitude,
imageWidth, imageHeight, latitudeImageToWorldRatio, longitudeImageToWorldRatio;

-(id)initWithNorthLatitude:(double)aNorthLatitude
          andSouthLatitude:(double)aSouthLatitude
          andWestLongitude:(double)aWestLongitude
          andEastLongitude:(double)anEastLongitude
             andImageWidth:(int)anImageWidth
            andImageHeight:(int)anImageHeight{
    if (self = [super init]) {
        self.northLatitude = aNorthLatitude;
        self.southLatitude = aSouthLatitude;
        self.westLongitude = aWestLongitude;
        self.eastLongitude = anEastLongitude;

        self.imageWidth = anImageWidth;
        self.imageHeight = anImageHeight;

        self.latitudeImageToWorldRatio = [self computeLatitudeImageToWorldRatio];
        self.longitudeImageToWorldRatio = [self computeLongitudeImageToWorldRatio];
    }
    return self;
}

-(double)computeLatitudeImageToWorldRatio {
    return fabs(self.northLatitude - self.southLatitude) / self.imageHeight;
}

-(double)computeLongitudeImageToWorldRatio {
    return fabs(self.eastLongitude - self.westLongitude) / self.imageWidth;
}

+(double)latitudeToMercatorY:(double)latitude {
    static const double M_PI_TO_4 = M_PI / 4;

    return RAD_TO_DEG * log(tan(M_PI_TO_4 + latitude * (DEG_TO_RAD / 2)));
}
@end

#import "PirateMapPoint.h"

PirateMapPoint2D PirateMapPoint2DMake(int x, int y) {
    return (PirateMapPoint2D) {x, y};
}

@implementation PirateMapPoint
@synthesize pirateMap, coordinate;

-(id)initWithPirateMap:(PirateMap *)aPirateMap andCoordinate:(PirateMapCoordinate2D)aCoordinate {
    if (self = [super init]) {
        self.pirateMap = aPirateMap;
        self.coordinate = aCoordinate;
    }

    return self;
}

-(PirateMapPoint2D)pointOnImage {
    double xDelta = self.coordinate.longitude - self.pirateMap.westLongitude;
    double yDelta = self.pirateMap.northLatitude - self.coordinate.latitude;
    return PirateMapPoint2DMake(round(xDelta / self.pirateMap.longitudeImageToWorldRatio), round(yDelta / self.pirateMap.latitudeImageToWorldRatio));
}
@end
person August Lilleaas    schedule 22.09.2010

Вы изучали использование MapKit? Он имеет методы для преобразования координат карты в координаты просмотра. Взгляните на семейство методов convert.

http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html

Если вы используете только 4.0, вы также можете воспользоваться классом оверлея.

http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKOverlayView_class/Reference/Reference.html

Ваше здоровье!

person logancautrell    schedule 12.09.2010