下图所示是最终实现效果:
技术点分析
在地图上根据一串经纬度坐标点画红色轨迹线和添加白色箭头百度地图和谷歌地图都已经有对应API实现,只要有正确的数据就可以。难点在于要正确标识出Annotation白色箭头的方向,需要一个小小的算法,关键代码如下。
实现代码
#pragma mark - 百度地图绘制轨迹
/**
* @description 百度地图绘制轨迹
*/
-(void)configureRoutes
{
//地图clear方法
NSArray *annotationsArray = [NSArray arrayWithArray:_mapView.annotations];
[_mapView removeAnnotations:annotationsArray];
NSArray *overlaysArray = [NSArray arrayWithArray:_mapView.overlays];
[_mapView removeOverlays:overlaysArray];
//去除数组中不合理的点
[self removeUnreasonablePoint];
// 1、分配内存空间给存储经过点的数组
CLLocationCoordinate2D* pointArray = (CLLocationCoordinate2D *)malloc(sizeof(CLLocationCoordinate2D) * self.markersArray.count);
[self.mapAnnotationArray removeAllObjects];
_mapView.delegate = self;
// 2、创建坐标点并添加到数组中 && 添加自定义图标
for(int idx = 0; idx < self.markersArray.count; idx++)
{
//创建坐标点并添加到数组中
DCModel24Location *location = self.markersArray[idx];
double longtitude = [location.lon doubleValue];// 经度
double latitude = [location.lat doubleValue];// 纬度
// NSLog(@"longtitude %f latitude %f",longtitude,latitude);
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longtitude);
NSDictionary* BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_COMMON);
//转换GPS坐标至百度坐标
BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_GPS);
// NSLog(@"x=%@,y=%@",[BMKChangedLocationDic objectForKey:@"x"],[BMKChangedLocationDic objectForKey:@"y"]);
//将x,y转换为经纬度
CLLocationCoordinate2D baiduCoor = BMKCoorDictionaryDecode(BMKChangedLocationDic);
NSLog(@"latitude111 %f longitude111 %f",baiduCoor.latitude,baiduCoor.longitude);
// BMKMapPoint point = BMKMapPointForCoordinate(baiduCoor);
pointArray[idx] = baiduCoor;
NSLog(@"pointArraylatitude %f pointArraylongitude%f",pointArray[idx].latitude,pointArray[idx].longitude);
//添加起点和终点图标 如果只有一个点 只显示end
if (0 == idx)
if (self.startAnnotation)
{
[self.mapView removeAnnotation:self.startAnnotation];
}
self.startAnnotation = [[TrailBMKPointAnnotation alloc] init];
self.startAnnotation.coordinate = baiduCoor;
self.startAnnotation.title = @" ";
if (self.markersArray.count <= 1)
{
self.startAnnotation.isStartAnnotation = NO;
}
else
{
self.startAnnotation.isStartAnnotation = YES;
}
[_mapView addAnnotation:self.startAnnotation];
[self.startAndEndAnnotationArray addObject:self.startAnnotation];
self.mapView.centerCoordinate = baiduCoor;
}
else if (self.markersArray.count - 1 == idx)
{
if (self.endAnnotation)
{
[self.mapView removeAnnotation:self.endAnnotation];
}
self.endAnnotation = [[TrailBMKPointAnnotation alloc] init];
self.endAnnotation.coordinate = baiduCoor;
self.endAnnotation.title = @" ";
self.endAnnotation.isStartAnnotation = NO;
[_mapView addAnnotation:self.endAnnotation];
[self.startAndEndAnnotationArray addObject:self.endAnnotation];
}
}
for(int idx = 0; idx < self.markersArray.count; idx++)
{
//创建坐标点并添加到数组中
DCModel24Location *location1 = self.markersArray[idx];
double longtitude1 = [location1.lon doubleValue];// 经度
double latitude1 = [location1.lat doubleValue];// 纬度
// NSLog(@"longtitude %f latitude %f",longtitude,latitude);
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude1, longtitude1);
NSDictionary* BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_COMMON);
//转换GPS坐标至百度坐标
BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_GPS);
// NSLog(@"x=%@,y=%@",[BMKChangedLocationDic objectForKey:@"x"],[BMKChangedLocationDic objectForKey:@"y"]);
//将x,y转换为经纬度
CLLocationCoordinate2D baiduCoor = BMKCoorDictionaryDecode(BMKChangedLocationDic);
//生成annotation
HistoryTrackAnnotation* mapAnnotation = [[HistoryTrackAnnotation alloc] init];
mapAnnotation.coordinate = baiduCoor;
mapAnnotation.title=@" ";
mapAnnotation.annotationTag = idx;
mapAnnotation.firstLon = baiduCoor.longitude;
mapAnnotation.firstLat = baiduCoor.latitude;
if (idx + 1 < self.markersArray.count)
{
DCModel24Location *location2 = self.markersArray[idx + 1];
double longtitude2 = [location2.lon doubleValue];// 经度
double latitude2 = [location2.lat doubleValue];// 纬度
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude2, longtitude2);
NSDictionary* BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_COMMON);
//转换GPS坐标至百度坐标
BMKChangedLocationDic = BMKConvertBaiduCoorFrom(coordinate,BMK_COORDTYPE_GPS);
// NSLog(@"x=%@,y=%@",[BMKChangedLocationDic objectForKey:@"x"],[BMKChangedLocationDic objectForKey:@"y"]);
//将x,y转换为经纬度
CLLocationCoordinate2D baiduCoor = BMKCoorDictionaryDecode(BMKChangedLocationDic);
mapAnnotation.secondLon = baiduCoor.longitude;
mapAnnotation.secondLat = baiduCoor.latitude;
}
pointArray[idx] = baiduCoor;
[self.mapAnnotationArray addObject:mapAnnotation];
}
//添加annotation
[self.mapView addAnnotations:self.mapAnnotationArray];
if (routeLine) {
//在地图上移除已有的坐标点
[self.mapView removeOverlay:routeLine];
}
// routeLine = [BMKPolyline polylineWithPoints:pointArray count:self.markersArray.count];
routeLine = [BMKPolyline polylineWithCoordinates:pointArray count:self.markersArray.count];
if (nil != routeLine) {
[self.mapView addOverlay:routeLine];
}
free(pointArray);
}
/**
* @description 移除不合理的点 前后两个点距离小于10m抛弃后点
*/
-(void) removeUnreasonablePoint
{
if (self.markersArray.count > 0)
{
NSMutableArray *tempArray = [NSMutableArray array];
for(int idx = 0; idx < self.markersArray.count; idx++)
{
DCModel24Location *location = self.markersArray[idx];
BOOL isRemove = NO;
//前后两个点距离小于10m抛弃后点
if (idx + 1 < self.markersArray.count)
{
DCModel24Location *locationNext = self.markersArray[idx + 1];
//计算两个点的距离
CLLocationCoordinate2D baiduDoorPre = [Tools getBaidudoorFromGpsLat:location.lat gpsLon:location.lon];
CLLocationCoordinate2D baiduDoorNext = [Tools getBaidudoorFromGpsLat:locationNext.lat gpsLon:locationNext.lon];
//pre坐标
BMKMapPoint petPointPre = BMKMapPointForCoordinate(baiduDoorPre);
//next坐标
BMKMapPoint petPointNext = BMKMapPointForCoordinate(baiduDoorNext);
CLLocationDistance getDistance = BMKMetersBetweenMapPoints(petPointPre, petPointNext);
isRemove = getDistance < 10 ? YES : NO;
}
NSLog(@"绘制isRemove %d",isRemove);
if ([location.operation isEqualToString:@"discard"] || isRemove)
{
[tempArray addObject:location];
}
}
WS(ws);
[tempArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[ws.markersArray removeObject:obj];
}];
}
}
/**
* @description 地图两点角度计算
@param x1 点1Lat
@param y1 点1Lon
@param x2 点2Lat
@param y2 点2Lon
@return 角度值
*/
-(double) getCircularWithFirstPointLat:(double) x1 FirstPointLon:(double) y1 SecondPointLat:(double) x2 SecondPointLon:(double) y2
{
double dRotateAngle = atan2(fabs(x1 - x2), fabs(y1 - y2));
if (x2 >= x1)
{
if (y2 >= y1)
{
}
else
{
dRotateAngle = M_PI - dRotateAngle;
}
}
else
{
if (y2 >= y1)
{
dRotateAngle = 2 * M_PI - dRotateAngle;
}
else
{
dRotateAngle = M_PI + dRotateAngle;
}
}
dRotateAngle = dRotateAngle * 180.00 / M_PI - 90;
return -dRotateAngle;
}
#pragma mark - mapView的协议
/**
* @description 自定义初始化大头针 根据anntation生成对应的View
@param mapView mapView
@param annotation 大头针
@return 自定义的view
UIView * leftCalloutAccessoryView
显示在气泡左侧的view 的width超出一定范围后无效。
UIView * rightCalloutAccessoryView
显示在气泡右侧的view 的width超出一定范围后无效。
*/
- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id <BMKAnnotation>)annotation
{
if ([annotation isKindOfClass:[HistoryTrackAnnotation class]])
{
NSString *identifier = @"trackAnnotation";
//
// HistoryTrackAnnotationView *trackAnnotationView =(HistoryTrackAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
//
// if (trackAnnotationView == nil)
// {
HistoryTrackAnnotationView *trackAnnotationView = [[HistoryTrackAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
// }
HistoryTrackAnnotation *animatedAnnotation = (HistoryTrackAnnotation *) annotation;
trackAnnotationView.canShowCallout = NO;
//除去起点和终点
if (animatedAnnotation.annotationTag != 0 && animatedAnnotation.annotationTag != self.mapAnnotationArray.count - 1)
{
//计算箭头方向
trackAnnotationView.backgroundColor = CLEAR_COLOR;
// //地图两点角度计算
NSLog(@"animatedAnnotationanimatedAnnotation %f %f %f %f",animatedAnnotation.firstLat,animatedAnnotation.firstLon,animatedAnnotation.secondLat,animatedAnnotation.secondLon);
double getCircleNum = [self getCircularWithFirstPointLat:animatedAnnotation.firstLat FirstPointLon:animatedAnnotation.firstLon SecondPointLat:animatedAnnotation.secondLat SecondPointLon:animatedAnnotation.secondLon];
trackAnnotationView.size = CGSizeMake(15, 15);
//设置锚点
trackAnnotationView.pointImageView.layer.anchorPoint = CGPointMake(0.5, 1);
trackAnnotationView.pointImageView.transform = CGAffineTransformRotate(trackAnnotationView.pointImageView.transform, getCircleNum * M_PI / 180);
}
return trackAnnotationView;
}
else if ([annotation isKindOfClass:[TrailBMKPointAnnotation class]])
{
//动画annotation
NSString *AnnotationViewID = @"AnimatedAnnotation";
MyAnimatedAnnotationView *annotationView = nil;
if (annotationView == nil) {
annotationView = [[MyAnimatedAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];
}
annotationView.enabled = NO;
TrailBMKPointAnnotation *getAnnotation = (TrailBMKPointAnnotation *)annotation;
if (getAnnotation.isStartAnnotation)
{
annotationView.image = [UIImage imageNamed:@"track_start"];
}
else
{
annotationView.image = [UIImage imageNamed:@"track_end"];
}
annotationView.size = CGSizeMake(23, 30);
return annotationView;
}
return nil;
}