Esto requiere un tipo de "cálculo de campo" en el que el valor calculado (basado en la latitud, longitud, acimut central, incertidumbre y distancia) es la forma del corbatín en lugar de un número. Debido a que dichas capacidades de cálculo de campo se hicieron mucho más difíciles en la transición de ArcView 3.x a ArcGIS 8.xy nunca se han restaurado por completo, hoy en día usamos scripts en Python, R o lo que sea: pero el proceso de pensamiento sigue siendo el mismo.
Ilustraré con R
código de trabajo . En su núcleo está el cálculo de una forma de corbatín, que por lo tanto encapsulamos como una función. La función es realmente muy simple: para generar los dos arcos en los extremos del arco, necesita trazar una secuencia a intervalos regulares (de acimut). Esto requiere la capacidad de encontrar las coordenadas (lon, lat) de un punto en función del inicio (lon, lat) y la distancia recorrida. Eso se hace con la subrutina goto
, donde ocurre todo el levantamiento aritmético pesado. El resto es solo preparar todo para aplicar goto
y luego aplicarlo.
bowtie <- function(azimuth, delta, origin=c(0,0), radius=1, eps=1) {
#
# On entry:
# azimuth and delta are in degrees.
# azimuth is east of north; delta should be positive.
# origin is (lon, lat) in degrees.
# radius is in meters.
# eps is in degrees: it is the angular spacing between vertices.
#
# On exit:
# returns an n by 2 array of (lon, lat) coordinates describing a "bowtie" shape.
#
# NB: we work in radians throughout, making conversions from and to degrees at the
# entry and exit.
#--------------------------------------------------------------------------------#
if (eps <= 0) stop("eps must be positive")
if (delta <= 0) stop ("delta must be positive")
if (delta > 90) stop ("delta must be between 0 and 90")
if (delta >= eps * 10^4) stop("eps is too small compared to delta")
if (origin[2] > 90 || origin[2] < -90) stop("origin must be in lon-lat")
a <- azimuth * pi/180; da <- delta * pi/180; de <- eps * pi/180
start <- origin * pi/180
#
# Precompute values for `goto`.
#
lon <- start[1]; lat <- start[2]
lat.c <- cos(lat); lat.s <- sin(lat)
radius.radians <- radius/6366710
radius.c <- cos(radius.radians); radius.s <- sin(radius.radians) * lat.c
#
# Find the point at a distance of `radius` from the origin at a bearing of theta.
# http://williams.best.vwh.net/avform.htm#Math
#
goto <- function(theta) {
lat1 <- asin(lat1.s <- lat.s * radius.c + radius.s * cos(theta))
dlon <- atan2(-sin(theta) * radius.s, radius.c - lat.s * lat1.s)
lon1 <- lon - dlon + pi %% (2*pi) - pi
c(lon1, lat1)
}
#
# Compute the perimeter vertices.
#
n.vertices <- ceiling(2*da/de)
bearings <- seq(from=a-da, to=a+da, length.out=n.vertices)
t(cbind(start,
sapply(bearings, goto),
start,
sapply(rev(bearings+pi), goto),
start) * 180/pi)
}
Esto está destinado a aplicarse a una tabla cuyos registros ya debe tener de alguna forma: cada uno de ellos proporciona la ubicación, el acimut, la incertidumbre (como un ángulo a cada lado) y (opcionalmente) una indicación de qué tan grande para hacer el corbata de moño. Simulemos una tabla de este tipo ubicando 1,000 bowties en todo el hemisferio norte:
n <- 1000
input <- data.frame(cbind(
id = 1:n,
lon = runif(n, -180, 180),
lat = asin(runif(n)) * 180/pi,
azimuth = runif(n, 0, 360),
delta = 90 * rbeta(n, 20, 70),
radius = 10^7/90 * rgamma(n, 10, scale=2/10)
))
En este punto, las cosas son casi tan simples como cualquier cálculo de campo. Aquí está:
shapes <- as.data.frame(do.call(rbind,
by(input, input$id,
function(d) cbind(d$id, bowtie(d$azimuth, d$delta, c(d$lon, d$lat), d$radius, 1)))))
(Las pruebas de tiempo indican que R
puede producir alrededor de 25,000 vértices por segundo. Por defecto, hay un vértice para cada grado de acimut, que el usuario puede configurar mediante el eps
argumento bowtie
).
Puede hacer un diagrama simple de los resultados en R
sí mismo como un control:
colnames(shapes) <- c("id", "x", "y")
plot(shapes$x, shapes$y, type="n", xlab="Longitude", ylab="Latitude", main="Bowties")
temp <- by(shapes, shapes$id, function(d) lines(d$x, d$y, type="l", lwd=2, col=d$id))
Para crear una salida de archivo de forma para importar a un SIG, use el shapefiles
paquete:
require(shapefiles)
write.shapefile(convert.to.shapefile(shapes, input, "id", 5), "f:/temp/bowties", arcgis=T)
Ahora puede proyectar los resultados, etc. Este ejemplo utiliza una proyección estereográfica del hemisferio norte y las pajaritas están coloreadas por cuantiles de la incertidumbre. (Si observa con mucho cuidado a 180 / -180 grados de longitud, verá dónde este SIG ha recortado las pajaritas que cruzan esta línea. Esa es una falla común con los SIG; no refleja un error en el R
código mismo).