NSPoint offset by pixels toward angle? - objective-c

Let me just start with the code.
- (NSPoint*) pointFromPoint:(NSPoint*)point withDistance:(float)distance towardAngle:(float)angle; {
float newX = distance * cos(angle);
float newY = distance * sin(angle);
NSPoint * anNSPoint;
anNSPoint.x = newX;
anNSPoint.y = newY;
return thePoint;
}
This should, based on my knowledge, be perfect. It should return and x value of 0 and a y value of 2 if I call this code.
somePoint = [NSPoint pointFromPoint:somePoint withDistance:2 towardAngle:90];
Instead, I get and x value of 1.05 and a y of 1.70. How can I find the x and y coordinates based on an angle and a distance?
Additional note: I have looked on math.stackexchange.com, but the formulas there led me to this. I need the code, not the normal math because I know I will probably screw this up.

A working version of your function, which accepts values in degrees instead of radians, would look like this:
- (NSPoint)pointFromPoint:(NSPoint)origin withDistance:(float)distance towardAngle:(float)angle
{
double radAngle = angle * M_PI / 180.0;
return NSMakePoint(origin.x + distance * cos(radAngle), point.y + distance * sin(radAngle));
}

Your problem is you're giving the angle in degrees (e.g. 90), but the math is expecting it in radians. Try replacing the 90 with M_PI_2

Related

Objective-C Trigonometry

