Skip to content

Commit

Permalink
fix dashed lines with square line caps (#9561)
Browse files Browse the repository at this point in the history
* fix "line-dasharray" with "line-cap": "square"

fix #9531

* remove leftover

Co-authored-by: Vladimir Agafonkin <[email protected]>
  • Loading branch information
ansis and mourner authored May 6, 2021
1 parent 291ba36 commit 7ca8f72
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 30 deletions.
42 changes: 26 additions & 16 deletions src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,12 @@ class LineBucket implements Bucket {
hasFeatureDashes = true;

} else {
const round = capPropertyValue.value === 'round';
const constCap = capPropertyValue.value;
const constDash = dashPropertyValue.value;
if (!constDash) continue;
lineAtlas.addDash(constDash.from, round);
lineAtlas.addDash(constDash.to, round);
if (constDash.other) lineAtlas.addDash(constDash.other, round);
lineAtlas.addDash(constDash.from, constCap);
lineAtlas.addDash(constDash.to, constCap);
if (constDash.other) lineAtlas.addDash(constDash.other, constCap);
}
}

Expand All @@ -228,7 +228,7 @@ class LineBucket implements Bucket {

if (dashPropertyValue.kind === 'constant' && capPropertyValue.kind === 'constant') continue;

let minDashArray, midDashArray, maxDashArray, minRound, midRound, maxRound;
let minDashArray, midDashArray, maxDashArray, minCap, midCap, maxCap;

if (dashPropertyValue.kind === 'constant') {
const constDash = dashPropertyValue.value;
Expand All @@ -244,21 +244,21 @@ class LineBucket implements Bucket {
}

if (capPropertyValue.kind === 'constant') {
minRound = midRound = maxRound = capPropertyValue.value === 'round';
minCap = midCap = maxCap = capPropertyValue.value;

} else {
minRound = capPropertyValue.evaluate({zoom: zoom - 1}, feature) === 'round';
midRound = capPropertyValue.evaluate({zoom}, feature) === 'round';
maxRound = capPropertyValue.evaluate({zoom: zoom + 1}, feature) === 'round';
minCap = capPropertyValue.evaluate({zoom: zoom - 1}, feature);
midCap = capPropertyValue.evaluate({zoom}, feature);
maxCap = capPropertyValue.evaluate({zoom: zoom + 1}, feature);
}

lineAtlas.addDash(minDashArray, minRound);
lineAtlas.addDash(midDashArray, midRound);
lineAtlas.addDash(maxDashArray, maxRound);
lineAtlas.addDash(minDashArray, minCap);
lineAtlas.addDash(midDashArray, midCap);
lineAtlas.addDash(maxDashArray, maxCap);

const min = lineAtlas.getKey(minDashArray, minRound);
const mid = lineAtlas.getKey(midDashArray, midRound);
const max = lineAtlas.getKey(maxDashArray, maxRound);
const min = lineAtlas.getKey(minDashArray, minCap);
const mid = lineAtlas.getKey(midDashArray, midCap);
const max = lineAtlas.getKey(maxDashArray, maxCap);

// save positions for paint array
feature.patterns[layer.id] = {min, mid, max};
Expand Down Expand Up @@ -540,7 +540,17 @@ class LineBucket implements Bucket {

} else if (currentJoin === 'square') {
const offset = prevVertex ? 1 : -1; // closing or starting square cap
this.addCurrentVertex(currentVertex, joinNormal, offset, offset, segment);

if (!prevVertex) {
this.addCurrentVertex(currentVertex, joinNormal, offset, offset, segment);
}

// make the cap it's own quad to avoid the cap affecting the line distance
this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment);

if (prevVertex) {
this.addCurrentVertex(currentVertex, joinNormal, offset, offset, segment);
}

} else if (currentJoin === 'round') {

Expand Down
5 changes: 2 additions & 3 deletions src/render/draw_line.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,8 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay

if (!image && constantDash && constantCap && tile.lineAtlas) {
const atlas = tile.lineAtlas;
const round = constantCap === 'round';
const posTo = atlas.getDash(constantDash.to, round);
const posFrom = atlas.getDash(constantDash.from, round);
const posTo = atlas.getDash(constantDash.to, constantCap);
const posFrom = atlas.getDash(constantDash.from, constantCap);
if (posTo && posFrom) programConfiguration.setConstantPatternPositions(posTo, posFrom);
}

Expand Down
22 changes: 12 additions & 10 deletions src/render/line_atlas.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ class LineAtlas {
* Get a dash line pattern.
*
* @param {Array<number>} dasharray
* @param {boolean} round whether to add circle caps in between dash segments
* @param {string} lineCap the type of line caps to be added to dashes
* @returns {Object} position of dash texture in { y, height, width }
* @private
*/
getDash(dasharray: Array<number>, round: boolean) {
const key = this.getKey(dasharray, round);
getDash(dasharray: Array<number>, lineCap: string) {
const key = this.getKey(dasharray, lineCap);
return this.positions[key];
}

Expand All @@ -49,8 +49,8 @@ class LineAtlas {
this.image.resize({width, height});
}

getKey(dasharray: Array<number>, round: boolean): string {
return dasharray.join(',') + String(round);
getKey(dasharray: Array<number>, lineCap: string): string {
return dasharray.join(',') + lineCap;
}

getDashRanges(dasharray: Array<number>, lineAtlasWidth: number, stretch: number) {
Expand Down Expand Up @@ -111,7 +111,7 @@ class LineAtlas {
}
}

addRegularDash(ranges: Object) {
addRegularDash(ranges: Object, capLength: number) {

// Collapse any zero-length range
// Collapse neighbouring same-type parts into a single part
Expand Down Expand Up @@ -147,14 +147,15 @@ class LineAtlas {
const distRight = Math.abs(x - range.right);

const minDist = Math.min(distLeft, distRight);
const signedDistance = range.isDash ? minDist : -minDist;
const signedDistance = (range.isDash ? minDist : -minDist) + capLength;

this.image.data[index + x] = Math.max(0, Math.min(255, signedDistance + 128));
}
}

addDash(dasharray: Array<number>, round: boolean) {
const key = this.getKey(dasharray, round);
addDash(dasharray: Array<number>, lineCap: string) {
const key = this.getKey(dasharray, lineCap);
const round = lineCap === 'round';
const n = round ? 7 : 0;
const height = 2 * n + 1;

Expand Down Expand Up @@ -185,7 +186,8 @@ class LineAtlas {
if (round) {
this.addRoundDash(ranges, stretch, n);
} else {
this.addRegularDash(ranges);
const capLength = lineCap === 'square' ? 0.5 * stretch : 0;
this.addRegularDash(ranges, capLength);
}
}

Expand Down
1 change: 0 additions & 1 deletion test/ignores.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"render-tests/geojson/inline-linestring-fill": "skip - current behavior is arbitrary",
"render-tests/icon-image/icon-sdf-non-sdf-one-layer": "skip - render sdf icon and normal icon in one layer",
"render-tests/icon-text-fit/text-variable-anchor-tile-map-mode": "skip - mapbox-gl-js does not support tile-mode",
"render-tests/line-dasharray/case/square": "skip - https://github.com/mapbox/mapbox-gl-js/issues/9531",
"render-tests/map-mode/static": "https://github.com/mapbox/mapbox-gl-js/issues/5649",
"render-tests/map-mode/tile": "skip - mapbox-gl-js does not support tile-mode",
"render-tests/map-mode/tile-avoid-edges": "skip - mapbox-gl-js does not support tile-mode",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7ca8f72

Please sign in to comment.