gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

regioncoverer.go (22232B)


      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package s2
     16 
     17 import (
     18 	"container/heap"
     19 	"sort"
     20 )
     21 
     22 // RegionCoverer allows arbitrary regions to be approximated as unions of cells (CellUnion).
     23 // This is useful for implementing various sorts of search and precomputation operations.
     24 //
     25 // Typical usage:
     26 //
     27 //	rc := &s2.RegionCoverer{MaxLevel: 30, MaxCells: 5}
     28 //	r := s2.Region(CapFromCenterArea(center, area))
     29 //	covering := rc.Covering(r)
     30 //
     31 // This yields a CellUnion of at most 5 cells that is guaranteed to cover the
     32 // given region (a disc-shaped region on the sphere).
     33 //
     34 // For covering, only cells where (level - MinLevel) is a multiple of LevelMod will be used.
     35 // This effectively allows the branching factor of the S2 CellID hierarchy to be increased.
     36 // Currently the only parameter values allowed are 1, 2, or 3, corresponding to
     37 // branching factors of 4, 16, and 64 respectively.
     38 //
     39 // Note the following:
     40 //
     41 //  - MinLevel takes priority over MaxCells, i.e. cells below the given level will
     42 //    never be used even if this causes a large number of cells to be returned.
     43 //
     44 //  - For any setting of MaxCells, up to 6 cells may be returned if that
     45 //    is the minimum number of cells required (e.g. if the region intersects
     46 //    all six face cells).  Up to 3 cells may be returned even for very tiny
     47 //    convex regions if they happen to be located at the intersection of
     48 //    three cube faces.
     49 //
     50 //  - For any setting of MaxCells, an arbitrary number of cells may be
     51 //    returned if MinLevel is too high for the region being approximated.
     52 //
     53 //  - If MaxCells is less than 4, the area of the covering may be
     54 //    arbitrarily large compared to the area of the original region even if
     55 //    the region is convex (e.g. a Cap or Rect).
     56 //
     57 // The approximation algorithm is not optimal but does a pretty good job in
     58 // practice. The output does not always use the maximum number of cells
     59 // allowed, both because this would not always yield a better approximation,
     60 // and because MaxCells is a limit on how much work is done exploring the
     61 // possible covering as well as a limit on the final output size.
     62 //
     63 // Because it is an approximation algorithm, one should not rely on the
     64 // stability of the output. In particular, the output of the covering algorithm
     65 // may change across different versions of the library.
     66 //
     67 // One can also generate interior coverings, which are sets of cells which
     68 // are entirely contained within a region. Interior coverings can be
     69 // empty, even for non-empty regions, if there are no cells that satisfy
     70 // the provided constraints and are contained by the region. Note that for
     71 // performance reasons, it is wise to specify a MaxLevel when computing
     72 // interior coverings - otherwise for regions with small or zero area, the
     73 // algorithm may spend a lot of time subdividing cells all the way to leaf
     74 // level to try to find contained cells.
     75 type RegionCoverer struct {
     76 	MinLevel int // the minimum cell level to be used.
     77 	MaxLevel int // the maximum cell level to be used.
     78 	LevelMod int // the LevelMod to be used.
     79 	MaxCells int // the maximum desired number of cells in the approximation.
     80 }
     81 
     82 // NewRegionCoverer returns a region coverer with the appropriate defaults.
     83 func NewRegionCoverer() *RegionCoverer {
     84 	return &RegionCoverer{
     85 		MinLevel: 0,
     86 		MaxLevel: maxLevel,
     87 		LevelMod: 1,
     88 		MaxCells: 8,
     89 	}
     90 }
     91 
     92 type coverer struct {
     93 	minLevel         int // the minimum cell level to be used.
     94 	maxLevel         int // the maximum cell level to be used.
     95 	levelMod         int // the LevelMod to be used.
     96 	maxCells         int // the maximum desired number of cells in the approximation.
     97 	region           Region
     98 	result           CellUnion
     99 	pq               priorityQueue
    100 	interiorCovering bool
    101 }
    102 
    103 type candidate struct {
    104 	cell        Cell
    105 	terminal    bool         // Cell should not be expanded further.
    106 	numChildren int          // Number of children that intersect the region.
    107 	children    []*candidate // Actual size may be 0, 4, 16, or 64 elements.
    108 	priority    int          // Priority of the candidate.
    109 }
    110 
    111 type priorityQueue []*candidate
    112 
    113 func (pq priorityQueue) Len() int {
    114 	return len(pq)
    115 }
    116 
    117 func (pq priorityQueue) Less(i, j int) bool {
    118 	// We want Pop to give us the highest, not lowest, priority so we use greater than here.
    119 	return pq[i].priority > pq[j].priority
    120 }
    121 
    122 func (pq priorityQueue) Swap(i, j int) {
    123 	pq[i], pq[j] = pq[j], pq[i]
    124 }
    125 
    126 func (pq *priorityQueue) Push(x interface{}) {
    127 	item := x.(*candidate)
    128 	*pq = append(*pq, item)
    129 }
    130 
    131 func (pq *priorityQueue) Pop() interface{} {
    132 	item := (*pq)[len(*pq)-1]
    133 	*pq = (*pq)[:len(*pq)-1]
    134 	return item
    135 }
    136 
    137 func (pq *priorityQueue) Reset() {
    138 	*pq = (*pq)[:0]
    139 }
    140 
    141 // newCandidate returns a new candidate with no children if the cell intersects the given region.
    142 // The candidate is marked as terminal if it should not be expanded further.
    143 func (c *coverer) newCandidate(cell Cell) *candidate {
    144 	if !c.region.IntersectsCell(cell) {
    145 		return nil
    146 	}
    147 	cand := &candidate{cell: cell}
    148 	level := int(cell.level)
    149 	if level >= c.minLevel {
    150 		if c.interiorCovering {
    151 			if c.region.ContainsCell(cell) {
    152 				cand.terminal = true
    153 			} else if level+c.levelMod > c.maxLevel {
    154 				return nil
    155 			}
    156 		} else if level+c.levelMod > c.maxLevel || c.region.ContainsCell(cell) {
    157 			cand.terminal = true
    158 		}
    159 	}
    160 	return cand
    161 }
    162 
    163 // expandChildren populates the children of the candidate by expanding the given number of
    164 // levels from the given cell.  Returns the number of children that were marked "terminal".
    165 func (c *coverer) expandChildren(cand *candidate, cell Cell, numLevels int) int {
    166 	numLevels--
    167 	var numTerminals int
    168 	last := cell.id.ChildEnd()
    169 	for ci := cell.id.ChildBegin(); ci != last; ci = ci.Next() {
    170 		childCell := CellFromCellID(ci)
    171 		if numLevels > 0 {
    172 			if c.region.IntersectsCell(childCell) {
    173 				numTerminals += c.expandChildren(cand, childCell, numLevels)
    174 			}
    175 			continue
    176 		}
    177 		if child := c.newCandidate(childCell); child != nil {
    178 			cand.children = append(cand.children, child)
    179 			cand.numChildren++
    180 			if child.terminal {
    181 				numTerminals++
    182 			}
    183 		}
    184 	}
    185 	return numTerminals
    186 }
    187 
    188 // addCandidate adds the given candidate to the result if it is marked as "terminal",
    189 // otherwise expands its children and inserts it into the priority queue.
    190 // Passing an argument of nil does nothing.
    191 func (c *coverer) addCandidate(cand *candidate) {
    192 	if cand == nil {
    193 		return
    194 	}
    195 
    196 	if cand.terminal {
    197 		c.result = append(c.result, cand.cell.id)
    198 		return
    199 	}
    200 
    201 	// Expand one level at a time until we hit minLevel to ensure that we don't skip over it.
    202 	numLevels := c.levelMod
    203 	level := int(cand.cell.level)
    204 	if level < c.minLevel {
    205 		numLevels = 1
    206 	}
    207 
    208 	numTerminals := c.expandChildren(cand, cand.cell, numLevels)
    209 	maxChildrenShift := uint(2 * c.levelMod)
    210 	if cand.numChildren == 0 {
    211 		return
    212 	} else if !c.interiorCovering && numTerminals == 1<<maxChildrenShift && level >= c.minLevel {
    213 		// Optimization: add the parent cell rather than all of its children.
    214 		// We can't do this for interior coverings, since the children just
    215 		// intersect the region, but may not be contained by it - we need to
    216 		// subdivide them further.
    217 		cand.terminal = true
    218 		c.addCandidate(cand)
    219 	} else {
    220 		// We negate the priority so that smaller absolute priorities are returned
    221 		// first. The heuristic is designed to refine the largest cells first,
    222 		// since those are where we have the largest potential gain. Among cells
    223 		// of the same size, we prefer the cells with the fewest children.
    224 		// Finally, among cells with equal numbers of children we prefer those
    225 		// with the smallest number of children that cannot be refined further.
    226 		cand.priority = -(((level<<maxChildrenShift)+cand.numChildren)<<maxChildrenShift + numTerminals)
    227 		heap.Push(&c.pq, cand)
    228 	}
    229 }
    230 
    231 // adjustLevel returns the reduced "level" so that it satisfies levelMod. Levels smaller than minLevel
    232 // are not affected (since cells at these levels are eventually expanded).
    233 func (c *coverer) adjustLevel(level int) int {
    234 	if c.levelMod > 1 && level > c.minLevel {
    235 		level -= (level - c.minLevel) % c.levelMod
    236 	}
    237 	return level
    238 }
    239 
    240 // adjustCellLevels ensures that all cells with level > minLevel also satisfy levelMod,
    241 // by replacing them with an ancestor if necessary. Cell levels smaller
    242 // than minLevel are not modified (see AdjustLevel). The output is
    243 // then normalized to ensure that no redundant cells are present.
    244 func (c *coverer) adjustCellLevels(cells *CellUnion) {
    245 	if c.levelMod == 1 {
    246 		return
    247 	}
    248 
    249 	var out int
    250 	for _, ci := range *cells {
    251 		level := ci.Level()
    252 		newLevel := c.adjustLevel(level)
    253 		if newLevel != level {
    254 			ci = ci.Parent(newLevel)
    255 		}
    256 		if out > 0 && (*cells)[out-1].Contains(ci) {
    257 			continue
    258 		}
    259 		for out > 0 && ci.Contains((*cells)[out-1]) {
    260 			out--
    261 		}
    262 		(*cells)[out] = ci
    263 		out++
    264 	}
    265 	*cells = (*cells)[:out]
    266 }
    267 
    268 // initialCandidates computes a set of initial candidates that cover the given region.
    269 func (c *coverer) initialCandidates() {
    270 	// Optimization: start with a small (usually 4 cell) covering of the region's bounding cap.
    271 	temp := &RegionCoverer{MaxLevel: c.maxLevel, LevelMod: 1, MaxCells: minInt(4, c.maxCells)}
    272 
    273 	cells := temp.FastCovering(c.region)
    274 	c.adjustCellLevels(&cells)
    275 	for _, ci := range cells {
    276 		c.addCandidate(c.newCandidate(CellFromCellID(ci)))
    277 	}
    278 }
    279 
    280 // coveringInternal generates a covering and stores it in result.
    281 // Strategy: Start with the 6 faces of the cube.  Discard any
    282 // that do not intersect the shape.  Then repeatedly choose the
    283 // largest cell that intersects the shape and subdivide it.
    284 //
    285 // result contains the cells that will be part of the output, while pq
    286 // contains cells that we may still subdivide further. Cells that are
    287 // entirely contained within the region are immediately added to the output,
    288 // while cells that do not intersect the region are immediately discarded.
    289 // Therefore pq only contains cells that partially intersect the region.
    290 // Candidates are prioritized first according to cell size (larger cells
    291 // first), then by the number of intersecting children they have (fewest
    292 // children first), and then by the number of fully contained children
    293 // (fewest children first).
    294 func (c *coverer) coveringInternal(region Region) {
    295 	c.region = region
    296 
    297 	c.initialCandidates()
    298 	for c.pq.Len() > 0 && (!c.interiorCovering || len(c.result) < c.maxCells) {
    299 		cand := heap.Pop(&c.pq).(*candidate)
    300 
    301 		// For interior covering we keep subdividing no matter how many children
    302 		// candidate has. If we reach MaxCells before expanding all children,
    303 		// we will just use some of them.
    304 		// For exterior covering we cannot do this, because result has to cover the
    305 		// whole region, so all children have to be used.
    306 		// candidate.numChildren == 1 case takes care of the situation when we
    307 		// already have more than MaxCells in result (minLevel is too high).
    308 		// Subdividing of the candidate with one child does no harm in this case.
    309 		if c.interiorCovering || int(cand.cell.level) < c.minLevel || cand.numChildren == 1 || len(c.result)+c.pq.Len()+cand.numChildren <= c.maxCells {
    310 			for _, child := range cand.children {
    311 				if !c.interiorCovering || len(c.result) < c.maxCells {
    312 					c.addCandidate(child)
    313 				}
    314 			}
    315 		} else {
    316 			cand.terminal = true
    317 			c.addCandidate(cand)
    318 		}
    319 	}
    320 
    321 	c.pq.Reset()
    322 	c.region = nil
    323 
    324 	// Rather than just returning the raw list of cell ids, we construct a cell
    325 	// union and then denormalize it. This has the effect of replacing four
    326 	// child cells with their parent whenever this does not violate the covering
    327 	// parameters specified (min_level, level_mod, etc). This significantly
    328 	// reduces the number of cells returned in many cases, and it is cheap
    329 	// compared to computing the covering in the first place.
    330 	c.result.Normalize()
    331 	if c.minLevel > 0 || c.levelMod > 1 {
    332 		c.result.Denormalize(c.minLevel, c.levelMod)
    333 	}
    334 }
    335 
    336 // newCoverer returns an instance of coverer.
    337 func (rc *RegionCoverer) newCoverer() *coverer {
    338 	return &coverer{
    339 		minLevel: maxInt(0, minInt(maxLevel, rc.MinLevel)),
    340 		maxLevel: maxInt(0, minInt(maxLevel, rc.MaxLevel)),
    341 		levelMod: maxInt(1, minInt(3, rc.LevelMod)),
    342 		maxCells: rc.MaxCells,
    343 	}
    344 }
    345 
    346 // Covering returns a CellUnion that covers the given region and satisfies the various restrictions.
    347 func (rc *RegionCoverer) Covering(region Region) CellUnion {
    348 	covering := rc.CellUnion(region)
    349 	covering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod)))
    350 	return covering
    351 }
    352 
    353 // InteriorCovering returns a CellUnion that is contained within the given region and satisfies the various restrictions.
    354 func (rc *RegionCoverer) InteriorCovering(region Region) CellUnion {
    355 	intCovering := rc.InteriorCellUnion(region)
    356 	intCovering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod)))
    357 	return intCovering
    358 }
    359 
    360 // CellUnion returns a normalized CellUnion that covers the given region and
    361 // satisfies the restrictions except for minLevel and levelMod. These criteria
    362 // cannot be satisfied using a cell union because cell unions are
    363 // automatically normalized by replacing four child cells with their parent
    364 // whenever possible. (Note that the list of cell ids passed to the CellUnion
    365 // constructor does in fact satisfy all the given restrictions.)
    366 func (rc *RegionCoverer) CellUnion(region Region) CellUnion {
    367 	c := rc.newCoverer()
    368 	c.coveringInternal(region)
    369 	cu := c.result
    370 	cu.Normalize()
    371 	return cu
    372 }
    373 
    374 // InteriorCellUnion returns a normalized CellUnion that is contained within the given region and
    375 // satisfies the restrictions except for minLevel and levelMod. These criteria
    376 // cannot be satisfied using a cell union because cell unions are
    377 // automatically normalized by replacing four child cells with their parent
    378 // whenever possible. (Note that the list of cell ids passed to the CellUnion
    379 // constructor does in fact satisfy all the given restrictions.)
    380 func (rc *RegionCoverer) InteriorCellUnion(region Region) CellUnion {
    381 	c := rc.newCoverer()
    382 	c.interiorCovering = true
    383 	c.coveringInternal(region)
    384 	cu := c.result
    385 	cu.Normalize()
    386 	return cu
    387 }
    388 
    389 // FastCovering returns a CellUnion that covers the given region similar to Covering,
    390 // except that this method is much faster and the coverings are not as tight.
    391 // All of the usual parameters are respected (MaxCells, MinLevel, MaxLevel, and LevelMod),
    392 // except that the implementation makes no attempt to take advantage of large values of
    393 // MaxCells.  (A small number of cells will always be returned.)
    394 //
    395 // This function is useful as a starting point for algorithms that
    396 // recursively subdivide cells.
    397 func (rc *RegionCoverer) FastCovering(region Region) CellUnion {
    398 	c := rc.newCoverer()
    399 	cu := CellUnion(region.CellUnionBound())
    400 	c.normalizeCovering(&cu)
    401 	return cu
    402 }
    403 
    404 // IsCanonical reports whether the given CellUnion represents a valid covering
    405 // that conforms to the current covering parameters.  In particular:
    406 //
    407 //  - All CellIDs must be valid.
    408 //
    409 //  - CellIDs must be sorted and non-overlapping.
    410 //
    411 //  - CellID levels must satisfy MinLevel, MaxLevel, and LevelMod.
    412 //
    413 //  - If the covering has more than MaxCells, there must be no two cells with
    414 //    a common ancestor at MinLevel or higher.
    415 //
    416 //  - There must be no sequence of cells that could be replaced by an
    417 //    ancestor (i.e. with LevelMod == 1, the 4 child cells of a parent).
    418 func (rc *RegionCoverer) IsCanonical(covering CellUnion) bool {
    419 	return rc.newCoverer().isCanonical(covering)
    420 }
    421 
    422 // normalizeCovering normalizes the "covering" so that it conforms to the
    423 // current covering parameters (maxCells, minLevel, maxLevel, and levelMod).
    424 // This method makes no attempt to be optimal. In particular, if
    425 // minLevel > 0 or levelMod > 1 then it may return more than the
    426 // desired number of cells even when this isn't necessary.
    427 //
    428 // Note that when the covering parameters have their default values, almost
    429 // all of the code in this function is skipped.
    430 func (c *coverer) normalizeCovering(covering *CellUnion) {
    431 	// If any cells are too small, or don't satisfy levelMod, then replace them with ancestors.
    432 	if c.maxLevel < maxLevel || c.levelMod > 1 {
    433 		for i, ci := range *covering {
    434 			level := ci.Level()
    435 			newLevel := c.adjustLevel(minInt(level, c.maxLevel))
    436 			if newLevel != level {
    437 				(*covering)[i] = ci.Parent(newLevel)
    438 			}
    439 		}
    440 	}
    441 	// Sort the cells and simplify them.
    442 	covering.Normalize()
    443 
    444 	// Make sure that the covering satisfies minLevel and levelMod,
    445 	// possibly at the expense of satisfying MaxCells.
    446 	if c.minLevel > 0 || c.levelMod > 1 {
    447 		covering.Denormalize(c.minLevel, c.levelMod)
    448 	}
    449 
    450 	// If there are too many cells and the covering is very large, use the
    451 	// RegionCoverer to compute a new covering. (This avoids possible O(n^2)
    452 	// behavior of the simpler algorithm below.)
    453 	excess := len(*covering) - c.maxCells
    454 	if excess <= 0 || c.isCanonical(*covering) {
    455 		return
    456 	}
    457 	if excess*len(*covering) > 10000 {
    458 		rc := NewRegionCoverer()
    459 		(*covering) = rc.Covering(covering)
    460 		return
    461 	}
    462 
    463 	// If there are still too many cells, then repeatedly replace two adjacent
    464 	// cells in CellID order by their lowest common ancestor.
    465 	for len(*covering) > c.maxCells {
    466 		bestIndex := -1
    467 		bestLevel := -1
    468 		for i := 0; i+1 < len(*covering); i++ {
    469 			level, ok := (*covering)[i].CommonAncestorLevel((*covering)[i+1])
    470 			if !ok {
    471 				continue
    472 			}
    473 			level = c.adjustLevel(level)
    474 			if level > bestLevel {
    475 				bestLevel = level
    476 				bestIndex = i
    477 			}
    478 		}
    479 
    480 		if bestLevel < c.minLevel {
    481 			break
    482 		}
    483 
    484 		// Replace all cells contained by the new ancestor cell.
    485 		id := (*covering)[bestIndex].Parent(bestLevel)
    486 		(*covering) = c.replaceCellsWithAncestor(*covering, id)
    487 
    488 		// Now repeatedly check whether all children of the parent cell are
    489 		// present, in which case we can replace those cells with their parent.
    490 		for bestLevel > c.minLevel {
    491 			bestLevel -= c.levelMod
    492 			id = id.Parent(bestLevel)
    493 			if !c.containsAllChildren(*covering, id) {
    494 				break
    495 			}
    496 			(*covering) = c.replaceCellsWithAncestor(*covering, id)
    497 		}
    498 	}
    499 }
    500 
    501 // isCanonical reports whether the covering is canonical.
    502 func (c *coverer) isCanonical(covering CellUnion) bool {
    503 	trueMax := c.maxLevel
    504 	if c.levelMod != 1 {
    505 		trueMax = c.maxLevel - (c.maxLevel-c.minLevel)%c.levelMod
    506 	}
    507 	tooManyCells := len(covering) > c.maxCells
    508 	sameParentCount := 1
    509 
    510 	prevID := CellID(0)
    511 	for _, id := range covering {
    512 		if !id.IsValid() {
    513 			return false
    514 		}
    515 
    516 		// Check that the CellID level is acceptable.
    517 		level := id.Level()
    518 		if level < c.minLevel || level > trueMax {
    519 			return false
    520 		}
    521 		if c.levelMod > 1 && (level-c.minLevel)%c.levelMod != 0 {
    522 			return false
    523 		}
    524 
    525 		if prevID != 0 {
    526 			// Check that cells are sorted and non-overlapping.
    527 			if prevID.RangeMax() >= id.RangeMin() {
    528 				return false
    529 			}
    530 
    531 			lev, ok := id.CommonAncestorLevel(prevID)
    532 			// If there are too many cells, check that no pair of adjacent cells
    533 			// could be replaced by an ancestor.
    534 			if tooManyCells && (ok && lev >= c.minLevel) {
    535 				return false
    536 			}
    537 
    538 			// Check that there are no sequences of (4 ** level_mod) cells that all
    539 			// have the same parent (considering only multiples of "level_mod").
    540 			pLevel := level - c.levelMod
    541 			if pLevel < c.minLevel || level != prevID.Level() ||
    542 				id.Parent(pLevel) != prevID.Parent(pLevel) {
    543 				sameParentCount = 1
    544 			} else {
    545 				sameParentCount++
    546 				if sameParentCount == 1<<uint(2*c.levelMod) {
    547 					return false
    548 				}
    549 			}
    550 		}
    551 		prevID = id
    552 	}
    553 
    554 	return true
    555 }
    556 
    557 func (c *coverer) containsAllChildren(covering []CellID, id CellID) bool {
    558 	pos := sort.Search(len(covering), func(i int) bool { return (covering)[i] >= id.RangeMin() })
    559 	level := id.Level() + c.levelMod
    560 	for child := id.ChildBeginAtLevel(level); child != id.ChildEndAtLevel(level); child = child.Next() {
    561 		if pos == len(covering) || covering[pos] != child {
    562 			return false
    563 		}
    564 		pos++
    565 	}
    566 	return true
    567 }
    568 
    569 // replaceCellsWithAncestor replaces all descendants of the given id in covering
    570 // with id. This requires the covering contains at least one descendant of id.
    571 func (c *coverer) replaceCellsWithAncestor(covering []CellID, id CellID) []CellID {
    572 	begin := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMin() })
    573 	end := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMax() })
    574 
    575 	return append(append(covering[:begin], id), covering[end:]...)
    576 }
    577 
    578 // SimpleRegionCovering returns a set of cells at the given level that cover
    579 // the connected region and a starting point on the boundary or inside the
    580 // region. The cells are returned in arbitrary order.
    581 //
    582 // Note that this method is not faster than the regular Covering
    583 // method for most region types, such as Cap or Polygon, and in fact it
    584 // can be much slower when the output consists of a large number of cells.
    585 // Currently it can be faster at generating coverings of long narrow regions
    586 // such as polylines, but this may change in the future.
    587 func SimpleRegionCovering(region Region, start Point, level int) []CellID {
    588 	return FloodFillRegionCovering(region, cellIDFromPoint(start).Parent(level))
    589 }
    590 
    591 // FloodFillRegionCovering returns all edge-connected cells at the same level as
    592 // the given CellID that intersect the given region, in arbitrary order.
    593 func FloodFillRegionCovering(region Region, start CellID) []CellID {
    594 	var output []CellID
    595 	all := map[CellID]bool{
    596 		start: true,
    597 	}
    598 	frontier := []CellID{start}
    599 	for len(frontier) > 0 {
    600 		id := frontier[len(frontier)-1]
    601 		frontier = frontier[:len(frontier)-1]
    602 		if !region.IntersectsCell(CellFromCellID(id)) {
    603 			continue
    604 		}
    605 		output = append(output, id)
    606 		for _, nbr := range id.EdgeNeighbors() {
    607 			if !all[nbr] {
    608 				all[nbr] = true
    609 				frontier = append(frontier, nbr)
    610 			}
    611 		}
    612 	}
    613 
    614 	return output
    615 }