Это требует своего рода «вычисления поля», в котором вычисленное значение (на основе широты, долготы, центрального азимута, неопределенности и расстояния) представляет собой форму бабочки, а не число. Поскольку при переходе от 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
может производить около 25 000 вершин в секунду. По умолчанию для каждой степени азимута существует одна вершина, которую можно задать с помощью eps
аргумента to 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
коде.)