Constructors
PATH should take x,y DF possibly with groupings/order, so easy to build path lines/polys/points and flip to segment versions. This would be useful for crosstalk testing and straightforward trip structure
In sctrip working on sc_path.data.frame(data, x, y, time) thing with NSE.
It breaks the convention of all non-feature columns being called "name_". So we have to think about
- a system to record a mapping of names to geometries (a la aes())
- there's got to always be a geometry, unless tools to reconstruct the geometry on primitives is brought forward
the double-join is awkard but it works, is there a two-join convention of some kind?
library(dplyr)
db <- src_sqlite("db.sqlite3")
db
x <- tbl(db, "event_log_interv_nav") %>%
filter(event_type == "GENU") %>%
mutate(x = start_lon_dec_deg_interp, y = start_lat_dec_deg_interp) %>%
select(x, y, utc, event_type, waypoint) %>%
collect()
#devtools::install_github("mdsumner/sctrip")
library(sctrip)
p <- sc::PRIMITIVE(sc_path(x, x, y, utc))
## sc needs fixing here
class(p) <- c("PRIMITIVE", "sc")
plot.PRIMITIVE <- function(x, ...) {
library(ggplot2)
ggplot(x$vertex, aes(x, y)) + geom_point() +
geom_segment(data = p$segment %>% inner_join(p$vertex, c(".vertex1" = "vertex_")) %>% rename(xend = x, yend = y) %>% inner_join(p$vertex, c(".vertex0" = "vertex_")),
aes(x = x, y = y, xend = xend, yend = yend, col = segment_))
}
plot(p)
A model for sc_path:
- input a grouped table, split on those groups by the path_ value
- groups can be specified a la
sc_path(d, x, y, z, .group = g) - should we have order, within group?
sc_path(d, x, y, z, .group = g, .gorder = z)
Validation stuff must include
- geometric sense for primitives, so downstream classes apply rules for length, increasing etc.
- rules for missing/Inf
- number of dims
this will work to dump ordered segments into ggplot for a lot of data types.
https://github.com/hypertidy/silicate/issues/32
Now that we have decido, the constructor for TRI is really obvious, it's the vertex pool and the object groupings, and the triangle indexes in between. That might help define the other cases
Some experimental wrappers here: https://github.com/hypertidy/silicate/blob/d6da41740ffa1490b7603470f6ef468f3b629981/R/000_cMESH.R
I like the idea of si_ prefix for constructors, but it's for later.
See these for ideas for sf builders
https://github.com/hypertidy/silicate/issues/32
https://github.com/mdsumner/sfcc
https://github.com/SymbolixAU/geojsonsf (and anything related for sf construction)
Might as well use the sfheaders format for a df, see PATH0_from_df - could also use a grouped_df to see how x, y are organized
d <- sqrt(3)/2
df <- data.frame(
x = c(0, 1, 0.5, 0.25, 0.5, 0.75),
y = c(0, 0, d , d/2 , 0 , d/2),
group = 1L,
subgroup = c(1, 1, 1 , 2, 2, 2)
)
library(silicate)
library(anglr)
library(sf)
par(mfcol = c(3, 2))
# illegal polygon (sfheaders will auto-close, but the hole intersects its island which is SF-non-compliant)
sfx <- sfheaders::sf_polygon(df, x = "x", y = "y", linestring_id = "subgroup", polygon_id = "group")
plot(sfx$geometry, col = "grey")
## decompose and make valid with sf
sf::st_make_valid(sfx) ## 3 POLYGON in one MULTIPOLYGON
## silicate is fine {decido}
plot(TRI0(sfx), col = viridis::viridis(3))
## anglr is fine {anglr}
plot(DEL0(sfx), col = viridis::viridis(3))
## what about a crazier "hole"
df2 <- df
df2$x[df$subgroup == 2] <- df2$x[df$subgroup == 2] + c(-0.1, 0, 0.1)
df2$y[df$subgroup == 2] <- df2$y[df$subgroup == 2] + c(0, -0.1, 0)
## illegal polygon (sfheaders will auto-close, but the hole intersects its island which is SF-non-compliant)
sfx2 <- sfheaders::sf_polygon(df2, x = "x", y = "y", linestring_id = "subgroup", polygon_id = "group")
plot(sfx2$geometry, col = "grey")
## silicate can't handle
plot(df2[1:2]); plot(TRI0(sfx2), col = viridis::viridis(6), add = TRUE)
## anglr is fine
plot(DEL0(sfx2), col = viridis::viridis(6))
sf::st_make_valid(sfx2) ## 6 POLYGON in one MULTIPOLYGON

Mike's examples (he misses the need for multipolygon_id, but that only affects TRI0
polygons_df <- data.frame(
x = c(4, 8, 8, 4, 6, 7, 7, 6),
y = c(4, 4, 8, 8, 6, 6, 7, 7),
group = c(1, 1, 1, 1, 1, 1, 1, 1),
subgroup = c(1, 1, 1, 1, 2, 2, 2, 2)
)
polygons_df <- data.frame(
x = c(4, 8, 8, 4, 6, 7, 7, 6, 4.5, 5, 5, 4.5),
y = c(4, 4, 8, 8, 6, 6, 7, 7, 4.5, 4.5, 5, 5),
group = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
subgroup = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3)
)
polygons_df <- data.frame(
x = c(1, 4, 4, 1, 2, 3, 3, 2, 5, 8, 8, 5, 6, 7, 7, 6),
y = c(1, 1, 4, 4, 2, 2, 3, 3, 5, 5, 8, 8, 6, 6, 7, 7),
group = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
subgroup = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4)
)
polygons_df <- data.frame(
x = c(0, 1, 2, 2, 1, 1),
y = c(0, 1, 1, 2, 2, 1),
group = 1,
subgroup = 1
)
set.seed(1)
polygons_df <- data.frame(
x = runif(10),
y = runif(10),
group = 1,
subgroup = 1
)
# illegal polygon (sfheaders will auto-close, but the hole intersects its island which is SF-non-compliant)
sfx <- sfheaders::sf_polygon(polygons_df, x = "x", y = "y", linestring_id = "subgroup", polygon_id = "group")
plot(sfx$geometry, col = "grey")
plot(TRI0(sfx), col = viridis::viridis(3))
plot(DEL0(sfx), col = viridis::viridis(3))
e.g. for multi
polygons_df <- data.frame(
x = c(1, 4, 4, 1, 2, 3, 3, 2, 5, 8, 8, 5, 6, 7, 7, 6),
y = c(1, 1, 4, 4, 2, 2, 3, 3, 5, 5, 8, 8, 6, 6, 7, 7),
## needs to be unique to be multipolygon per sfheaders (not grouped together by subgroup)
group = c(1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2),
# group = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
subgroup = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4)
)
sfx <- sfheaders::sf_polygon(polygons_df, x = "x", y = "y", linestring_id = "subgroup", polygon_id = "group")
plot(sfx$geometry, col = "grey")
plot(TRI0(sfx), col = viridis::viridis(3))
plot(DEL0(sfx), col = viridis::viridis(3))
