UNPKG

@deck.gl/layers

Version:

deck.gl core layers

1,450 lines (1,353 loc) 279 kB
(function webpackUniversalModuleDefinition(root, factory) { if (typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if (typeof define === 'function' && define.amd) define([], factory); else if (typeof exports === 'object') exports['deck'] = factory(); else root['deck'] = factory();})(globalThis, function () { "use strict"; var __exports__ = (() => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod2) => function __require() { return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __reExport = (target, mod2, secondTarget) => (__copyProps(target, mod2, "default"), secondTarget && __copyProps(secondTarget, mod2, "default")); var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, "default", { value: mod2, enumerable: true }) : target, mod2 )); var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2); // external-global-plugin:@deck.gl/core var require_core = __commonJS({ "external-global-plugin:@deck.gl/core"(exports, module) { module.exports = globalThis.deck; } }); // external-global-plugin:@luma.gl/engine var require_engine = __commonJS({ "external-global-plugin:@luma.gl/engine"(exports, module) { module.exports = globalThis.luma; } }); // external-global-plugin:@loaders.gl/core var require_core2 = __commonJS({ "external-global-plugin:@loaders.gl/core"(exports, module) { module.exports = globalThis.loaders; } }); // external-global-plugin:@luma.gl/core var require_core3 = __commonJS({ "external-global-plugin:@luma.gl/core"(exports, module) { module.exports = globalThis.luma; } }); // ../../node_modules/earcut/src/earcut.js var require_earcut = __commonJS({ "../../node_modules/earcut/src/earcut.js"(exports, module) { "use strict"; module.exports = earcut3; module.exports.default = earcut3; function earcut3(data, holeIndices, dim) { dim = dim || 2; var hasHoles = holeIndices && holeIndices.length, outerLen = hasHoles ? holeIndices[0] * dim : data.length, outerNode = linkedList(data, 0, outerLen, dim, true), triangles = []; if (!outerNode || outerNode.next === outerNode.prev) return triangles; var minX, minY, maxX, maxY, x, y, invSize; if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); if (data.length > 80 * dim) { minX = maxX = data[0]; minY = maxY = data[1]; for (var i = dim; i < outerLen; i += dim) { x = data[i]; y = data[i + 1]; if (x < minX) minX = x; if (y < minY) minY = y; if (x > maxX) maxX = x; if (y > maxY) maxY = y; } invSize = Math.max(maxX - minX, maxY - minY); invSize = invSize !== 0 ? 32767 / invSize : 0; } earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0); return triangles; } function linkedList(data, start, end, dim, clockwise) { var i, last; if (clockwise === signedArea(data, start, end, dim) > 0) { for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last); } else { for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last); } if (last && equals2(last, last.next)) { removeNode(last); last = last.next; } return last; } function filterPoints(start, end) { if (!start) return start; if (!end) end = start; var p = start, again; do { again = false; if (!p.steiner && (equals2(p, p.next) || area(p.prev, p, p.next) === 0)) { removeNode(p); p = end = p.prev; if (p === p.next) break; again = true; } else { p = p.next; } } while (again || p !== end); return end; } function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { if (!ear) return; if (!pass && invSize) indexCurve(ear, minX, minY, invSize); var stop = ear, prev, next; while (ear.prev !== ear.next) { prev = ear.prev; next = ear.next; if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { triangles.push(prev.i / dim | 0); triangles.push(ear.i / dim | 0); triangles.push(next.i / dim | 0); removeNode(ear); ear = next.next; stop = next.next; continue; } ear = next; if (ear === stop) { if (!pass) { earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); } else if (pass === 1) { ear = cureLocalIntersections(filterPoints(ear), triangles, dim); earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); } else if (pass === 2) { splitEarcut(ear, triangles, dim, minX, minY, invSize); } break; } } } function isEar(ear) { var a = ear.prev, b = ear, c = ear.next; if (area(a, b, c) >= 0) return false; var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx, y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy, x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx, y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy; var p = c.next; while (p !== a) { if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; p = p.next; } return true; } function isEarHashed(ear, minX, minY, invSize) { var a = ear.prev, b = ear, c = ear.next; if (area(a, b, c) >= 0) return false; var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx, y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy, x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx, y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy; var minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize); var p = ear.prevZ, n = ear.nextZ; while (p && p.z >= minZ && n && n.z <= maxZ) { if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; p = p.prevZ; if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; n = n.nextZ; } while (p && p.z >= minZ) { if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; p = p.prevZ; } while (n && n.z <= maxZ) { if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; n = n.nextZ; } return true; } function cureLocalIntersections(start, triangles, dim) { var p = start; do { var a = p.prev, b = p.next.next; if (!equals2(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { triangles.push(a.i / dim | 0); triangles.push(p.i / dim | 0); triangles.push(b.i / dim | 0); removeNode(p); removeNode(p.next); p = start = b; } p = p.next; } while (p !== start); return filterPoints(p); } function splitEarcut(start, triangles, dim, minX, minY, invSize) { var a = start; do { var b = a.next.next; while (b !== a.prev) { if (a.i !== b.i && isValidDiagonal(a, b)) { var c = splitPolygon(a, b); a = filterPoints(a, a.next); c = filterPoints(c, c.next); earcutLinked(a, triangles, dim, minX, minY, invSize, 0); earcutLinked(c, triangles, dim, minX, minY, invSize, 0); return; } b = b.next; } a = a.next; } while (a !== start); } function eliminateHoles(data, holeIndices, outerNode, dim) { var queue = [], i, len, start, end, list; for (i = 0, len = holeIndices.length; i < len; i++) { start = holeIndices[i] * dim; end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; list = linkedList(data, start, end, dim, false); if (list === list.next) list.steiner = true; queue.push(getLeftmost(list)); } queue.sort(compareX); for (i = 0; i < queue.length; i++) { outerNode = eliminateHole(queue[i], outerNode); } return outerNode; } function compareX(a, b) { return a.x - b.x; } function eliminateHole(hole, outerNode) { var bridge = findHoleBridge(hole, outerNode); if (!bridge) { return outerNode; } var bridgeReverse = splitPolygon(bridge, hole); filterPoints(bridgeReverse, bridgeReverse.next); return filterPoints(bridge, bridge.next); } function findHoleBridge(hole, outerNode) { var p = outerNode, hx = hole.x, hy = hole.y, qx = -Infinity, m; do { if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) { var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); if (x <= hx && x > qx) { qx = x; m = p.x < p.next.x ? p : p.next; if (x === hx) return m; } } p = p.next; } while (p !== outerNode); if (!m) return null; var stop = m, mx = m.x, my = m.y, tanMin = Infinity, tan2; p = m; do { if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { tan2 = Math.abs(hy - p.y) / (hx - p.x); if (locallyInside(p, hole) && (tan2 < tanMin || tan2 === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) { m = p; tanMin = tan2; } } p = p.next; } while (p !== stop); return m; } function sectorContainsSector(m, p) { return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; } function indexCurve(start, minX, minY, invSize) { var p = start; do { if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); p.prevZ = p.prev; p.nextZ = p.next; p = p.next; } while (p !== start); p.prevZ.nextZ = null; p.prevZ = null; sortLinked(p); } function sortLinked(list) { var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1; do { p = list; list = null; tail = null; numMerges = 0; while (p) { numMerges++; q = p; pSize = 0; for (i = 0; i < inSize; i++) { pSize++; q = q.nextZ; if (!q) break; } qSize = inSize; while (pSize > 0 || qSize > 0 && q) { if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { e = p; p = p.nextZ; pSize--; } else { e = q; q = q.nextZ; qSize--; } if (tail) tail.nextZ = e; else list = e; e.prevZ = tail; tail = e; } p = q; } tail.nextZ = null; inSize *= 2; } while (numMerges > 1); return list; } function zOrder(x, y, minX, minY, invSize) { x = (x - minX) * invSize | 0; y = (y - minY) * invSize | 0; x = (x | x << 8) & 16711935; x = (x | x << 4) & 252645135; x = (x | x << 2) & 858993459; x = (x | x << 1) & 1431655765; y = (y | y << 8) & 16711935; y = (y | y << 4) & 252645135; y = (y | y << 2) & 858993459; y = (y | y << 1) & 1431655765; return x | y << 1; } function getLeftmost(start) { var p = start, leftmost = start; do { if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p; p = p.next; } while (p !== start); return leftmost; } function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py); } function isValidDiagonal(a, b) { return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors equals2(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); } function area(p, q, r) { return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); } function equals2(p1, p2) { return p1.x === p2.x && p1.y === p2.y; } function intersects(p1, q1, p2, q2) { var o1 = sign(area(p1, q1, p2)); var o2 = sign(area(p1, q1, q2)); var o3 = sign(area(p2, q2, p1)); var o4 = sign(area(p2, q2, q1)); if (o1 !== o2 && o3 !== o4) return true; if (o1 === 0 && onSegment(p1, p2, q1)) return true; if (o2 === 0 && onSegment(p1, q2, q1)) return true; if (o3 === 0 && onSegment(p2, p1, q2)) return true; if (o4 === 0 && onSegment(p2, q1, q2)) return true; return false; } function onSegment(p, q, r) { return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y); } function sign(num) { return num > 0 ? 1 : num < 0 ? -1 : 0; } function intersectsPolygon(a, b) { var p = a; do { if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) return true; p = p.next; } while (p !== a); return false; } function locallyInside(a, b) { return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; } function middleInside(a, b) { var p = a, inside = false, px = (a.x + b.x) / 2, py = (a.y + b.y) / 2; do { if (p.y > py !== p.next.y > py && p.next.y !== p.y && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) inside = !inside; p = p.next; } while (p !== a); return inside; } function splitPolygon(a, b) { var a2 = new Node(a.i, a.x, a.y), b2 = new Node(b.i, b.x, b.y), an = a.next, bp = b.prev; a.next = b; b.prev = a; a2.next = an; an.prev = a2; b2.next = a2; a2.prev = b2; bp.next = b2; b2.prev = bp; return b2; } function insertNode(i, x, y, last) { var p = new Node(i, x, y); if (!last) { p.prev = p; p.next = p; } else { p.next = last.next; p.prev = last; last.next.prev = p; last.next = p; } return p; } function removeNode(p) { p.next.prev = p.prev; p.prev.next = p.next; if (p.prevZ) p.prevZ.nextZ = p.nextZ; if (p.nextZ) p.nextZ.prevZ = p.prevZ; } function Node(i, x, y) { this.i = i; this.x = x; this.y = y; this.prev = null; this.next = null; this.z = 0; this.prevZ = null; this.nextZ = null; this.steiner = false; } earcut3.deviation = function(data, holeIndices, dim, triangles) { var hasHoles = holeIndices && holeIndices.length; var outerLen = hasHoles ? holeIndices[0] * dim : data.length; var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim)); if (hasHoles) { for (var i = 0, len = holeIndices.length; i < len; i++) { var start = holeIndices[i] * dim; var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; polygonArea -= Math.abs(signedArea(data, start, end, dim)); } } var trianglesArea = 0; for (i = 0; i < triangles.length; i += 3) { var a = triangles[i] * dim; var b = triangles[i + 1] * dim; var c = triangles[i + 2] * dim; trianglesArea += Math.abs( (data[a] - data[c]) * (data[b + 1] - data[a + 1]) - (data[a] - data[b]) * (data[c + 1] - data[a + 1]) ); } return polygonArea === 0 && trianglesArea === 0 ? 0 : Math.abs((trianglesArea - polygonArea) / polygonArea); }; function signedArea(data, start, end, dim) { var sum = 0; for (var i = start, j = end - dim; i < end; i += dim) { sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); j = i; } return sum; } earcut3.flatten = function(data) { var dim = data[0][0].length, result = { vertices: [], holes: [], dimensions: dim }, holeIndex = 0; for (var i = 0; i < data.length; i++) { for (var j = 0; j < data[i].length; j++) { for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]); } if (i > 0) { holeIndex += data[i - 1].length; result.holes.push(holeIndex); } } return result; }; } }); // bundle/index.ts var bundle_exports = {}; __export(bundle_exports, { ArcLayer: () => ArcLayer, BitmapLayer: () => BitmapLayer, ColumnLayer: () => ColumnLayer, GeoJsonLayer: () => GeoJsonLayer, GridCellLayer: () => GridCellLayer, IconLayer: () => IconLayer, LineLayer: () => LineLayer, PathLayer: () => PathLayer, PointCloudLayer: () => PointCloudLayer, PolygonLayer: () => PolygonLayer, ScatterplotLayer: () => ScatterplotLayer, SolidPolygonLayer: () => SolidPolygonLayer, TextLayer: () => TextLayer, _MultiIconLayer: () => MultiIconLayer, _TextBackgroundLayer: () => TextBackgroundLayer }); // ../core/bundle/peer-dependency.ts var peer_dependency_exports = {}; var import_core = __toESM(require_core(), 1); __reExport(peer_dependency_exports, __toESM(require_core(), 1)); if (!import_core.Layer) { throw new Error("@deck.gl/core is not found"); } // bundle/index.ts __reExport(bundle_exports, peer_dependency_exports); // src/arc-layer/arc-layer.ts var import_core2 = __toESM(require_core(), 1); var import_engine = __toESM(require_engine(), 1); // src/arc-layer/arc-layer-uniforms.ts var uniformBlock = `uniform arcUniforms { bool greatCircle; bool useShortestPath; float numSegments; float widthScale; float widthMinPixels; float widthMaxPixels; highp int widthUnits; } arc; `; var arcUniforms = { name: "arc", vs: uniformBlock, fs: uniformBlock, uniformTypes: { greatCircle: "f32", useShortestPath: "f32", numSegments: "f32", widthScale: "f32", widthMinPixels: "f32", widthMaxPixels: "f32", widthUnits: "i32" } }; // src/arc-layer/arc-layer-vertex.glsl.ts var arc_layer_vertex_glsl_default = `#version 300 es #define SHADER_NAME arc-layer-vertex-shader in vec4 instanceSourceColors; in vec4 instanceTargetColors; in vec3 instanceSourcePositions; in vec3 instanceSourcePositions64Low; in vec3 instanceTargetPositions; in vec3 instanceTargetPositions64Low; in vec3 instancePickingColors; in float instanceWidths; in float instanceHeights; in float instanceTilts; out vec4 vColor; out vec2 uv; out float isValid; float paraboloid(float distance, float sourceZ, float targetZ, float ratio) { // d: distance on the xy plane // r: ratio of the current point // p: ratio of the peak of the arc // h: height multiplier // z = f(r) = sqrt(r * (p * 2 - r)) * d * h // f(0) = 0 // f(1) = dz float deltaZ = targetZ - sourceZ; float dh = distance * instanceHeights; if (dh == 0.0) { return sourceZ + deltaZ * ratio; } float unitZ = deltaZ / dh; float p2 = unitZ * unitZ + 1.0; // sqrt does not deal with negative values, manually flip source and target if delta.z < 0 float dir = step(deltaZ, 0.0); float z0 = mix(sourceZ, targetZ, dir); float r = mix(ratio, 1.0 - ratio, dir); return sqrt(r * (p2 - r)) * dh + z0; } // offset vector by strokeWidth pixels // offset_direction is -1 (left) or 1 (right) vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction, float width) { // normalized direction of the line vec2 dir_screenspace = normalize(line_clipspace * project.viewportSize); // rotate by 90 degrees dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); return dir_screenspace * offset_direction * width / 2.0; } float getSegmentRatio(float index) { return smoothstep(0.0, 1.0, index / (arc.numSegments - 1.0)); } vec3 interpolateFlat(vec3 source, vec3 target, float segmentRatio) { float distance = length(source.xy - target.xy); float z = paraboloid(distance, source.z, target.z, segmentRatio); float tiltAngle = radians(instanceTilts); vec2 tiltDirection = normalize(target.xy - source.xy); vec2 tilt = vec2(-tiltDirection.y, tiltDirection.x) * z * sin(tiltAngle); return vec3( mix(source.xy, target.xy, segmentRatio) + tilt, z * cos(tiltAngle) ); } /* Great circle interpolation * http://www.movable-type.co.uk/scripts/latlong.html */ float getAngularDist (vec2 source, vec2 target) { vec2 sourceRadians = radians(source); vec2 targetRadians = radians(target); vec2 sin_half_delta = sin((sourceRadians - targetRadians) / 2.0); vec2 shd_sq = sin_half_delta * sin_half_delta; float a = shd_sq.y + cos(sourceRadians.y) * cos(targetRadians.y) * shd_sq.x; return 2.0 * asin(sqrt(a)); } vec3 interpolateGreatCircle(vec3 source, vec3 target, vec3 source3D, vec3 target3D, float angularDist, float t) { vec2 lngLat; // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation if(abs(angularDist - PI) < 0.001) { lngLat = (1.0 - t) * source.xy + t * target.xy; } else { float a = sin((1.0 - t) * angularDist); float b = sin(t * angularDist); vec3 p = source3D.yxz * a + target3D.yxz * b; lngLat = degrees(vec2(atan(p.y, -p.x), atan(p.z, length(p.xy)))); } float z = paraboloid(angularDist * EARTH_RADIUS, source.z, target.z, t); return vec3(lngLat, z); } /* END GREAT CIRCLE */ void main(void) { geometry.worldPosition = instanceSourcePositions; geometry.worldPositionAlt = instanceTargetPositions; /* * --(i, -1)-----------_(i+1, -1)-- * | _,-" | * o _,-" o * | _,-" | * --(i, 1)"-------------(i+1, 1)-- */ float segmentIndex = float(gl_VertexID / 2); float segmentSide = mod(float(gl_VertexID), 2.) == 0. ? -1. : 1.; float segmentRatio = getSegmentRatio(segmentIndex); float prevSegmentRatio = getSegmentRatio(max(0.0, segmentIndex - 1.0)); float nextSegmentRatio = getSegmentRatio(min(arc.numSegments - 1.0, segmentIndex + 1.0)); // if it's the first point, use next - current as direction // otherwise use current - prev float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0)); isValid = 1.0; uv = vec2(segmentRatio, segmentSide); geometry.uv = uv; geometry.pickingColor = instancePickingColors; vec4 curr; vec4 next; vec3 source; vec3 target; if ((arc.greatCircle || project.projectionMode == PROJECTION_MODE_GLOBE) && project.coordinateSystem == COORDINATE_SYSTEM_LNGLAT) { source = project_globe_(vec3(instanceSourcePositions.xy, 0.0)); target = project_globe_(vec3(instanceTargetPositions.xy, 0.0)); float angularDist = getAngularDist(instanceSourcePositions.xy, instanceTargetPositions.xy); vec3 prevPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, prevSegmentRatio); vec3 currPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, segmentRatio); vec3 nextPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, nextSegmentRatio); if (abs(currPos.x - prevPos.x) > 180.0) { indexDir = -1.0; isValid = 0.0; } else if (abs(currPos.x - nextPos.x) > 180.0) { indexDir = 1.0; isValid = 0.0; } nextPos = indexDir < 0.0 ? prevPos : nextPos; nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio; if (isValid == 0.0) { // split at the 180th meridian nextPos.x += nextPos.x > 0.0 ? -360.0 : 360.0; float t = ((currPos.x > 0.0 ? 180.0 : -180.0) - currPos.x) / (nextPos.x - currPos.x); currPos = mix(currPos, nextPos, t); segmentRatio = mix(segmentRatio, nextSegmentRatio, t); } vec3 currPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, segmentRatio); vec3 nextPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, nextSegmentRatio); curr = project_position_to_clipspace(currPos, currPos64Low, vec3(0.0), geometry.position); next = project_position_to_clipspace(nextPos, nextPos64Low, vec3(0.0)); } else { vec3 source_world = instanceSourcePositions; vec3 target_world = instanceTargetPositions; if (arc.useShortestPath) { source_world.x = mod(source_world.x + 180., 360.0) - 180.; target_world.x = mod(target_world.x + 180., 360.0) - 180.; float deltaLng = target_world.x - source_world.x; if (deltaLng > 180.) target_world.x -= 360.; if (deltaLng < -180.) source_world.x -= 360.; } source = project_position(source_world, instanceSourcePositions64Low); target = project_position(target_world, instanceTargetPositions64Low); // common x at longitude=-180 float antiMeridianX = 0.0; if (arc.useShortestPath) { if (project.projectionMode == PROJECTION_MODE_WEB_MERCATOR_AUTO_OFFSET) { antiMeridianX = -(project.coordinateOrigin.x + 180.) / 360. * TILE_SIZE; } float thresholdRatio = (antiMeridianX - source.x) / (target.x - source.x); if (prevSegmentRatio <= thresholdRatio && nextSegmentRatio > thresholdRatio) { isValid = 0.0; indexDir = sign(segmentRatio - thresholdRatio); segmentRatio = thresholdRatio; } } nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio; vec3 currPos = interpolateFlat(source, target, segmentRatio); vec3 nextPos = interpolateFlat(source, target, nextSegmentRatio); if (arc.useShortestPath) { if (nextPos.x < antiMeridianX) { currPos.x += TILE_SIZE; nextPos.x += TILE_SIZE; } } curr = project_common_position_to_clipspace(vec4(currPos, 1.0)); next = project_common_position_to_clipspace(vec4(nextPos, 1.0)); geometry.position = vec4(currPos, 1.0); } // Multiply out width and clamp to limits // mercator pixels are interpreted as screen pixels float widthPixels = clamp( project_size_to_pixel(instanceWidths * arc.widthScale, arc.widthUnits), arc.widthMinPixels, arc.widthMaxPixels ); // extrude vec3 offset = vec3( getExtrusionOffset((next.xy - curr.xy) * indexDir, segmentSide, widthPixels), 0.0); DECKGL_FILTER_SIZE(offset, geometry); DECKGL_FILTER_GL_POSITION(curr, geometry); gl_Position = curr + vec4(project_pixel_size_to_clipspace(offset.xy), 0.0, 0.0); vec4 color = mix(instanceSourceColors, instanceTargetColors, segmentRatio); vColor = vec4(color.rgb, color.a * layer.opacity); DECKGL_FILTER_COLOR(vColor, geometry); } `; // src/arc-layer/arc-layer-fragment.glsl.ts var arc_layer_fragment_glsl_default = `#version 300 es #define SHADER_NAME arc-layer-fragment-shader precision highp float; in vec4 vColor; in vec2 uv; in float isValid; out vec4 fragColor; void main(void) { if (isValid == 0.0) { discard; } fragColor = vColor; geometry.uv = uv; DECKGL_FILTER_COLOR(fragColor, geometry); } `; // src/arc-layer/arc-layer.ts var DEFAULT_COLOR = [0, 0, 0, 255]; var defaultProps = { getSourcePosition: { type: "accessor", value: (x) => x.sourcePosition }, getTargetPosition: { type: "accessor", value: (x) => x.targetPosition }, getSourceColor: { type: "accessor", value: DEFAULT_COLOR }, getTargetColor: { type: "accessor", value: DEFAULT_COLOR }, getWidth: { type: "accessor", value: 1 }, getHeight: { type: "accessor", value: 1 }, getTilt: { type: "accessor", value: 0 }, greatCircle: false, numSegments: { type: "number", value: 50, min: 1 }, widthUnits: "pixels", widthScale: { type: "number", value: 1, min: 0 }, widthMinPixels: { type: "number", value: 0, min: 0 }, widthMaxPixels: { type: "number", value: Number.MAX_SAFE_INTEGER, min: 0 } }; var ArcLayer = class extends import_core2.Layer { getBounds() { return this.getAttributeManager()?.getBounds([ "instanceSourcePositions", "instanceTargetPositions" ]); } getShaders() { return super.getShaders({ vs: arc_layer_vertex_glsl_default, fs: arc_layer_fragment_glsl_default, modules: [import_core2.project32, import_core2.picking, arcUniforms] }); } // This layer has its own wrapLongitude logic get wrapLongitude() { return false; } initializeState() { const attributeManager = this.getAttributeManager(); attributeManager.addInstanced({ instanceSourcePositions: { size: 3, type: "float64", fp64: this.use64bitPositions(), transition: true, accessor: "getSourcePosition" }, instanceTargetPositions: { size: 3, type: "float64", fp64: this.use64bitPositions(), transition: true, accessor: "getTargetPosition" }, instanceSourceColors: { size: this.props.colorFormat.length, type: "unorm8", transition: true, accessor: "getSourceColor", defaultValue: DEFAULT_COLOR }, instanceTargetColors: { size: this.props.colorFormat.length, type: "unorm8", transition: true, accessor: "getTargetColor", defaultValue: DEFAULT_COLOR }, instanceWidths: { size: 1, transition: true, accessor: "getWidth", defaultValue: 1 }, instanceHeights: { size: 1, transition: true, accessor: "getHeight", defaultValue: 1 }, instanceTilts: { size: 1, transition: true, accessor: "getTilt", defaultValue: 0 } }); } updateState(params) { super.updateState(params); if (params.changeFlags.extensionsChanged) { this.state.model?.destroy(); this.state.model = this._getModel(); this.getAttributeManager().invalidateAll(); } } draw({ uniforms }) { const { widthUnits, widthScale, widthMinPixels, widthMaxPixels, greatCircle, wrapLongitude, numSegments } = this.props; const arcProps = { numSegments, widthUnits: import_core2.UNIT[widthUnits], widthScale, widthMinPixels, widthMaxPixels, greatCircle, useShortestPath: wrapLongitude }; const model = this.state.model; model.shaderInputs.setProps({ arc: arcProps }); model.setVertexCount(numSegments * 2); model.draw(this.context.renderPass); } _getModel() { return new import_engine.Model(this.context.device, { ...this.getShaders(), id: this.props.id, bufferLayout: this.getAttributeManager().getBufferLayouts(), topology: "triangle-strip", isInstanced: true }); } }; ArcLayer.layerName = "ArcLayer"; ArcLayer.defaultProps = defaultProps; // src/bitmap-layer/bitmap-layer.ts var import_core4 = __toESM(require_core(), 1); var import_engine2 = __toESM(require_engine(), 1); // ../../node_modules/@math.gl/core/dist/lib/common.js var RADIANS_TO_DEGREES = 1 / Math.PI * 180; var DEGREES_TO_RADIANS = 1 / 180 * Math.PI; var DEFAULT_CONFIG = { EPSILON: 1e-12, debug: false, precision: 4, printTypes: false, printDegrees: false, printRowMajor: true, _cartographicRadians: false }; globalThis.mathgl = globalThis.mathgl || { config: { ...DEFAULT_CONFIG } }; var config = globalThis.mathgl.config; function isArray(value) { return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView); } function lerp(a, b, t) { if (isArray(a)) { return a.map((ai, i) => lerp(ai, b[i], t)); } return t * b + (1 - t) * a; } // ../../node_modules/@math.gl/web-mercator/dist/assert.js function assert(condition, message) { if (!condition) { throw new Error(message || "@math.gl/web-mercator: assertion failed."); } } // ../../node_modules/@math.gl/web-mercator/dist/web-mercator-utils.js var PI = Math.PI; var PI_4 = PI / 4; var DEGREES_TO_RADIANS2 = PI / 180; var RADIANS_TO_DEGREES2 = 180 / PI; var TILE_SIZE = 512; function lngLatToWorld(lngLat) { const [lng, lat] = lngLat; assert(Number.isFinite(lng)); assert(Number.isFinite(lat) && lat >= -90 && lat <= 90, "invalid latitude"); const lambda2 = lng * DEGREES_TO_RADIANS2; const phi2 = lat * DEGREES_TO_RADIANS2; const x = TILE_SIZE * (lambda2 + PI) / (2 * PI); const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI); return [x, y]; } // ../../node_modules/@math.gl/web-mercator/dist/get-bounds.js var DEGREES_TO_RADIANS3 = Math.PI / 180; // src/bitmap-layer/create-mesh.ts var DEFAULT_INDICES = new Uint32Array([0, 2, 1, 0, 3, 2]); var DEFAULT_TEX_COORDS = new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]); function createMesh(bounds, resolution) { if (!resolution) { return createQuad(bounds); } const maxXSpan = Math.max( Math.abs(bounds[0][0] - bounds[3][0]), Math.abs(bounds[1][0] - bounds[2][0]) ); const maxYSpan = Math.max( Math.abs(bounds[1][1] - bounds[0][1]), Math.abs(bounds[2][1] - bounds[3][1]) ); const uCount = Math.ceil(maxXSpan / resolution) + 1; const vCount = Math.ceil(maxYSpan / resolution) + 1; const vertexCount = (uCount - 1) * (vCount - 1) * 6; const indices = new Uint32Array(vertexCount); const texCoords = new Float32Array(uCount * vCount * 2); const positions = new Float64Array(uCount * vCount * 3); let vertex = 0; let index = 0; for (let u = 0; u < uCount; u++) { const ut = u / (uCount - 1); for (let v = 0; v < vCount; v++) { const vt = v / (vCount - 1); const p = interpolateQuad(bounds, ut, vt); positions[vertex * 3 + 0] = p[0]; positions[vertex * 3 + 1] = p[1]; positions[vertex * 3 + 2] = p[2] || 0; texCoords[vertex * 2 + 0] = ut; texCoords[vertex * 2 + 1] = 1 - vt; if (u > 0 && v > 0) { indices[index++] = vertex - vCount; indices[index++] = vertex - vCount - 1; indices[index++] = vertex - 1; indices[index++] = vertex - vCount; indices[index++] = vertex - 1; indices[index++] = vertex; } vertex++; } } return { vertexCount, positions, indices, texCoords }; } function createQuad(bounds) { const positions = new Float64Array(12); for (let i = 0; i < bounds.length; i++) { positions[i * 3 + 0] = bounds[i][0]; positions[i * 3 + 1] = bounds[i][1]; positions[i * 3 + 2] = bounds[i][2] || 0; } return { vertexCount: 6, positions, indices: DEFAULT_INDICES, texCoords: DEFAULT_TEX_COORDS }; } function interpolateQuad(quad, ut, vt) { return lerp(lerp(quad[0], quad[1], vt), lerp(quad[3], quad[2], vt), ut); } // src/bitmap-layer/bitmap-layer-uniforms.ts var uniformBlock2 = `uniform bitmapUniforms { vec4 bounds; float coordinateConversion; float desaturate; vec3 tintColor; vec4 transparentColor; } bitmap; `; var bitmapUniforms = { name: "bitmap", vs: uniformBlock2, fs: uniformBlock2, uniformTypes: { bounds: "vec4<f32>", coordinateConversion: "f32", desaturate: "f32", tintColor: "vec3<f32>", transparentColor: "vec4<f32>" } }; // src/bitmap-layer/bitmap-layer-vertex.ts var bitmap_layer_vertex_default = `#version 300 es #define SHADER_NAME bitmap-layer-vertex-shader in vec2 texCoords; in vec3 positions; in vec3 positions64Low; out vec2 vTexCoord; out vec2 vTexPos; const vec3 pickingColor = vec3(1.0, 0.0, 0.0); void main(void) { geometry.worldPosition = positions; geometry.uv = texCoords; geometry.pickingColor = pickingColor; gl_Position = project_position_to_clipspace(positions, positions64Low, vec3(0.0), geometry.position); DECKGL_FILTER_GL_POSITION(gl_Position, geometry); vTexCoord = texCoords; if (bitmap.coordinateConversion < -0.5) { vTexPos = geometry.position.xy + project.commonOrigin.xy; } else if (bitmap.coordinateConversion > 0.5) { vTexPos = geometry.worldPosition.xy; } vec4 color = vec4(0.0); DECKGL_FILTER_COLOR(color, geometry); } `; // src/bitmap-layer/bitmap-layer-fragment.ts var packUVsIntoRGB = ` vec3 packUVsIntoRGB(vec2 uv) { // Extract the top 8 bits. We want values to be truncated down so we can add a fraction vec2 uv8bit = floor(uv * 256.); // Calculate the normalized remainders of u and v parts that do not fit into 8 bits // Scale and clamp to 0-1 range vec2 uvFraction = fract(uv * 256.); vec2 uvFraction4bit = floor(uvFraction * 16.); // Remainder can be encoded in blue channel, encode as 4 bits for pixel coordinates float fractions = uvFraction4bit.x + uvFraction4bit.y * 16.; return vec3(uv8bit, fractions) / 255.; } `; var bitmap_layer_fragment_default = `#version 300 es #define SHADER_NAME bitmap-layer-fragment-shader #ifdef GL_ES precision highp float; #endif uniform sampler2D bitmapTexture; in vec2 vTexCoord; in vec2 vTexPos; out vec4 fragColor; /* projection utils */ const float TILE_SIZE = 512.0; const float PI = 3.1415926536; const float WORLD_SCALE = TILE_SIZE / PI / 2.0; // from degrees to Web Mercator vec2 lnglat_to_mercator(vec2 lnglat) { float x = lnglat.x; float y = clamp(lnglat.y, -89.9, 89.9); return vec2( radians(x) + PI, PI + log(tan(PI * 0.25 + radians(y) * 0.5)) ) * WORLD_SCALE; } // from Web Mercator to degrees vec2 mercator_to_lnglat(vec2 xy) { xy /= WORLD_SCALE; return degrees(vec2( xy.x - PI, atan(exp(xy.y - PI)) * 2.0 - PI * 0.5 )); } /* End projection utils */ // apply desaturation vec3 color_desaturate(vec3 color) { float luminance = (color.r + color.g + color.b) * 0.333333333; return mix(color, vec3(luminance), bitmap.desaturate); } // apply tint vec3 color_tint(vec3 color) { return color * bitmap.tintColor; } // blend with background color vec4 apply_opacity(vec3 color, float alpha) { if (bitmap.transparentColor.a == 0.0) { return vec4(color, alpha); } float blendedAlpha = alpha + bitmap.transparentColor.a * (1.0 - alpha); float highLightRatio = alpha / blendedAlpha; vec3 blendedRGB = mix(bitmap.transparentColor.rgb, color, highLightRatio); return vec4(blendedRGB, blendedAlpha); } vec2 getUV(vec2 pos) { return vec2( (pos.x - bitmap.bounds[0]) / (bitmap.bounds[2] - bitmap.bounds[0]), (pos.y - bitmap.bounds[3]) / (bitmap.bounds[1] - bitmap.bounds[3]) ); } ${packUVsIntoRGB} void main(void) { vec2 uv = vTexCoord; if (bitmap.coordinateConversion < -0.5) { vec2 lnglat = mercator_to_lnglat(vTexPos); uv = getUV(lnglat); } else if (bitmap.coordinateConversion > 0.5) { vec2 commonPos = lnglat_to_mercator(vTexPos); uv = getUV(commonPos); } vec4 bitmapColor = texture(bitmapTexture, uv); fragColor = apply_opacity(color_tint(color_desaturate(bitmapColor.rgb)), bitmapColor.a * layer.opacity); geometry.uv = uv; DECKGL_FILTER_COLOR(fragColor, geometry); if (bool(picking.isActive) && !bool(picking.isAttribute)) { // Since instance information is not used, we can use picking color for pixel index fragColor.rgb = packUVsIntoRGB(uv); } } `; // src/bitmap-layer/bitmap-layer.ts var defaultProps2 = { image: { type: "image", value: null, async: true }, bounds: { type: "array", value: [1, 0, 0, 1], compare: true }, _imageCoordinateSystem: import_core4.COORDINATE_SYSTEM.DEFAULT, desaturate: { type: "number", min: 0, max: 1, value: 0 }, // More context: because of the blending mode we're using for ground imagery, // alpha is not effective when blending the bitmap layers with the base map. // Instead we need to manually dim/blend rgb values with a background color. transparentColor: { type: "color", value: [0, 0, 0, 0] }, tintColor: { type: "color", value: [255, 255, 255] }, textureParameters: { type: "object", ignore: true, value: null } }; var BitmapLayer = class extends import_core4.Layer { getShaders() { return super.getShaders({ vs: bitmap_layer_vertex_default, fs: bitmap_layer_fragment_default, modules: [import_core4.project32, import_core4.picking, bitmapUniforms] }); } initializeState() { const attributeManager = this.getAttributeManager(); attributeManager.remove(["instancePickingColors"]); const noAlloc = true; attributeManager.add({ indices: { size: 1, isIndexed: true, update: (attribute) => attribute.value = this.state.mesh.indices, noAlloc }, positions: { size: 3, type: "float64", fp64: this.use64bitPositions(), update: (attribute) => attribute.value = this.state.mesh.positions, noAlloc }, texCoords: { size: 2, update: (attribute) => attribute.value = this.state.mesh.texCoords, noAlloc } }); } updateState({ props, oldProps, changeFlags }) { const attributeManager = this.getAttributeManager(); if (changeFlags.extensionsChanged) { this.state.model?.destroy(); this.state.model = this._getModel(); attributeManager.invalidateAll(); } if (props.bounds !== oldProps.bounds) { const oldMesh = this.state.mesh; const mesh = this._createMesh(); this.state.model.setVertexCount(mesh.vertexCount); for (const key in mesh) { if (oldMesh && oldMesh[key] !== mesh[key]) { attributeManager.invalidate(key); } } this.setState({ mesh, ...this._getCoordinateUniforms() }); } else if (props._imageCoordinateSystem !== oldProps._imageCoordinateSystem) { this.setState(this._getCoordinateUniforms()); } } getPickingInfo(params) { const { image } = this.props; const info = params.info; if (!info.color || !image) { info.bitmap = null; return info; } const { width, height } = image; info.index = 0; const uv = unpackUVsFromRGB(info.color); info.bitmap = { size: { width, height }, uv, pixel: [Math.floor(uv[0] * width), Math.floor(uv[1] * height)] }; return info; } // Override base Layer multi-depth picking logic disablePickingIndex() { this.setState({ disablePicking: true }); } restorePickingColors() { this.setState({ disablePicking: false }); } _updateAutoHighlight(info) { super._updateAutoHighlight({ ...info, color: this.encodePickingColor(0) }); } _createMesh() { const { bounds } = this.props; let normalizedBounds = bounds; if (isRectangularBounds(bounds)) { normalizedBounds = [ [bounds[0], bounds[1]], [bounds[0], bounds[3]], [bounds[2], bounds[3]], [bounds[2], bounds[1]] ]; } return createMesh(normalizedBounds, this.context.viewport.resolution); } _getModel() { return new import_engine2.Model(this.context.device, { ...this.getShaders(), id: this.props.id, bufferLayout: this.getAttributeManager().getBufferLayouts(), topology: "triangle-list", isInstanced: false }); } draw(opts) { const { shaderModuleProps } = opts; const { model, coordinateConversion, bounds, disablePicking } = this.state; const { image, desaturate, transparentColor, tintColor } = this.props; if (shaderModuleProps.picking.isActive && disablePicking) { return; } if (image && model) { const bitmapProps = { bitmapTexture: image, bounds, coordinateConversion, desaturate, tintColor: tintColor.slice(0, 3).map((x) => x / 255), transparentColor: transparentColor.map((x) => x / 255) }; model.shaderInputs.setProps({ bitmap: bitmapProps }); model.draw(this.context.renderPass); } } _getCoordinateUniforms() { const { LNGLAT, CARTESIAN, DEFAULT } = import_core4.COORDINATE_SYSTEM; let { _imageCoordinateSystem: imageCoordinateSystem } = this.props; if (imageCoordinateSystem !== DEFAULT) { const { bounds } = this.props; if (!isRectangularBounds(bounds)) { throw new Error("_imageCoordinateSystem only supports rectangular bounds"); } const defaultImageCoordinateSystem = this.context.viewport.resolution ? LNGLAT : CARTESIAN; imageCoordinateSystem = imageCoordinateSystem === LNGLAT ? LNGLAT : CARTESIAN; if (imageCoordinateSystem === LNGLAT && defaultImageCoordinateSystem === CARTESIAN) { return { coordinateConversion: -1, bounds }; } if (imageCoordinateSystem === CARTESIAN && defaultImageCoordinateSystem === LNGLAT) { const bottomLeft = lngLatToWorld([bounds[0], bounds[1]]); const topRight = lngLatToWorld([bounds[2], bounds[3]]); return { coordinateConversion: 1, bounds: [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]] }; } } return { coordinateConversion: 0, bounds: [0, 0, 0, 0] }; } }; BitmapLayer.layerName = "BitmapLayer"; BitmapLayer.defaultProps = defaultProps2; function unpackUVsFromRGB(color) { const [u, v, fracUV] = color; const vFrac = (fracUV & 240) / 256; const uFrac = (fracUV & 15) / 16; return [(u + uFrac) / 256, (v + vFrac) / 256]; } function isRectangularBounds(bounds) { return Number.isFinite(bounds[0]); } // src/icon-layer/icon-layer.ts var import_core7 = __toESM(require_core(), 1); var import_engine3 = __toESM(require_engine