实现物流场景中小车Marker指向目的地
以下内容转载自面糊的文章《实现物流场景的小车Marker指向目的地》
作者:面糊
链接:https://www.jianshu.com/p/f794b02a81f5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
场景需求
快递物流相关APP中,如快递、送餐,可以让快递车Marker的车头,在途经点始终指向目的地,如下图所示:
使用技术:腾讯地图iOS SDK,点标记和绘制线
核心点:
1、操作QPointAnnotation的坐标
2、从mapView中获取途经点QPointAnnotation的坐标
3、通过三角函数计算途经点坐标与终点坐标的角度
4、操作QAnnotationView的transform属性
代码示例如下:
1、示例展示福州送至北京,途径西安、西宁、济南、太原、天津,先将这几个点的maker添加到地图中:
// 福州
locations[0] = CLLocationCoordinate2DMake(26.101797,119.415539);
// 西安
locations[1] = CLLocationCoordinate2DMake(34.475422,109.0005);
// 西宁
locations[2] = CLLocationCoordinate2DMake(36.69099,101.749523);
// 济南
locations[3] = CLLocationCoordinate2DMake(36.761434,117.174328);
// 太原
locations[4] = CLLocationCoordinate2DMake(37.949064,112.56007);
// 天津
locations[5] = CLLocationCoordinate2DMake(39.117802,117.174328);
// 北京
locations[6] = CLLocationCoordinate2DMake(39.897614,116.383312);
// 福州
QPointAnnotation *nnAnnotation = [[QPointAnnotation alloc] init];
nnAnnotation.coordinate = locations[0];
[self.mapView addAnnotation:nnAnnotation];
....
2、添加小车marker,以福州为起始点:
_carAnnotation = [[QPointAnnotation alloc] init];
_carAnnotation.coordinate = locations[0];
// 指定userData自定义数据,用于判断marker的类型
_carAnnotation.userData = @"car";
[self.mapView addAnnotation:_carAnnotation];
3、实现mapView代理方法,根据userData来区分不同的Marker
- (QAnnotationView *)mapView:(QMapView *)mapView viewForAnnotation:(id<QAnnotation>)annotation {
static NSString *reuse = @"annotation";
static NSString *reuseCar = @"annotationCar";
QPinAnnotationView *annotationView = (QPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuse];
if (annotationView == nil) {
if (annotation == _carAnnotation) {
annotationView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseCar];
annotationView.image = [UIImage imageNamed:@"car"];
// 将小车的AnnotationView保存为属性,用于操作转向
_carAnnotationView = annotationView;
} else {
annotationView = [[QPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuse];
}
}
return annotationView;
}
4、根据三角函数,计算起点和终点的角度,并调整小车Marker的角度
- (void)annotationRotate {
// 取出终点坐标位置
CLLocationCoordinate2D toCoord = _bjAnnotation.coordinate;
double fromLat = _carAnnotation.coordinate.latitude;
double fromlon = _carAnnotation.coordinate.longitude;
double toLat = toCoord.latitude;
double tolon = toCoord.longitude;
double slope = ((toLat - fromLat) / (tolon - fromlon));
double radio = atan(slope);
double angle = 180 * (radio / M_PI);
if (slope > 0) {
if (tolon < fromlon) {
angle = -90 - angle;
} else {
angle = 90 - angle;
}
} else if (slope == 0) {
if (tolon < fromlon) {
angle = -90;
} else {
angle = 90;
}
} else {
if (toLat < fromLat) {
angle = 90 - angle;
} else {
angle = -90 - angle;
}
}
// 这里要注意,计算出来的是角度,而旋转则需要先转换为弧度
_carAnnotationView.transform = CGAffineTransformMakeRotation((M_PI * (angle) / 180.0));
}
在这个基础上,我在navigationItem中添加了一个切换当前途径点的功能,每次点击按钮就会将小车移动到下一个途经点,示例代码如下:
- (void)handleTestAction {
_index++;
if (_index == self.mapView.annotations.count - 2) {
_index = 0;
}
QPointAnnotation *annotation = self.mapView.annotations[_index];
_carAnnotation.coordinate = annotation.coordinate;
[self annotationRotate];
}
效果示例如下图所示: