I m using Google map For my IOS application.
I m able to calculate Route and draw polyline based on it from directions API. The present direction api and my code is working well. But if user is not going to drawn route or going to wrong direction. I would like to recalculate route from the direction user is travelling not from the direction user is coming on. I m recalculating route for every 100 meters if not going to routhpath which is drawn.
It's calculating route correctly but in the opposite direction i m travelling on. So it should detect the direction i'm going on a road and not the backwards direction from which i m coming.
Here is code snippet. I written in delegate didUpdateToLocations:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
if (aLocationDistanceLoc == Nil) {
aLocationDistanceLoc=[[CLLocation alloc]init];
aLocationDistanceLoc=newLocation;
}
else
{
CLLocationDistance distance1 = [aLocationDistanceLoc distanceFromLocation:newLocation];
if (distance1 > 100) {
aLocationDistanceLoc=newLocation;
if (GMSGeometryIsLocationOnPathTolerance(newLocation.coordinate, routesPath, YES, 10)) {
}
else
{
flagForRouteRecalculateActive=YES;
[self callApiForNavigation:[NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude] destinationPoint:[NSString stringWithFormat:#"%#,%#",currentLatDropoff ,currentLongDropoff ]];
}
}
}
Here is my Directions API call:
[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true&mode=driving",[[arrayStart objectAtIndex:0] floatValue],[[arrayStart objectAtIndex:1] floatValue],[[arrayDestination objectAtIndex:0] floatValue],[[arrayDestination objectAtIndex:1] floatValue]]
Here is the Video demonstration of problem. You'll see as i moving in direction the route is recalculating but its recalculate from backward direction. I need to recalculate from front in the direction i m going.
video of actual Issue
Related
I am using Google Map SDK for iOS. I am drawing polylines in Driving mode.
But when i stop,and Zoom google map then, my Current position cursor automatically moves and redraw zigzag polylines, due to that all previous polylines drawn get overlapped and polylines get completely changed.Same things happens when i go in background and drive.
Could i know why is it happening? And How can I draw smooth polylines in driving and walking mode same time in same path.
My Code-
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
pointString=[NSString stringWithFormat:#"%f,%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude];
CLLocationDistance kilometers = [newLocation distanceFromLocation:oldLocation] / 1000;
NSLog(#"Distance Travelled in Kilometer :%f",kilometers);
[self.points addObject:pointString];
GMSMutablePath *path = [GMSMutablePath path];
for (int i=0; i<self.points.count; i++)
{
NSArray *latlongArray = [[self.points objectAtIndex:i]componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#","]];
[path addLatitude:[[latlongArray objectAtIndex:0] doubleValue] longitude:[[latlongArray objectAtIndex:1] doubleValue]];
}
if (self.points.count>2)
{
GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
polyline.strokeColor = [UIColor blueColor];
polyline.strokeWidth = 5.f;
polyline.map = mapView_;
self.mapContainerView = mapView_;
}
}
If , I remain in Same position, then Googme map Cursor position automaticalaly moves and draw polylines like this.
add a NSLocationAlwaysUsageDescription and a UIBackgroundModes -> "location" to Info.plist
AND
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
manager.allowsBackgroundLocationUpdates = YES;
}
Before allowing background location updtaes:
enter image description here
After Allowing background location updtaes:
enter image description here
Most of this itinerary has been drawn in the background.
Two things are going on. First, the GPS chip does not always return the same location when standing still. The determined GPS location always fluctuates a bit. iOS does an effort to detect that you're standing still, and then supply the same location, but I think that is done to a lesser extend in Driving mode.
Second, by using the convoluted way to store the samples as strings, you go through a %f conversion, which looses accuracy. That can exaggerate any differences between locations. If you use the CLLocation objects directly, you're likely getting a better result (and much cleaner code):
[self.points addObject:newLocation];
GMSMutablePath *path = [GMSMutablePath path];
for (CLLocation *col in self.points)
{
[path addLatitude:col.latitude longitude:col.longitude];
}
Also, make sure you set the correct settings on the CLLocationManager:
theLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
theLocationManager.distanceFilter = kCLDistanceFilterNone;
theLocationManager.activityType = CLActivityTypeOtherNavigation;
theLocationManager.allowsBackgroundLocationUpdates = YES
One other thing. It is also very strange that you change the view in the didUpdateToLocation: method:
self.mapContainerView = mapView_;
You should just use setNeedsDisplay on the existing view, after updating the path.
I want to achieve the following and I am unaware whether it is possible or not. I am having two points on a road (imagine like a finishing line - they are the two edges of the pavements - they are in a straight line) and I want to check whether a user's route has passed between these points.
So I thought, I can do something like this:
get the route between these two points (they are quite near - the road is 20 m wide at most)
get the users route
check if these routes are interecting, if there is any crossing between them.
If it was pure geometry, it would be easy. I am having two lines and I want to know if there is any intersection between them.
I want to use the following in an IOS project, if it makes any difference. For example, I thought that maybe there is a programmatically way of drawing the MKPolylines and see if there is intersection. I do not want to see it visually, I just need it programmatically.
Is it possible? Can you suggest me anything else?
There is no direct method to check for that intersection.
You can turn the problem into a geometry problem by converting the lat/long positions into map positions (applying the transform to flatten onto a normalised grid). This can be done with MKMapPointForCoordinate.
One thing to consider is the inaccuracy of the GPS reported positions. In a number of cases you will find that the reported track from the GPS isn't actually on the road but running beside the road. Particularly when turning (tight) corners you will often get a large curve in the track. As such you may want to extend the width of the 'finishing line' to compensate for this.
If you just care about whether the user is within a certain distance of a set point then you can create a CLRegion to represent the target location and then call containsCoordinate: with the current user location. This removes any projection and uses the lat/long directly. You can also get the system to monitor this for you and give you a callback when the user enters or exits the region with startMonitoringForRegion:desiredAccuracy:. Again, you need to consider GPS accuracy when setting the radius.
I would try to solve this problem in three steps:
Step 1. Convert each coordinate user's track has to CGPoint and save it an array.
// in viewDidLoad
locManager = [[CLLocationManager alloc] init];
[locManager setDelegate:self];
[locManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locManager startPdatingLocation];
self.userCoordinatePoints = [NSMutableArray alloc]init];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
CLLocationCoordinate2D loc = [newLocation coordinate];
CGPoint *currentPoint = [self.mapView convertCoordinate:loc toPointToView:self.mapView];
// add points to array
self.userCoordinatePoints addObject:currentpoint];
}
Step 2. Convert MKPolylineView to CGPathRef
Create a class variable of type CGPathRef
{
CGPathRef path;
}
This method you must have implemented to create the route between two points:
- (MKOverlayView*)mapView:(MKMapView*)theMapView
viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *overlayView = [[MKPolylineView alloc]
initWithOverlay:overlay];
overlayView.lineWidth = 3;
overlayView.strokeColor = [[UIColor blueColor]colorWithAlphaComponent:0.5f];
// overlayView.fillColor = [[UIColor purpleColor] colorWithAlphaComponent:0.1f];
path = overlayView.path;
return overlayView;
}
Step 3: Create a custom method to check whether point lies in CGPath or not
- (BOOL)userRouteIntersectsGoogleRoute
{
// Loop through all CGPoints
for(CGPoint point in self.userCoordinatePoints)
{
BOOL val = CGPathContainsPoint(path, NULL, point);
if(val)
{
return YES;
}
}
return NO;
}
I'm using the following code to calculate the distance between my app user's location, and nearby locations (annotations). When I try to display the "Distance Away" as text in a label, it keeps saying that the calculated distance is 0. Why is this?
*Note that my table is using the coordinates placed on my MapView to determine the distance away.
Here's the code I'm using to calculate the distance from my user to a nearby location
MapViewController.m
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
for (MapViewAnnotation *annotation in self.mapView.annotations) {
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *annotationLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
annotation.distance = [newLocation distanceFromLocation:annotationLocation];
}
And here's the bit I'm using to display the calculatedDistance in a label (located in my custom cell to be displayed in a tableview):
ViewController.m
cell.distanceLabel.text = [NSString stringWithFormat:#"%f m.", calculatedDistance];
Any help would be much appreciated!
for (MapViewAnnotation *annotation in self.mapView.annotations) {
CLLocationCoordinate2D coord = [annotation coordinate];
CLLocation *userLocation = [[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude];
That's not the user's location, that's the annotation's location. But odd variable names aside:
CLLocationDistance calculatedDistance = [userLocation distanceFromLocation:userLocation];
The distance from a location to itself is 0. That line is probably a bug. Maybe you meant
CLLocationDistance calculatedDistance = [newLocation distanceFromLocation:userLocation];
which would return the distance between the user's new location and the (misnamed) annotation's location - probably what you want. Of course, you actually calculate just that on the line above the distance-to-self calculation, then throw it away two lines later.
tl;dr
Throw away the last two lines, they're useless.
I am building an application that should show an arrow to a certain location. Forinstance, if I am at position X and the target is set to position Y, it should show an arrow pointing directly to that position.
After searching and searching I found that there are some fancy formulas of calculating this, however I seem to get it wrong over and over.
This is my problem. Although it seems to find the correct initial position, as soon as I turn my device the "arrow" turns in the opposite direction or what it should. So, if I turn my device clockwise, the arrow turns also clockwise... and visa versa.
This is some of my code:
#implementation CompassViewController
BOOL firstPositionFound = NO;
float lastPosition = 0;
float currentHeading = 0;
[...]
#pragma mark -
#pragma mark Core Location Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
if (newHeading.headingAccuracy > 0) {
CLLocationDirection theHeading = newHeading.magneticHeading;
currentHeading = theHeading;
[self fixPointer:theHeading];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
self.currentLocation = newLocation;
[self fixPointer:currentHeading];
}
- (void)fixPointer:(float)heading
{
float degree = [self calculateDegree:self.currentLocation];
degree = heading - degree;
NSLog(#"heading: %f, Degree: %f", heading, degree);
NSLog(#"Degree 2: %f", degree);
self.arrowView.transform = CGAffineTransformMakeRotation(degreesToRadians(degree));
}
#pragma mark -
#pragma mark Delegate methods
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma mark Other methods
- (float)calculateDegree:(CLLocation *)newLocation
{
CLLocationCoordinate2D from = newLocation.coordinate;
CLLocationCoordinate2D to;
to.latitude = APP_DESTINATION_LAT;
to.longitude = APP_DESTINATION_LON;
float res = atan2(sin((to.longitude*M_PI/180)-(from.longitude*M_PI/180))*cos(to.latitude*M_PI/180),
cos(from.latitude*M_PI/180)*sin(to.latitude*M_PI/180)-sin(from.latitude*M_PI/180)*cos(to.latitude*M_PI/180)*cos((to.longitude*M_PI/180)-(from.longitude*M_PI/180)));
res = res/M_PI*180;
if (res < 0)
res = 360.0f + res;
return res;
}
#pragma mark -
I am just lost, could someone please point out to me where I went wrong? I guess its some simple thing that I currently am to blind for to see.
Have a look at the answer in this Stack Overflow question:
CLLocation Category for Calculating Bearing w/ Haversine function
specifically, this part:
If you are getting negative bearings, add 2*M_PI to the final result in radiansBearing (or 360 if you do it after converting to degrees). atan2 returns the result in the range -M_PI to M_PI (-180 to 180 degrees), so you might want to convert it to compass bearings, using something like the following code
if(radiansBearing < 0.0)
radiansBearing += 2*M_PI;**
Also, heading info needs to be adjusted for device orientation and angle, unless you are always holding your device in portrait. Turn you device slowly to landscape mode and you will see your heading value change by 90°.
Check this out
Wikipedia - On rotation matrix
From I understand from the code you have the angle between the sin element and the cos element of the given (x,y) coordinate. [Basically given by (tan(x,0)/(0,y))]
lets call this angle theta.
What you should do is take this coordinate and multiply it by
lets call the new coordinate (x',y')
Hope this helps.
I have a location service app, in which the user's elevation is provided. I have found, though, that the elevation accuracy provided by the CLLocationManager is extremely inaccurate. When I test the same two spots twice, sometimes the elevation difference is forty feet and sometimes it is a hundred. Is there any way that I can improve the vertical accuracy of the CLLocation, or is there a different way of acquiring the user's elevation (third-party libraries)? I have already tried checking the verticalAccuracy property of the newLocation provided by the CLLocationManager and throwing it out if it isn't sufficient, but even when it is 'accurate' enough, it still often isn't actually accurate. Thanks for your time!
Right now I'm using:
if([newLocation verticalAccuracy] < 30) {
if(isCustomary)
altitudeLabel.text = [NSString stringWithFormat:#"%.2f feet", ([newLocation altitude] * 3.2808399)];
else
altitudeLabel.text = [NSString stringWithFormat:#"%.2f meters", [newLocation altitude]];
}
Problems with that code: often the verticalAccuracy never gets below 30, and when it does, that is still not even close to accurate enough; I have tested the code walking around my house (one story), and it says the elevation changes up to nineteen feet, which I'm sure isn't true.
The elevation derived from GPS satellites is inherently less accurate than the horizontal solution from GPS due to the geometry of the satellites. You should expect the vertical accuracy to be usually about 1.5 to 3 times worse than the horizontal accuracy. That's just a limitation of GPS and why aviation requires WAAS correction before you can use GPS for instrument approaches.
When the vertical accuracy is 20 or 30 meters you should expect the altitude to be off up to 100 feet. Expecting it to not vary by 19 feet as you walk around the house in unrealistic.
What you could do is keep a rolling, weighted average (or a Kalman filter) of the recent "good" altitude readings to help filter out the measurement errors.
What code have you tried?
This is the best code for elevation so I don't think there is anything beyond this:
-(void)awakeFromNib {
locmanager = [[CLLocationManager alloc] init];
[locmanager setDelegate:self];
[locmanager setDesiredAccuracy:kCLLocationAccuracyBest];
[locmanager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
heightMesurement.text = [NSString stringWithFormat: #"%.2f m", newLocation.altitude];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
heightMesurement.text = #"0.00 m";
}