目标注释在可见区域外的方向 [英] Direction of target annotation when outside of visible area

查看:161
本文介绍了目标注释在可见区域外的方向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在屏幕的各个方面显示方向图像。例如。如果目标的位置是用户位置的右侧并且位于可见地图区域之外,那么我想添加一个方向图像,如下图所示(绿色注释是用户的位置,红色是目标的方向,这是超出屏幕的界限):



这样做的标准方法是什么?

解决方案

最简单的方法是放置在每个基点的地图上方有四个指针视图。然后,随着用户移动地图(使用 mapView:regionDidChangeAnimated:委托方法)确定应显示哪个指针。隐藏所有其他的;然后显示正确的一个。另外,对指针应用一个转换,这样方位角就像你所做的一样。



以上是配置了故事板的屏幕截图:


以下是一个示例实现( ):

  // 
// MapViewController.m
/ / AnimationTest
//
//由Scott Atkinson在4/17/15创建。
//

#importMapViewController.h

@import MapKit;
$ b $ typedef NS_ENUM(NSInteger,CardinalPoint){
North,
South,
East,
West
};

@interface MapViewController()< MKMapViewDelegate>

@property(弱,非原子)IBOutlet MKMapView * mapView;

//在地图上显示基数点的视图(每次只显示一个)
@property(弱,非原子)IBOutlet UIView * northPointerView;
@property(弱,非原子)IBOutlet UIView * eastPointerView;
@property(弱,非原子)IBOutlet UIView * westPointerView;
@property(弱,非原子)IBOutlet UIView * southPointerView;

//在地图上显示的位置
@property(强,非原子)CLLocation * targetLocation;

@end

@implementation MapViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self hidePointerViews];

//将位置添加到地图
self.targetLocation = [[CLLocation alloc] initWithLatitude:37.331898 longitude:-122.029824];
MKPlacemark * placemark = [[MKPlacemark alloc] initWithCoordinate:self.targetLocation.coordinate addressDictionary:nil];
[self.mapView addAnnotation:placemark];
}


// ******************** MKMapViewDelegate ********** **********
#pragma mark - MKMapViewDelegate

//当地图移动时,更新基数指针视图
- (void)mapView :( MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
if([self isCurrentLocationVisible]&&![self isTargetLocationVisible]){
//用户位置可见,但目标不是,所以显示一个指针
double bearing = [self bearingToLocation:self.targetLocation fromLocation:self.mapView.userLocation.location];
[self showCardinalPointDirection:bearing];

} else {
//隐藏指针
[self hidePointerViews];
}
}


// ********************坐标助手**** ****************
#pragma mark - 坐标助手

- (BOOL)isCurrentLocationVisible {
返回MKMapRectContainsPoint(self.mapView .visibleMapRect,
MKMapPointForCoordinate(self.mapView.userLocation.coordinate));

$ b - (BOOL)isTargetLocationVisible {
return MKMapRectContainsPoint(self.mapView.visibleMapRect,
MKMapPointForCoordinate(self.targetLocation.coordinate));
}

//来自:http://stackoverflow.com/questions/3925942/cllocation-category-for-calculating-bearing-w-haversine-function
双DegreesToRadians (双度){返回度* M_PI / 180.0;};
double RadiansToDegrees(双弧度){返回弧度* 180.0 / M_PI;};

///计算两点之间的方位
- (double)bearingToLocation:(CLLocation *)destinationLocation fromLocation:(CLLocation *)fromLocation {

double lat1 = DegreesToRadians(fromLocation.coordinate.latitude);
double lon1 = DegreesToRadians(fromLocation.coordinate.longitude);

double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);

double dLon = lon2 - lon1;

double y = sin(dLon)* cos(lat2);
double x = cos(lat1)* sin(lat2) - sin(lat1)* cos(lat2)* cos(dLon);
double radiansBearing = atan2(y,x);

if(radiansBearing <0.0)
radiansBearing + = 2 * M_PI;

返回RadiansToDegrees(radiansBearing);
}

// ********************指针视图************* *******
#pragma mark - 指针视图

- (void)hidePointerViews {
self.northPointerView.hidden =
self.southPointerView.hidden =
self.eastPointerView.hidden =
self.westPointerView.hidden = YES;


- (void)showCardinalPointDirection:(double)bearing {
CardinalPoint point = [self cardinalPointWithBearing:bearing];

//确定根据方位显示哪个指针
UIView * activePointer;
switch(point){
case North:
activePointer = self.northPointerView;
休息;
case South:
activePointer = self.southPointerView;
休息;
案例东:
activePointer = self.eastPointerView;
休息;
case West:
activePointer = self.westPointerView;
休息;
}

//旋转指针以显示方位
activePointer.transform = CGAffineTransformMakeRotation(DegreesToRadians(bearing));

//隐藏除相关元素之外的所有指针
[self hidePointerViews];
activePointer.hidden = NO;
}

///返回给定轴承的基数点(以度为单位)
- (CardinalPoint)cardinalPointWithBearing :(双)轴承{
如果> 45.0&& bearing< = 135.0){
return East;
} else if(bearing> 135.0&& bearing< = 225.0){
return South;
} else if(bearing> 225.0&& bearing< = 315.0){
return West;
} else {
return North;
}
}
@end

另外,指针的旋转基于 userLocation targetLocation 之间的方位。这感觉有点奇怪。可能更好地根据其他点进行轮换。也许当时可见区域的中心......

