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 7 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
76 changes: 48 additions & 28 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ import { ProgramConfigurationSet } from '../program_configuration';
import { TriangleIndexArray, LineIndexArray } from '../index_array_type';
import transformText from '../../symbol/transform_text';
import mergeLines from '../../symbol/mergelines';
import {allowsVerticalWritingMode} from '../../util/script_detection';
import { allowsVerticalWritingMode } from '../../util/script_detection';
import { WritingMode } from '../../symbol/shaping';
import loadGeometry from '../load_geometry';
import mvt from '@mapbox/vector-tile';
const vectorTileFeatureTypes = mvt.VectorTileFeature.types;
import {verticalizedCharacterMap} from '../../util/verticalize_punctuation';
import { verticalizedCharacterMap } from '../../util/verticalize_punctuation';
import Anchor from '../../symbol/anchor';
import { getSizeData } from '../../symbol/symbol_size';
import { register } from '../../util/web_worker_transfer';
Expand All @@ -43,16 +43,16 @@ import type {
IndexedFeature,
PopulateParameters
} from '../bucket';
import type {CollisionBoxArray, CollisionBox, SymbolInstance} from '../array_types';
import type { CollisionBoxArray, CollisionBox, SymbolInstance } from '../array_types';
import type { StructArray, StructArrayMember } from '../../util/struct_array';
import SymbolStyleLayer from '../../style/style_layer/symbol_style_layer';
import type Context from '../../gl/context';
import type IndexBuffer from '../../gl/index_buffer';
import type VertexBuffer from '../../gl/vertex_buffer';
import type {SymbolQuad} from '../../symbol/quads';
import type {SizeData} from '../../symbol/symbol_size';
import type {FeatureStates} from '../../source/source_state';
import type {ImagePosition} from '../../render/image_atlas';
import type { SymbolQuad } from '../../symbol/quads';
import type { SizeData } from '../../symbol/symbol_size';
import type { FeatureStates } from '../../source/source_state';
import type { ImagePosition } from '../../render/image_atlas';

export type SingleCollisionBox = {
x1: number;
Expand Down Expand Up @@ -82,7 +82,7 @@ export type SymbolFeature = {|
geometry: Array<Array<Point>>,
properties: Object,
type: 'Point' | 'LineString' | 'Polygon',
id?: any
id ?: any
|};

// Opacity arrays are frequently updated but don't contain a lot of information, so we pack them
Expand Down 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 @@ -280,7 +282,7 @@ class SymbolBucket implements Bucket {
collisionArrays: Array<CollisionArrays>;
pixelRatio: number;
tilePixelRatio: number;
compareText: {[string]: Array<Point>};
compareText: { [string]: Array<Point> };
fadeStartTime: number;
sortFeaturesByKey: boolean;
sortFeaturesByY: boolean;
Expand All @@ -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
20 changes: 12 additions & 8 deletions src/render/draw_collision_debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type Painter from './painter';
import type SourceCache from '../source/source_cache';
import type StyleLayer from '../style/style_layer';
import type {OverscaledTileID} from '../source/tile_id';
import type { OverscaledTileID } from '../source/tile_id';
import type SymbolBucket from '../data/bucket/symbol_bucket';
import DepthMode from '../gl/depth_mode';
import StencilMode from '../gl/stencil_mode';
Expand All @@ -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.
Loading