Draw circle using latitude and longitude - matlab

I want to plot a latitude and longitude using matlab. Using that latitude and longitude as center of the circle, I want to plot a circle of radius 5 Nm.
r = 5/60;
nseg = 100;
x = 25.01;
y = 55.01;
theta = 0 : (2 * pi / nseg) : (2 * pi);
pline_x = r * cos(theta) + x;
pline_y = r * sin(theta) + y;
hold all
geoshow(pline_x, pline_y)
geoshow(x, y)
The circle does not look of what I expected.

Drawing a circle on earth is more complex that it looks like.
Drawing a line or a poly line is simple, because the vertices are defined.
Not so on circle.
a circle is defined by all points having the same distance from center (in meters! not in degrees!!!)
Unfortuantley lat and lon coordinates have not the same scale.
(The distance between two degrees of latidtude is always approx. 111.3 km, while for longitude this is only true at the equator. At the poles the distance between two longitudes approach zero. In Europe the factor is about 0.6. (cos(48deg))
There are two solution, the first is more universal, usefull for nearly all problems.
convert spherical coordinate (of circle center) to cartesian plane with unit = 1m, using a transformation (e.g equidistant transformation, also called equirectangular transf., this transformation works with the cos(centerLat) compensation factor)
calculate points (e.g circle points) in x,y plane using school mathematics.
transform all (x,y) points back to spherical (lat, lon) coordinates, using the inverse transformation of point 1.
Other solution
1. write a function which draws an ellipse in defined rectangle (all cartesian x,y)
2. define bounding of the circle to draw:
2a: calculate north-south diameter of circle/ in degrees: this a bit tricky: the distance is define in meters, you need a transformation to get the latitudeSpan: one degrees of lat is approx 111.3 km (eart circumence / 360.0): With this meters_per_degree value calc the N-S disatcne in degrees.
2b: calculate E-W span in degrees: now more tricky: calculate like 2a, but now divide by cos(centerLatitude) to compensate that E-W distances need more degrees when moving north to have the same meters.
Now draw ellipseInRectangle using N-S and E_W span for heigh and width.
But a circle on a sphere looks on the projected monitor display (or paper) only like a circle in the center of the projection. This shows:
Tissot's Error Ellipse

Related

How to correctly find UV on sphere

I have a sphere and a texture for it.
Texture consist of 16 tiles of zoom = 2 from OSM. Tile size is 256x256.
At top and bottom I added space to cover area in ranges [90, 85.0511] and [-85.0511, -90], proportionally. So texture size was 1024x1083.
I also tried texture without these two spaces, its size was 1024x1024 (map tiles only).
The problem is that after UV mapping on Y-axis objects are smaller on equator and bigger on poles.
There are two types of formulas
u = (lon + 180) / 360; // lon = [-180, 180]
v = (lat + 90) / 180; // lat = [-85.0511, 85.0511]
----
u = Math.atan2(z, x) / (2 * Math.PI) + 0.5; // x, y, z are vertex coordinates
v = Math.asin(y) / Math.PI + 0.5;
I tried all 8 variations: two textures, two u-formulas and two v-formulas.
The result is like on image above, or worse.
What am I doing wrong? Is it about texture, or UV-formulas, or something else?
P.S.: for poles (vertices in lat range = [-90, -85.0511], [85.0511, 90]) in fragment shader I don't use color from texture, but just solid color
OSM uses the Web Mercator projection. See also on OSM wiki.
The conversion from world (x,y,z) to texture (u,v) coordinates would be:
lon = atan2(y, x)
lat = atan2(z, sqrt(x*x+y*y))
u = (lon + pi)/(2*pi)
v = (log(tan(lat/2 + pi/4)) + pi)/(2*pi)
(I assume that z points north like in WGS-84 and all coordinates are right-handed.)
This projection doesn't cover the entire sphere: as the latitude approaches the poles, the v coordinate blows up to infinity. Therefore extending the map to the north or south direction is not going to be helpful.
Instead keep the original square 1024x1024 texture and render a texture mapped sphere capped at the ±85.051129° latitute (that's where v = 0,1) using the above coordinate mapping.
Alternatively (and this is more in-line with Web Mercator spirit), render each tile regular in the UV coordinates, and calculate the XYZ coordinates by reversing the above transformation.

Problem to converting km to geographical coordinates

I have some questions about converting kilometers to geographical coordinates.
As you can see figure attached, the left one is trajectory interms of kilometers. I entered geographical coordinates and calculate trajectory as kilometers. For my calculations I need to convert degrees to kilometers. I used this code:
LAT=[41.030503; 41.048334; 41.071551 ]*pi/180;
LON=[28.999000; 29.037494; 29.052138 ]*pi/180;
for i=1:length(LAT)-1
psi_coordinate(i,1) = atan2( sin (LON(i+1)-LON(i)) * cos (LAT(i+1)) , cos (LAT(i)) *sin (LAT(i+1)) - sin (LAT(i)) * cos (LAT(i+1)) * cos (LON(i+1)-LON(i)) );
a=(sin((LAT(i+1)-LAT(i))/2))^2+cos(LAT(i))*cos(LAT(i+1))*(sin((LON(i+1)-LON(i))/2))^2;
c=2*atan2(sqrt(a),sqrt(1-a));
d(i,1)=R*c;
pos_x(i+1,1)=pos_x(i,1)+d(i,1)*cos(psi_coordinate(i,1)); %convert to kilometer
pos_y(i+1,1)=pos_y(i,1)+d(i,1)*sin(psi_coordinate(i,1)); %convert to kilometer
distance_h(i,1)=sqrt(((LAT(i+1)-LAT(i))^2)+((LON(i+1)-LON(i))^2))*1000 ; %kilometer
end
distance=sum(d);
pos_x=pos_x*1000; %convert to meter
pos_y=pos_y*1000; %convert to meter
pos_x and pos_y are ploted as circle at the figure (left).
After I calculate ship trajectory, I need to convert them degrees again.
If I use "km2deg" command I obtained my coordinates as given figure (right) and the code that I used is:
ydeg=LON(1)*180/pi+km2deg(y/1000);
xdeg=LAT(1)*180/pi+km2deg(x/1000);
But as you can see the blue line (ship trajectory) is not close to the desired path as figure given left. Normally it should be the same trend for these two plot. Because all I do is here is just converting the units. I guess I have some troubles to used "km2deg" command.
Do you have any suggestions to convert my points correctly from km to deg?

Incorrect angle detected between two planes

I want to calculate the angle between 2 planes, Reference plane and Plane1. When I feed the X,Y,Z co-ordinates of pointCloud to the function plane_fit.m (by Kevin Mattheus Moerman), I get the coefficients:
reference_plane_coeff: [-0.13766204 -0.070385590 130.69409]
Plane1_coeff: [0.0044337390 -0.0013548643 95.890228]
Next, I find the intersection of both planes, separately on the XZ plane and get a line equation; ref_line_XZ and plane1_line_XZ respectively. For this, I make the second coefficient 0. (Is this right?)
Aref = reference_plane_coeff(1);
Cref = reference_plane_coeff(3);
ref_line_XZ = [Aref Cref];
Arun = Plane1_coeff(1);
Crun = Plane1_coeff(3);
plane1_line_XZ = [Arun Crun];
angle_XZ = acos( dot(ref_line_XZ,plane1_line_XZ ) / (norm(ref_line_XZ) * norm(plane1_line_XZ )) )
I get the angle_XZ value as 0.0012 rad. i.e. 0.0685 degrees
When I plot these planes on a graph and view it, the angle seems to be much more than 0.0012 degrees. I'm talking about the angle made by the two lines after intersection of both planes with the XZ plane.
What am I doing wrong?
Also, when I tried to find angle between its normals, using:
angle_beta_deg = acosd( dot(reference_plane_coeff,Plane1_coeff) / (norm(reference_plane_coeff) * norm(Plane1_coeff)) )
I got the angle as 0.0713.
On visual inspection of both planes' plots and manually calculating from the plot, angle_XZ should be around 9 degrees.
plane_fit.m (by Kevin Mattheus Moerman)

How to draw real world coordinates rotated relative to the device around a center coordinate?

I'm working on a simple location-aware game where the current location of the user is shown on a game map, as well as the locations of other players around him. It's not using MKMapView but a custom game map with no streets.
How can I translate the other lat/long coordinates of other players into CGPoint values to represent them in the world scale game map with a fixed scale like 50 meters = 50 points in screen, and orient all the points such that the user can see in which direction he would have to go to reach another player?
The key goal is to generate CGPoint values for lat/long coordinates for a flat top-down view, but orient the points around the users current location similar to the orient map feature (the arrow) of Google Maps so you know where is what.
Are there frameworks which do the calculations?
first you have to transform lon/lat to cartesian x,y in meters.
next is the direction in degrees to your other players. the direction is dy/dx where dy = player2.y to me.y, same for dx. normalize dy and dx by this value by dividing by distance between playerv2 and me.
you receive
ny = dy / sqrt(dx*dx + dy*dy)
nx = dx / sqrt(dx*dx + dy*dy)
multipl with 50. now you have a point 50 m in direction of the player2:
comp2x = 50 * nx;
comp2y = 50 * ny;
now center the map on me.x/me.y. and apply the screen to meter scale
You want MKMapPointForCoordinate from MapKit. This converts from latitude-longitude pairs to a flat surface defined by an x and y. Take a look at the documentation for MKMapPoint which describes the projection. You can then scale and rotate those x,y pairs into CGPoints as needed for your display. (You'll have to experiment to see what scaling factors work for your game.)
To center the points around your user, just subtract the value of their x and y position (in MKMapPoints) from the points of all other objects. Something like:
MKMapPoint userPoint = MKMapPointForCoordinate(userCoordinate);
MKMapPoint otherObjectPoint = MKMapPointForCoordinate(otherCoordinate);
otherObjectPoint.x -= userPoint.x; // center around your user
otherObjectPoint.y -= userPoint.y;
CGPoint otherObjectCenter = CGPointMake(otherObjectPoint.x * 0.001, otherObjectPoint.y * 0.001);
// Using (50, 50) as an example for where your user view is placed.
userView.center = CGPointMake(50, 50);
otherView.center = CGPointMake(50 + otherObjectCenter.x, 50 + otherObjectCenter.y);

Draw Camera Range with Postgis

i am working on some camera data. I have some points which consist of azimuth, angle, distance, and of course coordinate field attributes. In postgresql postgis I want to draw shapes like this with functions.
how can i draw this pink range shape?
at first should i draw 360 degree circle then extracting out of my shape... i dont know how?
I would create a circle around the point(x,y) with your radius distance, then use the info below to create a triangle that has a larger height than the radius.
Then using those two polygons do an ST_Intersection between the two geometries.
NOTE: This method only works if the angle is less than 180 degrees.
Note, that if you extend the outer edges and meet it with a 90 degree angle from the midpoint of your arc, you have a an angle, and an adjacent side. Now you can SOH CAH TOA!
Get Points B and C
Let point A = (x,y)
To get the top point:
point B = (x + radius, y + (r * tan(angle)))
to get the bottom point:
point C = (x + radius, y - (r * tan(angle)))
Rotate your triangle to you azimouth
Now that you have the triangle, you need to rotate it to your azimuth, with a pivot point of A. This means you need point A at the origin when you do the rotation. The rotation is the trickiest part. Its used in computer graphics all the time. (Actually, if you know OpenGL you could get it to do the rotation for you.)
NOTE: This method rotates counter-clockwise through an angle (theta) around the origin. You might have to adjust your azimuth accordingly.
First step: translate your triangle so that A (your original x,y) is at 0,0. Whatever you added/subtracted to x and y, do the same for the other two points.
(You need to translate it because you need point A to be at the origin)
Second step: Then rotate points B and C using a rotation matrix. More info here, but I'll give you the formula:
Your new point is (x', y')
Do this for points B and C.
Third step: Translate them back to the original place by adding or subtracting. If you subtracted x last time, add it this time.
Finally, use points {A,B,C} to create a triangle.
And then do a ST_Intersection(geom_circle,geom_triangle);
Because this takes a lot of calculations, it would be best to write a program that does all these calculations and then populates a table.
PostGIS supports curves, so one way to achieve this that might require less math on your behalf would be to do something like:
SELECT ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')
This describes a sector with an origin at 0,0, a radius of 10 degrees (geographic coordinates), and an opening angle of 45°.
Wrapping that with additional functions to convert it from a true curve into a LINESTRING, reduce the coordinate precision, and to transform it into WKT:
SELECT ST_AsText(ST_SnapToGrid(ST_CurveToLine(ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')), 0.01))
Gives:
This requires a few pieces of pre-computed information (the position of the centre, and the two adjacent vertices, and one other point on the edge of the segment) but it has the distinct advantage of actually producing a truly curved geometry. It also works with segments with opening angles greater than 180°.
A tip: the 7.071 x and y positions used in the example can be computed like this:
x = {radius} cos {angle} = 10 cos 45 ≈ 7.0171
y = {radius} sin {angle} = 10 sin 45 ≈ 7.0171
Corner cases: at the antimeridian, and at the poles.