I'm trying to convert the meters travelled into miles. The problem I'm having is that the results are completely inaccurate and I'm having trouble finding out why.
Here is the code I'm using:
CLLocation* newLocation = [locations lastObject];
NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow];
if (age > 120) return; //
if (newLocation.horizontalAccuracy < 0) return;
if (self.oldLocation == nil || self.oldLocation.horizontalAccuracy < 0) {
self.oldLocation = newLocation;
return;
}
CLLocationDistance distance = [newLocation distanceFromLocation: self.oldLocation];
NSLog(#"%6.6f/%6.6f to %6.6f/%6.6f for %2.0fm, accuracy +/-%2.0fm",
self.oldLocation.coordinate.latitude,
self.oldLocation.coordinate.longitude,
newLocation.coordinate.latitude,
newLocation.coordinate.longitude,
distance,
newLocation.horizontalAccuracy);
NSLog(#"distance is %f", distance);
totalDistanceBetween =+ (distance * 0.000621371192);
NSString *cycleDistanceString = [[NSString alloc]
initWithFormat:#"%f meters",
totalDistanceBetween];
_CurrentDistance.text = cycleDistanceString;
self.oldLocation = newLocation;
Can anyone give me an idea where i'm going wrong?
Thanks
Your code says this:
totalDistanceBetween =+ (distance * 0.000621371192);
That uses the unary + operator, which does nothing. It seems likely that you meant this:
totalDistanceBetween += (distance * 0.000621371192);
Also, the units of distance is meters (because that is what distanceFromLocation: returns), and the units of totalDistanceBetween is miles, because 0.000621371192 miles = 1 meter. But in the next statement, your format string says %f meters. It should say %f miles.
Related
I am currently working on iOS project, where i use motion data.
I get a good results with pitch and roll values, but yaw value is constantly drifting. I have applied Kalman filter and results are remain the same.
Does anyone has an idea how to solve it?
Here is some source code (Objective C)
[self.motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical
toQueue:[NSOperationQueue currentQueue]
withHandler:^(CMDeviceMotion *motion, NSError *error)
{
//NSString *yaw = [NSString
//stringWithFormat:#" %.3f", motion.attitude.yaw];
NSString *pitch = [NSString
stringWithFormat:#" %.3f", motion.attitude.pitch];
NSString *roll = [NSString
stringWithFormat:#" %.3f", motion.attitude.roll];
//Converting NSSring type variable in to a double
//double a_yaw = [yaw doubleValue];
double a_pitch = [pitch doubleValue];
double a_roll = [roll doubleValue];
CMQuaternion quat = self.motionManager.deviceMotion.attitude.quaternion;
double yaw = 180/M_PI * (asin(2*quat.x*quat.y + 2*quat.w*quat.z));
// Kalman filtering
static float q = 0.1; // process noise
static float r = 0.1; // sensor noise
static float p = 0.1; // estimated error
static float k = 0.5; // kalman filter gain
float x = motionLastYaw;
p = p + q;
k = p / (p + r);
x = x + k*(yaw - x);
p = (1 - k)*p;
motionLastYaw = x;
//Converting angles to degrees
//yaw = yaw * 180/M_PI;
a_pitch = a_pitch * 180/M_PI;
a_roll = a_roll * 180/M_PI;
"yaw" value need a reference to additional coordinate system(camera...).
Bullet objects are created with .l for location and .vel for velocity. I'm trying with a large radius of 30 and still they never collide.
- (void)bulletsFired:(NSArray *)bullets li:(int)li {
[self playBulletSound:li];
for (Bullet *b in bullets) {
[self addChild:b];
b.tag = -1;
b.shotNumber = shotsFired;
}
for (Bullet *b in bullets) {
for (Bullet *bb in self.bullets) {
float timeOfApproach = TimeOfClosestApproach(b.l, b.vel, bb.l, bb.vel, 30, 30);
if (timeOfApproach > 0) {
NSLog(#"time of : %f", timeOfApproach);
NSString *keyName = [self.collisions objectForKey:[self keyNameForTime:(int)timeOfApproach]];
NSMutableArray *timedCollisions = [self.collisions objectForKey:keyName];
if (timedCollisions == nil) {
NSMutableArray *newCollisions = [NSMutableArray array];
[self.collisions setObject:newCollisions forKey:keyName];
}
NSDictionary *collision = #{#"b1" : [NSString stringWithFormat:#"%d", bb.shotNumber], #"b2" : [NSString stringWithFormat:#"%d", b.shotNumber]};
[timedCollisions addObject:collision];
}
}
}
[self.bullets addObjectsFromArray:bullets];
[self.scoreCycler score:1];
}
I check for timeOfClosestApproach with this function:
float TimeOfClosestApproach(CGPoint Pa, CGPoint Pb, CGPoint Va, CGPoint Vb, float Ra, float Rb) {
CGPoint Pab = ccpSub(Pa, Pb);
CGPoint Vab = ccpSub(Va, Vb);
float a = ccpDot(Vab, Vab);
float b = 2 * ccpDot(Pab, Vab);
float c = ccpDot(Pab, Pab) - (Ra + Rb) * (Ra + Rb);
// The quadratic discriminant.
float discriminant = b * b - 4 * a * c;
// Case 1:
// If the discriminant is negative, then there are no real roots, so there is no collision. The time of
// closest approach is then given by the average of the imaginary roots, which is: t = -b / 2a
float t;
if (discriminant < 0) {
t = -b / (2 * a);
return -1;
} else {
// Case 2 and 3:
// If the discriminant is zero, then there is exactly one real root, meaning that the circles just grazed each other. If the
// discriminant is positive, then there are two real roots, meaning that the circles penetrate each other. In that case, the
// smallest of the two roots is the initial time of impact. We handle these two cases identically.
float t0 = (-b + (float)sqrt(discriminant)) / (2 * a);
float t1 = (-b - (float)sqrt(discriminant)) / (2 * a);
t = min(t0, t1);
// We also have to check if the time to impact is negative. If it is negative, then that means that the collision
// occured in the past. Since we're only concerned about future events, we say that no collision occurs if t < 0.
if (t < 0) {
return -1;
} else {
}
}
// Finally, if the time is negative, then set it to zero, because, again, we want this function to respond only to future events.
if (t < 0) {
t = 0;
}
return t;
}
I keep getting -1 returned, and the bullets are never predicted to collide, even when they should based on my eyesight.
if (t < 0) {
return -1;
} else {
}
Keeps getting triggered.
What's wrong with my timeOfClosestApproach function?
My actual problem is - How to obtain a CLLocation Object when the coordinate value on the map is available in Degree-Minute-Second form (as a String), instead of Double.
So, I am Looking for a way to convert Degree-Minute-Second to Double, which i can use to form a CLLocation object.
I came up with a bit of a cleaner answer when figuring this out
// split the string to deal with lat and lon separately
NSArray *parts = [dmsString componentsSeparatedByString:#","];
NSString *latStr = parts[0];
NSString *lonStr = parts[1];
// convert each string
double lat = [self degreesStringToDecimal:latStr];
double lon = [self degreesStringToDecimal:lonStr];
// init your location object
CLLocation *loc = [[CLLocation alloc] initWithLatitude:lat longitude:lon];
The magic
- (double)degreesStringToDecimal:(NSString*)string
{
// split the string
NSArray *splitDegs = [string componentsSeparatedByString:#"\u00B0"]; // unicode for degree symbol
NSArray *splitMins = [splitDegs[1] componentsSeparatedByString:#"'"];
NSArray *splitSecs = [splitMins[1] componentsSeparatedByString:#"\""];
// get each segment of the dms string
NSString *degreesString = splitDegs[0];
NSString *minutesString = splitMins[0];
NSString *secondsString = splitSecs[0];
NSString *direction = splitSecs[1];
// convert degrees
double degrees = [degreesString doubleValue];
// convert minutes
double minutes = [minutesString doubleValue] / 60; // 60 degrees in a minute
// convert seconds
double seconds = [secondsString doubleValue] / 3600; // 60 seconds in a minute, or 3600 in a degree
// add them all together
double decimal = degrees + minutes + seconds;
// determine if this is negative. south and west would be negative values
if ([direction.uppercaseString isEqualToString:#"W"] || [direction.uppercaseString isEqualToString:#"S"])
{
decimal = -decimal;
}
return decimal;
}
Note that I've only tested this with coordinates in Wisconsin, which is North and West. I'm using this tool to verify my calculations.
Let's say you have a the coordinate value in a String -
Split the String To obtain Degree-Minute-Second values in separate strings.
NSString *longlat= #"+39° 44' 39.28", -104° 50' 5.86" "(find a way to escape the " in the string)
//separate lat and long
NSArray *splitLonglat = [longlat componentsSeparatedByString:#","];
//separate Degree-Minute-Seconds
NSArray *arrayLat = [[splitLonglat objectAtIndex:0] componentsSeparatedByString:#" "];
double latitude,longitude;
if([arrayLat count]==3){
//get the double value for latitude
latitude= [self convertDMSToDD_deg:(NSString *)[arrayLat objectAtIndex:0]//degree
min:(NSString *)[arrayLat objectAtIndex:1]//minute
sec:(NSString *)[arrayLat objectAtIndex:2]//seconds
];
}else{
//some values could be in decimal form in the String already, instead of Degree-Minute-Second form and we might not need to convert them.
NSLog(#"latitude in decimal for %#",locationModelObject.name);
latitude=[[splitLonglat objectAtIndex:0]doubleValue];
}
NSArray *arrayLong= [[splitLonglat objectAtIndex:1] componentsSeparatedByString:#" "];
if([arrayLong count]==4){
//get the double value for longitude
longitude= [self convertDMSToDD_deg:(NSString *)[arrayLong objectAtIndex:1]//degree
min:(NSString *)[arrayLong objectAtIndex:2]//minute
sec:(NSString *)[arrayLong objectAtIndex:3]//seconds
];
}else{
//some values could be in decimal form in the String already, instead of Degree-Minute-Second form and we might not need to convert them.
NSLog(#"longitude in decimal for %#",locationModelObject.name);
longitude=[[splitLonglat objectAtIndex:1]doubleValue];
}
//add latitude longitude to the model object
locationModelObject.latitude=latitude;
locationModelObject.longitude=longitude;
The Method which does the conversion
-(double) convertDMSToDD_deg:(NSString*)degrees min:(NSString* )minutes sec:(NSString*)seconds {
int latsign=1;
double degree=[degrees doubleValue];
double minute=[minutes doubleValue];
double second=[seconds doubleValue];
if (degree<0){
latsign = -1;
}
else{
latsign=1;
}
double dd = (degree + (latsign* (minute/60.)) + (latsign* (second/3600.) ) ) ;
return dd;
}
I have the following calculation to make:
float value = MY_VALUE;
float percentage = (value - MIN)/(MAX - MIN);
if (percentage < 0)
percentage = 0;
if (percentage > 1)
percentage = 1
I was just wondering if there is some method that exists in Objective-C or C to help accomplish this, like for example a method that will round the "value" float to be between the MIN and MAX bounds.
There is no such method in standard C libraries (I don't know about Objective C).
No.
On another note, you should probably update your code so you are preventing a possible divide-by-zero:
float den = (value - MIN);
float num = (MAX - MIN);
float percentage;
if(den) {
percentage = num / den;
if (percentage < 0.0f ) {
percentage = 0.0f;
} else if (percentage > 1.0f) {
percentage = 1.0f;
} else {
printf("Percentage: %3.2f",percentage);
}
} else {
percentage = 0.0f;
printf("DIVIDE BY ZERO ERROR!");
}
Also, careful. Oracle is suing Google over a very similar piece of code. You may want to reconsider posting it publicly:
http://developers.slashdot.org/story/12/05/16/1612228/judge-to-oracle-a-high-schooler-could-write-rangecheck
If you want to calculate percentage in objective-c syntax then this is the way to go.
(I think Dogbert got it wrong (opposite) on line 6).
Here's what I did and it works just as wanted..
- (CGFloat)calculateProgressForValue:(CGFloat)value start:(CGFloat)start end:(CGFloat)end
{
CGFloat diff = (value - start);
CGFloat scope = (end - start);
CGFloat progress;
if(diff != 0.0) {
progress = diff / scope;
} else {
progress = 0.0f;
}
return progress;
}
And you can always constrain this to not go over 0.0 or 1.0 like so:
- (CGFloat)progressConstrained {
// example values
CGFloat start = 80;
CGFloat end = 160;
CGFloat a = 100;
// the constrain
return MAX(0.0, MIN(1.0, [self calculateProgressForValue:a start:start end:end]))
}
If you just want to make sure a value is not higher or lower than other values you should use MAX(a, b) and MIN(a, b)...
float maxValue = 1.0;
float minValue = 0.0;
float myValue = 2.8;
float myValueConstrained = MAX(minValue, MIN(maxValue, myValue)); // 1.0
MIN(a,b) takes the smallest of a and b
MAX(a,b) takes the greatest of a and b
I typically just do like this:
float myValueConstrained = MAX(0.0, MIN(1.0, myValue));
I am trying to find the closest "player" to a "ball" and each of these objects are CCSprite Objects. This is my first app, so if there's a better way to do this, feel free to suggest it :)
Here's my code so far:
for(CCSprite *currentPlayer in players) {
// distance formula
CGFloat dx = ball.position.x - currentPlayer.position.x;
CGFloat dy = ball.position.y - currentPlayer.position.y;
CGFloat distance = sqrt(dx*dx + dy*dy);
// add the distance to the distances array
[distances addObject:[NSNumber numberWithFloat:distance]];
NSLog(#"This happen be 5 times before the breakpoint");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
So this seems to work well; it logs each distance of the player from the ball. But then when I loop through my "distances" array, like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", [NSNumber numberWithInt:distance]);
}
And this is logging a huge number each time, like 220255312. I declare my distances array like this:
// setting the distance array
NSMutableArray *distances = [[NSMutableArray alloc] init];
What am I doing wrong?
Thanks for your time!
Use distance for the #"%#" like this:
for(NSNumber *distance in distances ) {
NSLog(#"Distance loop");
NSLog(#"%#", distance);
}
[NSNumber numberWithInt:distance]
In your first part distance is a CGFloat.
In the second part distance is a NSNumber.
numberWithInt can't take a NSNumber as its argument.
Hope this helps!
CCSprite *nearestPlayer;
for(CCSprite *currentPlayer in players) {
if(nearestPlayer == nil){
nearestPlayer = currentPlayer;
}
if(ccpDistance(ball.position, currentPlayer.position) < ccpDistance(ball.position, nearestPlayer.position)){
nearestPlayer = currentPlayer;
}
}