convert Lat/Long to X,Y Coordinates in iOS [duplicate] - ios

I am showing an image in an UIImageView and i'd like to convert coordinates to x/y values so i can show cities on this image.
This is what i tried based on my research:
CGFloat height = mapView.frame.size.height;
CGFloat width = mapView.frame.size.width;
int x = (int) ((width/360.0) * (180 + 8.242493)); // Mainz lon
int y = (int) ((height/180.0) * (90 - 49.993615)); // Mainz lat
NSLog(#"x: %i y: %i", x, y);
PinView *pinView = [[PinView alloc]initPinViewWithPoint:x andY:y];
[self.view addSubview:pinView];
which gives me 167 as x and y=104 but this example should have the values x=73 and y=294.
mapView is my UIImageView, just for clarification.
So my second try was to use the MKMapKit:
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(49.993615, 8.242493);
MKMapPoint point = MKMapPointForCoordinate(coord);
NSLog(#"x is %f and y is %f",point.x,point.y);
But this gives me some really strange values:
x = 140363776.241755 and y is 91045888.536491.
So do you have an idea what i have to do to get this working ?
Thanks so much!

To make this work you need to know 4 pieces of data:
Latitude and longitude of the top left corner of the image.
Latitude and longitude of the bottom right corner of the image.
Width and height of the image (in points).
Latitude and longitude of the data point.
With that info you can do the following:
// These should roughly box Germany - use the actual values appropriate to your image
double minLat = 54.8;
double minLong = 5.5;
double maxLat = 47.2;
double maxLong = 15.1;
// Map image size (in points)
CGSize mapSize = mapView.frame.size;
// Determine the map scale (points per degree)
double xScale = mapSize.width / (maxLong - minLong);
double yScale = mapSize.height / (maxLat - minLat);
// Latitude and longitude of city
double spotLat = 49.993615;
double spotLong = 8.242493;
// position of map image for point
CGFloat x = (spotLong - minLong) * xScale;
CGFloat y = (spotLat - minLat) * yScale;
If x or y are negative or greater than the image's size, then the point is off of the map.
This simple solution assumes the map image uses the basic cylindrical projection (Mercator) where all lines of latitude and longitude are straight lines.
Edit:
To convert an image point back to a coordinate, just reverse the calculation:
double pointLong = pointX / xScale + minLong;
double pointLat = pointY / yScale + minLat;
where pointX and pointY represent a point on the image in screen points. (0, 0) is the top left corner of the image.

Related

Angle betwee three points ios xcode

CGPoint pointA = [self.appDelegate.points[0] CGPointValue];//first point
CGPoint pointB = [self.appDelegate.points[1] CGPointValue];// second point
CGPoint pointC = [self.appDelegate.points[2] CGPointValue];//third point
CGFloat slopeAB = (pointB.y - pointA.y)/(pointB.x - pointA.x);//slope ab
CGFloat slopeBC = (pointC.y - pointB.y)/(pointC.x - pointB.x);//slope bc
self.ang=(slopeAB-slopeBC)/(1+(slopeAB)*(slopeBC));//slope
CGFloat finalAngle = atanf(self.ang);// angle tan inverse slope
CGFloat angle = (finalAngle * (180.0/M_PI));
NSLog(#"The angle is: %.2f degrees",angle);
calculated the slope of each line
calculated angle by tan inverse
Use the atan2() function. From the manual page:
#include <math.h>
double
atan2(double y, double x);
The atan2() function computes the principal value of the arc tangent of
y/x, using the signs of both arguments to determine the quadrant of the
return value.
To do this for the three points you'll need to call atan2() twice: once to find the angle of AB, and once for the angle of BC. Take the difference between these two to find the angle between AB and BC:
double angle_ab = atan2(pointA.y - pointB.y, pointA.x - pointB.x);
double angle_cb = atan2(pointC.y - pointB.y, pointC.x - pointB.x);
double angle_abc = angle_ab - angle_cb;
Note that this is assuming that B is the "center" point of the angle you're interested in. Adjust appropriately if I've assumed wrongly.

convertCoordinate toPointToView returning bad results with tilted maps

I have a UIView overlayed on a map, and I'm drawing some graphics in screen space between two of the coordinates using
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view
The problem is that when the map is very zoomed in and tilted (3D-like), the pixel position of the coordinate that is way off-screen stops being consistent. Sometimes the function returns NaN, sometimes it returns the right number and others it jumps to the other side of the screen.
Not sure how can I explain it better. Has anyone run into this?
During research have find a many solution. Any solution might be work for you.
Solution:1
int x = (int) ((MAP_WIDTH/360.0) * (180 + lon));
int y = (int) ((MAP_HEIGHT/180.0) * (90 - lat));
Solution:2
func addLocation(coordinate: CLLocationCoordinate2D)
{
// max MKMapPoint values
let maxY = Double(267995781)
let maxX = Double(268435456)
let mapPoint = MKMapPointForCoordinate(coordinate)
let normalizatePointX = CGFloat(mapPoint.x / maxX)
let normalizatePointY = CGFloat(mapPoint.y / maxY)
print(normalizatePointX)
print(normalizatePointX)
}
Solutuin:3
x = (total width of image in px) * (180 + latitude) / 360
y = (total height of image in px) * (90 - longitude) / 180
note: when using negative longitude of latitude make sure to add or subtract the negative number i.e. +(-92) or -(-35) which would actually be -92 and +35

iOS OpenGL ES 2.0 Rotate 1 Point Cartesian X Radians about Origin

I need to rotate a single point expressed in cartesian XYZ coordinates about the Z axis. The following 2 attempts are not working properly - I believe the first one is more correct..
I tried to rotate the points using the math on this website: http://farside.ph.utexas.edu/teaching/336k/newton/node153.html
// Rotate the XYZ coordinate for the pin image
if ( [satName isEqualToString:#"pin"] ) {
double x = xyz.x;
double y = xyz.y;
double radians = self.timeSinceOpenGlStarted;
x = x * cos(radians) + y * sin(radians);
y = -x * sin(radians) + y * cos(radians);
xyz.x = x;
xyz.z = y;
}
I also tried this function by extracting the points after GLKMatrix4Rotate:
// This function rotates XYZ a certain of radians about the origin and gives back XYZ
- (GLKVector4)rotateXYZCoordinates:(XYZ*)coords {
// Get the current modelview matrix
GLKMatrix4 currMat = self.effect.transform.modelviewMatrix;
// Print the coords before
NSLog(#"Before: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation Before: %f %f %f",currMat.m00,currMat.m10,currMat.m20);
// Construct the rows in the new matrix
float d = sqrt( pow(currMat.m00,2) + pow(currMat.m10,2) + pow(currMat.m20,2) );
GLKVector4 columnToInsert0 = GLKVector4Make(d, 0, 0, coords->x);
GLKVector4 columnToInsert1 = GLKVector4Make(0, d, 0, coords->y);
GLKVector4 columnToInsert2 = GLKVector4Make(0, 0, d, coords->z);
GLKVector4 columnToInsert3 = GLKVector4Make(0, 0, 0, 1);
// Build the new Matrix
GLKMatrix4 noTranslationInfo = GLKMatrix4SetRow(currMat, 0, columnToInsert0);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 1, columnToInsert1);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 2, columnToInsert2);
noTranslationInfo = GLKMatrix4SetRow(noTranslationInfo, 3, columnToInsert3);
// Throw the world translation coordinates in the matrix
noTranslationInfo.m30 = ( noTranslationInfo.m30 );
noTranslationInfo.m31 = ( noTranslationInfo.m31 );
noTranslationInfo.m32 = ( noTranslationInfo.m32 );
// Now rotate the matrix so many angles
noTranslationInfo = GLKMatrix4Rotate(noTranslationInfo, self.timeSinceOpenGlStarted, 0, 0, 1);
// Latch the output
coords->x = noTranslationInfo.m30;
coords->y = noTranslationInfo.m31;
coords->z = noTranslationInfo.m32;
// Print the coords After
NSLog(#"AFter: %f %f %f",coords->x,coords->y,coords->z);
NSLog(#"Rotation After: %f %f %f",noTranslationInfo.m00,noTranslationInfo.m10,noTranslationInfo.m20);
}
I have a globe spinning along the Z axis and a billboarded sprite specified at a specific spherical coordinate ( representing a lat/lon location ) and need the ability to have the point rotate along with the earth or not.
What am I doing wrong? How do I calculate a new X and Y coordinate ( Z is constant ) to rotate an XYZ point around the Z axis when I know the number of radians I want to rotate? Thanks!
UPDATE: Now I've tried this:
// Rotate the XYZ coordinate for the pin image
/* http://www.blitzbasic.com/Community/posts.php?topic=70536
;rotate offset around Z axis
newx# = x# * Cos#(zr#) - y# * Sin#(zr#)
newy# = x# * Sin#(zr#) + y# * Cos#(zr#)
x# = newx#
y# = newy#
;rotate offset around X axis
newy# = y# * Cos#(xr#) - z# * Sin#(xr#)
newz# = y# * Sin#(xr#) + z# * Cos#(xr#)
y# = newy#
z# = newz#
;rotate offset around Y axis
newx# = z# * Sin#(-yr#) + x# * Cos#(-yr#)
newz# = z# * Cos#(-yr#) - x# * Sin#(-yr#)
x# = newx#
z# = newz#
*/
if ( [satName isEqualToString:#"pin"] && self.shouldAnimate == YES ) {
//NSLog(#"ONE %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
double x = xyz.x;
double y = xyz.y;
double z = xyz.z;
NSLog(#"%f",self.timeSinceOpenGlStarted); // Values like: 32521.473728
double zr = self.timeSinceOpenGlStarted;
double yr = 0.0f;
double xr = 0.0f;
// Rotations must be in this order: Z then X then Y
// Rotate around Z
x = x * cos(zr) - y * sin(zr);
y = x * sin(zr) + y * cos(zr);
// Rotate around X
y = y * cos(xr) - z * sin(xr);
z = y * sin(xr) + z * cos(xr);
// Rotate around Y
x = z * sin(-yr) + x * cos(-yr);
z = z * cos(-yr) + x * sin(-yr);
// Get the coordinates back
xyz.x = x;
xyz.y = y;
xyz.z = z;
//NSLog(#"TWO %f %f %f %f",xyz.x,xyz.y,xyz.z,sqrt(pow(xyz.x, 2)+pow(xyz.y,2)+pow(xyz.z,2)));
}
The problem is that my image dances around the lat/lon it should be at - it almost does a figure 8.
I either don't understand what you want to achieve or these methods of yours are a bit strange. If you need to rotate a single point around centre (0,0,0) around Z axis (on the XY plane) then you should use something like this:
float x, y;
float currentAngle;
float radius = sqrt(x*x + y*y);
x = radius*cos(currentAngle);
y = radius*sin(currentAngle);
To make it even easier you can simply use radius (which should be constant in your case) and the angle in radians. In this case you only need last 2 lines of this snippet.
It looks like you are adding each frame to your angle. You can compute an "delta angle" just the angle to rotate from the previous frame, or to use the angle as it is now but apply the rotation to the initial orientation, not to last frame's result.

Tile to CGPoint conversion with Retina display

I have a project that uses a tilemap. I have a separate tilemap for low-res (29x29 Tilesize) and high-res (58x58). I have these methods to calculate tileCoord to position and back again.
- (CGPoint)tileCoordForPosition:(CGPoint)position {
int x = position.x / _tileMap.tileSize.width;
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
int x = (tileCoord.x * _tileMap.tileSize.width) + _tileMap.tileSize.width/2;
int y = (_tileMap.mapSize.height * _tileMap.tileSize.height) - (tileCoord.y * _tileMap.tileSize.height) - _tileMap.tileSize.height/2;
return ccp(x, y);
}
I got this from RayWenderLich and I do honeslty not understand how it works, and why it has to be so complicated. But this doesn't work when I use retina tilemaps, only on 480x320. Can someone clever come up with a way to make this work for HD? Does not have to work on low-res either, I do not plan on supporting sub-iOS 7.
I want the output to be in the low-res coordinate scale tho, as you might know, cocos2d does the resizing to HD for you. (By multiplying by two)
i think this will work
- (CGPoint)tileCoordForPosition:(CGPoint)position {
    int x = position.x/29;
    int y = ((11*29)-position.y) / 29;
    
    return ccp(x, y);
}
- (CGPoint)positionForTileCoord:(CGPoint)tileCoord {
    double x = tileCoord.x * 29 + 14.5;
    double y = (11*29) - (tileCoord.y * 29) - 14.5;
    return ccp(x, y);
}
Here you're trying to compute your map X coordinate:
int x = position.x / _tileMap.tileSize.width;
The problem here is that (as of v0.99.5-rc0, cocos2d generally uses points for positions, but CCTMXTiledMap always uses pixels for tileSize. On a low-res device, 1 point = 1 pixel, but on a Retina device, 1 point = 2 pixels. Thus on a Retina device, you need to multiply by 2.
You can use the CC_CONTENT_SCALE_FACTOR() macro to fix this:
int x = CC_CONTENT_SCALE_FACTOR() * position.x / _tileMap.tileSize.width;
Here you're trying to compute yoru map Y coordinate:
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
The extra math here is trying to account for the difference between Cocos2D's normal coordinate system and your map's flipped coordinate system. In standard Cartesian coordinates, the origin is at the lower left and Y coordinates increase as you move up. In a flipped coordinate system, the origin is at the upper left and Y coordinates increase as you move down. Thus you must subtract your position's Y coordinate from the height of the map (in scene units, which are points) to flip it to map coordinates.
The problem again is that _tileMap.tileSize is in pixels, not points. You can again fix that by using CC_CONTENT_SCALE_FACTOR():
CGFloat tileHeight = _tileMap.tileSize.height / CC_CONTENT_SCALE_FACTOR();
int y = ((_tileMap.mapSize.height * tileHeight) - position.y) / tileHeight;

Get distance between 2 latitude & longitude in iOS6+

I want to calculate the distance between 2 lat & long. I am able to calculate the distance as below
CLLocation *currentLoc = [[CLLocation alloc] initWithLatitude:-24.4132995 longitude:121.0790024];
CLLocation *restaurnatLoc = [[CLLocation alloc] initWithLatitude:-32.8310013 longitude:150.1390075];
CLLocationDistance meters = [restaurnatLoc distanceFromLocation:currentLoc];
NSLog(#"Distance between 2 geo cordinates: %.2f Meters",meters);
Now I want to get the direction from currentLocation to restaurnatLoc. For this I have below code
double DegreesToRadians(double degrees) {return degrees * M_PI / 180;};
double RadiansToDegrees(double radians) {return radians * 180/M_PI;};
-(double) bearingToLocationFromCoordinate:(CLLocation*)fromLoc toCoordinate:(CLLocation*)toLoc
{
double lat1 = DegreesToRadians(fromLoc.coordinate.latitude);
double lon1 = DegreesToRadians(fromLoc.coordinate.longitude);
double lat2 = DegreesToRadians(toLoc.coordinate.latitude);
double lon2 = DegreesToRadians(toLoc.coordinate.longitude);
double dLon = lon2 - lon1;
double y = sin(dLon) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
double radiansBearing = atan2(y, x);
return RadiansToDegrees(radiansBearing);
}
It returns bearing = 114.975752 Now how can I decide whether restaurant is in North,South,West,East,NW,NE,SW,SE from my current location ?
I get 1 solution from this link Direction based off of 2 Lat,Long points But if I consider this solution , then I have doubt on bearing 114 from my location(red circle) to restaurant (green circle) as shown below. Correct me if I am wrong.
As current location is "Western Australia" & restaurant location is "Sydney" as shown in Google Maps.
Can any body tell me whats going wrong here ? Thanks.
///////////////////////////// Update /////////////////////////////
My compass diagram is wrong. Here is the correct diagram all thanks to AlexWien
Now I am getting the correct output
your compass rose is totally wrong. have you ever looked at a compass? open the iphone compass app and look where 90Degrees is located. It is east, not west like in your graphic.
geographical direction is measured clockwise!
so 114 deg is east, which matches you expectation

Resources