@@ -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