Ciò richiede una sorta di "calcolo del campo" in cui il valore calcolato (basato su latitudine, longitudine, azimut centrale, incertezza e distanza) è la forma della cravatta a farfalla piuttosto che un numero. Poiché tali capacità di calcolo del campo sono state rese molto più difficili nella transizione da ArcView 3.x ad ArcGIS 8.x e non sono mai state completamente ripristinate, al giorno d'oggi utilizziamo gli script in Python, R o qualsiasi altra cosa: ma il processo di pensiero è ancora il stesso.
Illustrerò con il R
codice di lavoro . Al suo centro c'è il calcolo di una forma a papillon, che quindi incapsuliamo come una funzione. La funzione è davvero molto semplice: per generare i due archi alle estremità dell'arco, è necessario tracciare una sequenza a intervalli regolari (di azimut). Ciò richiede la capacità di trovare le coordinate (lon, lat) di un punto in base all'inizio (lon, lat) e alla distanza percorsa. Questo viene fatto con la subroutine goto
, in cui si verifica tutto il sollevamento aritmetico pesante. Il resto sta solo preparando tutto da applicare goto
e quindi applicandolo.
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)
}
Questo è destinato ad essere applicato a una tabella i cui record devono già avere in qualche forma: ognuno di essi fornisce la posizione, l'azimut, l'incertezza (come un angolo su ciascun lato) e (facoltativamente) un'indicazione di quanto sia grande la dimensione cravatta a farfalla. Simuliamo una tabella di questo tipo collocando 1.000 inchini in tutto l'emisfero settentrionale:
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)
))
A questo punto, le cose sono quasi semplici come qualsiasi calcolo di campo. Ecco qui:
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)))))
(I test di temporizzazione indicano che R
possono produrre circa 25.000 vertici al secondo. Per impostazione predefinita, esiste un vertice per ciascun grado di azimut, che può essere impostato dall'utente tramite l' eps
argomento bowtie
.)
Puoi fare una semplice trama dei risultati in R
sé come un controllo:
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))
Per creare un output dello shapefile per l'importazione in un GIS, utilizzare il shapefiles
pacchetto:
require(shapefiles)
write.shapefile(convert.to.shapefile(shapes, input, "id", 5), "f:/temp/bowties", arcgis=T)
Ora puoi proiettare i risultati, ecc. Questo esempio usa una proiezione stereografica dell'emisfero nord e i papillon sono colorati da quantili dell'incertezza. (Se osservi attentamente la longitudine di 180 / -180 gradi vedrai dove questo GIS ha tagliato i papillon che attraversano questa linea. Questo è un difetto comune con i GIS; non riflette un bug nel R
codice stesso.)