In the past, in MATLAB, I've calculated the index of a point given its lat and lon using a great circle distance calculation. I'll share my code with you. I'm fairly stumped as to what the equivalent function in R would look like or whether on exists? I've found some code that shows the distance between two points, but none that help me to index my data.
This is my MATLAB code!
%% Define latlon grid and coordinates (lon follows lat)
lon_grid = transpose([40.1 40.12 40.14; 40.3 40.32 40.34; 40.5 40.52 40.54]);
lat_grid = transpose([30 30.2 30.4;30.02 30.22 30.42; 30.04 30.24 30.44]);
coord = [30.4125 40.4043];
%% Compute great circle distance
dist = distance('gc',coord(1),coord(2),lat_grid,lon_grid);
%% Retrieve index of minimum distance
[value,array_index] = min(distance(:));
[i,j] = ind2sub(size(dist),array_index);
The "dist" calculation is sort of the party piece here. You should be able to use the provided code to reproduce the results and see what I'm hoping to achieve in R.
Again, what might a comparable function in R be given I have the following:
A grid of latitude points
A grid of longitude points
Two points, in degrees, for the latitude and longitude of my position.
maybe this works:
library(geoshpere)
dist<-apply(coord, 1, FUN=function(p) distHaversine(p, lonlat_matrix))
Related
I want to know the fastest algorithms for obtaining the cartesian distances between each point in a SpatialPointsDataFrame (X) and either (a) the closest point in a second SpatialPointsDataFrame (Y), or (b) the closest line segment in a SpatialLinesDataFrame (Y). So this is basically 2 questions, with perhaps the same answer.
For the lines, I know I can use dist2Line(X,Y, distfun=distGeo) but this is insanely slow. I also tried using nncross, after converting both X and Y to ppp objects, as below. This is did NOT work; heat mapping the new distance measure showed that it does not radiate from Y.
X_ppp <- as(X, "ppp")
Y_psp <- as(Y, "psp")
distR <- nncross(X_ppp,Y_ppp,what="dist",k=1)
X$dist2road <- distR
For lines, I also tried using gDistance(X,Y) but was met with the error, for i=1,2: Spatial object i is not projected; GEOS expects planar coordinates. I think this is because I'm using lat-lon, and it needs a true projection. But all the files i'm working with are lat-lon, and I'm not sure how to choose and specify a projection (for tanzania) w/out coping it from another file.
For points, again using the nncross approach resulted in definitely wrong distances. (In each the point and line case, is this because the output vector is not ordered in the same way that the points within X are? If so, I see now way of outputting an ID for the point within X.)
Also for points, this knn code below did work. But it's clearly not in cartesian distance, and so I'd like to convert it or find some other algorithm that provides cartesian distance.
knn.results = knn(data=coordinates(market.shp),
query=coordinates(tzprice.shp), k=1)
knn.results <- data.frame(knn.results)
tzprice.shp$dist2market <- knn.results[,2]
Basically, my hope is to find the fastest algorithm for each purpose (distance to nearest point, distance to nearest line), with output either in cartesian distance or convertible to cartesian distance. Thanks!
Somebody pointed me towards one possible answer for finding the cartesian distance between each point in a SpatialPointsDataFrame (X) and the closest point in a second SpatialPointsDataFrame (let's call it Y). So that's the first half of my question... perhaps there's a faster method out there, but this way is quite fast, and it DOES return answers in Km, at least if proj=longlat.
tree <- createTree(coordinates(Y))
inds <- knnLookup(tree, newdat=coordinates(X), k=1)
distkm <- sapply(seq_len(nrow(inds)), function(i) spDists(X[i, ], Y[inds[i, ],]))
Still looking for an algorithm that (quickly) finds meters/km from each point in X to the nearest line in a SpatialLinesDataFrame.
It is well known that the Haversine formula is a useful mechanism in which to calculate distances between geographic coordinates. Obviously, there are certain packages in R which provider further refinements; accounting for the ellipsoidal nature of the earth.
What I cannot find, however, is any method for finding the straight-line distance between NED coordinates: that is, latitude, longitude and depth.
This type of distance calculation is essential for research on events which occur deep under oceans, or under the earth's crust in general.
Is anyone aware of a method to assist with this type of distance calculation on a sphere? On the earth? If not, does anyone have any ideas what the best trigonometric approach to this problem would be?
Linear distances are much easier to compute in a Cartesian coordinate system, so the first step is to convert your NED coordinates (i.e. long-lat-height) coordinates to some such system. In the open source world, PROJ4's "geocent" projection, which gives locations in meters in an orthogonal x-y-z coordinate system, is a good choice.
Simon Urbanek's proj4 package provides a good lightweight means of accomplishing that conversion. To demonstrate it's use, I'll write a little wrapper function that takes two points in NED coordinates and computes their separation in meters. (The one complication is that the ptransform() expects its latitude and longitude coordinate in radians; hence the divisions by 180/pi in the function's first and second lines.)
library(proj4)
findDist <- function(x=c(0,0,0), y=c(0,0,0)) {
x <- matrix(x/c(180/pi, 180/pi, 1), ncol=3)
y <- matrix(y/c(180/pi, 180/pi, 1), ncol=3)
xx <- ptransform(x, src.proj="+proj=longlat +ellps=WGS84",
dst.proj="+proj=geocent +ellps=WGS84")
yy <- ptransform(y, src.proj="+proj=longlat +ellps=WGS84",
dst.proj="+proj=geocent +ellps=WGS84")
sqrt(sum((yy-xx)^2))
}
## A sanity check. (Find distance between two points at 0°N 0°E, one on the
## surface and one 100m below the surface (i.e. at a height of -100m).)
findDist(c(0,0,0), c(0,0,-100))
## [1] 100
## Distance from North to South Pole
findDist(c(0,90,0), c(0,-90,0))
## [1] 12713505
## Diameter of the earth at its equator
findDist(c(0,0,0), c(180,0,0))
## [1] 12756274
You can use Matlab function ecefOffset to compute distance between two geographical locations in 3D.
https://www.mathworks.com/help/map/ref/ecefoffset.html
I’m ashamed bothering you with a stupid (but very necessary to me) question. I’ve a bunch of lat/lon points distributed almost randomly within a rectangle of ca. two x three degrees (latitude x longitude).
I need to calculate the maximum distance to the second nearest neighbor as well as the maximum distance to the farthest neighbor. I calculated these using package spatstat,
d2 <- max(nndist(data[,2:3], k = 2)
dn <- max(nndist(data[,2:3], k=(nrow(data))-1))
, respectively, and the distances obtained were 0.3 to 4.2.
I need these distances in kilometers.
So, I supposed that distances provided by nndist where expressed in radians.
So, if θ = a /r, where θ is the subtended angle in radians, a is arc length, and r is Earth radius), then, to calculate a the equations becomes: a = θr.
However, the distances transformed in such a way ranged from:
a = 6371 * 0.3 = 1911.3, and
a= 6371 * 4.2 = 2650.2
This is evidently wrong; since the maximum distance measured using – for example – Qgis between the farthest points is just 480 km…
Can anybody indicate me where am I mistaken?
Thanks a lot in advance!!!
nndist is simply calculating the euclidean distance. It does no unit conversion. As such you have given it values in "degrees", and thus it will return a value whose units are degrees. (not radians).
Thus
6371*0.3*pi/180 = 33.36
will give an approximation of the distance between these points.
A better approach would be to use great circle distances (eg in geosphere or gstat packages or to project the lat/long coordinates onto an appropriate map projection. (rgdal::spTransform will do this) and then nndist will calculate your distances in metres.
I have a set of latitudes and longitudes , so this is the data for an animal as it moves in time. what i want to do is to calculate turning angle, that is by what angle it turns between every movement. so say i have point 1, point 2 and point 3 with latitude and longitude value corresponding to each point(animal moves from point 1 to point 2 to point 3 and so on) and i want to calculate the angle between these 3 points, point 2 being the middle point. what should i do? my OS is windows and i am using R for analysis.
so here is my sample data:
longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863
they are in decimal degrees
Using the function trackAzimuth in maptools:
library(maptools)
trackAngle <- function(xy) {
angles <- abs(c(trackAzimuth(xy), 0) -
c(0, rev(trackAzimuth(xy[nrow(xy):1, ]))))
angles <- ifelse(angles > 180, 360 - angles, angles)
angles[is.na(angles)] <- 180
angles[-c(1, length(angles))]
}
The trackAzimuth function is a simple loop wrapper around gzAzimuth. See ?gzAzimuth for references on calculating directions on the sphere.
Using your data:
x <- read.table(text = "longitude latitude
36.89379547 0.290166977
36.89384037 0.290194109
36.88999724 0.286821044
36.88708721 0.288339411
36.88650313 0.29010232
36.88563203 0.289939416
36.88545224 0.290924863", header = TRUE)
trackAngle(as.matrix(x))
[1] 10.12946 111.17211 135.88514 97.73801 89.74684
EDIT: I had to remove first/last angles from the function, something I was doing after the fact with this function elsewhere. Should be right now. :)
Also, the packages adehabitatLT and argosfilter contain functions to calculate track directions and angles.
Your data points vary over only a small range. We can look at one small patch of Earth's surface and pretend it's flat, two dimensional. You have to figure out the scale of how many km, meters, miles, whatever your favorite unit is, corresponds to one degree of latitude, and for one degree of longitude. The latter depends on latitude - it'll be the same as the scale for latitude when near the equator, but if you are standing within arm's length of the north pole, one step will take you through fifty degrees. Set up x,y coordinates where x=0 is at longitude 36.88000, and y=0 is latitude 0.29000.
So, now you have a series of (x,y) points. Take the differences from each point to the next: P2-P1, P3-P2, etc. These could be called "displacement vectors" but other terms may be used in other fields than where i'm from. Call them V1, V2, etc. Use dot products and norms: dot(V1,V2) = magnitude(V1)*magnitude(V2)*cos(a) where a is the angle by which V2 deviates from the direction of V1. Repeat for V3 and V2, and so on.
R has all the tools to do this, but I don't know enough syntax of R to give examples.
I have data with associated longitudes and latitudes. How do I get a variogram for this data based on the great-circle distances between the points?
This simple example has all the data on the equator:
require(geoR)
long <- seq(-179, 180)
x <- sin(pi * long / 180) + rnorm(length(long))
V <- variog(data=x, coords=cbind(long, 0))
# variog: computing omnidirectional variogram
plot(V)
The first and last points are actually only 1 degree apart, but my naive attempt results in variog thinking they're separated by 359 degrees.
You should use the Semi-variogram from nmle. It allows you to specify a distance matrix, which you can trivially work out for yourself.
From a post on R-sig-geo (mailing list dedicated to spatial data in R) I seem to remember that there are no ready-to-go functions in R that support great circle distances:
http://r-sig-geo.2731867.n2.nabble.com/Great-Circle-distances-in-Automap-Gstat-td6863940.html
My suggestion would be to project your data and than perform interpolation on the projected data.