Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix icon/text collisionBox translation #8659

Merged
merged 8 commits into from
Aug 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 🐞 Bug fixes

* Fix bug in `NavigationControl` compass button that prevented it from rotating with the map ([#8605](https://github.com/mapbox/mapbox-gl-js/pull/8605))
* Fix rendering of `collisionBox` when `text-translate` or `icon-translate` is enabled ([#8659](https://github.com/mapbox/mapbox-gl-js/pull/8659))

## 1.2.0

Expand Down
58 changes: 39 additions & 19 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,10 @@ register('CollisionBuffers', CollisionBuffers);
* `this.collisionBoxArray`: collision data for use by foreground
* `this.text`: SymbolBuffers for text symbols
* `this.icons`: SymbolBuffers for icons
* `this.collisionBox`: Debug SymbolBuffers for collision boxes
* `this.collisionCircle`: Debug SymbolBuffers for collision circles
* `this.iconCollisionBox`: Debug SymbolBuffers for icon collision boxes
* `this.textCollisionBox`: Debug SymbolBuffers for text collision boxes
* `this.iconCollisionCircle`: Debug SymbolBuffers for icon collision circles
* `this.textCollisionCircle`: Debug SymbolBuffers for text collision circles
* The results are sent to the foreground for rendering
*
* 4. performSymbolPlacement(bucket, collisionIndex) is run on the foreground,
Expand Down Expand Up @@ -289,8 +291,10 @@ class SymbolBucket implements Bucket {

text: SymbolBuffers;
icon: SymbolBuffers;
collisionBox: CollisionBuffers;
collisionCircle: CollisionBuffers;
textCollisionBox: CollisionBuffers;
iconCollisionBox: CollisionBuffers;
textCollisionCircle: CollisionBuffers;
iconCollisionCircle: CollisionBuffers;
uploaded: boolean;
sourceLayerIndex: number;
sourceID: string;
Expand Down Expand Up @@ -341,8 +345,10 @@ class SymbolBucket implements Bucket {
this.text = new SymbolBuffers(new ProgramConfigurationSet(symbolLayoutAttributes.members, this.layers, this.zoom, property => /^text/.test(property)));
this.icon = new SymbolBuffers(new ProgramConfigurationSet(symbolLayoutAttributes.members, this.layers, this.zoom, property => /^icon/.test(property)));

this.collisionBox = new CollisionBuffers(CollisionBoxLayoutArray, collisionBoxLayout.members, LineIndexArray);
this.collisionCircle = new CollisionBuffers(CollisionCircleLayoutArray, collisionCircleLayout.members, TriangleIndexArray);
this.textCollisionBox = new CollisionBuffers(CollisionBoxLayoutArray, collisionBoxLayout.members, LineIndexArray);
this.iconCollisionBox = new CollisionBuffers(CollisionBoxLayoutArray, collisionBoxLayout.members, LineIndexArray);
this.textCollisionCircle = new CollisionBuffers(CollisionCircleLayoutArray, collisionCircleLayout.members, TriangleIndexArray);
this.iconCollisionCircle = new CollisionBuffers(CollisionCircleLayoutArray, collisionCircleLayout.members, TriangleIndexArray);

this.glyphOffsetArray = new GlyphOffsetArray();
this.lineVertexArray = new SymbolLineVertexArray();
Expand Down Expand Up @@ -476,8 +482,10 @@ class SymbolBucket implements Bucket {

upload(context: Context) {
if (!this.uploaded) {
this.collisionBox.upload(context);
this.collisionCircle.upload(context);
this.textCollisionBox.upload(context);
this.iconCollisionBox.upload(context);
this.textCollisionCircle.upload(context);
this.iconCollisionCircle.upload(context);
}
this.text.upload(context, this.sortFeaturesByY, !this.uploaded, this.text.programConfigurations.needsUpload);
this.icon.upload(context, this.sortFeaturesByY, !this.uploaded, this.icon.programConfigurations.needsUpload);
Expand All @@ -487,8 +495,10 @@ class SymbolBucket implements Bucket {
destroy() {
this.text.destroy();
this.icon.destroy();
this.collisionBox.destroy();
this.collisionCircle.destroy();
this.textCollisionBox.destroy();
this.iconCollisionBox.destroy();
this.textCollisionCircle.destroy();
this.iconCollisionCircle.destroy();
}

addToLineVertexArray(anchor: Anchor, line: any) {
Expand Down Expand Up @@ -659,7 +669,7 @@ class SymbolBucket implements Bucket {
}
}

addDebugCollisionBoxes(startIndex: number, endIndex: number, symbolInstance: SymbolInstance) {
addDebugCollisionBoxes(startIndex: number, endIndex: number, symbolInstance: SymbolInstance, isText: boolean) {
for (let b = startIndex; b < endIndex; b++) {
const box: CollisionBox = (this.collisionBoxArray.get(b): any);
const x1 = box.x1;
Expand All @@ -670,16 +680,18 @@ class SymbolBucket implements Bucket {
// If the radius > 0, this collision box is actually a circle
// The data we add to the buffers is exactly the same, but we'll render with a different shader.
const isCircle = box.radius > 0;
this.addCollisionDebugVertices(x1, y1, x2, y2, isCircle ? this.collisionCircle : this.collisionBox, box.anchorPoint, symbolInstance, isCircle);
this.addCollisionDebugVertices(x1, y1, x2, y2, isCircle ?
(isText ? this.textCollisionCircle : this.iconCollisionCircle) : (isText ? this.textCollisionBox : this.iconCollisionBox),
box.anchorPoint, symbolInstance, isCircle);
}
}

generateCollisionDebugBuffers() {
for (let i = 0; i < this.symbolInstances.length; i++) {
const symbolInstance = this.symbolInstances.get(i);
this.addDebugCollisionBoxes(symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance);
this.addDebugCollisionBoxes(symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance);
this.addDebugCollisionBoxes(symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance);
this.addDebugCollisionBoxes(symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance, true);
this.addDebugCollisionBoxes(symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance, true);
this.addDebugCollisionBoxes(symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance, false);
}
}

Expand Down Expand Up @@ -746,12 +758,20 @@ class SymbolBucket implements Bucket {
return this.icon.segments.get().length > 0;
}

hasCollisionBoxData() {
return this.collisionBox.segments.get().length > 0;
hasTextCollisionBoxData() {
return this.textCollisionBox.segments.get().length > 0;
}

hasCollisionCircleData() {
return this.collisionCircle.segments.get().length > 0;
hasIconCollisionBoxData() {
return this.iconCollisionBox.segments.get().length > 0;
}

hasTextCollisionCircleData() {
return this.textCollisionCircle.segments.get().length > 0;
}

hasIconCollisionCircleData() {
return this.iconCollisionCircle.segments.get().length > 0;
}

addIndicesForPlacedTextSymbol(placedTextSymbolIndex: number) {
Expand Down
18 changes: 11 additions & 7 deletions src/render/draw_collision_debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { collisionUniformValues } from './program/collision_program';

export default drawCollisionDebug;

function drawCollisionDebugGeometry(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>, drawCircles: boolean) {
function drawCollisionDebugGeometry(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>, drawCircles: boolean,
translate: [number, number], translateAnchor: 'map' | 'viewport', isText: boolean) {
const context = painter.context;
const gl = context.gl;
const program = drawCircles ? painter.useProgram('collisionCircle') : painter.useProgram('collisionBox');
Expand All @@ -22,15 +23,18 @@ function drawCollisionDebugGeometry(painter: Painter, sourceCache: SourceCache,
const tile = sourceCache.getTile(coord);
const bucket: ?SymbolBucket = (tile.getBucket(layer): any);
if (!bucket) continue;
const buffers = drawCircles ? bucket.collisionCircle : bucket.collisionBox;
const buffers = drawCircles ? (isText ? bucket.textCollisionCircle : bucket.iconCollisionCircle) : (isText ? bucket.textCollisionBox : bucket.iconCollisionBox);
if (!buffers) continue;

let posMatrix = coord.posMatrix;
if (translate[0] !== 0 || translate[1] !== 0) {
posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor);
}
program.draw(context, drawCircles ? gl.TRIANGLES : gl.LINES,
DepthMode.disabled, StencilMode.disabled,
painter.colorModeForRenderPass(),
CullFaceMode.disabled,
collisionUniformValues(
coord.posMatrix,
posMatrix,
painter.transform,
tile),
layer.id, buffers.layoutVertexBuffer, buffers.indexBuffer,
Expand All @@ -39,7 +43,7 @@ function drawCollisionDebugGeometry(painter: Painter, sourceCache: SourceCache,
}
}

function drawCollisionDebug(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>) {
drawCollisionDebugGeometry(painter, sourceCache, layer, coords, false);
drawCollisionDebugGeometry(painter, sourceCache, layer, coords, true);
function drawCollisionDebug(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>, translate: [number, number], translateAnchor: 'map' | 'viewport', isText: boolean) {
drawCollisionDebugGeometry(painter, sourceCache, layer, coords, false, translate, translateAnchor, isText);
drawCollisionDebugGeometry(painter, sourceCache, layer, coords, true, translate, translateAnchor, isText);
}
5 changes: 4 additions & 1 deletion src/render/draw_symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolSt
}

if (sourceCache.map.showCollisionBoxes) {
drawCollisionDebug(painter, sourceCache, layer, coords);
drawCollisionDebug(painter, sourceCache, layer, coords, layer.paint.get('text-translate'),
layer.paint.get('text-translate-anchor'), true);
drawCollisionDebug(painter, sourceCache, layer, coords, layer.paint.get('icon-translate'),
layer.paint.get('icon-translate-anchor'), false);
}
}

Expand Down
34 changes: 22 additions & 12 deletions src/symbol/placement.js
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,10 @@ export class Placement {
updateBucketOpacities(bucket: SymbolBucket, seenCrossTileIDs: { [string | number]: boolean }, collisionBoxArray: ?CollisionBoxArray) {
if (bucket.hasTextData()) bucket.text.opacityVertexArray.clear();
if (bucket.hasIconData()) bucket.icon.opacityVertexArray.clear();
if (bucket.hasCollisionBoxData()) bucket.collisionBox.collisionVertexArray.clear();
if (bucket.hasCollisionCircleData()) bucket.collisionCircle.collisionVertexArray.clear();
if (bucket.hasIconCollisionBoxData()) bucket.iconCollisionBox.collisionVertexArray.clear();
if (bucket.hasTextCollisionBoxData()) bucket.textCollisionBox.collisionVertexArray.clear();
if (bucket.hasIconCollisionCircleData()) bucket.iconCollisionCircle.collisionVertexArray.clear();
if (bucket.hasTextCollisionCircleData()) bucket.textCollisionCircle.collisionVertexArray.clear();

const layout = bucket.layers[0].layout;
const duplicateOpacityState = new JointOpacityState(null, 0, false, false, true);
Expand All @@ -715,7 +717,8 @@ export class Placement {
iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || layout.get('text-optional')),
true);

if (!bucket.collisionArrays && collisionBoxArray && (bucket.hasCollisionBoxData() || bucket.hasCollisionCircleData())) {
if (!bucket.collisionArrays && collisionBoxArray && ((bucket.hasIconCollisionBoxData() || bucket.hasIconCollisionCircleData() ||
bucket.hasTextCollisionBoxData() || bucket.hasTextCollisionCircleData()))) {
bucket.deserializeCollisionBoxes(collisionBoxArray);
}

Expand Down Expand Up @@ -794,7 +797,8 @@ export class Placement {
(opacityState.icon.isHidden(): any);
}

if (bucket.hasCollisionBoxData() || bucket.hasCollisionCircleData()) {
if (bucket.hasIconCollisionBoxData() || bucket.hasIconCollisionCircleData() ||
bucket.hasTextCollisionBoxData() || bucket.hasTextCollisionCircleData()) {
const collisionArrays = bucket.collisionArrays[s];
if (collisionArrays) {
if (collisionArrays.textBox) {
Expand Down Expand Up @@ -823,18 +827,18 @@ export class Placement {
}
}

updateCollisionVertices(bucket.collisionBox.collisionVertexArray, opacityState.text.placed, !used, shift.x, shift.y);
updateCollisionVertices(bucket.textCollisionBox.collisionVertexArray, opacityState.text.placed, !used, shift.x, shift.y);
}

if (collisionArrays.iconBox) {
updateCollisionVertices(bucket.collisionBox.collisionVertexArray, opacityState.icon.placed, false);
updateCollisionVertices(bucket.iconCollisionBox.collisionVertexArray, opacityState.icon.placed, false);
}

const textCircles = collisionArrays.textCircles;
if (textCircles && bucket.hasCollisionCircleData()) {
if (textCircles && bucket.hasTextCollisionCircleData()) {
for (let k = 0; k < textCircles.length; k += 5) {
const notUsed = isDuplicate || textCircles[k + 4] === 0;
updateCollisionVertices(bucket.collisionCircle.collisionVertexArray, opacityState.text.placed, notUsed);
updateCollisionVertices(bucket.textCollisionCircle.collisionVertexArray, opacityState.text.placed, notUsed);
}
}
}
Expand All @@ -852,11 +856,17 @@ export class Placement {
if (bucket.hasIconData() && bucket.icon.opacityVertexBuffer) {
bucket.icon.opacityVertexBuffer.updateData(bucket.icon.opacityVertexArray);
}
if (bucket.hasCollisionBoxData() && bucket.collisionBox.collisionVertexBuffer) {
bucket.collisionBox.collisionVertexBuffer.updateData(bucket.collisionBox.collisionVertexArray);
if (bucket.hasIconCollisionBoxData() && bucket.iconCollisionBox.collisionVertexBuffer) {
bucket.iconCollisionBox.collisionVertexBuffer.updateData(bucket.iconCollisionBox.collisionVertexArray);
}
if (bucket.hasCollisionCircleData() && bucket.collisionCircle.collisionVertexBuffer) {
bucket.collisionCircle.collisionVertexBuffer.updateData(bucket.collisionCircle.collisionVertexArray);
if (bucket.hasTextCollisionBoxData() && bucket.textCollisionBox.collisionVertexBuffer) {
bucket.textCollisionBox.collisionVertexBuffer.updateData(bucket.textCollisionBox.collisionVertexArray);
}
if (bucket.hasIconCollisionCircleData() && bucket.iconCollisionCircle.collisionVertexBuffer) {
bucket.iconCollisionCircle.collisionVertexBuffer.updateData(bucket.iconCollisionCircle.collisionVertexArray);
}
if (bucket.hasTextCollisionCircleData() && bucket.textCollisionCircle.collisionVertexBuffer) {
bucket.textCollisionCircle.collisionVertexBuffer.updateData(bucket.textCollisionCircle.collisionVertexArray);
}

assert(bucket.text.opacityVertexArray.length === bucket.text.layoutVertexArray.length / 4);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"version": 8,
"metadata": {
"test": {
"collisionDebug": true,
"height": 1000,
"width" : 1000
}
},
"center": [
0,
0
],
"zoom": 12,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "LineString",
"coordinates": [
[
0,
0
],
[
0.5,
0.5
]
]
}
}
},
"glyphs": "local://glyphs/{fontstack}/{range}.pbf",
"sprite": "local://sprites/sprite",
"layers": [
{
"id": "background",
"type": "background",
"paint": {
"background-color": "white"
}
},
{
"id": "translate",
"type": "symbol",
"source": "geojson",
"layout": {
"icon-image": "fav-airport-18",
"text-field": "abc",
"text-font": [
"Open Sans Semibold",
"Arial Unicode MS Bold"
],
"symbol-placement": "line",
"symbol-spacing": 50
},
"paint": {
"icon-opacity": 1,
"text-color": "hsl(0, 82%, 48%)",
"icon-translate": [
"interpolate",
["exponential", 2.0],
["zoom"],
9,
["literal", [0, 0]],
14,
["literal", [-130, -130]]
],
"text-translate": [
"interpolate",
["exponential", 1.2],
["zoom"],
9,
["literal", [0, 0]],
13,
["literal", [0, -130]]
]
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading