Điều này đòi hỏi một loại "tính toán trường" trong đó giá trị được tính toán (dựa trên vĩ độ, kinh độ, góc phương vị trung tâm, độ không đảm bảo và khoảng cách) là hình dạng cung chứ không phải là số. Bởi vì các khả năng tính toán trường như vậy đã trở nên khó khăn hơn nhiều trong quá trình chuyển đổi từ ArcView 3.x sang ArcGIS 8.x và chưa bao giờ được khôi phục hoàn toàn, ngày nay chúng tôi sử dụng kịch bản trong Python, R hoặc bất cứ điều gì thay vào đó: nhưng quá trình suy nghĩ vẫn là tương tự.
Tôi sẽ minh họa với R
mã làm việc . Tại cốt lõi của nó là tính toán của một hình dạng cung, do đó chúng tôi gói gọn như là một chức năng. Hàm này thực sự rất đơn giản: để tạo ra hai cung ở hai đầu cung, nó cần phải tìm ra một chuỗi theo các khoảng đều đặn (của góc phương vị). Điều này đòi hỏi khả năng tìm tọa độ (lon, lat) của một điểm dựa trên điểm bắt đầu (lon, lat) và khoảng cách đi qua. Điều đó đã được thực hiện với chương trình con goto
, nơi xảy ra tất cả các động tác nâng vật nặng. Việc còn lại chỉ là chuẩn bị mọi thứ để áp dụng goto
và sau đó áp dụng nó.
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)
}
Điều này được dự định sẽ được áp dụng cho một bảng có các bản ghi mà bạn phải có ở một số dạng: mỗi bảng cung cấp vị trí, góc phương vị, độ không chắc chắn (như một góc cho mỗi bên) và (tùy chọn) chỉ ra mức độ lớn để tạo ra cây cung. Hãy mô phỏng một bảng như vậy bằng cách đặt 1.000 cung tên trên khắp bán cầu bắc:
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)
))
Tại thời điểm này, mọi thứ gần như đơn giản như bất kỳ tính toán trường nào. Đây là:
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)))))
(Các thử nghiệm thời gian chỉ ra rằng R
có thể tạo ra khoảng 25.000 đỉnh mỗi giây. Theo mặc định, có một đỉnh cho mỗi mức phương vị, có thể xác định được người dùng thông qua eps
đối số bowtie
.)
Bạn có thể tự tạo một biểu đồ đơn giản cho kết quả R
dưới dạng kiểm tra:
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))
Để tạo đầu ra shapefile để nhập vào GIS, hãy sử dụng shapefiles
gói:
require(shapefiles)
write.shapefile(convert.to.shapefile(shapes, input, "id", 5), "f:/temp/bowties", arcgis=T)
Bây giờ bạn có thể chiếu kết quả, v.v. Ví dụ này sử dụng phép chiếu lập thể của bán cầu bắc và các dây cung được tô màu bởi các lượng tử của sự không chắc chắn. (Nếu bạn nhìn rất cẩn thận tại 180 / -180 độ kinh độ, bạn sẽ thấy nơi GIS này đã cắt bớt các nơ mà vượt qua ranh giới này Đó là một lỗ hổng phổ biến với GISes;. Nó không phản ánh một lỗi trong R
mã riêng của mình.)