UNPKG

terriajs-tiff-imagery-provider

Version:

Load GeoTIFF/COG(Cloud optimized GeoTIFF) on Cesium

2,730 lines 124 kB
import { Color, WebMercatorTilingScheme, Rectangle, Math as Math$1, Cartesian3, Cartographic, Credit, Event, defined, Cartesian2, GeographicTilingScheme, DeveloperError, ImageryLayerFeatureInfo } from 'terriajs-cesium';
import { Pool, fromBlob, fromUrl } from 'geotiff';

const colorscales = {
  viridis: new Uint8Array([68, 1, 84, 255, 68, 2, 86, 255, 69, 4, 87, 255, 69, 5, 89, 255, 70, 7, 90, 255, 70, 8, 92, 255, 70, 10, 93, 255, 70, 11, 94, 255, 71, 13, 96, 255, 71, 14, 97, 255, 71, 16, 99, 255, 71, 17, 100, 255, 71, 19, 101, 255, 72, 20, 103, 255, 72, 22, 104, 255, 72, 23, 105, 255, 72, 24, 106, 255, 72, 26, 108, 255, 72, 27, 109, 255, 72, 28, 110, 255, 72, 29, 111, 255, 72, 31, 112, 255, 72, 32, 113, 255, 72, 33, 115, 255, 72, 35, 116, 255, 72, 36, 117, 255, 72, 37, 118, 255, 72, 38, 119, 255, 72, 40, 120, 255, 72, 41, 121, 255, 71, 42, 122, 255, 71, 44, 122, 255, 71, 45, 123, 255, 71, 46, 124, 255, 71, 47, 125, 255, 70, 48, 126, 255, 70, 50, 126, 255, 70, 51, 127, 255, 70, 52, 128, 255, 69, 53, 129, 255, 69, 55, 129, 255, 69, 56, 130, 255, 68, 57, 131, 255, 68, 58, 131, 255, 68, 59, 132, 255, 67, 61, 132, 255, 67, 62, 133, 255, 66, 63, 133, 255, 66, 64, 134, 255, 66, 65, 134, 255, 65, 66, 135, 255, 65, 68, 135, 255, 64, 69, 136, 255, 64, 70, 136, 255, 63, 71, 136, 255, 63, 72, 137, 255, 62, 73, 137, 255, 62, 74, 137, 255, 62, 76, 138, 255, 61, 77, 138, 255, 61, 78, 138, 255, 60, 79, 138, 255, 60, 80, 139, 255, 59, 81, 139, 255, 59, 82, 139, 255, 58, 83, 139, 255, 58, 84, 140, 255, 57, 85, 140, 255, 57, 86, 140, 255, 56, 88, 140, 255, 56, 89, 140, 255, 55, 90, 140, 255, 55, 91, 141, 255, 54, 92, 141, 255, 54, 93, 141, 255, 53, 94, 141, 255, 53, 95, 141, 255, 52, 96, 141, 255, 52, 97, 141, 255, 51, 98, 141, 255, 51, 99, 141, 255, 50, 100, 142, 255, 50, 101, 142, 255, 49, 102, 142, 255, 49, 103, 142, 255, 49, 104, 142, 255, 48, 105, 142, 255, 48, 106, 142, 255, 47, 107, 142, 255, 47, 108, 142, 255, 46, 109, 142, 255, 46, 110, 142, 255, 46, 111, 142, 255, 45, 112, 142, 255, 45, 113, 142, 255, 44, 113, 142, 255, 44, 114, 142, 255, 44, 115, 142, 255, 43, 116, 142, 255, 43, 117, 142, 255, 42, 118, 142, 255, 42, 119, 142, 255, 42, 120, 142, 255, 41, 121, 142, 255, 41, 122, 142, 255, 41, 123, 142, 255, 40, 124, 142, 255, 40, 125, 142, 255, 39, 126, 142, 255, 39, 127, 142, 255, 39, 128, 142, 255, 38, 129, 142, 255, 38, 130, 142, 255, 38, 130, 142, 255, 37, 131, 142, 255, 37, 132, 142, 255, 37, 133, 142, 255, 36, 134, 142, 255, 36, 135, 142, 255, 35, 136, 142, 255, 35, 137, 142, 255, 35, 138, 141, 255, 34, 139, 141, 255, 34, 140, 141, 255, 34, 141, 141, 255, 33, 142, 141, 255, 33, 143, 141, 255, 33, 144, 141, 255, 33, 145, 140, 255, 32, 146, 140, 255, 32, 146, 140, 255, 32, 147, 140, 255, 31, 148, 140, 255, 31, 149, 139, 255, 31, 150, 139, 255, 31, 151, 139, 255, 31, 152, 139, 255, 31, 153, 138, 255, 31, 154, 138, 255, 30, 155, 138, 255, 30, 156, 137, 255, 30, 157, 137, 255, 31, 158, 137, 255, 31, 159, 136, 255, 31, 160, 136, 255, 31, 161, 136, 255, 31, 161, 135, 255, 31, 162, 135, 255, 32, 163, 134, 255, 32, 164, 134, 255, 33, 165, 133, 255, 33, 166, 133, 255, 34, 167, 133, 255, 34, 168, 132, 255, 35, 169, 131, 255, 36, 170, 131, 255, 37, 171, 130, 255, 37, 172, 130, 255, 38, 173, 129, 255, 39, 173, 129, 255, 40, 174, 128, 255, 41, 175, 127, 255, 42, 176, 127, 255, 44, 177, 126, 255, 45, 178, 125, 255, 46, 179, 124, 255, 47, 180, 124, 255, 49, 181, 123, 255, 50, 182, 122, 255, 52, 182, 121, 255, 53, 183, 121, 255, 55, 184, 120, 255, 56, 185, 119, 255, 58, 186, 118, 255, 59, 187, 117, 255, 61, 188, 116, 255, 63, 188, 115, 255, 64, 189, 114, 255, 66, 190, 113, 255, 68, 191, 112, 255, 70, 192, 111, 255, 72, 193, 110, 255, 74, 193, 109, 255, 76, 194, 108, 255, 78, 195, 107, 255, 80, 196, 106, 255, 82, 197, 105, 255, 84, 197, 104, 255, 86, 198, 103, 255, 88, 199, 101, 255, 90, 200, 100, 255, 92, 200, 99, 255, 94, 201, 98, 255, 96, 202, 96, 255, 99, 203, 95, 255, 101, 203, 94, 255, 103, 204, 92, 255, 105, 205, 91, 255, 108, 205, 90, 255, 110, 206, 88, 255, 112, 207, 87, 255, 115, 208, 86, 255, 117, 208, 84, 255, 119, 209, 83, 255, 122, 209, 81, 255, 124, 210, 80, 255, 127, 211, 78, 255, 129, 211, 77, 255, 132, 212, 75, 255, 134, 213, 73, 255, 137, 213, 72, 255, 139, 214, 70, 255, 142, 214, 69, 255, 144, 215, 67, 255, 147, 215, 65, 255, 149, 216, 64, 255, 152, 216, 62, 255, 155, 217, 60, 255, 157, 217, 59, 255, 160, 218, 57, 255, 162, 218, 55, 255, 165, 219, 54, 255, 168, 219, 52, 255, 170, 220, 50, 255, 173, 220, 48, 255, 176, 221, 47, 255, 178, 221, 45, 255, 181, 222, 43, 255, 184, 222, 41, 255, 186, 222, 40, 255, 189, 223, 38, 255, 192, 223, 37, 255, 194, 223, 35, 255, 197, 224, 33, 255, 200, 224, 32, 255, 202, 225, 31, 255, 205, 225, 29, 255, 208, 225, 28, 255, 210, 226, 27, 255, 213, 226, 26, 255, 216, 226, 25, 255, 218, 227, 25, 255, 221, 227, 24, 255, 223, 227, 24, 255, 226, 228, 24, 255, 229, 228, 25, 255, 231, 228, 25, 255, 234, 229, 26, 255, 236, 229, 27, 255, 239, 229, 28, 255, 241, 229, 29, 255, 244, 230, 30, 255, 246, 230, 32, 255, 248, 230, 33, 255, 251, 231, 35, 255, 253, 231, 37, 255]),
  inferno: new Uint8Array([0, 0, 4, 255, 1, 0, 5, 255, 1, 1, 6, 255, 1, 1, 8, 255, 2, 1, 10, 255, 2, 2, 12, 255, 2, 2, 14, 255, 3, 2, 16, 255, 4, 3, 18, 255, 4, 3, 20, 255, 5, 4, 23, 255, 6, 4, 25, 255, 7, 5, 27, 255, 8, 5, 29, 255, 9, 6, 31, 255, 10, 7, 34, 255, 11, 7, 36, 255, 12, 8, 38, 255, 13, 8, 41, 255, 14, 9, 43, 255, 16, 9, 45, 255, 17, 10, 48, 255, 18, 10, 50, 255, 20, 11, 52, 255, 21, 11, 55, 255, 22, 11, 57, 255, 24, 12, 60, 255, 25, 12, 62, 255, 27, 12, 65, 255, 28, 12, 67, 255, 30, 12, 69, 255, 31, 12, 72, 255, 33, 12, 74, 255, 35, 12, 76, 255, 36, 12, 79, 255, 38, 12, 81, 255, 40, 11, 83, 255, 41, 11, 85, 255, 43, 11, 87, 255, 45, 11, 89, 255, 47, 10, 91, 255, 49, 10, 92, 255, 50, 10, 94, 255, 52, 10, 95, 255, 54, 9, 97, 255, 56, 9, 98, 255, 57, 9, 99, 255, 59, 9, 100, 255, 61, 9, 101, 255, 62, 9, 102, 255, 64, 10, 103, 255, 66, 10, 104, 255, 68, 10, 104, 255, 69, 10, 105, 255, 71, 11, 106, 255, 73, 11, 106, 255, 74, 12, 107, 255, 76, 12, 107, 255, 77, 13, 108, 255, 79, 13, 108, 255, 81, 14, 108, 255, 82, 14, 109, 255, 84, 15, 109, 255, 85, 15, 109, 255, 87, 16, 110, 255, 89, 16, 110, 255, 90, 17, 110, 255, 92, 18, 110, 255, 93, 18, 110, 255, 95, 19, 110, 255, 97, 19, 110, 255, 98, 20, 110, 255, 100, 21, 110, 255, 101, 21, 110, 255, 103, 22, 110, 255, 105, 22, 110, 255, 106, 23, 110, 255, 108, 24, 110, 255, 109, 24, 110, 255, 111, 25, 110, 255, 113, 25, 110, 255, 114, 26, 110, 255, 116, 26, 110, 255, 117, 27, 110, 255, 119, 28, 109, 255, 120, 28, 109, 255, 122, 29, 109, 255, 124, 29, 109, 255, 125, 30, 109, 255, 127, 30, 108, 255, 128, 31, 108, 255, 130, 32, 108, 255, 132, 32, 107, 255, 133, 33, 107, 255, 135, 33, 107, 255, 136, 34, 106, 255, 138, 34, 106, 255, 140, 35, 105, 255, 141, 35, 105, 255, 143, 36, 105, 255, 144, 37, 104, 255, 146, 37, 104, 255, 147, 38, 103, 255, 149, 38, 103, 255, 151, 39, 102, 255, 152, 39, 102, 255, 154, 40, 101, 255, 155, 41, 100, 255, 157, 41, 100, 255, 159, 42, 99, 255, 160, 42, 99, 255, 162, 43, 98, 255, 163, 44, 97, 255, 165, 44, 96, 255, 166, 45, 96, 255, 168, 46, 95, 255, 169, 46, 94, 255, 171, 47, 94, 255, 173, 48, 93, 255, 174, 48, 92, 255, 176, 49, 91, 255, 177, 50, 90, 255, 179, 50, 90, 255, 180, 51, 89, 255, 182, 52, 88, 255, 183, 53, 87, 255, 185, 53, 86, 255, 186, 54, 85, 255, 188, 55, 84, 255, 189, 56, 83, 255, 191, 57, 82, 255, 192, 58, 81, 255, 193, 58, 80, 255, 195, 59, 79, 255, 196, 60, 78, 255, 198, 61, 77, 255, 199, 62, 76, 255, 200, 63, 75, 255, 202, 64, 74, 255, 203, 65, 73, 255, 204, 66, 72, 255, 206, 67, 71, 255, 207, 68, 70, 255, 208, 69, 69, 255, 210, 70, 68, 255, 211, 71, 67, 255, 212, 72, 66, 255, 213, 74, 65, 255, 215, 75, 63, 255, 216, 76, 62, 255, 217, 77, 61, 255, 218, 78, 60, 255, 219, 80, 59, 255, 221, 81, 58, 255, 222, 82, 56, 255, 223, 83, 55, 255, 224, 85, 54, 255, 225, 86, 53, 255, 226, 87, 52, 255, 227, 89, 51, 255, 228, 90, 49, 255, 229, 92, 48, 255, 230, 93, 47, 255, 231, 94, 46, 255, 232, 96, 45, 255, 233, 97, 43, 255, 234, 99, 42, 255, 235, 100, 41, 255, 235, 102, 40, 255, 236, 103, 38, 255, 237, 105, 37, 255, 238, 106, 36, 255, 239, 108, 35, 255, 239, 110, 33, 255, 240, 111, 32, 255, 241, 113, 31, 255, 241, 115, 29, 255, 242, 116, 28, 255, 243, 118, 27, 255, 243, 120, 25, 255, 244, 121, 24, 255, 245, 123, 23, 255, 245, 125, 21, 255, 246, 126, 20, 255, 246, 128, 19, 255, 247, 130, 18, 255, 247, 132, 16, 255, 248, 133, 15, 255, 248, 135, 14, 255, 248, 137, 12, 255, 249, 139, 11, 255, 249, 140, 10, 255, 249, 142, 9, 255, 250, 144, 8, 255, 250, 146, 7, 255, 250, 148, 7, 255, 251, 150, 6, 255, 251, 151, 6, 255, 251, 153, 6, 255, 251, 155, 6, 255, 251, 157, 7, 255, 252, 159, 7, 255, 252, 161, 8, 255, 252, 163, 9, 255, 252, 165, 10, 255, 252, 166, 12, 255, 252, 168, 13, 255, 252, 170, 15, 255, 252, 172, 17, 255, 252, 174, 18, 255, 252, 176, 20, 255, 252, 178, 22, 255, 252, 180, 24, 255, 251, 182, 26, 255, 251, 184, 29, 255, 251, 186, 31, 255, 251, 188, 33, 255, 251, 190, 35, 255, 250, 192, 38, 255, 250, 194, 40, 255, 250, 196, 42, 255, 250, 198, 45, 255, 249, 199, 47, 255, 249, 201, 50, 255, 249, 203, 53, 255, 248, 205, 55, 255, 248, 207, 58, 255, 247, 209, 61, 255, 247, 211, 64, 255, 246, 213, 67, 255, 246, 215, 70, 255, 245, 217, 73, 255, 245, 219, 76, 255, 244, 221, 79, 255, 244, 223, 83, 255, 244, 225, 86, 255, 243, 227, 90, 255, 243, 229, 93, 255, 242, 230, 97, 255, 242, 232, 101, 255, 242, 234, 105, 255, 241, 236, 109, 255, 241, 237, 113, 255, 241, 239, 117, 255, 241, 241, 121, 255, 242, 242, 125, 255, 242, 244, 130, 255, 243, 245, 134, 255, 243, 246, 138, 255, 244, 248, 142, 255, 245, 249, 146, 255, 246, 250, 150, 255, 248, 251, 154, 255, 249, 252, 157, 255, 250, 253, 161, 255, 252, 255, 164, 255]),
  turbo: new Uint8Array([48, 18, 59, 255, 50, 21, 67, 255, 51, 24, 74, 255, 52, 27, 81, 255, 53, 30, 88, 255, 54, 33, 95, 255, 55, 36, 102, 255, 56, 39, 109, 255, 57, 42, 115, 255, 58, 45, 121, 255, 59, 47, 128, 255, 60, 50, 134, 255, 61, 53, 139, 255, 62, 56, 145, 255, 63, 59, 151, 255, 63, 62, 156, 255, 64, 64, 162, 255, 65, 67, 167, 255, 65, 70, 172, 255, 66, 73, 177, 255, 66, 75, 181, 255, 67, 78, 186, 255, 68, 81, 191, 255, 68, 84, 195, 255, 68, 86, 199, 255, 69, 89, 203, 255, 69, 92, 207, 255, 69, 94, 211, 255, 70, 97, 214, 255, 70, 100, 218, 255, 70, 102, 221, 255, 70, 105, 224, 255, 70, 107, 227, 255, 71, 110, 230, 255, 71, 113, 233, 255, 71, 115, 235, 255, 71, 118, 238, 255, 71, 120, 240, 255, 71, 123, 242, 255, 70, 125, 244, 255, 70, 128, 246, 255, 70, 130, 248, 255, 70, 133, 250, 255, 70, 135, 251, 255, 69, 138, 252, 255, 69, 140, 253, 255, 68, 143, 254, 255, 67, 145, 254, 255, 66, 148, 255, 255, 65, 150, 255, 255, 64, 153, 255, 255, 62, 155, 254, 255, 61, 158, 254, 255, 59, 160, 253, 255, 58, 163, 252, 255, 56, 165, 251, 255, 55, 168, 250, 255, 53, 171, 248, 255, 51, 173, 247, 255, 49, 175, 245, 255, 47, 178, 244, 255, 46, 180, 242, 255, 44, 183, 240, 255, 42, 185, 238, 255, 40, 188, 235, 255, 39, 190, 233, 255, 37, 192, 231, 255, 35, 195, 228, 255, 34, 197, 226, 255, 32, 199, 223, 255, 31, 201, 221, 255, 30, 203, 218, 255, 28, 205, 216, 255, 27, 208, 213, 255, 26, 210, 210, 255, 26, 212, 208, 255, 25, 213, 205, 255, 24, 215, 202, 255, 24, 217, 200, 255, 24, 219, 197, 255, 24, 221, 194, 255, 24, 222, 192, 255, 24, 224, 189, 255, 25, 226, 187, 255, 25, 227, 185, 255, 26, 228, 182, 255, 28, 230, 180, 255, 29, 231, 178, 255, 31, 233, 175, 255, 32, 234, 172, 255, 34, 235, 170, 255, 37, 236, 167, 255, 39, 238, 164, 255, 42, 239, 161, 255, 44, 240, 158, 255, 47, 241, 155, 255, 50, 242, 152, 255, 53, 243, 148, 255, 56, 244, 145, 255, 60, 245, 142, 255, 63, 246, 138, 255, 67, 247, 135, 255, 70, 248, 132, 255, 74, 248, 128, 255, 78, 249, 125, 255, 82, 250, 122, 255, 85, 250, 118, 255, 89, 251, 115, 255, 93, 252, 111, 255, 97, 252, 108, 255, 101, 253, 105, 255, 105, 253, 102, 255, 109, 254, 98, 255, 113, 254, 95, 255, 117, 254, 92, 255, 121, 254, 89, 255, 125, 255, 86, 255, 128, 255, 83, 255, 132, 255, 81, 255, 136, 255, 78, 255, 139, 255, 75, 255, 143, 255, 73, 255, 146, 255, 71, 255, 150, 254, 68, 255, 153, 254, 66, 255, 156, 254, 64, 255, 159, 253, 63, 255, 161, 253, 61, 255, 164, 252, 60, 255, 167, 252, 58, 255, 169, 251, 57, 255, 172, 251, 56, 255, 175, 250, 55, 255, 177, 249, 54, 255, 180, 248, 54, 255, 183, 247, 53, 255, 185, 246, 53, 255, 188, 245, 52, 255, 190, 244, 52, 255, 193, 243, 52, 255, 195, 241, 52, 255, 198, 240, 52, 255, 200, 239, 52, 255, 203, 237, 52, 255, 205, 236, 52, 255, 208, 234, 52, 255, 210, 233, 53, 255, 212, 231, 53, 255, 215, 229, 53, 255, 217, 228, 54, 255, 219, 226, 54, 255, 221, 224, 55, 255, 223, 223, 55, 255, 225, 221, 55, 255, 227, 219, 56, 255, 229, 217, 56, 255, 231, 215, 57, 255, 233, 213, 57, 255, 235, 211, 57, 255, 236, 209, 58, 255, 238, 207, 58, 255, 239, 205, 58, 255, 241, 203, 58, 255, 242, 201, 58, 255, 244, 199, 58, 255, 245, 197, 58, 255, 246, 195, 58, 255, 247, 193, 58, 255, 248, 190, 57, 255, 249, 188, 57, 255, 250, 186, 57, 255, 251, 184, 56, 255, 251, 182, 55, 255, 252, 179, 54, 255, 252, 177, 54, 255, 253, 174, 53, 255, 253, 172, 52, 255, 254, 169, 51, 255, 254, 167, 50, 255, 254, 164, 49, 255, 254, 161, 48, 255, 254, 158, 47, 255, 254, 155, 45, 255, 254, 153, 44, 255, 254, 150, 43, 255, 254, 147, 42, 255, 254, 144, 41, 255, 253, 141, 39, 255, 253, 138, 38, 255, 252, 135, 37, 255, 252, 132, 35, 255, 251, 129, 34, 255, 251, 126, 33, 255, 250, 123, 31, 255, 249, 120, 30, 255, 249, 117, 29, 255, 248, 114, 28, 255, 247, 111, 26, 255, 246, 108, 25, 255, 245, 105, 24, 255, 244, 102, 23, 255, 243, 99, 21, 255, 242, 96, 20, 255, 241, 93, 19, 255, 240, 91, 18, 255, 239, 88, 17, 255, 237, 85, 16, 255, 236, 83, 15, 255, 235, 80, 14, 255, 234, 78, 13, 255, 232, 75, 12, 255, 231, 73, 12, 255, 229, 71, 11, 255, 228, 69, 10, 255, 226, 67, 10, 255, 225, 65, 9, 255, 223, 63, 8, 255, 221, 61, 8, 255, 220, 59, 7, 255, 218, 57, 7, 255, 216, 55, 6, 255, 214, 53, 6, 255, 212, 51, 5, 255, 210, 49, 5, 255, 208, 47, 5, 255, 206, 45, 4, 255, 204, 43, 4, 255, 202, 42, 4, 255, 200, 40, 3, 255, 197, 38, 3, 255, 195, 37, 3, 255, 193, 35, 2, 255, 190, 33, 2, 255, 188, 32, 2, 255, 185, 30, 2, 255, 183, 29, 2, 255, 180, 27, 1, 255, 178, 26, 1, 255, 175, 24, 1, 255, 172, 23, 1, 255, 169, 22, 1, 255, 167, 20, 1, 255, 164, 19, 1, 255, 161, 18, 1, 255, 158, 16, 1, 255, 155, 15, 1, 255, 152, 14, 1, 255, 149, 13, 1, 255, 146, 11, 1, 255, 142, 10, 1, 255, 139, 9, 2, 255, 136, 8, 2, 255, 133, 7, 2, 255, 129, 6, 2, 255, 126, 5, 2, 255, 122, 4, 3, 255]),
  rainbow: {
    colors: ["#96005A", "#0000C8", "#0019FF", "#0098FF", "#2CFF96", "#97FF00", "#FFEA00", "#FF6F00", "#FF0000"],
    positions: [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]
  },
  jet: {
    colors: ["#000083", "#003CAA", "#05FFFF", "#FFFF00", "#FA0000", "#800000"],
    positions: [0, 0.125, 0.375, 0.625, 0.875, 1]
  },
  hsv: {
    colors: ["#ff0000", "#fdff02", "#f7ff02", "#00fc04", "#00fc0a", "#01f9ff", "#0200fd", "#0800fd", "#ff00fb", "#ff00f5", "#ff0006"],
    positions: [0, 0.169, 0.173, 0.337, 0.341, 0.506, 0.671, 0.675, 0.839, 0.843, 1]
  },
  hot: {
    colors: ["#000000", "#e60000", "#ffd200", "#ffffff"],
    positions: [0, 0.3, 0.6, 1]
  },
  cool: {
    colors: ["#00ffff", "#ff00ff"],
    positions: [0, 1]
  },
  spring: {
    colors: ["#ff00ff", "#ffff00"],
    positions: [0, 1]
  },
  summer: {
    colors: ["#008066", "#ffff66"],
    positions: [0, 1]
  },
  autumn: {
    colors: ["#ff0000", "#ffff00"],
    positions: [0, 1]
  },
  winter: {
    colors: ["#0000ff", "#00ff80"],
    positions: [0, 1]
  },
  bone: {
    colors: ["#000000", "#545474", "#a9c8c8", "#ffffff"],
    positions: [0, 0.376, 0.753, 1]
  },
  copper: {
    colors: ["#000000", "#ffa066", "#ffc77f"],
    positions: [0, 0.804, 1]
  },
  greys: {
    colors: ["#000000", "#ffffff"],
    positions: [0, 1]
  },
  ylgnbu: {
    colors: ["#081d58", "#253494", "#225ea8", "#1d91c0", "#41b6c4", "#7fcdbb", "#c7e9b4", "#edf8d9", "#ffffd9"],
    positions: [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]
  },
  greens: {
    colors: ["#00441b", "#006d2c", "#238b45", "#41ab5d", "#74c476", "#a1d99b", "#c7e9c0", "#e5f5e0", "#f7fcf5"],
    positions: [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]
  },
  ylorrd: {
    colors: ["#800026", "#bd0026", "#e31a1c", "#fc4e2a", "#fd8d3c", "#feb24c", "#fed976", "#ffeda0", "#ffffcc"],
    positions: [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1]
  },
  bluered: {
    colors: ["#0000ff", "#ff0000"],
    positions: [0, 1]
  },
  rdbu: {
    colors: ["#050aac", "#6a89f7", "#bebebe", "#dcaa84", "#e6915a", "#b20a1c"],
    positions: [0, 0.35, 0.5, 0.6, 0.7, 1]
  },
  picnic: {
    colors: ["#0000ff", "#3399ff", "#66ccff", "#99ccff", "#ccccff", "#ffffff", "#ffccff", "#ff99ff", "#ff66cc", "#ff6666", "#ff0000"],
    positions: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
  },
  portland: {
    colors: ["#0c3383", "#0a88ba", "#f2d338", "#f28f38", "#d91e1e"],
    positions: [0, 0.25, 0.5, 0.75, 1]
  },
  blackbody: {
    colors: ["#000000", "#e60000", "#e6d200", "#ffffff", "#a0c8ff"],
    positions: [0, 0.2, 0.4, 0.7, 1]
  },
  earth: {
    colors: ["#000082", "#00b4b4", "#28d228", "#e6e632", "#784614", "#ffffff"],
    positions: [0, 0.1, 0.2, 0.4, 0.6, 1]
  },
  electric: {
    colors: ["#000000", "#1e0064", "#780064", "#a05a00", "#e6c800", "#fffadc"],
    positions: [0, 0.15, 0.4, 0.6, 0.8, 1]
  },
  magma: new Uint8Array([0, 0, 4, 255, 1, 0, 5, 255, 1, 1, 6, 255, 1, 1, 8, 255, 2, 1, 9, 255, 2, 2, 11, 255, 2, 2, 13, 255, 3, 3, 15, 255, 3, 3, 18, 255, 4, 4, 20, 255, 5, 4, 22, 255, 6, 5, 24, 255, 6, 5, 26, 255, 7, 6, 28, 255, 8, 7, 30, 255, 9, 7, 32, 255, 10, 8, 34, 255, 11, 9, 36, 255, 12, 9, 38, 255, 13, 10, 41, 255, 14, 11, 43, 255, 16, 11, 45, 255, 17, 12, 47, 255, 18, 13, 49, 255, 19, 13, 52, 255, 20, 14, 54, 255, 21, 14, 56, 255, 22, 15, 59, 255, 24, 15, 61, 255, 25, 16, 63, 255, 26, 16, 66, 255, 28, 16, 68, 255, 29, 17, 71, 255, 30, 17, 73, 255, 32, 17, 75, 255, 33, 17, 78, 255, 34, 17, 80, 255, 36, 18, 83, 255, 37, 18, 85, 255, 39, 18, 88, 255, 41, 17, 90, 255, 42, 17, 92, 255, 44, 17, 95, 255, 45, 17, 97, 255, 47, 17, 99, 255, 49, 17, 101, 255, 51, 16, 103, 255, 52, 16, 105, 255, 54, 16, 107, 255, 56, 16, 108, 255, 57, 15, 110, 255, 59, 15, 112, 255, 61, 15, 113, 255, 63, 15, 114, 255, 64, 15, 116, 255, 66, 15, 117, 255, 68, 15, 118, 255, 69, 16, 119, 255, 71, 16, 120, 255, 73, 16, 120, 255, 74, 16, 121, 255, 76, 17, 122, 255, 78, 17, 123, 255, 79, 18, 123, 255, 81, 18, 124, 255, 82, 19, 124, 255, 84, 19, 125, 255, 86, 20, 125, 255, 87, 21, 126, 255, 89, 21, 126, 255, 90, 22, 126, 255, 92, 22, 127, 255, 93, 23, 127, 255, 95, 24, 127, 255, 96, 24, 128, 255, 98, 25, 128, 255, 100, 26, 128, 255, 101, 26, 128, 255, 103, 27, 128, 255, 104, 28, 129, 255, 106, 28, 129, 255, 107, 29, 129, 255, 109, 29, 129, 255, 110, 30, 129, 255, 112, 31, 129, 255, 114, 31, 129, 255, 115, 32, 129, 255, 117, 33, 129, 255, 118, 33, 129, 255, 120, 34, 129, 255, 121, 34, 130, 255, 123, 35, 130, 255, 124, 35, 130, 255, 126, 36, 130, 255, 128, 37, 130, 255, 129, 37, 129, 255, 131, 38, 129, 255, 132, 38, 129, 255, 134, 39, 129, 255, 136, 39, 129, 255, 137, 40, 129, 255, 139, 41, 129, 255, 140, 41, 129, 255, 142, 42, 129, 255, 144, 42, 129, 255, 145, 43, 129, 255, 147, 43, 128, 255, 148, 44, 128, 255, 150, 44, 128, 255, 152, 45, 128, 255, 153, 45, 128, 255, 155, 46, 127, 255, 156, 46, 127, 255, 158, 47, 127, 255, 160, 47, 127, 255, 161, 48, 126, 255, 163, 48, 126, 255, 165, 49, 126, 255, 166, 49, 125, 255, 168, 50, 125, 255, 170, 51, 125, 255, 171, 51, 124, 255, 173, 52, 124, 255, 174, 52, 123, 255, 176, 53, 123, 255, 178, 53, 123, 255, 179, 54, 122, 255, 181, 54, 122, 255, 183, 55, 121, 255, 184, 55, 121, 255, 186, 56, 120, 255, 188, 57, 120, 255, 189, 57, 119, 255, 191, 58, 119, 255, 192, 58, 118, 255, 194, 59, 117, 255, 196, 60, 117, 255, 197, 60, 116, 255, 199, 61, 115, 255, 200, 62, 115, 255, 202, 62, 114, 255, 204, 63, 113, 255, 205, 64, 113, 255, 207, 64, 112, 255, 208, 65, 111, 255, 210, 66, 111, 255, 211, 67, 110, 255, 213, 68, 109, 255, 214, 69, 108, 255, 216, 69, 108, 255, 217, 70, 107, 255, 219, 71, 106, 255, 220, 72, 105, 255, 222, 73, 104, 255, 223, 74, 104, 255, 224, 76, 103, 255, 226, 77, 102, 255, 227, 78, 101, 255, 228, 79, 100, 255, 229, 80, 100, 255, 231, 82, 99, 255, 232, 83, 98, 255, 233, 84, 98, 255, 234, 86, 97, 255, 235, 87, 96, 255, 236, 88, 96, 255, 237, 90, 95, 255, 238, 91, 94, 255, 239, 93, 94, 255, 240, 95, 94, 255, 241, 96, 93, 255, 242, 98, 93, 255, 242, 100, 92, 255, 243, 101, 92, 255, 244, 103, 92, 255, 244, 105, 92, 255, 245, 107, 92, 255, 246, 108, 92, 255, 246, 110, 92, 255, 247, 112, 92, 255, 247, 114, 92, 255, 248, 116, 92, 255, 248, 118, 92, 255, 249, 120, 93, 255, 249, 121, 93, 255, 249, 123, 93, 255, 250, 125, 94, 255, 250, 127, 94, 255, 250, 129, 95, 255, 251, 131, 95, 255, 251, 133, 96, 255, 251, 135, 97, 255, 252, 137, 97, 255, 252, 138, 98, 255, 252, 140, 99, 255, 252, 142, 100, 255, 252, 144, 101, 255, 253, 146, 102, 255, 253, 148, 103, 255, 253, 150, 104, 255, 253, 152, 105, 255, 253, 154, 106, 255, 253, 155, 107, 255, 254, 157, 108, 255, 254, 159, 109, 255, 254, 161, 110, 255, 254, 163, 111, 255, 254, 165, 113, 255, 254, 167, 114, 255, 254, 169, 115, 255, 254, 170, 116, 255, 254, 172, 118, 255, 254, 174, 119, 255, 254, 176, 120, 255, 254, 178, 122, 255, 254, 180, 123, 255, 254, 182, 124, 255, 254, 183, 126, 255, 254, 185, 127, 255, 254, 187, 129, 255, 254, 189, 130, 255, 254, 191, 132, 255, 254, 193, 133, 255, 254, 194, 135, 255, 254, 196, 136, 255, 254, 198, 138, 255, 254, 200, 140, 255, 254, 202, 141, 255, 254, 204, 143, 255, 254, 205, 144, 255, 254, 207, 146, 255, 254, 209, 148, 255, 254, 211, 149, 255, 254, 213, 151, 255, 254, 215, 153, 255, 254, 216, 154, 255, 253, 218, 156, 255, 253, 220, 158, 255, 253, 222, 160, 255, 253, 224, 161, 255, 253, 226, 163, 255, 253, 227, 165, 255, 253, 229, 167, 255, 253, 231, 169, 255, 253, 233, 170, 255, 253, 235, 172, 255, 252, 236, 174, 255, 252, 238, 176, 255, 252, 240, 178, 255, 252, 242, 180, 255, 252, 244, 182, 255, 252, 246, 184, 255, 252, 247, 185, 255, 252, 249, 187, 255, 252, 251, 189, 255, 252, 253, 191, 255]),
  plasma: new Uint8Array([13, 8, 135, 255, 16, 7, 136, 255, 19, 7, 137, 255, 22, 7, 138, 255, 25, 6, 140, 255, 27, 6, 141, 255, 29, 6, 142, 255, 32, 6, 143, 255, 34, 6, 144, 255, 36, 6, 145, 255, 38, 5, 145, 255, 40, 5, 146, 255, 42, 5, 147, 255, 44, 5, 148, 255, 46, 5, 149, 255, 47, 5, 150, 255, 49, 5, 151, 255, 51, 5, 151, 255, 53, 4, 152, 255, 55, 4, 153, 255, 56, 4, 154, 255, 58, 4, 154, 255, 60, 4, 155, 255, 62, 4, 156, 255, 63, 4, 156, 255, 65, 4, 157, 255, 67, 3, 158, 255, 68, 3, 158, 255, 70, 3, 159, 255, 72, 3, 159, 255, 73, 3, 160, 255, 75, 3, 161, 255, 76, 2, 161, 255, 78, 2, 162, 255, 80, 2, 162, 255, 81, 2, 163, 255, 83, 2, 163, 255, 85, 2, 164, 255, 86, 1, 164, 255, 88, 1, 164, 255, 89, 1, 165, 255, 91, 1, 165, 255, 92, 1, 166, 255, 94, 1, 166, 255, 96, 1, 166, 255, 97, 0, 167, 255, 99, 0, 167, 255, 100, 0, 167, 255, 102, 0, 167, 255, 103, 0, 168, 255, 105, 0, 168, 255, 106, 0, 168, 255, 108, 0, 168, 255, 110, 0, 168, 255, 111, 0, 168, 255, 113, 0, 168, 255, 114, 1, 168, 255, 116, 1, 168, 255, 117, 1, 168, 255, 119, 1, 168, 255, 120, 1, 168, 255, 122, 2, 168, 255, 123, 2, 168, 255, 125, 3, 168, 255, 126, 3, 168, 255, 128, 4, 168, 255, 129, 4, 167, 255, 131, 5, 167, 255, 132, 5, 167, 255, 134, 6, 166, 255, 135, 7, 166, 255, 136, 8, 166, 255, 138, 9, 165, 255, 139, 10, 165, 255, 141, 11, 165, 255, 142, 12, 164, 255, 143, 13, 164, 255, 145, 14, 163, 255, 146, 15, 163, 255, 148, 16, 162, 255, 149, 17, 161, 255, 150, 19, 161, 255, 152, 20, 160, 255, 153, 21, 159, 255, 154, 22, 159, 255, 156, 23, 158, 255, 157, 24, 157, 255, 158, 25, 157, 255, 160, 26, 156, 255, 161, 27, 155, 255, 162, 29, 154, 255, 163, 30, 154, 255, 165, 31, 153, 255, 166, 32, 152, 255, 167, 33, 151, 255, 168, 34, 150, 255, 170, 35, 149, 255, 171, 36, 148, 255, 172, 38, 148, 255, 173, 39, 147, 255, 174, 40, 146, 255, 176, 41, 145, 255, 177, 42, 144, 255, 178, 43, 143, 255, 179, 44, 142, 255, 180, 46, 141, 255, 181, 47, 140, 255, 182, 48, 139, 255, 183, 49, 138, 255, 184, 50, 137, 255, 186, 51, 136, 255, 187, 52, 136, 255, 188, 53, 135, 255, 189, 55, 134, 255, 190, 56, 133, 255, 191, 57, 132, 255, 192, 58, 131, 255, 193, 59, 130, 255, 194, 60, 129, 255, 195, 61, 128, 255, 196, 62, 127, 255, 197, 64, 126, 255, 198, 65, 125, 255, 199, 66, 124, 255, 200, 67, 123, 255, 201, 68, 122, 255, 202, 69, 122, 255, 203, 70, 121, 255, 204, 71, 120, 255, 204, 73, 119, 255, 205, 74, 118, 255, 206, 75, 117, 255, 207, 76, 116, 255, 208, 77, 115, 255, 209, 78, 114, 255, 210, 79, 113, 255, 211, 81, 113, 255, 212, 82, 112, 255, 213, 83, 111, 255, 213, 84, 110, 255, 214, 85, 109, 255, 215, 86, 108, 255, 216, 87, 107, 255, 217, 88, 106, 255, 218, 90, 106, 255, 218, 91, 105, 255, 219, 92, 104, 255, 220, 93, 103, 255, 221, 94, 102, 255, 222, 95, 101, 255, 222, 97, 100, 255, 223, 98, 99, 255, 224, 99, 99, 255, 225, 100, 98, 255, 226, 101, 97, 255, 226, 102, 96, 255, 227, 104, 95, 255, 228, 105, 94, 255, 229, 106, 93, 255, 229, 107, 93, 255, 230, 108, 92, 255, 231, 110, 91, 255, 231, 111, 90, 255, 232, 112, 89, 255, 233, 113, 88, 255, 233, 114, 87, 255, 234, 116, 87, 255, 235, 117, 86, 255, 235, 118, 85, 255, 236, 119, 84, 255, 237, 121, 83, 255, 237, 122, 82, 255, 238, 123, 81, 255, 239, 124, 81, 255, 239, 126, 80, 255, 240, 127, 79, 255, 240, 128, 78, 255, 241, 129, 77, 255, 241, 131, 76, 255, 242, 132, 75, 255, 243, 133, 75, 255, 243, 135, 74, 255, 244, 136, 73, 255, 244, 137, 72, 255, 245, 139, 71, 255, 245, 140, 70, 255, 246, 141, 69, 255, 246, 143, 68, 255, 247, 144, 68, 255, 247, 145, 67, 255, 247, 147, 66, 255, 248, 148, 65, 255, 248, 149, 64, 255, 249, 151, 63, 255, 249, 152, 62, 255, 249, 154, 62, 255, 250, 155, 61, 255, 250, 156, 60, 255, 250, 158, 59, 255, 251, 159, 58, 255, 251, 161, 57, 255, 251, 162, 56, 255, 252, 163, 56, 255, 252, 165, 55, 255, 252, 166, 54, 255, 252, 168, 53, 255, 252, 169, 52, 255, 253, 171, 51, 255, 253, 172, 51, 255, 253, 174, 50, 255, 253, 175, 49, 255, 253, 177, 48, 255, 253, 178, 47, 255, 253, 180, 47, 255, 253, 181, 46, 255, 254, 183, 45, 255, 254, 184, 44, 255, 254, 186, 44, 255, 254, 187, 43, 255, 254, 189, 42, 255, 254, 190, 42, 255, 254, 192, 41, 255, 253, 194, 41, 255, 253, 195, 40, 255, 253, 197, 39, 255, 253, 198, 39, 255, 253, 200, 39, 255, 253, 202, 38, 255, 253, 203, 38, 255, 252, 205, 37, 255, 252, 206, 37, 255, 252, 208, 37, 255, 252, 210, 37, 255, 251, 211, 36, 255, 251, 213, 36, 255, 251, 215, 36, 255, 250, 216, 36, 255, 250, 218, 36, 255, 249, 220, 36, 255, 249, 221, 37, 255, 248, 223, 37, 255, 248, 225, 37, 255, 247, 226, 37, 255, 247, 228, 37, 255, 246, 230, 38, 255, 246, 232, 38, 255, 245, 233, 38, 255, 245, 235, 39, 255, 244, 237, 39, 255, 243, 238, 39, 255, 243, 240, 39, 255, 242, 242, 39, 255, 241, 244, 38, 255, 241, 245, 37, 255, 240, 247, 36, 255, 240, 249, 33, 255]),
  redblue: {
    colors: ["#ff0000", "#0000ff"],
    positions: [0, 1]
  },
  coolwarm: {
    colors: ["#0000ff", "#ffffff", "#ff0000"],
    positions: [0, 0.5, 1]
  },
  diverging_1: {
    colors: ["#400040", "#3b004d", "#36005b", "#320068", "#2d0076", "#290084", "#240091", "#20009f", "#1b00ad", "#1600ba", "#1200c8", "#0d00d6", "#0900e3", "#0400f1", "#0000ff", "#0217ff", "#042eff", "#0645ff", "#095cff", "#0b73ff", "#0d8bff", "#10a2ff", "#12b9ff", "#14d0ff", "#17e7ff", "#19ffff", "#3fffff", "#66ffff", "#8cffff", "#b2ffff", "#d8ffff", "#ffffff", "#ffffd4", "#ffffaa", "#ffff7f", "#ffff54", "#ffff2a", "#ffff00", "#ffed00", "#ffdd00", "#ffcc00", "#ffba00", "#ffaa00", "#ff9900", "#ff8700", "#ff7700", "#ff6600", "#ff5400", "#ff4400", "#ff3300", "#ff2100", "#ff1100", "#ff0000", "#ff0017", "#ff002e", "#ff0045", "#ff005c", "#ff0073", "#ff008b", "#ff00a2", "#ff00b9", "#ff00d0", "#ff00e7", "#ff00ff"],
    positions: [0, 0.01587301587, 0.03174603174, 0.04761904761, 0.06349206348, 0.07936507935, 0.09523809522, 0.11111111109, 0.12698412696, 0.14285714283, 0.1587301587, 0.17460317457, 0.19047619044, 0.20634920631, 0.22222222218, 0.23809523805, 0.25396825392, 0.26984126979, 0.28571428566, 0.30158730153, 0.3174603174, 0.33333333327, 0.34920634914, 0.36507936501, 0.38095238088, 0.39682539675, 0.41269841262, 0.42857142849, 0.44444444436, 0.46031746023, 0.4761904761, 0.49206349197, 0.50793650784, 0.52380952371, 0.53968253958, 0.55555555545, 0.57142857132, 0.58730158719, 0.60317460306, 0.61904761893, 0.6349206348, 0.65079365067, 0.66666666654, 0.68253968241, 0.69841269828, 0.71428571415, 0.73015873002, 0.74603174589, 0.76190476176, 0.77777777763, 0.7936507935, 0.80952380937, 0.82539682524, 0.84126984111, 0.85714285698, 0.87301587285, 0.88888888872, 0.90476190459, 0.92063492046, 0.93650793633, 0.9523809522, 0.96825396807, 0.98412698394, 1]
  },
  diverging_2: {
    colors: ["#000000", "#030aff", "#204aff", "#3c8aff", "#77c4ff", "#f0ffff", "#f0ffff", "#f2ff7f", "#ffff00", "#ff831e", "#ff083d", "#ff00ff"],
    positions: [0, 1e-10, 0.1, 0.2, 0.3333, 0.4666, 0.5333, 0.6666, 0.8, 0.9, 0.999999999999, 1]
  },
  blackwhite: {
    colors: ["#000000", "#ffffff"],
    positions: [0, 1]
  },
  twilight: {
    colors: ["#E2D9E2", "#E0D9E2", "#DDD9E0", "#DAD8DF", "#D6D7DD", "#D2D5DB", "#CDD3D8", "#C8D0D6", "#C2CED4", "#BCCBD1", "#B6C8CF", "#B0C5CD", "#AAC2CC", "#A4BECA", "#9EBBC9", "#99B8C8", "#93B4C6", "#8EB1C5", "#89ADC5", "#85A9C4", "#80A5C3", "#7CA2C2", "#789EC2", "#759AC1", "#7196C1", "#6E92C0", "#6C8EBF", "#698ABF", "#6786BE", "#6682BD", "#647DBC", "#6379BB", "#6275BA", "#6170B9", "#606CB8", "#6067B6", "#5F62B4", "#5F5EB3", "#5F59B1", "#5E54AE", "#5E4FAC", "#5E4BA9", "#5E46A6", "#5D41A3", "#5D3CA0", "#5C379C", "#5B3298", "#5A2E93", "#59298E", "#572588", "#562182", "#531E7C", "#511A75", "#4E186F", "#4B1668", "#471461", "#44135A", "#411254", "#3D114E", "#3A1149", "#371144", "#351140", "#33113C", "#311339", "#301437", "#331237", "#351138", "#381139", "#3B113B", "#3F123D", "#43123E", "#481341", "#4D1443", "#521545", "#571647", "#5C1749", "#61184B", "#67194C", "#6C1B4E", "#711D4F", "#761F4F", "#7B2150", "#802350", "#852650", "#8A2950", "#8E2C50", "#922F50", "#963350", "#9A3750", "#9E3B50", "#A13F50", "#A54350", "#A84750", "#AB4B50", "#AE5051", "#B15452", "#B35953", "#B65D54", "#B86255", "#BA6657", "#BC6B59", "#BE705B", "#C0755E", "#C27A61", "#C37F64", "#C58468", "#C6896C", "#C78E71", "#C89275", "#C9977B", "#CA9C80", "#CCA186", "#CDA68C", "#CEAB92", "#CFAF99", "#D1B4A0", "#D2B8A7", "#D4BDAD", "#D6C1B4", "#D8C5BB", "#D9C9C2", "#DBCCC8", "#DDD0CE", "#DED3D3", "#DFD5D8", "#E0D7DB", "#E1D8DF", "#E2D9E1"],
    positions: [0, 0.0078740157, 0.0157480315, 0.0236220472, 0.031496063, 0.0393700787, 0.0472440945, 0.0551181102, 0.062992126, 0.0708661417, 0.0787401575, 0.0866141732, 0.094488189, 0.1023622047, 0.1102362205, 0.1181102362, 0.125984252, 0.1338582677, 0.1417322835, 0.1496062992, 0.157480315, 0.1653543307, 0.1732283465, 0.1811023622, 0.188976378, 0.1968503937, 0.2047244094, 0.2125984252, 0.2204724409, 0.2283464567, 0.2362204724, 0.2440944882, 0.2519685039, 0.2598425197, 0.2677165354, 0.2755905512, 0.2834645669, 0.2913385827, 0.2992125984, 0.3070866142, 0.3149606299, 0.3228346457, 0.3307086614, 0.3385826772, 0.3464566929, 0.3543307087, 0.3622047244, 0.3700787402, 0.3779527559, 0.3858267717, 0.3937007874, 0.4015748031, 0.4094488189, 0.4173228346, 0.4251968504, 0.4330708661, 0.4409448819, 0.4488188976, 0.4566929134, 0.4645669291, 0.4724409449, 0.4803149606, 0.4881889764, 0.4960629921, 0.5039370079, 0.5118110236, 0.5196850394, 0.5275590551, 0.5354330709, 0.5433070866, 0.5511811024, 0.5590551181, 0.5669291339, 0.5748031496, 0.5826771654, 0.5905511811, 0.5984251969, 0.6062992126, 0.6141732283, 0.6220472441, 0.6299212598, 0.6377952756, 0.6456692913, 0.6535433071, 0.6614173228, 0.6692913386, 0.6771653543, 0.6850393701, 0.6929133858, 0.7007874016, 0.7086614173, 0.7165354331, 0.7244094488, 0.7322834646, 0.7401574803, 0.7480314961, 0.7559055118, 0.7637795276, 0.7716535433, 0.7795275591, 0.7874015748, 0.7952755906, 0.8031496063, 0.811023622, 0.8188976378, 0.8267716535, 0.8346456693, 0.842519685, 0.8503937008, 0.8582677165, 0.8661417323, 0.874015748, 0.8818897638, 0.8897637795, 0.8976377953, 0.905511811, 0.9133858268, 0.9212598425, 0.9291338583, 0.937007874, 0.9448818898, 0.9527559055, 0.9606299213, 0.968503937, 0.9763779528, 0.9842519685, 0.9921259843, 1]
  },
  twilight_shifted: {
    colors: ["#301437", "#32123A", "#34113E", "#361142", "#391146", "#3C114B", "#3F1251", "#421257", "#46145E", "#491564", "#4C176B", "#4F1972", "#521C79", "#551F7F", "#572385", "#58278B", "#5A2B90", "#5B3095", "#5C359A", "#5D3A9E", "#5D3EA1", "#5E43A5", "#5E48A8", "#5E4DAB", "#5E52AD", "#5F57B0", "#5F5BB2", "#5F60B4", "#5F65B5", "#6069B7", "#606EB8", "#6172BA", "#6277BB", "#637BBC", "#657FBD", "#6684BD", "#6888BE", "#6B8CBF", "#6D90C0", "#7094C0", "#7398C1", "#769CC1", "#7AA0C2", "#7EA4C3", "#82A7C3", "#87ABC4", "#8CAFC5", "#91B2C6", "#96B6C7", "#9CB9C8", "#A1BDC9", "#A7C0CB", "#ADC3CD", "#B3C6CE", "#B9C9D0", "#BFCCD3", "#C5CFD5", "#CBD2D7", "#D0D4D9", "#D4D6DC", "#D8D8DE", "#DCD9DF", "#DED9E1", "#E1D9E2", "#E2D9E1", "#E1D8DF", "#E0D7DB", "#DFD5D8", "#DED3D3", "#DDD0CE", "#DBCCC8", "#D9C9C2", "#D8C5BB", "#D6C1B4", "#D4BDAD", "#D2B8A7", "#D1B4A0", "#CFAF99", "#CEAB92", "#CDA68C", "#CCA186", "#CA9C80", "#C9977B", "#C89275", "#C78E71", "#C6896C", "#C58468", "#C37F64", "#C27A61", "#C0755E", "#BE705B", "#BC6B59", "#BA6657", "#B86255", "#B65D54", "#B35953", "#B15452", "#AE5051", "#AB4B50", "#A84750", "#A54350", "#A13F50", "#9E3B50", "#9A3750", "#963350", "#922F50", "#8E2C50", "#8A2950", "#852650", "#802350", "#7B2150", "#761F4F", "#711D4F", "#6C1B4E", "#67194C", "#61184B", "#5C1749", "#571647", "#521545", "#4D1443", "#481341", "#43123E", "#3F123D", "#3B113B", "#381139", "#351138", "#331237", "#301437"],
    positions: [0, 0.0078740157, 0.0157480315, 0.0236220472, 0.031496063, 0.0393700787, 0.0472440945, 0.0551181102, 0.062992126, 0.0708661417, 0.0787401575, 0.0866141732, 0.094488189, 0.1023622047, 0.1102362205, 0.1181102362, 0.125984252, 0.1338582677, 0.1417322835, 0.1496062992, 0.157480315, 0.1653543307, 0.1732283465, 0.1811023622, 0.188976378, 0.1968503937, 0.2047244094, 0.2125984252, 0.2204724409, 0.2283464567, 0.2362204724, 0.2440944882, 0.2519685039, 0.2598425197, 0.2677165354, 0.2755905512, 0.2834645669, 0.2913385827, 0.2992125984, 0.3070866142, 0.3149606299, 0.3228346457, 0.3307086614, 0.3385826772, 0.3464566929, 0.3543307087, 0.3622047244, 0.3700787402, 0.3779527559, 0.3858267717, 0.3937007874, 0.4015748031, 0.4094488189, 0.4173228346, 0.4251968504, 0.4330708661, 0.4409448819, 0.4488188976, 0.4566929134, 0.4645669291, 0.4724409449, 0.4803149606, 0.4881889764, 0.4960629921, 0.5039370079, 0.5118110236, 0.5196850394, 0.5275590551, 0.5354330709, 0.5433070866, 0.5511811024, 0.5590551181, 0.5669291339, 0.5748031496, 0.5826771654, 0.5905511811, 0.5984251969, 0.6062992126, 0.6141732283, 0.6220472441, 0.6299212598, 0.6377952756, 0.6456692913, 0.6535433071, 0.6614173228, 0.6692913386, 0.6771653543, 0.6850393701, 0.6929133858, 0.7007874016, 0.7086614173, 0.7165354331, 0.7244094488, 0.7322834646, 0.7401574803, 0.7480314961, 0.7559055118, 0.7637795276, 0.7716535433, 0.7795275591, 0.7874015748, 0.7952755906, 0.8031496063, 0.811023622, 0.8188976378, 0.8267716535, 0.8346456693, 0.842519685, 0.8503937008, 0.8582677165, 0.8661417323, 0.874015748, 0.8818897638, 0.8897637795, 0.8976377953, 0.905511811, 0.9133858268, 0.9212598425, 0.9291338583, 0.937007874, 0.9448818898, 0.9527559055, 0.9606299213, 0.968503937, 0.9763779528, 0.9842519685, 0.9921259843, 1]
  }
};

