Skip to content

Commit efaaea5

Browse files
committed
Optimize cross tile index searching
1 parent b85b206 commit efaaea5

1 file changed

Lines changed: 64 additions & 19 deletions

File tree

src/symbol/cross_tile_symbol_index.ts

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ class TileLayerIndex {
104104
}) {
105105
const tolerance = this.tileID.canonical.z < newTileID.canonical.z ? 1 : Math.pow(2, this.tileID.canonical.z - newTileID.canonical.z);
106106

107+
const symbolKeyToScaledCoordinatesToSymbolInstanceMap = new Map<number, Map<number, SymbolInstance[]>>();
108+
107109
for (let i = 0; i < symbolInstances.length; i++) {
108110
const symbolInstance = symbolInstances.get(i);
109111
if (symbolInstance.crossTileID) {
@@ -118,27 +120,22 @@ class TileLayerIndex {
118120
}
119121

120122
const scaledSymbolCoord = this.getScaledCoordinates(symbolInstance, newTileID);
121-
122123
if (entry.index) {
123-
// Return any symbol with the same keys whose coordinates are within 1
124-
// grid unit. (with a 4px grid, this covers a 12px by 12px area)
125-
const indexes = entry.index.range(
126-
scaledSymbolCoord.x - tolerance,
127-
scaledSymbolCoord.y - tolerance,
128-
scaledSymbolCoord.x + tolerance,
129-
scaledSymbolCoord.y + tolerance).sort();
130-
131-
for (const i of indexes) {
132-
const crossTileID = entry.crossTileIDs[i];
133-
134-
if (!zoomCrossTileIDs[crossTileID]) {
135-
// Once we've marked ourselves duplicate against this parent symbol,
136-
// don't let any other symbols at the same zoom level duplicate against
137-
// the same parent (see issue #5993)
138-
zoomCrossTileIDs[crossTileID] = true;
139-
symbolInstance.crossTileID = crossTileID;
140-
break;
124+
// Build a map keyed by common symbol instance keys, which are also
125+
// used to key indexes. For each symbol index key, build a reverse map
126+
// of the scaled coordinates back to a set of SymbolInstance that
127+
// resolve to that coordinate.
128+
const scaledCoordinateId = scaledSymbolCoord.x << 16 | scaledSymbolCoord.y;
129+
const existingSymbolKey = symbolKeyToScaledCoordinatesToSymbolInstanceMap.get(symbolInstance.key);
130+
if (existingSymbolKey) {
131+
const existingSymbolsAtCoordinate = existingSymbolKey.get(scaledCoordinateId);
132+
if (existingSymbolsAtCoordinate) {
133+
existingSymbolsAtCoordinate.push(symbolInstance);
134+
} else {
135+
existingSymbolKey.set(scaledCoordinateId, [symbolInstance]);
141136
}
137+
} else {
138+
symbolKeyToScaledCoordinatesToSymbolInstanceMap.set(symbolInstance.key, new Map([[scaledCoordinateId, [symbolInstance]]]));
142139
}
143140
} else if (entry.positions) {
144141
for (let i = 0; i < entry.positions.length; i++) {
@@ -159,6 +156,54 @@ class TileLayerIndex {
159156
}
160157
}
161158
}
159+
160+
}
161+
162+
for (const [symbolKey, coordinateMap] of symbolKeyToScaledCoordinatesToSymbolInstanceMap.entries()) {
163+
const entry = this._symbolsByKey[symbolKey];
164+
if (!entry) {
165+
// Shouldn't happen
166+
continue;
167+
}
168+
169+
if (!entry.index){
170+
// Shouldn't happen
171+
continue;
172+
}
173+
174+
for (const [coordinateId, symbolInstancesAtCoordinate] of coordinateMap.entries()) {
175+
const x = coordinateId >>> 16;
176+
const y = coordinateId % (1 << 16);
177+
const indexes = entry.index.range(
178+
x - tolerance,
179+
y - tolerance,
180+
x + tolerance,
181+
y + tolerance);
182+
183+
// Iterate through cross tile entries at this quadrant _and_
184+
// symbol instances and pair them up until one of the lists
185+
// runs out. This is faster than re-running a range query
186+
// for every symbol instance, as each of these symbol
187+
// instances already have the same key, and thus can be
188+
// paired with any entry in the index.
189+
let i = 0;
190+
let j = 0;
191+
while (i < indexes.length && j < symbolInstancesAtCoordinate.length) {
192+
const crossTileID = entry.crossTileIDs[i];
193+
const symbolInstanceAtCoordinate = symbolInstancesAtCoordinate[j];
194+
195+
if (!zoomCrossTileIDs[crossTileID]) {
196+
// Once we've marked ourselves duplicate against this parent symbol,
197+
// don't let any other symbols at the same zoom level duplicate against
198+
// the same parent (see issue #5993)
199+
zoomCrossTileIDs[crossTileID] = true;
200+
symbolInstanceAtCoordinate.crossTileID = crossTileID;
201+
j++;
202+
203+
}
204+
i++;
205+
}
206+
}
162207
}
163208
}
164209

0 commit comments

Comments
 (0)