美文网首页
iOS ArcGIS 10.2.5 详细介绍

iOS ArcGIS 10.2.5 详细介绍

作者: 软件iOS开发 | 来源:发表于2018-01-13 12:18 被阅读75次

    经常有人问我,ArcGIS怎么弄,怎么弄。

    作为当年在厦门搞过商业级天地图项目的我来说,是时候展现一波技术了,就把干货告诉大家,让大家好好搞。不仅会介绍API,还会介绍思路,以及分析过程等等。

    前公司项目:天地图·厦门,已发布在App Store,欢迎下载查看。

    天地图·厦门 首页

    [AGSRuntimeEnvironment setClientID:clientID error:&error];

    用来设置认证,只有通过认证,地图才不会显示开发版。

    self.mapView.locationDisplay.showsPing = NO;//取消闪烁的光圈

    self.mapView.locationDisplay.showsAccuracy = NO;//取消闪烁的光圈

    通过这两段代码可以取消ArcGIS闪烁的光圈。

    self.mapView.locationDisplay.location.accuracy = 10;

    设置定位精度,单位是米。

    self.mapView.layerDelegate = self;

    设置层代理,主要用到了mapViewDidLoad的代理方法,当地图加载完成时调用。

    self.mapView.touchDelegate = self;

    设置触碰代理,主要用到了didClickAtPoint的代理方法,当点击地图时调用。

    self.mapView.minScale = 100000000;

    self.mapView.maxScale = 1000;

    设置地图的放大倍数和缩小倍数,ArcGIS不会自己缩小到很小,需要你来设置,通过设置这个参数,可以看到门牌号。

    [self.mapView enableWrapAround];

    设置允许地图环绕,如果不设置这个参数,左右滑动地图时会到底。比如向左滑动到美国时就停止了,设置了这个参数,滑动到美国,可以继续左滑到英国,再回到美国,形成循环。

    AGSSpatialReference *sr = [AGSSpatialReference spatialReferenceWithWKID:4490];

    AGSEnvelope *env = [AGSEnvelope envelopeWithXmin:117.85362348365

    ymin:24.398242072050003

    xmax:118.48276347535

    ymax:24.93150561495

    spatialReference:sr];

    [self.mapView zoomToEnvelope:env animated:NO];

    设置初始定位区域,我将它定位在厦门。

    以上方法我放在viewDidLoad方法中执行。

    [self.mapView.locationDisplay startDataSource];

    在地图上显示设备位置。

    [self.mapView.locationDisplay addObserver:self

    forKeyPath:@"autoPanMode"

    options:(NSKeyValueObservingOptionNew)

    context:NULL];

    监听地图的定位情况,用来控制当前是否处于地图的中心

    [self.mapView addObserver:self

    forKeyPath:@"mapScale"

    options:(NSKeyValueObservingOptionNew)

    context:NULL];

    地图缩放系数改变时调用,我用来取消搜索框键盘。

    [self.mapView addObserver:self

    forKeyPath:@"visibleAreaEnvelope"

    options:(NSKeyValueObservingOptionNew)

    context:NULL];

    地图可见区域监测,实时获取地图中心位置,纠错的时候可以用到。

    [[NSNotificationCenter defaultCenter] addObserver:self

    selector:@selector(mapViewDidEndZooming:)

    name:AGSMapViewDidEndZoomingNotification

    object:nil];

    地图停止缩放时触发,用来判断是否需要移除全球地图,提高加载速度。

    [[NSNotificationCenter defaultCenter] addObserver:self

    selector:@selector(mapViewDidEndPanning:)

    name:AGSMapViewDidEndPanningNotification

    object:nil];

    地图停止平移时触发。

    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self

    action:@selector(handleMapPan:)];

    [self.mapView addGestureRecognizer:panGestureRecognizer];

    处理地图平移。

    以上方法我放在mapViewDidLoad方法中执行。

    [self.mapView zoomIn:YES];

    [self.mapView zoomOut:YES];

    地图的放大和缩小操作。

    TDTTiledServiceLayer *tianDiTuLyr = [[TDTTiledServiceLayer alloc] initWithLayerType:type LocalServiceURL:nil error:&err];

    添加全球地图操作,TDTTiledServiceLayer是我自己自定义的类,用来加载全球地图用的。遗憾的是,ArcGIS并没有使用一个类来处理加载这一类型全球底图的操作,所以要自己去实现,而这个实现过程过于复杂,我当初也是花了不少时间,篇幅的限制,就不在这里细细展开,因为细细展开的话,文章太长太长了。

    [self.mapView insertMapLayer:tianDiTuLyr withName:name atIndex:0];

    在某个层级插入地图。地图上放置一张底图,如果上面有什么信息的话,就往上面加一层,需要什么样的信息,就叠加什么样的层,层级处理的理论基础与iOS视图或者cocos 2D都是一样的。

    id tiledLayer = [AGSLocalTiledLayer localTiledLayerWithPath:fileName];

    加载本地图层,如果本地有tpk文件,可以直接加载。tpk文件和离线地图有紧密的关系,因为离线地图下载下来的就是tpk文件,tpk文件是离线地图数据格式,之后会说到离线地图。

    id tiledLayer = [MDTiledMapServiceLayer tiledMapServiceLayerWithURL:url];

    MDTiledMapServiceLayer是我自己定义的,继承于AGSTiledMapServiceLayer,根据需要,可能要重写urlForTileKey方法,并配置好column、row、level等信息,而level信息要与服务端约定好。

    以上内容是图层的初始化和叠加操作。

    接下来介绍专题图的加载。

    所谓的专题图,无非是各种功能或者数据显示图,比如在地图上显示自行车位置,显示水坝位置,显示公园位置,这些都是一个个图层,需要往地图上叠加。而加载这些图层用到的地图类也不尽相同。比如:

    AGSDynamicMapServiceLayer layer = [AGSDynamicMapServiceLayer dynamicMapServiceLayerWithURL:url];

    用来加载动态图层。

    AGSGraphicsLayer *graphicsLayer = [AGSGraphicsLayer graphicsLayer];

    用来加载图像层。

    我目前用到这两个,当然还有其他很多图层,之前都有研究过,走过不少弯路。

    AGSCredential *credential = [[AGSCredential alloc] initWithToken:data.appToken referer:data.appReferer];

    地图凭证,保证系统的安全和对用户的控制。

    AGSQueryTask *queryTask = [AGSQueryTask queryTaskWithURL:url credential:credential];

    queryTask.delegate = self;

    创建查询任务。

    AGSQuery *query = [AGSQuery query];

    query.whereClause = data.whereClause;

    query.outFields = [NSArray arrayWithObject:@"*"];

    query.returnGeometry = YES;

    query.outSpatialReference = self.mapView.spatialReference;

    [queryTask executeWithQuery:query];

    创建查询参数。

    查询任务和查询参数用于显示图层上已经标出的指定的点。有些需求可能需要对这些点进行抽稀,我在抽稀过程中使用了冒泡算法,加了点动态规划。

    AGSIdentifyTask *identifyTask = [AGSIdentifyTask identifyTaskWithURL:url];

    identifyTask.delegate = self;

    创建一个Id任务,之前使用这个去加载,因为内容定制度较差,后来改用服务端进行。

    但无论是查询任务或者Id任务,它们都需要设置代理,然后实现代理的方法,确保操作得到响应。

    接下来介绍测距和测面。

    AGSSketchGraphicsLayer *measureSketchLayer = [AGSSketchGraphicsLayer graphicsLayer];

    需要使用到该图层,在这图层上进行绘制。

    然后你需要理解图层上几个相关变量的含义,比如:

    midVertexSymbol

    allowHitTest

    vertexSymbol

    selectedVertexSymbol

    mainSymbol

    geometry

    特别是geometry,几种几何图形不同的创建方式如下:

    //创建线

    measureSketchLayer.geometry = [[AGSMutablePolyline alloc] initWithSpatialReference:self.mapView.spatialReference];

    //创建面

    measureSketchLayer.geometry = [[AGSMutablePolygon alloc] initWithSpatialReference:self.mapView.spatialReference];

    记得设置一下地图的触摸代理。

    self.mapView.touchDelegate = measureSketchLayer;

    下面的通知,AGSSketchGraphicsLayerGeometryDidChangeNotification,是用来监测几何体的形状变化。

    [[NSNotificationCenter defaultCenter] addObserver:self

    selector:@selector(respondToGeomChanged:)

    name:AGSSketchGraphicsLayerGeometryDidChangeNotification

    object:nil];

    在这个方法里面处理距离变化或者面积变化,以及处理之后要介绍的标绘内容。

    介绍一下距离和面积的计算方法:

    AGSGeometry *sketchGeometry = measureSketchLayer.geometry;

    AGSGeometryEngine *geometryEngine = [AGSGeometryEngine defaultGeometryEngine];

    self.distance = [geometryEngine geodesicLengthOfGeometry:sketchGeometry inUnit:AGSSRUnitMeter];

    距离计算,单位是米。

    AGSGeometry *sketchGeometry = measureSketchLayer.geometry;

    AGSGeometryEngine *geometryEngine = [AGSGeometryEngine defaultGeometryEngine];

    self.area = [geometryEngine shapePreservingAreaOfGeometry:sketchGeometry inUnit:AGSAreaUnitsSquareMeters];

    面积计算,单位是平方米。

    接下来介绍标绘,包括点标绘、线标绘、面标绘、文字标绘。

    创建方式:

    //创建点

    measureSketchLayer.geometry = [[AGSMutablePoint alloc] initWithX:NAN y:NAN spatialReference:self.mapView.spatialReference];

    //创建线

    measureSketchLayer.geometry = [[AGSMutablePolyline alloc] initWithSpatialReference:self.mapView.spatialReference];

    //创建面

    measureSketchLayer.geometry = [[AGSMutablePolygon alloc] initWithSpatialReference:self.mapView.spatialReference];

    在AGSSketchGraphicsLayerGeometryDidChangeNotification的通知方法中,更新点的信息。

    如果你希望在点上面增加自定义视图,可以这么写:

    self.mapView.callout.customView = antherView;

    其中antherView,是我自己定义的一个视图,比如在视图上放个删除按钮,放个label显示数据等等,都可以。

    如果你想创建文字标绘,你需要这么写:

    AGSTextSymbol *textSymbol = [[AGSTextSymbol alloc] initWithText:self.plottingData.title

    color:[UIColor redColor]];

    textSymbol.fontFamily = @"Heiti SC";

    textSymbol.vAlignment = AGSTextSymbolVAlignmentMiddle;

    textSymbol.hAlignment = AGSTextSymbolHAlignmentCenter;

    textSymbol.fontSize = 13;

    textSymbol.offset = CGPointMake(0, 0);

    AGSCompositeSymbol *compositeSymbol = [AGSCompositeSymbol compositeSymbol];

    [compositeSymbol addSymbol:textSymbol];

    AGSPoint *point_ags = [[AGSPoint alloc] initWithX:point.x y:point.y spatialReference:self.mapView.spatialReference];

    AGSGraphic *graphic = [AGSGraphic graphicWithGeometry:point_ags symbol:compositeSymbol attributes:nil];

    其中各种参数的含义,你通过英文的字面意思或者实际操作,应该都能理解。

    有一个业务需求提到需要保存标绘数据,研究发现AGSGeometry实现了AGSCoding协议,可以将AGSGeometry对象转成NSDictionary,这样就可以使用归档保存在本地,归档类NSKeyedArchiver。

    接下来介绍纠错,路线规划,运动,搜索,离线地图。

    纠错需要让地图标识符一直处于地图的中点,调用的函数为:

    CGPoint point = self.view.center;

    AGSPoint *mapPoint = [self.mapView toMapPoint:point];

    配合之前说的visibleAreaEnvelope就可以实现了。

    路线规划涉及到画路线轨迹,先创建一个图像层AGSGraphicsLayer,然后创建直线,或者在直线终点创建点。

    //创建直线,添加路径

    AGSMutablePolyline *polyline = [[AGSMutablePolyline alloc] initWithSpatialReference:self.mapView.spatialReference];

    [polyline addPathToPolyline];

    //创建点,添加点路径

    AGSPoint *point = [AGSPoint pointWithX:x y:y spatialReference:self.mapView.spatialReference];

    [polyline addPointToPath:point];

    起点和终点的符号是由图片和文字组成,你需要这么写:

    //创建一个图片符号

    AGSPictureMarkerSymbol *marker = [AGSPictureMarkerSymbol pictureMarkerSymbolWithImage:image];

    //创建一个文字符号

    AGSTextSymbol *textSymbol = [[AGSTextSymbol alloc] initWithText:text

    color:[UIColor whiteColor]];

    //然后创建一个AGSCompositeSymbol来加入这两个符号,如:

    AGSCompositeSymbol *compositeSymbol = [AGSCompositeSymbol compositeSymbol];

    [compositeSymbol addSymbol:marker];

    [compositeSymbol addSymbol:textSymbol];

    路线规划的数据是通过请求服务端获取的,获取的数据有一定的格式,一般为分段的一系列点的集合,需要根据约定好的规范进行适配。

    路线画出来了,那么如何跳到路线所在位置的中心,你可以这么写:

    AGSMutableEnvelope *envelope = [routeGraphicsLayer.fullEnvelope mutableCopy];

    [envelope expandByFactor:2.5];

    [self.mapView zoomToEnvelope:envelope animated:YES];

    说说运动:

    运动中需要计步,计步采用加速度传感器实现,封装了一个StepManager来管理步数,具体的算法就不细细展开,非本篇所讲内容。

    运动需要在后台长时间运行,需要申请后台权限,上架的时候在备注中讲清楚这个事,态度诚恳,必要的时候叫苹果几声爹,一般就没什么问题了。

    double distance = [geometryEngine geodesicLengthOfGeometry:lineGraphic.geometry inUnit:AGSSRUnitMeter];

    运动采用的也是距离函数,保存上一点和下一点,然后规定一下距离超过5米或者10米时才画直线。

    接下来说搜索,

    [self.mapView zoomToScale:self.mapView.mapScale withCenterPoint:(AGSPoint *)graphic.geometry animated:YES];

    当点击搜索出来的红色点时,或者点击表格数据时,相应的红点要位于中心。

    搜索时需要与路线规划对接,记住在程序设计的时候,多抽离模块代码,避免相同模块写了两份相同的代码。

    离线地图比较简单,就没什么好说的了。需要注意的是这是个在后台发起的下载任务,而不是属于某个控制器的下载任务,判断好总大小,控制好节点数据,处理好暂停、继续,就没什么问题了。

    总结:ArcGIS是定位最准确的地图,比高德和百度还准确。但是缺点也是很明显的,API封装臃肿,内存消耗大,线程处理不够优美,地图块状切割太大,用户体验不够好等等。比起高德和百度地图来说,还是差了一截。但是,处理地图的方式基本都是一致的,可以作为参考。

    尾记:当年研究的热血涌上心头,不断地自我突破,它是我1个人花了1个多月的时间做出来,同样的Deadline,安卓是两个人做的,还不算上我调通接口的时间。而且,论体验和Bug率来说,都属上层,最终让地测院的人赞不绝口。

    当然,当初的架构还没有使用到我文章列表的“iOS架构”,代码的结构也非常的不优美,但是注释还是都有的。之所以出现这样的问题,还是那句话:Deadline不是第一生产力,只是给了你把一堆Shit交上去的勇气。

    看完了,不点个赞吗?哈哈哈,随便你,开心就好。

    相关文章

      网友评论

          本文标题:iOS ArcGIS 10.2.5 详细介绍

          本文链接:https://www.haomeiwen.com/subject/xohcoxtx.html