Spaces:
Sleeping
Sleeping
File size: 4,180 Bytes
11811dc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | // @flow
import type {CollisionBoxArray} from '../data/array_types';
import Point from '@mapbox/point-geometry';
import type Anchor from './anchor';
/**
* A CollisionFeature represents the area of the tile covered by a single label.
* It is used with CollisionIndex to check if the label overlaps with any
* previous labels. A CollisionFeature is mostly just a set of CollisionBox
* objects.
*
* @private
*/
class CollisionFeature {
boxStartIndex: number;
boxEndIndex: number;
circleDiameter: ?number;
/**
* Create a CollisionFeature, adding its collision box data to the given collisionBoxArray in the process.
* For line aligned labels a collision circle diameter is computed instead.
*
* @param anchor The point along the line around which the label is anchored.
* @param shaped The text or icon shaping results.
* @param boxScale A magic number used to convert from glyph metrics units to geometry units.
* @param padding The amount of padding to add around the label edges.
* @param alignLine Whether the label is aligned with the line or the viewport.
* @private
*/
constructor(collisionBoxArray: CollisionBoxArray,
anchor: Anchor,
featureIndex: number,
sourceLayerIndex: number,
bucketIndex: number,
shaped: Object,
boxScale: number,
padding: number,
alignLine: boolean,
rotate: number) {
this.boxStartIndex = collisionBoxArray.length;
if (alignLine) {
// Compute height of the shape in glyph metrics and apply collision padding.
// Note that the pixel based 'text-padding' is applied at runtime
let top = shaped.top;
let bottom = shaped.bottom;
const collisionPadding = shaped.collisionPadding;
if (collisionPadding) {
top -= collisionPadding[1];
bottom += collisionPadding[3];
}
let height = bottom - top;
if (height > 0) {
// set minimum box height to avoid very many small labels
height = Math.max(10, height);
this.circleDiameter = height;
}
} else {
let y1 = shaped.top * boxScale - padding;
let y2 = shaped.bottom * boxScale + padding;
let x1 = shaped.left * boxScale - padding;
let x2 = shaped.right * boxScale + padding;
const collisionPadding = shaped.collisionPadding;
if (collisionPadding) {
x1 -= collisionPadding[0] * boxScale;
y1 -= collisionPadding[1] * boxScale;
x2 += collisionPadding[2] * boxScale;
y2 += collisionPadding[3] * boxScale;
}
if (rotate) {
// Account for *-rotate in point collision boxes
// See https://github.com/mapbox/mapbox-gl-js/issues/6075
// Doesn't account for icon-text-fit
const tl = new Point(x1, y1);
const tr = new Point(x2, y1);
const bl = new Point(x1, y2);
const br = new Point(x2, y2);
const rotateRadians = rotate * Math.PI / 180;
tl._rotate(rotateRadians);
tr._rotate(rotateRadians);
bl._rotate(rotateRadians);
br._rotate(rotateRadians);
// Collision features require an "on-axis" geometry,
// so take the envelope of the rotated geometry
// (may be quite large for wide labels rotated 45 degrees)
x1 = Math.min(tl.x, tr.x, bl.x, br.x);
x2 = Math.max(tl.x, tr.x, bl.x, br.x);
y1 = Math.min(tl.y, tr.y, bl.y, br.y);
y2 = Math.max(tl.y, tr.y, bl.y, br.y);
}
collisionBoxArray.emplaceBack(anchor.x, anchor.y, x1, y1, x2, y2, featureIndex, sourceLayerIndex, bucketIndex);
}
this.boxEndIndex = collisionBoxArray.length;
}
}
export default CollisionFeature;
|