-
Notifications
You must be signed in to change notification settings - Fork 4
geovctrs for TRI
Michael Sumner edited this page Apr 20, 2020
·
2 revisions
library(geovctrs)
library(vctrs)
## triangles, taken from https://paleolimbot.github.io/geovctrs/articles/extending-geovctrs.html
# base constructor for developers
new_triangle <- function(x = list(x0 = geo_xy(),
x1 = geo_xy(),
x2 = geo_xy())) {
vec_assert(x$x0, geo_xy())
vec_assert(x$x1, geo_xy())
vec_assert(x$x2, geo_xy())
vctrs::new_rcrd(x, class = "triangle")
}
# convenient constructor for users
triangle <- function(x0 = geo_xy(),
x1 = geo_xy(),
x2 = geo_xy()) {
new_triangle(
vec_recycle_common(
x0 = vec_cast(x0, geo_xy()),
x1 = vec_cast(x1, geo_xy()),
x2 = vec_cast(x2, geo_xy())
) )
}
triangle_TRI <- function(x) {
if (inherits(x, "DEL")) {
x$triangle <- dplyr::filter(x$triangle, .data$visible)
}
idx <- do.call(rbind, sc_object(x)$topology_)[c(".vx0", ".vx1", ".vx2")]
XX <- sc_vertex(x)$x_
YY <- sc_vertex(x)$y_
triangle(x0 = geo_xy(XX[idx$.vx0], YY[idx$.vx0]),
x1 = geo_xy(XX[idx$.vx1], YY[idx$.vx1]),
x2 = geo_xy(XX[idx$.vx2], YY[idx$.vx2]))
}
# rcrd vectors require a format method
format.triangle <- function(x, ...) {
sprintf("<triangle: %s->%s->%s>",
format(field(x, "x0")),
format(field(x, "x1")),
format(field(x, "x2")))
}
triangle_coordinates <- function(x) {
c(
field(x, "x0"),
field(x, "x1"),
field(x, "x2")
)
}
#The easiest way to construct a geovctr is using the geo_collection() family of functions, all of which take coordinates and return a geometry vector. For a single circle, we could construct polygons like so:
triangle_polygon <- function(x) {
geo_polygon(triangle_coordinates(x)[c(1, 2, 3, 1)])
}
as_geovctr.triangle <- function(x, ...) {
x_data <- x
features <- lapply(
seq_len(vec_size(x)),
function(i) triangle_polygon(x_data[i])
)
vec_c(!!!features)
}
# create a vector of triangles
x <- triangle(geo_xy(0:5, 0:5),
geo_xy(2:7, 1:6),
geo_xy(1:6, 2:7))
x
#> <triangle[6]>
#> [1] <triangle: (0 0)->(2 1)->(1 2)> <triangle: (1 1)->(3 2)->(2 3)>
#> [3] <triangle: (2 2)->(4 3)->(3 4)> <triangle: (3 3)->(5 4)->(4 5)>
#> [5] <triangle: (4 4)->(6 5)->(5 6)> <triangle: (5 5)->(7 6)->(6 7)>
triangle_coordinates(x)
#> <geovctrs_xy[18]>
#> [1] (0 0) (1 1) (2 2) (3 3) (4 4) (5 5) (2 1) (3 2) (4 3) (5 4) (6 5) (7 6)
#> [13] (1 2) (2 3) (3 4) (4 5) (5 6) (6 7)
triangle_polygon(x)
#> <geovctrs_collection[1]>
#> [1] POLYGON (0 0)...+3
plot(as_geovctr(x))
geo_envelope(x)
#> <geovctrs_rect[6]>
#> [1] (0 0...2 2) (1 1...3 3) (2 2...4 4) (3 3...5 5) (4 4...6 6) (5 5...7 7)
geo_plot(x, lty = 1:6)
## draft conversion from silicate/anglr
library(silicate)
#>
#> Attaching package: 'silicate'
#> The following object is masked from 'package:stats':
#>
#> filter
geo_plot(triangle_TRI(TRI0(silicate::minimal_mesh)))
Created on 2020-04-20 by the reprex package (v0.3.0)
mesh_plot.triangle <- function(x, col = NA, border = NA, ..., add = FALSE) {
x0 <- field(x, "x0")
x1 <- field(x, "x1")
x2 <- field(x, "x2")
xx <- list(x = c(t(cbind(field(x0, "x"), field(x1, "x"), field(x2, "x")))),
y = c(t(cbind(field(x0, "y"), field(x1, "y"), field(x2, "y")))),
id = rep(seq_along(x), each = 3L))
if (!add) {
graphics::plot.new()
graphics::plot.window(xlim = range(xx$x, finite = TRUE), ylim = range(xx$y, finite = TRUE),
...)
}
vps <- gridBase::baseViewports()
grid::pushViewport(vps$inner, vps$figure, vps$plot)
if (!is.na(col[1])) {
xx$col <- rep(col, length.out = length(x))
}
grid::grid.polygon(xx$x, xx$y, xx$id, gp = grid::gpar(col = border, fill = xx$col),
default.units = "native")
grid::popViewport(3)
}
x <- triangle_TRI(DEL0(minimal_mesh, max_area = 0.0001))
system.time(geo_plot(x[1:100]))
user system elapsed
0.76 0.04 0.86
system.time(mesh_plot(x[order(x)], col = viridis::viridis(length(x))))
user system elapsed
0.13 0.11 0.24