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.
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.
I would like to calculate the average distance from a point to a polygon using MATLAB. The polygon is represented by a sequence of points, such as P{(0,0),(1,0),(2,0.5),(1,1),(2,2),(0,2),(0,0)}. Note that the polygon could be convex or nonconvex. To calculate the average distance between point a(-1,-1) and polygon P, I can use the equation as below
I do not know how to implement that using MATLAB. Is there any function I can use?
You can probably use this intpoly function from: https://www.mathworks.com/matlabcentral/fileexchange/62278-intpoly-f-x-y
Something like f = #(x,y) sqrt((x+1).^2 + (y+1).^2) to throw into intploy
I want to determine a point in space by geometry and I have math computations that gives me several theta values. After evaluating the theta values, I could get N 1 x 3 dimension matrix where N is the number of theta evaluated. Since I have my targeted point, I only need to decide which of the matrices is closest to the target with adequate focus on the three coordinates (x,y,z).
Take a view of the analysis in the figure below:
Fig 1: Determining Closest Point with all points having minimal error
It can easily be seen that the third matrix is closest using sum(abs(Matrix[x,y,z])). However, if the method is applied on another figure given below, obviously, the result is wrong.
Fig 2: One Point has closest values with 2-axes of the reference point
Looking at point B, it is closer to the reference point on y-,z- axes but just that it strayed greatly on x-axis.
So how can I evaluate the matrices and select the closest one to point of reference and adequate emphasis will be on error differences in all coordinates (x,y,z)?
If your results is in terms of (x,y,z), why don't evaluate the euclidean distance of each matrix you have obtained from the reference point?
Sort of matlab code:
Ref_point = [48.98, 20.56, -1.44];
Curr_point = [x,y,z];
Xd = (x-Ref_point(1))^2 ;
Yd = (y-Ref_point(2))^2 ;
Zd = (z-Ref_point(3))^2 ;
distance = sqrt(Xd + Yd + Zd);
%find the minimum distance
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.
I wanted to generate a set of coordinates distributed uniformly at random within a ball of radius R. Is there any way to do this in Matlab without for loops, in a matrix-like form?
Thanks
UPDATE:
I'm sorry for the confusion. I only need to generate n points uniformly at random over a circle of radius R, not a sphere.
the correct answer is here http://mathworld.wolfram.com/DiskPointPicking.html. The distribution is known as "Disk point picking"
I was about to mark this as a duplicate of a previous question on generating uniform distribution of points in a sphere, but I think you deserve the benefit of doubt here, as although there's a matlab script in the question, most of that thread is python.
This little function given in the question (and I'm pasting it directly from there), is what you need.
function X = randsphere(m,n,r)
% This function returns an m by n array, X, in which
% each of the m rows has the n Cartesian coordinates
% of a random point uniformly-distributed over the
% interior of an n-dimensional hypersphere with
% radius r and center at the origin. The function
% 'randn' is initially used to generate m sets of n
% random variables with independent multivariate
% normal distribution, with mean 0 and variance 1.
% Then the incomplete gamma function, 'gammainc',
% is used to map these points radially to fit in the
% hypersphere of finite radius r with a uniform % spatial distribution.
% Roger Stafford - 12/23/05
X = randn(m,n);
s2 = sum(X.^2,2);
X = X.*repmat(r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2),1,n);
To learn why you can't just use uniform random variable for all three co-ordinates as one might think is the correct way, give this article a read.
For the sake of completeness, here is some MATLAB code for a point-culling solution. It generates a set of random points within a unit cube, removes points that are outside a unit sphere, and scales the coordinate points up to fill a sphere of radius R:
XYZ = rand(1000,3)-0.5; %# 1000 random 3-D coordinates
index = (sum(XYZ.^2,2) <= 0.25); %# Find the points inside the unit sphere
XYZ = 2*R.*XYZ(index,:); %# Remove points and scale the coordinates
One key drawback to this point-culling method is that it makes it difficult to generate a specific number of points. For example, if you want to generate 1000 points within your sphere, how many do you have to create in the cube before culling them? If you scale up the number of points generated in the cube by a factor of 6/pi (i.e. the ratio of the volume of a unit cube to a unit sphere), then you can get close to the number of desired points in the sphere. However, since we're dealing with (pseudo)random numbers after all, we can never be absolutely certain we will generate enough points that fall in the sphere.
In short, if you want to generate a specific number of points, I'd try out one of the other solutions suggested. Otherwise, the point-culling solution is nice and simple.
Not sure if I understand your question correctly, but can't you just generate any random number inside a sphere by setting φ, θ and r, assigned to random numbers?