function peg$subclass(child, parent) {
  function C() {
    this.constructor = child;
  }
  C.prototype = parent.prototype;
  child.prototype = new C();
}
function peg$SyntaxError(message, expected, found, location) {
  this.message = message;
  this.expected = expected;
  this.found = found;
  this.location = location;
  this.name = "SyntaxError";
  if (typeof Error.captureStackTrace === "function") {
    Error.captureStackTrace(this, peg$SyntaxError);
  }
}
peg$subclass(peg$SyntaxError, Error);
peg$SyntaxError.buildMessage = function(expected, found) {
  var DESCRIBE_EXPECTATION_FNS = {
    literal: function(expectation) {
      return '"' + literalEscape(expectation.text) + '"';
    },
    class: function(expectation) {
      var escapedParts = expectation.parts.map(function(part) {
        return Array.isArray(part) ? classEscape(part[0]) + "-" + classEscape(part[1]) : classEscape(part);
      });
      return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
    },
    any: function() {
      return "any character";
    },
    end: function() {
      return "end of input";
    },
    other: function(expectation) {
      return expectation.description;
    },
    not: function(expectation) {
      return "not " + describeExpectation(expectation.expected);
    }
  };
  function hex(ch) {
    return ch.charCodeAt(0).toString(16).toUpperCase();
  }
  function literalEscape(s) {
    return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\0/g, "\\0").replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/[\x00-\x0F]/g, function(ch) {
      return "\\x0" + hex(ch);
    }).replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) {
      return "\\x" + hex(ch);
    });
  }
  function classEscape(s) {
    return s.replace(/\\/g, "\\\\").replace(/\]/g, "\\]").replace(/\^/g, "\\^").replace(/-/g, "\\-").replace(/\0/g, "\\0").replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/[\x00-\x0F]/g, function(ch) {
      return "\\x0" + hex(ch);
    }).replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) {
      return "\\x" + hex(ch);
    });
  }
  function describeExpectation(expectation) {
    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
  }
  function describeExpected(expected2) {
    var descriptions = expected2.map(describeExpectation);
    var i, j;
    descriptions.sort();
    if (descriptions.length > 0) {
      for (i = 1, j = 1; i < descriptions.length; i++) {
        if (descriptions[i - 1] !== descriptions[i]) {
          descriptions[j] = descriptions[i];
          j++;
        }
      }
      descriptions.length = j;
    }
    switch (descriptions.length) {
      case 1:
        return descriptions[0];
      case 2:
        return descriptions[0] + " or " + descriptions[1];
      default:
        return descriptions.slice(0, -1).join(", ") + ", or " + descriptions[descriptions.length - 1];
    }
  }
  function describeFound(found2) {
    return found2 ? '"' + literalEscape(found2) + '"' : "end of input";
  }
  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};
