From 24584fa9aea4c0d06ce151b4f7cd1a0ad9905edd Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 6 May 2025 14:32:16 +0200 Subject: [PATCH 1/2] fix: refactor dashDistanceField function to use parameters for dash lengths --- src/ol/render/webgl/style.js | 12 +-- .../spec/ol/render/webgl/style.test.js | 102 ++++++++++++++++-- 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/src/ol/render/webgl/style.js b/src/ol/render/webgl/style.js index 5431b5daf45..8c7acb603d7 100644 --- a/src/ol/render/webgl/style.js +++ b/src/ol/render/webgl/style.js @@ -648,9 +648,9 @@ function parseStrokeProperties(style, builder, uniforms, context) { const uniqueDashKey = computeHash(style['stroke-line-dash']); const dashFunctionName = `dashDistanceField_${uniqueDashKey}`; - const dashLengthsDef = dashPattern.map( - (v, i) => `float dashLength${i} = ${v};`, - ); + const dashLengthsParamsDef = dashPattern + .map((v, i) => `float dashLength${i}`) + .join(', '); const totalLengthDef = dashPattern .map((v, i) => `dashLength${i}`) .join(' + '); @@ -664,13 +664,13 @@ function parseStrokeProperties(style, builder, uniforms, context) { } context.functions[dashFunctionName] = - `float ${dashFunctionName}(float distance, float radius, float capType, float lineWidth) { - ${dashLengthsDef.join('\n ')} + `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)`, + `${dashFunctionName}(currentLengthPx + ${offsetExpression}, currentRadiusPx, capType, v_width, ${dashLengthsCalls})`, ); } } diff --git a/test/browser/spec/ol/render/webgl/style.test.js b/test/browser/spec/ol/render/webgl/style.test.js index ef7cac408ed..c48ba85f8f2 100644 --- a/test/browser/spec/ol/render/webgl/style.test.js +++ b/test/browser/spec/ol/render/webgl/style.test.js @@ -746,7 +746,7 @@ describe('ol/render/webgl/style', () => { '(u_var_miterLimit - 10.0)', ); expect(result.builder.strokeDistanceFieldExpression_).to.eql( - 'dashDistanceField_450289113(currentLengthPx + (u_time * 5.0), currentRadiusPx, capType, v_width)', + 'dashDistanceField_450289113(currentLengthPx + (u_time * 5.0), currentRadiusPx, capType, v_width, (a_prop_size * 10.0), (a_prop_size * 20.0), 5.0, (a_prop_size * 20.0))', ); expect(Object.keys(result.attributes).length).to.eql(3); expect(result.attributes).to.have.property('prop_intensity'); @@ -761,11 +761,7 @@ describe('ol/render/webgl/style', () => { 'float getSingleDashDistance', ); expect(result.builder.fragmentShaderFunctions_).to - .contain(`float dashDistanceField_450289113(float distance, float radius, float capType, float lineWidth) { - float dashLength0 = (a_prop_size * 10.0); - float dashLength1 = (a_prop_size * 20.0); - float dashLength2 = 5.0; - float dashLength3 = (a_prop_size * 20.0); + .contain(`float dashDistanceField_450289113(float distance, float radius, float capType, float lineWidth, float dashLength0, float dashLength1, float dashLength2, float dashLength3) { float totalDashLength = dashLength0 + dashLength1 + dashLength2 + dashLength3; return min(getSingleDashDistance(distance, radius, 0., dashLength0, totalDashLength, capType, lineWidth), getSingleDashDistance(distance, radius, 0. + dashLength0 + dashLength1, dashLength2, totalDashLength, capType, lineWidth)); }`); @@ -832,6 +828,100 @@ describe('ol/render/webgl/style', () => { ); }); }); + + describe('stroke style with all dynamic dash length expressions', () => { + let result; + + beforeEach(() => { + // Create a style where ALL dash lengths come from expressions + const style = { + 'stroke-color': 'red', + 'stroke-width': 3, + 'stroke-line-dash': [ + ['get', 'dashLength0'], + ['get', 'dashLength1'], + ['get', 'dashLength2'], + ['get', 'dashLength3'], + ], + 'stroke-line-dash-offset': ['get', 'dashOffset'], + }; + result = parseLiteralStyle(style); + }); + + it('includes dash distance functions in the shader', () => { + expect( + result.builder.fragmentShaderFunctions_.some((fn) => + fn.includes('getSingleDashDistance'), + ), + ).to.be(true); + + const dashFunctionName = result.builder.fragmentShaderFunctions_ + .find((fn) => fn.startsWith('float dashDistanceField_')) + .split('(')[0] + .split(' ')[1]; + + expect(dashFunctionName).to.contain('dashDistanceField_'); + }); + + it('defines dash lengths as function parameters instead of inside function body', () => { + // Get the dashDistanceField function definition + const dashFunctionDef = result.builder.fragmentShaderFunctions_.find( + (fn) => fn.startsWith('float dashDistanceField_'), + ); + + // The function signature should include parameters for all dash lengths + const functionSignature = dashFunctionDef.split('{')[0]; + expect(functionSignature).to.contain('float distance'); + expect(functionSignature).to.contain('float radius'); + expect(functionSignature).to.contain('float capType'); + expect(functionSignature).to.contain('float lineWidth'); + expect(functionSignature).to.contain('float dashLength0'); + expect(functionSignature).to.contain('float dashLength1'); + expect(functionSignature).to.contain('float dashLength2'); + expect(functionSignature).to.contain('float dashLength3'); + }); + + it('passes all dynamic dash length expressions to the function as parameters', () => { + expect(result.builder.strokeDistanceFieldExpression_).to.contain( + 'dashDistanceField_', + ); + expect(result.builder.strokeDistanceFieldExpression_).to.contain( + 'a_prop_dashLength0', + ); + expect(result.builder.strokeDistanceFieldExpression_).to.contain( + 'a_prop_dashLength1', + ); + expect(result.builder.strokeDistanceFieldExpression_).to.contain( + 'a_prop_dashLength2', + ); + expect(result.builder.strokeDistanceFieldExpression_).to.contain( + 'a_prop_dashLength3', + ); + }); + + it('correctly extracts all dash length values from features', () => { + const feature = new Feature({ + dashLength0: 10, + dashLength1: 5, + dashLength2: 15, + dashLength3: 12, + dashOffset: 2, + }); + + expect( + result.attributes['prop_dashLength0'].callback(feature), + ).to.eql(10); + expect( + result.attributes['prop_dashLength1'].callback(feature), + ).to.eql(5); + expect( + result.attributes['prop_dashLength2'].callback(feature), + ).to.eql(15); + expect( + result.attributes['prop_dashLength3'].callback(feature), + ).to.eql(12); + }); + }); }); describe('fill style', () => { From 1880d769b7b72286bcce52da337feab345e4b783 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 7 May 2025 10:52:25 +0200 Subject: [PATCH 2/2] fix: Update webgl closedLine rendering test to include a dynamic dash distance --- test/rendering/cases/webgl-line/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/rendering/cases/webgl-line/main.js b/test/rendering/cases/webgl-line/main.js index 14defc4f4d4..6e9789afd7e 100644 --- a/test/rendering/cases/webgl-line/main.js +++ b/test/rendering/cases/webgl-line/main.js @@ -18,6 +18,7 @@ const openLine = new Feature({ [-60, -50], ]), lineColor: 'rgba(80,0,0,0.75)', + firstDashDistance: 18, }); const closedLine = new Feature({ @@ -32,6 +33,7 @@ const closedLine = new Feature({ [90, -80], ]), lineColor: 'rgba(255,243,177,0.75)', + firstDashDistance: 18, }); const dataDriven = { @@ -55,7 +57,7 @@ const dashed = { 'stroke-color': 'rgb(0,104,218)', 'stroke-offset': -10, 'stroke-width': 4, - 'stroke-line-dash': [18, 10, 10, 10], + 'stroke-line-dash': [['get', 'firstDashDistance'], 10, 10, 10], 'stroke-line-dash-offset': 10, }; const style = [bevelJoins, dataDriven, miterJoins, dashed];