Це вимагає свого роду "обчислення поля", при якому обчислене значення (виходячи з широти, довготи, центрального азимуту, невизначеності та відстані) - це форма боті, а не число. Оскільки такі можливості обчислення поля були набагато складнішими при переході від ArcView 3.x до ArcGIS 8.x і ніколи не були повністю відновлені, то сьогодні ми використовуємо сценарії в Python, R чи будь-що інше: але процес мислення все ще є те саме.
Я проілюструю робочим R
кодом. В його основі лежить обчислення форми бантика, яку ми, таким чином, інкапсулюємо як функцію. Функція насправді дуже проста: для генерації двох дуг на кінцях лука необхідно простежити послідовність через рівні проміжки часу (по азимуту). Для цього потрібна можливість знайти (lon, lat) координати точки на основі початкової (lon, lat) та пройденої відстані. Це робиться з підпрограмою goto
, де відбувається все важке арифметичне підняття. Решта - це просто готувати все до goto
подачі заявки, а потім застосовувати його.
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)
}
Це покликане застосувати до таблиці, записи якої ви вже повинні мати в якійсь формі: кожен з них дає розташування, азимут, невизначеність (як кут у кожну сторону) та (необов'язково) вказівку на те, наскільки великими є розмір боти. Давайте змоделюємо таку таблицю, розташувавши 1000 боутіків по всій північній півкулі:
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)
))
На даний момент, речі майже такі ж прості, як і будь-який обчислення поля. Ось:
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)))))
(Тести часу визначають, що R
може виробляти близько 25000 вершин в секунду. За замовчуванням існує одна вершина для кожного ступеня азимуту, яку можна встановити користувачем за допомогою eps
аргументу до bowtie
.)
Ви можете зробити простий графік результатів R
сам по собі як перевірку:
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))
Щоб створити вихідний файл форми для імпорту до ГІС, використовуйте shapefiles
пакет:
require(shapefiles)
write.shapefile(convert.to.shapefile(shapes, input, "id", 5), "f:/temp/bowties", arcgis=T)
Тепер ви можете спроектувати результати тощо. У цьому прикладі використовується стереографічна проекція північної півкулі, а краватки луків забарвлені квантилами невизначеності. (Якщо ви уважно подивитесь на довжину 180 / -180 градусів, то побачите, де цей ГІС вирізав зв'язки, які перетинають цю лінію. Це загальна вада з ГІС; це не відображає помилку в самому R
коді.)