in s2/edge_query.go [580:673]
func (e *EdgeQuery) initQueue() {
if len(e.indexCovering) == 0 {
// We delay iterator initialization until now to make queries on very
// small indexes a bit faster (i.e., where brute force is used).
e.iter = NewShapeIndexIterator(e.index)
}
// Optimization: if the user is searching for just the closest edge, and the
// center of the target's bounding cap happens to intersect an index cell,
// then we try to limit the search region to a small disc by first
// processing the edges in that cell. This sets distance_limit_ based on
// the closest edge in that cell, which we can then use to limit the search
// area. This means that the cell containing "target" will be processed
// twice, but in general this is still faster.
//
// TODO(roberts): Even if the cap center is not contained, we could still
// process one or both of the adjacent index cells in CellID order,
// provided that those cells are closer than distanceLimit.
cb := e.target.capBound()
if cb.IsEmpty() {
return // Empty target.
}
if e.opts.maxResults == 1 && e.iter.LocatePoint(cb.Center()) {
e.processEdges(&queryQueueEntry{
distance: e.target.distance().zero(),
id: e.iter.CellID(),
indexCell: e.iter.IndexCell(),
})
// Skip the rest of the algorithm if we found an intersecting edge.
if e.distanceLimit == e.target.distance().zero() {
return
}
}
if len(e.indexCovering) == 0 {
e.initCovering()
}
if e.distanceLimit == e.target.distance().infinity() {
// Start with the precomputed index covering.
for i := range e.indexCovering {
e.processOrEnqueue(e.indexCovering[i], e.indexCells[i])
}
} else {
// Compute a covering of the search disc and intersect it with the
// precomputed index covering.
coverer := &RegionCoverer{MaxCells: 4, LevelMod: 1, MaxLevel: maxLevel}
radius := cb.Radius() + e.distanceLimit.chordAngleBound().Angle()
searchCB := CapFromCenterAngle(cb.Center(), radius)
maxDistCover := coverer.FastCovering(searchCB)
e.initialCells = CellUnionFromIntersection(e.indexCovering, maxDistCover)
// Now we need to clean up the initial cells to ensure that they all
// contain at least one cell of the ShapeIndex. (Some may not intersect
// the index at all, while other may be descendants of an index cell.)
i, j := 0, 0
for i < len(e.initialCells) {
idI := e.initialCells[i]
// Find the top-level cell that contains this initial cell.
for e.indexCovering[j].RangeMax() < idI {
j++
}
idJ := e.indexCovering[j]
if idI == idJ {
// This initial cell is one of the top-level cells. Use the
// precomputed ShapeIndexCell pointer to avoid an index seek.
e.processOrEnqueue(idJ, e.indexCells[j])
i++
j++
} else {
// This initial cell is a proper descendant of a top-level cell.
// Check how it is related to the cells of the ShapeIndex.
r := e.iter.LocateCellID(idI)
if r == Indexed {
// This cell is a descendant of an index cell.
// Enqueue it and skip any other initial cells
// that are also descendants of this cell.
e.processOrEnqueue(e.iter.CellID(), e.iter.IndexCell())
lastID := e.iter.CellID().RangeMax()
for i < len(e.initialCells) && e.initialCells[i] <= lastID {
i++
}
} else {
// Enqueue the cell only if it contains at least one index cell.
if r == Subdivided {
e.processOrEnqueue(idI, nil)
}
i++
}
}
}
}
}