美文网首页ArcGIS学习
IOS ArcGIS 调用 定位服务和地理围栏

IOS ArcGIS 调用 定位服务和地理围栏

作者: 多喝热开水 | 来源:发表于2020-06-01 09:50 被阅读0次

    ArcGIS 一些常规应用场景描述:

    一、获得用户的位置

    使用CoreLocation框架。

    1、如果你的应用基于位置来正确运行,你应该在你的Info.plist中包括UIRequiredDeviceCapabilities键.App Store使用这个信息来阻止没有定位的设备下载该应用。

    UIRequiredDeviceCapabilities键对应一个字符串数组,包括:
    1)location-services字符串--如果你请求一般的定位服务
    2)gps--如果你请求GPS级的精度
    如果你的应用需要定位,但是没有定位也能正常运行,就不要包含这个键。

    2、获得用户的定位

    有2种方法:
    1)标准的定位服务
    2)显著的位置变化定位服务:只在4.0以后有效。

    3、确定定位服务是否可用:

    1)用户可以在设置程序中禁用定位服务
    2)用户可以对某个应用拒绝定位服务
    3)设备可能在飞行模式,并且不能启用需要的硬件。
    因为这些原因,推荐你调用[CLLocationManager locationServicesEnabled]来确定定位服务是否可用。
    使用[CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied 检查定位服务是否对本app禁止。

    4.启动标准的定位服务:

    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    // Set a movement threshold for new events.
    locationManager.distanceFilter = 500;
    [locationManager startUpdatingLocation];
    

    5、启动Significant-Change Location Service:

    [locationManager startMonitoringSignificantLocationChanges];
    

    启动此服务后,即使应用没有被启动也可以接收通知,并且进入到后台状态来处理事件。但是不能让程序的后台任务超过10分钟

    6, 从服务中接收位置数据

    locationManager:didUpdateToLocation:fromLocation
    locationManager:didFailWithError:
    

    7、监视Shape-Based Regions:

    在iOS4.0以后,当用户穿过地理边界时应用可以使用region monitoring来被通知。这个通知即使应用没有被启动也可以接收,并且进入到后台状态来处理事件。(推断:应该和startMonitoringSignificantLocationChanges一样,不能让程序的后台任务超过10分钟)

    8、确定Region Monitoring的可用性

    有几种原因可能导致Region Monitoring可能不可用:
    1)设备可能没有硬件来支持region Monitoring
    2)用户可能禁用了定位服务
    3)设备可能出于飞行模式。
    因此,你需要调用[CLLocationManager regionMonitoringAvailable]和[CLLocationManager regionMonitoringEnabled]来确定其是否可用。

    9、定义一个要监视的Region:

    要监视一个区域,你需要定义个region并且注册其到系统。Regions使用CLRegion类来定义,支持创建一个圆形区域。你创建的Region必须包括地理区域的数据和唯一的标志字符串。要注册一个Region,你需要调用CLLocationManager对象的startMonitoringForRegion:desiredAccuracy:方法。
    例子:

    // 如果不支持RegionMonitoring,就不要创建Region了
    if ( ![CLLocationManager regionMonitoringAvailable] ||
    ![CLLocationManager regionMonitoringEnabled] )
    return NO;
    
    
    // 如果半径太大,注册会自动失败,因此当半径太大时,将其设置为最大值
    CLLocationDegrees radius = overlay.radius;
    if (radius > self.locManager.maximumRegionMonitoringDistance)
    radius = self.locManager.maximumRegionMonitoringDistance;
    
    // 创建一个Region并开始监视它
    CLRegion* region = [[CLRegion alloc] initCircularRegionWithCenter:overlay.coordinate radius:radius identifier:identifier];
    [self.locManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyHundredMeters];
    
    [region release];
    

    在注册之后立即就开始了监视Region,但是不要奢望马上就收到一个事件。只有穿过边界时才会产生事件。因此,如果在注册时,用户的位置已经在区域内,locationManager不会产生事件的。
    你必须明智的使用Regions Monitoring。Regions是一个系统分享资源,并且其数量是有上限的。因此,Core Location限制一个应用同时监听的Regions数量。你应该考虑只监听用户临近位置的Region,当用户的位置变化时,你可以移除远处的Regions并添加近处的Regions来监听。如果你尝试注册一个Region并且没有空间了,LocationManager会调用locationManager:monitoringDidFailForRegion:withError:方法,并传递一个kCLErrorRegionMonitoringFailure错误码。

    10、处理Region的穿过边界事件

    locationManager:didEnterRegion:
    locationManager:didExitRegion:

    11、在后台获得定位事件

    有几种方法:
    1)使用Signicant Location Change服务: [locationManager startMonitoringSignificantLocationChanges];
    2)使用标准的定位服务: 在Info.plist中的UIBackgroundMode键中指定location

    12、保护电池电量的技巧

    1)在你不需要定位的时候关闭定位服务:
    2)使用significant-change 定位服务
    3)使用低精度的desired accuracy
    4)如果是周期性的轮询服务,那在周期中间关闭定位服务

    二、获得方向相关的事件

    Core Location支持两种方法来获得方向相关的信息:
    1)有磁力计(magnetometer)的设备可以报告设备指向的方向,也称为heading。
    2)有GPS的设备可以报告设备移动的方向,也称为course。
    记住,heading和course不表示相同的信息。

    1、如果你的应用需要方向相关的信息才能正确运行,需要在Info.plist中指定UIRequiredDeviceCapabilities键,其值为一个字符串的数组,包括:

    1)magnetometer---对应heading
    2)gps--对应course

    2、获得Heading-Related事件:步骤:

    1)实例化CLLocationManager对象
    2)确定[CLLocationManager headingAvailable]
    3)指定代理
    4)如果你想获得真实的north values,需要启用标准服务
    5)调用startUpdatingHeading开始投递heading事件

    如下例:

    CLLocationManager* locManager = [[[CLLocationManager alloc] init] autorelease];
    locManager.delegate = self;
    
    // Start location services to get the true heading.
    locManager.distanceFilter = 1000;
    locManager.desiredAccuracy = kCLLocationAccuracyKilometer;
    [locManager startUpdatingLocation];
    
    // Start heading updates.
    if ([CLLocationManager headingAvailable]) {
    locManager.headingFilter = 5;
    [locManager startUpdatingHeading];
    }
    

    代理函数:locationManager:didUpdateHeading:方法。
    一旦你收到一个新的事件,你需要检查headingAccuracy属性来确保数据有效。另外,如果你正在使用true heading value,你应该在使用它之前,检查其是否包含一个有效的值。

    (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    if (newHeading.headingAccuracy < 0)
    return;
    
    // Use the true heading if it is valid.
    CLLocationDirection theHeading = ((newHeading.trueHeading > 0) ? newHeading.trueHeading : newHeading.magneticHeading);
    self.currentHeading = theHeading;
    [self updateHeadingDisplays];
    }
    

    3、在用户移动时获得course信息

    拥有GPS硬件的设备可以生成设备的当前course和速度的信息。crouse信息用来指示设备正在移动的方向,并且不需要反应设备自身的方向。因此,主要用来导航。
    实际的course和speed消息在CLLocation对象中返回.
    newLocation.speed
    newLocation.course

    三、地理编码位置数据 Geocoding Location Data:

    1、关于Geocoder对象:

    一个geocoder对象使用网络服务来在(经度、纬度)和地标之间转换,地标为一组数据的集合,例如街道、城市、州和国家信息。Reverse geocoding(逆地理编码)是将(经度、纬度)转换为地标。Forward geocoding(正地理编码)是将位置名称信息转换为(经度、纬度)值。逆地理编码在所有的iOS版本中都可用,但正地理编码仅在iOS5.0以后支持。
    因为地理编码服务需要网络,因此,如果设备出于飞行模式或者设备当前没有网络,地理编码对象不能连接它需要的服务,因此肯定返回一个错误。

    2、转换坐标到Place Name信息:

    在iOS中,你可以使用CLGeocoder类来处理逆地理编码。MKReverseGecoder在iOS5.0以后被弃用。

    3、使用CLGeocoder获得地标信息:

    创建一个CLGeocoder类的实例,并调用
    [gecoder reverseGeocodeLocation:completionHandler:]方法
    例子:

    CLGeocoder *gecoder=[[CLGeocoder alloc]init];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks,NSError *error){
    if ([placemarks count]>0){
    annotation.placemark=[placemark objectAtIndex:0];
    
    }
    }];
    

    4、从Reverse Geocoder中获得地标信息:

    MKReverseGeocoder *theGeocoder=[[MKReverseGeocoder alloc]initWithCoordinate:location.coordinate];
    theGeocoder.delegate=self;
    [theGeocoder start];
    

    代理函数为:
    -(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlaceMark:(MKPlaceMark *)place
    -(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error

    5、转换Place Names为Coordinate

    [geocoder gecodeAddressString:@"1 Infinite Loop" completionHandler:^(NSArray *placeMarks,NSError *error){
    for (CLPlacemark *aPlaceMark in placemarks){
    //CLPlacemark对象包含地理位置信息,当然包括经纬度
    }
    }];
    

    四、显示地图

    Map Kit框架

    1、理解Map Geometry

    一个map view扁平的表现一个球形对象--地球。你需要了解一些关于如何在map view中指定点,并且这些点如何转换为地球表面的坐标。如果你打算防止自定义的内容,如overlays,到地图上,理解地图坐标系统是非常重要的。

    2、地图坐标系统

    地球的三维坐标如何被映射到地图的二维坐标上的?
    Map Kit使用Mercator地图映射。
    你如何指定地图上的数据点取决于你打算如何使用它们。Map Kit支持3中基本的坐标系统来指定地图数据点:
    1)A map coordinate:是地图的球形表示的(经度,纬度)。地图坐标系主要的方法来指定地球上的位置。使用CLLocationCoordinate2D结构。使用MKCoordinateSpan和MKCoordinateRegion结构来指定区域。
    2)A map point:是Mercator地图映射之后的(x,y)点。使用地图点来计算地图相关的计算,而不是map坐标,因为他们简化了计算。在应用中,你主要使用map point来指定shape和自定义的overlay的position。使用MKMapPoint结构。使用MKMapSize和MKMapRect结构来指定区域。
    3)A Point是UIView坐标系中的graphical单元。在绘制view的内容之前,Map Piont和Map Coordinate必须被映射为Point。使用CGPoint,CGSize和CGRect。
    在大多数情况中,你应该使用的坐标系取决于你要使用的Map Kit界面。当你要存储实际的数据到文件中时,map coordinate是首选。
    Core Location也是用map coordinate来指定位置值。

    3、坐标系统间的转换:

    Convert From Convert To Conversion routines
    Map Coordinate Points convertCoordinate:toPointToView:(MKMapView)
    convertRegion:toRectToView:(MKMapView)
    Map Coordinate Map Points MKMapPointForCoordinate
    Map Points Map Coordinates MKCoordinateForMapPoint
    MKCoordinateRegionForMapRect
    Map Points Points PointForMapPoint:(MKOverlayView)
    rectForMapRect:(MKOverlayView)
    Points Map Coordinates convertPoint:toCoordinateFromView:(MKMapView)
    convertRect:toRegionFromView:(MKMapView)
    Points Map Points mapPointForPoint:(MKOverlayView)
    mapRectForRect:(MKOverlayView)

    4、添加一个Map View到用户界面

    MKMapView

    5、配置Map的属性

    1)设置Map的可见部分:region属性,是一个MKCoordinateRegion结构
    typedef struct {
    CLLocationCoordinate2D center;
    MKCoordinateSpan span;
    } MKCoordinateRegion;
    有趣的是span。span类似于一个矩形的宽度和高度值,但是通过map coordinate指定,因此,通过degree(度)、minutes(分)、seconds(秒)来度量。latitude(纬度)的一度大约为111km,但是longitude(经度)的一度不同与纬度。在赤道,经度的一度大约为111km,但是在极点,这个值为0.如果你选择使用米来指定span,你可以使用MKCoordinateRegionMakeWithDistance来创建一个region data 结构,用米而不是用度。
    你指定的region属性的值(或者使用setRegion:animated:方法)通常和实际存储在属性中的值不一样。设置region的span只是定义了你想要查看的矩形,但也隐式设置了map view的缩放级别。map view不能显示任意的缩放级别,并且必须调整你设置的region来匹配它支持的缩放级别。它选择能容纳你的整个region可见,同时又尽可能填满屏幕的缩放级别。相应地,它然后调整region属性。要查找region的结果而不实际更改region的属性,你可以使用map view的regionThatFits:方法。

    2)缩放和Panning 地图内容:
    a)Pan 地图:更改centerCoordinate属性的值 或者 setCenterCoordinate:animated:方法
    b)更改缩放级别:更改region属性的值或setRegion:animated:方法
    如果只是要Pan地图,需要使用第一种方法,如果你更改region属性的center属性,通常会导致缩放级别发生变化。

    CLLocationCoordinate2D mapCenter = myMapView.centerCoordinate;
    mapCenter = [myMapView convertPoint:CGPointMake(1, (myMapView.frame.size.height/2.0)) toCoordinateFromView:myMapView];
    [myMapView setCenterCoordinate:mapCenter animated:YES];
    

    要缩放地图,修改region的span,要zoom in,就设置一个更小的值给span,要zoom out,就设置一个更大的值给span。

    MKCoordinateRegion theRegion = myMapView.region;
    // Zoom out
    theRegion.span.longitudeDelta *= 2.0;
    theRegion.span.latitudeDelta *= 2.0;
    [myMapView setRegion:theRegion animated:YES];
    

    3)在地图上显示用户的当前位置
    设置showsUserLocation属性为YES。这样做导致map view使用Core Location来查找用户的位置并添加一个MKUserLocation类型的annotation到地图上。

    6、响应用户与地图的交互

    MKMapView报告显著的map-related事件给其代理。代理遵循MKMapViewDelegate协议。可以响应如下事件:
    1)更改地图的可见region
    2)从网络上加载map 碎片
    3)更改用户的位置
    4)更改相关的annotation和overlay

    五、Annotating Maps

    1、添加Annotations到地图上:

    要实现这个必须提供两个对象:
    1)遵守MKAnnotation协议的对象(即annotation对象)
    2)一个继承自MKAnnotationView类的视图,用来绘制annoatation的表现(及annotation view)
    Map Kit提供了一些标准的annotation视图,并且你可以定义自己的annotation views。

    2、添加Annotation到地图上的清单:

    1)定义一个合适的annotation对象,使用下面的选项:
    a)使用MKPointAnnotation类来实现一个简单的annotation。
    b)定义一个自定义的遵循MKAnnotation协议的对象
    2)定义一个annotation view来表示屏幕上的数据。
    a)如果annotation可以被一个静态图像代表,那就创建一个MKAnnotationView类的实例,并指定image属性
    b)如果你想使用一个标准的annotation,那就创建一个MKPinAnnotationView类的实例
    c)如果静态图像不合适,那就子类化MKAnnotationView,并实现自定义的draw代码。
    3)实现mapView:viewForAnnotation:方法---在你的mapView代理中。并返回一个annotationView。
    4)使用addAnnotation:或addAnnotations:方法来添加addnotation对象。

    3、定义自定义的Annotation对象

    主要是遵守MKAnnotation协议:
    必须有coordinate只读属性

    4、使用标准的Annotation Views:

    MKAnnotationView 和 MKPinAnnotationView(MKAnnotationView的子类)
    MKAnnotationView适用于只展示一幅图像。通过image属性,还可以指定centerOffset属性来移动中心点。

    5、定义自己的Annotation View

    子类化MKAnnotationView,你可以继续使用image属性,并重载drawRect:方法。

    6、在代理中创建Annotation Views

    -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation{
    }
    

    7、管理地图的Annotation对象:

    可以在mapView:regionWillChangeAnimated:和mapView:regionDidChangeAnimated:方法中添加和移除annotations
    在iOS4.0以后,你可以使用MKMetersBetweenMapPoints方法来获得两个点之间的绝对距离。你还可以使用MKMapRectIntersetsRect函数来查找任何的交集。

    8、标记你的AnnotationView为可拖动:

    1)在你的annotation对象中,实现setCoordinate:方法来允许map view更新annotation的coordinate点。
    2)设置其draggable属性为YES。

    当用户拖动annotation时,委托收到mapView:annotationView:didChangeDragState:fromOldState:方法

    9、在地图上显示OverLay:

    和Annotation类似:
    1)需要实现了MKOverLay协议的对象(即overlay对象)
    2)一个视图(继承自MKOverlayView类)(即overlay视图)

    10、添加overlay到地图的清单:

    1)定义一个overlay对象:
    a)使用MKCircle、MKPolygon、MKPolyline类 等
    b)子类化MKShape或MKMultiPoint来创建自定义的overlay对象。
    c)使用一个已存在的类并遵守MKOverlay协议。
    2)定义一个overlay视图:
    a)对于标准图形,使用MKCircleView、MKPolygonView、MKPolylineView
    b)对于继承自MKShape的自定义形状,定义合适的MKOverlayPathView的子类来渲染形状。
    c)对于其它自定义的形状和overlay,子类化MKOverlayView并实现drawRect:方法
    3)实现代理函数: mapView:viewForOverlay: 并返回MKOverlayView
    4)使用addOverlay:方法添加overlay

    11、使用标准的Overlay对象和视图:

    MKCircle、MKPolygon、MKPolyline为overlay对象。
    MKCircleView、MKPolygonView、MKPolylineVIew为overlay视图。

    12、定义自定义的Overlay对象:

    子类化MKShape或MKMultiPoint或者采用MKOverlay协议。
    1)必须有coordinate可读属性
    2)一个bounding rectangle,完全包含了overlay的内容。

    13、定义自定义的Overlay视图:

    子类化MKOverlayView,并重载
    drawMapRect:zoomScale:inContext:
    canDrawMapRect:zoomScale:

    14、从代理中创建Overlay视图

    mapView:viewForOverlay:方法

    15、管理地图的Overlay对象:

    overlays属性
    代理函数mapView:didAddOverlayViews:方法,然后使用MKMapRectIntersectsRect函数来看看已经添加的overlay与其它的overlay是否有交集。

    16、使用overlay当作annotations

    MKOverlay协议遵循MKAnnotation协议。因此,所有的overlay对象都可以当作annotation对象来使用。

    相关文章

      网友评论

        本文标题:IOS ArcGIS 调用 定位服务和地理围栏

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