在图像上绘制经纬度点

5

我有以下内容:

  • 一张手绘地图,大约600x400米的区域。这张图片是在Google地图瓦片之上绘制的。
  • 该图像的角落的纬度/经度(来自Google地图)。或者换句话说,我有图像的南北纬度和东西经度。
  • iPhone CoreLocation的纬度/经度坐标。

如何在此图像上绘制一个点(如果超出边界,则不要绘制任何东西),代表来自CoreLocation的坐标?

额外奖励:如果该坐标超出图像的边界,可以在地图边缘上绘制一个箭头指向该坐标。

为了避免打包大型库文件并更好地理解操作原理,请尝试不使用像proj这样的库。

正如您可能已经猜到的那样,我正在用Objective-C编写此代码。但是,您的答案不必使用Objective-C。

3个回答

3
如果我理解正确,您需要做两件事。第一件事是将您的自定义图像放入地图视图中,并在正确的坐标处显示您的自定义瓦片,然后进行平移、缩放等操作。第二件事是在特定的纬度和经度上在该图像上绘制一个点。
您需要的是iOS 4及以上版本中提供的自定义覆盖物。了解自定义覆盖物的最佳途径是观看WWDC 2010视频,名为“Session 127 - Customizing Maps with Overlays”。视频中还提供了自定义代码。在视频中,演示者创建了一个自定义地图并将其嵌入到MKMapView中。他还描述了一个工具,您可以使用该工具来制作您的瓷砖(将它们切成碎片,并将它们的形状投影到墨卡托投影中并正确命名)。他的地图是从海图扫描的,然后放置在正常地图视图的顶部。
您可以使用boundingMapRect通过将自定义地图的边界转换为点来创建边界矩形。您可以使用MKMapPointForCoordinateMKCoordinateForMapPoint在点和坐标之间进行转换。
至于在地图上绘制点,有几种方法可以实现。最简单的方法是使用自定义的MKAnnotationView,其图像为一个点。这样,随着缩放,图像不会变大或缩小。如果您希望点能够随着缩放而变化,则应该为此使用自定义覆盖层。您可以轻松地使用MKCircleView,它是MKOverlayView的子类。
对于箭头,您可以使用普通视图并根据越界点的方向旋转它(并将其放置在屏幕的一侧)。使用MKMapPointForCoordinate,然后从视图中心计算方向。
但是,您最好的信息来源将是那个视频。他深入讲解了整个过程,并提供了一个可工作的应用程序的源代码,这正是您需要构建自己的地图的90%。

由于我只有一个存储在应用程序包中的图像,因此除了我的自己的图像之外,从谷歌下载地图瓦片似乎有点愚蠢。我该如何阻止MapKit下载Google瓦片?文档中找不到任何内容,而WWDC视频显示了一个不透明的地图覆盖在Google的瓦片上... - August Lilleaas
你最终会得到不止一张图片。你需要运行一个叫做GDAL(http://www.gdal.org/)的工具,在不同的缩放级别下将大图切成瓦片。较高的缩放级别将有更多的瓦片。我不确定是否可以阻止MapKit下载瓦片,但我认为如果你自己的地图是100%不透明的,它就不会下载它们。在视频中,他的地图实际上略微透明。他谈到能够在卫星上看到一艘船。看看旧金山附近的Google地图,你也能看到同样的船只。 - nevan king

3

经过一些研究,我编写了自己的库: 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

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接