iOS 在地图上绘制出你运动的轨迹

iOS中的MapKit集成了google地图api的很多功能加上iOS的定位的功能,我们就可以实现将你运行的轨迹绘制到地图上面。这个功能非常有用,比如快递追踪、汽车的gprs追踪、人员追踪等等。这篇文章我们将使用Map Kit和iOS的定位功能,将你的运行轨迹绘制在地图上面。

实现

   在之前的一篇文章描述了如何在地图上显示自己的位置,如果我们将这些位置先保存起来,然后串联起来绘制到地图上面,那就是我们的运行轨迹了。

    首先我们看下如何在地图上绘制曲线。在Map Kit中提供了一个叫MKPolyline的类,我们可以利用它来绘制曲线,先看个简单的例子。

    使用下面代码从一个文件中读取出经纬度,然后创建一个路径:MKPolyline实例。

[plain]  view plain copy
  1. -(void) loadRoute 
  2. NSString* filePath = [[NSBundle mainBundle] pathForResource:@”route” ofType:@”csv”]; 
  3. NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; 
  4. NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 
  5.  
  6. // while we create the route points, we will also be calculating the bounding box of our route 
  7. // so we can easily zoom in on it. 
  8. MKMapPoint northEastPoint; 
  9. MKMapPoint southWestPoint;  
  10.  
  11. // create a c array of points. 
  12. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * pointStrings.count); 
  13.  
  14. for(int idx = 0; idx < pointStrings.count; idx++) 
  15. // break the string down even further to latitude and longitude fields. 
  16. NSString* currentPointString = [pointStrings objectAtIndex:idx]; 
  17. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 
  18.  
  19. CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue]; 
  20. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue]; 
  21.  
  22. // create our coordinate and add it to the correct spot in the array 
  23. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude); 
  24.  
  25. MKMapPoint point = MKMapPointForCoordinate(coordinate); 
  26.  
  27. // 
  28. // adjust the bounding box 
  29. // 
  30.  
  31. // if it is the first point, just use them, since we have nothing to compare to yet. 
  32. if (idx == 0) { 
  33. northEastPoint = point; 
  34. southWestPoint = point; 
  35. else 
  36. if (point.x > northEastPoint.x) 
  37. northEastPoint.x = point.x; 
  38. if(point.y > northEastPoint.y) 
  39. northEastPoint.y = point.y; 
  40. if (point.x < southWestPoint.x) 
  41. southWestPoint.x = point.x; 
  42. if (point.y < southWestPoint.y) 
  43. southWestPoint.y = point.y; 
  44.  
  45. pointArr[idx] = point; 
  46.  
  47.  
  48. // create the polyline based on the array of points. 
  49. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:pointStrings.count]; 
  50.  
  51. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);
  52.  
  53. // clear the memory allocated earlier for the points 
  54. free(pointArr); 
  55.  
  56. }  
[plain]  view plain copy
  1. -(void) loadRoute  
  2. {  
  3. NSString* filePath = [[NSBundle mainBundle] pathForResource:@”route” ofType:@”csv”];  
  4. NSString* fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];  
  5. NSArray* pointStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
  6.   
  7. // while we create the route points, we will also be calculating the bounding box of our route  
  8. // so we can easily zoom in on it.  
  9. MKMapPoint northEastPoint;  
  10. MKMapPoint southWestPoint;   
  11.   
  12. // create a c array of points.  
  13. MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * pointStrings.count);  
  14.   
  15. for(int idx = 0; idx < pointStrings.count; idx++)  
  16. {  
  17. // break the string down even further to latitude and longitude fields.  
  18. NSString* currentPointString = [pointStrings objectAtIndex:idx];  
  19. NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];  
  20.   
  21. CLLocationDegrees latitude = [[latLonArr objectAtIndex:0] doubleValue];  
  22. CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];  
  23.   
  24. // create our coordinate and add it to the correct spot in the array  
  25. CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);  
  26.   
  27. MKMapPoint point = MKMapPointForCoordinate(coordinate);  
  28.   
  29. //  
  30. // adjust the bounding box  
  31. //  
  32.   
  33. // if it is the first point, just use them, since we have nothing to compare to yet.  
  34. if (idx == 0) {  
  35. northEastPoint = point;  
  36. southWestPoint = point;  
  37. }  
  38. else  
  39. {  
  40. if (point.x > northEastPoint.x)  
  41. northEastPoint.x = point.x;  
  42. if(point.y > northEastPoint.y)  
  43. northEastPoint.y = point.y;  
  44. if (point.x < southWestPoint.x)  
  45. southWestPoint.x = point.x;  
  46. if (point.y < southWestPoint.y)  
  47. southWestPoint.y = point.y;  
  48. }  
  49.   
  50. pointArr[idx] = point;  
  51.   
  52. }  
  53.   
  54. // create the polyline based on the array of points.  
  55. self.routeLine = [MKPolyline polylineWithPoints:pointArr count:pointStrings.count];  
  56.   
  57. _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);  
  58.   
  59. // clear the memory allocated earlier for the points  
  60. free(pointArr);  
  61.   
  62. }   


