https://github.com/forestgeo/ttt/issues/33 Author: Gabriel Arellano gabriel.arellano.torres@gmail.com
# A general function to calculate distances in a n-dimensional toroid:
dist_in_torus <- function(x, lower = rep(-Inf, ncol(x)), upper = rep(Inf, ncol(x)))
{
# x: the matrix with the coordinates of the points
# lower and upper: the minimum and maximum possible values of the coordinates along each dimension
# By default, this function returns the distance in the Euclidean space
# by assuming borders infinitely apart (i.e. points in a small portion
# of an infinitely large toroid).
# The shortest distance in the toroid is the hypotenuse
# of the smallest hyper-triangle. The 'internal' distance
# is the typical distance based on the coordinates, as
# in the Euclidean space. The 'external' distance is
# crossing borders, going around. There are only
# two ways of measuring distance along each dimension.
n = ncol(x) # number of dimensions
ranges <- upper - lower # size of the n-dimensional space considered
# Internal and external cathetuses along each dimension:
internal.cats <- sapply(1:n, function(i) abs(outer(x[,i], x[,i], '-')), simplify = "array")
external.cats <- sapply(1:n, function(i) ranges[i] - internal.cats[,,i])
# The shortest cathetuses along each dimension
# define the smallest hyper-triangle:
shortest.cats <- pmin(internal.cats, external.cats)
# Application of the Pythagorean theorem across layers:
hypo <- sqrt(rowSums(shortest.cats^2, dims = 2))
return(hypo)
}
# Example
x <- data.frame(runif(10, min = 3, max = 5), runif(10, min = 13, max = 15))
d0 <- dist(x) # Euclidean distances
d1 <- dist_in_torus(x) # default behaviour
d2 <- dist_in_torus(x, lower = c(3, 13), upper = c(5, 15)) # distances in the toroid
par(mfrow = c(1, 3))
plot(x, xlim = c(3, 5), ylim = c(13, 15), xlab = "x", ylab = "y")
plot(c(d0), c(as.dist(d1)), main = "default = Euclidean = infinite toroid"); abline(0, 1)
plot(c(d0), c(as.dist(d2)), main = "finite toroid"); abline(0, 1)
.