--- title: "design - textures package" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{design} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Design A quad mesh on a regular grid is completely determined by a tiny recipe: the grid `dimension` (nx, ny cells), the `extent` (xmin, xmax, ymin, ymax), and the y orientation (`ydown`). Everything in textures is a view of that recipe at some level of materialization: * `quad_spec()` - the recipe itself, a plain serializable list, nothing materialized * `quad_edges()` - the unexpanded intermediate, the x and y coordinates of the cell edges as two short vectors (nx + 1 and ny + 1 values) * `quad_index()`, `quad_vertex()` - the materialized components, the 4 x (nx * ny) vertex index and the expanded vertex coordinates * `quad_mesh()`, `quad()`, `quad_texture()` - assembled 'mesh3d' objects 'mesh3d' objects are constructed directly (rgl is not required, it lives in Suggests). With rgl installed they plot with `plot3d()`, `shade3d()`, `persp3d()`, `wire3d()`, or `dot3d()`, and `as.mesh3d()` works on a quad_spec via delayed S3 registration. A 2D base graphics `plot()` method is included. ### Conventions * Default extent is the unit square, "y-up" (y begins at 0). * Quads are emitted in cell order, x fastest - the `matrix()`/`image()` convention, and raster cell order when `ydown = TRUE`. Face-indexed values (colours, `na.rm`) align with grid cell order. * Quad vertex winding is counter-clockwise, as required by rgl (see `material3d` `back` argument). * `ydown` flips the orientation so y coordinates begin at the top and count down, and rotates the index cycle so winding remains correct. * Texture coordinates are the extent-normalized vertex coordinates, so they remain valid for any mesh whose vertices lie in the extent. Mesh density (`dimension`) is independent of the pixel dimension of a texture image: a coarse mesh may carry a full-resolution image, the graphics engine interpolates within each quad. * Coordinate transformation belongs outside the core: the mesh vertex matrix is the interchange, transform it (e.g. with reproj) and the texture drapes unchanged. ### Large grids `quad_index()` returns integer storage where it fits, and transparently promotes to double storage (exact for integer values to 2^53) when the vertex count or index length exceeds the integer maximum. R subsetting and 'mesh3d' use accept double indexes natively; take care not to apply `as.integer()` to such an index. The compact spec and the edges intermediate are the escape hatch when full materialization is not wanted at all. ### Compiled code Registered via cpp11 in `src/quad-build.cpp`, callable from R as internal functions: ```C++ cpp11::integers quad_index_cpp(int nx, int ny, bool ydown) cpp11::doubles quad_index_dbl_cpp(double nx, double ny, bool ydown) cpp11::doubles quad_vertex_cpp(int nx, int ny, bool ydown, bool zh) cpp11::writable::doubles_matrix<> quad_vertex_matrix_cpp(int nx, int ny, bool ydown, bool zh) ``` ### Headers `inst/include/textures/quad.h`, namespace `quad`, installed so that other packages may generate mesh components via `LinkingTo: textures`: ```C++ cpp11::writable::integers quad_ib(int nx, int ny, bool ydown) cpp11::writable::doubles quad_ib_dbl(double nx, double ny, bool ydown) cpp11::writable::doubles quad_vb(int nx, int ny, bool ydown, bool zh) cpp11::writable::doubles_matrix<> quad_matrix_vb(int nx, int ny, bool ydown, bool zh) ``` `quad_ib` and `quad_vb` return flat vectors (4 values per quad, and interleaved x, y with optional constant z and homogeneous h), `quad_matrix_vb` returns the matrix form. ### R reference implementations `ib_index()` and `vb_vertex()` in `R/quad-Rcode.R` are pure-R versions of the index and vertex generators, kept as the executable specification - the tests pin the compiled path to them.