将这个路径添加到地图上

[plain]  view plain copy
  1. [self.mapView addOverlay:self.routeLine];  
[plain]  view plain copy
  1. [self.mapView addOverlay:self.routeLine];   


显示在地图上:

[plain]  view plain copy
  1. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay 
  2. MKOverlayView* overlayView = nil; 
  3.  
  4. if(overlay == self.routeLine) 
  5. //if we have not yet created an overlay view for this overlay, create it now. 
  6. if(nil == self.routeLineView) 
  7. self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease]; 
  8. self.routeLineView.fillColor = [UIColor redColor]; 
  9. self.routeLineView.strokeColor = [UIColor redColor]; 
  10. self.routeLineView.lineWidth = 3; 
  11.  
  12. overlayView = self.routeLineView; 
  13.  
  14.  
  15. return overlayView; 
  16.  
  17. }  
[plain]  view plain copy
  1. - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id )overlay  
  2. {  
  3. MKOverlayView* overlayView = nil;  
  4.   
  5. if(overlay == self.routeLine)  
  6. {  
  7. //if we have not yet created an overlay view for this overlay, create it now.  
  8. if(nil == self.routeLineView)  
  9. {  
  10. self.routeLineView = [[[MKPolylineView alloc] initWithPolyline:self.routeLine] autorelease];  
  11. self.routeLineView.fillColor = [UIColor redColor];  
  12. self.routeLineView.strokeColor = [UIColor redColor];  
  13. self.routeLineView.lineWidth = 3;  
  14. }  
  15.   
  16. overlayView = self.routeLineView;  
  17.   
  18. }  
  19.   
  20. return overlayView;  
  21.   
  22. }   

效果:
iOS 在地图上绘制出你运动的轨迹_第1张图片

然后我们在从文件中读取位置的方法改成从用gprs等方法获取当前位置。

第一步:创建一个CLLocationManager实例
第二步:设置CLLocationManager实例委托和精度
第三步:设置距离筛选器distanceFilter
第四步:启动请求
代码如下:
[plain]  view plain copy
  1. - (void)viewDidLoad { 
  2.     [super viewDidLoad]; 
  3.      
  4.     noUpdates = 0; 
  5.     locations = [[NSMutableArray alloc] init]; 
  6.      
  7.     locationMgr = [[CLLocationManager alloc] init]; 
  8.     locationMgr.delegate = self; 
  9.     locationMgr.desiredAccuracy =kCLLocationAccuracyBest; 
  10.     locationMgr.distanceFilter  = 1.0f; 
  11.     [locationMgr startUpdatingLocation]; 
  12.      
  13.      
[plain]  view plain copy
  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.       
  4.     noUpdates = 0;  
  5.     locations = [[NSMutableArray alloc] init];  
  6.       
  7.     locationMgr = [[CLLocationManager alloc] init];  
  8.     locationMgr.delegate = self;  
  9.     locationMgr.desiredAccuracy =kCLLocationAccuracyBest;  
  10.     locationMgr.distanceFilter  = 1.0f;  
  11.     [locationMgr startUpdatingLocation];  
  12.       
  13.       
  14. }  


上面的代码我定义了一个数组,用于保存运行轨迹的经纬度。

每次通知更新当前位置的时候,我们将当前位置的经纬度放到这个数组中,并重新绘制路径,代码如下:

