From 022fbee1f70b6f46e9cad73346cd6fddc3385784 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 8 Aug 2017 13:40:20 -0700 Subject: [PATCH 1/3] Fix issue #5112 (line labels can render incorrectly on overzoomed tiles) Adds special handling for (rare) case that line geometry projects to a point behind the plane of the camera. --- src/symbol/projection.js | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/symbol/projection.js b/src/symbol/projection.js index e8755215735..e27bf65e89f 100644 --- a/src/symbol/projection.js +++ b/src/symbol/projection.js @@ -107,10 +107,14 @@ function getGlCoordMatrix(posMatrix: mat4, return m; } -function project(point: Point, matrix: mat4): Point { +function project(point: Point, matrix: mat4) { const pos = [point.x, point.y, 0, 1]; vec4.transformMat4(pos, pos, matrix); - return new Point(pos[0] / pos[3], pos[1] / pos[3]); + const w = pos[3]; + return { + point: new Point(pos[0] / w, pos[1] / w), + distanceToCamera: w + }; } function isVisible(anchorPos: [number, number, number, number], @@ -175,16 +179,17 @@ function updateLineLabels(bucket: SymbolBucket, fontSize * perspectiveRatio : fontSize / perspectiveRatio; - const anchorPoint = project(new Point(symbol.anchorX, symbol.anchorY), labelPlaneMatrix); + const tileAnchorPoint = new Point(symbol.anchorX, symbol.anchorY); + const anchorPoint = project(tileAnchorPoint, labelPlaneMatrix).point; const projectionCache = {}; const placeUnflipped = placeGlyphsAlongLine(symbol, pitchScaledFontSize, false /*unflipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, - bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, anchorPoint, projectionCache); + bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, anchorPoint, tileAnchorPoint, projectionCache); if (placeUnflipped.notEnoughRoom || (placeUnflipped.needsFlipping && placeGlyphsAlongLine(symbol, pitchScaledFontSize, true /*flipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, - bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, anchorPoint, projectionCache).notEnoughRoom)) { + bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, anchorPoint, tileAnchorPoint, projectionCache).notEnoughRoom)) { hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray); } } @@ -207,6 +212,7 @@ function placeGlyphsAlongLine(symbol, lineVertexArray: any, dynamicLayoutVertexArray, anchorPoint: Point, + tileAnchorPoint: Point, projectionCache: {[number]: Point}) { const fontScale = fontSize / 24; const lineOffsetX = symbol.lineOffsetX * fontSize; @@ -223,18 +229,18 @@ function placeGlyphsAlongLine(symbol, const lineStartIndex = symbol.lineStartIndex; const lineEndIndex = symbol.lineStartIndex + symbol.lineLength; - const firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, + const firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache); if (!firstPlacedGlyph) return { notEnoughRoom: true }; - const lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, + const lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache); if (!lastPlacedGlyph) return { notEnoughRoom: true }; - const firstPoint = project(firstPlacedGlyph.point, glCoordMatrix); - const lastPoint = project(lastPlacedGlyph.point, glCoordMatrix); + const firstPoint = project(firstPlacedGlyph.point, glCoordMatrix).point; + const lastPoint = project(lastPlacedGlyph.point, glCoordMatrix).point; if (keepUpright && !flip && (symbol.vertical ? firstPoint.y < lastPoint.y : firstPoint.x > lastPoint.x)) { @@ -246,7 +252,7 @@ function placeGlyphsAlongLine(symbol, const glyph = glyphOffsetArray.get(glyphIndex); // Since first and last glyph fit on the line, we're sure that the rest of the glyphs can be placed - placedGlyphs.push(placeGlyphAlongLine(fontScale * glyph.offsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, + placedGlyphs.push(placeGlyphAlongLine(fontScale * glyph.offsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache)); } placedGlyphs.push(lastPlacedGlyph); @@ -254,14 +260,22 @@ function placeGlyphsAlongLine(symbol, // Only a single glyph to place // So, determine whether to flip based on projected angle of the line segment it's on if (keepUpright && !flip) { - const a = project(lineVertexArray.get(symbol.lineStartIndex + symbol.segment), posMatrix); - const b = project(lineVertexArray.get(symbol.lineStartIndex + symbol.segment + 1), posMatrix); + const a = project(tileAnchorPoint, posMatrix).point; + const tileSegmentEnd = lineVertexArray.get(symbol.lineStartIndex + symbol.segment + 1); + const projectedVertex = project(tileSegmentEnd, posMatrix); + // We know the anchor will be in the viewport, but the end of the line segment may be + // past the plane of the camera, in which case we can use a point at any arbitrary (closer) + // point on the segment. + const b = (projectedVertex.distanceToCamera > 0) ? + projectedVertex.point : + projectTruncatedLineSegment(tileAnchorPoint, new Point(tileSegmentEnd.x, tileSegmentEnd.y), a, 1, posMatrix); + if (symbol.vertical ? b.y > a.y : b.x < a.x) { return { needsFlipping: true }; } } const glyph = glyphOffsetArray.get(symbol.glyphStartIndex); - const singleGlyph = placeGlyphAlongLine(fontScale * glyph.offsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, symbol.segment, + const singleGlyph = placeGlyphAlongLine(fontScale * glyph.offsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, symbol.lineStartIndex, symbol.lineStartIndex + symbol.lineLength, lineVertexArray, labelPlaneMatrix, projectionCache); if (!singleGlyph) return { notEnoughRoom: true }; @@ -276,11 +290,19 @@ function placeGlyphsAlongLine(symbol, return {}; } +function projectTruncatedLineSegment(previousTilePoint: Point, currentTilePoint: Point, previousProjectedPoint: Point, minimumLength: number, projectionMatrix: mat4) { + const projectedUnitVertex = project(previousTilePoint.add(previousTilePoint.sub(currentTilePoint)._unit()), projectionMatrix).point; + const projectedUnitSegment = previousProjectedPoint.sub(projectedUnitVertex); + + return previousProjectedPoint.add(projectedUnitSegment._mult(minimumLength / projectedUnitSegment.mag())); +} + function placeGlyphAlongLine(offsetX: number, lineOffsetX: number, lineOffsetY: number, flip: boolean, anchorPoint: Point, + tileAnchorPoint: Point, anchorSegment: number, lineStartIndex: number, lineEndIndex: number, @@ -325,7 +347,19 @@ function placeGlyphAlongLine(offsetX: number, current = projectionCache[currentIndex]; if (current === undefined) { - current = projectionCache[currentIndex] = project(lineVertexArray.get(currentIndex), labelPlaneMatrix); + const projection = project(lineVertexArray.get(currentIndex), labelPlaneMatrix); + if (projection.distanceToCamera > 0) { + current = projectionCache[currentIndex] = projection.point; + } else { + // The vertex is behind the plane of the camera, so we can't project it + // Instead, we'll create a vertex along the line that's far enough to include the glyph + const previousTilePoint = distanceToPrev === 0 ? + tileAnchorPoint : + new Point(lineVertexArray.get(currentIndex - dir).x, lineVertexArray.get(currentIndex - dir).y); + const currentTilePoint = new Point(lineVertexArray.get(currentIndex).x, lineVertexArray.get(currentIndex).y); + // Don't cache because the new vertex might not be far enough out for future glyphs on the same segment + current = projectTruncatedLineSegment(previousTilePoint, currentTilePoint, prev, absOffsetX - distanceToPrev + 1, labelPlaneMatrix); + } } distanceToPrev += currentSegmentDistance; From 5aa127c5063cd73a807eecfefa01a11f3cd4f633 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 8 Aug 2017 15:51:22 -0700 Subject: [PATCH 2/3] Add tests for issue #5112. Without the fix: - The "viewport-overzoomed" test would show "Figueroa St." jumbled in the lower half of the screen - The "viewport-overzoomed-single-glyph" test would show the letter "C" upside down --- .../expected.png | Bin 0 -> 4160 bytes .../style.json | 56 ++++++++++++++++++ .../viewport-overzoomed/expected.png | Bin 0 -> 20829 bytes .../viewport-overzoomed/style.json | 56 ++++++++++++++++++ .../16-11235-26208.mvt | Bin 0 -> 7134 bytes 5 files changed, 112 insertions(+) create mode 100644 test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/expected.png create mode 100644 test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/style.json create mode 100644 test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/expected.png create mode 100644 test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/style.json create mode 100644 test/integration/tiles/mapbox.mapbox-streets-v7/16-11235-26208.mvt diff --git a/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/expected.png b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e0968e8aff9ae20d4143dcbfc5cddc9c4a6a14cf GIT binary patch literal 4160 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 literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/style.json b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/style.json new file mode 100644 index 00000000000..e12c4b361ac --- /dev/null +++ b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed-single-glyph/style.json @@ -0,0 +1,56 @@ +{ + "version": 8, + "center": [ + -118.28162, + 33.86852 + ], + "zoom": 21, + "pitch": 60, + "bearing": 161.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 16, + "tiles": [ + "local://tiles/mapbox.mapbox-streets-v7/16-11235-26208.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "road-label-large", + "type": "symbol", + "source": "mapbox", + "source-layer": "road_label", + "layout": { + "text-size": { "base": 1, "stops": [ [ 9, 10 ], [ 20, 16 ] ] }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "C", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + } + ] +} diff --git a/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/expected.png b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..97ad6702e4416af7b755aee74968ae85bc20cd7e GIT binary patch literal 20829 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 literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/style.json b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/style.json new file mode 100644 index 00000000000..2f68454b9b5 --- /dev/null +++ b/test/integration/render-tests/text-pitch-alignment/viewport-overzoomed/style.json @@ -0,0 +1,56 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 1024 + } + }, + "center": [ + 50, + 0 + ], + "zoom": 18, + "pitch": 60, + "sources": { + "geojson": { + "type": "geojson", + "maxzoom": 16, + "data": { + "type": "LineString", + "coordinates": [ + [ 50, -90 ], + [ 50, 90 ] + ] + } + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "geojson", + "layout": { + "symbol-placement": "line", + "symbol-spacing": 10, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "Figueroa St.", + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-opacity": 1 + } + } + ] +} diff --git a/test/integration/tiles/mapbox.mapbox-streets-v7/16-11235-26208.mvt b/test/integration/tiles/mapbox.mapbox-streets-v7/16-11235-26208.mvt new file mode 100644 index 0000000000000000000000000000000000000000..2d27c088316aca3d2e99fd422cca1e5a14af9917 GIT binary patch literal 7134 zcma)B3w#viwLj@L>k{YaC7!Cz>klZf$>TEmZmeS~Lc7AwpFF!1yS_f*lBK!R?C5 z-($nqHqhF0v|okBd>8BcLQ2iDf{BTV6PDkL7y6C5BCU9Gk#5wL_)5)DGj2Xh@VT^j zv^G$CvSJb2${r&rTiEw~I(~|mF$hcse4I@I$R8$?ye7r;FFhR2>iGAf?Eyo)Piz?f z6X9eTGfQMgnk3?MrsGb%)21@DbWW`8y_!e+c*CmCFi7Ap1T(NGN$` zsX|Lt^3Y@=EZ26K`^GMU!aERPBhF_~ssWtWz@Xxr3>twD45o zQmOs8Xv>t#*>U-KN${WYaR9a9{33vJ;*$pv@xQQz6p=CrbwcPx{CHYdqJ5$q9T^ul zifuxMD}4Y<3jv=dx8>4S5p9w7T9Fxtsn?O|V_#)3`ah6)cFdt9L~7U~>WSK6bC+)| zTZg}+6x)RD4DZF=jImvqmQ{QU2LxwxF9*0N4lpOE${B3FA?sBWhf?j<$kvf@;t&Ri zkUMU~4VsGoPT+Ehvw?AJ%m=;}b}Ku;5bnZPB^fSy77n9{d>#Z^}&lI>plW~=WZ`RLe92wyJ&D4YuLZzqH#?q?MM z{(BTZ-_2%`k10{LGQiX*x&~D>!_zAZeu~8?$;{Jk)b^fd!0I1K3|0kI?KFiKt=V#W ztnA$paj}u_rVx4&=K&tXt&#-FFlvfIWvCpzlXw3_gYA?4LgnabDX8ihu7ROA%i7PL z`CPRj_VZU28J{M7b7@)#+jQ-=nV)cql}R$NQ%J!$_I3s!x)@ZCq3V3S02sZE5<@K} zcT)EK4Ns^F)DGvB&5ZYF{JCTR*%4L*?1B*hHQu!tSWO{-Ma8}*3UG)$rTMj&NwZuu z69`S2cDU?Ub#e9zJA^1+VLy>o{xd;&4sAizmr>A5q%Y0(Y}Ky1xVTM9OEP|j0w@)^ zhjBP{Ju#1ITW0QxEn<%_LM94;9l(1u9X8;30IgIxucrXZm62^9A4QHeECOpPus2yP z5VFT)fHgJ(Kgd!H9ym)_HgR6pUTYjLPVmPh!2e?hD0znKK+g1qXArV#ZE%8JyjFGv zm5kXlKVA;dcoi!~xhcvRK805!$U)VgF+<*vpR+acSn2V~MQop-NF4h|GC;*2 z=xaCIMxOi(x6*fT__~oK)~9U>nBkkTv6T8t;B@#<*b*{-_(CG7*Y-AUr11mfID*

