diff --git a/src/data/array_types.js b/src/data/array_types.js index c829b057115..eaf87cd53b1 100644 --- a/src/data/array_types.js +++ b/src/data/array_types.js @@ -603,11 +603,11 @@ register('StructArrayLayout2i2ui3ul3ui2f3ub1ul1i1ub48', StructArrayLayout2i2ui3u * [0]: Int16[8] * [16]: Uint16[15] * [48]: Uint32[1] - * [52]: Float32[4] + * [52]: Float32[3] * * @private */ -class StructArrayLayout8i15ui1ul4f68 extends StructArray { +class StructArrayLayout8i15ui1ul3f64 extends StructArray { uint8: Uint8Array; int16: Int16Array; uint16: Uint16Array; @@ -622,15 +622,15 @@ class StructArrayLayout8i15ui1ul4f68 extends StructArray { this.float32 = new Float32Array(this.arrayBuffer); } - emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number) { + emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number) { const i = this.length; this.resize(i + 1); - return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); + return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } - emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number) { - const o2 = i * 34; - const o4 = i * 17; + emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number) { + const o2 = i * 32; + const o4 = i * 16; this.int16[o2 + 0] = v0; this.int16[o2 + 1] = v1; this.int16[o2 + 2] = v2; @@ -658,13 +658,12 @@ class StructArrayLayout8i15ui1ul4f68 extends StructArray { this.float32[o4 + 13] = v24; this.float32[o4 + 14] = v25; this.float32[o4 + 15] = v26; - this.float32[o4 + 16] = v27; return i; } } -StructArrayLayout8i15ui1ul4f68.prototype.bytesPerElement = 68; -register('StructArrayLayout8i15ui1ul4f68', StructArrayLayout8i15ui1ul4f68); +StructArrayLayout8i15ui1ul3f64.prototype.bytesPerElement = 64; +register('StructArrayLayout8i15ui1ul3f64', StructArrayLayout8i15ui1ul3f64); /** * Implementation of the StructArray layout: @@ -1003,7 +1002,6 @@ class SymbolInstanceStruct extends Struct { numVerticalIconVertices: number; useRuntimeCollisionCircles: number; crossTileID: number; - textBoxScale: number; textOffset0: number; textOffset1: number; collisionCircleDiameter: number; @@ -1032,20 +1030,19 @@ class SymbolInstanceStruct extends Struct { get useRuntimeCollisionCircles() { return this._structArray.uint16[this._pos2 + 22]; } get crossTileID() { return this._structArray.uint32[this._pos4 + 12]; } set crossTileID(x: number) { this._structArray.uint32[this._pos4 + 12] = x; } - get textBoxScale() { return this._structArray.float32[this._pos4 + 13]; } - get textOffset0() { return this._structArray.float32[this._pos4 + 14]; } - get textOffset1() { return this._structArray.float32[this._pos4 + 15]; } - get collisionCircleDiameter() { return this._structArray.float32[this._pos4 + 16]; } + get textOffset0() { return this._structArray.float32[this._pos4 + 13]; } + get textOffset1() { return this._structArray.float32[this._pos4 + 14]; } + get collisionCircleDiameter() { return this._structArray.float32[this._pos4 + 15]; } } -SymbolInstanceStruct.prototype.size = 68; +SymbolInstanceStruct.prototype.size = 64; export type SymbolInstance = SymbolInstanceStruct; /** * @private */ -export class SymbolInstanceArray extends StructArrayLayout8i15ui1ul4f68 { +export class SymbolInstanceArray extends StructArrayLayout8i15ui1ul3f64 { /** * Return the SymbolInstanceStruct at the given location in the array. * @param {number} index The index of the element. @@ -1157,7 +1154,7 @@ export { StructArrayLayout2ub2f12, StructArrayLayout3ui6, StructArrayLayout2i2ui3ul3ui2f3ub1ul1i1ub48, - StructArrayLayout8i15ui1ul4f68, + StructArrayLayout8i15ui1ul3f64, StructArrayLayout1f4, StructArrayLayout3i6, StructArrayLayout1ul3ui12, diff --git a/src/data/bucket/symbol_attributes.js b/src/data/bucket/symbol_attributes.js index 4a23b02d4ca..a4acc5d2003 100644 --- a/src/data/bucket/symbol_attributes.js +++ b/src/data/bucket/symbol_attributes.js @@ -109,7 +109,6 @@ export const symbolInstance = createLayout([ {type: 'Uint16', name: 'numVerticalIconVertices'}, {type: 'Uint16', name: 'useRuntimeCollisionCircles'}, {type: 'Uint32', name: 'crossTileID'}, - {type: 'Float32', name: 'textBoxScale'}, {type: 'Float32', components: 2, name: 'textOffset'}, {type: 'Float32', name: 'collisionCircleDiameter'}, ]); diff --git a/src/render/draw_symbol.js b/src/render/draw_symbol.js index 10707b4fbd2..0cedb8dc5d9 100644 --- a/src/render/draw_symbol.js +++ b/src/render/draw_symbol.js @@ -102,14 +102,14 @@ function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolSt } } -function calculateVariableRenderShift(anchor, width, height, textOffset, textBoxScale, renderTextSize): Point { +function calculateVariableRenderShift(anchor, width, height, textOffset, textScale, renderTextSize): Point { const {horizontalAlign, verticalAlign} = getAnchorAlignment(anchor); const shiftX = -(horizontalAlign - 0.5) * width; const shiftY = -(verticalAlign - 0.5) * height; const variableOffset = evaluateVariableOffset(anchor, textOffset); return new Point( - (shiftX / textBoxScale + variableOffset[0]) * renderTextSize, - (shiftY / textBoxScale + variableOffset[1]) * renderTextSize + (shiftX / textScale + variableOffset[0]) * renderTextSize, + (shiftY / textScale + variableOffset[1]) * renderTextSize ); } @@ -168,10 +168,10 @@ function updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, var renderTextSize *= bucket.tilePixelRatio / tileScale; } - const {width, height, anchor, textOffset, textBoxScale} = variableOffset; + const {width, height, anchor, textOffset, textScale} = variableOffset; const shift = calculateVariableRenderShift( - anchor, width, height, textOffset, textBoxScale, renderTextSize); + anchor, width, height, textOffset, textScale, renderTextSize); // Usual case is that we take the projected anchor and add the pixel-based shift // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent diff --git a/src/symbol/placement.js b/src/symbol/placement.js index b5a0470b5d1..b09c07f968c 100644 --- a/src/symbol/placement.js +++ b/src/symbol/placement.js @@ -130,14 +130,14 @@ class CollisionGroups { } } -function calculateVariableLayoutShift(anchor: TextAnchor, width: number, height: number, textOffset: [number, number], textBoxScale: number): Point { +function calculateVariableLayoutShift(anchor: TextAnchor, width: number, height: number, textOffset: [number, number], textScale: number): Point { const {horizontalAlign, verticalAlign} = getAnchorAlignment(anchor); const shiftX = -(horizontalAlign - 0.5) * width; const shiftY = -(verticalAlign - 0.5) * height; const offset = evaluateVariableOffset(anchor, textOffset); return new Point( - shiftX + offset[0] * textBoxScale, - shiftY + offset[1] * textBoxScale + shiftX + offset[0] * textScale, + shiftY + offset[1] * textScale ); } @@ -154,7 +154,7 @@ export type VariableOffset = { width: number, height: number, anchor: TextAnchor, - textBoxScale: number, + textScale: number, prevAnchor?: TextAnchor }; @@ -298,14 +298,13 @@ export class Placement { } attemptAnchorPlacement(anchor: TextAnchor, textBox: SingleCollisionBox, width: number, height: number, - textBoxScale: number, rotateWithMap: boolean, pitchWithMap: boolean, textPixelRatio: number, + textScale: number, rotateWithMap: boolean, pitchWithMap: boolean, textPixelRatio: number, posMatrix: mat4, collisionGroup: CollisionGroup, textAllowOverlap: boolean, symbolInstance: SymbolInstance, symbolIndex: number, bucket: SymbolBucket, orientation: number, iconBox: ?SingleCollisionBox, textSize: any, iconSize: any): ?{ shift: Point, placedGlyphBoxes: { box: Array, offscreen: boolean } } { const textOffset = [symbolInstance.textOffset0, symbolInstance.textOffset1]; - const textScale = bucket.getSymbolInstanceTextSize(textSize, symbolInstance, this.transform.zoom, symbolIndex); - const shift = calculateVariableLayoutShift(anchor, width, height, textOffset, textBoxScale); + const shift = calculateVariableLayoutShift(anchor, width, height, textOffset, textScale); const placedGlyphBoxes = this.collisionIndex.placeCollisionBox( textScale, textBox, offsetShift(shift.x, shift.y, rotateWithMap, pitchWithMap, this.transform.angle), @@ -335,7 +334,7 @@ export class Placement { width, height, anchor, - textBoxScale, + textScale, prevAnchor }; this.markUsedJustification(bucket, anchor, symbolInstance, orientation); @@ -515,9 +514,9 @@ export class Placement { } const placeBoxForVariableAnchors = (collisionTextBox, collisionIconBox, orientation) => { - const textBoxScale = symbolInstance.textBoxScale; - const width = (collisionTextBox.x2 - collisionTextBox.x1) * textBoxScale + 2.0 * collisionTextBox.padding; - const height = (collisionTextBox.y2 - collisionTextBox.y1) * textBoxScale + 2.0 * collisionTextBox.padding; + const textScale = bucket.getSymbolInstanceTextSize(partiallyEvaluatedTextSize, symbolInstance, this.transform.zoom, symbolIndex); + const width = (collisionTextBox.x2 - collisionTextBox.x1) * textScale + 2.0 * collisionTextBox.padding; + const height = (collisionTextBox.y2 - collisionTextBox.y1) * textScale + 2.0 * collisionTextBox.padding; const variableIconBox = hasIconTextFit && !iconAllowOverlap ? collisionIconBox : null; if (variableIconBox) updateBoxData(variableIconBox); @@ -528,7 +527,7 @@ export class Placement { const anchor = anchors[i % anchors.length]; const allowOverlap = (i >= anchors.length); const result = this.attemptAnchorPlacement( - anchor, collisionTextBox, width, height, textBoxScale, rotateWithMap, + anchor, collisionTextBox, width, height, textScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, allowOverlap, symbolInstance, symbolIndex, bucket, orientation, variableIconBox, partiallyEvaluatedTextSize, partiallyEvaluatedIconSize); @@ -991,7 +990,7 @@ export class Placement { variableOffset.width, variableOffset.height, variableOffset.textOffset, - variableOffset.textBoxScale); + variableOffset.textScale); if (rotateWithMap) { shift._rotate(pitchWithMap ? this.transform.angle : -this.transform.angle); } diff --git a/src/symbol/symbol_layout.js b/src/symbol/symbol_layout.js index afe8495c47d..f7d48ac18cd 100644 --- a/src/symbol/symbol_layout.js +++ b/src/symbol/symbol_layout.js @@ -373,7 +373,6 @@ function addFeature(bucket: SymbolBucket, const defaultHorizontalShaping = getDefaultHorizontalShaping(shapedTextOrientations.horizontal); const glyphSize = ONE_EM, fontScale = layoutTextSize / glyphSize, - textBoxScale = bucket.tilePixelRatio * fontScale, textMaxBoxScale = bucket.tilePixelRatio * textMaxSize / glyphSize, iconBoxScale = bucket.tilePixelRatio * layoutIconSize, symbolMinDistance = bucket.tilePixelRatio * layout.get('symbol-spacing'), @@ -408,8 +407,8 @@ function addFeature(bucket: SymbolBucket, } addSymbol(bucket, anchor, line, shapedTextOrientations, shapedIcon, imageMap, verticallyShapedIcon, bucket.layers[0], - bucket.collisionBoxArray, feature.index, feature.sourceLayerIndex, bucket.index, - textBoxScale, textPadding, textAlongLine, textOffset, + bucket.collisionBoxArray, feature.index, feature.sourceLayerIndex, + bucket.index, textPadding, textAlongLine, textOffset, iconBoxScale, iconPadding, iconAlongLine, iconOffset, feature, sizes, isSDFIcon, canonical, layoutTextSize); }; @@ -551,7 +550,6 @@ export function evaluateBoxCollisionFeature(collisionBoxArray: CollisionBoxArray sourceLayerIndex: number, bucketIndex: number, shaped: Object, - boxScale: number, padding: number, rotate: number): number { let y1 = shaped.top; @@ -628,7 +626,6 @@ function addSymbol(bucket: SymbolBucket, featureIndex: number, sourceLayerIndex: number, bucketIndex: number, - textBoxScale: number, textPadding: number, textAlongLine: boolean, textOffset: [number, number], @@ -674,9 +671,9 @@ function addSymbol(bucket: SymbolBucket, } else { const textRotation = layer.layout.get('text-rotate').evaluate(feature, {}, canonical); const verticalTextRotation = textRotation + 90.0; - verticalTextBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticalShaping, textBoxScale, textPadding, verticalTextRotation); + verticalTextBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticalShaping, textPadding, verticalTextRotation); if (verticallyShapedIcon) { - verticalIconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticallyShapedIcon, iconBoxScale, iconPadding, verticalTextRotation); + verticalIconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticallyShapedIcon, iconPadding, verticalTextRotation); } } } @@ -690,7 +687,7 @@ function addSymbol(bucket: SymbolBucket, const hasIconTextFit = layer.layout.get('icon-text-fit') !== 'none'; const iconQuads = getIconQuads(shapedIcon, iconRotate, isSDFIcon, hasIconTextFit); const verticalIconQuads = verticallyShapedIcon ? getIconQuads(verticallyShapedIcon, iconRotate, isSDFIcon, hasIconTextFit) : undefined; - iconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedIcon, iconBoxScale, iconPadding, iconRotate); + iconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedIcon, iconPadding, iconRotate); numIconVertices = iconQuads.length * 4; const sizeData = bucket.iconSizeData; @@ -761,7 +758,7 @@ function addSymbol(bucket: SymbolBucket, textCircle = evaluateCircleCollisionFeature(shaping); } else { const textRotate = layer.layout.get('text-rotate').evaluate(feature, {}, canonical); - textBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, shaping, textBoxScale, textPadding, textRotate); + textBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, anchor, featureIndex, sourceLayerIndex, bucketIndex, shaping, textPadding, textRotate); } } @@ -834,7 +831,6 @@ function addSymbol(bucket: SymbolBucket, numVerticalIconVertices, useRuntimeCollisionCircles, 0, - textBoxScale, textOffset0, textOffset1, collisionCircleDiameter); diff --git a/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/expected.png b/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/expected.png new file mode 100644 index 00000000000..ab3d953bff4 Binary files /dev/null and b/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/expected.png differ diff --git a/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/style.json b/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/style.json new file mode 100644 index 00000000000..dfa8df24b55 --- /dev/null +++ b/test/integration/render-tests/debug/collision-overscaled-fractional-zoom-variable-anchor/style.json @@ -0,0 +1,62 @@ +{ + "version": 8, + "metadata": { + "test": { + "collisionDebug": true, + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 17.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line", + "type": "symbol", + "source": "mapbox", + "source-layer": "road_label", + "layout": { + "text-field": "test test", + "text-size": [ + "interpolate", + ["linear"], + ["zoom"], + 17, + 10, + 18, + 30 + ], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ], + "text-variable-anchor": ["left", "right"], + "symbol-placement": "point", + "symbol-spacing": 20 + }, + "paint": { + "icon-opacity": 1 + } + } + ] +} \ No newline at end of file