gtsocial-umbx

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

cellunion.go (18498B)


      1 // Copyright 2014 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 	"fmt"
     19 	"io"
     20 	"sort"
     21 
     22 	"github.com/golang/geo/s1"
     23 )
     24 
     25 // A CellUnion is a collection of CellIDs.
     26 //
     27 // It is normalized if it is sorted, and does not contain redundancy.
     28 // Specifically, it may not contain the same CellID twice, nor a CellID that
     29 // is contained by another, nor the four sibling CellIDs that are children of
     30 // a single higher level CellID.
     31 //
     32 // CellUnions are not required to be normalized, but certain operations will
     33 // return different results if they are not (e.g. Contains).
     34 type CellUnion []CellID
     35 
     36 // CellUnionFromRange creates a CellUnion that covers the half-open range
     37 // of leaf cells [begin, end). If begin == end the resulting union is empty.
     38 // This requires that begin and end are both leaves, and begin <= end.
     39 // To create a closed-ended range, pass in end.Next().
     40 func CellUnionFromRange(begin, end CellID) CellUnion {
     41 	// We repeatedly add the largest cell we can.
     42 	var cu CellUnion
     43 	for id := begin.MaxTile(end); id != end; id = id.Next().MaxTile(end) {
     44 		cu = append(cu, id)
     45 	}
     46 	// The output is normalized because the cells are added in order by the iteration.
     47 	return cu
     48 }
     49 
     50 // CellUnionFromUnion creates a CellUnion from the union of the given CellUnions.
     51 func CellUnionFromUnion(cellUnions ...CellUnion) CellUnion {
     52 	var cu CellUnion
     53 	for _, cellUnion := range cellUnions {
     54 		cu = append(cu, cellUnion...)
     55 	}
     56 	cu.Normalize()
     57 	return cu
     58 }
     59 
     60 // CellUnionFromIntersection creates a CellUnion from the intersection of the given CellUnions.
     61 func CellUnionFromIntersection(x, y CellUnion) CellUnion {
     62 	var cu CellUnion
     63 
     64 	// This is a fairly efficient calculation that uses binary search to skip
     65 	// over sections of both input vectors. It takes constant time if all the
     66 	// cells of x come before or after all the cells of y in CellID order.
     67 	var i, j int
     68 	for i < len(x) && j < len(y) {
     69 		iMin := x[i].RangeMin()
     70 		jMin := y[j].RangeMin()
     71 		if iMin > jMin {
     72 			// Either j.Contains(i) or the two cells are disjoint.
     73 			if x[i] <= y[j].RangeMax() {
     74 				cu = append(cu, x[i])
     75 				i++
     76 			} else {
     77 				// Advance j to the first cell possibly contained by x[i].
     78 				j = y.lowerBound(j+1, len(y), iMin)
     79 				// The previous cell y[j-1] may now contain x[i].
     80 				if x[i] <= y[j-1].RangeMax() {
     81 					j--
     82 				}
     83 			}
     84 		} else if jMin > iMin {
     85 			// Identical to the code above with i and j reversed.
     86 			if y[j] <= x[i].RangeMax() {
     87 				cu = append(cu, y[j])
     88 				j++
     89 			} else {
     90 				i = x.lowerBound(i+1, len(x), jMin)
     91 				if y[j] <= x[i-1].RangeMax() {
     92 					i--
     93 				}
     94 			}
     95 		} else {
     96 			// i and j have the same RangeMin(), so one contains the other.
     97 			if x[i] < y[j] {
     98 				cu = append(cu, x[i])
     99 				i++
    100 			} else {
    101 				cu = append(cu, y[j])
    102 				j++
    103 			}
    104 		}
    105 	}
    106 
    107 	// The output is generated in sorted order.
    108 	cu.Normalize()
    109 	return cu
    110 }
    111 
    112 // CellUnionFromIntersectionWithCellID creates a CellUnion from the intersection
    113 // of a CellUnion with the given CellID. This can be useful for splitting a
    114 // CellUnion into chunks.
    115 func CellUnionFromIntersectionWithCellID(x CellUnion, id CellID) CellUnion {
    116 	var cu CellUnion
    117 	if x.ContainsCellID(id) {
    118 		cu = append(cu, id)
    119 		cu.Normalize()
    120 		return cu
    121 	}
    122 
    123 	idmax := id.RangeMax()
    124 	for i := x.lowerBound(0, len(x), id.RangeMin()); i < len(x) && x[i] <= idmax; i++ {
    125 		cu = append(cu, x[i])
    126 	}
    127 
    128 	cu.Normalize()
    129 	return cu
    130 }
    131 
    132 // CellUnionFromDifference creates a CellUnion from the difference (x - y)
    133 // of the given CellUnions.
    134 func CellUnionFromDifference(x, y CellUnion) CellUnion {
    135 	// TODO(roberts): This is approximately O(N*log(N)), but could probably
    136 	// use similar techniques as CellUnionFromIntersectionWithCellID to be more efficient.
    137 
    138 	var cu CellUnion
    139 	for _, xid := range x {
    140 		cu.cellUnionDifferenceInternal(xid, &y)
    141 	}
    142 
    143 	// The output is generated in sorted order, and there should not be any
    144 	// cells that can be merged (provided that both inputs were normalized).
    145 	return cu
    146 }
    147 
    148 // The C++ constructor methods FromNormalized and FromVerbatim are not necessary
    149 // since they don't call Normalize, and just set the CellIDs directly on the object,
    150 // so straight casting is sufficient in Go to replicate this behavior.
    151 
    152 // IsValid reports whether the cell union is valid, meaning that the CellIDs are
    153 // valid, non-overlapping, and sorted in increasing order.
    154 func (cu *CellUnion) IsValid() bool {
    155 	for i, cid := range *cu {
    156 		if !cid.IsValid() {
    157 			return false
    158 		}
    159 		if i == 0 {
    160 			continue
    161 		}
    162 		if (*cu)[i-1].RangeMax() >= cid.RangeMin() {
    163 			return false
    164 		}
    165 	}
    166 	return true
    167 }
    168 
    169 // IsNormalized reports whether the cell union is normalized, meaning that it is
    170 // satisfies IsValid and that no four cells have a common parent.
    171 // Certain operations such as Contains will return a different
    172 // result if the cell union is not normalized.
    173 func (cu *CellUnion) IsNormalized() bool {
    174 	for i, cid := range *cu {
    175 		if !cid.IsValid() {
    176 			return false
    177 		}
    178 		if i == 0 {
    179 			continue
    180 		}
    181 		if (*cu)[i-1].RangeMax() >= cid.RangeMin() {
    182 			return false
    183 		}
    184 		if i < 3 {
    185 			continue
    186 		}
    187 		if areSiblings((*cu)[i-3], (*cu)[i-2], (*cu)[i-1], cid) {
    188 			return false
    189 		}
    190 	}
    191 	return true
    192 }
    193 
    194 // Normalize normalizes the CellUnion.
    195 func (cu *CellUnion) Normalize() {
    196 	sortCellIDs(*cu)
    197 
    198 	output := make([]CellID, 0, len(*cu)) // the list of accepted cells
    199 	// Loop invariant: output is a sorted list of cells with no redundancy.
    200 	for _, ci := range *cu {
    201 		// The first two passes here either ignore this new candidate,
    202 		// or remove previously accepted cells that are covered by this candidate.
    203 
    204 		// Ignore this cell if it is contained by the previous one.
    205 		// We only need to check the last accepted cell. The ordering of the
    206 		// cells implies containment (but not the converse), and output has no redundancy,
    207 		// so if this candidate is not contained by the last accepted cell
    208 		// then it cannot be contained by any previously accepted cell.
    209 		if len(output) > 0 && output[len(output)-1].Contains(ci) {
    210 			continue
    211 		}
    212 
    213 		// Discard any previously accepted cells contained by this one.
    214 		// This could be any contiguous trailing subsequence, but it can't be
    215 		// a discontiguous subsequence because of the containment property of
    216 		// sorted S2 cells mentioned above.
    217 		j := len(output) - 1 // last index to keep
    218 		for j >= 0 {
    219 			if !ci.Contains(output[j]) {
    220 				break
    221 			}
    222 			j--
    223 		}
    224 		output = output[:j+1]
    225 
    226 		// See if the last three cells plus this one can be collapsed.
    227 		// We loop because collapsing three accepted cells and adding a higher level cell
    228 		// could cascade into previously accepted cells.
    229 		for len(output) >= 3 && areSiblings(output[len(output)-3], output[len(output)-2], output[len(output)-1], ci) {
    230 			// Replace four children by their parent cell.
    231 			output = output[:len(output)-3]
    232 			ci = ci.immediateParent() // checked !ci.isFace above
    233 		}
    234 		output = append(output, ci)
    235 	}
    236 	*cu = output
    237 }
    238 
    239 // IntersectsCellID reports whether this CellUnion intersects the given cell ID.
    240 func (cu *CellUnion) IntersectsCellID(id CellID) bool {
    241 	// Find index of array item that occurs directly after our probe cell:
    242 	i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] })
    243 
    244 	if i != len(*cu) && (*cu)[i].RangeMin() <= id.RangeMax() {
    245 		return true
    246 	}
    247 	return i != 0 && (*cu)[i-1].RangeMax() >= id.RangeMin()
    248 }
    249 
    250 // ContainsCellID reports whether the CellUnion contains the given cell ID.
    251 // Containment is defined with respect to regions, e.g. a cell contains its 4 children.
    252 //
    253 // CAVEAT: If you have constructed a non-normalized CellUnion, note that groups
    254 // of 4 child cells are *not* considered to contain their parent cell. To get
    255 // this behavior you must use one of the call Normalize() explicitly.
    256 func (cu *CellUnion) ContainsCellID(id CellID) bool {
    257 	// Find index of array item that occurs directly after our probe cell:
    258 	i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] })
    259 
    260 	if i != len(*cu) && (*cu)[i].RangeMin() <= id {
    261 		return true
    262 	}
    263 	return i != 0 && (*cu)[i-1].RangeMax() >= id
    264 }
    265 
    266 // Denormalize replaces this CellUnion with an expanded version of the
    267 // CellUnion where any cell whose level is less than minLevel or where
    268 // (level - minLevel) is not a multiple of levelMod is replaced by its
    269 // children, until either both of these conditions are satisfied or the
    270 // maximum level is reached.
    271 func (cu *CellUnion) Denormalize(minLevel, levelMod int) {
    272 	var denorm CellUnion
    273 	for _, id := range *cu {
    274 		level := id.Level()
    275 		newLevel := level
    276 		if newLevel < minLevel {
    277 			newLevel = minLevel
    278 		}
    279 		if levelMod > 1 {
    280 			newLevel += (maxLevel - (newLevel - minLevel)) % levelMod
    281 			if newLevel > maxLevel {
    282 				newLevel = maxLevel
    283 			}
    284 		}
    285 		if newLevel == level {
    286 			denorm = append(denorm, id)
    287 		} else {
    288 			end := id.ChildEndAtLevel(newLevel)
    289 			for ci := id.ChildBeginAtLevel(newLevel); ci != end; ci = ci.Next() {
    290 				denorm = append(denorm, ci)
    291 			}
    292 		}
    293 	}
    294 	*cu = denorm
    295 }
    296 
    297 // RectBound returns a Rect that bounds this entity.
    298 func (cu *CellUnion) RectBound() Rect {
    299 	bound := EmptyRect()
    300 	for _, c := range *cu {
    301 		bound = bound.Union(CellFromCellID(c).RectBound())
    302 	}
    303 	return bound
    304 }
    305 
    306 // CapBound returns a Cap that bounds this entity.
    307 func (cu *CellUnion) CapBound() Cap {
    308 	if len(*cu) == 0 {
    309 		return EmptyCap()
    310 	}
    311 
    312 	// Compute the approximate centroid of the region. This won't produce the
    313 	// bounding cap of minimal area, but it should be close enough.
    314 	var centroid Point
    315 
    316 	for _, ci := range *cu {
    317 		area := AvgAreaMetric.Value(ci.Level())
    318 		centroid = Point{centroid.Add(ci.Point().Mul(area))}
    319 	}
    320 
    321 	if zero := (Point{}); centroid == zero {
    322 		centroid = PointFromCoords(1, 0, 0)
    323 	} else {
    324 		centroid = Point{centroid.Normalize()}
    325 	}
    326 
    327 	// Use the centroid as the cap axis, and expand the cap angle so that it
    328 	// contains the bounding caps of all the individual cells.  Note that it is
    329 	// *not* sufficient to just bound all the cell vertices because the bounding
    330 	// cap may be concave (i.e. cover more than one hemisphere).
    331 	c := CapFromPoint(centroid)
    332 	for _, ci := range *cu {
    333 		c = c.AddCap(CellFromCellID(ci).CapBound())
    334 	}
    335 
    336 	return c
    337 }
    338 
    339 // ContainsCell reports whether this cell union contains the given cell.
    340 func (cu *CellUnion) ContainsCell(c Cell) bool {
    341 	return cu.ContainsCellID(c.id)
    342 }
    343 
    344 // IntersectsCell reports whether this cell union intersects the given cell.
    345 func (cu *CellUnion) IntersectsCell(c Cell) bool {
    346 	return cu.IntersectsCellID(c.id)
    347 }
    348 
    349 // ContainsPoint reports whether this cell union contains the given point.
    350 func (cu *CellUnion) ContainsPoint(p Point) bool {
    351 	return cu.ContainsCell(CellFromPoint(p))
    352 }
    353 
    354 // CellUnionBound computes a covering of the CellUnion.
    355 func (cu *CellUnion) CellUnionBound() []CellID {
    356 	return cu.CapBound().CellUnionBound()
    357 }
    358 
    359 // LeafCellsCovered reports the number of leaf cells covered by this cell union.
    360 // This will be no more than 6*2^60 for the whole sphere.
    361 func (cu *CellUnion) LeafCellsCovered() int64 {
    362 	var numLeaves int64
    363 	for _, c := range *cu {
    364 		numLeaves += 1 << uint64((maxLevel-int64(c.Level()))<<1)
    365 	}
    366 	return numLeaves
    367 }
    368 
    369 // Returns true if the given four cells have a common parent.
    370 // This requires that the four CellIDs are distinct.
    371 func areSiblings(a, b, c, d CellID) bool {
    372 	// A necessary (but not sufficient) condition is that the XOR of the
    373 	// four cell IDs must be zero. This is also very fast to test.
    374 	if (a ^ b ^ c) != d {
    375 		return false
    376 	}
    377 
    378 	// Now we do a slightly more expensive but exact test. First, compute a
    379 	// mask that blocks out the two bits that encode the child position of
    380 	// "id" with respect to its parent, then check that the other three
    381 	// children all agree with "mask".
    382 	mask := d.lsb() << 1
    383 	mask = ^(mask + (mask << 1))
    384 	idMasked := (uint64(d) & mask)
    385 	return ((uint64(a)&mask) == idMasked &&
    386 		(uint64(b)&mask) == idMasked &&
    387 		(uint64(c)&mask) == idMasked &&
    388 		!d.isFace())
    389 }
    390 
    391 // Contains reports whether this CellUnion contains all of the CellIDs of the given CellUnion.
    392 func (cu *CellUnion) Contains(o CellUnion) bool {
    393 	// TODO(roberts): Investigate alternatives such as divide-and-conquer
    394 	// or alternating-skip-search that may be significantly faster in both
    395 	// the average and worst case. This applies to Intersects as well.
    396 	for _, id := range o {
    397 		if !cu.ContainsCellID(id) {
    398 			return false
    399 		}
    400 	}
    401 
    402 	return true
    403 }
    404 
    405 // Intersects reports whether this CellUnion intersects any of the CellIDs of the given CellUnion.
    406 func (cu *CellUnion) Intersects(o CellUnion) bool {
    407 	for _, c := range *cu {
    408 		if o.IntersectsCellID(c) {
    409 			return true
    410 		}
    411 	}
    412 
    413 	return false
    414 }
    415 
    416 // lowerBound returns the index in this CellUnion to the first element whose value
    417 // is not considered to go before the given cell id. (i.e., either it is equivalent
    418 // or comes after the given id.) If there is no match, then end is returned.
    419 func (cu *CellUnion) lowerBound(begin, end int, id CellID) int {
    420 	for i := begin; i < end; i++ {
    421 		if (*cu)[i] >= id {
    422 			return i
    423 		}
    424 	}
    425 
    426 	return end
    427 }
    428 
    429 // cellUnionDifferenceInternal adds the difference between the CellID and the union to
    430 // the result CellUnion. If they intersect but the difference is non-empty, it divides
    431 // and conquers.
    432 func (cu *CellUnion) cellUnionDifferenceInternal(id CellID, other *CellUnion) {
    433 	if !other.IntersectsCellID(id) {
    434 		(*cu) = append((*cu), id)
    435 		return
    436 	}
    437 
    438 	if !other.ContainsCellID(id) {
    439 		for _, child := range id.Children() {
    440 			cu.cellUnionDifferenceInternal(child, other)
    441 		}
    442 	}
    443 }
    444 
    445 // ExpandAtLevel expands this CellUnion by adding a rim of cells at expandLevel
    446 // around the unions boundary.
    447 //
    448 // For each cell c in the union, we add all cells at level
    449 // expandLevel that abut c. There are typically eight of those
    450 // (four edge-abutting and four sharing a vertex). However, if c is
    451 // finer than expandLevel, we add all cells abutting
    452 // c.Parent(expandLevel) as well as c.Parent(expandLevel) itself,
    453 // as an expandLevel cell rarely abuts a smaller cell.
    454 //
    455 // Note that the size of the output is exponential in
    456 // expandLevel. For example, if expandLevel == 20 and the input
    457 // has a cell at level 10, there will be on the order of 4000
    458 // adjacent cells in the output. For most applications the
    459 // ExpandByRadius method below is easier to use.
    460 func (cu *CellUnion) ExpandAtLevel(level int) {
    461 	var output CellUnion
    462 	levelLsb := lsbForLevel(level)
    463 	for i := len(*cu) - 1; i >= 0; i-- {
    464 		id := (*cu)[i]
    465 		if id.lsb() < levelLsb {
    466 			id = id.Parent(level)
    467 			// Optimization: skip over any cells contained by this one. This is
    468 			// especially important when very small regions are being expanded.
    469 			for i > 0 && id.Contains((*cu)[i-1]) {
    470 				i--
    471 			}
    472 		}
    473 		output = append(output, id)
    474 		output = append(output, id.AllNeighbors(level)...)
    475 	}
    476 	sortCellIDs(output)
    477 
    478 	*cu = output
    479 	cu.Normalize()
    480 }
    481 
    482 // ExpandByRadius expands this CellUnion such that it contains all points whose
    483 // distance to the CellUnion is at most minRadius, but do not use cells that
    484 // are more than maxLevelDiff levels higher than the largest cell in the input.
    485 // The second parameter controls the tradeoff between accuracy and output size
    486 // when a large region is being expanded by a small amount (e.g. expanding Canada
    487 // by 1km). For example, if maxLevelDiff == 4 the region will always be expanded
    488 // by approximately 1/16 the width of its largest cell. Note that in the worst case,
    489 // the number of cells in the output can be up to 4 * (1 + 2 ** maxLevelDiff) times
    490 // larger than the number of cells in the input.
    491 func (cu *CellUnion) ExpandByRadius(minRadius s1.Angle, maxLevelDiff int) {
    492 	minLevel := maxLevel
    493 	for _, cid := range *cu {
    494 		minLevel = minInt(minLevel, cid.Level())
    495 	}
    496 
    497 	// Find the maximum level such that all cells are at least "minRadius" wide.
    498 	radiusLevel := MinWidthMetric.MaxLevel(minRadius.Radians())
    499 	if radiusLevel == 0 && minRadius.Radians() > MinWidthMetric.Value(0) {
    500 		// The requested expansion is greater than the width of a face cell.
    501 		// The easiest way to handle this is to expand twice.
    502 		cu.ExpandAtLevel(0)
    503 	}
    504 	cu.ExpandAtLevel(minInt(minLevel+maxLevelDiff, radiusLevel))
    505 }
    506 
    507 // Equal reports whether the two CellUnions are equal.
    508 func (cu CellUnion) Equal(o CellUnion) bool {
    509 	if len(cu) != len(o) {
    510 		return false
    511 	}
    512 	for i := 0; i < len(cu); i++ {
    513 		if cu[i] != o[i] {
    514 			return false
    515 		}
    516 	}
    517 	return true
    518 }
    519 
    520 // AverageArea returns the average area of this CellUnion.
    521 // This is accurate to within a factor of 1.7.
    522 func (cu *CellUnion) AverageArea() float64 {
    523 	return AvgAreaMetric.Value(maxLevel) * float64(cu.LeafCellsCovered())
    524 }
    525 
    526 // ApproxArea returns the approximate area of this CellUnion. This method is accurate
    527 // to within 3% percent for all cell sizes and accurate to within 0.1% for cells
    528 // at level 5 or higher within the union.
    529 func (cu *CellUnion) ApproxArea() float64 {
    530 	var area float64
    531 	for _, id := range *cu {
    532 		area += CellFromCellID(id).ApproxArea()
    533 	}
    534 	return area
    535 }
    536 
    537 // ExactArea returns the area of this CellUnion as accurately as possible.
    538 func (cu *CellUnion) ExactArea() float64 {
    539 	var area float64
    540 	for _, id := range *cu {
    541 		area += CellFromCellID(id).ExactArea()
    542 	}
    543 	return area
    544 }
    545 
    546 // Encode encodes the CellUnion.
    547 func (cu *CellUnion) Encode(w io.Writer) error {
    548 	e := &encoder{w: w}
    549 	cu.encode(e)
    550 	return e.err
    551 }
    552 
    553 func (cu *CellUnion) encode(e *encoder) {
    554 	e.writeInt8(encodingVersion)
    555 	e.writeInt64(int64(len(*cu)))
    556 	for _, ci := range *cu {
    557 		ci.encode(e)
    558 	}
    559 }
    560 
    561 // Decode decodes the CellUnion.
    562 func (cu *CellUnion) Decode(r io.Reader) error {
    563 	d := &decoder{r: asByteReader(r)}
    564 	cu.decode(d)
    565 	return d.err
    566 }
    567 
    568 func (cu *CellUnion) decode(d *decoder) {
    569 	version := d.readInt8()
    570 	if d.err != nil {
    571 		return
    572 	}
    573 	if version != encodingVersion {
    574 		d.err = fmt.Errorf("only version %d is supported", encodingVersion)
    575 		return
    576 	}
    577 	n := d.readInt64()
    578 	if d.err != nil {
    579 		return
    580 	}
    581 	const maxCells = 1000000
    582 	if n > maxCells {
    583 		d.err = fmt.Errorf("too many cells (%d; max is %d)", n, maxCells)
    584 		return
    585 	}
    586 	*cu = make([]CellID, n)
    587 	for i := range *cu {
    588 		(*cu)[i].decode(d)
    589 	}
    590 }