46oo2#Pf*HIPG}R`~2IZntk%@ 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 literal 0 HcmV?d00001 From fd0fe6aea07176b1214ed2071bd78281ab97e3fc Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 22 Aug 2017 09:32:08 -0700 Subject: [PATCH 3/3] Line projection comment/name edits based on review. --- src/symbol/projection.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/symbol/projection.js b/src/symbol/projection.js index e27bf65e89f..0d87e7718c5 100644 --- a/src/symbol/projection.js +++ b/src/symbol/projection.js @@ -113,7 +113,7 @@ function project(point: Point, matrix: mat4) { const w = pos[3]; return { point: new Point(pos[0] / w, pos[1] / w), - distanceToCamera: w + signedDistanceFromCamera: w }; } @@ -264,9 +264,9 @@ function placeGlyphsAlongLine(symbol, const tileSegmentEnd = lineVertexArray.get(symbol.lineStartIndex + symbol.segment + 1); const projectedVertex = project(tileSegmentEnd, posMatrix); // We know the anchor will be in the viewport, but the end of the line segment may be - // past the plane of the camera, in which case we can use a point at any arbitrary (closer) + // behind the plane of the camera, in which case we can use a point at any arbitrary (closer) // point on the segment. - const b = (projectedVertex.distanceToCamera > 0) ? + const b = (projectedVertex.signedDistanceFromCamera > 0) ? projectedVertex.point : projectTruncatedLineSegment(tileAnchorPoint, new Point(tileSegmentEnd.x, tileSegmentEnd.y), a, 1, posMatrix); @@ -291,6 +291,10 @@ function placeGlyphsAlongLine(symbol, } function projectTruncatedLineSegment(previousTilePoint: Point, currentTilePoint: Point, previousProjectedPoint: Point, minimumLength: number, projectionMatrix: mat4) { + // We are assuming "previousTilePoint" won't project to a point within one unit of the camera plane + // If it did, that would mean our label extended all the way out from within the viewport to a (very distant) + // point near the plane of the camera. We wouldn't be able to render the label anyway once it crossed the + // plane of the camera. const projectedUnitVertex = project(previousTilePoint.add(previousTilePoint.sub(currentTilePoint)._unit()), projectionMatrix).point; const projectedUnitSegment = previousProjectedPoint.sub(projectedUnitVertex); @@ -348,7 +352,7 @@ function placeGlyphAlongLine(offsetX: number, current = projectionCache[currentIndex]; if (current === undefined) { const projection = project(lineVertexArray.get(currentIndex), labelPlaneMatrix); - if (projection.distanceToCamera > 0) { + if (projection.signedDistanceFromCamera > 0) { current = projectionCache[currentIndex] = projection.point; } else { // The vertex is behind the plane of the camera, so we can't project it