This algorithm decomposes a general polygon into simple polygons and uses the “ear-clipping” algorithm to triangulate it. Polygons with holes are supported.

triangulate(x, y = NULL, z = NULL, random = TRUE, plot = FALSE, partial = NA)

## Arguments

x, y, z

Coordinates of a two-dimensional polygon in a format supported by xyz.coords. See Details for how z is handled.

random

Whether to use a random or deterministic triangulation.

plot

Whether to plot the triangulation; mainly for debugging purposes.

partial

If the triangulation fails, should partial results be returned?

## Details

Normally triangulate looks only at the x and y coordinates. However, if one of those is constant, it is replaced with the z coordinate if present.

The algorithm works as follows. First, it breaks the polygon into pieces separated by NA values in x or y. Each of these pieces should be a simple, non-self-intersecting polygon, separate from the other pieces. (Though some minor exceptions to this rule may work, none are guaranteed). The nesting of these pieces is determined.

The “outer” polygon(s) are then merged with the polygons that they immediately contain, and each of these pieces is triangulated using the ear-clipping algorithm.

Finally, all the triangulated pieces are put together into one result.

## Value

A three-by-n array giving the indices of the vertices of each triangle. (No vertices are added; only the original vertices are used in the triangulation.)

The array has an integer vector attribute "nextvert"

with one entry per vertex, giving the index of the next vertex to proceed counter-clockwise around outer polygon boundaries, clockwise around inner boundaries.

## References

See the Wikipedia article “polygon triangulation” for a description of the ear-clipping algorithm.

Duncan Murdoch

## Note

Not all inputs will succeed, even when a triangulation is possible. Generally using random = TRUE will find a successful triangulation if one exists, but it may occasionally take more than one try.

extrude3d for a solid extrusion of a polygon, polygon3d for a flat display; both use triangulate.

## Examples

theta <- seq(0, 2*pi, length.out = 25)[-25]
theta <- c(theta, NA, theta, NA, theta, NA, theta, NA, theta)
r <- c(rep(1.5, 24), NA, rep(0.5, 24), NA, rep(0.5, 24), NA, rep(0.3, 24), NA, rep(0.1, 24))
dx <- c(rep(0, 24), NA, rep(0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24))
x <- r*cos(theta) + dx
y <- r*sin(theta)
plot(x, y, type = "n")
polygon(x, y)
triangulate(x, y, plot = TRUE)

#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
#> [1,]   64   13   13   63   62   61   60   13   20    20    60    59    58    20
#> [2,]   63   65   66   62   61   60    7   20   67    68    59    58    57    69
#> [3,]   13   64   65   13   13   13   13   66   66    67     7     7     7    68
#>      [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
#> [1,]    20    57    43    20    43    56    20    42    42    55    20    42
#> [2,]    43    56    70    44    42    55    45    71    72    54    46    41
#> [3,]    69     7    69    43    70     7    44    70    71     7    45    72
#>      [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
#> [1,]    20    41    20    41    24    41    24    24    40    39    39    24
#> [2,]    47    73    24    74    48    40    49    26    39    51    38    27
#> [3,]    46    72    47    73    47    74    48    49    74    74    51    26
#>      [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
#> [1,]    54    24    53    33    38    32    53    38     7    10    31    53
#> [2,]    53    28    33    32    52    31    34    37    10    12    30    52
#> [3,]     7    27     7     7    51     7    33    52    13    13     7    34
#>      [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62]
#> [1,]    37    20    30    30    10    13    21    13    29    29    36    13
#> [2,]    36    21     4    29    11    19    22    16     3     1    35    14
#> [3,]    52    24     7     4    12    20    24    19     4     3    52    16
#>      [,63] [,64] [,65] [,66] [,67] [,68] [,69] [,70] [,71] [,72] [,73] [,74]
#> [1,]     4    16    22    29     7     1     5    24     8    17    52    14
#> [2,]     5    17    23    28     8     2     6     1     9    18    35    15
#> [3,]     7    19    24     1    10     3     7    28    10    19    34    16
#>      [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
#> [1,]   118   117    90   116   115   114   113   112   111   110   110    90
#> [2,]   117   116   119   115   114   113   112   111   110    81   109   120
#> [3,]    90    90   118    90    90    90    90    90    90    90    81   119
#>      [,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98]
#> [1,]    90    95   109    95    95    95   108   107   107    95   106    95
#> [2,]    95   121   108   122   123   124   107    80   106   101    77    98
#> [3,]   120   120    81   121   122   123    81    81    80   124    80   101
#>      [,99] [,100] [,101] [,102] [,103] [,104] [,105] [,106] [,107] [,108]
#> [1,]    98     99     95     90     99     95    106     81     87    106
#> [2,]    99    102     97     92    103     96     76     87     89    105
#> [3,]   101    101     98     95    102     97     77     90     90     76
#>      [,109] [,110] [,111] [,112] [,113] [,114] [,115] [,116] [,117] [,118]
#> [1,]    105     81     87     99     81     81     92     77     83     77
#> [2,]    104     86     88    104     83     82     93     79     85     78
#> [3,]     76     87     89    103     86     83     95     80     86     79
#>      [,119] [,120] [,121] [,122]
#> [1,]     90     99     93     83
#> [2,]     91     76     94     84
#> [3,]     92    104     95     85
#> attr(,"nextvert")
#>   [1]   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19
#>  [19]  20  21  22  23  24   1  NA  49  26  27  28  29  30  31  32  33  34  35
#>  [37]  36  37  38  39  40  41  42  43  44  45  46  47  48  NA  74  51  52  53
#>  [55]  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71
#>  [73]  72  73  NA  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91
#>  [91]  92  93  94  95  96  97  98  99  76  NA 124 101 102 103 104 105 106 107
#> [109] 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
open3d()
polygon3d(x, y, x - y, col = "red")
3D plot

