import { ARRAY_BUFFER, AttributeType, Buffer_default, DYNAMIC_DRAW, DefaultUniform, ELEMENT_ARRAY_BUFFER, FEATURE_ID_PROPERTY_NAME, GEOMETRY_TYPE_PROPERTY_NAME, Layer_default, UNDEFINED_PROP_VALUE, applyContextToBuilder, colorToGlsl, expressionToGlsl, generateAttributesFromContext, generateUniformsFromContext, getGlslSizeFromType, getGlslTypeFromType, getStringNumberEquivalent, newCompilationContext, numberToGlsl, stringToGlsl } from "./chunk-PZZAKLYX.js"; import { create as create2, fromTransform } from "./chunk-L47B4DRW.js"; import { VectorEventType_default } from "./chunk-V7WRBSQ6.js"; import { Feature_default } from "./chunk-FDGVG43Y.js"; import { BaseVector_default, buildExpression, newEvaluationContext } from "./chunk-OVJRLVXU.js"; import { BooleanType, ColorType, NumberArrayType, NumberType, SizeType, StringType, computeGeometryType, newParsingContext } from "./chunk-E5F6ZCFZ.js"; import { ViewHint_default } from "./chunk-S5OMZ56B.js"; import { createCanvasContext2D } from "./chunk-YWIWRQT2.js"; import { inflateEnds } from "./chunk-RBA5LKAR.js"; import { transform2D } from "./chunk-YUTQGDGI.js"; import { apply, create, makeInverse, multiply, setFromArray, translate } from "./chunk-JFONEOYG.js"; import { getTransformFromProjections, getUserProjection, toUserExtent, toUserResolution } from "./chunk-XZU4LSFD.js"; import { clamp } from "./chunk-54BTDBAD.js"; import { buffer, createEmpty, equals as equals2, getWidth } from "./chunk-CKDBVGKM.js"; import { assert } from "./chunk-QFCIXVZ3.js"; import { getUid } from "./chunk-H47PV7W6.js"; import { listen, unlistenByKey } from "./chunk-KJXIHBKT.js"; import { equals } from "./chunk-FQY6EMA7.js"; // node_modules/ol/style/flat.js function createDefaultStyle() { return { "fill-color": "rgba(255,255,255,0.4)", "stroke-color": "#3399CC", "stroke-width": 1.25, "circle-radius": 5, "circle-fill-color": "rgba(255,255,255,0.4)", "circle-stroke-width": 1.25, "circle-stroke-color": "#3399CC" }; } // node_modules/ol/render/webgl/bufferUtil.js var LINESTRING_ANGLE_COSINE_CUTOFF = 0.985; // node_modules/ol/render/webgl/ShaderBuilder.js var COMMON_HEADER = `#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif uniform mat4 u_projectionMatrix; uniform mat4 u_screenToWorldMatrix; uniform vec2 u_viewportSizePx; uniform float u_pixelRatio; uniform float u_globalAlpha; uniform float u_time; uniform float u_zoom; uniform float u_resolution; uniform float u_rotation; uniform vec4 u_renderExtent; uniform vec2 u_patternOrigin; uniform float u_depth; uniform mediump int u_hitDetection; const float PI = 3.141592653589793238; const float TWO_PI = 2.0 * PI; float currentLineMetric = 0.; // an actual value will be used in the stroke shaders `; var DEFAULT_STYLE = createDefaultStyle(); var ShaderBuilder = class { constructor() { this.uniforms_ = []; this.attributes_ = []; this.hasSymbol_ = false; this.symbolSizeExpression_ = `vec2(${numberToGlsl( DEFAULT_STYLE["circle-radius"] )} + ${numberToGlsl(DEFAULT_STYLE["circle-stroke-width"] * 0.5)})`; this.symbolRotationExpression_ = "0.0"; this.symbolOffsetExpression_ = "vec2(0.0)"; this.symbolColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["circle-fill-color"] ); this.texCoordExpression_ = "vec4(0.0, 0.0, 1.0, 1.0)"; this.discardExpression_ = "false"; this.symbolRotateWithView_ = false; this.hasStroke_ = false; this.strokeWidthExpression_ = numberToGlsl(DEFAULT_STYLE["stroke-width"]); this.strokeColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["stroke-color"] ); this.strokeOffsetExpression_ = "0."; this.strokeCapExpression_ = stringToGlsl("round"); this.strokeJoinExpression_ = stringToGlsl("round"); this.strokeMiterLimitExpression_ = "10."; this.strokeDistanceFieldExpression_ = "-1000."; this.hasFill_ = false; this.fillColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["fill-color"] ); this.vertexShaderFunctions_ = []; this.fragmentShaderFunctions_ = []; } /** * Adds a uniform accessible in both fragment and vertex shaders. * The given name should include a type, such as `sampler2D u_texture`. * @param {string} name Uniform name, including the `u_` prefix * @param {'float'|'vec2'|'vec3'|'vec4'|'sampler2D'} type GLSL type * @return {ShaderBuilder} the builder object */ addUniform(name, type) { this.uniforms_.push({ name, type }); return this; } /** * Adds an attribute accessible in the vertex shader, read from the geometry buffer. * The given name should include a type, such as `vec2 a_position`. * Attributes will also be made available under the same name in fragment shaders. * @param {string} name Attribute name, including the `a_` prefix * @param {'float'|'vec2'|'vec3'|'vec4'} type GLSL type * @param {string} [varyingExpression] Expression which will be assigned to the varying in the vertex shader, and * passed on to the fragment shader. * @param {'float'|'vec2'|'vec3'|'vec4'} [varyingType] Type of the attribute after transformation; * e.g. `vec4` after unpacking color components * @return {ShaderBuilder} the builder object */ addAttribute(name, type, varyingExpression, varyingType) { this.attributes_.push({ name, type, varyingName: name.replace(/^a_/, "v_"), varyingType: varyingType ?? type, varyingExpression: varyingExpression ?? name }); return this; } /** * Sets an expression to compute the size of the shape. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec2` value. * @param {string} expression Size expression * @return {ShaderBuilder} the builder object */ setSymbolSizeExpression(expression) { this.hasSymbol_ = true; this.symbolSizeExpression_ = expression; return this; } /** * @return {string} The current symbol size expression */ getSymbolSizeExpression() { return this.symbolSizeExpression_; } /** * Sets an expression to compute the rotation of the shape. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `float` value in radians. * @param {string} expression Size expression * @return {ShaderBuilder} the builder object */ setSymbolRotationExpression(expression) { this.symbolRotationExpression_ = expression; return this; } /** * Sets an expression to compute the offset of the symbol from the point center. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec2` value. * @param {string} expression Offset expression * @return {ShaderBuilder} the builder object */ setSymbolOffsetExpression(expression) { this.symbolOffsetExpression_ = expression; return this; } /** * @return {string} The current symbol offset expression */ getSymbolOffsetExpression() { return this.symbolOffsetExpression_; } /** * Sets an expression to compute the color of the shape. * This expression can use all the uniforms, varyings and attributes available * in the fragment shader, and should evaluate to a `vec4` value. * @param {string} expression Color expression * @return {ShaderBuilder} the builder object */ setSymbolColorExpression(expression) { this.hasSymbol_ = true; this.symbolColorExpression_ = expression; return this; } /** * @return {string} The current symbol color expression */ getSymbolColorExpression() { return this.symbolColorExpression_; } /** * Sets an expression to compute the texture coordinates of the vertices. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec4` value. * @param {string} expression Texture coordinate expression * @return {ShaderBuilder} the builder object */ setTextureCoordinateExpression(expression) { this.texCoordExpression_ = expression; return this; } /** * Sets an expression to determine whether a fragment (pixel) should be discarded, * i.e. not drawn at all. * This expression can use all the uniforms, varyings and attributes available * in the fragment shader, and should evaluate to a `bool` value (it will be * used in an `if` statement) * @param {string} expression Fragment discard expression * @return {ShaderBuilder} the builder object */ setFragmentDiscardExpression(expression) { this.discardExpression_ = expression; return this; } /** * @return {string} The current fragment discard expression */ getFragmentDiscardExpression() { return this.discardExpression_; } /** * Sets whether the symbols should rotate with the view or stay aligned with the map. * Note: will only be used for point geometry shaders. * @param {boolean} rotateWithView Rotate with view * @return {ShaderBuilder} the builder object */ setSymbolRotateWithView(rotateWithView) { this.symbolRotateWithView_ = rotateWithView; return this; } /** * @param {string} expression Stroke width expression, returning value in pixels * @return {ShaderBuilder} the builder object */ setStrokeWidthExpression(expression) { this.hasStroke_ = true; this.strokeWidthExpression_ = expression; return this; } /** * @param {string} expression Stroke color expression, evaluate to `vec4`: can rely on currentLengthPx and currentRadiusPx * @return {ShaderBuilder} the builder object */ setStrokeColorExpression(expression) { this.hasStroke_ = true; this.strokeColorExpression_ = expression; return this; } /** * @return {string} The current stroke color expression */ getStrokeColorExpression() { return this.strokeColorExpression_; } /** * @param {string} expression Stroke color expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeOffsetExpression(expression) { this.strokeOffsetExpression_ = expression; return this; } /** * @param {string} expression Stroke line cap expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeCapExpression(expression) { this.strokeCapExpression_ = expression; return this; } /** * @param {string} expression Stroke line join expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeJoinExpression(expression) { this.strokeJoinExpression_ = expression; return this; } /** * @param {string} expression Stroke miter limit expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeMiterLimitExpression(expression) { this.strokeMiterLimitExpression_ = expression; return this; } /** * @param {string} expression Stroke distance field expression, evaluate to `float` * This can override the default distance field; can rely on currentLengthPx and currentRadiusPx * @return {ShaderBuilder} the builder object */ setStrokeDistanceFieldExpression(expression) { this.strokeDistanceFieldExpression_ = expression; return this; } /** * @param {string} expression Fill color expression, evaluate to `vec4` * @return {ShaderBuilder} the builder object */ setFillColorExpression(expression) { this.hasFill_ = true; this.fillColorExpression_ = expression; return this; } /** * @return {string} The current fill color expression */ getFillColorExpression() { return this.fillColorExpression_; } addVertexShaderFunction(code) { if (this.vertexShaderFunctions_.includes(code)) { return this; } this.vertexShaderFunctions_.push(code); return this; } addFragmentShaderFunction(code) { if (this.fragmentShaderFunctions_.includes(code)) { return this; } this.fragmentShaderFunctions_.push(code); return this; } /** * Generates a symbol vertex shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getSymbolVertexShader() { if (!this.hasSymbol_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_position; attribute float a_index; attribute vec4 a_hitColor; varying vec2 v_texCoord; varying vec2 v_quadCoord; varying vec4 v_hitColor; varying vec2 v_centerPx; varying float v_angle; varying vec2 v_quadSizePx; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} vec2 pxToScreen(vec2 coordPx) { vec2 scaled = coordPx / u_viewportSizePx / 0.5; return scaled; } vec2 screenToPx(vec2 coordScreen) { return (coordScreen * 0.5 + 0.5) * u_viewportSizePx; } void main(void) { v_quadSizePx = ${this.symbolSizeExpression_}; vec2 halfSizePx = v_quadSizePx * 0.5; vec2 centerOffsetPx = ${this.symbolOffsetExpression_}; vec2 offsetPx = centerOffsetPx; if (a_index == 0.0) { offsetPx -= halfSizePx; } else if (a_index == 1.0) { offsetPx += halfSizePx * vec2(1., -1.); } else if (a_index == 2.0) { offsetPx += halfSizePx; } else { offsetPx += halfSizePx * vec2(-1., 1.); } float angle = ${this.symbolRotationExpression_}${this.symbolRotateWithView_ ? " + u_rotation" : ""}; float c = cos(-angle); float s = sin(-angle); offsetPx = vec2(c * offsetPx.x - s * offsetPx.y, s * offsetPx.x + c * offsetPx.y); vec4 center = u_projectionMatrix * vec4(a_position, 0.0, 1.0); gl_Position = center + vec4(pxToScreen(offsetPx), u_depth, 0.); vec4 texCoord = ${this.texCoordExpression_}; float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p; float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q; v_texCoord = vec2(u, v); v_hitColor = a_hitColor; v_angle = angle; c = cos(-v_angle); s = sin(-v_angle); centerOffsetPx = vec2(c * centerOffsetPx.x - s * centerOffsetPx.y, s * centerOffsetPx.x + c * centerOffsetPx.y); v_centerPx = screenToPx(center.xy) + centerOffsetPx; ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a symbol fragment shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getSymbolFragmentShader() { if (!this.hasSymbol_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec2 v_texCoord; varying vec4 v_hitColor; varying vec2 v_centerPx; varying float v_angle; varying vec2 v_quadSizePx; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} if (${this.discardExpression_}) { discard; } vec2 coordsPx = gl_FragCoord.xy / u_pixelRatio - v_centerPx; // relative to center float c = cos(v_angle); float s = sin(v_angle); coordsPx = vec2(c * coordsPx.x - s * coordsPx.y, s * coordsPx.x + c * coordsPx.y); gl_FragColor = ${this.symbolColorExpression_}; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.05) { discard; }; gl_FragColor = v_hitColor; } }`; } /** * Generates a stroke vertex shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getStrokeVertexShader() { if (!this.hasStroke_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_segmentStart; attribute vec2 a_segmentEnd; attribute float a_measureStart; attribute float a_measureEnd; attribute float a_parameters; attribute float a_distance; attribute vec2 a_joinAngles; attribute vec4 a_hitColor; varying vec2 v_segmentStart; varying vec2 v_segmentEnd; varying float v_angleStart; varying float v_angleEnd; varying float v_width; varying vec4 v_hitColor; varying float v_distanceOffsetPx; varying float v_measureStart; varying float v_measureEnd; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} vec2 worldToPx(vec2 worldPos) { vec4 screenPos = u_projectionMatrix * vec4(worldPos, 0.0, 1.0); return (0.5 * screenPos.xy + 0.5) * u_viewportSizePx; } vec4 pxToScreen(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return vec4(screenPos, u_depth, 1.0); } bool isCap(float joinAngle) { return joinAngle < -0.1; } vec2 getJoinOffsetDirection(vec2 normalPx, float joinAngle) { float halfAngle = joinAngle / 2.0; float c = cos(halfAngle); float s = sin(halfAngle); vec2 angleBisectorNormal = vec2(s * normalPx.x + c * normalPx.y, -c * normalPx.x + s * normalPx.y); float length = 1.0 / s; return angleBisectorNormal * length; } vec2 getOffsetPoint(vec2 point, vec2 normal, float joinAngle, float offsetPx) { // if on a cap or the join angle is too high, offset the line along the segment normal if (cos(joinAngle) > 0.998 || isCap(joinAngle)) { return point - normal * offsetPx; } // offset is applied along the inverted normal (positive offset goes "right" relative to line direction) return point - getJoinOffsetDirection(normal, joinAngle) * offsetPx; } void main(void) { v_angleStart = a_joinAngles.x; v_angleEnd = a_joinAngles.y; float vertexNumber = floor(abs(a_parameters) / 10000. + 0.5); currentLineMetric = vertexNumber < 1.5 ? a_measureStart : a_measureEnd; // we're reading the fractional part while keeping the sign (so -4.12 gives -0.12, 3.45 gives 0.45) float angleTangentSum = fract(abs(a_parameters) / 10000.) * 10000. * sign(a_parameters); float lineWidth = ${this.strokeWidthExpression_}; float lineOffsetPx = ${this.strokeOffsetExpression_}; // compute segment start/end in px with offset vec2 segmentStartPx = worldToPx(a_segmentStart); vec2 segmentEndPx = worldToPx(a_segmentEnd); vec2 tangentPx = normalize(segmentEndPx - segmentStartPx); vec2 normalPx = vec2(-tangentPx.y, tangentPx.x); segmentStartPx = getOffsetPoint(segmentStartPx, normalPx, v_angleStart, lineOffsetPx), segmentEndPx = getOffsetPoint(segmentEndPx, normalPx, v_angleEnd, lineOffsetPx); // compute current vertex position float normalDir = vertexNumber < 0.5 || (vertexNumber > 1.5 && vertexNumber < 2.5) ? 1.0 : -1.0; float tangentDir = vertexNumber < 1.5 ? 1.0 : -1.0; float angle = vertexNumber < 1.5 ? v_angleStart : v_angleEnd; vec2 joinDirection; vec2 positionPx = vertexNumber < 1.5 ? segmentStartPx : segmentEndPx; // if angle is too high, do not make a proper join if (cos(angle) > ${LINESTRING_ANGLE_COSINE_CUTOFF} || isCap(angle)) { joinDirection = normalPx * normalDir - tangentPx * tangentDir; } else { joinDirection = getJoinOffsetDirection(normalPx * normalDir, angle); } positionPx = positionPx + joinDirection * (lineWidth * 0.5 + 1.); // adding 1 pixel for antialiasing gl_Position = pxToScreen(positionPx); v_segmentStart = segmentStartPx; v_segmentEnd = segmentEndPx; v_width = lineWidth; v_hitColor = a_hitColor; v_distanceOffsetPx = a_distance / u_resolution - (lineOffsetPx * angleTangentSum); v_measureStart = a_measureStart; v_measureEnd = a_measureEnd; ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a stroke fragment shader from the builder parameters * * @return {string|null} The full shader as a string; null if no size or color specified */ getStrokeFragmentShader() { if (!this.hasStroke_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec2 v_segmentStart; varying vec2 v_segmentEnd; varying float v_angleStart; varying float v_angleEnd; varying float v_width; varying vec4 v_hitColor; varying float v_distanceOffsetPx; varying float v_measureStart; varying float v_measureEnd; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} vec2 pxToWorld(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return (u_screenToWorldMatrix * vec4(screenPos, 0.0, 1.0)).xy; } bool isCap(float joinAngle) { return joinAngle < -0.1; } float segmentDistanceField(vec2 point, vec2 start, vec2 end, float width) { vec2 tangent = normalize(end - start); vec2 normal = vec2(-tangent.y, tangent.x); vec2 startToPoint = point - start; return abs(dot(startToPoint, normal)) - width * 0.5; } float buttCapDistanceField(vec2 point, vec2 start, vec2 end) { vec2 startToPoint = point - start; vec2 tangent = normalize(end - start); return dot(startToPoint, -tangent); } float squareCapDistanceField(vec2 point, vec2 start, vec2 end, float width) { return buttCapDistanceField(point, start, end) - width * 0.5; } float roundCapDistanceField(vec2 point, vec2 start, vec2 end, float width) { float onSegment = max(0., 1000. * dot(point - start, end - start)); // this is very high when inside the segment return length(point - start) - width * 0.5 - onSegment; } float roundJoinDistanceField(vec2 point, vec2 start, vec2 end, float width) { return roundCapDistanceField(point, start, end, width); } float bevelJoinField(vec2 point, vec2 start, vec2 end, float width, float joinAngle) { vec2 startToPoint = point - start; vec2 tangent = normalize(end - start); float c = cos(joinAngle * 0.5); float s = sin(joinAngle * 0.5); float direction = -sign(sin(joinAngle)); vec2 bisector = vec2(c * tangent.x - s * tangent.y, s * tangent.x + c * tangent.y); float radius = width * 0.5 * s; return dot(startToPoint, bisector * direction) - radius; } float miterJoinDistanceField(vec2 point, vec2 start, vec2 end, float width, float joinAngle) { if (cos(joinAngle) > ${LINESTRING_ANGLE_COSINE_CUTOFF}) { // avoid risking a division by zero return bevelJoinField(point, start, end, width, joinAngle); } float miterLength = 1. / sin(joinAngle * 0.5); float miterLimit = ${this.strokeMiterLimitExpression_}; if (miterLength > miterLimit) { return bevelJoinField(point, start, end, width, joinAngle); } return -1000.; } float capDistanceField(vec2 point, vec2 start, vec2 end, float width, float capType) { if (capType == ${stringToGlsl("butt")}) { return buttCapDistanceField(point, start, end); } else if (capType == ${stringToGlsl("square")}) { return squareCapDistanceField(point, start, end, width); } return roundCapDistanceField(point, start, end, width); } float joinDistanceField(vec2 point, vec2 start, vec2 end, float width, float joinAngle, float joinType) { if (joinType == ${stringToGlsl("bevel")}) { return bevelJoinField(point, start, end, width, joinAngle); } else if (joinType == ${stringToGlsl("miter")}) { return miterJoinDistanceField(point, start, end, width, joinAngle); } return roundJoinDistanceField(point, start, end, width); } float computeSegmentPointDistance(vec2 point, vec2 start, vec2 end, float width, float joinAngle, float capType, float joinType) { if (isCap(joinAngle)) { return capDistanceField(point, start, end, width, capType); } return joinDistanceField(point, start, end, width, joinAngle, joinType); } float distanceFromSegment(vec2 point, vec2 start, vec2 end) { vec2 tangent = end - start; vec2 startToPoint = point - start; // inspire by capsule fn in https://iquilezles.org/articles/distfunctions/ float h = clamp(dot(startToPoint, tangent) / dot(tangent, tangent), 0.0, 1.0); return length(startToPoint - tangent * h); } void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} vec2 currentPoint = gl_FragCoord.xy / u_pixelRatio; #ifdef GL_FRAGMENT_PRECISION_HIGH vec2 worldPos = pxToWorld(currentPoint); if ( abs(u_renderExtent[0] - u_renderExtent[2]) > 0.0 && ( worldPos[0] < u_renderExtent[0] || worldPos[1] < u_renderExtent[1] || worldPos[0] > u_renderExtent[2] || worldPos[1] > u_renderExtent[3] ) ) { discard; } #endif float segmentLength = length(v_segmentEnd - v_segmentStart); vec2 segmentTangent = (v_segmentEnd - v_segmentStart) / segmentLength; vec2 segmentNormal = vec2(-segmentTangent.y, segmentTangent.x); vec2 startToPoint = currentPoint - v_segmentStart; float lengthToPoint = max(0., min(dot(segmentTangent, startToPoint), segmentLength)); float currentLengthPx = lengthToPoint + v_distanceOffsetPx; float currentRadiusPx = distanceFromSegment(currentPoint, v_segmentStart, v_segmentEnd); float currentRadiusRatio = dot(segmentNormal, startToPoint) * 2. / v_width; currentLineMetric = mix( v_measureStart, v_measureEnd, lengthToPoint / max(segmentLength, 1.17549429e-38) ); if (${this.discardExpression_}) { discard; } float capType = ${this.strokeCapExpression_}; float joinType = ${this.strokeJoinExpression_}; float segmentStartDistance = computeSegmentPointDistance(currentPoint, v_segmentStart, v_segmentEnd, v_width, v_angleStart, capType, joinType); float segmentEndDistance = computeSegmentPointDistance(currentPoint, v_segmentEnd, v_segmentStart, v_width, v_angleEnd, capType, joinType); float distanceField = max( segmentDistanceField(currentPoint, v_segmentStart, v_segmentEnd, v_width), max(segmentStartDistance, segmentEndDistance) ); distanceField = max(distanceField, ${this.strokeDistanceFieldExpression_}); vec4 color = ${this.strokeColorExpression_}; color.a *= smoothstep(0.5, -0.5, distanceField); gl_FragColor = color; gl_FragColor.a *= u_globalAlpha; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.1) { discard; }; gl_FragColor = v_hitColor; } }`; } /** * Generates a fill vertex shader from the builder parameters * * @return {string|null} The full shader as a string; null if no color specified */ getFillVertexShader() { if (!this.hasFill_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_position; attribute vec4 a_hitColor; varying vec4 v_hitColor; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} void main(void) { gl_Position = u_projectionMatrix * vec4(a_position, u_depth, 1.0); v_hitColor = a_hitColor; ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a fill fragment shader from the builder parameters * @return {string|null} The full shader as a string; null if no color specified */ getFillFragmentShader() { if (!this.hasFill_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec4 v_hitColor; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} vec2 pxToWorld(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return (u_screenToWorldMatrix * vec4(screenPos, 0.0, 1.0)).xy; } vec2 worldToPx(vec2 worldPos) { vec4 screenPos = u_projectionMatrix * vec4(worldPos, 0.0, 1.0); return (0.5 * screenPos.xy + 0.5) * u_viewportSizePx; } void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} vec2 pxPos = gl_FragCoord.xy / u_pixelRatio; vec2 pxOrigin = worldToPx(u_patternOrigin); #ifdef GL_FRAGMENT_PRECISION_HIGH vec2 worldPos = pxToWorld(pxPos); if ( abs(u_renderExtent[0] - u_renderExtent[2]) > 0.0 && ( worldPos[0] < u_renderExtent[0] || worldPos[1] < u_renderExtent[1] || worldPos[0] > u_renderExtent[2] || worldPos[1] > u_renderExtent[3] ) ) { discard; } #endif if (${this.discardExpression_}) { discard; } gl_FragColor = ${this.fillColorExpression_}; gl_FragColor.a *= u_globalAlpha; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.1) { discard; }; gl_FragColor = v_hitColor; } }`; } }; // node_modules/ol/render/webgl/MixedGeometryBatch.js var MixedGeometryBatch = class _MixedGeometryBatch { constructor() { this.globalCounter_ = 0; this.refToFeature_ = /* @__PURE__ */ new Map(); this.uidToRef_ = /* @__PURE__ */ new Map(); this.freeGlobalRef_ = []; this.polygonBatch = { entries: {}, geometriesCount: 0, verticesCount: 0, ringsCount: 0 }; this.pointBatch = { entries: {}, geometriesCount: 0 }; this.lineStringBatch = { entries: {}, geometriesCount: 0, verticesCount: 0 }; } /** * @param {Array} features Array of features to add to the batch * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ addFeatures(features, projectionTransform) { for (let i = 0; i < features.length; i++) { this.addFeature(features[i], projectionTransform); } } /** * @param {Feature|RenderFeature} feature Feature to add to the batch * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ addFeature(feature, projectionTransform) { let geometry = feature.getGeometry(); if (!geometry) { return; } if (projectionTransform) { geometry = geometry.clone(); geometry.applyTransform(projectionTransform); } this.addGeometry_(geometry, feature); } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInPointBatch_(feature) { const featureUid = getUid(feature); const entry = this.pointBatch.entries[featureUid]; if (!entry) { return; } this.pointBatch.geometriesCount -= entry.flatCoordss.length; delete this.pointBatch.entries[featureUid]; return entry; } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInLineStringBatch_(feature) { const featureUid = getUid(feature); const entry = this.lineStringBatch.entries[featureUid]; if (!entry) { return; } this.lineStringBatch.verticesCount -= entry.verticesCount; this.lineStringBatch.geometriesCount -= entry.flatCoordss.length; delete this.lineStringBatch.entries[featureUid]; return entry; } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInPolygonBatch_(feature) { const featureUid = getUid(feature); const entry = this.polygonBatch.entries[featureUid]; if (!entry) { return; } this.polygonBatch.verticesCount -= entry.verticesCount; this.polygonBatch.ringsCount -= entry.ringsCount; this.polygonBatch.geometriesCount -= entry.flatCoordss.length; delete this.polygonBatch.entries[featureUid]; return entry; } /** * @param {import("../../geom.js").Geometry|RenderFeature} geometry Geometry * @param {Feature|RenderFeature} feature Feature * @private */ addGeometry_(geometry, feature) { var _a; const type = geometry.getType(); switch (type) { case "GeometryCollection": { const geometries = ( /** @type {import("../../geom.js").GeometryCollection} */ geometry.getGeometriesArray() ); for (const geometry2 of geometries) { this.addGeometry_(geometry2, feature); } break; } case "MultiPolygon": { const multiPolygonGeom = ( /** @type {import("../../geom.js").MultiPolygon} */ geometry ); this.addCoordinates_( type, multiPolygonGeom.getFlatCoordinates(), multiPolygonGeom.getEndss(), feature, getUid(feature), multiPolygonGeom.getStride() ); break; } case "MultiLineString": { const multiLineGeom = ( /** @type {import("../../geom.js").MultiLineString|RenderFeature} */ geometry ); this.addCoordinates_( type, multiLineGeom.getFlatCoordinates(), multiLineGeom.getEnds(), feature, getUid(feature), multiLineGeom.getStride() ); break; } case "MultiPoint": { const multiPointGeom = ( /** @type {import("../../geom.js").MultiPoint|RenderFeature} */ geometry ); this.addCoordinates_( type, multiPointGeom.getFlatCoordinates(), null, feature, getUid(feature), multiPointGeom.getStride() ); break; } case "Polygon": { const polygonGeom = ( /** @type {import("../../geom.js").Polygon|RenderFeature} */ geometry ); this.addCoordinates_( type, polygonGeom.getFlatCoordinates(), polygonGeom.getEnds(), feature, getUid(feature), polygonGeom.getStride() ); break; } case "Point": { const pointGeom = ( /** @type {import("../../geom.js").Point} */ geometry ); this.addCoordinates_( type, pointGeom.getFlatCoordinates(), null, feature, getUid(feature), pointGeom.getStride() ); break; } case "LineString": case "LinearRing": { const lineGeom = ( /** @type {import("../../geom.js").LineString} */ geometry ); const stride = lineGeom.getStride(); this.addCoordinates_( type, lineGeom.getFlatCoordinates(), null, feature, getUid(feature), stride, (_a = lineGeom.getLayout) == null ? void 0 : _a.call(lineGeom) ); break; } default: } } /** * @param {GeometryType} type Geometry type * @param {Array} flatCoords Flat coordinates * @param {Array | Array> | null} ends Coordinate ends * @param {Feature|RenderFeature} feature Feature * @param {string} featureUid Feature uid * @param {number} stride Stride * @param {import('../../geom/Geometry.js').GeometryLayout} [layout] Layout * @private */ addCoordinates_(type, flatCoords, ends, feature, featureUid, stride, layout) { let verticesCount; switch (type) { case "MultiPolygon": { const multiPolygonEndss = ( /** @type {Array>} */ ends ); for (let i = 0, ii = multiPolygonEndss.length; i < ii; i++) { let polygonEnds = multiPolygonEndss[i]; const prevPolygonEnds = i > 0 ? multiPolygonEndss[i - 1] : null; const startIndex = prevPolygonEnds ? prevPolygonEnds[prevPolygonEnds.length - 1] : 0; const endIndex = polygonEnds[polygonEnds.length - 1]; polygonEnds = startIndex > 0 ? polygonEnds.map((end) => end - startIndex) : polygonEnds; this.addCoordinates_( "Polygon", flatCoords.slice(startIndex, endIndex), polygonEnds, feature, featureUid, stride, layout ); } break; } case "MultiLineString": { const multiLineEnds = ( /** @type {Array} */ ends ); for (let i = 0, ii = multiLineEnds.length; i < ii; i++) { const startIndex = i > 0 ? multiLineEnds[i - 1] : 0; this.addCoordinates_( "LineString", flatCoords.slice(startIndex, multiLineEnds[i]), null, feature, featureUid, stride, layout ); } break; } case "MultiPoint": for (let i = 0, ii = flatCoords.length; i < ii; i += stride) { this.addCoordinates_( "Point", flatCoords.slice(i, i + 2), null, feature, featureUid, null, null ); } break; case "Polygon": { const polygonEnds = ( /** @type {Array} */ ends ); if (feature instanceof Feature_default) { const multiPolygonEnds = inflateEnds(flatCoords, polygonEnds); if (multiPolygonEnds.length > 1) { this.addCoordinates_( "MultiPolygon", flatCoords, multiPolygonEnds, feature, featureUid, stride, layout ); return; } } if (!this.polygonBatch.entries[featureUid]) { this.polygonBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [], verticesCount: 0, ringsCount: 0, ringsVerticesCounts: [] } ); } verticesCount = flatCoords.length / stride; const ringsCount = ends.length; const ringsVerticesCount = ends.map( (end, ind, arr) => ind > 0 ? (end - arr[ind - 1]) / stride : end / stride ); this.polygonBatch.verticesCount += verticesCount; this.polygonBatch.ringsCount += ringsCount; this.polygonBatch.geometriesCount++; this.polygonBatch.entries[featureUid].flatCoordss.push( getFlatCoordinatesXY(flatCoords, stride) ); this.polygonBatch.entries[featureUid].ringsVerticesCounts.push( ringsVerticesCount ); this.polygonBatch.entries[featureUid].verticesCount += verticesCount; this.polygonBatch.entries[featureUid].ringsCount += ringsCount; for (let i = 0, ii = polygonEnds.length; i < ii; i++) { const startIndex = i > 0 ? polygonEnds[i - 1] : 0; this.addCoordinates_( "LinearRing", flatCoords.slice(startIndex, polygonEnds[i]), null, feature, featureUid, stride, layout ); } break; } case "Point": if (!this.pointBatch.entries[featureUid]) { this.pointBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [] } ); } this.pointBatch.geometriesCount++; this.pointBatch.entries[featureUid].flatCoordss.push(flatCoords); break; case "LineString": case "LinearRing": if (!this.lineStringBatch.entries[featureUid]) { this.lineStringBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [], verticesCount: 0 } ); } verticesCount = flatCoords.length / stride; this.lineStringBatch.verticesCount += verticesCount; this.lineStringBatch.geometriesCount++; this.lineStringBatch.entries[featureUid].flatCoordss.push( getFlatCoordinatesXYM(flatCoords, stride, layout) ); this.lineStringBatch.entries[featureUid].verticesCount += verticesCount; break; default: } } /** * @param {string} featureUid Feature uid * @param {GeometryBatchItem} entry The entry to add * @return {GeometryBatchItem} the added entry * @private */ addRefToEntry_(featureUid, entry) { const currentRef = this.uidToRef_.get(featureUid); const ref = currentRef || this.freeGlobalRef_.pop() || ++this.globalCounter_; entry.ref = ref; if (!currentRef) { this.refToFeature_.set(ref, entry.feature); this.uidToRef_.set(featureUid, ref); } return entry; } /** * Return a ref to the pool of available refs. * @param {number} ref the ref to return * @param {string} featureUid the feature uid * @private */ removeRef_(ref, featureUid) { if (!ref) { throw new Error("This feature has no ref: " + featureUid); } this.refToFeature_.delete(ref); this.uidToRef_.delete(featureUid); this.freeGlobalRef_.push(ref); } /** * @param {Feature|RenderFeature} feature Feature * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ changeFeature(feature, projectionTransform) { if (!this.uidToRef_.get(getUid(feature))) { return; } this.removeFeature(feature); let geometry = feature.getGeometry(); if (!geometry) { return; } if (projectionTransform) { geometry = geometry.clone(); geometry.applyTransform(projectionTransform); } this.addGeometry_(geometry, feature); } /** * @param {Feature|RenderFeature} feature Feature */ removeFeature(feature) { let entry = this.clearFeatureEntryInPointBatch_(feature); entry = this.clearFeatureEntryInPolygonBatch_(feature) || entry; entry = this.clearFeatureEntryInLineStringBatch_(feature) || entry; if (entry) { this.removeRef_(entry.ref, getUid(entry.feature)); } } clear() { this.polygonBatch.entries = {}; this.polygonBatch.geometriesCount = 0; this.polygonBatch.verticesCount = 0; this.polygonBatch.ringsCount = 0; this.lineStringBatch.entries = {}; this.lineStringBatch.geometriesCount = 0; this.lineStringBatch.verticesCount = 0; this.pointBatch.entries = {}; this.pointBatch.geometriesCount = 0; this.globalCounter_ = 0; this.freeGlobalRef_ = []; this.refToFeature_.clear(); this.uidToRef_.clear(); } /** * Resolve the feature associated to a ref. * @param {number} ref Hit detected ref * @return {Feature|RenderFeature} feature */ getFeatureFromRef(ref) { return this.refToFeature_.get(ref); } isEmpty() { return this.globalCounter_ === 0; } /** * Will return a new instance of this class that only contains the features * for which the provided callback returned true * @param {function((Feature|RenderFeature)): boolean} featureFilter Feature filter callback * @return {MixedGeometryBatch} Filtered geometry batch */ filter(featureFilter) { const filtered = new _MixedGeometryBatch(); filtered.globalCounter_ = this.globalCounter_; filtered.uidToRef_ = this.uidToRef_; filtered.refToFeature_ = this.refToFeature_; let empty = true; for (const feature of this.refToFeature_.values()) { if (featureFilter(feature)) { filtered.addFeature(feature); empty = false; } } if (empty) { return new _MixedGeometryBatch(); } return filtered; } }; function getFlatCoordinatesXY(flatCoords, stride) { if (stride === 2) { return flatCoords; } return flatCoords.filter((v, i) => i % stride < 2); } function getFlatCoordinatesXYM(flatCoords, stride, layout) { if (stride === 3 && layout === "XYM") { return flatCoords; } if (stride === 4) { return flatCoords.filter((v, i) => i % stride !== 2); } if (stride === 3) { return flatCoords.map((v, i) => i % stride !== 2 ? v : 0); } return new Array(flatCoords.length * 1.5).fill(0).map((v, i) => i % 3 === 2 ? 0 : flatCoords[Math.round(i / 1.5)]); } var MixedGeometryBatch_default = MixedGeometryBatch; // node_modules/ol/worker/webgl.js function create3() { const source = 'function t(t,n,x=2){const o=n&&n.length,i=o?n[0]*x:t.length;let u=e(t,0,i,x,!0);const l=[];if(!u||u.next===u.prev)return l;let c,h,y;if(o&&(u=function(t,n,r,x){const o=[];for(let r=0,i=n.length;r80*x){c=1/0,h=1/0;let e=-1/0,n=-1/0;for(let r=x;re&&(e=x),o>n&&(n=o)}y=Math.max(e-c,n-h),y=0!==y?32767/y:0}return r(u,l,x,c,h,y,0),l}function e(t,e,n,r,x){let o;if(x===function(t,e,n,r){let x=0;for(let o=e,i=n-r;o0)for(let x=e;x=e;x-=r)o=w(x/r|0,t[x],t[x+1],o);return o&&g(o,o.next)&&(A(o),o=o.next),o}function n(t,e){if(!t)return t;e||(e=t);let n,r=t;do{if(n=!1,r.steiner||!g(r,r.next)&&0!==v(r.prev,r,r.next))r=r.next;else{if(A(r),r=e=r.prev,r===r.next)break;n=!0}}while(n||r!==e);return e}function r(t,e,f,s,l,a,h){if(!t)return;!h&&a&&function(t,e,n,r){let x=t;do{0===x.z&&(x.z=c(x.x,x.y,e,n,r)),x.prevZ=x.prev,x.nextZ=x.next,x=x.next}while(x!==t);x.prevZ.nextZ=null,x.prevZ=null,function(t){let e,n=1;do{let r,x=t;t=null;let o=null;for(e=0;x;){e++;let i=x,u=0;for(let t=0;t0||f>0&&i;)0!==u&&(0===f||!i||x.z<=i.z)?(r=x,x=x.nextZ,u--):(r=i,i=i.nextZ,f--),o?o.nextZ=r:t=r,r.prevZ=o,o=r;x=i}o.nextZ=null,n*=2}while(e>1)}(x)}(t,s,l,a);let y=t;for(;t.prev!==t.next;){const c=t.prev,p=t.next;if(a?o(t,s,l,a):x(t))e.push(c.i,t.i,p.i),A(t),t=p.next,y=p.next;else if((t=p)===y){h?1===h?r(t=i(n(t),e),e,f,s,l,a,2):2===h&&u(t,e,f,s,l,a):r(n(t),e,f,s,l,a,1);break}}}function x(t){const e=t.prev,n=t,r=t.next;if(v(e,n,r)>=0)return!1;const x=e.x,o=n.x,i=r.x,u=e.y,f=n.y,s=r.y,l=Math.min(x,o,i),c=Math.min(u,f,s),a=Math.max(x,o,i),h=Math.max(u,f,s);let p=r.next;for(;p!==e;){if(p.x>=l&&p.x<=a&&p.y>=c&&p.y<=h&&y(x,u,o,f,i,s,p.x,p.y)&&v(p.prev,p,p.next)>=0)return!1;p=p.next}return!0}function o(t,e,n,r){const x=t.prev,o=t,i=t.next;if(v(x,o,i)>=0)return!1;const u=x.x,f=o.x,s=i.x,l=x.y,a=o.y,h=i.y,p=Math.min(u,f,s),g=Math.min(l,a,h),b=Math.max(u,f,s),M=Math.max(l,a,h),m=c(p,g,e,n,r),Z=c(b,M,e,n,r);let d=t.prevZ,w=t.nextZ;for(;d&&d.z>=m&&w&&w.z<=Z;){if(d.x>=p&&d.x<=b&&d.y>=g&&d.y<=M&&d!==x&&d!==i&&y(u,l,f,a,s,h,d.x,d.y)&&v(d.prev,d,d.next)>=0)return!1;if(d=d.prevZ,w.x>=p&&w.x<=b&&w.y>=g&&w.y<=M&&w!==x&&w!==i&&y(u,l,f,a,s,h,w.x,w.y)&&v(w.prev,w,w.next)>=0)return!1;w=w.nextZ}for(;d&&d.z>=m;){if(d.x>=p&&d.x<=b&&d.y>=g&&d.y<=M&&d!==x&&d!==i&&y(u,l,f,a,s,h,d.x,d.y)&&v(d.prev,d,d.next)>=0)return!1;d=d.prevZ}for(;w&&w.z<=Z;){if(w.x>=p&&w.x<=b&&w.y>=g&&w.y<=M&&w!==x&&w!==i&&y(u,l,f,a,s,h,w.x,w.y)&&v(w.prev,w,w.next)>=0)return!1;w=w.nextZ}return!0}function i(t,e){let r=t;do{const n=r.prev,x=r.next.next;!g(n,x)&&b(n,r,r.next,x)&&Z(n,x)&&Z(x,n)&&(e.push(n.i,r.i,x.i),A(r),A(r.next),r=t=x),r=r.next}while(r!==t);return n(r)}function u(t,e,x,o,i,u){let f=t;do{let t=f.next.next;for(;t!==f.prev;){if(f.i!==t.i&&p(f,t)){let s=d(f,t);return f=n(f,f.next),s=n(s,s.next),r(f,e,x,o,i,u,0),void r(s,e,x,o,i,u,0)}t=t.next}f=f.next}while(f!==t)}function f(t,e){let n=t.x-e.x;if(0===n&&(n=t.y-e.y,0===n)){n=(t.next.y-t.y)/(t.next.x-t.x)-(e.next.y-e.y)/(e.next.x-e.x)}return n}function s(t,e){const r=function(t,e){let n=e;const r=t.x,x=t.y;let o,i=-1/0;if(g(t,n))return n;do{if(g(t,n.next))return n.next;if(x<=n.y&&x>=n.next.y&&n.next.y!==n.y){const t=n.x+(x-n.y)*(n.next.x-n.x)/(n.next.y-n.y);if(t<=r&&t>i&&(i=t,o=n.x=n.x&&n.x>=f&&r!==n.x&&h(xo.x||n.x===o.x&&l(o,n)))&&(o=n,c=e)}n=n.next}while(n!==u);return o}(t,e);if(!r)return e;const x=d(r,t);return n(x,x.next),n(r,r.next)}function l(t,e){return v(t.prev,t,e.prev)<0&&v(e.next,t,t.next)<0}function c(t,e,n,r,x){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-n)*x|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-r)*x|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function a(t){let e=t,n=t;do{(e.x=(t-i)*(o-u)&&(t-i)*(r-u)>=(n-i)*(e-u)&&(n-i)*(o-u)>=(x-i)*(r-u)}function y(t,e,n,r,x,o,i,u){return!(t===i&&e===u)&&h(t,e,n,r,x,o,i,u)}function p(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&b(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(Z(t,e)&&Z(e,t)&&function(t,e){let n=t,r=!1;const x=(t.x+e.x)/2,o=(t.y+e.y)/2;do{n.y>o!=n.next.y>o&&n.next.y!==n.y&&x<(n.next.x-n.x)*(o-n.y)/(n.next.y-n.y)+n.x&&(r=!r),n=n.next}while(n!==t);return r}(t,e)&&(v(t.prev,t,e.prev)||v(t,e.prev,e))||g(t,e)&&v(t.prev,t,t.next)>0&&v(e.prev,e,e.next)>0)}function v(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function g(t,e){return t.x===e.x&&t.y===e.y}function b(t,e,n,r){const x=m(v(t,e,n)),o=m(v(t,e,r)),i=m(v(n,r,t)),u=m(v(n,r,e));return x!==o&&i!==u||(!(0!==x||!M(t,n,e))||(!(0!==o||!M(t,r,e))||(!(0!==i||!M(n,t,r))||!(0!==u||!M(n,e,r)))))}function M(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function m(t){return t>0?1:t<0?-1:0}function Z(t,e){return v(t.prev,t,t.next)<0?v(t,e,t.next)>=0&&v(t,t.prev,e)>=0:v(t,e,t.prev)<0||v(t,t.next,e)<0}function d(t,e){const n=E(t.i,t.x,t.y),r=E(e.i,e.x,e.y),x=t.next,o=e.prev;return t.next=e,e.prev=t,n.next=x,x.prev=n,r.next=n,n.prev=r,o.next=r,r.prev=o,r}function w(t,e,n,r){const x=E(t,e,n);return r?(x.next=r.next,x.prev=r,r.next.prev=x,r.next=x):(x.prev=x,x.next=x),x}function A(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function E(t,e,n){return{i:t,x:e,y:n,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function I(t,e){const n=e[0],r=e[1];return e[0]=t[0]*n+t[2]*r+t[4],e[1]=t[1]*n+t[3]*r+t[5],e}function z(t,e){const n=(r=e)[0]*r[3]-r[1]*r[2];var r;!function(t,e){if(!t)throw new Error(e)}(0!==n,"Transformation matrix cannot be inverted");const x=e[0],o=e[1],i=e[2],u=e[3],f=e[4],s=e[5];return t[0]=u/n,t[1]=-o/n,t[2]=-i/n,t[3]=x/n,t[4]=(i*s-u*f)/n,t[5]=-(x*s-o*f)/n,t}new Array(6);const F=[],P={vertexPosition:0,indexPosition:0};function B(t,e,n,r,x){t[e+0]=n,t[e+1]=r,t[e+2]=x}function N(t,e,n,r,x,o){const i=3+x,u=t[e+0],f=t[e+1],s=F;s.length=x;for(let n=0;n0?f:2*Math.PI-f}let m=-1,Z=-1,d=l;const w=null!==x;if(null!==r){m=M(g,b,I(f,[...[t[r],t[r+1]]])),Math.cos(m)<=.985&&(d+=Math.tan((m-Math.PI)/2))}if(w){Z=M(b,g,I(f,[...[t[x],t[x+1]]])),Math.cos(Z)<=.985&&(d+=Math.tan((Math.PI-Z)/2))}function A(t,e){return 0===e?1e4*t:Math.sign(e)*(1e4*t+Math.abs(e))}return o.push(h[0],h[1],p,y[0],y[1],v,m,Z,s,A(0,l)),o.push(...u),o.push(h[0],h[1],p,y[0],y[1],v,m,Z,s,A(1,l)),o.push(...u),o.push(h[0],h[1],p,y[0],y[1],v,m,Z,s,A(2,l)),o.push(...u),o.push(h[0],h[1],p,y[0],y[1],v,m,Z,s,A(3,l)),o.push(...u),i.push(a,a+1,a+2,a+1,a+3,a+2),{length:s+Math.sqrt((b[0]-g[0])*(b[0]-g[0])+(b[1]-g[1])*(b[1]-g[1])),angle:d}}function S(e,n,r,x,o){const i=2+o;let u=n;const f=e.slice(u,u+o);u+=o;const s=e[u++];let l=0;const c=new Array(s-1);for(let t=0;t{const e=t.data;switch(e.type){case _:{const t=3,n=2,r=e.customAttributesSize,x=n+r,o=new Float32Array(e.renderInstructions),i=o.length/x,u=4*i*(r+t),f=new Uint32Array(6*i),s=new Float32Array(u);let l;for(let t=0;t0?y=i+(r-1)*x:c&&(y=l-x);let p=null;r prev + (customAttributes[curr].size || 1), 0 ); } function generatePointRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = (2 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const tmpCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { tmpCoords[0] = batchEntry.flatCoordss[i][0]; tmpCoords[1] = batchEntry.flatCoordss[i][1]; apply(transform, tmpCoords); renderInstructions[renderIndex++] = tmpCoords[0]; renderInstructions[renderIndex++] = tmpCoords[1]; renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); } } return renderInstructions; } function generateLineStringRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = 3 * batch.verticesCount + (1 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const flatCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { flatCoords.length = batchEntry.flatCoordss[i].length; transform2D( batchEntry.flatCoordss[i], 0, flatCoords.length, 3, transform, flatCoords, 3 ); renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); renderInstructions[renderIndex++] = flatCoords.length / 3; for (let j = 0, jj = flatCoords.length; j < jj; j += 3) { renderInstructions[renderIndex++] = flatCoords[j]; renderInstructions[renderIndex++] = flatCoords[j + 1]; renderInstructions[renderIndex++] = flatCoords[j + 2]; } } } return renderInstructions; } function generatePolygonRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = 2 * batch.verticesCount + (1 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount + batch.ringsCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const flatCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { flatCoords.length = batchEntry.flatCoordss[i].length; transform2D( batchEntry.flatCoordss[i], 0, flatCoords.length, 2, transform, flatCoords ); renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); renderInstructions[renderIndex++] = batchEntry.ringsVerticesCounts[i].length; for (let j = 0, jj = batchEntry.ringsVerticesCounts[i].length; j < jj; j++) { renderInstructions[renderIndex++] = batchEntry.ringsVerticesCounts[i][j]; } for (let j = 0, jj = flatCoords.length; j < jj; j += 2) { renderInstructions[renderIndex++] = flatCoords[j]; renderInstructions[renderIndex++] = flatCoords[j + 1]; } } } return renderInstructions; } // node_modules/ol/render/webgl/style.js function computeHash(input) { const hash = JSON.stringify(input).split("").reduce((prev, curr) => (prev << 5) - prev + curr.charCodeAt(0), 0); return (hash >>> 0).toString(); } function parseCommonSymbolProperties(style, builder, vertContext, prefix) { if (`${prefix}radius` in style && prefix !== "icon-") { let radius = expressionToGlsl( vertContext, style[`${prefix}radius`], NumberType ); if (`${prefix}radius2` in style) { const radius2 = expressionToGlsl( vertContext, style[`${prefix}radius2`], NumberType ); radius = `max(${radius}, ${radius2})`; } if (`${prefix}stroke-width` in style) { radius = `(${radius} + ${expressionToGlsl( vertContext, style[`${prefix}stroke-width`], NumberType )} * 0.5)`; } builder.setSymbolSizeExpression(`vec2(${radius} * 2. + 0.5)`); } if (`${prefix}scale` in style) { const scale = expressionToGlsl( vertContext, style[`${prefix}scale`], SizeType ); builder.setSymbolSizeExpression( `${builder.getSymbolSizeExpression()} * ${scale}` ); } if (`${prefix}displacement` in style) { builder.setSymbolOffsetExpression( expressionToGlsl( vertContext, style[`${prefix}displacement`], NumberArrayType ) ); } if (`${prefix}rotation` in style) { builder.setSymbolRotationExpression( expressionToGlsl(vertContext, style[`${prefix}rotation`], NumberType) ); } if (`${prefix}rotate-with-view` in style) { builder.setSymbolRotateWithView(!!style[`${prefix}rotate-with-view`]); } } function getColorFromDistanceField(distanceField, fillColor, strokeColor, strokeWidth, opacity) { let color = "vec4(0.)"; if (fillColor !== null) { color = fillColor; } if (strokeColor !== null && strokeWidth !== null) { const strokeFillRatio = `smoothstep(-${strokeWidth} + 0.63, -${strokeWidth} - 0.58, ${distanceField})`; color = `mix(${strokeColor}, ${color}, ${strokeFillRatio})`; } const shapeOpacity = `(1.0 - smoothstep(-0.63, 0.58, ${distanceField}))`; let result = `${color} * vec4(1.0, 1.0, 1.0, ${shapeOpacity})`; if (opacity !== null) { result = `${result} * vec4(1.0, 1.0, 1.0, ${opacity})`; } return result; } function parseImageProperties(style, builder, uniforms, prefix, textureId) { const image = new Image(); image.crossOrigin = style[`${prefix}cross-origin`] === void 0 ? "anonymous" : style[`${prefix}cross-origin`]; assert( typeof style[`${prefix}src`] === "string", `WebGL layers do not support expressions for the ${prefix}src style property` ); image.src = /** @type {string} */ style[`${prefix}src`]; uniforms[`u_texture${textureId}_size`] = () => { return image.complete ? [image.width, image.height] : [0, 0]; }; builder.addUniform(`u_texture${textureId}_size`, "vec2"); const size = `u_texture${textureId}_size`; uniforms[`u_texture${textureId}`] = image; builder.addUniform(`u_texture${textureId}`, "sampler2D"); return size; } function parseImageOffsetProperties(style, prefix, context, imageSize, sampleSize) { let offsetExpression = expressionToGlsl( context, style[`${prefix}offset`], SizeType ); if (`${prefix}offset-origin` in style) { switch (style[`${prefix}offset-origin`]) { case "top-right": offsetExpression = `vec2(${imageSize}.x, 0.) + ${sampleSize} * vec2(-1., 0.) + ${offsetExpression} * vec2(-1., 1.)`; break; case "bottom-left": offsetExpression = `vec2(0., ${imageSize}.y) + ${sampleSize} * vec2(0., -1.) + ${offsetExpression} * vec2(1., -1.)`; break; case "bottom-right": offsetExpression = `${imageSize} - ${sampleSize} - ${offsetExpression}`; break; default: } } return offsetExpression; } function parseCircleProperties(style, builder, uniforms, context) { context.functions["circleDistanceField"] = `float circleDistanceField(vec2 point, float radius) { return length(point) - radius; }`; parseCommonSymbolProperties(style, builder, context, "circle-"); let opacity = null; if ("circle-opacity" in style) { opacity = expressionToGlsl(context, style["circle-opacity"], NumberType); } let currentPoint = "coordsPx"; if ("circle-scale" in style) { const scale = expressionToGlsl(context, style["circle-scale"], SizeType); currentPoint = `coordsPx / ${scale}`; } let fillColor = null; if ("circle-fill-color" in style) { fillColor = expressionToGlsl( context, style["circle-fill-color"], ColorType ); } let strokeColor = null; if ("circle-stroke-color" in style) { strokeColor = expressionToGlsl( context, style["circle-stroke-color"], ColorType ); } let radius = expressionToGlsl(context, style["circle-radius"], NumberType); let strokeWidth = null; if ("circle-stroke-width" in style) { strokeWidth = expressionToGlsl( context, style["circle-stroke-width"], NumberType ); radius = `(${radius} + ${strokeWidth} * 0.5)`; } const distanceField = `circleDistanceField(${currentPoint}, ${radius})`; const colorExpression = getColorFromDistanceField( distanceField, fillColor, strokeColor, strokeWidth, opacity ); builder.setSymbolColorExpression(colorExpression); } function parseShapeProperties(style, builder, uniforms, context) { context.functions["round"] = `float round(float v) { return sign(v) * floor(abs(v) + 0.5); }`; context.functions["starDistanceField"] = `float starDistanceField(vec2 point, float numPoints, float radius, float radius2, float angle) { float startAngle = -PI * 0.5 + angle; // tip starts upwards and rotates clockwise with angle float c = cos(startAngle); float s = sin(startAngle); vec2 pointRotated = vec2(c * point.x - s * point.y, s * point.x + c * point.y); float alpha = TWO_PI / numPoints; // the angle of one sector float beta = atan(pointRotated.y, pointRotated.x); float gamma = round(beta / alpha) * alpha; // angle in sector c = cos(-gamma); s = sin(-gamma); vec2 inSector = vec2(c * pointRotated.x - s * pointRotated.y, abs(s * pointRotated.x + c * pointRotated.y)); vec2 tipToPoint = inSector + vec2(-radius, 0.); vec2 edgeNormal = vec2(radius2 * sin(alpha * 0.5), -radius2 * cos(alpha * 0.5) + radius); return dot(normalize(edgeNormal), tipToPoint); }`; context.functions["regularDistanceField"] = `float regularDistanceField(vec2 point, float numPoints, float radius, float angle) { float startAngle = -PI * 0.5 + angle; // tip starts upwards and rotates clockwise with angle float c = cos(startAngle); float s = sin(startAngle); vec2 pointRotated = vec2(c * point.x - s * point.y, s * point.x + c * point.y); float alpha = TWO_PI / numPoints; // the angle of one sector float radiusIn = radius * cos(PI / numPoints); float beta = atan(pointRotated.y, pointRotated.x); float gamma = round((beta - alpha * 0.5) / alpha) * alpha + alpha * 0.5; // angle in sector from mid c = cos(-gamma); s = sin(-gamma); vec2 inSector = vec2(c * pointRotated.x - s * pointRotated.y, abs(s * pointRotated.x + c * pointRotated.y)); return inSector.x - radiusIn; }`; parseCommonSymbolProperties(style, builder, context, "shape-"); let opacity = null; if ("shape-opacity" in style) { opacity = expressionToGlsl(context, style["shape-opacity"], NumberType); } let currentPoint = "coordsPx"; if ("shape-scale" in style) { const scale = expressionToGlsl(context, style["shape-scale"], SizeType); currentPoint = `coordsPx / ${scale}`; } let fillColor = null; if ("shape-fill-color" in style) { fillColor = expressionToGlsl(context, style["shape-fill-color"], ColorType); } let strokeColor = null; if ("shape-stroke-color" in style) { strokeColor = expressionToGlsl( context, style["shape-stroke-color"], ColorType ); } let strokeWidth = null; if ("shape-stroke-width" in style) { strokeWidth = expressionToGlsl( context, style["shape-stroke-width"], NumberType ); } const numPoints = expressionToGlsl( context, style["shape-points"], NumberType ); let angle = "0."; if ("shape-angle" in style) { angle = expressionToGlsl(context, style["shape-angle"], NumberType); } let shapeField; let radius = expressionToGlsl(context, style["shape-radius"], NumberType); if (strokeWidth !== null) { radius = `${radius} + ${strokeWidth} * 0.5`; } if ("shape-radius2" in style) { let radius2 = expressionToGlsl(context, style["shape-radius2"], NumberType); if (strokeWidth !== null) { radius2 = `${radius2} + ${strokeWidth} * 0.5`; } shapeField = `starDistanceField(${currentPoint}, ${numPoints}, ${radius}, ${radius2}, ${angle})`; } else { shapeField = `regularDistanceField(${currentPoint}, ${numPoints}, ${radius}, ${angle})`; } const colorExpression = getColorFromDistanceField( shapeField, fillColor, strokeColor, strokeWidth, opacity ); builder.setSymbolColorExpression(colorExpression); } function parseIconProperties(style, builder, uniforms, context) { let color = "vec4(1.0)"; if ("icon-color" in style) { color = expressionToGlsl(context, style["icon-color"], ColorType); } if ("icon-opacity" in style) { color = `${color} * vec4(1.0, 1.0, 1.0, ${expressionToGlsl( context, style["icon-opacity"], NumberType )})`; } const textureId = computeHash(style["icon-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "icon-", textureId ); builder.setSymbolColorExpression( `${color} * texture2D(u_texture${textureId}, v_texCoord)` ).setSymbolSizeExpression(sizeExpression); if ("icon-width" in style && "icon-height" in style) { builder.setSymbolSizeExpression( `vec2(${expressionToGlsl( context, style["icon-width"], NumberType )}, ${expressionToGlsl(context, style["icon-height"], NumberType)})` ); } if ("icon-offset" in style && "icon-size" in style) { const sampleSize = expressionToGlsl( context, style["icon-size"], NumberArrayType ); const fullsize = builder.getSymbolSizeExpression(); builder.setSymbolSizeExpression(sampleSize); const offset = parseImageOffsetProperties( style, "icon-", context, "v_quadSizePx", sampleSize ); builder.setTextureCoordinateExpression( `(vec4((${offset}).xyxy) + vec4(0., 0., ${sampleSize})) / (${fullsize}).xyxy` ); } parseCommonSymbolProperties(style, builder, context, "icon-"); if ("icon-anchor" in style) { const anchor = expressionToGlsl( context, style["icon-anchor"], NumberArrayType ); let scale = `1.0`; if (`icon-scale` in style) { scale = expressionToGlsl(context, style[`icon-scale`], SizeType); } let shiftPx; if (style["icon-anchor-x-units"] === "pixels" && style["icon-anchor-y-units"] === "pixels") { shiftPx = `${anchor} * ${scale}`; } else if (style["icon-anchor-x-units"] === "pixels") { shiftPx = `${anchor} * vec2(vec2(${scale}).x, v_quadSizePx.y)`; } else if (style["icon-anchor-y-units"] === "pixels") { shiftPx = `${anchor} * vec2(v_quadSizePx.x, vec2(${scale}).x)`; } else { shiftPx = `${anchor} * v_quadSizePx`; } let offsetPx = `v_quadSizePx * vec2(0.5, -0.5) + ${shiftPx} * vec2(-1., 1.)`; if ("icon-anchor-origin" in style) { switch (style["icon-anchor-origin"]) { case "top-right": offsetPx = `v_quadSizePx * -0.5 + ${shiftPx}`; break; case "bottom-left": offsetPx = `v_quadSizePx * 0.5 - ${shiftPx}`; break; case "bottom-right": offsetPx = `v_quadSizePx * vec2(-0.5, 0.5) + ${shiftPx} * vec2(1., -1.)`; break; default: } } builder.setSymbolOffsetExpression( `${builder.getSymbolOffsetExpression()} + ${offsetPx}` ); } } function parseStrokeProperties(style, builder, uniforms, context) { if ("stroke-color" in style) { builder.setStrokeColorExpression( expressionToGlsl(context, style["stroke-color"], ColorType) ); } if ("stroke-pattern-src" in style) { const textureId = computeHash(style["stroke-pattern-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "stroke-pattern-", textureId ); let sampleSizeExpression = sizeExpression; let offsetExpression = "vec2(0.)"; if ("stroke-pattern-offset" in style && "stroke-pattern-size" in style) { sampleSizeExpression = expressionToGlsl( context, style[`stroke-pattern-size`], NumberArrayType ); offsetExpression = parseImageOffsetProperties( style, "stroke-pattern-", context, sizeExpression, sampleSizeExpression ); } let spacingExpression = "0."; if ("stroke-pattern-spacing" in style) { spacingExpression = expressionToGlsl( context, style["stroke-pattern-spacing"], NumberType ); } context.functions["sampleStrokePattern"] = `vec4 sampleStrokePattern(sampler2D texture, vec2 textureSize, vec2 textureOffset, vec2 sampleSize, float spacingPx, float currentLengthPx, float currentRadiusRatio, float lineWidth) { float currentLengthScaled = currentLengthPx * sampleSize.y / lineWidth; float spacingScaled = spacingPx * sampleSize.y / lineWidth; float uCoordPx = mod(currentLengthScaled, (sampleSize.x + spacingScaled)); // make sure that we're not sampling too close to the borders to avoid interpolation with outside pixels uCoordPx = clamp(uCoordPx, 0.5, sampleSize.x - 0.5); float vCoordPx = (-currentRadiusRatio * 0.5 + 0.5) * sampleSize.y; vec2 texCoord = (vec2(uCoordPx, vCoordPx) + textureOffset) / textureSize; return texture2D(texture, texCoord); }`; const textureName = `u_texture${textureId}`; let tintExpression = "1."; if ("stroke-color" in style) { tintExpression = builder.getStrokeColorExpression(); } builder.setStrokeColorExpression( `${tintExpression} * sampleStrokePattern(${textureName}, ${sizeExpression}, ${offsetExpression}, ${sampleSizeExpression}, ${spacingExpression}, currentLengthPx, currentRadiusRatio, v_width)` ); } if ("stroke-width" in style) { builder.setStrokeWidthExpression( expressionToGlsl(context, style["stroke-width"], NumberType) ); } if ("stroke-offset" in style) { builder.setStrokeOffsetExpression( expressionToGlsl(context, style["stroke-offset"], NumberType) ); } if ("stroke-line-cap" in style) { builder.setStrokeCapExpression( expressionToGlsl(context, style["stroke-line-cap"], StringType) ); } if ("stroke-line-join" in style) { builder.setStrokeJoinExpression( expressionToGlsl(context, style["stroke-line-join"], StringType) ); } if ("stroke-miter-limit" in style) { builder.setStrokeMiterLimitExpression( expressionToGlsl(context, style["stroke-miter-limit"], NumberType) ); } if ("stroke-line-dash" in style) { context.functions["getSingleDashDistance"] = `float getSingleDashDistance(float distance, float radius, float dashOffset, float dashLength, float dashLengthTotal, float capType, float lineWidth) { float localDistance = mod(distance, dashLengthTotal); float distanceSegment = abs(localDistance - dashOffset - dashLength * 0.5) - dashLength * 0.5; distanceSegment = min(distanceSegment, dashLengthTotal - localDistance); if (capType == ${stringToGlsl("square")}) { distanceSegment -= lineWidth * 0.5; } else if (capType == ${stringToGlsl("round")}) { distanceSegment = min(distanceSegment, sqrt(distanceSegment * distanceSegment + radius * radius) - lineWidth * 0.5); } return distanceSegment; }`; let dashPattern = style["stroke-line-dash"].map( (v) => expressionToGlsl(context, v, NumberType) ); if (dashPattern.length % 2 === 1) { dashPattern = [...dashPattern, ...dashPattern]; } let offsetExpression = "0."; if ("stroke-line-dash-offset" in style) { offsetExpression = expressionToGlsl( context, style["stroke-line-dash-offset"], NumberType ); } const uniqueDashKey = computeHash(style["stroke-line-dash"]); const dashFunctionName = `dashDistanceField_${uniqueDashKey}`; const dashLengthsParamsDef = dashPattern.map((v, i) => `float dashLength${i}`).join(", "); const totalLengthDef = dashPattern.map((v, i) => `dashLength${i}`).join(" + "); let currentDashOffset = "0."; let distanceExpression = `getSingleDashDistance(distance, radius, ${currentDashOffset}, dashLength0, totalDashLength, capType, lineWidth)`; for (let i = 2; i < dashPattern.length; i += 2) { currentDashOffset = `${currentDashOffset} + dashLength${i - 2} + dashLength${i - 1}`; distanceExpression = `min(${distanceExpression}, getSingleDashDistance(distance, radius, ${currentDashOffset}, dashLength${i}, totalDashLength, capType, lineWidth))`; } context.functions[dashFunctionName] = `float ${dashFunctionName}(float distance, float radius, float capType, float lineWidth, ${dashLengthsParamsDef}) { float totalDashLength = ${totalLengthDef}; return ${distanceExpression}; }`; const dashLengthsCalls = dashPattern.map((v, i) => `${v}`).join(", "); builder.setStrokeDistanceFieldExpression( `${dashFunctionName}(currentLengthPx + ${offsetExpression}, currentRadiusPx, capType, v_width, ${dashLengthsCalls})` ); } } function parseFillProperties(style, builder, uniforms, context) { if ("fill-color" in style) { builder.setFillColorExpression( expressionToGlsl(context, style["fill-color"], ColorType) ); } if ("fill-pattern-src" in style) { const textureId = computeHash(style["fill-pattern-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "fill-pattern-", textureId ); let sampleSizeExpression = sizeExpression; let offsetExpression = "vec2(0.)"; if ("fill-pattern-offset" in style && "fill-pattern-size" in style) { sampleSizeExpression = expressionToGlsl( context, style[`fill-pattern-size`], NumberArrayType ); offsetExpression = parseImageOffsetProperties( style, "fill-pattern-", context, sizeExpression, sampleSizeExpression ); } context.functions["sampleFillPattern"] = `vec4 sampleFillPattern(sampler2D texture, vec2 textureSize, vec2 textureOffset, vec2 sampleSize, vec2 pxOrigin, vec2 pxPosition) { float scaleRatio = pow(2., mod(u_zoom + 0.5, 1.) - 0.5); vec2 pxRelativePos = pxPosition - pxOrigin; // rotate the relative position from origin by the current view rotation pxRelativePos = vec2(pxRelativePos.x * cos(u_rotation) - pxRelativePos.y * sin(u_rotation), pxRelativePos.x * sin(u_rotation) + pxRelativePos.y * cos(u_rotation)); // sample position is computed according to the sample offset & size vec2 samplePos = mod(pxRelativePos / scaleRatio, sampleSize); // also make sure that we're not sampling too close to the borders to avoid interpolation with outside pixels samplePos = clamp(samplePos, vec2(0.5), sampleSize - vec2(0.5)); samplePos.y = sampleSize.y - samplePos.y; // invert y axis so that images appear upright return texture2D(texture, (samplePos + textureOffset) / textureSize); }`; const textureName = `u_texture${textureId}`; let tintExpression = "1."; if ("fill-color" in style) { tintExpression = builder.getFillColorExpression(); } builder.setFillColorExpression( `${tintExpression} * sampleFillPattern(${textureName}, ${sizeExpression}, ${offsetExpression}, ${sampleSizeExpression}, pxOrigin, pxPos)` ); } } function parseLiteralStyle(style, variables, filter) { const context = newCompilationContext(); const builder = new ShaderBuilder(); const uniforms = {}; if ("icon-src" in style) { parseIconProperties(style, builder, uniforms, context); } else if ("shape-points" in style) { parseShapeProperties(style, builder, uniforms, context); } else if ("circle-radius" in style) { parseCircleProperties(style, builder, uniforms, context); } parseStrokeProperties(style, builder, uniforms, context); parseFillProperties(style, builder, uniforms, context); if (filter) { const parsedFilter = expressionToGlsl(context, filter, BooleanType); builder.setFragmentDiscardExpression(`!${parsedFilter}`); } const attributes = {}; function defineSpecialInput(contextPropName, glslPropName, type, callback) { if (!context[contextPropName]) { return; } const glslType = getGlslTypeFromType(type); const attrSize = getGlslSizeFromType(type); builder.addAttribute(`a_${glslPropName}`, glslType); attributes[glslPropName] = { size: attrSize, callback }; } defineSpecialInput( "geometryType", GEOMETRY_TYPE_PROPERTY_NAME, StringType, (feature) => getStringNumberEquivalent(computeGeometryType(feature.getGeometry())) ); defineSpecialInput( "featureId", FEATURE_ID_PROPERTY_NAME, StringType | NumberType, (feature) => { const id = feature.getId() ?? null; return typeof id === "string" ? getStringNumberEquivalent(id) : id; } ); applyContextToBuilder(builder, context); return { builder, attributes: { ...attributes, ...generateAttributesFromContext(context) }, uniforms: { ...uniforms, ...generateUniformsFromContext(context, variables) } }; } function breakDownFlatStyle(style) { const asArray = Array.isArray(style) ? style : [style]; if ("style" in asArray[0]) { const styles = []; const rules = ( /** @type {Array} */ asArray ); const previousFilters = []; for (const rule of rules) { const ruleStyles = Array.isArray(rule.style) ? rule.style : [rule.style]; let currentFilter = rule.filter; if (rule.else && previousFilters.length) { currentFilter = [ "all", ...previousFilters.map((filter) => ["!", filter]) ]; if (rule.filter) { currentFilter.push(rule.filter); } if (currentFilter.length < 3) { currentFilter = currentFilter[1]; } } if (rule.filter) { previousFilters.push(rule.filter); } const stylesWithFilters = ruleStyles.map((style2) => ({ style: style2, ...currentFilter && { filter: currentFilter } })); styles.push(...stylesWithFilters); } return styles; } if ("builder" in asArray[0]) { return ( /** @type {Array} */ asArray ); } return asArray.map( (style2) => ( /** @type {StyleAsRule} */ { style: style2 } ) ); } // node_modules/ol/render/webgl/VectorStyleRenderer.js var tmpColor = []; var WEBGL_WORKER; function getWebGLWorker() { if (!WEBGL_WORKER) { WEBGL_WORKER = create3(); } return WEBGL_WORKER; } var workerMessageCounter = 0; var Attributes = { POSITION: "a_position", INDEX: "a_index", SEGMENT_START: "a_segmentStart", SEGMENT_END: "a_segmentEnd", MEASURE_START: "a_measureStart", MEASURE_END: "a_measureEnd", PARAMETERS: "a_parameters", JOIN_ANGLES: "a_joinAngles", DISTANCE: "a_distance" }; var VectorStyleRenderer = class { /** * @param {VectorStyle} styleOrShaders Literal style or custom shaders * @param {import('../../style/flat.js').StyleVariables} variables Style variables * @param {import('../../webgl/Helper.js').default} helper Helper * @param {boolean} [enableHitDetection] Whether to enable the hit detection (needs compatible shader) * @param {import("../../expr/expression.js").ExpressionValue} [filter] Optional filter expression */ constructor(styleOrShaders, variables, helper, enableHitDetection, filter) { this.helper_; this.hitDetectionEnabled_ = !!enableHitDetection; let asShaders = ( /** @type {AsShaders} */ styleOrShaders ); const isShaders = "builder" in styleOrShaders; if (!isShaders) { const asRule = ( /** @type {AsRule} */ styleOrShaders ); const parseResult = parseLiteralStyle( asRule.style, variables, asRule.filter ); asShaders = { builder: parseResult.builder, attributes: parseResult.attributes, uniforms: parseResult.uniforms }; } this.fillProgram_; this.strokeProgram_; this.symbolProgram_; this.hasFill_ = !!asShaders.builder.getFillVertexShader(); if (this.hasFill_) { this.fillVertexShader_ = asShaders.builder.getFillVertexShader(); this.fillFragmentShader_ = asShaders.builder.getFillFragmentShader(); } this.hasStroke_ = !!asShaders.builder.getStrokeVertexShader(); if (this.hasStroke_) { this.strokeVertexShader_ = asShaders.builder.getStrokeVertexShader(); this.strokeFragmentShader_ = asShaders.builder.getStrokeFragmentShader(); } this.hasSymbol_ = !!asShaders.builder.getSymbolVertexShader(); if (this.hasSymbol_) { this.symbolVertexShader_ = asShaders.builder.getSymbolVertexShader(); this.symbolFragmentShader_ = asShaders.builder.getSymbolFragmentShader(); } this.featureFilter_ = null; if (filter) { this.featureFilter_ = this.computeFeatureFilter(filter); } const hitDetectionAttributes = this.hitDetectionEnabled_ ? { hitColor: { callback() { return colorEncodeId(this.ref, tmpColor); }, size: 4 } } : {}; this.customAttributes_ = Object.assign( {}, hitDetectionAttributes, asShaders.attributes ); this.uniforms_ = asShaders.uniforms; const customAttributesDesc = Object.entries(this.customAttributes_).map( ([name, value]) => ({ name: `a_${name}`, size: value.size || 1, type: AttributeType.FLOAT }) ); this.polygonAttributesDesc_ = [ { name: Attributes.POSITION, size: 2, type: AttributeType.FLOAT }, ...customAttributesDesc ]; this.lineStringAttributesDesc_ = [ { name: Attributes.SEGMENT_START, size: 2, type: AttributeType.FLOAT }, { name: Attributes.MEASURE_START, size: 1, type: AttributeType.FLOAT }, { name: Attributes.SEGMENT_END, size: 2, type: AttributeType.FLOAT }, { name: Attributes.MEASURE_END, size: 1, type: AttributeType.FLOAT }, { name: Attributes.JOIN_ANGLES, size: 2, type: AttributeType.FLOAT }, { name: Attributes.DISTANCE, size: 1, type: AttributeType.FLOAT }, { name: Attributes.PARAMETERS, size: 1, type: AttributeType.FLOAT }, ...customAttributesDesc ]; this.pointAttributesDesc_ = [ { name: Attributes.POSITION, size: 2, type: AttributeType.FLOAT }, { name: Attributes.INDEX, size: 1, type: AttributeType.FLOAT }, ...customAttributesDesc ]; this.setHelper(helper); } /** * Will apply the style filter when generating geometry batches (if it can be evaluated outside a map context) * @param {import("../../expr/expression.js").ExpressionValue} filter Style filter * @return {function(import('../../Feature.js').FeatureLike): boolean} Feature filter * @private */ computeFeatureFilter(filter) { const parsingContext = newParsingContext(); let compiled; try { compiled = buildExpression(filter, BooleanType, parsingContext); } catch { return null; } if (parsingContext.mapState || parsingContext.variables.size > 0) { return null; } const evalContext = newEvaluationContext(); return (feature) => { evalContext.properties = feature.getPropertiesInternal(); if (parsingContext.featureId) { const id = feature.getId(); if (id !== void 0) { evalContext.featureId = id; } else { evalContext.featureId = null; } } evalContext.geometryType = computeGeometryType(feature.getGeometry()); return ( /** @type {boolean} */ compiled(evalContext) ); }; } /** * @param {import('./MixedGeometryBatch.js').default} geometryBatch Geometry batch * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {Promise} A promise resolving to WebGL buffers; returns null if buffers are empty */ async generateBuffers(geometryBatch, transform) { let filteredBatch = geometryBatch; if (this.featureFilter_) { filteredBatch = filteredBatch.filter(this.featureFilter_); if (filteredBatch.isEmpty()) { return null; } } const renderInstructions = this.generateRenderInstructions_( filteredBatch, transform ); const [polygonBuffers, lineStringBuffers, pointBuffers] = await Promise.all( [ this.generateBuffersForType_( renderInstructions.polygonInstructions, "Polygon", transform ), this.generateBuffersForType_( renderInstructions.lineStringInstructions, "LineString", transform ), this.generateBuffersForType_( renderInstructions.pointInstructions, "Point", transform ) ] ); const invertVerticesTransform = makeInverse( create(), transform ); return { polygonBuffers, lineStringBuffers, pointBuffers, invertVerticesTransform }; } /** * @param {import('./MixedGeometryBatch.js').default} geometryBatch Geometry batch * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {RenderInstructions} Render instructions * @private */ generateRenderInstructions_(geometryBatch, transform) { const polygonInstructions = this.hasFill_ ? generatePolygonRenderInstructions( geometryBatch.polygonBatch, new Float32Array(0), this.customAttributes_, transform ) : null; const lineStringInstructions = this.hasStroke_ ? generateLineStringRenderInstructions( geometryBatch.lineStringBatch, new Float32Array(0), this.customAttributes_, transform ) : null; const pointInstructions = this.hasSymbol_ ? generatePointRenderInstructions( geometryBatch.pointBatch, new Float32Array(0), this.customAttributes_, transform ) : null; return { polygonInstructions, lineStringInstructions, pointInstructions }; } /** * @param {Float32Array|null} renderInstructions Render instructions * @param {import("../../geom/Geometry.js").Type} geometryType Geometry type * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {Promise>|null} Indices buffer and vertices buffer; null if nothing to render * @private */ generateBuffersForType_(renderInstructions, geometryType, transform) { if (renderInstructions === null) { return null; } const messageId = workerMessageCounter++; let messageType; switch (geometryType) { case "Polygon": messageType = WebGLWorkerMessageType.GENERATE_POLYGON_BUFFERS; break; case "LineString": messageType = WebGLWorkerMessageType.GENERATE_LINE_STRING_BUFFERS; break; case "Point": messageType = WebGLWorkerMessageType.GENERATE_POINT_BUFFERS; break; default: } const message = { id: messageId, type: messageType, renderInstructions: renderInstructions.buffer, renderInstructionsTransform: transform, customAttributesSize: getCustomAttributesSize(this.customAttributes_) }; const WEBGL_WORKER2 = getWebGLWorker(); WEBGL_WORKER2.postMessage(message, [renderInstructions.buffer]); renderInstructions = null; return new Promise((resolve) => { const handleMessage = (event) => { const received = event.data; if (received.id !== messageId) { return; } WEBGL_WORKER2.removeEventListener("message", handleMessage); if (!this.helper_.getGL()) { return; } const verticesBuffer = new Buffer_default( ARRAY_BUFFER, DYNAMIC_DRAW ).fromArrayBuffer(received.vertexBuffer); const indicesBuffer = new Buffer_default( ELEMENT_ARRAY_BUFFER, DYNAMIC_DRAW ).fromArrayBuffer(received.indexBuffer); this.helper_.flushBufferData(verticesBuffer); this.helper_.flushBufferData(indicesBuffer); resolve([indicesBuffer, verticesBuffer]); }; WEBGL_WORKER2.addEventListener("message", handleMessage); }); } /** * Render the geometries in the given buffers. * @param {WebGLBuffers} buffers WebGL Buffers to draw * @param {import("../../Map.js").FrameState} frameState Frame state * @param {function(): void} preRenderCallback This callback will be called right before drawing, and can be used to set uniforms */ render(buffers, frameState, preRenderCallback) { this.hasFill_ && this.renderInternal_( buffers.polygonBuffers[0], buffers.polygonBuffers[1], this.fillProgram_, this.polygonAttributesDesc_, frameState, preRenderCallback ); this.hasStroke_ && this.renderInternal_( buffers.lineStringBuffers[0], buffers.lineStringBuffers[1], this.strokeProgram_, this.lineStringAttributesDesc_, frameState, preRenderCallback ); this.hasSymbol_ && this.renderInternal_( buffers.pointBuffers[0], buffers.pointBuffers[1], this.symbolProgram_, this.pointAttributesDesc_, frameState, preRenderCallback ); } /** * @param {WebGLArrayBuffer} indicesBuffer Indices buffer * @param {WebGLArrayBuffer} verticesBuffer Vertices buffer * @param {WebGLProgram} program Program * @param {Array} attributes Attribute descriptions * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {function(): void} preRenderCallback This callback will be called right before drawing, and can be used to set uniforms * @private */ renderInternal_(indicesBuffer, verticesBuffer, program, attributes, frameState, preRenderCallback) { const renderCount = indicesBuffer.getSize(); if (renderCount === 0) { return; } this.helper_.useProgram(program, frameState); this.helper_.bindBuffer(verticesBuffer); this.helper_.bindBuffer(indicesBuffer); this.helper_.enableAttributes(attributes); preRenderCallback(); this.helper_.drawElements(0, renderCount); } /** * @param {import('../../webgl/Helper.js').default} helper Helper * @param {WebGLBuffers} buffers WebGL Buffers to reload if any */ setHelper(helper, buffers = null) { this.helper_ = helper; if (this.hasFill_) { this.fillProgram_ = this.helper_.getProgram( this.fillFragmentShader_, this.fillVertexShader_ ); } if (this.hasStroke_) { this.strokeProgram_ = this.helper_.getProgram( this.strokeFragmentShader_, this.strokeVertexShader_ ); } if (this.hasSymbol_) { this.symbolProgram_ = this.helper_.getProgram( this.symbolFragmentShader_, this.symbolVertexShader_ ); } this.helper_.addUniforms(this.uniforms_); if (buffers) { if (buffers.polygonBuffers) { this.helper_.flushBufferData(buffers.polygonBuffers[0]); this.helper_.flushBufferData(buffers.polygonBuffers[1]); } if (buffers.lineStringBuffers) { this.helper_.flushBufferData(buffers.lineStringBuffers[0]); this.helper_.flushBufferData(buffers.lineStringBuffers[1]); } if (buffers.pointBuffers) { this.helper_.flushBufferData(buffers.pointBuffers[0]); this.helper_.flushBufferData(buffers.pointBuffers[1]); } } } }; var VectorStyleRenderer_default = VectorStyleRenderer; // node_modules/ol/webgl/RenderTarget.js var tmpArray4 = new Uint8Array(4); var WebGLRenderTarget = class { /** * @param {import("./Helper.js").default} helper WebGL helper; mandatory. * @param {Array} [size] Expected size of the render target texture; note: this can be changed later on. */ constructor(helper, size) { this.helper_ = helper; const gl = helper.getGL(); this.texture_ = gl.createTexture(); this.framebuffer_ = gl.createFramebuffer(); this.depthbuffer_ = gl.createRenderbuffer(); this.size_ = size || [1, 1]; this.data_ = new Uint8Array(0); this.dataCacheDirty_ = true; this.updateSize_(); } /** * Changes the size of the render target texture. Note: will do nothing if the size * is already the same. * @param {Array} size Expected size of the render target texture */ setSize(size) { if (equals(size, this.size_)) { return; } this.size_[0] = size[0]; this.size_[1] = size[1]; this.updateSize_(); } /** * Returns the size of the render target texture * @return {Array} Size of the render target texture */ getSize() { return this.size_; } /** * This will cause following calls to `#readAll` or `#readPixel` to download the content of the * render target into memory, which is an expensive operation. * This content will be kept in cache but should be cleared after each new render. */ clearCachedData() { this.dataCacheDirty_ = true; } /** * Returns the full content of the frame buffer as a series of r, g, b, a components * in the 0-255 range (unsigned byte). * @return {Uint8Array} Integer array of color values */ readAll() { if (this.dataCacheDirty_) { const size = this.size_; const gl = this.helper_.getGL(); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_); gl.readPixels( 0, 0, size[0], size[1], gl.RGBA, gl.UNSIGNED_BYTE, this.data_ ); this.dataCacheDirty_ = false; } return this.data_; } /** * Reads one pixel of the frame buffer as an array of r, g, b, a components * in the 0-255 range (unsigned byte). * If x and/or y are outside of existing data, an array filled with 0 is returned. * @param {number} x Pixel coordinate * @param {number} y Pixel coordinate * @return {Uint8Array} Integer array with one color value (4 components) */ readPixel(x, y) { if (x < 0 || y < 0 || x > this.size_[0] || y >= this.size_[1]) { tmpArray4[0] = 0; tmpArray4[1] = 0; tmpArray4[2] = 0; tmpArray4[3] = 0; return tmpArray4; } this.readAll(); const index = Math.floor(x) + (this.size_[1] - Math.floor(y) - 1) * this.size_[0]; tmpArray4[0] = this.data_[index * 4]; tmpArray4[1] = this.data_[index * 4 + 1]; tmpArray4[2] = this.data_[index * 4 + 2]; tmpArray4[3] = this.data_[index * 4 + 3]; return tmpArray4; } /** * @return {WebGLTexture} Texture to render to */ getTexture() { return this.texture_; } /** * @return {WebGLFramebuffer} Frame buffer of the render target */ getFramebuffer() { return this.framebuffer_; } /** * @return {WebGLRenderbuffer} Depth buffer of the render target */ getDepthbuffer() { return this.depthbuffer_; } /** * @private */ updateSize_() { const size = this.size_; const gl = this.helper_.getGL(); this.texture_ = this.helper_.createTexture(size, null, this.texture_); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_); gl.viewport(0, 0, size[0], size[1]); gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture_, 0 ); gl.bindRenderbuffer(gl.RENDERBUFFER, this.depthbuffer_); gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size[0], size[1] ); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthbuffer_ ); this.data_ = new Uint8Array(size[0] * size[1] * 4); } }; var RenderTarget_default = WebGLRenderTarget; // node_modules/ol/renderer/webgl/worldUtil.js function getWorldParameters(frameState, layer) { const projection = frameState.viewState.projection; const vectorSource = layer.getSource(); const multiWorld = vectorSource.getWrapX() && projection.canWrapX(); const projectionExtent = projection.getExtent(); const extent = frameState.extent; const worldWidth = multiWorld ? getWidth(projectionExtent) : null; const endWorld = multiWorld ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1 : 1; const startWorld = multiWorld ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth) : 0; return [startWorld, endWorld, worldWidth]; } // node_modules/ol/renderer/webgl/VectorLayer.js var Uniforms = { ...DefaultUniform, RENDER_EXTENT: "u_renderExtent", // intersection of layer, source, and view extent PATTERN_ORIGIN: "u_patternOrigin", GLOBAL_ALPHA: "u_globalAlpha" }; var WebGLVectorLayerRenderer = class extends Layer_default { /** * @param {import("../../layer/Layer.js").default} layer Layer. * @param {Options} options Options. */ constructor(layer, options) { const uniforms = { [Uniforms.RENDER_EXTENT]: [0, 0, 0, 0], [Uniforms.PATTERN_ORIGIN]: [0, 0], [Uniforms.GLOBAL_ALPHA]: 1 }; super(layer, { uniforms, postProcesses: options.postProcesses }); this.hitDetectionEnabled_ = !options.disableHitDetection; this.hitRenderTarget_; this.sourceRevision_ = -1; this.previousExtent_ = createEmpty(); this.currentTransform_ = create(); this.tmpCoords_ = [0, 0]; this.tmpTransform_ = create(); this.tmpMat4_ = create2(); this.currentFrameStateTransform_ = create(); this.styleVariables_ = {}; this.styles_ = []; this.styleRenderers_ = []; this.buffers_ = []; this.applyOptions_(options); this.batch_ = new MixedGeometryBatch_default(); this.initialFeaturesAdded_ = false; this.sourceListenKeys_ = null; } /** * @private * @param {import("../../Map.js").FrameState} frameState Frame state. */ addInitialFeatures_(frameState) { const source = this.getLayer().getSource(); const userProjection = getUserProjection(); let projectionTransform; if (userProjection) { projectionTransform = getTransformFromProjections( userProjection, frameState.viewState.projection ); } this.batch_.addFeatures(source.getFeatures(), projectionTransform); this.sourceListenKeys_ = [ listen( source, VectorEventType_default.ADDFEATURE, this.handleSourceFeatureAdded_.bind(this, projectionTransform) ), listen( source, VectorEventType_default.CHANGEFEATURE, this.handleSourceFeatureChanged_.bind(this, projectionTransform), this ), listen( source, VectorEventType_default.REMOVEFEATURE, this.handleSourceFeatureDelete_, this ), listen( source, VectorEventType_default.CLEAR, this.handleSourceFeatureClear_, this ) ]; } /** * @param {Options} options Options. * @private */ applyOptions_(options) { this.styleVariables_ = options.variables; this.styles_ = breakDownFlatStyle(options.style); } /** * @private */ createRenderers_() { this.buffers_ = []; this.styleRenderers_ = this.styles_.map( (style) => new VectorStyleRenderer_default( style, this.styleVariables_, this.helper, this.hitDetectionEnabled_, "filter" in style ? style.filter : null ) ); } /** * @override */ reset(options) { this.applyOptions_(options); if (this.helper) { this.createRenderers_(); } super.reset(options); } /** * @override */ afterHelperCreated() { if (this.styleRenderers_.length) { this.styleRenderers_.forEach( (renderer, i) => renderer.setHelper(this.helper, this.buffers_[i]) ); } else { this.createRenderers_(); } if (this.hitDetectionEnabled_) { this.hitRenderTarget_ = new RenderTarget_default(this.helper); } } /** * @param {import("../../proj.js").TransformFunction} projectionTransform Transform function. * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureAdded_(projectionTransform, event) { const feature = event.feature; this.batch_.addFeature(feature, projectionTransform); } /** * @param {import("../../proj.js").TransformFunction} projectionTransform Transform function. * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureChanged_(projectionTransform, event) { const feature = event.feature; this.batch_.changeFeature(feature, projectionTransform); } /** * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureDelete_(event) { const feature = event.feature; this.batch_.removeFeature(feature); } /** * @private */ handleSourceFeatureClear_() { this.batch_.clear(); } /** * @param {import("../../transform.js").Transform} batchInvertTransform Inverse of the transformation in which geometries are expressed * @private */ applyUniforms_(batchInvertTransform) { setFromArray(this.tmpTransform_, this.currentFrameStateTransform_); multiply(this.tmpTransform_, batchInvertTransform); this.helper.setUniformMatrixValue( Uniforms.PROJECTION_MATRIX, fromTransform(this.tmpMat4_, this.tmpTransform_) ); makeInverse(this.tmpTransform_, this.tmpTransform_); this.helper.setUniformMatrixValue( Uniforms.SCREEN_TO_WORLD_MATRIX, fromTransform(this.tmpMat4_, this.tmpTransform_) ); this.tmpCoords_[0] = 0; this.tmpCoords_[1] = 0; makeInverse(this.tmpTransform_, batchInvertTransform); apply(this.tmpTransform_, this.tmpCoords_); this.helper.setUniformFloatVec2(Uniforms.PATTERN_ORIGIN, this.tmpCoords_); } /** * Render the layer. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {HTMLElement} The rendered element. * @override */ renderFrame(frameState) { const gl = this.helper.getGL(); this.preRender(gl, frameState); const [startWorld, endWorld, worldWidth] = getWorldParameters( frameState, this.getLayer() ); this.helper.prepareDraw(frameState); this.renderWorlds(frameState, false, startWorld, endWorld, worldWidth); this.helper.finalizeDraw( frameState, this.dispatchPreComposeEvent, this.dispatchPostComposeEvent ); const canvas = this.helper.getCanvas(); if (this.hitDetectionEnabled_) { this.renderWorlds(frameState, true, startWorld, endWorld, worldWidth); this.hitRenderTarget_.clearCachedData(); } this.postRender(gl, frameState); return canvas; } /** * Determine whether renderFrame should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @override */ prepareFrameInternal(frameState) { if (!this.initialFeaturesAdded_) { this.addInitialFeatures_(frameState); this.initialFeaturesAdded_ = true; } const layer = this.getLayer(); const vectorSource = layer.getSource(); const viewState = frameState.viewState; const viewNotMoving = !frameState.viewHints[ViewHint_default.ANIMATING] && !frameState.viewHints[ViewHint_default.INTERACTING]; const extentChanged = !equals2(this.previousExtent_, frameState.extent); const sourceChanged = this.sourceRevision_ < vectorSource.getRevision(); if (sourceChanged) { this.sourceRevision_ = vectorSource.getRevision(); } if (viewNotMoving && (extentChanged || sourceChanged)) { const projection = viewState.projection; const resolution = viewState.resolution; const renderBuffer = layer instanceof BaseVector_default ? layer.getRenderBuffer() : 0; const extent = buffer(frameState.extent, renderBuffer * resolution); const userProjection = getUserProjection(); if (userProjection) { vectorSource.loadFeatures( toUserExtent(extent, userProjection), toUserResolution(resolution, projection), userProjection ); } else { vectorSource.loadFeatures(extent, resolution, projection); } this.ready = false; const transform = this.helper.makeProjectionTransform( frameState, create() ); const generatePromises = this.styleRenderers_.map( (renderer, i) => renderer.generateBuffers(this.batch_, transform).then((buffers) => { if (this.buffers_[i]) { this.disposeBuffers(this.buffers_[i]); } this.buffers_[i] = buffers; }) ); Promise.all(generatePromises).then(() => { this.ready = true; this.getLayer().changed(); }); this.previousExtent_ = frameState.extent.slice(); } return true; } /** * Render the world, either to the main framebuffer or to the hit framebuffer * @param {import("../../Map.js").FrameState} frameState current frame state * @param {boolean} forHitDetection whether the rendering is for hit detection * @param {number} startWorld the world to render in the first iteration * @param {number} endWorld the last world to render * @param {number} worldWidth the width of the worlds being rendered */ renderWorlds(frameState, forHitDetection, startWorld, endWorld, worldWidth) { let world = startWorld; if (forHitDetection) { this.hitRenderTarget_.setSize([ Math.floor(frameState.size[0] / 2), Math.floor(frameState.size[1] / 2) ]); this.helper.prepareDrawToRenderTarget( frameState, this.hitRenderTarget_, true ); } do { this.helper.makeProjectionTransform( frameState, this.currentFrameStateTransform_ ); translate( this.currentFrameStateTransform_, world * worldWidth, 0 ); for (let i = 0, ii = this.styleRenderers_.length; i < ii; i++) { const renderer = this.styleRenderers_[i]; const buffers = this.buffers_[i]; if (!buffers) { continue; } renderer.render(buffers, frameState, () => { this.applyUniforms_(buffers.invertVerticesTransform); this.helper.applyHitDetectionUniform(forHitDetection); }); } } while (++world < endWorld); } /** * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {number} hitTolerance Hit tolerance in pixels. * @param {import("../vector.js").FeatureCallback} callback Feature callback. * @param {Array>} matches The hit detected matches with tolerance. * @return {T|undefined} Callback result. * @template T * @override */ forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, matches) { assert( this.hitDetectionEnabled_, "`forEachFeatureAtCoordinate` cannot be used on a WebGL layer if the hit detection logic has been disabled using the `disableHitDetection: true` option." ); if (!this.styleRenderers_.length || !this.hitDetectionEnabled_) { return void 0; } const pixel = apply( frameState.coordinateToPixelTransform, coordinate.slice() ); const data = this.hitRenderTarget_.readPixel(pixel[0] / 2, pixel[1] / 2); const color = [data[0] / 255, data[1] / 255, data[2] / 255, data[3] / 255]; const ref = colorDecodeId(color); const feature = this.batch_.getFeatureFromRef(ref); if (feature) { return callback(feature, this.getLayer(), null); } return void 0; } /** * Will release a set of Webgl buffers * @param {import('../../render/webgl/VectorStyleRenderer.js').WebGLBuffers} buffers Buffers */ disposeBuffers(buffers) { const disposeBuffersOfType = (typeBuffers) => { for (const buffer2 of typeBuffers) { if (buffer2) { this.helper.deleteBuffer(buffer2); } } }; if (buffers.pointBuffers) { disposeBuffersOfType(buffers.pointBuffers); } if (buffers.lineStringBuffers) { disposeBuffersOfType(buffers.lineStringBuffers); } if (buffers.polygonBuffers) { disposeBuffersOfType(buffers.polygonBuffers); } } /** * Clean up. * @override */ disposeInternal() { this.buffers_.forEach((buffers) => { if (buffers) { this.disposeBuffers(buffers); } }); if (this.sourceListenKeys_) { this.sourceListenKeys_.forEach(function(key) { unlistenByKey(key); }); this.sourceListenKeys_ = null; } super.disposeInternal(); } renderDeclutter() { } }; var VectorLayer_default = WebGLVectorLayerRenderer; // node_modules/ol/layer/Heatmap.js var Property = { BLUR: "blur", GRADIENT: "gradient", RADIUS: "radius" }; var DEFAULT_GRADIENT = ["#00f", "#0ff", "#0f0", "#ff0", "#f00"]; var Heatmap = class extends BaseVector_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; const baseOptions = Object.assign({}, options); delete baseOptions.gradient; delete baseOptions.radius; delete baseOptions.blur; delete baseOptions.weight; super(baseOptions); this.filter_ = options.filter ?? true; this.styleVariables_ = options.variables || {}; this.gradient_ = null; this.addChangeListener(Property.GRADIENT, this.handleGradientChanged_); this.setGradient(options.gradient ? options.gradient : DEFAULT_GRADIENT); this.setBlur(options.blur !== void 0 ? options.blur : 15); this.setRadius(options.radius !== void 0 ? options.radius : 8); const weight = options.weight ? options.weight : "weight"; this.weight_ = weight; this.setRenderOrder(null); } /** * Return the blur size in pixels. * @return {import("../style/flat.js").NumberExpression} Blur size in pixels. * @api * @observable */ getBlur() { return ( /** @type {import("../style/flat.js").NumberExpression} */ this.get(Property.BLUR) ); } /** * Return the gradient colors as array of strings. * @return {Array} Colors. * @api * @observable */ getGradient() { return ( /** @type {Array} */ this.get(Property.GRADIENT) ); } /** * Return the size of the radius in pixels. * @return {import("../style/flat.js").NumberExpression} Radius size in pixel. * @api * @observable */ getRadius() { return ( /** @type {import("../style/flat.js").NumberExpression} */ this.get(Property.RADIUS) ); } /** * @private */ handleGradientChanged_() { this.gradient_ = createGradient(this.getGradient()); } /** * Set the blur size in pixels. * @param {import("../style/flat.js").NumberExpression} blur Blur size in pixels (supports expressions). * @api * @observable */ setBlur(blur) { const previousValue = this.get(Property.BLUR); this.set(Property.BLUR, blur); if (typeof blur === "number" && typeof previousValue === "number") { this.changed(); return; } this.clearRenderer(); } /** * Set the gradient colors as array of strings. * @param {Array} colors Gradient. * @api * @observable */ setGradient(colors) { this.set(Property.GRADIENT, colors); } /** * Set the size of the radius in pixels. * @param {import("../style/flat.js").NumberExpression} radius Radius size in pixel (supports expressions). * @api * @observable */ setRadius(radius) { const previousValue = this.get(Property.RADIUS); this.set(Property.RADIUS, radius); if (typeof radius === "number" && typeof previousValue === "number") { this.changed(); return; } this.clearRenderer(); } /** * Set the filter expression * @param {import("../style/flat.js").BooleanExpression} filter Filter expression * @api */ setFilter(filter) { this.filter_ = filter; this.changed(); this.clearRenderer(); } /** * Set the weight expression * @param {WeightExpression} weight Weight expression * @api */ setWeight(weight) { this.weight_ = weight; this.changed(); this.clearRenderer(); } /** * @override */ createRenderer() { const builder = new ShaderBuilder(); const context = newCompilationContext(); const filterCompiled = expressionToGlsl(context, this.filter_, BooleanType); let radiusCompiled = expressionToGlsl( context, this.getRadius(), NumberType ); let blurCompiled = expressionToGlsl(context, this.getBlur(), NumberType); const blurRadiusUniforms = {}; if (typeof this.getBlur() === "number") { blurCompiled = "a_blur"; blurRadiusUniforms["a_blur"] = () => this.getBlur(); builder.addUniform("a_blur", "float"); } if (typeof this.getRadius() === "number") { radiusCompiled = "a_radius"; blurRadiusUniforms["a_radius"] = () => this.getRadius(); builder.addUniform("a_radius", "float"); } const weightAttribute = {}; let weightExpression = null; if (typeof this.weight_ === "string" || typeof this.weight_ === "function") { const weightFunction = typeof this.weight_ === "string" ? (feature) => feature.get(this.weight_) : this.weight_; weightAttribute["prop_weight"] = { size: 1, callback: (feature) => { const weightValue = weightFunction(feature); return weightValue !== void 0 ? clamp(weightValue, 0, 1) : 1; } }; weightExpression = "a_prop_weight"; builder.addAttribute("a_prop_weight", "float"); } else { const clampedWeight = ["clamp", this.weight_, 0, 1]; weightExpression = expressionToGlsl(context, clampedWeight, NumberType); } builder.addFragmentShaderFunction( `float getBlurSlope() { float blur = max(1., ${blurCompiled}); float radius = ${radiusCompiled}; return radius / blur; }` ).setSymbolSizeExpression(`vec2(${radiusCompiled} + ${blurCompiled}) * 2.`).setSymbolColorExpression( `vec4(smoothstep(0., 1., (1. - length(coordsPx * 2. / v_quadSizePx)) * getBlurSlope()) * ${weightExpression})` ).setStrokeColorExpression( `vec4(smoothstep(0., 1., (1. - length(currentRadiusPx * 2. / v_width)) * getBlurSlope()) * ${weightExpression})` ).setStrokeWidthExpression(`(${radiusCompiled} + ${blurCompiled}) * 2.`).setFillColorExpression(`vec4(${weightExpression})`).setFragmentDiscardExpression(`!${filterCompiled}`); applyContextToBuilder(builder, context); const attributes = generateAttributesFromContext(context); const uniforms = generateUniformsFromContext(context, this.styleVariables_); return new VectorLayer_default(this, { className: this.getClassName(), variables: this.styleVariables_, style: { builder, attributes: { ...attributes, ...weightAttribute }, uniforms: { ...uniforms, ...blurRadiusUniforms } }, disableHitDetection: false, postProcesses: [ { fragmentShader: ` precision mediump float; uniform sampler2D u_image; uniform sampler2D u_gradientTexture; uniform float u_opacity; varying vec2 v_texCoord; void main() { vec4 color = texture2D(u_image, v_texCoord); gl_FragColor.a = color.a * u_opacity; gl_FragColor.rgb = texture2D(u_gradientTexture, vec2(0.5, color.a)).rgb; gl_FragColor.rgb *= gl_FragColor.a; }`, uniforms: { u_gradientTexture: () => this.gradient_, u_opacity: () => this.getOpacity() } } ] }); } /** * Update any variables used by the layer style and trigger a re-render. * @param {import('../style/flat.js').StyleVariables} variables Variables to update. */ updateStyleVariables(variables) { Object.assign(this.styleVariables_, variables); this.changed(); } /** * @override */ renderDeclutter() { } }; function createGradient(colors) { const width = 1; const height = 256; const context = createCanvasContext2D(width, height); const gradient = context.createLinearGradient(0, 0, width, height); const step = 1 / (colors.length - 1); for (let i = 0, ii = colors.length; i < ii; ++i) { gradient.addColorStop(i * step, colors[i]); } context.fillStyle = gradient; context.fillRect(0, 0, width, height); return context.canvas; } var Heatmap_default = Heatmap; export { create3 as create, WebGLWorkerMessageType, colorEncodeId, colorDecodeId, parseLiteralStyle, RenderTarget_default, getWorldParameters, VectorLayer_default, Heatmap_default }; //# sourceMappingURL=chunk-MY3Y56DQ.js.map