Skip to content

Commit

Permalink
Roll back "flat array" optimization for collision boxes -- it only ma…
Browse files Browse the repository at this point in the history
…kes a measurable difference for circles (there are many of them per symbol instance, instead of just one).

Use plain x/y arguments in CollisionIndex projection logic instead of wrapping/unwrapping the x/y values in a Point object.
  • Loading branch information
ChrisLoer committed Sep 1, 2017
1 parent 2ade351 commit 6b0cd2e
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 35 deletions.
32 changes: 15 additions & 17 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,19 @@ type SymbolBucketParameters = BucketParameters & {
lineVertexArray: StructArray,
}

export type SingleCollisionBox = {
x1: number;
y1: number;
x2: number;
y2: number;
anchorPointX: number;
anchorPointY: number;
};

export type CollisionArrays = {
textBox?: Array<number>;
iconBox?: Array<number>;
textCircles?: Array<any>;
textBox?: SingleCollisionBox;
iconBox?: SingleCollisionBox;
textCircles?: Array<number | boolean>;
};

export type SymbolInstance = {
Expand Down Expand Up @@ -714,13 +723,8 @@ class SymbolBucket implements Bucket {
for (let k = textStartIndex; k < textEndIndex; k++) {
const box: CollisionBox = (collisionBoxArray.get(k): any);
if (box.radius === 0) {
collisionArrays.textBox = [];
collisionArrays.textBox.push(box.x1);
collisionArrays.textBox.push(box.y1);
collisionArrays.textBox.push(box.x2);
collisionArrays.textBox.push(box.y2);
collisionArrays.textBox.push(box.anchorPointX);
collisionArrays.textBox.push(box.anchorPointY);
collisionArrays.textBox = { x1: box.x1, y1: box.y1, x2: box.x2, y2: box.y2, anchorPointX: box.anchorPointX, anchorPointY: box.anchorPointY };

break; // Only one box allowed per instance
} else {
if (!collisionArrays.textCircles) {
Expand All @@ -737,13 +741,7 @@ class SymbolBucket implements Bucket {
// An icon can only have one box now, so this indexing is a bit vestigial...
const box: CollisionBox = (collisionBoxArray.get(k): any);
if (box.radius === 0) {
collisionArrays.iconBox = [];
collisionArrays.iconBox.push(box.x1);
collisionArrays.iconBox.push(box.y1);
collisionArrays.iconBox.push(box.x2);
collisionArrays.iconBox.push(box.y2);
collisionArrays.iconBox.push(box.anchorPointX);
collisionArrays.iconBox.push(box.anchorPointY);
collisionArrays.iconBox = { x1: box.x1, y1: box.y1, x2: box.x2, y2: box.y2, anchorPointX: box.anchorPointX, anchorPointY: box.anchorPointY };
break; // Only one box allowed per instance
}
}
Expand Down
36 changes: 18 additions & 18 deletions src/symbol/collision_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const projection = require('../symbol/projection');

import type Transform from '../geo/transform';
import type TileCoord from '../source/tile_coord';
import type {SingleCollisionBox} from '../data/bucket/symbol_bucket';

// When a symbol crosses the edge that causes it to be included in
// collision detection, it will cause changes in the symbols around
Expand Down Expand Up @@ -52,13 +53,13 @@ class CollisionIndex {
* overlapping with other features.
* @private
*/
placeCollisionBox(collisionBox: Array<number>, allowOverlap: boolean, scale: number, pixelsToTileUnits: number): Array<number> {
const projectedPoint = this.projectAndGetPerspectiveRatio(new Point(collisionBox[4], collisionBox[5]));
placeCollisionBox(collisionBox: SingleCollisionBox, allowOverlap: boolean, scale: number, pixelsToTileUnits: number): Array<number> {
const projectedPoint = this.projectAndGetPerspectiveRatio(collisionBox.anchorPointX, collisionBox.anchorPointY);
const tileToViewport = pixelsToTileUnits * scale * projectedPoint.perspectiveRatio;
const tlX = collisionBox[0] / tileToViewport + projectedPoint.point.x;
const tlY = collisionBox[1] / tileToViewport + projectedPoint.point.y;
const brX = collisionBox[2] / tileToViewport + projectedPoint.point.x;
const brY = collisionBox[3] / tileToViewport + projectedPoint.point.y;
const tlX = collisionBox.x1 / tileToViewport + projectedPoint.point.x;
const tlY = collisionBox.y1 / tileToViewport + projectedPoint.point.y;
const brX = collisionBox.x2 / tileToViewport + projectedPoint.point.x;
const brY = collisionBox.y2 / tileToViewport + projectedPoint.point.y;

if (!allowOverlap) {
if (this.grid.hitTest(tlX, tlY, brX, brY)) {
Expand All @@ -74,15 +75,14 @@ class CollisionIndex {
return placedCollisionCircles;
}

const tileUnitAnchorPoint = new Point(symbol.anchorX, symbol.anchorY);
const perspectiveRatio = this.getPerspectiveRatio(tileUnitAnchorPoint);
const perspectiveRatio = this.getPerspectiveRatio(symbol.anchorX, symbol.anchorY);

const projectionCache = {};
const fontScale = fontSize / 24;
const lineOffsetX = symbol.lineOffsetX * fontSize;
const lineOffsetY = symbol.lineOffsetY * fontSize;

const labelPlaneAnchorPoint = projection.project(tileUnitAnchorPoint, labelPlaneMatrix);
const labelPlaneAnchorPoint = projection.project(new Point(symbol.anchorX, symbol.anchorY), labelPlaneMatrix);
const firstAndLastGlyph = projection.placeFirstAndLastGlyph(
fontScale,
glyphOffsetArray,
Expand All @@ -109,7 +109,7 @@ class CollisionIndex {
continue;
}

const projectedPoint = this.projectPoint(new Point(collisionCircles[k], collisionCircles[k + 1]));
const projectedPoint = this.projectPoint(collisionCircles[k], collisionCircles[k + 1]);
const x = projectedPoint.x;
const y = projectedPoint.y;

Expand Down Expand Up @@ -186,7 +186,7 @@ class CollisionIndex {
for (let i = 0; i < queryGeometry.length; i++) {
const ring = queryGeometry[i];
for (let k = 0; k < ring.length; k++) {
const p = this.projectPoint(ring[k]);
const p = this.projectPoint(ring[k].x, ring[k].y);
minX = Math.min(minX, p.x);
minY = Math.min(minY, p.y);
maxX = Math.max(maxX, p.x);
Expand Down Expand Up @@ -228,7 +228,7 @@ class CollisionIndex {
// Since there's no actual collision taking place, the circle vs. square
// distinction doesn't matter as much, and box geometry is easier
// to work with.
const projectedPoint = this.projectAndGetPerspectiveRatio(blocking.anchorPoint);
const projectedPoint = this.projectAndGetPerspectiveRatio(blocking.anchorPointX, blocking.anchorPointY);
const tileToViewport = pixelsToTileUnits * scale * projectedPoint.perspectiveRatio;
const x1 = blocking.x1 / tileToViewport + projectedPoint.point.x;
const y1 = blocking.y1 / tileToViewport + projectedPoint.point.y;
Expand Down Expand Up @@ -277,23 +277,23 @@ class CollisionIndex {
this.matrix = matrix;
}

getPerspectiveRatio(anchor) {
const p = [anchor.x, anchor.y, 0, 1];
getPerspectiveRatio(x: number, y: number) {
const p = [x, y, 0, 1];
projection.xyTransformMat4(p, p, this.matrix);
return 0.5 + 0.5 * (p[3] / this.transform.cameraToCenterDistance);
}

projectPoint(point) {
const p = [point.x, point.y, 0, 1];
projectPoint(x: number, y: number) {
const p = [x, y, 0, 1];
projection.xyTransformMat4(p, p, this.matrix);
return new Point(
(((p[0] / p[3] + 1) / 2) * this.transform.width) + viewportPadding,
(((-p[1] / p[3] + 1) / 2) * this.transform.height) + viewportPadding
);
}

projectAndGetPerspectiveRatio(point) {
const p = [point.x, point.y, 0, 1];
projectAndGetPerspectiveRatio(x: number, y: number) {
const p = [x, y, 0, 1];
projection.xyTransformMat4(p, p, this.matrix);
const a = new Point(
(((p[0] / p[3] + 1) / 2) * this.transform.width) + viewportPadding,
Expand Down

0 comments on commit 6b0cd2e

Please sign in to comment.