{"x":{"material":{"color":"#000000","alpha":1,"lit":true,"ambient":"#000000","specular":"#FFFFFF","emission":"#000000","shininess":50,"smooth":true,"front":"filled","back":"filled","size":3,"lwd":1,"fog":true,"point_antialias":false,"line_antialias":false,"texture":null,"textype":"rgb","texmode":"modulate","texmipmap":false,"texminfilter":"linear","texmagfilter":"linear","texenvmap":false,"depth_mask":true,"depth_test":"less","isTransparent":false,"polygon_offset":[0,0],"margin":"","floating":false,"tag":"","blend":["src_alpha","one_minus_src_alpha"]},"rootSubscene":2124,"objects":{"2130":{"id":2130,"type":"triangles","material":{},"vertices":"0","colors":"2","centers":"3","normals":"1","ignoreExtent":false,"flags":32771},"2128":{"id":2128,"type":"light","vertices":[[0,0,1]],"colors":[[1,1,1,1],[1,1,1,1],[1,1,1,1]],"viewpoint":true,"finite":false},"2127":{"id":2127,"type":"background","material":{},"colors":"4","centers":"5","sphere":false,"fogtype":"none","fogscale":1,"flags":32768},"2129":{"id":2129,"type":"background","material":{"lit":false,"back":"lines"},"colors":"6","centers":"7","sphere":false,"fogtype":"none","fogscale":1,"flags":32768},"2124":{"id":2124,"type":"subscene","par3d":{"antialias":8,"FOV":30,"ignoreExtent":false,"listeners":2124,"mouseMode":{"none":"none","left":"trackball","right":"zoom","middle":"fov","wheel":"pull"},"observer":[0,0,11.59111022949219],"modelMatrix":[[1,0,0,0],[0,0.3420201539993286,0.9396926164627075,0],[0,-0.9396926164627075,0.3420201539993286,-11.59111022949219],[0,0,0,1]],"projMatrix":[[3.732050895690918,0,0,0],[0,3.732050895690918,0,0],[0,0,-3.863703489303589,-41.78461074829102],[0,0,-1,0]],"skipRedraw":false,"userMatrix":[[1,0,0,0],[0,0.3420201433256682,0.9396926207859085,0],[0,-0.9396926207859085,0.3420201433256682,0],[0,0,0,1]],"userProjection":[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],"scale":[1,1,1],"viewport":{"x":0,"y":0,"width":1,"height":1},"zoom":1,"bbox":[-1.5,1.5,-1.5,1.5,-2.121320247650146,2.121320247650146],"windowRect":[500,544,756,800],"family":"sans","font":1,"cex":1,"useFreeType":true,"fontname":"/Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/library/rgl/fonts/FreeSans.ttf","maxClipPlanes":6,"glVersion":2.1,"activeSubscene":0},"embeddings":{"viewport":"replace","projection":"replace","model":"replace","mouse":"replace"},"objects":[2129,2130,2128],"subscenes":[],"flags":33027}},"crosstalk":{"key":[],"group":[],"id":[],"options":[]},"width":480,"height":480,"buffer":{"accessors":[{"bufferView":0,"componentType":5126,"count":366,"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":366,"type":"VEC3"},{"bufferView":2,"componentType":5121,"count":1,"type":"VEC4"},{"bufferView":3,"componentType":5126,"count":122,"type":"VEC3"},{"bufferView":4,"componentType":5126,"count":1,"type":"VEC4"},{"bufferView":5,"componentType":5121,"count":1,"type":"VEC3"},{"bufferView":6,"componentType":5121,"count":1,"type":"VEC4"},{"bufferView":7,"componentType":5121,"count":1,"type":"VEC3"}],"bufferViews":[{"buffer":0,"byteLength":4392,"byteOffset":0},{"buffer":0,"byteLength":4392,"byteOffset":4392},{"buffer":0,"byteLength":4,"byteOffset":8784},{"buffer":0,"byteLength":1464,"byteOffset":8788},{"buffer":0,"byteLength":16,"byteOffset":10252},{"buffer":0,"byteLength":3,"byteOffset":10268},{"buffer":0,"byteLength":4,"byteOffset":10271},{"buffer":0,"byteLength":3,"byteOffset":10275}],"buffers":[{"byteLength":10278,"bytes":"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\nZmbmvoEFhT70tTW/mpkZv5qZmT5mZma/4+dPvyQ5WT4WG4O/4+dPvyQ5WT4WG4O/Whxcv5qZ\nGT5gQYG/mpkZv83MzD0zMzO/mpmZvgAAAACamZm+c9WevrcEnz2hlsa+ZmbmvoEFhT70tTW/\nWhxcv5qZGb70tTW/mpkZv5qZmb6amZm+c9WevrcEn72LKG6+ZmYmv6xcsT38kTy/zDkgv1XS\nxT0X9Di/ZmZmvzxuKSRmZma/Whxcv5qZGb70tTW/4+dPvyQ5Wb6amRm/mpkZv5qZmb6amZm+\nmpkZv5qZmT5mZma/MXotv8BdlD4QqXe/4+dPvyQ5WT4WG4O/c9WevrcEnz2hlsa+oZbGviQ5\nWT6amRm/ZmbmvoEFhT70tTW/Whxcv5qZGT5gQYG/echjv7cEnz0QqXe/mpkZv83MzD0zMzO/\nmpkZv5qZmb6amZm+A7kFv8BdlL6LKG6+c9WevrcEn72LKG6+c9WevrcEnz2hlsa+si2uvpqZ\nGT5/+vq+oZbGviQ5WT6amRm/4+dPvyQ5Wb6amRm/AABAv4EFhb5/+vq+mpkZv5qZmb6amZm+\nzDkgv1XSxT0X9Di/echjv7cEnz0QqXe/ZmZmvzxuKSRmZma/A7kFv8BdlL6LKG6+ZmbmvoEF\nhb7KwUK+c9WevrcEn72LKG6+ZmbmvoEFhb7KwUK+oZbGviQ5Wb4f9DO+c9WevrcEn72LKG6+\nAABAv4EFhb5/+vq+MXotv8BdlL6hlsa+mpkZv5qZmb6amZm+ZmbmvoEFhT70tTW/A7kFv8Bd\nlD7j50+/mpkZv5qZmT5mZma/oZbGviQ5Wb4f9DO+si2uvpqZGb7KwUK+c9WevrcEn72LKG6+\nMXotv8BdlD4QqXe/AABAv4EFhT5gQYG/4+dPvyQ5WT4WG4O/echjv7cEnz0QqXe/zDkgv1XS\nxT0X9Di/mpkZv83MzD0zMzO/Oc0TvzzNEz86zRM/Oc0TvzzNEz86zRM/Oc0TvzzNEz86zRM/\nOs0TvzrNEz85zRM/Os0TvzrNEz85zRM/Os0TvzrNEz85zRM/Pc0TvzbNEz87zRM/Pc0TvzbN\nEz87zRM/Pc0TvzbNEz87zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/\nOs0TvzvNEz87zRM/Os0TvzvNEz87zRM/Os0TvzvNEz87zRM/Oc0TvznNEz85zRM/Oc0TvznN\nEz85zRM/Oc0TvznNEz85zRM/Oc0TvzrNEz87zRM/Oc0TvzrNEz87zRM/Oc0TvzrNEz87zRM/\nOs0TvzrNEz85zRM/Os0TvzrNEz85zRM/Os0TvzrNEz85zRM/OM0Tvz7NEz85zRM/OM0Tvz7N\nEz85zRM/OM0Tvz7NEz85zRM/Os0TvzfNEz8+zRM/Os0TvzfNEz8+zRM/Os0TvzfNEz8+zRM/\nN80Tvz/NEz84zRM/N80Tvz/NEz84zRM/N80Tvz/NEz84zRM/Oc0Tvz3NEz84zRM/Oc0Tvz3N\nEz84zRM/Oc0Tvz3NEz84zRM/O80TvzvNEz86zRM/O80TvzvNEz86zRM/O80TvzvNEz86zRM/\nO80TvzvNEz87zRM/O80TvzvNEz87zRM/O80TvzvNEz87zRM/O80TvzrNEz86zRM/O80TvzrN\nEz86zRM/O80TvzrNEz86zRM/PM0TvzrNEz86zRM/PM0TvzrNEz86zRM/PM0TvzrNEz86zRM/\nOs0TvzrNEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/O80TvzvNEz85zRM/O80TvzvN\nEz85zRM/O80TvzvNEz85zRM/Os0TvzrNEz88zRM/Os0TvzrNEz88zRM/Os0TvzrNEz88zRM/\nN80Tvz/NEz84zRM/N80Tvz/NEz84zRM/N80Tvz/NEz84zRM/Pc0TvznNEz85zRM/Pc0TvznN\nEz85zRM/Pc0TvznNEz85zRM/Os0TvzvNEz87zRM/Os0TvzvNEz87zRM/Os0TvzvNEz87zRM/\nPs0TvzjNEz84zRM/Ps0TvzjNEz84zRM/Ps0TvzjNEz84zRM/Oc0TvzrNEz86zRM/Oc0TvzrN\nEz86zRM/Oc0TvzrNEz86zRM/O80TvzvNEz86zRM/O80TvzvNEz86zRM/O80TvzvNEz86zRM/\nO80TvznNEz87zRM/O80TvznNEz87zRM/O80TvznNEz87zRM/PM0TvzTNEz8/zRM/PM0TvzTN\nEz8/zRM/PM0TvzTNEz8/zRM/OM0Tvz7NEz85zRM/OM0Tvz7NEz85zRM/OM0Tvz7NEz85zRM/\nO80TvzzNEz86zRM/O80TvzzNEz86zRM/O80TvzzNEz86zRM/PM0TvznNEz88zRM/PM0TvznN\nEz88zRM/PM0TvznNEz88zRM/N80TvzvNEz85zRM/N80TvzvNEz85zRM/N80TvzvNEz85zRM/\nOs0TvznNEz87zRM/Os0TvznNEz87zRM/Os0TvznNEz87zRM/Os0TvzvNEz84zRM/Os0TvzvN\nEz84zRM/Os0TvzvNEz84zRM/Os0TvzvNEz86zRM/Os0TvzvNEz86zRM/Os0TvzvNEz86zRM/\nOc0Tvz3NEz87zRM/Oc0Tvz3NEz87zRM/Oc0Tvz3NEz87zRM/PM0TvzjNEz86zRM/PM0TvzjN\nEz86zRM/PM0TvzjNEz86zRM/Hc0Tv1LNEz9BzRM/Hc0Tv1LNEz9BzRM/Hc0Tv1LNEz9BzRM/\nWc0TvxbNEz8+zRM/Wc0TvxbNEz8+zRM/Wc0TvxbNEz8+zRM/G80Tv1PNEz9AzRM/G80Tv1PN\nEz9AzRM/G80Tv1PNEz9AzRM/Os0TvzvNEz86zRM/Os0TvzvNEz86zRM/Os0TvzvNEz86zRM/\nPM0TvznNEz88zRM/PM0TvznNEz88zRM/PM0TvznNEz88zRM/Ns0Tv0LNEz85zRM/Ns0Tv0LN\nEz85zRM/Ns0Tv0LNEz85zRM/Qs0TvzPNEz84zRM/Qs0TvzPNEz84zRM/Qs0TvzPNEz84zRM/\nRs0Tvy3NEz87zRM/Rs0Tvy3NEz87zRM/Rs0Tvy3NEz87zRM/Os0TvzrNEz86zRM/Os0TvzrN\nEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/\nOM0TvzvNEz86zRM/OM0TvzvNEz86zRM/OM0TvzvNEz86zRM/Oc0TvzzNEz84zRM/Oc0TvzzN\nEz84zRM/Oc0TvzzNEz84zRM/PM0TvzrNEz86zRM/PM0TvzrNEz86zRM/PM0TvzrNEz86zRM/\nOM0Tvz3NEz85zRM/OM0Tvz3NEz85zRM/OM0Tvz3NEz85zRM/PM0TvznNEz85zRM/PM0TvznN\nEz85zRM/PM0TvznNEz85zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/Os0TvzrNEz86zRM/\nOM0Tvz3NEz86zRM/OM0Tvz3NEz86zRM/OM0Tvz3NEz86zRM/Os0TvzvNEz86zRM/Os0TvzvN\nEz86zRM/Os0TvzvNEz86zRM/QM0Tvy/NEz89zRM/QM0Tvy/NEz89zRM/QM0Tvy/NEz89zRM/\nOc0Tvz3NEz87zRM/Oc0Tvz3NEz87zRM/Oc0Tvz3NEz87zRM/N80TvzvNEz87zRM/N80TvzvN\nEz87zRM/N80TvzvNEz87zRM/Pc0TvzXNEz89zRM/Pc0TvzXNEz89zRM/Pc0TvzXNEz89zRM/\nSs0Tvy3NEz83zRM/Ss0Tvy3NEz83zRM/Ss0Tvy3NEz83zRM/Os0TvznNEz88zRM/Os0TvznN\nEz88zRM/Os0TvznNEz88zRM/Ps0TvzLNEz89zRM/Ps0TvzLNEz89zRM/Ps0TvzLNEz89zRM/\nMc0Tvz7NEz9AzRM/Mc0Tvz7NEz9AzRM/Mc0Tvz7NEz9AzRM/Ns0Tv0PNEz82zRM/Ns0Tv0PN\nEz82zRM/Ns0Tv0PNEz82zRM/PM0Tv0TNEz8uzRM/PM0Tv0TNEz8uzRM/PM0Tv0TNEz8uzRM/\nNs0Tvz/NEz82zRM/Ns0Tvz/NEz82zRM/Ns0Tvz/NEz82zRM/N80TvzzNEz86zRM/N80TvzzN\nEz86zRM/N80TvzzNEz86zRM/O80TvzrNEz86zRM/O80TvzrNEz86zRM/O80TvzrNEz86zRM/\nPM0TvznNEz85zRM/PM0TvznNEz85zRM/PM0TvznNEz85zRM/O80TvznNEz87zRM/O80TvznN\nEz87zRM/O80TvznNEz87zRM/Nc0TvzXNEz9FzRM/Nc0TvzXNEz9FzRM/Nc0TvzXNEz9FzRM/\nO80TvzvNEz85zRM/O80TvzvNEz85zRM/O80TvzvNEz85zRM/Pc0TvzrNEz85zRM/Pc0TvzrN\nEz85zRM/Pc0TvzrNEz85zRM/PM0TvzjNEz88zRM/PM0TvzjNEz88zRM/PM0TvzjNEz88zRM/\nKs0Tv0XNEz8/zRM/Ks0Tv0XNEz8/zRM/Ks0Tv0XNEz8/zRM/Ns0Tv0TNEz82zRM/Ns0Tv0TN\nEz82zRM/Ns0Tv0TNEz82zRM/Os0TvznNEz86zRM/Os0TvznNEz86zRM/Os0TvznNEz86zRM/\nPc0TvzTNEz8+zRM/Pc0TvzTNEz8+zRM/Pc0TvzTNEz8+zRM/CM0Tv6zNEz/7zBM/CM0Tv6zN\nEz/7zBM/CM0Tv6zNEz/7zBM/P80Tvy7NEz9BzRM/P80Tvy7NEz9BzRM/P80Tvy7NEz9BzRM/\nPM0TvzbNEz87zRM/PM0TvzbNEz87zRM/PM0TvzbNEz87zRM/Nc0Tv0rNEz8tzRM/Nc0Tv0rN\nEz8tzRM/Nc0Tv0rNEz8tzRM/Os0TvzjNEz86zRM/Os0TvzjNEz86zRM/Os0TvzjNEz86zRM/\nPM0TvzTNEz9BzRM/PM0TvzTNEz9BzRM/PM0TvzTNEz9BzRM/Pc0Tvz7NEz81zRM/Pc0Tvz7N\nEz81zRM/Pc0Tvz7NEz81zRM/Os0TvzjNEz8+zRM/Os0TvzjNEz8+zRM/Os0TvzjNEz8+zRM/\nQc0Tv0DNEz8vzRM/Qc0Tv0DNEz8vzRM/Qc0Tv0DNEz8vzRM/P80TvzHNEz89zRM/P80TvzHN\nEz89zRM/P80TvzHNEz89zRM/N80Tvz7NEz86zRM/N80Tvz7NEz86zRM/N80Tvz7NEz86zRM/\nMs0TvzTNEz9KzRM/Ms0TvzTNEz9KzRM/Ms0TvzTNEz9KzRM/Pc0TvzXNEz87zRM/Pc0TvzXN\nEz87zRM/Pc0TvzXNEz87zRM/O80TvzrNEz84zRM/O80TvzrNEz84zRM/O80TvzrNEz84zRM/\nOs0TvzrNEz88zRM/Os0TvzrNEz88zRM/Os0TvzrNEz88zRM/M80Tv0TNEz82zRM/M80Tv0TN\nEz82zRM/M80Tv0TNEz82zRM/O80TvzfNEz8+zRM/O80TvzfNEz8+zRM/O80TvzfNEz8+zRM/\nPc0Tvy/NEz9DzRM/Pc0Tvy/NEz9DzRM/Pc0Tvy/NEz9DzRM/Os0TvzvNEz86zRM/Os0TvzvN\nEz86zRM/Os0TvzvNEz86zRM/QM0TvzrNEz80zRM/QM0TvzrNEz80zRM/QM0TvzrNEz80zRM/\nM80Tv1jNEz8izRM/M80Tv1jNEz8izRM/M80Tv1jNEz8izRM/Lc0TvzvNEz9FzRM/Lc0TvzvN\nEz9FzRM/Lc0TvzvNEz9FzRM/Oc0TvzvNEz85zRM/Oc0TvzvNEz85zRM/Oc0TvzvNEz85zRM/\nBM4TvzrMEz9vzRM/BM4TvzrMEz9vzRM/BM4TvzrMEz9vzRM/Es0Tv27NEz8wzRM/Es0Tv27N\nEz8wzRM/Es0Tv27NEz8wzRM/PM0TvzLNEz8/zRM/PM0TvzLNEz8/zRM/PM0TvzLNEz8/zRM/\nOM0Tvz3NEz84zRM/OM0Tvz3NEz84zRM/OM0Tvz3NEz84zRM/O80TvzvNEz85zRM/O80TvzvN\nEz85zRM/O80TvzvNEz85zRM/Os0TvzvNEz85zRM/Os0TvzvNEz85zRM/Os0TvzvNEz85zRM/\nQM0TvxnNEz9WzRM/QM0TvxnNEz9WzRM/QM0TvxnNEz9WzRM/Nc0Tvz/NEz85zRM/Nc0Tvz/N\nEz85zRM/Nc0Tvz/NEz85zRM/PM0TvzTNEz88zRM/PM0TvzTNEz88zRM/PM0TvzTNEz88zRM/\nN80Tvz/NEz86zRM/N80Tvz/NEz86zRM/N80Tvz/NEz86zRM/Pc0TvzfNEz88zRM/Pc0TvzfN\nEz88zRM/Pc0TvzfNEz88zRM/O80Tvz3NEz84zRM/O80Tvz3NEz84zRM/O80Tvz3NEz84zRM/\nSc0Tvy/NEz84zRM/Sc0Tvy/NEz84zRM/Sc0Tvy/NEz84zRM/Os0TvzvNEz86zRM/Os0TvzvN\nEz86zRM/Os0TvzvNEz86zRM/Oc0TvzvNEz86zRM/Oc0TvzvNEz86zRM/Oc0TvzvNEz86zRM/\nOc0TvzvNEz88zRM/Oc0TvzvNEz88zRM/Oc0TvzvNEz88zRM/OM0TvzrNEz89zRM/OM0TvzrN\nEz89zRM/OM0TvzrNEz89zRM/LM0Tv03NEz81zRM/LM0Tv03NEz81zRM/LM0Tv03NEz81zRM/\nMc0Tv0XNEz86zRM/Mc0Tv0XNEz86zRM/Mc0Tv0XNEz86zRM/P80TvzvNEz83zRM/P80TvzvN\nEz83zRM/P80TvzvNEz83zRM/Pc0TvzjNEz86zRM/Pc0TvzjNEz86zRM/Pc0TvzjNEz86zRM/\nqc0Tv0HMEz/GzRM/qc0Tv0HMEz/GzRM/qc0Tv0HMEz/GzRM/AQAAAas9qL1SrJE+vLu7vm7L\nH72m1lY+gMl+vrqWEr5E6LA+oDP6vlariLxQgQE+upYSvoY3rTxE6LA+yxSmvlariLxupSQ9\nGPtovW7LH73orzC91iOHO27LHz3orzA91iOHu3b5Q76Sqtg+plMdv2v6Ab/7YQc/M66Ev1M1\nSr8n4RM/Pguvv1BLYL8n4RM/PBa6v1eriDxupSS9GPtoPVeriDxQgQG+upYSPlyGiL5AOg+/\nJO6VPqagdb/LKQ4/OOXBv5INH75AOg+/tu3OPjDD5b2/WiK/WaIFP86mUb24+DG/TN4kP5Ng\nhL/NHgM/+u/Fv5AvjL+nAec++O/Fv1DCwDy3Az2/yglDPw+1kb+owMA+OuXBv0Db2j0Tu0K/\nexZeP5TFRT4Tu0K/eCx0P07D8z5jMTm/homZPxg1gT+Old6+e9q4P1jFij+Qf8i+POW8PzSP\nxr6/WiK/k0x8PlWUkj+eQ6m+O+W8P7yQlL/+FZY+PBa6v9QZmD+fAoO+e9q4PyfL5b64+DG/\nk0x8PhMGBr+2Az2/kPZbPoL1mj/orzC+fwuxP4L1mj/or7C9gACmP9QZmD+rp0C7KHqYP/Pq\ndD+fr98+JBMFPy+mSj9IJC8/Mw/cPeRbpr8AAIA+5lvGv8cjnb/orzC9SJ6XvxpImr9QgQG+\n7xeKvzYIOz9Cwj4/AINuvJrClL9OA06+XwR2v2DRb77MHgM/JhM/v2NPI77LKQ4/pP02v2hb\nG78Tu0K/rH4dPmF9Kj/n+k+/JDy9P2ZxMb8Tu0K/b02KPRSBpr/mMX2+19qGvwhT0z5iS5A/\nQO02v9ez3T7s2Y6/40bGP7vGBj/LKU4/IsaOvj4i4r173IE/n/6Pv153tz2gYy4/tnQXv7vG\nRr+2Az2/OzAcvVDCk7/zzhm/rbUNv+6DBD6mq6y/JDy9P+1/or92ozu/ZlwJv+pG9774Eqs/\nsuTovwAAgL5rELO/axCTP7A+tb/3QcI+L8/lvwAAAAB2o7u/dqO7P3ajO7/tf6I/1CgAwBv0\nm70n4RM/rF8nv3LEXD9mXEk/YECbPQMLY7+zT26/G0s0PbA+lT/wuA0/cMQcP7A+tT8k+PY9\nLs+lPzOuhD8zroS/M64EQDOuhD8zroQ/AAAAALNpdL9GoR2/25CtvjIpFr8kLUU/K6utv7A+\ntT/3QcI+M66EP7Ak7b4OZqC9LAvFvoDl5r5LaYe9LgvFvkrL9L4+EbK9+kbIvtJT/b6eNru9\nKobOvuUKF78+rN+9uir2vpb6Mb9zm+y9J2cUv9o+Nr8SduO9GNAZvyYSOr/iytG9y9gfv74x\nPb8gzri9+xcmvyZnP7+6M5q9riAsv9CLQL8vI3C9nokxv9CLQL9sdim9a/Q1v7N64r7LnVG9\n+kbIvlsx4L6HWQ29K4bOviZnP79PZMq8AxQ5v1sx4L6GWY28w1vXvlbjT7+ui3K9nLpAvzgP\nvr6GWY28oDm1vha84L5MNc88a6/tvlpRU7+C+xa8bPVQv8OfQL9yzyQ9uuxKv66e177PftM9\nMD8Gv3vA/r4z4gE+y9gfvyuAPb/2yFY9uuxKv9Z/Ar+UYA4++xcmv6KiGr8qpj4+K0xKvwg6\nJb838AY+FvZGv0x+Kb/nggs+Bl9Mv+bmHr+QvoM+LsZgv0jfQb+3vR0+tk5pv9DxtL4/XuY9\nYonuvuUKF79jGjS+lwjUvt6sOb9WH3o9005Jv0jfQb/7AWK+yl4Jv+ZTMr/624g+4MF2v9Pw\nw76Alzs+St4Qv3t/SL8+rN89AnVkvzp+9L5b0GO+DZaCvkIzsb5eHBY+ckH8voCAOL+PvoO+\ncELtvuMiTr+z5G09MAFdv6Dk2r5KGFa+9rBfvtTww76Alzu+J0pMvpgGLb/0/pC+Pg7Jvpss\nBr/0/pA+FqxOv0Mzsb5eHBa+J0pMvrIgP7/x/4E+VRCAv0uJNL+eNrs9H/BLv5mYmD6ZmJg+\nmZiYPgAAgD8AAAABAQEBAAAA"}]},"context":{"shiny":false,"rmarkdown":null},"vertexShader":"#line 2 1\n// File 1 is the vertex shader\n#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#endif\n\nattribute vec3 aPos;\nattribute vec4 aCol;\nuniform mat4 mvMatrix;\nuniform mat4 prMatrix;\nvarying vec4 vCol;\nvarying vec4 vPosition;\n\n#ifdef NEEDS_VNORMAL\nattribute vec3 aNorm;\nuniform mat4 normMatrix;\nvarying vec4 vNormal;\n#endif\n\n#if defined(HAS_TEXTURE) || defined (IS_TEXT)\nattribute vec2 aTexcoord;\nvarying vec2 vTexcoord;\n#endif\n\n#ifdef FIXED_SIZE\nuniform vec3 textScale;\n#endif\n\n#ifdef FIXED_QUADS\nattribute vec3 aOfs;\n#endif\n\n#ifdef IS_TWOSIDED\n#ifdef HAS_NORMALS\nvarying float normz;\nuniform mat4 invPrMatrix;\n#else\nattribute vec3 aPos1;\nattribute vec3 aPos2;\nvarying float normz;\n#endif\n#endif // IS_TWOSIDED\n\n#ifdef FAT_LINES\nattribute vec3 aNext;\nattribute vec2 aPoint;\nvarying vec2 vPoint;\nvarying float vLength;\nuniform float uAspect;\nuniform float uLwd;\n#endif\n\n#ifdef USE_ENVMAP\nvarying vec3 vReflection;\n#endif\n\nvoid main(void) {\n  \n#ifndef IS_BRUSH\n#if defined(NCLIPPLANES) || !defined(FIXED_QUADS) || defined(HAS_FOG) || defined(USE_ENVMAP)\n  vPosition = mvMatrix * vec4(aPos, 1.);\n#endif\n  \n#ifndef FIXED_QUADS\n  gl_Position = prMatrix * vPosition;\n#endif\n#endif // !IS_BRUSH\n  \n#ifdef IS_POINTS\n  gl_PointSize = POINTSIZE;\n#endif\n  \n  vCol = aCol;\n  \n// USE_ENVMAP implies NEEDS_VNORMAL\n\n#ifdef NEEDS_VNORMAL\n  vNormal = normMatrix * vec4(-aNorm, dot(aNorm, aPos));\n#endif\n\n#ifdef USE_ENVMAP\n  vReflection = normalize(reflect(vPosition.xyz/vPosition.w, \n                        normalize(vNormal.xyz/vNormal.w)));\n#endif\n  \n#ifdef IS_TWOSIDED\n#ifdef HAS_NORMALS\n  /* normz should be calculated *after* projection */\n  normz = (invPrMatrix*vNormal).z;\n#else\n  vec4 pos1 = prMatrix*(mvMatrix*vec4(aPos1, 1.));\n  pos1 = pos1/pos1.w - gl_Position/gl_Position.w;\n  vec4 pos2 = prMatrix*(mvMatrix*vec4(aPos2, 1.));\n  pos2 = pos2/pos2.w - gl_Position/gl_Position.w;\n  normz = pos1.x*pos2.y - pos1.y*pos2.x;\n#endif\n#endif // IS_TWOSIDED\n  \n#ifdef NEEDS_VNORMAL\n  vNormal = vec4(normalize(vNormal.xyz/vNormal.w), 1);\n#endif\n  \n#if defined(HAS_TEXTURE) || defined(IS_TEXT)\n  vTexcoord = aTexcoord;\n#endif\n  \n#if defined(FIXED_SIZE) && !defined(ROTATING)\n  vec4 pos = prMatrix * mvMatrix * vec4(aPos, 1.);\n  pos = pos/pos.w;\n  gl_Position = pos + vec4(aOfs*textScale, 0.);\n#endif\n  \n#if defined(IS_SPRITES) && !defined(FIXED_SIZE)\n  vec4 pos = mvMatrix * vec4(aPos, 1.);\n  pos = pos/pos.w + vec4(aOfs,  0.);\n  gl_Position = prMatrix*pos;\n#endif\n  \n#ifdef FAT_LINES\n  /* This code was inspired by Matt Deslauriers' code in \n   https://mattdesl.svbtle.com/drawing-lines-is-hard */\n  vec2 aspectVec = vec2(uAspect, 1.0);\n  mat4 projViewModel = prMatrix * mvMatrix;\n  vec4 currentProjected = projViewModel * vec4(aPos, 1.0);\n  currentProjected = currentProjected/currentProjected.w;\n  vec4 nextProjected = projViewModel * vec4(aNext, 1.0);\n  vec2 currentScreen = currentProjected.xy * aspectVec;\n  vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec;\n  float len = uLwd;\n  vec2 dir = vec2(1.0, 0.0);\n  vPoint = aPoint;\n  vLength = length(nextScreen - currentScreen)/2.0;\n  vLength = vLength/(vLength + len);\n  if (vLength > 0.0) {\n    dir = normalize(nextScreen - currentScreen);\n  }\n  vec2 normal = vec2(-dir.y, dir.x);\n  dir.x /= uAspect;\n  normal.x /= uAspect;\n  vec4 offset = vec4(len*(normal*aPoint.x*aPoint.y - dir), 0.0, 0.0);\n  gl_Position = currentProjected + offset;\n#endif\n  \n#ifdef IS_BRUSH\n  gl_Position = vec4(aPos, 1.);\n#endif\n}","fragmentShader":"#line 2 2\n// File 2 is the fragment shader\n#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#endif\nvarying vec4 vCol; // carries alpha\nvarying vec4 vPosition;\n#if defined(HAS_TEXTURE) || defined (IS_TEXT)\nvarying vec2 vTexcoord;\nuniform sampler2D uSampler;\n#endif\n\n#ifdef HAS_FOG\nuniform int uFogMode;\nuniform vec3 uFogColor;\nuniform vec4 uFogParms;\n#endif\n\n#if defined(IS_LIT) && !defined(FIXED_QUADS)\nvarying vec4 vNormal;\n#endif\n\n#if NCLIPPLANES > 0\nuniform vec4 vClipplane[NCLIPPLANES];\n#endif\n\n#if NLIGHTS > 0\nuniform mat4 mvMatrix;\n#endif\n\n#ifdef IS_LIT\nuniform vec3 emission;\nuniform float shininess;\n#if NLIGHTS > 0\nuniform vec3 ambient[NLIGHTS];\nuniform vec3 specular[NLIGHTS]; // light*material\nuniform vec3 diffuse[NLIGHTS];\nuniform vec3 lightDir[NLIGHTS];\nuniform bool viewpoint[NLIGHTS];\nuniform bool finite[NLIGHTS];\n#endif\n#endif // IS_LIT\n\n#ifdef IS_TWOSIDED\nuniform bool front;\nvarying float normz;\n#endif\n\n#ifdef FAT_LINES\nvarying vec2 vPoint;\nvarying float vLength;\n#endif\n\n#ifdef USE_ENVMAP\nvarying vec3 vReflection;\n#endif\n\nvoid main(void) {\n  vec4 fragColor;\n#ifdef FAT_LINES\n  vec2 point = vPoint;\n  bool neg = point.y < 0.0;\n  point.y = neg ? (point.y + vLength)/(1.0 - vLength) :\n                 -(point.y - vLength)/(1.0 - vLength);\n#if defined(IS_TRANSPARENT) && defined(IS_LINESTRIP)\n  if (neg && length(point) <= 1.0) discard;\n#endif\n  point.y = min(point.y, 0.0);\n  if (length(point) > 1.0) discard;\n#endif // FAT_LINES\n  \n#ifdef ROUND_POINTS\n  vec2 coord = gl_PointCoord - vec2(0.5);\n  if (length(coord) > 0.5) discard;\n#endif\n  \n#if NCLIPPLANES > 0\n  for (int i = 0; i < NCLIPPLANES; i++)\n    if (dot(vPosition, vClipplane[i]) < 0.0) discard;\n#endif\n    \n#ifdef FIXED_QUADS\n    vec3 n = vec3(0., 0., 1.);\n#elif defined(IS_LIT)\n    vec3 n = normalize(vNormal.xyz);\n#endif\n    \n#ifdef IS_TWOSIDED\n    if ((normz <= 0.) != front) discard;\n#endif\n\n#ifdef IS_LIT\n    vec3 eye = normalize(-vPosition.xyz/vPosition.w);\n    vec3 lightdir;\n    vec4 colDiff;\n    vec3 halfVec;\n    vec4 lighteffect = vec4(emission, 0.);\n    vec3 col;\n    float nDotL;\n#ifdef FIXED_QUADS\n    n = -faceforward(n, n, eye);\n#endif\n    \n#if NLIGHTS > 0\n    for (int i=0;i<NLIGHTS;i++) {\n      colDiff = vec4(vCol.rgb * diffuse[i], vCol.a);\n      lightdir = lightDir[i];\n      if (!viewpoint[i])\n        lightdir = (mvMatrix * vec4(lightdir, 1.)).xyz;\n      if (!finite[i]) {\n        halfVec = normalize(lightdir + eye);\n      } else {\n        lightdir = normalize(lightdir - vPosition.xyz/vPosition.w);\n        halfVec = normalize(lightdir + eye);\n      }\n      col = ambient[i];\n      nDotL = dot(n, lightdir);\n      col = col + max(nDotL, 0.) * colDiff.rgb;\n      col = col + pow(max(dot(halfVec, n), 0.), shininess) * specular[i];\n      lighteffect = lighteffect + vec4(col, colDiff.a);\n    }\n#endif\n    \n#else // not IS_LIT\n    vec4 colDiff = vCol;\n    vec4 lighteffect = colDiff;\n#endif\n    \n#ifdef IS_TEXT\n    vec4 textureColor = lighteffect*texture2D(uSampler, vTexcoord);\n#endif\n    \n#ifdef HAS_TEXTURE\n\n// These calculations use the definitions from \n// https://docs.gl/gl3/glTexEnv\n\n#ifdef USE_ENVMAP\n    float m = 2.0 * sqrt(dot(vReflection, vReflection) + 2.0*vReflection.z + 1.0);\n    vec4 textureColor = texture2D(uSampler, vReflection.xy / m + vec2(0.5, 0.5));\n#else\n    vec4 textureColor = texture2D(uSampler, vTexcoord);\n#endif\n\n#ifdef TEXTURE_rgb\n\n#if defined(TEXMODE_replace) || defined(TEXMODE_decal)\n    textureColor = vec4(textureColor.rgb, lighteffect.a);\n#endif \n\n#ifdef TEXMODE_modulate\n    textureColor = lighteffect*vec4(textureColor.rgb, 1.);\n#endif\n\n#ifdef TEXMODE_blend\n    textureColor = vec4((1. - textureColor.rgb) * lighteffect.rgb, lighteffect.a);\n#endif\n\n#ifdef TEXMODE_add\n    textureColor = vec4(lighteffect.rgb + textureColor.rgb, lighteffect.a);\n#endif\n\n#endif //TEXTURE_rgb\n        \n#ifdef TEXTURE_rgba\n\n#ifdef TEXMODE_replace\n// already done\n#endif \n\n#ifdef TEXMODE_modulate\n    textureColor = lighteffect*textureColor;\n#endif\n\n#ifdef TEXMODE_decal\n    textureColor = vec4((1. - textureColor.a)*lighteffect.rgb) +\n                     textureColor.a*textureColor.rgb, \n                     lighteffect.a);\n#endif\n\n#ifdef TEXMODE_blend\n    textureColor = vec4((1. - textureColor.rgb) * lighteffect.rgb,\n                    lighteffect.a*textureColor.a);\n#endif\n\n#ifdef TEXMODE_add\n    textureColor = vec4(lighteffect.rgb + textureColor.rgb,\n                    lighteffect.a*textureColor.a);\n#endif\n    \n#endif //TEXTURE_rgba\n    \n#ifdef TEXTURE_alpha\n#if defined(TEXMODE_replace) || defined(TEXMODE_decal)\n    textureColor = vec4(lighteffect.rgb, textureColor.a);\n#endif \n\n#if defined(TEXMODE_modulate) || defined(TEXMODE_blend) || defined(TEXMODE_add)\n    textureColor = vec4(lighteffect.rgb, lighteffect.a*textureColor.a);\n#endif\n \n#endif\n    \n// The TEXTURE_luminance values are not from that reference    \n#ifdef TEXTURE_luminance\n    float luminance = dot(vec3(1.,1.,1.),textureColor.rgb)/3.;\n\n#if defined(TEXMODE_replace) || defined(TEXMODE_decal)\n    textureColor = vec4(luminance, luminance, luminance, lighteffect.a);\n#endif \n\n#ifdef TEXMODE_modulate\n    textureColor = vec4(luminance*lighteffect.rgb, lighteffect.a);\n#endif\n\n#ifdef TEXMODE_blend\n    textureColor = vec4((1. - luminance)*lighteffect.rgb,\n                        lighteffect.a);\n#endif\n\n#ifdef TEXMODE_add\n    textureColor = vec4(luminance + lighteffect.rgb, lighteffect.a);\n#endif\n\n#endif // TEXTURE_luminance\n \n    \n#ifdef TEXTURE_luminance_alpha\n    float luminance = dot(vec3(1.,1.,1.),textureColor.rgb)/3.;\n\n#if defined(TEXMODE_replace) || defined(TEXMODE_decal)\n    textureColor = vec4(luminance, luminance, luminance, textureColor.a);\n#endif \n\n#ifdef TEXMODE_modulate\n    textureColor = vec4(luminance*lighteffect.rgb, \n                        textureColor.a*lighteffect.a);\n#endif\n\n#ifdef TEXMODE_blend\n    textureColor = vec4((1. - luminance)*lighteffect.rgb,\n                        textureColor.a*lighteffect.a);\n#endif\n\n#ifdef TEXMODE_add\n    textureColor = vec4(luminance + lighteffect.rgb, \n                        textureColor.a*lighteffect.a);\n\n#endif\n\n#endif // TEXTURE_luminance_alpha\n    \n    fragColor = textureColor;\n\n#elif defined(IS_TEXT)\n    if (textureColor.a < 0.1)\n      discard;\n    else\n      fragColor = textureColor;\n#else\n    fragColor = lighteffect;\n#endif // HAS_TEXTURE\n    \n#ifdef HAS_FOG\n    // uFogParms elements: x = near, y = far, z = fogscale, w = (1-sin(FOV/2))/(1+sin(FOV/2))\n    // In Exp and Exp2: use density = density/far\n    // fogF will be the proportion of fog\n    // Initialize it to the linear value\n    float fogF;\n    if (uFogMode > 0) {\n      fogF = (uFogParms.y - vPosition.z/vPosition.w)/(uFogParms.y - uFogParms.x);\n      if (uFogMode > 1)\n        fogF = mix(uFogParms.w, 1.0, fogF);\n      fogF = fogF*uFogParms.z;\n      if (uFogMode == 2)\n        fogF = 1.0 - exp(-fogF);\n      // Docs are wrong: use (density*c)^2, not density*c^2\n      // https://gitlab.freedesktop.org/mesa/mesa/-/blob/master/src/mesa/swrast/s_fog.c#L58\n      else if (uFogMode == 3)\n        fogF = 1.0 - exp(-fogF*fogF);\n      fogF = clamp(fogF, 0.0, 1.0);\n      gl_FragColor = vec4(mix(fragColor.rgb, uFogColor, fogF), fragColor.a);\n    } else gl_FragColor = fragColor;\n#else\n    gl_FragColor = fragColor;\n#endif // HAS_FOG\n    \n}","players":[],"webGLoptions":{"preserveDrawingBuffer":true}},"evals":[],"jsHooks":[]}