function peg$parse(input, options) {
  options = options !== void 0 ? options : {};
  var peg$FAILED = {};
  var peg$startRuleFunctions = { Expression: peg$parseExpression };
  var peg$startRuleFunction = peg$parseExpression;
  var peg$c0 = "+";
  var peg$c1 = "-";
  var peg$c2 = "*";
  var peg$c3 = "/";
  var peg$c4 = "**";
  var peg$c5 = "(";
  var peg$c6 = ")";
  var peg$r0 = /^[\-+]/;
  var peg$r1 = /^[0-9]/;
  var peg$r2 = /^[a-zA-Z_$]/;
  var peg$r3 = /^[a-zA-Z_$0-9]/;
  var peg$r4 = /^[ \t\n\r]/;
  var peg$e0 = peg$literalExpectation("+", false);
  var peg$e1 = peg$literalExpectation("-", false);
  var peg$e2 = peg$literalExpectation("*", false);
  var peg$e3 = peg$literalExpectation("/", false);
  var peg$e4 = peg$literalExpectation("**", false);
  var peg$e5 = peg$literalExpectation("(", false);
  var peg$e6 = peg$literalExpectation(")", false);
  var peg$e7 = peg$otherExpectation("float");
  var peg$e8 = peg$otherExpectation("integer");
  var peg$e9 = peg$otherExpectation("identifier");
  var peg$e10 = peg$otherExpectation("whitespace");
  var peg$f0 = function(head, tail) {
    var lhs = head;
    var i, op;
    for (i = 0; i < tail.length; i++) {
      op = tail[i][1];
      lhs = makeNode(lhs, tail[i][3], op);
    }
    return lhs;
  };
  var peg$f1 = function(head, tail) {
    var lhs = head;
    var i, op;
    for (i = 0; i < tail.length; i++) {
      op = tail[i][1];
      lhs = makeNode(lhs, tail[i][3], op);
    }
    return lhs;
  };
  var peg$f2 = function(expr) {
    return expr;
  };
  var peg$f3 = function(n, e) {
    return { fn: n, lhs: e };
  };
  var peg$f4 = function() {
    return parseFloat(text(), 10);
  };
  var peg$f5 = function() {
    return parseInt(text(), 10);
  };
  var peg$f6 = function() {
    return text();
  };
  var peg$currPos = 0;
  var peg$savedPos = 0;
  var peg$posDetailsCache = [{ line: 1, column: 1 }];
  var peg$expected = [];
  var peg$silentFails = 0;
  var peg$result;
  if ("startRule" in options) {
    if (!(options.startRule in peg$startRuleFunctions)) {
      throw new Error(`Can't start parsing from rule "` + options.startRule + '".');
    }
    peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
  }
  function text() {
    return input.substring(peg$savedPos, peg$currPos);
  }
  function peg$literalExpectation(text2, ignoreCase) {
    return { type: "literal", text: text2, ignoreCase };
  }
  function peg$endExpectation() {
    return { type: "end" };
  }
  function peg$otherExpectation(description) {
    return { type: "other", description };
  }
  function peg$computePosDetails(pos) {
    var details = peg$posDetailsCache[pos];
    var p;
    if (details) {
      return details;
    } else {
      p = pos - 1;
      while (!peg$posDetailsCache[p]) {
        p--;
      }
      details = peg$posDetailsCache[p];
      details = {
        line: details.line,
        column: details.column
      };
      while (p < pos) {
        if (input.charCodeAt(p) === 10) {
          details.line++;
          details.column = 1;
        } else {
          details.column++;
        }
        p++;
      }
      peg$posDetailsCache[pos] = details;
      return details;
    }
  }
  var peg$VALIDFILENAME = typeof options.filename === "string" && options.filename.length > 0;
  function peg$computeLocation(startPos, endPos) {
    var loc = {};
    if (peg$VALIDFILENAME)
      loc.filename = options.filename;
    var startPosDetails = peg$computePosDetails(startPos);
    loc.start = {
      offset: startPos,
      line: startPosDetails.line,
      column: startPosDetails.column
    };
    var endPosDetails = peg$computePosDetails(endPos);
    loc.end = {
      offset: endPos,
      line: endPosDetails.line,
      column: endPosDetails.column
    };
    return loc;
  }
  function peg$begin() {
    peg$expected.push({ pos: peg$currPos, variants: [] });
  }
  function peg$expect(expected2) {
    var top = peg$expected[peg$expected.length - 1];
    if (peg$currPos < top.pos) {
      return;
    }
    if (peg$currPos > top.pos) {
      top.pos = peg$currPos;
      top.variants = [];
    }
    top.variants.push(expected2);
  }
  function peg$buildStructuredError(expected2, found, location2) {
    return new peg$SyntaxError(
      peg$SyntaxError.buildMessage(expected2, found),
      expected2,
      found,
      location2
    );
  }
  function peg$buildError() {
    var expected2 = peg$expected[0];
    var failPos = expected2.pos;
    return peg$buildStructuredError(
      expected2.variants,
      failPos < input.length ? input.charAt(failPos) : null,
      failPos < input.length ? peg$computeLocation(failPos, failPos + 1) : peg$computeLocation(failPos, failPos)
    );
  }
  function peg$parseExpression() {
    var s0, s1, s2, s3, s4, s5, s6, s7;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    s0 = peg$currPos;
    s1 = peg$parseTerm();
    if (s1 !== peg$FAILED) {
      s2 = [];
      s3 = peg$currPos;
      s4 = peg$parse_();
      rule$expects(peg$e0);
      if (input.charCodeAt(peg$currPos) === 43) {
        s5 = peg$c0;
        peg$currPos++;
      } else {
        s5 = peg$FAILED;
      }
      if (s5 === peg$FAILED) {
        rule$expects(peg$e1);
        if (input.charCodeAt(peg$currPos) === 45) {
          s5 = peg$c1;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
      }
      if (s5 !== peg$FAILED) {
        s6 = peg$parse_();
        s7 = peg$parseTerm();
        if (s7 !== peg$FAILED) {
          s4 = [s4, s5, s6, s7];
          s3 = s4;
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      } else {
        peg$currPos = s3;
        s3 = peg$FAILED;
      }
      while (s3 !== peg$FAILED) {
        s2.push(s3);
        s3 = peg$currPos;
        s4 = peg$parse_();
        rule$expects(peg$e0);
        if (input.charCodeAt(peg$currPos) === 43) {
          s5 = peg$c0;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
        if (s5 === peg$FAILED) {
          rule$expects(peg$e1);
          if (input.charCodeAt(peg$currPos) === 45) {
            s5 = peg$c1;
            peg$currPos++;
          } else {
            s5 = peg$FAILED;
          }
        }
        if (s5 !== peg$FAILED) {
          s6 = peg$parse_();
          s7 = peg$parseTerm();
          if (s7 !== peg$FAILED) {
            s4 = [s4, s5, s6, s7];
            s3 = s4;
          } else {
            peg$currPos = s3;
            s3 = peg$FAILED;
          }
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      }
      peg$savedPos = s0;
      s0 = peg$f0(s1, s2);
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    return s0;
  }
  function peg$parseTerm() {
    var s0, s1, s2, s3, s4, s5, s6, s7;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    s0 = peg$currPos;
    s1 = peg$parseExponential();
    if (s1 !== peg$FAILED) {
      s2 = [];
      s3 = peg$currPos;
      s4 = peg$parse_();
      rule$expects(peg$e2);
      if (input.charCodeAt(peg$currPos) === 42) {
        s5 = peg$c2;
        peg$currPos++;
      } else {
        s5 = peg$FAILED;
      }
      if (s5 === peg$FAILED) {
        rule$expects(peg$e3);
        if (input.charCodeAt(peg$currPos) === 47) {
          s5 = peg$c3;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
      }
      if (s5 !== peg$FAILED) {
        s6 = peg$parse_();
        s7 = peg$parseExponential();
        if (s7 !== peg$FAILED) {
          s4 = [s4, s5, s6, s7];
          s3 = s4;
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      } else {
        peg$currPos = s3;
        s3 = peg$FAILED;
      }
      while (s3 !== peg$FAILED) {
        s2.push(s3);
        s3 = peg$currPos;
        s4 = peg$parse_();
        rule$expects(peg$e2);
        if (input.charCodeAt(peg$currPos) === 42) {
          s5 = peg$c2;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
        if (s5 === peg$FAILED) {
          rule$expects(peg$e3);
          if (input.charCodeAt(peg$currPos) === 47) {
            s5 = peg$c3;
            peg$currPos++;
          } else {
            s5 = peg$FAILED;
          }
        }
        if (s5 !== peg$FAILED) {
          s6 = peg$parse_();
          s7 = peg$parseExponential();
          if (s7 !== peg$FAILED) {
            s4 = [s4, s5, s6, s7];
            s3 = s4;
          } else {
            peg$currPos = s3;
            s3 = peg$FAILED;
          }
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      }
      peg$savedPos = s0;
      s0 = peg$f1(s1, s2);
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    return s0;
  }
  function peg$parseExponential() {
    var s0, s1, s2, s3, s4, s5, s6, s7;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    s0 = peg$currPos;
    s1 = peg$parseFactor();
    if (s1 !== peg$FAILED) {
      s2 = [];
      s3 = peg$currPos;
      s4 = peg$parse_();
      rule$expects(peg$e4);
      if (input.substr(peg$currPos, 2) === peg$c4) {
        s5 = peg$c4;
        peg$currPos += 2;
      } else {
        s5 = peg$FAILED;
      }
      if (s5 !== peg$FAILED) {
        s6 = peg$parse_();
        s7 = peg$parseFactor();
        if (s7 !== peg$FAILED) {
          s4 = [s4, s5, s6, s7];
          s3 = s4;
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      } else {
        peg$currPos = s3;
        s3 = peg$FAILED;
      }
      while (s3 !== peg$FAILED) {
        s2.push(s3);
        s3 = peg$currPos;
        s4 = peg$parse_();
        rule$expects(peg$e4);
        if (input.substr(peg$currPos, 2) === peg$c4) {
          s5 = peg$c4;
          peg$currPos += 2;
        } else {
          s5 = peg$FAILED;
        }
        if (s5 !== peg$FAILED) {
          s6 = peg$parse_();
          s7 = peg$parseFactor();
          if (s7 !== peg$FAILED) {
            s4 = [s4, s5, s6, s7];
            s3 = s4;
          } else {
            peg$currPos = s3;
            s3 = peg$FAILED;
          }
        } else {
          peg$currPos = s3;
          s3 = peg$FAILED;
        }
      }
      peg$savedPos = s0;
      s0 = peg$f1(s1, s2);
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    return s0;
  }
  function peg$parseFactor() {
    var s0, s1, s2, s3, s4, s5;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    s0 = peg$currPos;
    rule$expects(peg$e5);
    if (input.charCodeAt(peg$currPos) === 40) {
      s1 = peg$c5;
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
    }
    if (s1 !== peg$FAILED) {
      s2 = peg$parse_();
      s3 = peg$parseExpression();
      if (s3 !== peg$FAILED) {
        s4 = peg$parse_();
        rule$expects(peg$e6);
        if (input.charCodeAt(peg$currPos) === 41) {
          s5 = peg$c6;
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
        if (s5 !== peg$FAILED) {
          peg$savedPos = s0;
          s0 = peg$f2(s3);
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    if (s0 === peg$FAILED) {
      s0 = peg$parseFloat();
      if (s0 === peg$FAILED) {
        s0 = peg$parseInteger();
        if (s0 === peg$FAILED) {
          s0 = peg$currPos;
          s1 = peg$parseIdentifier();
          if (s1 !== peg$FAILED) {
            rule$expects(peg$e5);
            if (input.charCodeAt(peg$currPos) === 40) {
              s2 = peg$c5;
              peg$currPos++;
            } else {
              s2 = peg$FAILED;
            }
            if (s2 !== peg$FAILED) {
              s3 = peg$parseExpression();
              if (s3 !== peg$FAILED) {
                rule$expects(peg$e6);
                if (input.charCodeAt(peg$currPos) === 41) {
                  s4 = peg$c6;
                  peg$currPos++;
                } else {
                  s4 = peg$FAILED;
                }
                if (s4 !== peg$FAILED) {
                  peg$savedPos = s0;
                  s0 = peg$f3(s1, s3);
                } else {
                  peg$currPos = s0;
                  s0 = peg$FAILED;
                }
              } else {
                peg$currPos = s0;
                s0 = peg$FAILED;
              }
            } else {
              peg$currPos = s0;
              s0 = peg$FAILED;
            }
          } else {
            peg$currPos = s0;
            s0 = peg$FAILED;
          }
          if (s0 === peg$FAILED) {
            s0 = peg$parseIdentifier();
          }
        }
      }
    }
    return s0;
  }
  function peg$parseFloat() {
    var s0, s1, s2, s3, s4, s5;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    rule$expects(peg$e7);
    peg$silentFails++;
    s0 = peg$currPos;
    s1 = [];
    if (peg$r0.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
    }
    while (s2 !== peg$FAILED) {
      s1.push(s2);
      if (peg$r0.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
      }
    }
    s2 = [];
    if (peg$r1.test(input.charAt(peg$currPos))) {
      s3 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s3 = peg$FAILED;
    }
    if (s3 !== peg$FAILED) {
      while (s3 !== peg$FAILED) {
        s2.push(s3);
        if (peg$r1.test(input.charAt(peg$currPos))) {
          s3 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s3 = peg$FAILED;
        }
      }
    } else {
      s2 = peg$FAILED;
    }
    if (s2 !== peg$FAILED) {
      if (input.length > peg$currPos) {
        s3 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s3 = peg$FAILED;
      }
      if (s3 !== peg$FAILED) {
        s4 = [];
        if (peg$r1.test(input.charAt(peg$currPos))) {
          s5 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s5 = peg$FAILED;
        }
        if (s5 !== peg$FAILED) {
          while (s5 !== peg$FAILED) {
            s4.push(s5);
            if (peg$r1.test(input.charAt(peg$currPos))) {
              s5 = input.charAt(peg$currPos);
              peg$currPos++;
            } else {
              s5 = peg$FAILED;
            }
          }
        } else {
          s4 = peg$FAILED;
        }
        if (s4 !== peg$FAILED) {
          peg$savedPos = s0;
          s0 = peg$f4();
        } else {
          peg$currPos = s0;
          s0 = peg$FAILED;
        }
      } else {
        peg$currPos = s0;
        s0 = peg$FAILED;
      }
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    peg$silentFails--;
    return s0;
  }
  function peg$parseInteger() {
    var s0, s1, s2, s3;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    rule$expects(peg$e8);
    peg$silentFails++;
    s0 = peg$currPos;
    s1 = [];
    if (peg$r0.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
    }
    while (s2 !== peg$FAILED) {
      s1.push(s2);
      if (peg$r0.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
      }
    }
    s2 = [];
    if (peg$r1.test(input.charAt(peg$currPos))) {
      s3 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s3 = peg$FAILED;
    }
    if (s3 !== peg$FAILED) {
      while (s3 !== peg$FAILED) {
        s2.push(s3);
        if (peg$r1.test(input.charAt(peg$currPos))) {
          s3 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s3 = peg$FAILED;
        }
      }
    } else {
      s2 = peg$FAILED;
    }
    if (s2 !== peg$FAILED) {
      peg$savedPos = s0;
      s0 = peg$f5();
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    peg$silentFails--;
    return s0;
  }
  function peg$parseIdentifier() {
    var s0, s1, s2, s3, s4;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    rule$expects(peg$e9);
    peg$silentFails++;
    s0 = peg$currPos;
    s1 = [];
    if (peg$r0.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
    }
    while (s2 !== peg$FAILED) {
      s1.push(s2);
      if (peg$r0.test(input.charAt(peg$currPos))) {
        s2 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s2 = peg$FAILED;
      }
    }
    if (peg$r2.test(input.charAt(peg$currPos))) {
      s2 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s2 = peg$FAILED;
    }
    if (s2 !== peg$FAILED) {
      s3 = [];
      if (peg$r3.test(input.charAt(peg$currPos))) {
        s4 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s4 = peg$FAILED;
      }
      while (s4 !== peg$FAILED) {
        s3.push(s4);
        if (peg$r3.test(input.charAt(peg$currPos))) {
          s4 = input.charAt(peg$currPos);
          peg$currPos++;
        } else {
          s4 = peg$FAILED;
        }
      }
      peg$savedPos = s0;
      s0 = peg$f6();
    } else {
      peg$currPos = s0;
      s0 = peg$FAILED;
    }
    peg$silentFails--;
    return s0;
  }
  function peg$parse_() {
    var s0, s1;
    var rule$expects = function(expected2) {
      if (peg$silentFails === 0)
        peg$expect(expected2);
    };
    rule$expects(peg$e10);
    peg$silentFails++;
    s0 = [];
    if (peg$r4.test(input.charAt(peg$currPos))) {
      s1 = input.charAt(peg$currPos);
      peg$currPos++;
    } else {
      s1 = peg$FAILED;
    }
    while (s1 !== peg$FAILED) {
      s0.push(s1);
      if (peg$r4.test(input.charAt(peg$currPos))) {
        s1 = input.charAt(peg$currPos);
        peg$currPos++;
      } else {
        s1 = peg$FAILED;
      }
    }
    peg$silentFails--;
    return s0;
  }
  function makeNode(lhs, rhs, op) {
    if (typeof lhs === "number" && typeof rhs === "number") {
      switch (op) {
        case "+":
          return lhs + rhs;
        case "-":
          return lhs - rhs;
        case "*":
          return lhs * rhs;
        case "/":
          return lhs / rhs;
        case "**":
          return Math.pow(lhs, rhs);
      }
    }
    return {
      lhs,
      rhs,
      op
    };
  }
  peg$begin();
  peg$result = peg$startRuleFunction();
  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
    return peg$result;
  } else {
    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
      peg$expect(peg$endExpectation());
    }
    throw peg$buildError();
  }
}

function hasOwnProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}
function defaultFor(arg, val) {
  return typeof arg !== "undefined" ? arg : val;
}
function create3DContext(canvas, optAttribs) {
  const names = ["webgl", "experimental-webgl"];
  let context = null;
  for (let ii = 0; ii < names.length; ++ii) {
    try {
      context = canvas.getContext(names[ii], optAttribs);
    } catch (e) {
    }
    if (context) {
      break;
    }
  }
  if (!context || !context.getExtension("OES_texture_float")) {
    return null;
  }
  return context;
}
function createProgram(gl, vertexShaderSource2, fragmentShaderSource2) {
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vertexShader, vertexShaderSource2);
  gl.compileShader(vertexShader);
  if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(vertexShader));
  }
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fragmentShader, fragmentShaderSource2);
  gl.compileShader(fragmentShader);
  if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(fragmentShader));
  }
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  return program;
}
function setRectangle(gl, x, y, width, height) {
  const x1 = x;
  const x2 = x + width;
  const y1 = y;
  const y2 = y + height;
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    x1,
    y1,
    x2,
    y1,
    x1,
    y2,
    x1,
    y2,
    x2,
    y1,
    x2,
    y2
  ]), gl.STATIC_DRAW);
}
function createDataset(gl, id, data, width, height) {
  let textureData;
  if (gl) {
    gl.viewport(0, 0, width, height);
    textureData = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, textureData);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texImage2D(
      gl.TEXTURE_2D,
      0,
      gl.LUMINANCE,
      width,
      height,
      0,
      gl.LUMINANCE,
      gl.FLOAT,
      new Float32Array(data)
    );
  }
  return { textureData, width, height, data, id };
}
function destroyDataset(gl, dataset) {
  if (gl) {
    gl.deleteTexture(dataset.textureData);
  }
}
function addColorScale(name, colors, positions) {
  if (colors.length !== positions.length) {
    throw new Error("Invalid color scale.");
  }
  colorscales[name] = { colors, positions };
}
function renderColorScaleToCanvas(name, canvas, type = "continuous") {
  const csDef = colorscales[name];
  canvas.height = 1;
  const ctx = canvas.getContext("2d");
  const width = 8192;
  if (!ctx) {
    throw new Error("Unable to get canvas context.");
  }
  if (Object.prototype.toString.call(csDef) === "[object Object]") {
    canvas.width = width;
    if (type === "continuous") {
      const gradient = ctx.createLinearGradient(0, 0, width, 1);
      for (let i = 0; i < csDef.colors.length; ++i) {
        gradient.addColorStop(csDef.positions[i], csDef.colors[i]);
      }
      ctx.fillStyle = gradient;
      ctx.fillRect(0, 0, width, 1);
    } else if (type === "discrete") {
      for (let i = 0; i < csDef.colors.length; ++i) {
        const nowPos = csDef.positions[i], lastPos = csDef.positions[i + 1];
        const startPos = nowPos * (width - 10);
        const endPos = lastPos ? lastPos * (width - 10) : width;
        ctx.fillStyle = csDef.colors[i];
        ctx.fillRect(startPos, 0, endPos - startPos, 1);
      }
    } else {
      throw new Error("Invalid color scale type.");
    }
  } else if (Object.prototype.toString.call(csDef) === "[object Uint8Array]") {
    canvas.width = width;
    const imgData = ctx.createImageData(width, 1);
    imgData.data.set(csDef);
    ctx.putImageData(imgData, 0, 0);
  } else {
    throw new Error("Color scale not defined.");
  }
}
const vertexShaderSource = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform mat3 u_matrix;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
  // apply transformation matrix
  vec2 position = (u_matrix * vec3(a_position, 1)).xy;
  // convert the rectangle from pixels to 0.0 to 1.0
  vec2 zeroToOne = position / u_resolution;
  // convert from 0->1 to 0->2
  vec2 zeroToTwo = zeroToOne * 2.0;
  // convert from 0->2 to -1->+1 (clipspace)
  vec2 clipSpace = zeroToTwo - 1.0;
  gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
  // pass the texCoord to the fragment shader
  // The GPU will interpolate this value between points.
  v_texCoord = a_texCoord;
}`;
const fragmentShaderSource = `
precision mediump float;
// our texture
uniform sampler2D u_textureData;
uniform sampler2D u_textureScale;
uniform vec2 u_textureSize;
uniform vec2 u_domain;
uniform vec2 u_display_range;
uniform bool u_apply_display_range;
uniform float u_noDataValue;
uniform bool u_clampLow;
uniform bool u_clampHigh;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

bool isnan( float val ) {
  return ( val < 0.0 || 0.0 < val || val == 0.0 ) ? false : true;
}

void main() {
  vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;
  float value = texture2D(u_textureData, v_texCoord)[0];
  if(value < -3.402823466e+38) // Check for possible NaN value
    gl_FragColor = vec4(0.0, 0, 0, 0.0);
  else if (value == u_noDataValue || isnan(value))
    gl_FragColor = vec4(0.0, 0, 0, 0.0);
  else if (u_apply_display_range && (value < u_display_range[0] || value >= u_display_range[1]))
        gl_FragColor = vec4(0.0, 0, 0, 0.0);
  else if ((!u_clampLow && value < u_domain[0]) || (!u_clampHigh && value > u_domain[1]))
    gl_FragColor = vec4(0, 0, 0, 0);
  else {
    float normalisedValue = (value - u_domain[0]) / (u_domain[1] - u_domain[0]);
    gl_FragColor = texture2D(u_textureScale, vec2(normalisedValue, 0));
  }
}`;
class plot {
  canvas;
  currentDataset;
  datasetCollection;
  gl;
  program;
  texCoordBuffer;
  ctx;
  displayRange;
  applyDisplayRange;
  matrix;
  colorScaleImage;
  domain;
  colorScaleCanvas;
  name;
  clampLow;
  clampHigh;
  textureScale;
  noDataValue;
  expressionAst;
  colorType = "continuous";
  positionBuffer;
  programCache = {};
  constructor(options) {
    this.datasetCollection = {};
    this.currentDataset = null;
    this.setCanvas(options.canvas);
    this.setColorType(options.type);
    if (defaultFor(options.useWebGL, true)) {
      const gl = create3DContext(this.canvas, { premultipliedAlpha: false });
      if (gl !== null) {
        this.gl = gl;
        this.program = createProgram(gl, vertexShaderSource, fragmentShaderSource);
        gl.useProgram(this.program);
        const texCoordLocation = gl.getAttribLocation(this.program, "a_texCoord");
        this.texCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          0,
          0,
          1,
          0,
          0,
          1,
          0,
          1,
          1,
          0,
          1,
          1
        ]), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(texCoordLocation);
        gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
        this.positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          0,
          0,
          1,
          0,
          0,
          1,
          0,
          1,
          1,
          0,
          1,
          1
        ]), gl.STATIC_DRAW);
        const positionLocation = gl.getAttribLocation(this.program, "a_position");
        gl.enableVertexAttribArray(positionLocation);
        gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
      } else {
        this.ctx = this.canvas.getContext("2d");
      }
    } else {
      this.ctx = this.canvas.getContext("2d");
    }
    if (options.colorScaleImage) {
      this.setColorScaleImage(options.colorScaleImage);
    } else {
      this.setColorScale(defaultFor(options.colorScale, "viridis"));
    }
    this.setDomain(defaultFor(options.domain, [0, 1]));
    this.displayRange = defaultFor(options.displayRange, [0, 1]);
    this.applyDisplayRange = defaultFor(options.applyDisplayRange, false);
    this.setClamp(defaultFor(options.clampLow, true), options.clampHigh);
    this.setNoDataValue(options.noDataValue);
    if (options.data) {
      const l = options.data.length;
      this.setData(
        options.data,
        defaultFor(options.width, options.data[l - 2]),
        defaultFor(options.height, options.data[l - 2])
      );
    }
    if (options.datasets) {
      for (let i = 0; i < options.datasets.length; ++i) {
        const ds = options.datasets[i];
        this.addDataset(ds.id, ds.data, ds.width, ds.height);
      }
    }
    if (options.matrix) {
      this.matrix = options.matrix;
    } else {
      this.matrix = [
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1
      ];
    }
  }
  /**
   * Get the raw data from the currently selected dataset.
   * @returns {TypedArray} the data of the currently selected dataset.
   */
  getData() {
    const dataset = this.currentDataset;
    if (!dataset) {
      throw new Error("No dataset available.");
    }
    return dataset.data;
  }
  /**
   * Query the raw raster data at the specified coordinates.
   * @param {Number} x the x coordinate
   * @param {Number} y the y coordinate
   * @returns {Number} the value at the specified coordinates
   */
  atPoint(x, y) {
    const dataset = this.currentDataset;
    if (!dataset) {
      throw new Error("No dataset available.");
    } else if (x >= dataset.width || y >= dataset.height) {
      throw new Error("Coordinates are outside of image bounds.");
    }
    return dataset.data[y * dataset.width + x];
  }
  /**
   * Set the raw raster data to be rendered. This creates a new unnamed dataset.
   * @param {TypedArray} data the raw raster data. This can be a typed array of
   *                          any type, but will be coerced to Float32Array when
   *                          beeing rendered.
   * @param {number} width the width of the raster image
   * @param {number} height the height of the data
   */
  setData(data, width, height) {
    if (this.currentDataset && this.currentDataset.id === null) {
      destroyDataset(this.gl, this.currentDataset);
    }
    this.currentDataset = createDataset(this.gl, null, data, width, height);
  }
  /**
   * Add a new named dataset. The semantics are the same as with @see setData.
   * @param {string} id the identifier for the dataset.
   * @param {TypedArray} data the raw raster data. This can be a typed array of
   *                          any type, but will be coerced to Float32Array when
   *                          beeing rendered.
   * @param {number} width the width of the raster image
   * @param {number} height the height of the data
   */
  addDataset(id, data, width, height) {
    if (this.datasetAvailable(id)) {
      throw new Error(`There is already a dataset registered with id '${id}'`);
    }
    this.datasetCollection[id] = createDataset(this.gl, id, data, width, height);
    if (!this.currentDataset) {
      this.currentDataset = this.datasetCollection[id];
    }
  }
  /**
   * Set the current dataset to be rendered.
   * @param {string} id the identifier of the dataset to be rendered.
   */
  setCurrentDataset(id) {
    if (!this.datasetAvailable(id)) {
      throw new Error(`No such dataset registered: '${id}'`);
    }
    if (this.currentDataset && this.currentDataset.id === null) {
      destroyDataset(this.gl, this.currentDataset);
    }
    this.currentDataset = this.datasetCollection[id];
  }
  /**
   * Remove the dataset.
   * @param {string} id the identifier of the dataset to be removed.
   */
  removeDataset(id) {
    const dataset = this.datasetCollection[id];
    if (!dataset) {
      throw new Error(`No such dataset registered: '${id}'`);
    }
    destroyDataset(this.gl, dataset);
    if (this.currentDataset === dataset) {
      this.currentDataset = null;
    }
    delete this.datasetCollection[id];
  }
  removeAllDataset() {
    Object.keys(this.datasetCollection).forEach((id) => this.removeDataset(id));
  }
  /**
   * Check if the dataset is available.
   * @param {string} id the identifier of the dataset to check.
   * @returns {Boolean} whether or not a dataset with that identifier is defined
   */
  datasetAvailable(id) {
    return hasOwnProperty(this.datasetCollection, id);
  }
  /**
   * Retrieve the rendered color scale image.
   * @returns {(HTMLCanvasElement|HTMLImageElement)} the canvas or image element
   *                                                 for the rendered color scale
   */
  getColorScaleImage() {
    return this.colorScaleImage;
  }
  /**
   * Set the canvas to draw to. When no canvas is supplied, a new canvas element
   * is created.
   * @param {HTMLCanvasElement | OffscreenCanvas} [canvas] the canvas element to render to.
   */
  setCanvas(canvas) {
    this.canvas = canvas || document.createElement("canvas");
  }
  setColorType(type) {
    this.colorType = type ?? "continuous";
  }
  /**
   * Set the new value domain for the rendering.
   * @param {number[]} domain the value domain range in the form [low, high]
   */
  setDomain(domain) {
    if (!domain || domain.length !== 2) {
      throw new Error("Invalid domain specified.");
    }
    this.domain = domain;
  }
  /**
   * Set the display range that will be rendered, values outside of the range
   * will not be rendered (transparent)
   * @param {number[]} displayRange range array in the form [min, max]
   */
  setDisplayRange(displayRange) {
    if (!displayRange || displayRange.length !== 2) {
      throw new Error("Invalid view range specified.");
    }
    this.displayRange = displayRange;
    this.applyDisplayRange = true;
  }
  /**
   * Get the canvas that is currently rendered to.
   * @returns {HTMLCanvasElement} the canvas that is currently rendered to.
   */
  getCanvas() {
    return this.canvas;
  }
  /**
   * Set the currently selected color scale.
   * @param {ColorScaleNames} name the name of the colorscale. Must be registered.
   */
  setColorScale(name) {
    if (!hasOwnProperty(colorscales, name)) {
      throw new Error(`No such color scale '${name}'`);
    }
    if (!this.colorScaleCanvas) {
      this.colorScaleCanvas = document.createElement("canvas");
      this.colorScaleCanvas.width = 256;
      this.colorScaleCanvas.height = 1;
    }
    renderColorScaleToCanvas(name, this.colorScaleCanvas, this.colorType);
    this.name = name;
    this.setColorScaleImage(this.colorScaleCanvas);
  }
  /**
   * Set the clamping for the lower and the upper border of the values. When
   * clamping is enabled for either side, the values below or above will be
   * clamped to the minimum/maximum color.
   * @param {Boolean} clampLow whether or not the minimum shall be clamped.
   * @param {Boolean} clampHigh whether or not the maxmimum shall be clamped.
   *                            defaults to clampMin.
   */
  setClamp(clampLow, clampHigh) {
    this.clampLow = clampLow;
    this.clampHigh = typeof clampHigh !== "undefined" ? clampHigh : clampLow;
  }
  /**
   * Set the currently selected color scale as an image or canvas.
   * @param {(HTMLCanvasElement|HTMLImageElement)} colorScaleImage the new color
   *                                                               scale image
   */
  setColorScaleImage(colorScaleImage) {
    this.colorScaleImage = colorScaleImage;
    const gl = this.gl;
    if (gl) {
      if (this.textureScale) {
        gl.deleteTexture(this.textureScale);
      }
      this.textureScale = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, this.textureScale);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, colorScaleImage);
    }
  }
  /**
   * Set the no-data-value: a special value that will be rendered transparent.
   * @param {number} noDataValue the no-data-value. Use null to clear a
   *                            previously set no-data-value.
   */
  setNoDataValue(noDataValue) {
    this.noDataValue = noDataValue;
  }
  /**
   * Render the map to the specified canvas with the given settings.
   */
  render() {
    const canvas = this.canvas;
    const dataset = this.currentDataset;
    canvas.width = dataset.width;
    canvas.height = dataset.height;
    let ids = this.getExpressionIds();
    if (this.gl) {
      this.renderWebGL(dataset, ids);
    } else if (this.ctx) {
      this.render2D(dataset);
    }
  }
  getExpressionIds() {
    if (!this.expressionAst)
      return null;
    const idsSet = /* @__PURE__ */ new Set();
    const getIds = (node) => {
      if (typeof node === "string") {
        idsSet.add(node.replace(/[+-]/g, ""));
      }
      if (typeof node.lhs === "string") {
        idsSet.add(node.lhs.replace(/[+-]/g, ""));
      } else if (typeof node.lhs === "object") {
        getIds(node.lhs);
      }
      if (typeof node.rhs === "string") {
        idsSet.add(node.rhs.replace(/[+-]/g, ""));
      } else if (typeof node.rhs === "object") {
        getIds(node.rhs);
      }
    };
    getIds(this.expressionAst);
    return Array.from(idsSet);
  }
  renderWebGL(dataset, ids) {
    const gl = this.gl;
    gl.viewport(0, 0, dataset.width, dataset.height);
    const program = this.getOrCreateProgram(ids);
    gl.useProgram(program);
    this.setupTextures(program, ids, dataset);
    this.setupUniforms(program);
    this.setupAttributes(program);
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  }
  getOrCreateProgram(ids) {
    if (!this.expressionAst) {
      return this.program;
    }
    const exprKey = JSON.stringify(this.expressionAst);
    if (this.programCache[exprKey]) {
      return this.programCache[exprKey];
    }
    const vertexShader = this.createVertexShader();
    const fragmentShader = this.createFragmentShader(ids);
    const program = createProgram(this.gl, vertexShader, fragmentShader);
    this.programCache[exprKey] = program;
    return program;
  }
  createVertexShader() {
    return `
      attribute vec2 a_position;
      attribute vec2 a_texCoord;
      uniform mat3 u_matrix;
      uniform vec2 u_resolution;
      varying vec2 v_texCoord;
      void main() {
        vec2 position = (u_matrix * vec3(a_position, 1)).xy;
        vec2 zeroToOne = position / u_resolution;
        vec2 zeroToTwo = zeroToOne * 2.0;
        vec2 clipSpace = zeroToTwo - 1.0;
        gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
        v_texCoord = a_texCoord;
      }
    `;
  }
  createFragmentShader(ids) {
    if (!ids) {
      return fragmentShaderSource;
    }
    const expressionReducer = (node) => {
      if (typeof node === "object") {
        if (node.op === "**") {
          return `pow(${expressionReducer(node.lhs)}, ${expressionReducer(node.rhs)})`;
        }
        if (node.fn) {
          return `(${node.fn}(${expressionReducer(node.lhs)}))`;
        }
        return `(${expressionReducer(node.lhs)} ${node.op} ${expressionReducer(node.rhs)})`;
      } else if (typeof node === "string") {
        return `${node}_value`;
      }
      return `float(${node})`;
    };
    const compiledExpression = expressionReducer(this.expressionAst);
    return `
      precision mediump float;
      uniform sampler2D u_textureScale;
      ${ids.map((id) => `uniform sampler2D u_texture_${id};`).join("\n")}
      uniform vec2 u_textureSize;
      uniform vec2 u_domain;
      uniform vec2 u_display_range;
      uniform bool u_apply_display_range;
      uniform float u_noDataValue;
      uniform bool u_clampLow;
      uniform bool u_clampHigh;
      varying vec2 v_texCoord;
      void main() {
        ${ids.map((id) => `float ${id}_value = texture2D(u_texture_${id}, v_texCoord)[0];`).join("\n")}
        float value = ${compiledExpression};

        if (value == u_noDataValue)
          gl_FragColor = vec4(0.0, 0, 0, 0.0);
        else if (u_apply_display_range && (value < u_display_range[0] || value >= u_display_range[1]))
          gl_FragColor = vec4(0.0, 0, 0, 0.0);
        else if ((!u_clampLow && value < u_domain[0]) || (!u_clampHigh && value > u_domain[1]))
          gl_FragColor = vec4(0, 0, 0, 0);
        else {
          float normalisedValue = (value - u_domain[0]) / (u_domain[1] - u_domain[0]);
          gl_FragColor = texture2D(u_textureScale, vec2(normalisedValue, 0));
        }
      }
    `;
  }
  setupTextures(program, ids, dataset) {
    const gl = this.gl;
    if (ids) {
      gl.uniform1i(gl.getUniformLocation(program, "u_textureScale"), 0);
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, this.textureScale);
      ids.forEach((id, index) => {
        const location = index + 1;
        const ds = this.datasetCollection[id];
        if (!ds) {
          throw new Error(`No such dataset registered: '${id}'`);
        }
        gl.uniform1i(gl.getUniformLocation(program, `u_texture_${id}`), location);
        gl.activeTexture(gl[`TEXTURE${location}`]);
        gl.bindTexture(gl.TEXTURE_2D, ds.textureData);
      });
    } else {
      gl.uniform1i(gl.getUniformLocation(program, "u_textureData"), 0);
      gl.uniform1i(gl.getUniformLocation(program, "u_textureScale"), 1);
      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, dataset.textureData);
      gl.activeTexture(gl.TEXTURE1);
      gl.bindTexture(gl.TEXTURE_2D, this.textureScale);
    }
  }
  setupUniforms(program) {
    const gl = this.gl;
    const canvas = this.canvas;
    gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), canvas.width, canvas.height);
    gl.uniform2fv(gl.getUniformLocation(program, "u_domain"), this.domain);
    gl.uniform2fv(gl.getUniformLocation(program, "u_display_range"), this.displayRange);
    gl.uniform1i(gl.getUniformLocation(program, "u_apply_display_range"), +this.applyDisplayRange);
    gl.uniform1i(gl.getUniformLocation(program, "u_clampLow"), +this.clampLow);
    gl.uniform1i(gl.getUniformLocation(program, "u_clampHigh"), +this.clampHigh);
    gl.uniform1f(gl.getUniformLocation(program, "u_noDataValue"), this.noDataValue);
    gl.uniformMatrix3fv(gl.getUniformLocation(program, "u_matrix"), false, this.matrix);
  }
  setupAttributes(program) {
    const gl = this.gl;
    const canvas = this.canvas;
    const positionLocation = gl.getAttribLocation(program, "a_position");
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    setRectangle(gl, 0, 0, canvas.width, canvas.height);
  }
  render2D(dataset) {
    const ctx = this.ctx;
    const w = this.canvas.width;
    const h = this.canvas.height;
    const imageData = ctx.createImageData(w, h);
    const trange = this.domain[1] - this.domain[0];
    const steps = this.colorScaleCanvas.width;
    const csImageData = this.colorScaleCanvas.getContext("2d").getImageData(0, 0, steps, 1).data;
    let alpha;
    const data = dataset.data;
    for (let y = 0; y < h; y++) {
      for (let x = 0; x < w; x++) {
        const i = y * w + x;
        let c = Math.floor((data[i] - this.domain[0]) / trange * (steps - 1));
        alpha = 255;
        if (c < 0) {
          c = 0;
          if (!this.clampLow) {
            alpha = 0;
          }
        } else if (c > 255) {
          c = 255;
          if (!this.clampHigh) {
            alpha = 0;
          }
        }
        if (data[i] === this.noDataValue || data[i] !== data[i]) {
          alpha = 0;
        } else if (this.applyDisplayRange && (data[i] < this.displayRange[0] || data[i] >= this.displayRange[1])) {
          alpha = 0;
        }
        const index = (y * w + x) * 4;
        imageData.data[index + 0] = csImageData[c * 4];
        imageData.data[index + 1] = csImageData[c * 4 + 1];
        imageData.data[index + 2] = csImageData[c * 4 + 2];
        imageData.data[index + 3] = Math.min(alpha, csImageData[c * 4 + 3]);
      }
    }
    ctx.putImageData(imageData, 0, 0);
  }
  /**
   * Render the specified dataset with the current settings.
   * @param {string} id the identifier of the dataset to render.
   */
  renderDataset(id) {
    this.setCurrentDataset(id);
    return this.render();
  }
  /**
   * Get the color for the specified value.
   * @param {number} val the value to query the color for.
   * @returns {Array} the 4-tuple: red, green, blue, alpha in the range 0-255.
   */
  getColor(val) {
    const steps = this.colorScaleCanvas.width;
    const csImageData = this.colorScaleCanvas.getContext("2d").getImageData(0, 0, steps, 1).data;
    const trange = this.domain[1] - this.domain[0];
    let c = Math.round((val - this.domain[0]) / trange * steps);
    let alpha = 255;
    if (c < 0) {
      c = 0;
      if (!this.clampLow) {
        alpha = 0;
      }
    }
    if (c > 255) {
      c = 255;
      if (!this.clampHigh) {
        alpha = 0;
      }
    }
    return [
      csImageData[c * 4],
      csImageData[c * 4 + 1],
      csImageData[c * 4 + 2],
      alpha
    ];
  }
  /**
   * Sets a mathematical expression to be evaluated on the plot. Expression can contain mathematical operations with integer/float values, dataset identifiers or GLSL supported functions with a single parameter.
   * Supported mathematical operations are: add '+', subtract '-', multiply '*', divide '/', power '**', unary plus '+a', unary minus '-a'.
   * Useful GLSL functions are for example: radians, degrees, sin, asin, cos, acos, tan, atan, log2, log, sqrt, exp2, exp, abs, sign, floor, ceil, fract.
   * @param {string} expression Mathematical expression. Example: '-2 * sin(3.1415 - dataset1) ** 2'
   */
  setExpression(expression) {
    if (!expression || !expression.length) {
      this.expressionAst = null;
    } else {
      this.expressionAst = peg$parse(expression);
    }
  }
  destroy() {
    var _a;
    (_a = this.gl) == null ? void 0 : _a.deleteProgram(this.program);
    this.removeAllDataset();
  }
}

function getMinMax(data, nodata) {
  let min, max;
  for (let j = 0; j < data.length; j += 1) {
    const val = data[j];
    if (val === nodata)
      continue;
    if (min === void 0 && max === void 0) {
      min = max = val;
      continue;
    }
    if (val < min) {
      min = val;
    } else if (val > max) {
      max = val;
    }
  }
  return {
    min,
    max
  };
}
function decimal2rgb(number) {
  return Math.round(number * 255);
}
function getRange(bands, opts) {
  const band = bands[opts.band];
  if (!band) {
    throw new Error(`Invalid band${opts.band}`);
  }
  const min = (opts == null ? void 0 : opts.min) ?? +band.min;
  const max = (opts == null ? void 0 : opts.max) ?? +band.max;
  const range = max - min;
  return { min, max, range };
}
function generateColorScale(colors, minMax) {
  let stops;
  if (typeof colors[0] === "string") {
    stops = colors.map((color, index) => [index / colors.length, color]);
  } else {
    const [min, max] = minMax;
    stops = colors.map((item) => [(item[0] - min) / (max - min), item[1]]);
  }
  stops.sort((a, b) => a[0] - b[0]);
  let i = stops.length - 1;
  while (i > 1 && stops[i][0] >= 1 && stops[i - 1][0] >= 1) {
    stops.pop();
    i--;
  }
  if (stops[0][0] > 0) {
    stops = [[0, stops[0][1]], ...stops];
  }
  const colorScale = {
    colors: stops.map((stop) => stop[1]),
    positions: stops.map((stop) => {
      let s = stop[0];
      if (s < 0)
        return 0;
      if (s > 1)
        return 1;
      return s;
    })
  };
  return colorScale;
}
function findAndSortBandNumbers(str) {
  const regex = /b(\d+)/g;
  const bandNumbers = /* @__PURE__ */ new Set();
  let match;
  while ((match = regex.exec(str)) !== null) {
    bandNumbers.add(parseInt(match[1]) - 1);
  }
  return Array.from(bandNumbers).sort((a, b) => a - b);
}
function stringColorToRgba(color) {
  const newColor = Color.fromCssColorString(color);
  const { red, green, blue, alpha } = newColor;
  return [red, green, blue, alpha].map((val) => Math.round(val * 255));
}
function reverseArray(options) {
  const { array, width, height } = options;
  const reversedArray = [];
  for (let row = height - 1; row >= 0; row--) {
    const startIndex = row * width;
    const endIndex = startIndex + width;
    const rowArray = array.slice(startIndex, endIndex);
    reversedArray.push(...rowArray);
  }
  return reversedArray;
}

class TIFFImageryProviderTilingScheme extends WebMercatorTilingScheme {
  nativeRectangle;
  constructor(options) {
    super(options);
    const { project, unproject } = options;
    this.nativeRectangle = new Rectangle(options.rectangleSouthwestInMeters.x, options.rectangleSouthwestInMeters.y, options.rectangleNortheastInMeters.x, options.rectangleNortheastInMeters.y);
    this._projection = {
      ellipsoid: this.ellipsoid,
      project(cartographic, result) {
        const [x, y] = project([cartographic.longitude, cartographic.latitude].map(Math$1.toDegrees));
        const z = cartographic.height;
        return Cartesian3.fromElements(x, y, z, result);
      },
      unproject(cartesian, result) {
        const [longitude, latitude] = unproject([cartesian.x, cartesian.y]);
        const height = cartesian.z;
        return Cartographic.fromDegrees(longitude, latitude, height, result);
      }
    };
    const swMeters = new Cartesian3();
    options.rectangleSouthwestInMeters.clone(swMeters);
    const neMeters = new Cartesian3();
    options.rectangleNortheastInMeters.clone(neMeters);
    const seMeters = new Cartesian3(neMeters.x, swMeters.y);
    const nwMeters = new Cartesian3(swMeters.x, neMeters.y);
    const southwest = this.projection.unproject(swMeters);
    const southeast = this.projection.unproject(seMeters);
    const northwest = this.projection.unproject(nwMeters);
    const northeast = this.projection.unproject(neMeters);
    this._rectangle = Rectangle.fromCartographicArray([southwest, southeast, northwest, northeast]);
  }
  tileXYToNativeRectangle2(x, y, level) {
    const rect = this.tileXYToRectangle(x, y, level);
    const projection = this.projection;
    const ws = projection.project(new Cartographic(rect.west, rect.south));
    const wn = projection.project(new Cartographic(rect.west, rect.north));
    const en = projection.project(new Cartographic(rect.east, rect.north));
    const es = projection.project(new Cartographic(rect.east, rect.south));
    const positions = [ws, wn, en, es];
    const xx = positions.map((pos) => pos.x);
    const yy = positions.map((pos) => pos.y);
    return new Rectangle(
      Math.min(...xx),
      Math.min(...yy),
      Math.max(...xx),
      Math.max(...yy)
    );
  }
  tileXYToRectangle(x, y, level) {
    const rect = this.tileXYToNativeRectangle(x, y, level);
    const projection = this.projection;
    const ws = projection.unproject(new Cartesian3(rect.west, rect.south));
    const wn = projection.unproject(new Cartesian3(rect.west, rect.north));
    const en = projection.unproject(new Cartesian3(rect.east, rect.north));
    const es = projection.unproject(new Cartesian3(rect.east, rect.south));
    const newRect = Rectangle.fromCartographicArray([ws, wn, en, es]);
    if (newRect.east < newRect.west) {
      newRect.east += Math$1.TWO_PI;
    }
    return newRect;
  }
}

function resampleNearest(data, options) {
  const { sourceWidth, sourceHeight, targetWidth, targetHeight, window, buffer = 0 } = options;
  const [x0, y0, x1, y1] = window;
  const effectiveSourceWidth = sourceWidth - 2 * buffer;
  const effectiveSourceHeight = sourceHeight - 2 * buffer;
  const resampledData = copyNewSize(data, targetWidth, targetHeight);
  for (let y = 0; y < targetHeight; y++) {
    for (let x = 0; x < targetWidth; x++) {
      const col = buffer + (effectiveSourceWidth * (x0 + x / targetWidth * (x1 - x0)) >>> 0);
      const row = buffer + (effectiveSourceHeight * (y0 + y / targetHeight * (y1 - y0)) >>> 0);
      resampledData[y * targetWidth + x] = data[row * sourceWidth + col];
    }
  }
  return resampledData;
}
function resampleData(data, options) {
  const { method = "nearest" } = options;
  switch (method) {
    case "nearest":
      return resampleNearest(data, options);
    case "bilinear":
      return resampleBilinear(data, options);
  }
}
function copyNewSize(array, width, height, samplesPerPixel = 1) {
  return new (Object.getPrototypeOf(array)).constructor(width * height * samplesPerPixel);
}
function lerp(v0, v1, t) {
  return (1 - t) * v0 + t * v1;
}
function resampleBilinear(data, options) {
  const { sourceWidth, sourceHeight, targetWidth, targetHeight, window, buffer = 0, nodata } = options;
  const [x0, y0, x1, y1] = window;
  const windowWidth = x1 - x0;
  const windowHeight = y1 - y0;
  const newArray = copyNewSize(data, targetWidth, targetHeight);
  const effectiveSourceWidth = sourceWidth - 2 * buffer;
  const effectiveSourceHeight = sourceHeight - 2 * buffer;
  const invTargetWidth = 1 / targetWidth;
  const invTargetHeight = 1 / targetHeight;
  const isNodata = (value) => {
    if (nodata === void 0)
      return false;
    if (nodata === 0)
      return value === 0;
    return Math.abs((value - nodata) / nodata) < 1e-6;
  };
  for (let y = 0; y < targetHeight; y++) {
    const yRatio = y * invTargetHeight;
    const yMapped = y0 + yRatio * windowHeight;
    const rawY = effectiveSourceHeight * yMapped + buffer;
    const yl = Math.floor(rawY);
    const yh = Math.min(Math.ceil(rawY), sourceHeight - buffer - 1);
    const ty = rawY - yl;
    for (let x = 0; x < targetWidth; x++) {
      const xRatio = x * invTargetWidth;
      const xMapped = x0 + xRatio * windowWidth;
      const rawX = effectiveSourceWidth * xMapped + buffer;
      const xl = Math.floor(rawX);
      const xh = Math.min(Math.ceil(rawX), sourceWidth - buffer - 1);
      const txFraction = rawX - xl;
      const center = data[yl * sourceWidth + xl];
      const neighbors = [
        data[yl * sourceWidth + xl],
        data[yl * sourceWidth + xh],
        data[yh * sourceWidth + xl],
        data[yh * sourceWidth + xh]
      ];
      neighbors.forEach((neighbor, index) => {
        if (isNodata(neighbor)) {
          neighbors[index] = center;
        }
      });
      if (isNodata(center)) {
        newArray[y * targetWidth + x] = nodata;
        continue;
      }
      const [ll, hl, lh, hh] = neighbors;
      const v0 = lerp(ll, hl, txFraction);
      const v1 = lerp(lh, hh, txFraction);
      const value = lerp(v0, v1, ty);
      newArray[y * targetWidth + x] = value;
    }
  }
  return newArray;
}

function inRange(val, range) {
  if (val < range[0] && val < range[1] || val > range[0] && val > range[1]) {
    return false;
  } else {
    return true;
  }
}
function reprojection(options) {
  const { data, sourceBBox, targetBBox, project, sourceWidth, sourceHeight, nodata } = options;
  const { targetWidth = sourceWidth, targetHeight = sourceHeight } = options;
  const [minX, minY, maxX, maxY] = sourceBBox;
  const [minLon, minLat, maxLon, maxLat] = targetBBox;
  const stepX = Math.abs(maxX - minX) / sourceWidth;
  const stepY = Math.abs(maxY - minY) / sourceHeight;
  const stepLon = Math.abs(maxLon - minLon) / targetWidth;
  const stepLat = Math.abs(maxLat - minLat) / targetHeight;
  const result = copyNewSize(data, targetWidth, targetHeight).fill(nodata);
  for (let i = 0; i < targetHeight; i++) {
    for (let j = 0; j < targetWidth; j++) {
      const lon = minLon + stepLon * (j + 0.5);
      const lat = maxLat - stepLat * (i + 0.5);
      const [x, y] = project([lon, lat]);
      if (!inRange(x, [minX, maxX]) || !inRange(y, [minX, maxY])) {
        break;
      }
      const indexX = ~~((x - minX) / stepX);
      const indexY = ~~((maxY - y) / stepY);
      const sourceVal = data[indexY * sourceWidth + indexX];
      const index = i * targetWidth + j;
      result[index] = sourceVal;
    }
  }
  return result;
}

async function generateImage(opts) {
  const { data, width, height, renderOptions, bands, noData, colorMapping } = opts;
  const imageData = new Uint8ClampedArray(width * height * 4);
  function ifNoDataFunc(...vals) {
    if (vals.some((val) => isNaN(val) || val === noData))
      return true;
    return false;
  }
  const { r, g, b } = renderOptions ?? {};
  const ranges = [r, g, b].map((item) => getRange(bands, item));
  const redData = data[0];
  const greenData = data[1];
  const blueData = data[2];
  for (let i = 0; i < data[0].length; i++) {
    let red = decimal2rgb((redData[i] - ranges[0].min) / ranges[0].range);
    let green = decimal2rgb((greenData[i] - ranges[1].min) / ranges[1].range);
    let blue = decimal2rgb((blueData[i] - ranges[2].min) / ranges[2].range);
    let alpha = ifNoDataFunc(redData[i], greenData[i], blueData[i]) ? 0 : 255;
    colorMapping.map(([colorFrom, colorTo]) => {
      if (red === colorFrom[0] && green === colorFrom[1] && blue === colorFrom[2]) {
        red = colorTo[0];
        green = colorTo[1];
        blue = colorTo[2];
        alpha = colorTo[3];
      }
    });
    imageData[i * 4] = red;
    imageData[i * 4 + 1] = green;
    imageData[i * 4 + 2] = blue;
    imageData[i * 4 + 3] = alpha;
  }
  const result = new ImageData(imageData, width, height);
  return result;
}

function createCanavas(width, height) {
  if ("OffscreenCanvas" in window) {
    return new OffscreenCanvas(width, height);
  } else {
    const canv = document.createElement("canvas");
    canv.width = width;
    canv.height = height;
    return canv;
  }
}

var WorkerClass = null;

try {
    var WorkerThreads =
        typeof module !== 'undefined' && typeof module.require === 'function' && module.require('worker_threads') ||
        typeof __non_webpack_require__ === 'function' && __non_webpack_require__('worker_threads') ||
        typeof require === 'function' && require('worker_threads');
    WorkerClass = WorkerThreads.Worker;
} catch(e) {} // eslint-disable-line

function decodeBase64$1(base64, enableUnicode) {
    return Buffer.from(base64, 'base64').toString(enableUnicode ? 'utf16' : 'utf8');
}

function createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg) {
    var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
    var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
    var source = decodeBase64$1(base64, enableUnicode);
    var start = source.indexOf('\n', 10) + 1;
    var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
    return function WorkerFactory(options) {
        return new WorkerClass(body, Object.assign({}, options, { eval: true }));
    };
}

function decodeBase64(base64, enableUnicode) {
    var binaryString = atob(base64);
    if (enableUnicode) {
        var binaryView = new Uint8Array(binaryString.length);
        for (var i = 0, n = binaryString.length; i < n; ++i) {
            binaryView[i] = binaryString.charCodeAt(i);
        }
        return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));
    }
    return binaryString;
}

function createURL(base64, sourcemapArg, enableUnicodeArg) {
    var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
    var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
    var source = decodeBase64(base64, enableUnicode);
    var start = source.indexOf('\n', 10) + 1;
    var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
    var blob = new Blob([body], { type: 'application/javascript' });
    return URL.createObjectURL(blob);
}

function createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg) {
    var url;
    return function WorkerFactory(options) {
        url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
        return new Worker(url, options);
    };
}

var kIsNodeJS = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';

function isNodeJS() {
    return kIsNodeJS;
}

function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
    if (isNodeJS()) {
        return createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg);
    }
    return createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg);
}

var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgZnVuY3Rpb24gcmVzYW1wbGVOZWFyZXN0KGRhdGEsIG9wdGlvbnMpIHsKICAgIGNvbnN0IHsgc291cmNlV2lkdGgsIHNvdXJjZUhlaWdodCwgdGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCwgd2luZG93LCBidWZmZXIgPSAwIH0gPSBvcHRpb25zOwogICAgY29uc3QgW3gwLCB5MCwgeDEsIHkxXSA9IHdpbmRvdzsKICAgIGNvbnN0IGVmZmVjdGl2ZVNvdXJjZVdpZHRoID0gc291cmNlV2lkdGggLSAyICogYnVmZmVyOwogICAgY29uc3QgZWZmZWN0aXZlU291cmNlSGVpZ2h0ID0gc291cmNlSGVpZ2h0IC0gMiAqIGJ1ZmZlcjsKICAgIGNvbnN0IHJlc2FtcGxlZERhdGEgPSBjb3B5TmV3U2l6ZShkYXRhLCB0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0KTsKICAgIGZvciAobGV0IHkgPSAwOyB5IDwgdGFyZ2V0SGVpZ2h0OyB5KyspIHsKICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCB0YXJnZXRXaWR0aDsgeCsrKSB7CiAgICAgICAgY29uc3QgY29sID0gYnVmZmVyICsgKGVmZmVjdGl2ZVNvdXJjZVdpZHRoICogKHgwICsgeCAvIHRhcmdldFdpZHRoICogKHgxIC0geDApKSA+Pj4gMCk7CiAgICAgICAgY29uc3Qgcm93ID0gYnVmZmVyICsgKGVmZmVjdGl2ZVNvdXJjZUhlaWdodCAqICh5MCArIHkgLyB0YXJnZXRIZWlnaHQgKiAoeTEgLSB5MCkpID4+PiAwKTsKICAgICAgICByZXNhbXBsZWREYXRhW3kgKiB0YXJnZXRXaWR0aCArIHhdID0gZGF0YVtyb3cgKiBzb3VyY2VXaWR0aCArIGNvbF07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiByZXNhbXBsZWREYXRhOwogIH0KICBmdW5jdGlvbiByZXNhbXBsZURhdGEoZGF0YSwgb3B0aW9ucykgewogICAgY29uc3QgeyBtZXRob2QgPSAibmVhcmVzdCIgfSA9IG9wdGlvbnM7CiAgICBzd2l0Y2ggKG1ldGhvZCkgewogICAgICBjYXNlICJuZWFyZXN0IjoKICAgICAgICByZXR1cm4gcmVzYW1wbGVOZWFyZXN0KGRhdGEsIG9wdGlvbnMpOwogICAgICBjYXNlICJiaWxpbmVhciI6CiAgICAgICAgcmV0dXJuIHJlc2FtcGxlQmlsaW5lYXIoZGF0YSwgb3B0aW9ucyk7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGNvcHlOZXdTaXplKGFycmF5LCB3aWR0aCwgaGVpZ2h0LCBzYW1wbGVzUGVyUGl4ZWwgPSAxKSB7CiAgICByZXR1cm4gbmV3IChPYmplY3QuZ2V0UHJvdG90eXBlT2YoYXJyYXkpKS5jb25zdHJ1Y3Rvcih3aWR0aCAqIGhlaWdodCAqIHNhbXBsZXNQZXJQaXhlbCk7CiAgfQogIGZ1bmN0aW9uIGxlcnAodjAsIHYxLCB0KSB7CiAgICByZXR1cm4gKDEgLSB0KSAqIHYwICsgdCAqIHYxOwogIH0KICBmdW5jdGlvbiByZXNhbXBsZUJpbGluZWFyKGRhdGEsIG9wdGlvbnMpIHsKICAgIGNvbnN0IHsgc291cmNlV2lkdGgsIHNvdXJjZUhlaWdodCwgdGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCwgd2luZG93LCBidWZmZXIgPSAwLCBub2RhdGEgfSA9IG9wdGlvbnM7CiAgICBjb25zdCBbeDAsIHkwLCB4MSwgeTFdID0gd2luZG93OwogICAgY29uc3Qgd2luZG93V2lkdGggPSB4MSAtIHgwOwogICAgY29uc3Qgd2luZG93SGVpZ2h0ID0geTEgLSB5MDsKICAgIGNvbnN0IG5ld0FycmF5ID0gY29weU5ld1NpemUoZGF0YSwgdGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCk7CiAgICBjb25zdCBlZmZlY3RpdmVTb3VyY2VXaWR0aCA9IHNvdXJjZVdpZHRoIC0gMiAqIGJ1ZmZlcjsKICAgIGNvbnN0IGVmZmVjdGl2ZVNvdXJjZUhlaWdodCA9IHNvdXJjZUhlaWdodCAtIDIgKiBidWZmZXI7CiAgICBjb25zdCBpbnZUYXJnZXRXaWR0aCA9IDEgLyB0YXJnZXRXaWR0aDsKICAgIGNvbnN0IGludlRhcmdldEhlaWdodCA9IDEgLyB0YXJnZXRIZWlnaHQ7CiAgICBjb25zdCBpc05vZGF0YSA9ICh2YWx1ZSkgPT4gewogICAgICBpZiAobm9kYXRhID09PSB2b2lkIDApCiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICBpZiAobm9kYXRhID09PSAwKQogICAgICAgIHJldHVybiB2YWx1ZSA9PT0gMDsKICAgICAgcmV0dXJuIE1hdGguYWJzKCh2YWx1ZSAtIG5vZGF0YSkgLyBub2RhdGEpIDwgMWUtNjsKICAgIH07CiAgICBmb3IgKGxldCB5ID0gMDsgeSA8IHRhcmdldEhlaWdodDsgeSsrKSB7CiAgICAgIGNvbnN0IHlSYXRpbyA9IHkgKiBpbnZUYXJnZXRIZWlnaHQ7CiAgICAgIGNvbnN0IHlNYXBwZWQgPSB5MCArIHlSYXRpbyAqIHdpbmRvd0hlaWdodDsKICAgICAgY29uc3QgcmF3WSA9IGVmZmVjdGl2ZVNvdXJjZUhlaWdodCAqIHlNYXBwZWQgKyBidWZmZXI7CiAgICAgIGNvbnN0IHlsID0gTWF0aC5mbG9vcihyYXdZKTsKICAgICAgY29uc3QgeWggPSBNYXRoLm1pbihNYXRoLmNlaWwocmF3WSksIHNvdXJjZUhlaWdodCAtIGJ1ZmZlciAtIDEpOwogICAgICBjb25zdCB0eSA9IHJhd1kgLSB5bDsKICAgICAgZm9yIChsZXQgeCA9IDA7IHggPCB0YXJnZXRXaWR0aDsgeCsrKSB7CiAgICAgICAgY29uc3QgeFJhdGlvID0geCAqIGludlRhcmdldFdpZHRoOwogICAgICAgIGNvbnN0IHhNYXBwZWQgPSB4MCArIHhSYXRpbyAqIHdpbmRvd1dpZHRoOwogICAgICAgIGNvbnN0IHJhd1ggPSBlZmZlY3RpdmVTb3VyY2VXaWR0aCAqIHhNYXBwZWQgKyBidWZmZXI7CiAgICAgICAgY29uc3QgeGwgPSBNYXRoLmZsb29yKHJhd1gpOwogICAgICAgIGNvbnN0IHhoID0gTWF0aC5taW4oTWF0aC5jZWlsKHJhd1gpLCBzb3VyY2VXaWR0aCAtIGJ1ZmZlciAtIDEpOwogICAgICAgIGNvbnN0IHR4RnJhY3Rpb24gPSByYXdYIC0geGw7CiAgICAgICAgY29uc3QgY2VudGVyID0gZGF0YVt5bCAqIHNvdXJjZVdpZHRoICsgeGxdOwogICAgICAgIGNvbnN0IG5laWdoYm9ycyA9IFsKICAgICAgICAgIGRhdGFbeWwgKiBzb3VyY2VXaWR0aCArIHhsXSwKICAgICAgICAgIGRhdGFbeWwgKiBzb3VyY2VXaWR0aCArIHhoXSwKICAgICAgICAgIGRhdGFbeWggKiBzb3VyY2VXaWR0aCArIHhsXSwKICAgICAgICAgIGRhdGFbeWggKiBzb3VyY2VXaWR0aCArIHhoXQogICAgICAgIF07CiAgICAgICAgbmVpZ2hib3JzLmZvckVhY2goKG5laWdoYm9yLCBpbmRleCkgPT4gewogICAgICAgICAgaWYgKGlzTm9kYXRhKG5laWdoYm9yKSkgewogICAgICAgICAgICBuZWlnaGJvcnNbaW5kZXhdID0gY2VudGVyOwogICAgICAgICAgfQogICAgICAgIH0pOwogICAgICAgIGlmIChpc05vZGF0YShjZW50ZXIpKSB7CiAgICAgICAgICBuZXdBcnJheVt5ICogdGFyZ2V0V2lkdGggKyB4XSA9IG5vZGF0YTsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KICAgICAgICBjb25zdCBbbGwsIGhsLCBsaCwgaGhdID0gbmVpZ2hib3JzOwogICAgICAgIGNvbnN0IHYwID0gbGVycChsbCwgaGwsIHR4RnJhY3Rpb24pOwogICAgICAgIGNvbnN0IHYxID0gbGVycChsaCwgaGgsIHR4RnJhY3Rpb24pOwogICAgICAgIGNvbnN0IHZhbHVlID0gbGVycCh2MCwgdjEsIHR5KTsKICAgICAgICBuZXdBcnJheVt5ICogdGFyZ2V0V2lkdGggKyB4XSA9IHZhbHVlOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gbmV3QXJyYXk7CiAgfQoKICBvbm1lc3NhZ2UgPSBmdW5jdGlvbihlKSB7CiAgICBjb25zdCB7IGRhdGEsIG9wdGlvbnMsIGlkIH0gPSBlLmRhdGE7CiAgICBjb25zdCByZXN1bHQgPSByZXNhbXBsZURhdGEoZGF0YSwgb3B0aW9ucyk7CiAgICBwb3N0TWVzc2FnZSh7IGRhdGE6IHJlc3VsdCwgaWQgfSk7CiAgfTsKCn0pKCk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPXdvcmtlci5qcy5tYXAKCg==', null, false);
/* eslint-enable */

const defaultPoolSize = typeof navigator !== "undefined" ? navigator.hardwareConcurrency || 2 : 2;
class WorkerPool {
  workers;
  size;
  messageId;
  /**
   * @constructor
   * @param {Number} [size] The size of the pool. Defaults to the number of CPUs
   *                      available. When this parameter is `null` or 0, then the
   *                      decoding will be done in the main thread.
   */
  constructor(size = defaultPoolSize) {
    this.workers = null;
    this.size = size ?? 0;
    this.messageId = 0;
    if (size) {
      this.workers = [];
      for (let i = 0; i < size; i++) {
        this.workers.push({ worker: WorkerFactory(), idle: true });
      }
    }
  }
  async resample(data, options) {
    return this.size === 0 ? resampleData(data, options) : new Promise((resolve) => {
      const worker = this.workers.find((candidate) => candidate.idle) || this.workers[Math.floor(Math.random() * this.size)];
      worker.idle = false;
      const id = this.messageId++;
      const onMessage = (e) => {
        if (e.data.id === id) {
          worker.idle = true;
          resolve(e.data.data);
          worker.worker.removeEventListener("message", onMessage);
        }
      };
      worker.worker.addEventListener("message", onMessage);
      worker.worker.postMessage({ data, options, id });
    });
  }
  destroy() {
    if (this.workers) {
      this.workers.forEach((worker) => {
        worker.worker.terminate();
      });
      this.workers = null;
    }
  }
}

const canvas = createCanavas(256, 256);
class TIFFImageryProvider {
  constructor(options) {
    this.options = options;
    this.hasAlphaChannel = options.hasAlphaChannel ?? true;
    this.maximumLevel = options.maximumLevel ?? 18;
    this.minimumLevel = options.minimumLevel ?? 0;
    this.credit = new Credit(options.credit || "", false);
    this.errorEvent = new Event();
    this._cacheSize = options.cacheSize ?? 100;
    this.workerPool = new WorkerPool(options.workerPoolSize);
    this.geotiffWorkerPool = new Pool(options.workerPoolSize);
    this.ready = false;
    if (defined(options.url)) {
      this.readyPromise = this._build(options.url, options).then(() => {
        return true;
      });
    }
  }
  ready;
  tilingScheme;
  rectangle;
  tileSize;
  tileWidth;
  tileHeight;
  maximumLevel;
  minimumLevel;
  credit;
  errorEvent;
  readyPromise;
  bands;
  noData;
  hasAlphaChannel;
  plot;
  renderOptions;
  readSamples;
  requestLevels;
  bbox;
  _destroyed = false;
  _source;
  _imageCount;
  _images = [];
  _imagesCache = /* @__PURE__ */ new Map();
  _cacheSize;
  _isTiled;
  _proj;
  origin;
  reverseY = false;
  samples;
  workerPool;
  geotiffWorkerPool;
  get isDestroyed() {
    return this._destroyed;
  }
  async _build(url, options = {}) {
    var _a, _b;
    const { tileSize, renderOptions, projFunc, requestOptions } = options;
    let source = await (url instanceof File || url instanceof Blob ? fromBlob(url) : fromUrl(url, requestOptions));
    let image = await source.getImage();
    this._isTiled = image.isTiled;
    if (!this._isTiled && typeof url === "string") {
      source = await fromBlob(await (await fetch(url)).blob());
      image = await source.getImage();
    }
    this._source = source;
    this.origin = this._getOrigin(image);
    this.bbox = image.getBoundingBox();
    this.reverseY = this._checkIfReversed(image);
    const [west, south, east, north] = this.bbox;
    const prjCode = +(image.geoKeys.ProjectedCSTypeGeoKey ?? image.geoKeys.GeographicTypeGeoKey);
    this._proj = projFunc == null ? void 0 : projFunc(prjCode);
    if (prjCode === 3857 || prjCode === 900913) {
      this.tilingScheme = new WebMercatorTilingScheme({
        rectangleNortheastInMeters: new Cartesian2(east, north),
        rectangleSouthwestInMeters: new Cartesian2(west, south)
      });
    } else if (prjCode === 4326) {
      this.tilingScheme = new GeographicTilingScheme({
        rectangle: Rectangle.fromDegrees(...this.bbox),
        numberOfLevelZeroTilesX: 1,
        numberOfLevelZeroTilesY: 1
      });
    } else if (typeof ((_a = this._proj) == null ? void 0 : _a.project) === "function" && typeof ((_b = this._proj) == null ? void 0 : _b.unproject) === "function") {
      console.warn(`[Experimental] Reprojection EPSG:${prjCode}`);
      this.tilingScheme = new TIFFImageryProviderTilingScheme({
        rectangleNortheastInMeters: new Cartesian2(east, north),
        rectangleSouthwestInMeters: new Cartesian2(west, south),
        ...this._proj
      });
    } else {
      const error = new DeveloperError(`Unspported projection type: EPSG:${prjCode}, please add projFunc parameter to handle projection`);
      throw error;
    }
    this.rectangle = this.tilingScheme.rectangle;
    if (this.rectangle.east < this.rectangle.west) {
      this.rectangle.east += Math$1.TWO_PI;
    }
    this._imageCount = await source.getImageCount();
    this.tileSize = this.tileWidth = tileSize || (this._isTiled ? image.getTileWidth() : image.getWidth()) || 256;
    this.tileHeight = tileSize || (this._isTiled ? image.getTileHeight() : image.getHeight()) || 256;
    console.log(this.tileWidth, this.tileHeight);
    this.requestLevels = this._isTiled ? await this._getCogLevels() : [0];
    this._images = new Array(this._imageCount).fill(null);
    const samples = image.getSamplesPerPixel();
    this.samples = samples;
    this.renderOptions = renderOptions ?? {};
    const noData = image.getGDALNoData();
    this.noData = this.renderOptions.nodata ?? noData;
    if (samples < 3 && this.renderOptions.convertToRGB) {
      const error = new DeveloperError("Can not render the image as RGB, please check the convertToRGB parameter");
      throw error;
    }
    if (!this.renderOptions.single && !this.renderOptions.multi && !this.renderOptions.convertToRGB) {
      if (samples > 2) {
        this.renderOptions = {
          convertToRGB: true,
          ...this.renderOptions
        };
      } else {
        this.renderOptions = {
          single: {
            band: 1
          },
          ...this.renderOptions
        };
      }
    }
    if (this.renderOptions.single) {
      this.renderOptions.single.band = this.renderOptions.single.band ?? 1;
    }
    const { single, multi, convertToRGB } = this.renderOptions;
    this.readSamples = multi ? [multi.r.band - 1, multi.g.band - 1, multi.b.band - 1] : convertToRGB ? [0, 1, 2] : [single.band - 1];
    if (single == null ? void 0 : single.expression) {
      this.readSamples = findAndSortBandNumbers(single.expression);
    }
    const bands = {};
    await Promise.all(this.readSamples.map(async (i) => {
      const element = image.getGDALMetadata(i);
      const bandNum = i + 1;
      if ((element == null ? void 0 : element.STATISTICS_MINIMUM) && (element == null ? void 0 : element.STATISTICS_MAXIMUM)) {
        bands[bandNum] = {
          min: +element.STATISTICS_MINIMUM,
          max: +element.STATISTICS_MAXIMUM
        };
      } else {
        if (convertToRGB) {
          bands[bandNum] = {
            min: 0,
            max: 255
          };
        }
        if (multi) {
          const inputBand = multi[Object.keys(multi).find((key) => {
            var _a2;
            return ((_a2 = multi[key]) == null ? void 0 : _a2.band) === bandNum;
          })];
          if ((inputBand == null ? void 0 : inputBand.min) !== void 0 && (inputBand == null ? void 0 : inputBand.max) !== void 0) {
            const { min, max } = inputBand;
            bands[bandNum] = {
              min,
              max
            };
          }
        }
        if (single && !single.expression && single.band === bandNum && single.domain) {
          bands[bandNum] = {
            min: single.domain[0],
            max: single.domain[1]
          };
        }
        if (!(single == null ? void 0 : single.expression) && !bands[bandNum]) {
          console.warn(`Can not get band${bandNum} min/max, try to calculate min/max values, or setting ${single ? "domain" : "min / max"}`);
          const previewImage = await source.getImage(this.requestLevels[0]);
          const data = (await previewImage.readRasters({
            samples: [i],
            pool: this.geotiffWorkerPool
          }))[0].filter((item) => !isNaN(item));
          bands[bandNum] = getMinMax(data, noData);
        }
      }
    }));
    this.bands = bands;
    try {
      if (this.renderOptions.single) {
        const band = this.bands[single.band];
        if (!single.expression && !band) {
          throw new DeveloperError(`Invalid band${single.band}`);
        }
        const domain = single.domain ?? [band.min, band.max];
        this.plot = new plot({
          canvas,
          ...single,
          domain
        });
        this.plot.setNoDataValue(this.noData);
        const { expression, colors, colorScaleImage } = single;
        this.plot.setExpression(expression);
        if (colors) {
          const colorScale = generateColorScale(colors, (single == null ? void 0 : single.useRealValue) ? domain : [0, 1]);
          addColorScale("temp", colorScale.colors, colorScale.positions);
          this.plot.setColorScale("temp");
        } else if (!colorScaleImage) {
          this.plot.setColorScale((single == null ? void 0 : single.colorScale) ?? "blackwhite");
        }
      }
    } catch (e) {
      console.error(e);
      this.errorEvent.raiseEvent(e);
    }
    this.readyPromise = Promise.resolve(true);
    this.ready = true;
  }
  static async fromUrl(url, options = {}) {
    const provider = new TIFFImageryProvider(options);
    await provider._build(url, {
      ...options,
      url: void 0
    });
    return provider;
  }
  /**
   * Get the origin of an image.  If the image does not have an affine transform,
   * the top-left corner of the pixel bounds is returned.
   * @param {GeoTIFFImage} image The image.
   * @return {Array<number>} The image origin.
   */
  _getOrigin(image) {
    try {
      return image.getOrigin().slice(0, 2);
    } catch (_) {
      return [0, image.fileDirectory.ImageLength];
    }
  }
  _checkIfReversed(image) {
    const pixelScale = image.getFileDirectory().ModelPixelScale;
    if (pixelScale) {
      const pixelScaleY = pixelScale[1];
      if (pixelScaleY < 0)
        return true;
    }
    const transformation = image.getFileDirectory().ModelTransformation;
    if (transformation) {
      const originX = transformation[3];
      const originY = transformation[7];
      if (originY > originX)
        return true;
    }
    return false;
  }
  /**
   * get suitable cog levels
   */
  async _getCogLevels() {
    const levels = [];
    let maximumLevel = this._imageCount - 1;
    for (let i = this._imageCount - 1; i >= 0; i--) {
      const image = this._images[i] = await this._source.getImage(i);
      const width = image.getWidth();
      const height = image.getHeight();
      const size = Math.max(width, height);
      if (i === this._imageCount - 1) {
        const firstImageLevel = Math.ceil((size - this.tileSize) / this.tileSize);
        levels.push(...new Array(firstImageLevel).fill(i));
      }
      if (size > this.tileSize * 0.5) {
        maximumLevel = i;
        break;
      }
    }
    let nowCogLevel = maximumLevel;
    while (nowCogLevel >= 0) {
      levels.push(nowCogLevel--);
    }
    return levels;
  }
  /**
   * Get tile data
   * @param x 
   * @param y 
   * @param z 
   */
  async _loadTile(reqx, reqy, reqz) {
    var _a;
    let x = reqx, y = reqy, z = reqz, startX = reqx, startY = reqy;
    const maxCogLevel = this.requestLevels.length - 1;
    if (z > maxCogLevel) {
      z = maxCogLevel;
      x = x >> reqz - maxCogLevel;
      y = y >> reqz - maxCogLevel;
      startX = x << reqz - z;
      startY = y << reqz - z;
    }
    const index = this.requestLevels[z];
    let image = this._images[index];
    if (!image) {
      image = this._images[index] = await this._source.getImage(index);
    }
    const width = image.getWidth();
    const height = image.getHeight();
    const tileXNum = this.tilingScheme.getNumberOfXTilesAtLevel(z);
    const tileYNum = this.tilingScheme.getNumberOfYTilesAtLevel(z);
    const tilePixel = {
      xWidth: width / tileXNum,
      yWidth: height / tileYNum
    };
    let window = [
      Math.round(x * tilePixel.xWidth),
      Math.round(y * tilePixel.yWidth),
      Math.round((x + 1) * tilePixel.xWidth),
      Math.round((y + 1) * tilePixel.yWidth)
    ];
    if (this._proj && this.tilingScheme instanceof TIFFImageryProviderTilingScheme) {
      const targetRect = this.tilingScheme.tileXYToNativeRectangle2(x, y, z);
      const nativeRect = this.tilingScheme.nativeRectangle;
      targetRect.west -= nativeRect.width / width;
      targetRect.east += nativeRect.width / width;
      targetRect.south -= nativeRect.height / height;
      targetRect.north += nativeRect.height / height;
      window = [
        ~~((targetRect.west - nativeRect.west) / nativeRect.width * width),
        ~~((nativeRect.north - targetRect.north) / nativeRect.height * height),
        ~~((targetRect.east - nativeRect.west) / nativeRect.width * width),
        ~~((nativeRect.north - targetRect.south) / nativeRect.height * height)
      ];
    }
    if (this.reverseY) {
      window = [window[0], height - window[3], window[2], height - window[1]];
    }
    const buffer = 1;
    window = [window[0] - buffer, window[1] - buffer, window[2] + buffer, window[3] + buffer];
    const sourceWidth = window[2] - window[0], sourceHeight = window[3] - window[1];
    const options = {
      window,
      pool: this.geotiffWorkerPool,
      samples: this.readSamples,
      fillValue: this.noData,
      interleave: false
    };
    let res;
    try {
      if (this.renderOptions.convertToRGB) {
        res = await image.readRGB(options);
      } else {
        res = await image.readRasters(options);
        if (this.reverseY) {
          res = await Promise.all(res.map((array) => reverseArray({ array, width: res.width, height: res.height })));
        }
      }
      if (((_a = this._proj) == null ? void 0 : _a.project) && this.tilingScheme instanceof TIFFImageryProviderTilingScheme) {
        const sourceRect = this.tilingScheme.tileXYToNativeRectangle2(x, y, z);
        const targetRect = this.tilingScheme.tileXYToRectangle(x, y, z);
        const sourceBBox = [sourceRect.west, sourceRect.south, sourceRect.east, sourceRect.north];
        const targetBBox = [targetRect.west, targetRect.south, targetRect.east, targetRect.north].map(Math$1.toDegrees);
        const result = [];
        for (let i = 0; i < res.length; i++) {
          const prjData = reprojection({
            data: res[i],
            sourceWidth,
            sourceHeight,
            nodata: this.noData,
            project: this._proj.project,
            sourceBBox,
            targetBBox
          });
          result.push(prjData);
        }
        res = result;
      }
      const tileNum = 1 << reqz - z;
      const x0 = (reqx - startX) / tileNum;
      const y0 = (reqy - startY) / tileNum;
      const step = 1 / (1 << reqz - z);
      const x1 = x0 + step;
      const y1 = y0 + step;
      res = await Promise.all(res.map(async (data) => this.workerPool.resample(data, {
        sourceWidth,
        sourceHeight,
        targetWidth: this.tileWidth,
        targetHeight: this.tileHeight,
        window: [x0, y0, x1, y1],
        method: this.renderOptions.resampleMethod,
        buffer,
        nodata: this.noData
      })));
      return {
        data: res,
        width: this.tileWidth,
        height: this.tileHeight
      };
    } catch (error) {
      this.errorEvent.raiseEvent(error);
      throw error;
    }
  }
  async requestImage(x, y, z) {
    if (!this.ready) {
      throw new DeveloperError(
        "requestImage must not be called before the imagery provider is ready."
      );
    }
    if (z < this.minimumLevel || z > this.maximumLevel)
      return void 0;
    const cacheKey = `${x}_${y}_${z}`;
    if (this._imagesCache.has(cacheKey)) {
      return this._imagesCache.get(cacheKey);
    }
    const { single, multi, convertToRGB } = this.renderOptions;
    try {
      const { width, height, data } = await this._loadTile(x, y, z);
      if (this._destroyed || !width || !height) {
        return void 0;
      }
      let result;
      if (multi || convertToRGB) {
        const opts = {
          data,
          width,
          height,
          renderOptions: multi ?? ["r", "g", "b"].reduce((pre, val, index) => ({
            ...pre,
            [val]: {
              band: index + 1,
              min: 0,
              max: 255
            }
          }), {}),
          bands: this.bands,
          noData: this.noData,
          colorMapping: Object.entries(this.renderOptions.colorMapping ?? { "black": "transparent" }).map((val) => val.map(stringColorToRgba))
        };
        result = await generateImage(opts);
      } else if (single && this.plot) {
        const { band = 1 } = single;
        this.plot.removeAllDataset();
        this.readSamples.forEach((sample, index) => {
          this.plot.addDataset(`b${sample + 1}`, data[index], width, height);
        });
        if (single.expression) {
          this.plot.render();
        } else {
          this.plot.renderDataset(`b${band}`);
        }
        const canv = createCanavas(this.tileWidth, this.tileHeight);
        const ctx = canv.getContext("2d");
        ctx.drawImage(this.plot.canvas, 0, 0);
        result = canv;
      }
      if (result) {
        if (this._imagesCache.size >= this._cacheSize) {
          const oldestKey = this._imagesCache.keys().next().value;
          this._imagesCache.delete(oldestKey);
        }
        this._imagesCache.set(cacheKey, result);
      }
      return result;
    } catch (e) {
      console.error(e);
      this.errorEvent.raiseEvent(e);
      throw e;
    }
  }
  async pickFeatures(x, y, zoom, longitude, latitude) {
    if (!this.options.enablePickFeatures)
      return void 0;
    const z = zoom > this.maximumLevel ? this.maximumLevel : zoom;
    const index = this.requestLevels[z];
    let image = this._images[index];
    if (!image) {
      image = this._images[index] = await this._source.getImage(index);
    }
    const width = image.getWidth();
    const height = image.getHeight();
    let posX, posY, window;
    const { west, south, north, width: lonWidth } = this.rectangle;
    let lonGap = longitude - west;
    if (longitude < west) {
      lonGap += Math$1.TWO_PI;
    }
    posX = ~~(Math.abs(lonGap / lonWidth) * width);
    posY = ~~(Math.abs((north - latitude) / (north - south)) * height);
    window = [posX, posY, posX + 1, posY + 1];
    if (this.reverseY) {
      posY = height - posY;
      window = [posX, posY - 1, posX + 1, posY];
    }
    const options = {
      window,
      height: 1,
      width: 1,
      pool: this.geotiffWorkerPool,
      interleave: false
    };
    let res;
    if (this.renderOptions.convertToRGB) {
      res = await image.readRGB(options);
    } else {
      res = await image.readRasters(options);
    }
    const featureInfo = new ImageryLayerFeatureInfo();
    featureInfo.name = `lon:${(longitude / Math.PI * 180).toFixed(6)}, lat:${(latitude / Math.PI * 180).toFixed(6)}`;
    const data = {};
    res == null ? void 0 : res.forEach((item, index2) => {
      data[index2] = item == null ? void 0 : item[0];
    });
    featureInfo.data = data;
    if (res) {
      featureInfo.configureDescriptionFromProperties(data);
    }
    return [featureInfo];
  }
  destroy() {
    var _a;
    if (this._imagesCache) {
      for (const key in this._imagesCache) {
        delete this._imagesCache[key];
      }
      this._imagesCache.clear();
    }
    if (this.workerPool) {
      this.workerPool.destroy();
    }
    if (this.plot && this.plot.gl) {
      for (const programKey in this.plot.programCache) {
        this.plot.gl.deleteProgram(this.plot.programCache[programKey]);
      }
      this.plot.gl.deleteBuffer(this.plot.positionBuffer);
    }
    (_a = this.plot) == null ? void 0 : _a.destroy();
    this._images = [];
    this._source = void 0;
    this._destroyed = true;
  }
}

export { TIFFImageryProvider, colorscales, TIFFImageryProvider as default, renderColorScaleToCanvas };
//# sourceMappingURL=index.js.map