[plain]  view plain copy
  1. - (void)locationManager:(CLLocationManager *)manager  
  2.     didUpdateToLocation:(CLLocation *)newLocation  
  3.            fromLocation:(CLLocation *)oldLocation{ 
  4.        noUpdates++; 
  5.   
  6.        [locations addObject: [NSString stringWithFormat:@"%f,%f",[newLocation coordinate].latitude, [newLocation coordinate].longitude]]; 
  7.   
  8.        [self updateLocation]; 
  9.         if (self.routeLine!=nil) { 
  10.           self.routeLine =nil; 
  11.         } 
  12.     if(self.routeLine!=nil) 
  13.           [self.mapView removeOverlay:self.routeLine]; 
  14.         self.routeLine =nil; 
  15.     // create the overlay 
  16.     [self loadRoute]; 
  17.      
  18.     // add the overlay to the map 
  19.     if (nil != self.routeLine) { 
  20.         [self.mapView addOverlay:self.routeLine]; 
  21.     } 
  22.      
  23.     // zoom in on the route.  
  24.     [self zoomInOnRoute]; 
  25.           
[plain]  view plain copy
  1. - (void)locationManager:(CLLocationManager *)manager   
  2.     didUpdateToLocation:(CLLocation *)newLocation   
  3.            fromLocation:(CLLocation *)oldLocation{  
  4.        noUpdates++;  
  5.    
  6.        [locations addObject: [NSString stringWithFormat:@"%f,%f",[newLocation coordinate].latitude, [newLocation coordinate].longitude]];  
  7.    
  8.        [self updateLocation];  
  9.         if (self.routeLine!=nil) {  
  10.           self.routeLine =nil;  
  11.         }  
  12.     if(self.routeLine!=nil)  
  13.           [self.mapView removeOverlay:self.routeLine];  
  14.         self.routeLine =nil;  
  15.     // create the overlay  
  16.     [self loadRoute];  
  17.       
  18.     // add the overlay to the map  
  19.     if (nil != self.routeLine) {  
  20.         [self.mapView addOverlay:self.routeLine];  
  21.     }  
  22.       
  23.     // zoom in on the route.   
  24.     [self zoomInOnRoute];  
  25.            
  26. }  


我们将前面从文件获取经纬度创建轨迹的代码修改成从这个数组中取值就行了:

[plain]  view plain copy
  1. // creates the route (MKPolyline) overlay 
  2. -(void) loadRoute 
  3.   
  4.      
  5.     // while we create the route points, we will also be calculating the bounding box of our route 
  6.     // so we can easily zoom in on it.  
  7.     MKMapPoint northEastPoint;  
  8.     MKMapPoint southWestPoint;  
  9.      
  10.     // create a c array of points.  
  11.     MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * locations.count); 
  12.     for(int idx = 0; idx < locations.count; idx++) 
  13.     { 
  14.         // break the string down even further to latitude and longitude fields.  
  15.         NSString* currentPointString = [locations objectAtIndex:idx]; 
  16.         NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]]; 
  17.      
  18.         CLLocationDegrees latitude  = [[latLonArr objectAtIndex:0] doubleValue]; 
  19.         CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue]; 
  20.           
  21.         CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude); 
  22.  
  23.         MKMapPoint point = MKMapPointForCoordinate(coordinate); 
  24.  
  25.      
  26.         if (idx == 0) { 
  27.             northEastPoint = point; 
  28.             southWestPoint = point; 
  29.         } 
  30.         else  
  31.         { 
  32.             if (point.x > northEastPoint.x)  
  33.                 northEastPoint.x = point.x; 
  34.             if(point.y > northEastPoint.y) 
  35.                 northEastPoint.y = point.y; 
  36.             if (point.x < southWestPoint.x)  
  37.                 southWestPoint.x = point.x; 
  38.             if (point.y < southWestPoint.y)  
  39.                 southWestPoint.y = point.y; 
  40.         } 
  41.  
  42.         pointArr[idx] = point; 
  43.  
  44.     } 
  45.      
  46.     self.routeLine = [MKPolyline polylineWithPoints:pointArr count:locations.count]; 
  47.  
  48.     _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y); 
  49.      
  50.     free(pointArr); 
  51.      
[plain]  view plain copy
  1. // creates the route (MKPolyline) overlay  
  2. -(void) loadRoute  
  3. {  
  4.    
  5.       
  6.     // while we create the route points, we will also be calculating the bounding box of our route  
  7.     // so we can easily zoom in on it.   
  8.     MKMapPoint northEastPoint;   
  9.     MKMapPoint southWestPoint;   
  10.       
  11.     // create a c array of points.   
  12.     MKMapPoint* pointArr = malloc(sizeof(CLLocationCoordinate2D) * locations.count);  
  13.     for(int idx = 0; idx < locations.count; idx++)  
  14.     {  
  15.         // break the string down even further to latitude and longitude fields.   
  16.         NSString* currentPointString = [locations objectAtIndex:idx];  
  17.         NSArray* latLonArr = [currentPointString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];  
  18.       
  19.         CLLocationDegrees latitude  = [[latLonArr objectAtIndex:0] doubleValue];  
  20.         CLLocationDegrees longitude = [[latLonArr objectAtIndex:1] doubleValue];  
  21.            
  22.         CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);  
  23.   
  24.         MKMapPoint point = MKMapPointForCoordinate(coordinate);  
  25.   
  26.       
  27.         if (idx == 0) {  
  28.             northEastPoint = point;  
  29.             southWestPoint = point;  
  30.         }  
  31.         else   
  32.         {  
  33.             if (point.x > northEastPoint.x)   
  34.                 northEastPoint.x = point.x;  
  35.             if(point.y > northEastPoint.y)  
  36.                 northEastPoint.y = point.y;  
  37.             if (point.x < southWestPoint.x)   
  38.                 southWestPoint.x = point.x;  
  39.             if (point.y < southWestPoint.y)   
  40.                 southWestPoint.y = point.y;  
  41.         }  
  42.   
  43.         pointArr[idx] = point;  
  44.   
  45.     }  
  46.       
  47.     self.routeLine = [MKPolyline polylineWithPoints:pointArr count:locations.count];  
  48.   
  49.     _routeRect = MKMapRectMake(southWestPoint.x, southWestPoint.y, northEastPoint.x - southWestPoint.x, northEastPoint.y - southWestPoint.y);  
  50.       
  51.     free(pointArr);  
  52.       
  53. }  


这样我们就将我们运行得轨迹绘制google地图上面了。

扩展:

    如果你想使用其他的地图,比如百度地图,其实也很方便。可以将百度地图放置到UIWebView中间,通过用js去绘制轨迹。

总结:这篇文章我们介绍了一种常见的技术实现:在地图上绘制出你运行的轨迹。

你可能感兴趣的:(iOS 在地图上绘制出你运动的轨迹)