zoukankan      html  css  js  c++  java
  • iOS 利用高德地图WMS服务

    Demo:  https://github.com/xushiyou23/AMapTesting

    转:

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Bear_861110453/article/details/81564605
     
    本文主要介绍通过自定义高德地图 MATileOverlay 接口,添加 WMS 服务到地图上。

    自定义类 WMSTileOverlayUtil,继承自高德地图接口 MATileOverlay,主要重载函数: 
    - (NSURL *)URLForTilePath:(MATileOverlayPath)path; 
    - (void)loadTileAtPath:(MATileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))result;,见代码注释。

    #import <Foundation/Foundation.h>
    #import <MAMapKit/MATileOverlay.h>
    
    
    @interface WMSTileOverlayUtil : MATileOverlay
    
    - (id)initWithRootURL:(NSString *)rootRUL;
    
    /**
     * @brief 以tile path生成URL。用于加载tile,此方法默认填充URLTemplate
     * @param path tile path
     * @return 以tile path生成tileOverlay
     */
    - (NSURL *)URLForTilePath:(MATileOverlayPath)path;
    
    @end
    #import "WMSTileOverlayUtil.h"
    #import <MAMapKit/MAMapKit.h>
    #import <AMapFoundationKit/AMapFoundationKit.h>
    #import <math.h>
    
    #import "Api.h"
    
    @implementation WMSTileOverlayUtil
    {
        NSString *  rootURL;
        NSInteger   titleSize;           // = 256
        double      initialResolution;   // = 156543.03392804062;//2*Math.PI*6378137/titleSize;
        double      originShift;         // = 20037508.342789244;//2*Math.PI*6378137/2.0; 周长的一半
        double      HALF_PI;             // = Math.PI / 2.0;
        double      RAD_PER_DEGREE;      // = Math.PI / 180.0;
        double      METER_PER_DEGREE;    // = originShift / 180.0;//一度多少米
        double      DEGREE_PER_METER;    // = 180.0 / originShift;//一米多少度
    }
    
    - (id)initWithRootURL:(NSString *)rootRUL {
        self = [super init];
        if (self) {
            rootURL = rootRUL;
            titleSize = 256;
            initialResolution = 156543.03392804062;
            originShift = 20037508.342789244;
            HALF_PI = M_PI_2;
            RAD_PER_DEGREE = M_PI / 180.0;
            METER_PER_DEGREE = originShift / 180.0;
            DEGREE_PER_METER = 180.0 / originShift;
        }
        return self;
    }
    
    /**
     * @brief 以tile path生成URL。用于加载tile,此方法默认填充URLTemplate
     * @param path tile path
     * @return 以tile path生成tileOverlay
     */
    - (NSURL *)URLForTilePath:(MATileOverlayPath)path {
        NSString * strURL = [[NSString alloc] initWithFormat:@"%@%@", rootURL, [self titleBoundsByX:path.x
                                                                                                  Y:path.y
                                                                                                  Z:path.z]];
        NSURL * url = [NSURL URLWithString:strURL];
        return url;
    }
    
    /**
     * @brief 加载被请求的tile,并以tile数据或加载tile失败error访问回调block;默认实现为首先用URLForTilePath去获取URL,然后用异步NSURLConnection加载tile
     * @param path   tile path
     * @param result 用来传入tile数据或加载tile失败的error访问的回调block
     */
    - (void)loadTileAtPath:(MATileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))result {
        if (path.z < 8) return;
        NSURL * url = [self URLForTilePath:path];
        NSString * strURL = url.absoluteString;
    
        SuccessCallback successCallback = ^(id responseObject) {
            UIImage * image = [UIImage imageWithData:responseObject];
            NSData * data = UIImagePNGRepresentation(image);
            result(data, nil);
        };
    
        FailureCallBack failureCallBack = ^(NSError *error) {
            result(nil, error);
        };
    
        [Api GETWMSWith:strURL successCallback:successCallback failureCallBack:failureCallBack];
    }
    
    /**
     * @brief 取消请求瓦片,当地图显示区域发生变化时,会取消显示区域外的瓦片的下载, 当disableOffScreenTileLoading=YES时会被调用。since 5.3.0
     * @param path  tile path
     */
    - (void)cancelLoadOfTileAtPath:(MATileOverlayPath)path {
        [super cancelLoadOfTileAtPath:path];
    }
    
    /**
     * 根据瓦片的x/y等级返回瓦片范围
     *
     * @param tx x
     * @param ty y
     * @param zoom z
     * @return url
     */
    - (NSString *)titleBoundsByX:(NSInteger)tx Y:(NSInteger)ty Z:(NSInteger)zoom {
        double minX = [self pixels2Meters:(tx * titleSize) zoom:zoom];
        double maxY = -[self pixels2Meters:(ty * titleSize) zoom:zoom];
        double maxX = [self pixels2Meters:((tx + 1) * titleSize) zoom:zoom];
        double minY = -[self pixels2Meters:((ty + 1) * titleSize) zoom:zoom];
    
        //转换成经纬度
        minX = [self meters2Lon:minX];
        minY = [self meters2Lat:minY];
        maxX = [self meters2Lon:maxX];
        maxY = [self meters2Lat:maxY];
        //坐标转换工具类构造方法 Gps( WGS-84) 转 为高德地图需要的坐标
        CLLocationCoordinate2D amapcoord = AMapCoordinateConvert(CLLocationCoordinate2DMake(minY, minX), AMapCoordinateTypeGPS);
        minY = amapcoord.latitude;
        minX = amapcoord.longitude;
    
        CLLocationCoordinate2D maxAmapcoord = AMapCoordinateConvert(CLLocationCoordinate2DMake(maxY, maxX), AMapCoordinateTypeGPS);
        maxY = maxAmapcoord.latitude;
        maxX = maxAmapcoord.longitude;
        NSString * result = [[NSString alloc] initWithFormat:@"%f,%f,%f,%f&width=256&height=256", minX, minY, maxX, maxY];
        return result;
    }
    
    /**
     * 根据像素、等级算出坐标
     *
     * @param p p
     * @param zoom z
     * @return double
     */
    - (double)pixels2Meters:(NSInteger)p zoom:(NSInteger)zoom {
        return p * [self resolution:zoom] - originShift;
    }
    
    /**
     * 计算分辨率
     *
     * @param zoom z
     * @return double
     */
    - (double)resolution:(NSInteger)zoom {
        return initialResolution / (pow(2, zoom));
    }
    
    /**
     * X米转经纬度
     */
    - (double)meters2Lon:(double)mx {
        double lon = mx * DEGREE_PER_METER;
        return lon;
    }
    
    /**
     * Y米转经纬度
     */
    - (double)meters2Lat:(double)my {
        double lat = my * DEGREE_PER_METER;
        lat = 180.0 / M_PI * (2 * atan(exp(lat * RAD_PER_DEGREE)) - HALF_PI);
        return lat;
    }
    
    @end

    其中,- (void)loadTileAtPath:(MATileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))result; 函数中,使用自己写的 网络访问层去请求 wms 服务,并通过 result 函数贴到地图上。你也可以 改写成自己的网络访问层。

    问题

    为啥要重载 - (void)loadTileAtPath:(MATileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))result; 函数,因为只是从载 - (NSURL *)URLForTilePath:(MATileOverlayPath)path; 生成 NSURL 后,loadTileAtPath 函数会去通过网络请求加载 wms 服务,然而,这一步网络请求会报错:NSURLConnection -errorcode -1004,且一个星期没有解决为啥报错,所以只得重写,如果有熟悉高德地图 api 的小伙伴能够给予解答,不胜感激。

    注意

    如果使用 AFNetworking 要注意修改支持的类型:

     AFHTTPSessionManager * manager = [[AFHTTPSessionManager alloc] init];
     AFHTTPResponseSerializer *serializer=[AFHTTPResponseSerializer serializer];
     serializer.acceptableContentTypes = [NSSet setWithObject:@"image/png"];
     manager.responseSerializer = serializer;
  • 相关阅读:
    Error 1313: RETURN is only allowed in a FUNCTION SQL Statement
    Error Code: 1318. Incorrect number of arguments for PROCEDURE student.new_procedure; expected 0, got
    Error Code: 1305. FUNCTION student.rand_string does not exist
    Error Code: 1630. FUNCTION rand.string does not exist
    初入职场少年时,谁人不犯错?——北漂18年(6)
    错误代码: 1064
    第30章 表维护
    消息系统kafka及其变种Jafka、Metamorphosis (MetaQ)
    KAFKA分布式消息系统
    FineReport的JS编辑框和URL地址栏语法简介
  • 原文地址:https://www.cnblogs.com/xujiahui/p/9600588.html
Copyright © 2011-2022 走看看