Merge pull request #20353 from calixteman/improve_intersector
[Annotation] Improve the performance of the code for getting glyphs which belongs to annotations bounding boxes (bug 1987914)
This commit is contained in:
commit
0d8a300777
@ -16,13 +16,13 @@
|
|||||||
class SingleIntersector {
|
class SingleIntersector {
|
||||||
#annotation;
|
#annotation;
|
||||||
|
|
||||||
#minX = Infinity;
|
minX = Infinity;
|
||||||
|
|
||||||
#minY = Infinity;
|
minY = Infinity;
|
||||||
|
|
||||||
#maxX = -Infinity;
|
maxX = -Infinity;
|
||||||
|
|
||||||
#maxY = -Infinity;
|
maxY = -Infinity;
|
||||||
|
|
||||||
#quadPoints = null;
|
#quadPoints = null;
|
||||||
|
|
||||||
@ -40,30 +40,21 @@ class SingleIntersector {
|
|||||||
if (!quadPoints) {
|
if (!quadPoints) {
|
||||||
// If there are no quad points, we use the rectangle to determine the
|
// If there are no quad points, we use the rectangle to determine the
|
||||||
// bounds of the annotation.
|
// bounds of the annotation.
|
||||||
[this.#minX, this.#minY, this.#maxX, this.#maxY] = annotation.data.rect;
|
[this.minX, this.minY, this.maxX, this.maxY] = annotation.data.rect;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0, ii = quadPoints.length; i < ii; i += 8) {
|
for (let i = 0, ii = quadPoints.length; i < ii; i += 8) {
|
||||||
this.#minX = Math.min(this.#minX, quadPoints[i]);
|
this.minX = Math.min(this.minX, quadPoints[i]);
|
||||||
this.#maxX = Math.max(this.#maxX, quadPoints[i + 2]);
|
this.maxX = Math.max(this.maxX, quadPoints[i + 2]);
|
||||||
this.#minY = Math.min(this.#minY, quadPoints[i + 5]);
|
this.minY = Math.min(this.minY, quadPoints[i + 5]);
|
||||||
this.#maxY = Math.max(this.#maxY, quadPoints[i + 1]);
|
this.maxY = Math.max(this.maxY, quadPoints[i + 1]);
|
||||||
}
|
}
|
||||||
if (quadPoints.length > 8) {
|
if (quadPoints.length > 8) {
|
||||||
this.#quadPoints = quadPoints;
|
this.#quadPoints = quadPoints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
overlaps(other) {
|
|
||||||
return !(
|
|
||||||
this.#minX >= other.#maxX ||
|
|
||||||
this.#maxX <= other.#minX ||
|
|
||||||
this.#minY >= other.#maxY ||
|
|
||||||
this.#maxY <= other.#minY
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given point intersects with the annotation's quad points.
|
* Check if the given point intersects with the annotation's quad points.
|
||||||
* The point (x, y) is supposed to be the center of the glyph.
|
* The point (x, y) is supposed to be the center of the glyph.
|
||||||
@ -72,12 +63,7 @@ class SingleIntersector {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
#intersects(x, y) {
|
#intersects(x, y) {
|
||||||
if (
|
if (this.minX >= x || this.maxX <= x || this.minY >= y || this.maxY <= y) {
|
||||||
this.#minX >= x ||
|
|
||||||
this.#maxX <= x ||
|
|
||||||
this.#minY >= y ||
|
|
||||||
this.#maxY <= y
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,56 +140,91 @@ class SingleIntersector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The grid is STEPS x STEPS.
|
||||||
|
const STEPS = 64;
|
||||||
|
|
||||||
class Intersector {
|
class Intersector {
|
||||||
#intersectors = new Map();
|
#intersectors = [];
|
||||||
|
|
||||||
|
#grid = [];
|
||||||
|
|
||||||
|
#minX;
|
||||||
|
|
||||||
|
#minY;
|
||||||
|
|
||||||
|
#invXRatio;
|
||||||
|
|
||||||
|
#invYRatio;
|
||||||
|
|
||||||
constructor(annotations) {
|
constructor(annotations) {
|
||||||
|
let minX = Infinity;
|
||||||
|
let minY = Infinity;
|
||||||
|
let maxX = -Infinity;
|
||||||
|
let maxY = -Infinity;
|
||||||
|
const intersectors = this.#intersectors;
|
||||||
for (const annotation of annotations) {
|
for (const annotation of annotations) {
|
||||||
if (!annotation.data.quadPoints && !annotation.data.rect) {
|
if (!annotation.data.quadPoints && !annotation.data.rect) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const intersector = new SingleIntersector(annotation);
|
const intersector = new SingleIntersector(annotation);
|
||||||
for (const [otherIntersector, overlapping] of this.#intersectors) {
|
intersectors.push(intersector);
|
||||||
if (otherIntersector.overlaps(intersector)) {
|
minX = Math.min(minX, intersector.minX);
|
||||||
if (!overlapping) {
|
minY = Math.min(minY, intersector.minY);
|
||||||
this.#intersectors.set(otherIntersector, new Set([intersector]));
|
maxX = Math.max(maxX, intersector.maxX);
|
||||||
} else {
|
maxY = Math.max(maxY, intersector.maxY);
|
||||||
overlapping.add(intersector);
|
}
|
||||||
|
this.#minX = minX;
|
||||||
|
this.#minY = minY;
|
||||||
|
this.#invXRatio = (STEPS - 1) / (maxX - minX);
|
||||||
|
this.#invYRatio = (STEPS - 1) / (maxY - minY);
|
||||||
|
for (const intersector of intersectors) {
|
||||||
|
const iMin = this.#getGridIndex(intersector.minX, intersector.minY);
|
||||||
|
const iMax = this.#getGridIndex(intersector.maxX, intersector.maxY);
|
||||||
|
const w = (iMax - iMin) % STEPS;
|
||||||
|
const h = Math.floor((iMax - iMin) / STEPS);
|
||||||
|
for (let i = iMin; i <= iMin + h * STEPS; i += STEPS) {
|
||||||
|
for (let j = 0; j <= w; j++) {
|
||||||
|
let existing = this.#grid[i + j];
|
||||||
|
if (!existing) {
|
||||||
|
this.#grid[i + j] = existing = [];
|
||||||
|
}
|
||||||
|
existing.push(intersector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#intersectors.set(intersector, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#getGridIndex(x, y) {
|
||||||
|
const i = Math.floor((x - this.#minX) * this.#invXRatio);
|
||||||
|
const j = Math.floor((y - this.#minY) * this.#invYRatio);
|
||||||
|
return i >= 0 && i < STEPS && j >= 0 && j < STEPS ? i + j * STEPS : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addGlyph(transform, width, height, glyph) {
|
addGlyph(transform, width, height, glyph) {
|
||||||
const x = transform[4] + width / 2;
|
const x = transform[4] + width / 2;
|
||||||
const y = transform[5] + height / 2;
|
const y = transform[5] + height / 2;
|
||||||
let overlappingIntersectors;
|
const index = this.#getGridIndex(x, y);
|
||||||
for (const [intersector, overlapping] of this.#intersectors) {
|
if (index < 0) {
|
||||||
if (overlappingIntersectors) {
|
return;
|
||||||
if (overlappingIntersectors.has(intersector)) {
|
}
|
||||||
|
const intersectors = this.#grid[index];
|
||||||
|
if (!intersectors) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const intersector of intersectors) {
|
||||||
intersector.addGlyph(x, y, glyph);
|
intersector.addGlyph(x, y, glyph);
|
||||||
} else {
|
|
||||||
intersector.disableExtraChars();
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!intersector.addGlyph(x, y, glyph)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
overlappingIntersectors = overlapping;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addExtraChar(char) {
|
addExtraChar(char) {
|
||||||
for (const intersector of this.#intersectors.keys()) {
|
for (const intersector of this.#intersectors) {
|
||||||
intersector.addExtraChar(char);
|
intersector.addExtraChar(char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setText() {
|
setText() {
|
||||||
for (const intersector of this.#intersectors.keys()) {
|
for (const intersector of this.#intersectors) {
|
||||||
intersector.setText();
|
intersector.setText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user