I'm having a pain with trig at the moment.
double angle = tan(opposite/adjacent);
angle = (angle) * (180.0 / M_PI);
That finds the angle for them particulars, we'll say in this case it equals 15.18º after being converted from radians.
Then, to find the adjacent and opposite of the new Hypotenuse with the same angle I do..
double oppAngle = sin(angle);
double adjAngle = cos(angle);
double secondOpposite = newDistance * oppAngle;
double secondAdjacent = newDistance * adjAngle;
NSLog(#"opposite = %.2f * %.2f = %.2f", oppAngle, newDistance, secondOpposite);
NSLog(#"Adjacent = %.2f * %.2f = %.2f", adjAngle, newDistance, secondAdjacent);
That logs,
2015-06-27 17:36:14.565 opposite = -0.51 * 183.27 = -92.94
2015-06-27 17:36:14.565 Adjacent = -0.86 * 183.27 = -157.95
Which is obviously wrong, as the sine and cosine of them angles are incorrect. The angle logs 15.18º so I'm not too sure where I'm going wrong, unless.. They are converted into radians again? I'm not quite sure where I'm going wrong, however.. It's wrong.
The trig formula is
tan(angle) = opposite / adjacent
So to get the angle from the side lengths, you need to use the inverse tangent, which is atan2.
double angle = atan2(opposite, adjacent);
From there the rest of your code works as long as you know that atan2 returns an angle in radians (so your second line is unnecessary).

Calculate distance in (x, y) between two GPS-Points

I'm looking for a smooth way to calculate the distance between two GPS Points, so I get the result like: "You have to go x meters up and y meters to the left - so I can work with a 2d-coordinate system, where I have my position as (0,0) and the other positions is showing the distance in (x, y) in meters from my position.
My idea was to calculate the distance between the points using the haversine formula. (This returns my hypotenuse)
In addition to that, I'm calculating the bearing between this two points. This is my alpha.
With this two values, I wanted to use basic trigonometry functions to resolve my problem.
So I tried to calculate:catheti_1 = sin(alpha) * hypotenuse, catheti_2 = cos(alpha) * hypotenuse.
Maybe I'm doing something wrong, but my results are useless at the moment.
So my question is: How can I calculate the distance in x and y direction between two GPS points?
I'm calculating alpha in the following procedure:
public static double bearingTo(GPSBean point1, GPSBean point2) {
double lat1 = Math.toRadians(point1.latitude);
double lat2 = Math.toRadians(point2.latitude);
double lon1 = Math.toRadians(point1.longitude);
double lon2 = Math.toRadians(point2.longitude);
double deltaLong = lon2 - lon1;
double y = Math.sin(deltaLong) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(deltaLong);
double bearing = Math.atan2(y, x);
return (Math.toDegrees(bearing) + 360) % 360;
}
I just implemented your code, using approximate coordinates of NYC and Boston as reference points, and implementing the Haversine formula as found at http://www.movable-type.co.uk/scripts/latlong.html (which you didn't show):
long1 = -71.02; lat1 = 42.33;
long2 = -73.94; lat2 = 40.66;
lat1 *=pi/180;
lat2 *=pi/180;
long1*=pi/180;
long2*=pi/180;
dlong = (long2 - long1);
dlat = (lat2 - lat1);
// Haversine formula:
R = 6371;
a = sin(dlat/2)*sin(dlat/2) + cos(lat1)*cos(lat2)*sin(dlong/2)*sin(dlong/2)
c = 2 * atan2( sqrt(a), sqrt(1-a) );
d = R * c;
When I run this code, I get d = 306, which agrees with the answer from the above site.
For the bearing I get 52 deg - again, close to what the site gave.
Without seeing the rest of your code it's hard to know why your answer is different.
Note: when the two points are close together, you could make all kinds of approximations, but this code should still work - the formula has good numerical stability because it's using the sin of the difference between longitudes, latitudes (rather than the difference of the sin).
Addendum:
Using your code for x, y (in your question), I get sensible values for the distance - agreeing with the "proper" answer to within 120 m (which isn't bad since one is a straight line approximation and the other follows the curvature of the earth). So I think your code is basically OK now you fixed the typo.
Use Haversine formula to Calculate distance (in km) between two points specified by latitude/longitude (in numeric degrees)
from: Haversine formula - R. W. Sinnott, "Virtues of the Haversine"
Sky and Telescope, vol 68, no 2, 1984
http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
Example usage from form:
result.value = LatLon.distHaversine(lat1.value.parseDeg(), long1.value.parseDeg(), * lat2.value.parseDeg(), long2.value.parseDeg());
Javascript :
LatLon.distHaversine = function(lat1, lon1, lat2, lon2) {
var R = 6371; // earth's mean radius in km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
lat1 = lat1.toRad(), lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return d;
}
If anybody is interested to have a simpler formula that anyone can understand. Here is mine, it works for Sweden, but you can adapt it to work anywhere by making a more general formula for calculation of longfactor.
Hope you can understand even if it is written in an odd language.
<gpsDist lat1,long1,lat2,long2> all parameters in 1/100000 degree.
Example: <getDist 5950928,1327120,5958505,1302241> => 16303
Same at https://gps-coordinates.org/distance-between-coordinates.php => 16.35 KM.
<var $latFactor,1.112>
<function getDist,
-<var $longFactor,<calc 0.638 - ($1/100000-55)*0.0171,3>>
-<var $latDist,<calc ($3-$1)*$latFactor>>
-<var $longDist,<calc ($4-$2)*$longFactor>>
-<sqrt $latDist*$latDist + $longDist*$longDist>
->
/Bertil Friman

CCMoveTo duration / speed issue

Some help would be most appreciated. Sprite movement based upon a heading that is given from a touch on the screen. Sprite moves as expected but I am unable to vary the speed, no matter what value I use for currentSpeed. This is in the update method of the sprite. Thanks in advance.
// Distance between two points (Distance formula, Pythagorean Theorem c^2=a^2+b^2, so d=sqrt((x2-x1)^2+(y2-y1)^2)
// Duration (time = distance / rate)
CGPoint adjustedPosition;
adjustedPosition.x = position_.x - sinf(heading);
adjustedPosition.y = position_.y - cosf(heading);
float distance = CGPointDistanceBetweenTwoPoints(adjustedPosition, position_);
float duration = distance / currentSpeed;
position_ = adjustedPosition;
[self runAction:[CCMoveTo actionWithDuration:duration position:position_]];
dont use a moveto or for that matter any action in an update method. Instead, compute the position , something like this:
-(void) update:(ccTime) dt {
// _velocity in points per second.
// heading should be in ccw notation, 0 on x axis, RHS
float deltaX = dt * _velocity * cosf(heading);
float deltaY = dt * _velocity * sinf(heading);
CGPoint adjustedPosition = ccpAdd(self.position, ccp(deltaX,deltaY));
self.position = adjustedPosition;
}
or something similar. This will ease out any variance id dt, for which the only thing you can bet on is that it wont be constant ; but the physics should be right.
Try this for distance:
float distance = ccpLength(ccpSub(adjustedPosition, position_));

Cocos2d Collision Detection model - best for my case?

I'm building a cocos2d iPhone game with lots of bullets and moving enemies and I'm detecting collisions between them. Every sprite can be represented by a circle for collision purposes. I'm considering the following options:
1) Simple Sphere Detection
I detect like this at regular intervals:
-(BOOL) isCollidingSphere:(CCSpriteExt*) obj1 WithSphere:(CCSprite *) obj2
{
float minDistance = obj1.radius + obj2.radius;
float dx = obj2.position.x - obj1.position.x;
float dy = obj2.position.y - obj1.position.y;
if (! (dx > minDistance || dy > minDistance) )
{
float actualDistance = sqrt( dx * dx + dy * dy );
return (actualDistance <= minDistance);
}
return NO;
}
2) Box2d for collision detection only
I create a Box2d body for all sprites as shown in this tutorial: http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone
My question is simple: If my priority is optimisation, which approach is faster?
Thanks!
If all you need is distance/radius based collision checks, you don't need a physics engine.
You should get rid of the sqrt though. First of all, you're using the square root function that works on doubles. For the float version use sqrtf.
To get rid entirely of the square root, make sure your objects store their radius squared (radiusSquared = radius * radius). That way you don't have to take the square root anymore:
-(BOOL) isCollidingSphere:(CCSpriteExt*) obj1 WithSphere:(CCSprite *) obj2
{
float r1 = obj1.radius;
float r2 = obj2.radius;
float minDistanceSquared = r1 * r1 + r2 * r2 + 2 * r1 * r2;
float dx = obj2.position.x - obj1.position.x;
float dy = obj2.position.y - obj1.position.y;
float actualDistanceSquared = dx * dx + dy * dy;
return (actualDistanceSquared <= minDistanceSquared);
}

Map GPS Coordinates to an Image and draw some GPS Points on it

I have some problems figuring out where my error is. I got the following:
Have an image and corresponding GPS coordinates of its top-left and bottom-right vertices.
E.g:
topLeft.longitude = 8.235128;
topLeft.latitude = 49.632383;
bottomRight.longitude = 8.240547;
bottomRight.latitude = 49.629808;
Now a have an Point that lies in that map:
p.longitude = 8.238567;
p.latitude = 49.630664;
I draw my image in landscape fullscreen (1024*748).
Now I want to calculate the exact Pixel position (x,y) of my point.
For doing that I am trying to use the great circle distance approach from here: Link.
CGFloat DegreesToRadians(CGFloat degrees)
{
return degrees * M_PI / 180;
};
- (float) calculateDistanceP1:(CLLocationCoordinate2D)p1 andP2:(CLLocationCoordinate2D)p2 {
double circumference = 40000.0; // Erdumfang in km am Äquator
double distance = 0.0;
double latitude1Rad = DegreesToRadians(p1.latitude);
double longitude1Rad = DegreesToRadians(p1.longitude);
double latititude2Rad = DegreesToRadians(p2.latitude);
double longitude2Rad = DegreesToRadians(p2.longitude);
double logitudeDiff = fabs(longitude1Rad - longitude2Rad);
if (logitudeDiff > M_PI)
{
logitudeDiff = 2.0 * M_PI - logitudeDiff;
}
double angleCalculation =
acos(sin(latititude2Rad) * sin(latitude1Rad) + cos(latititude2Rad) * cos(latitude1Rad) * cos(logitudeDiff));
distance = circumference * angleCalculation / (2.0 * M_PI);
NSLog(#"%f",distance);
return distance;
}
Here is my code for getting the Pixel position:
- (CGPoint) calculatePoint:(CLLocationCoordinate2D)point {
float x_coord;
float y_coord;
CLLocationCoordinate2D x1;
CLLocationCoordinate2D x2;
x1.longitude = p.longitude;
x1.latitude = topLeft.latitude;
x2.longitude = p.longitude;
x2.latitude = bottomRight.latitude;
CLLocationCoordinate2D y1;
CLLocationCoordinate2D y2;
y1.longitude = topLeft.longitude;
y1.latitude = p.latitude;
y2.longitude = bottomRight.longitude;
y2.latitude = p.latitude;
float distanceX = [self calculateDistanceP1:x1 andP2:x2];
float distanceY = [self calculateDistanceP1:y1 andP2:y2];
float distancePX = [self calculateDistanceP1:x1 andP2:p];
float distancePY = [self calculateDistanceP1:y1 andP2:p];
x_coord = fabs(distancePX * (1024 / distanceX))-1;
y_coord = fabs(distancePY * (748 / distanceY))-1;
return CGPointMake(x_coord,y_coord);
}
x1 and x2 are the points on the longitude of p and with latitude of topLeft and bottomRight.
y1 and y2 are the points on the latitude of p and with longitude of topLeft and bottomRight.
So I got the distance between left and right on longitude of p and distance between top and bottom on latitude of p. (Needed for calculate the pixel position)
Now I calculate the distance between x1 and p (my distance between x_0 and x_p) after that I calculate the distance between y1 and p (distance between y_0 and y_p)
Last but not least the Pixel position is calculated and returned.
The Result is, that my point is on the red and NOT on the blue position:
Maybe you find any mistakes or have any suggestions for improving the accuracy.
Maybe I didn't understand your question, but shouldn't you be using the Converting Map Coordinates methods of MKMapView?
See this image
I used your co-ordinates, and simply did the following:
x_coord = 1024 * (p.longitude - topLeft.longitude)/(bottomRight.longitude - topLeft.longitude);
y_coord = 748 - (748 * (p.latitude - bottomRight.latitude)/(topLeft.latitude - bottomRight.latitude));
The red dot markes this point. For such small distances you don't really need to use great circles, and your rounding errors will be making things much more inaccurate