I would like to show the direction images on all sides of the screen. E.g. if the target's location is the right side of user's location and is outside of the visible map area, then I want to add a direction image as shown on the picture below (The Green annotation is user's location, red one is the direction for the target, which is out of bounds of the screen):

What is the standard approach to do this?

解决方案

The simplest way is to place four "pointer" views above the map at each of the cardinal points. Then, as the user moves the map (using mapView:regionDidChangeAnimated: delegate method) determine which pointer should be shown. Hide all the other ones; and then show the correct one. Also, apply a transformation to the pointer so that the bearing angle is represented as you have done.

Here is a screenshot of a storyboard with the above configuration:

And here is a sample implementation (Code is not optimal, of course.):

//
//  MapViewController.m
//  AnimationTest
//
//  Created by Scott Atkinson on 4/17/15.
//

#import "MapViewController.h"

@import MapKit;

typedef NS_ENUM(NSInteger, CardinalPoint) {
    North,
    South,
    East,
    West
};

@interface MapViewController () <MKMapViewDelegate>

@property (weak, nonatomic) IBOutlet MKMapView *mapView;

// Views that show cardinal points on the map (Only one should be shown at a time)
@property (weak, nonatomic) IBOutlet UIView *northPointerView;
@property (weak, nonatomic) IBOutlet UIView *eastPointerView;
@property (weak, nonatomic) IBOutlet UIView *westPointerView;
@property (weak, nonatomic) IBOutlet UIView *southPointerView;

// Location to show on the map
@property (strong, nonatomic) CLLocation * targetLocation;

@end

@implementation MapViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self hidePointerViews];

    // Add the location to the map
    self.targetLocation = [[CLLocation alloc] initWithLatitude:37.331898 longitude:-122.029824];
    MKPlacemark * placemark = [[MKPlacemark alloc] initWithCoordinate:self.targetLocation.coordinate addressDictionary:nil];
    [self.mapView addAnnotation:placemark];
}


// ******************** MKMapViewDelegate ********************
#pragma mark - MKMapViewDelegate

// As the map moves, update the cardinal pointer views
- (void) mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
    if([self isCurrentLocationVisible] && ![self isTargetLocationVisible]) {
        // The user location is visible, but the target is not, so show a pointer
        double bearing = [self bearingToLocation:self.targetLocation fromLocation:self.mapView.userLocation.location];
        [self showCardinalPointDirection:bearing];

    } else {
        // Hide the pointers
        [self hidePointerViews];
    }
}


// ******************** Coordinate Helpers ********************
#pragma mark - Coordinate Helpers

- (BOOL) isCurrentLocationVisible {
    return MKMapRectContainsPoint(self.mapView.visibleMapRect,
                                  MKMapPointForCoordinate(self.mapView.userLocation.coordinate));
}

- (BOOL) isTargetLocationVisible {
    return MKMapRectContainsPoint(self.mapView.visibleMapRect,
                                  MKMapPointForCoordinate(self.targetLocation.coordinate));
}

// From: http://stackoverflow.com/questions/3925942/cllocation-category-for-calculating-bearing-w-haversine-function
double DegreesToRadians(double degrees) {return degrees * M_PI / 180.0;};
double RadiansToDegrees(double radians) {return radians * 180.0/M_PI;};

/// Calculate the bearing between two points
-(double) bearingToLocation:(CLLocation *) destinationLocation fromLocation:(CLLocation *) fromLocation {

    double lat1 = DegreesToRadians(fromLocation.coordinate.latitude);
    double lon1 = DegreesToRadians(fromLocation.coordinate.longitude);

    double lat2 = DegreesToRadians(destinationLocation.coordinate.latitude);
    double lon2 = DegreesToRadians(destinationLocation.coordinate.longitude);

    double dLon = lon2 - lon1;

    double y = sin(dLon) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
    double radiansBearing = atan2(y, x);

    if(radiansBearing < 0.0)
        radiansBearing += 2*M_PI;

    return RadiansToDegrees(radiansBearing);
}

// ******************** Pointer View ********************
#pragma mark - Pointer View

- (void) hidePointerViews {
    self.northPointerView.hidden =
    self.southPointerView.hidden =
    self.eastPointerView.hidden =
    self.westPointerView.hidden = YES;
}

- (void) showCardinalPointDirection:(double) bearing {
    CardinalPoint point = [self cardinalPointWithBearing:bearing];

    // Determine which pointer should be shown based on the bearing
    UIView * activePointer;
    switch (point) {
        case North:
            activePointer = self.northPointerView;
            break;
        case South:
            activePointer = self.southPointerView;
            break;
        case East:
            activePointer = self.eastPointerView;
            break;
        case West:
            activePointer = self.westPointerView;
            break;
    }

    // Rotate the pointer to show the bearing
    activePointer.transform = CGAffineTransformMakeRotation(DegreesToRadians(bearing));

    // Hide all pointers except the pertinent one
    [self hidePointerViews];
    activePointer.hidden = NO;
}

/// Returns the cardinal point for a given bearing (in Degrees)
- (CardinalPoint) cardinalPointWithBearing:(double) bearing {
    if (bearing > 45.0 && bearing <= 135.0) {
        return East;
    } else if (bearing > 135.0 && bearing <= 225.0) {
        return South;
    } else if (bearing > 225.0 && bearing <= 315.0) {
        return West;
    } else {
        return North;
    }
}
@end

Additionally, the pointer rotation is based on the bearing between the userLocation and the targetLocation. It feels a little strange. Probably better to make the rotation based off of some other point. Maybe the center of the visible region at that moment...

这篇关于目标注释在可见区域外的方向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