I want to emulate the function of ntps which is in basemap.Geod class.
Its function is described as follows:
Given a single initial point and terminus point (specified by
python floats lon1,lat1 and lon2,lat2), returns a list of
longitude/latitude pairs describing npts equally spaced
intermediate points along the geodesic between the initial and
terminus points.
I want to do the same thing in cartopy, aparantly one way is to calculate the distance needed between each pair of successive coordinate and use that distance to compute coordinates from start to end point. Is there any other way to do so?
Based on cartopy's source, https://github.com/SciTools/cartopy/tree/master/lib/cartopy/geodesic
, it is clearly that no equivalent of ntps() function is available from cartopy.
However, it is not difficult to compute locations of points along a geodesic if you know the bearing from one of the end point. Here are steps that you can follow:
Use Geodesic.inverse() with input of (long, lat) of point1 and2, and get (forward_bearing, backward_bearing, geodesic_dist) as the result.
Suppose you want to get (long, lat) of a point (say 1/4 of the whole distance) along that geodesic (in 1), use Geodesic.direct() with long1, lat1, the obtained forward_bearing and geodesic_dist/4.
A better alternative is to use pyproj and forget all the above.
Related
I am searching for a (fast) way to calculate the nearest point y in a dataset to a given point x under a (x,y)-depending distance function.
My distance function has the form: d(x,y) = 1/f(x,y) * |||x-y||^2, where ||x|| denotes the standard Euclidean-norm. The function f(x,y) fulfills all necessary properties such that d(x,y) is a distance measurement i.e. positive, symmetric,...
For a "normal" distance function I could to some transformation on the data itself and use some k-nearest neighbor approaches. But for this case I could not find something useful. Does anyone have an idea?
Right now, I am using Julia for the implementation.
You should be able to use most standard spacial indexes (kd-tree, r-tree, quadtree, and their derivatives) as long as d(x,y) is "convex".
With "convex" I mean that a curve of equidistant points around P is convex. E.g. for Euclidean this is a circle, for Manhatten/Taxi distance it is a square.
This is required because these indexes usually partition the data into squares, rectangles or half-spaces (kd-tree), so they rely on calculating the minimum distance to a group of points by calculating the distance to the corner or sides of a bounding rectangle. As long as your distance function is convex (or at least not concave) then any index of these indexes should work.
Being neither great at math nor coding, I am trying to understand the output I am getting when I try to calculate the linear distance between pairs of 3D points. Essentially, I have the 3D points of a bird that is moving in a confined area towards a stationary reward. I would like to calculate the distance of the animal to the reward at each point. However, when looking online for the best way to do this, I tried several options and get different results that I'm not sure how to interpret.
Example data:
reward = [[0.381605200000000,6.00214980000000,0.596942400000000]];
animal_path = = [2.08638710671220,-1.06496059617432,0.774253689976102;2.06262715454806,-1.01019576900787,0.773933446776898;2.03912411242035,-0.954888684677576,0.773408777383975;2.01583648760496,-0.898935333316342,0.772602855030873];
distance1 = sqrt(sum(([animal_path]-[reward]).^2));
distance2 = norm(animal_path - reward);
distance3 = pdist2(animal_path, reward);
Distance 1 gives 3.33919107083497 13.9693378592353 0.353216791787775
Distance 2 gives 14.3672145652704
Distance 3 gives 7.27198528565078
7.21319284516199
7.15394253573951
7.09412041863743
Why do these all yield different values (and different numbers of values)? Distance 3 seems to make the most sense for my purposes, even though the values are too large for the dimensions of the animal enclosure, which should be something like 3 or 4 meters.
Can someone please explain this in simple terms and/or point me to something less technical and jargon-y than the Matlab pages?
There are many things mathematicians call distance. What you normally associate with distance is the eucledian distance. This is what you want in this situation. The length of the line between two points. Now to your problem. The Euclidean distance distance is also called norm (or 2-norm).
For two points you can use the norm function, which means with distance2 you are already close to a solution. The problem is only, you input all your points at once. This does not calculate the distance for each point, instead it calculates the norm of the matrix. Something of no interest for you. This means you have to call norm once for each row point on the path:
k=nan(size(animal_path,1),1)
for p=1:size(animal_path,1),
k(p)=norm(animal_path(p,:) - reward);
end
Alternatively you can follow the idea you had in distance1. The only mistake you made there, you calculated the sum for each column, where the sum of each row was needed. Simple fix, you can control this using the second input argument of sum:
distance1 = sqrt(sum((animal_path-reward).^2,2))
In matlab, I have a list of 2410 locations given by their latitude and longitude. I want to create a distance matrix in kilometres. I know how to do this in degrees but how do I do this in kilometres? I have the mapping toolbox, using 2016b. Thanks!
For example, my distance matrix in degrees looks like this:
First you need to ask your self what you mean by distance.
Do you want the euclidean distance between the points? Imagine you could tunnel through the earth from one point to the other, this is the euclidean distance between the points. To calculate this distance you need to first convert each of the lat long points to ecef points. You can do this conversion with this code (https://www.mathworks.com/matlabcentral/fileexchange/7942-covert-lat--lon--alt-to-ecef-cartesian). After you've converted each point to an ecef point you can now calculate the euclidean norm https://en.wikipedia.org/wiki/Norm_(mathematics)) between each possible pair of points.
Or do you want to calculate the distance a traveler would traverse if they were to walk along the surface of the earth. From the looks of it, this is a much more difficult problem requiring an iterative solver. Fortunately someone has already done the work of implementing an algorithm to do this for you (https://www.mathworks.com/matlabcentral/fileexchange/5379-geodetic-distance-on-wgs84-earth-ellipsoid). Note if you read the comments of this function it appears as if mathworks has already implemented a different algorithm to perform the same calculation in the mapping toolbox. To calculate the matrix you simply need to iterate over each possible pairing of lat long points and plug them into the vdist function.
Following should calculate the distance matrix for you using the vdist function above. Note I have not tested this code so you may to to correct errors.
points % assuming this is a matrix of your points [2 x N] formatted as follows
% [ lat1 , lat2, ... ]
% [ lon1 , lat2, ... ]
dist = zeros(N,N); % the resulting distance matrix
for(idx1 = 1:N)
for(idx2 = 1:N)
dist(idx1,idx2) = vdist(points(1,idx1),points(2,idx1),points(1,idx2)points(2,idx2) );
end
end
Note because the earth surface is manifold (https://en.wikipedia.org/wiki/Manifold) the results will be similar if the points are close to each other. If speed is important to you and the points are closely grouped, you may want to use the first method to calculate your distance matrix. How close together the points should be to make use of this approximation will depend on how accurate you need the results to be.
I am struggling with finding the global (or at least local minimum) of nonlinear 3-variable function S(t,x,y) defined as following with MATLAB 2016b:
Given function requires x_i, y_i, d_i, v as input variables and x, y, t are variables to be actually changed in certain range.
I found out that the MATLAB function fminsearch is quite useful when finding the local minimum, but I couldn't find the solution to find global minimum of such complicated function in the web.
The range of (x, y) is the every coordinate in the surface of Earth and t varies within short interval with the gap of approximately 100. Also, the function S is designed to take the input variables as Cartesian coordinates, not latitudes or longitudes.
I have another relevant question. Actually I have variables x_i, y_i as the form of latitudes and longitudes, not Cartesian coordinates. Thus, it is necessary that I should change those locations to Cartesian coordinates. Since four locations are concentrated in narrow region (within the latitude and longitude range less than 1 degree), I want to convert them to the Cartesian coordinates in plane by approximating that curvature is almost 0. However, I find it difficult because of lack of geometrical ability. Thus, I would be appreciated if someone could help me with this problem as well.
The following are four locations with latitudes and longitudes which I should input in S:
[lat_1, long_1]=(40.326800,-124.949200),
[lat_2, long_2]=(40.381200,-124.785300),
[lat_3, long_3]=(40.438700, -124.808500),
[lat_4, long_4]=(40.495500, -124.591800)
Currently, I wrote the function S in function_handle form like the following:
S=#(x)(((x(1)+sqrt((x(2)-m1(2,1))^2+(x(3)-m1(3,1))^2)/v)-m1(1,1))^2+((x(1)+sqrt((x(2)-m2(2,1))^2+(x(3)-m2(3,1))^2)/v)-m2(1,1))^2+((x(1)+sqrt((x(2)-m3(2,1))^2+(x(3)-m3(3,1))^2)/v)-m3(1,1))^2+((x(1)+sqrt((x(2)-m4(2,1))^2+(x(3)-m4(3,1))^2)/v)-m4(1,1))^2);
where m1,m2,m3,m4 are column vectors in the form of (t,x,y)
I need to solve a minimization problem with Matlab and I'm wondering which is the easiest solution. All the potential solutions that I've been thinking in require lot of programming effort.
Suppose that I have a lat/long coordinate point (A,B), what I need is to search for the nearest point to this one in a map of lat/lon coordinates.
In particular, the latitude and longitude arrays are two matrices of 2030x1354 elements (1km distance) and the idea is to find the unique indexes in those matrices that minimize the distance to the coordinates (A,B), i.e., to find the closest values to the given coordinates (A,B).
Any help would be very appreciated.
Thanks!
This is always a fun one :)
First off: Mohsen Nosratinia's answer is OK, as long as
you don't need to know the actual distance
you can guarantee with absolute certainty that you will never go near the polar regions
and will never go near the ±180° meridian
For a given latitude, -180° and +180° longitude are actually the same point, so simply looking at differences between angles is not sufficient. This will be more of a problem in the polar regions, since large longitude differences there will have less of an impact on the actual distance.
Spherical coordinates are very useful and practical for purposes of navigation, mapping, and that sort of thing. For spatial computations however, like the on-surface distances you are trying to compute, spherical coordinates are actually pretty cumbersome to work with.
Although it is possible to do such calculations using the angles directly, I personally don't consider it very practical: you often have to have a strong background in spherical trigonometry, and considerable experience to know its many pitfalls -- very often there are instabilities or "special points" you need to work around (the poles, for example), quadrant ambiguities you need to consider because of trig functions you've introduced, etc.
I've learned to do all this in university, but I also learned that the spherical trig approach often introduces complexity that mathematically speaking is not strictly required, in other words, the spherical trig is not the simplest representation of the underlying problem.
For example, your distance problem is pretty trivial if you convert your latitudes and longitudes to 3D Cartesian X,Y,Z coordinates, and then find the distances through the simple formula
distance (a, b) = R · arccos( a/|a| · b/|b| )
where a and b are two such Cartesian vectors on the sphere. Note that |a| = |b| = R, with R = 6371 the radius of Earth.
In MATLAB code:
% Some example coordinates (degrees are assumed)
lon = 360*rand(2030, 1354);
lat = 180*rand(2030, 1354) - 90;
% Your point of interest
P = [4, 54];
% Radius of Earth
RE = 6371;
% Convert the array of lat/lon coordinates to Cartesian vectors
% NOTE: sph2cart expects radians
% NOTE: use radius 1, so we don't have to normalize the vectors
[X,Y,Z] = sph2cart( lon*pi/180, lat*pi/180, 1);
% Same for your point of interest
[xP,yP,zP] = sph2cart(P(1)*pi/180, P(2)*pi/180, 1);
% The minimum distance, and the linear index where that distance was found
% NOTE: force the dot product into the interval [-1 +1]. This prevents
% slight overshoots due to numerical artifacts
dotProd = xP*X(:) + yP*Y(:) + zP*Z(:);
[minDist, index] = min( RE*acos( min(max(-1,dotProd),1) ) );
% Convert that linear index to 2D subscripts
[ii,jj] = ind2sub(size(lon), index)
If you insist on skipping the conversion to Cartesian and use lat/lon directly, you'll have to use the Haversine formula, as outlined on this website for example, which is also the method used by distance() from the mapping toolbox.
Now, all of this is valid for the whole Earth, provided you find the smooth spherical Earth accurate enough an approximation. If you want to include the Earth's oblateness or some higher order shape model (or God forbid, distances including terrain), you need to do far more complicated stuff. But I don't think that is your goal here :)
PS - I wouldn't be surprised that if you would write everything out that I did, you'll probably re-discover the Haversine formula. I just prefer to be able to calculate something as simple as distances along the sphere from first principles alone, rather than from some black box formula you had implanted in your head sometime long ago :)
Let Lat and Long denote latitude and longitude matrices, then
dist2=sum(bsxfun(#minus, cat(3,A,B), cat(3,Lat,Long)).^2,3);
[I,J]=find(dist2==min(dist2(:)));
I and J contain the indices in A and B that correspond to nearest point. Note that if there are multiple answers, I and J will not be scalar values, but vectors.