【问题标题】:Drawing lat/lng points on an image在图像上绘制 lat/lng 点
【发布时间】:2010-09-11 17:45:45
【问题描述】:

我有以下:

  • 图像 - 手绘地图 - 面积约为 600x400 米。该图像绘制在 Google 地图图块之上。
  • 此图像角落的纬度/经度(来自 Google 地图)。或者换句话说,我有图像的南北纬和东西经度。
  • 来自 iPhone 的 CoreLocation 的纬度/经度坐标。

如何在此图像上绘制一个点(如果超出范围则不绘制),表示来自 CoreLocation 的坐标?

额外奖励:在地图边缘画一个箭头,指向坐标,如果坐标超出图像范围。

我想在不使用 proj 之类的库的情况下执行此操作,以便不必捆绑大型库,并了解我在做什么以及为什么。

你可能已经猜到了,我是用 Objective-C 写的。不过,您的答案不一定要在 Objective-C 中。

【问题讨论】:

    标签: objective-c math map gis trigonometry


    【解决方案1】:

    如果我理解正确,您需要做两件事。第一种是将您的自定义图像放入地图视图中,并让您的自定义图块出现在正确的坐标处,然后平移、缩放等。您需要做的第二件事是在该图像上的某个纬度和经度上画一个点。

    您需要的是custom overlays,适用于 iOS 4 及更高版本。了解自定义叠加层的最佳位置是WWDC 2010 video,名为“Session 127 - Customizing Maps with Overlays”。视频还提供自定义代码。在视频中,演示者创建了一个自定义地图并将其嵌入到 MKMapView 中。他还描述了一种可以用来制作瓷砖的工具(将它们切割,将它们的形状放入墨卡托投影并正确命名)。他的地图是从海洋地图中扫描出来的,然后放在法线地图视图的顶部。

    您可以使用boundingMapRect 通过将自定义地图的边界转换为点来创建边界矩形。您可以使用MKMapPointForCoordinateMKCoordinateForMapPoint 在点和坐标之间进行转换。

    至于在地图上绘制一个点,您可以通过多种方式进行。最简单的方法是使用自定义的MKAnnotationView,并带有一个点作为其图像。这样,当您放大时,图像不会变大和变小。如果您希望点变大和缩小,您也应该使用自定义叠加层。您可以轻松使用MKCircleView,它是MKOverlayView 的子类

    对于箭头,您可以使用普通视图并根据边界点的方向旋转它(并将其放置在屏幕的一侧)。使用MKMapPointForCoordinate,然后从您的视图中心计算方向。

    但您最好的来源是该视频。他对整个过程进行了深入研究,并提供了一个工作应用程序的源代码,它是您自己地图所需资源的 90%。

    【讨论】:

    • 由于我只有一个图像存储在应用程序包中,除了我自己的图像之外,从谷歌下载地图图块会有点愚蠢。如何阻止 MapKit 下载谷歌图块?在文档中找不到任何内容,WWDC 视频在 Google 的图块上显示了一张不透明的地图..
    • 您实际上会得到不止一张图像。您需要运行一个名为 GDAL (gdal.org) 的工具来将您的大图像切割成各种缩放级别的图块。更高的缩放将有更多的瓷砖。我不确定你是否可以阻止 MapKit 下载瓷砖,但我假设如果你自己的地图是 100% 不透明的,它就不会下载它们。在视频中,他的地图实际上是略微透明的。他谈到能够在卫星上看到一艘船。查看旧金山附近的 Google 地图,您将能够看到相同的船只。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      您是否考虑过使用 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

      干杯!

      【讨论】:

        猜你喜欢
        • 2011-11-29
        • 2022-01-03
        • 1970-01-01
        • 2016-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多