The as.mesh3d()
generic function converts various objects to
mesh3d objects. Methods are added to support a variety of
spatial formats, which will include triangles or quads according to their
inherent form. For quad-types the argument triangles
can be specified to
generate triangles from quads. The majority of conversions are done by model
functions in the silicate package, and anglr adds models DEL()
, DEL0()
,
and QUAD()
.
The mesh3d format is the rgl workhorse behind plot3d(), wire3d(), persp3d() and dot3d().'
A method for a numeric matrix is included, as are methods for sf, sp, raster, RTriangle, and silicate types. and for a matrix.
# S3 method for TRI as.mesh3d( x, z, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for TRI0 as.mesh3d( x, z, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for ARC as.mesh3d( x, triangles = TRUE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for BasicRaster as.mesh3d( x, triangles = TRUE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces", max_triangles = NULL ) # S3 method for QUAD as.mesh3d( x, triangles = FALSE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for triangulation as.mesh3d(x, ...) # S3 method for sfc as.mesh3d( x, triangles = FALSE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for sf as.mesh3d( x, triangles = FALSE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for Spatial as.mesh3d( x, triangles = FALSE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for matrix as.mesh3d( x, triangles = FALSE, smooth = FALSE, normals = NULL, texcoords = NULL, ..., keep_all = TRUE, image_texture = NULL, meshColor = "faces" ) # S3 method for sc as.mesh3d(x, ...)
x | a surface-alike, a matrix, or spatial object from raster, sp, sf, trip, or silicate |
---|---|
z | numeric vector or raster object (see details) |
smooth | Whether to average normals at vertices for a smooth appearance. |
normals | User-specified normals at each vertex. Requires |
texcoords | Texture coordinates at each vertex. |
... | arguments collected and passed to |
keep_all | whether to keep non-visible triangles |
image_texture | an rgb object to texture the surface |
meshColor | how should colours be interpreted? 'vertices' or 'faces', for more details see rgl::tmesh3d. |
triangles | for quad input types, the quads may optionally be split into triangles |
max_triangles | limit on triangles to create, passed to terrainmeshr |
When converting a matrix to mesh3d it is considered to be quad-based (area
interpretation) within xmin = 0, xmax = nrow(x), ymin = 0, ymax = ncol(x)
.
Note that this differs from the [0, 1, 0, 1]
interpretation of image()
,
but shares its orientation. Raster-types from the raster package are
interpreted in the t(ranspose), y-flip
orientation used by
plot(raster::raster(matrix))
.
The conversion function anglr::as.mesh3d()
consolidates code from quadmesh
and angstroms packages where the basic facilities were developed. The
function as.mesh3d() is imported from rgl and re-exported,
and understands all of the surface types from sf, sp, raster, and silicate,
and can accept a raw matrix as input.
When creating a surface mesh there is an optional z
argument to extract
elevation values from a raster, and/or an image_texture
argument to drape
an image from a raster RGB object onto the surface. Map projections are
automatically resolved to the coordinate system of the x
argument.
We support conversion to mesh for strictly linear types such as sf 'POLYGON',
'MULTIPOLYGON', 'MULTILINESTRING', 'LINESTRING' and their sp counterparts
'SpatialPolygons' and 'SpatialLines'. Even polygons are only implicit
surfaces and so conversion and plotting functions try to reflect this
inherent nature as much as possible. A mesh is inherently a surface, and so
the method for polygons or lines will first call a surface-generating
function, silicate::TRI0()
or DEL0()
in order to created the required
primitives, while plot3d() will not do this. The key goal is
flexibility, and so we can call a meshing function
as.mesh3d() (does conversion) or
persp3d() (a plot function, but requires conversion to
surface) and they will choose an interpretation. An non-formal guideline is
to use the cheapest method possible, i.e. silicate::TRI0()
.
Much of the above is open for discussion, so please get in touch! Use the issues tab or ping me on twitter to clarify or discuss anything.
z
The 'z' argument can be a constant value or a vector of values to be used for each vertex. Alternatively, it may be a spatial raster object from which 'z' values are derived. If not set, the vertex 'z_' value from TRI/TRI0 is used, otherwise z = 0' is assumed.
Please see the documentation for rgl textures in
vignette("rgl", package = "rgl")
.
The most important detail is that the $material$color
property of
a mesh3d
not be set to "black" ("#000000" or equivalent), or it will not be
visible at all. The only way to add a texture in mesh3d is as a PNG file
on-disk, so anglr functions take an in-memory object and create the file if
needed.
sf <- silicate::minimal_mesh #sf <- silicate::inlandwaters x <- silicate::TRI(sf) library(rgl) clear3d(); plot3d(x); view3d(phi = -10) ## simple convention to carry feature colours sf$color_ <- c("firebrick", "dodgerblue") clear3d(); plot3d(silicate::TRI(sf)); view3d(phi = -10) # material properties for $material are collected in ... # and will override the 'color_' mech x$object$color_ <- "black" clear3d(); plot3d(as.mesh3d(x, color = rainbow(14))) ## we cannot assume TRI triangles relate to features simply ## but sometimes it does (always does for TRI0) cols <- c("black", "grey")[c(rep(1, 12), c(2, 2))] clear3d(); plot3d(as.mesh3d(x, color = cols)) ## smear by vertices meshColor cols <- c("black", "grey") clear3d(); plot3d(as.mesh3d(x, color = cols), meshColor = "vertices") ## other material properties clear3d() plot3d(as.mesh3d(x, color = cols, specular = "black"), meshColor = "vertices") clear3d() plot3d(as.mesh3d(x, color = cols, front = "lines", lwd = 5), meshColor = "vertices") clear3d() plot3d(as.mesh3d(x, color = viridis::viridis(20), alpha = 0.3), meshColor = "faces") clear3d() plot3d(as.mesh3d(x, color = viridis::viridis(5), alpha = 0.3), meshColor = "vertices") # TRI0 - index is stored structurally, not relations x0 <- silicate::TRI0(sf) clear3d(); plot3d(x0); view3d(phi = -10) # (TRI0 - it *is* guaranteed that triangle order is native) clear3d(); plot3d(as.mesh3d(x0, color = rainbow(14))) ## arbitrarily drape polygons over raster r <- raster::setExtent(raster::raster(volcano), raster::extent(-0.1, 1.1, -0.1, 1.1)) clear3d();shade3d(as.mesh3d(DEL(silicate::minimal_mesh, max_area = 0.001), z =r)) aspect3d(1, 1, 0.5) # \donttest{ library(rgl) ## get sf extent ext <- sf_extent(silicate::inlandwaters) r1 <- raster::setExtent(raster::raster(volcano), ext) clear3d();shade3d(as.mesh3d(DEL(silicate::inlandwaters, max_area = 1e9), z =r1)) aspect3d(1, 1, .2) ## fake news rgl::wire3d(as.mesh3d(r1)) # }