summaryrefslogtreecommitdiff
path: root/vendor/github.com/golang/geo/s2/cellunion.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/golang/geo/s2/cellunion.go')
-rw-r--r--vendor/github.com/golang/geo/s2/cellunion.go590
1 files changed, 0 insertions, 590 deletions
diff --git a/vendor/github.com/golang/geo/s2/cellunion.go b/vendor/github.com/golang/geo/s2/cellunion.go
deleted file mode 100644
index 0654de973..000000000
--- a/vendor/github.com/golang/geo/s2/cellunion.go
+++ /dev/null
@@ -1,590 +0,0 @@
-// Copyright 2014 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package s2
-
-import (
- "fmt"
- "io"
- "sort"
-
- "github.com/golang/geo/s1"
-)
-
-// A CellUnion is a collection of CellIDs.
-//
-// It is normalized if it is sorted, and does not contain redundancy.
-// Specifically, it may not contain the same CellID twice, nor a CellID that
-// is contained by another, nor the four sibling CellIDs that are children of
-// a single higher level CellID.
-//
-// CellUnions are not required to be normalized, but certain operations will
-// return different results if they are not (e.g. Contains).
-type CellUnion []CellID
-
-// CellUnionFromRange creates a CellUnion that covers the half-open range
-// of leaf cells [begin, end). If begin == end the resulting union is empty.
-// This requires that begin and end are both leaves, and begin <= end.
-// To create a closed-ended range, pass in end.Next().
-func CellUnionFromRange(begin, end CellID) CellUnion {
- // We repeatedly add the largest cell we can.
- var cu CellUnion
- for id := begin.MaxTile(end); id != end; id = id.Next().MaxTile(end) {
- cu = append(cu, id)
- }
- // The output is normalized because the cells are added in order by the iteration.
- return cu
-}
-
-// CellUnionFromUnion creates a CellUnion from the union of the given CellUnions.
-func CellUnionFromUnion(cellUnions ...CellUnion) CellUnion {
- var cu CellUnion
- for _, cellUnion := range cellUnions {
- cu = append(cu, cellUnion...)
- }
- cu.Normalize()
- return cu
-}
-
-// CellUnionFromIntersection creates a CellUnion from the intersection of the given CellUnions.
-func CellUnionFromIntersection(x, y CellUnion) CellUnion {
- var cu CellUnion
-
- // This is a fairly efficient calculation that uses binary search to skip
- // over sections of both input vectors. It takes constant time if all the
- // cells of x come before or after all the cells of y in CellID order.
- var i, j int
- for i < len(x) && j < len(y) {
- iMin := x[i].RangeMin()
- jMin := y[j].RangeMin()
- if iMin > jMin {
- // Either j.Contains(i) or the two cells are disjoint.
- if x[i] <= y[j].RangeMax() {
- cu = append(cu, x[i])
- i++
- } else {
- // Advance j to the first cell possibly contained by x[i].
- j = y.lowerBound(j+1, len(y), iMin)
- // The previous cell y[j-1] may now contain x[i].
- if x[i] <= y[j-1].RangeMax() {
- j--
- }
- }
- } else if jMin > iMin {
- // Identical to the code above with i and j reversed.
- if y[j] <= x[i].RangeMax() {
- cu = append(cu, y[j])
- j++
- } else {
- i = x.lowerBound(i+1, len(x), jMin)
- if y[j] <= x[i-1].RangeMax() {
- i--
- }
- }
- } else {
- // i and j have the same RangeMin(), so one contains the other.
- if x[i] < y[j] {
- cu = append(cu, x[i])
- i++
- } else {
- cu = append(cu, y[j])
- j++
- }
- }
- }
-
- // The output is generated in sorted order.
- cu.Normalize()
- return cu
-}
-
-// CellUnionFromIntersectionWithCellID creates a CellUnion from the intersection
-// of a CellUnion with the given CellID. This can be useful for splitting a
-// CellUnion into chunks.
-func CellUnionFromIntersectionWithCellID(x CellUnion, id CellID) CellUnion {
- var cu CellUnion
- if x.ContainsCellID(id) {
- cu = append(cu, id)
- cu.Normalize()
- return cu
- }
-
- idmax := id.RangeMax()
- for i := x.lowerBound(0, len(x), id.RangeMin()); i < len(x) && x[i] <= idmax; i++ {
- cu = append(cu, x[i])
- }
-
- cu.Normalize()
- return cu
-}
-
-// CellUnionFromDifference creates a CellUnion from the difference (x - y)
-// of the given CellUnions.
-func CellUnionFromDifference(x, y CellUnion) CellUnion {
- // TODO(roberts): This is approximately O(N*log(N)), but could probably
- // use similar techniques as CellUnionFromIntersectionWithCellID to be more efficient.
-
- var cu CellUnion
- for _, xid := range x {
- cu.cellUnionDifferenceInternal(xid, &y)
- }
-
- // The output is generated in sorted order, and there should not be any
- // cells that can be merged (provided that both inputs were normalized).
- return cu
-}
-
-// The C++ constructor methods FromNormalized and FromVerbatim are not necessary
-// since they don't call Normalize, and just set the CellIDs directly on the object,
-// so straight casting is sufficient in Go to replicate this behavior.
-
-// IsValid reports whether the cell union is valid, meaning that the CellIDs are
-// valid, non-overlapping, and sorted in increasing order.
-func (cu *CellUnion) IsValid() bool {
- for i, cid := range *cu {
- if !cid.IsValid() {
- return false
- }
- if i == 0 {
- continue
- }
- if (*cu)[i-1].RangeMax() >= cid.RangeMin() {
- return false
- }
- }
- return true
-}
-
-// IsNormalized reports whether the cell union is normalized, meaning that it is
-// satisfies IsValid and that no four cells have a common parent.
-// Certain operations such as Contains will return a different
-// result if the cell union is not normalized.
-func (cu *CellUnion) IsNormalized() bool {
- for i, cid := range *cu {
- if !cid.IsValid() {
- return false
- }
- if i == 0 {
- continue
- }
- if (*cu)[i-1].RangeMax() >= cid.RangeMin() {
- return false
- }
- if i < 3 {
- continue
- }
- if areSiblings((*cu)[i-3], (*cu)[i-2], (*cu)[i-1], cid) {
- return false
- }
- }
- return true
-}
-
-// Normalize normalizes the CellUnion.
-func (cu *CellUnion) Normalize() {
- sortCellIDs(*cu)
-
- output := make([]CellID, 0, len(*cu)) // the list of accepted cells
- // Loop invariant: output is a sorted list of cells with no redundancy.
- for _, ci := range *cu {
- // The first two passes here either ignore this new candidate,
- // or remove previously accepted cells that are covered by this candidate.
-
- // Ignore this cell if it is contained by the previous one.
- // We only need to check the last accepted cell. The ordering of the
- // cells implies containment (but not the converse), and output has no redundancy,
- // so if this candidate is not contained by the last accepted cell
- // then it cannot be contained by any previously accepted cell.
- if len(output) > 0 && output[len(output)-1].Contains(ci) {
- continue
- }
-
- // Discard any previously accepted cells contained by this one.
- // This could be any contiguous trailing subsequence, but it can't be
- // a discontiguous subsequence because of the containment property of
- // sorted S2 cells mentioned above.
- j := len(output) - 1 // last index to keep
- for j >= 0 {
- if !ci.Contains(output[j]) {
- break
- }
- j--
- }
- output = output[:j+1]
-
- // See if the last three cells plus this one can be collapsed.
- // We loop because collapsing three accepted cells and adding a higher level cell
- // could cascade into previously accepted cells.
- for len(output) >= 3 && areSiblings(output[len(output)-3], output[len(output)-2], output[len(output)-1], ci) {
- // Replace four children by their parent cell.
- output = output[:len(output)-3]
- ci = ci.immediateParent() // checked !ci.isFace above
- }
- output = append(output, ci)
- }
- *cu = output
-}
-
-// IntersectsCellID reports whether this CellUnion intersects the given cell ID.
-func (cu *CellUnion) IntersectsCellID(id CellID) bool {
- // Find index of array item that occurs directly after our probe cell:
- i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] })
-
- if i != len(*cu) && (*cu)[i].RangeMin() <= id.RangeMax() {
- return true
- }
- return i != 0 && (*cu)[i-1].RangeMax() >= id.RangeMin()
-}
-
-// ContainsCellID reports whether the CellUnion contains the given cell ID.
-// Containment is defined with respect to regions, e.g. a cell contains its 4 children.
-//
-// CAVEAT: If you have constructed a non-normalized CellUnion, note that groups
-// of 4 child cells are *not* considered to contain their parent cell. To get
-// this behavior you must use one of the call Normalize() explicitly.
-func (cu *CellUnion) ContainsCellID(id CellID) bool {
- // Find index of array item that occurs directly after our probe cell:
- i := sort.Search(len(*cu), func(i int) bool { return id < (*cu)[i] })
-
- if i != len(*cu) && (*cu)[i].RangeMin() <= id {
- return true
- }
- return i != 0 && (*cu)[i-1].RangeMax() >= id
-}
-
-// Denormalize replaces this CellUnion with an expanded version of the
-// CellUnion where any cell whose level is less than minLevel or where
-// (level - minLevel) is not a multiple of levelMod is replaced by its
-// children, until either both of these conditions are satisfied or the
-// maximum level is reached.
-func (cu *CellUnion) Denormalize(minLevel, levelMod int) {
- var denorm CellUnion
- for _, id := range *cu {
- level := id.Level()
- newLevel := level
- if newLevel < minLevel {
- newLevel = minLevel
- }
- if levelMod > 1 {
- newLevel += (maxLevel - (newLevel - minLevel)) % levelMod
- if newLevel > maxLevel {
- newLevel = maxLevel
- }
- }
- if newLevel == level {
- denorm = append(denorm, id)
- } else {
- end := id.ChildEndAtLevel(newLevel)
- for ci := id.ChildBeginAtLevel(newLevel); ci != end; ci = ci.Next() {
- denorm = append(denorm, ci)
- }
- }
- }
- *cu = denorm
-}
-
-// RectBound returns a Rect that bounds this entity.
-func (cu *CellUnion) RectBound() Rect {
- bound := EmptyRect()
- for _, c := range *cu {
- bound = bound.Union(CellFromCellID(c).RectBound())
- }
- return bound
-}
-
-// CapBound returns a Cap that bounds this entity.
-func (cu *CellUnion) CapBound() Cap {
- if len(*cu) == 0 {
- return EmptyCap()
- }
-
- // Compute the approximate centroid of the region. This won't produce the
- // bounding cap of minimal area, but it should be close enough.
- var centroid Point
-
- for _, ci := range *cu {
- area := AvgAreaMetric.Value(ci.Level())
- centroid = Point{centroid.Add(ci.Point().Mul(area))}
- }
-
- if zero := (Point{}); centroid == zero {
- centroid = PointFromCoords(1, 0, 0)
- } else {
- centroid = Point{centroid.Normalize()}
- }
-
- // Use the centroid as the cap axis, and expand the cap angle so that it
- // contains the bounding caps of all the individual cells. Note that it is
- // *not* sufficient to just bound all the cell vertices because the bounding
- // cap may be concave (i.e. cover more than one hemisphere).
- c := CapFromPoint(centroid)
- for _, ci := range *cu {
- c = c.AddCap(CellFromCellID(ci).CapBound())
- }
-
- return c
-}
-
-// ContainsCell reports whether this cell union contains the given cell.
-func (cu *CellUnion) ContainsCell(c Cell) bool {
- return cu.ContainsCellID(c.id)
-}
-
-// IntersectsCell reports whether this cell union intersects the given cell.
-func (cu *CellUnion) IntersectsCell(c Cell) bool {
- return cu.IntersectsCellID(c.id)
-}
-
-// ContainsPoint reports whether this cell union contains the given point.
-func (cu *CellUnion) ContainsPoint(p Point) bool {
- return cu.ContainsCell(CellFromPoint(p))
-}
-
-// CellUnionBound computes a covering of the CellUnion.
-func (cu *CellUnion) CellUnionBound() []CellID {
- return cu.CapBound().CellUnionBound()
-}
-
-// LeafCellsCovered reports the number of leaf cells covered by this cell union.
-// This will be no more than 6*2^60 for the whole sphere.
-func (cu *CellUnion) LeafCellsCovered() int64 {
- var numLeaves int64
- for _, c := range *cu {
- numLeaves += 1 << uint64((maxLevel-int64(c.Level()))<<1)
- }
- return numLeaves
-}
-
-// Returns true if the given four cells have a common parent.
-// This requires that the four CellIDs are distinct.
-func areSiblings(a, b, c, d CellID) bool {
- // A necessary (but not sufficient) condition is that the XOR of the
- // four cell IDs must be zero. This is also very fast to test.
- if (a ^ b ^ c) != d {
- return false
- }
-
- // Now we do a slightly more expensive but exact test. First, compute a
- // mask that blocks out the two bits that encode the child position of
- // "id" with respect to its parent, then check that the other three
- // children all agree with "mask".
- mask := d.lsb() << 1
- mask = ^(mask + (mask << 1))
- idMasked := (uint64(d) & mask)
- return ((uint64(a)&mask) == idMasked &&
- (uint64(b)&mask) == idMasked &&
- (uint64(c)&mask) == idMasked &&
- !d.isFace())
-}
-
-// Contains reports whether this CellUnion contains all of the CellIDs of the given CellUnion.
-func (cu *CellUnion) Contains(o CellUnion) bool {
- // TODO(roberts): Investigate alternatives such as divide-and-conquer
- // or alternating-skip-search that may be significantly faster in both
- // the average and worst case. This applies to Intersects as well.
- for _, id := range o {
- if !cu.ContainsCellID(id) {
- return false
- }
- }
-
- return true
-}
-
-// Intersects reports whether this CellUnion intersects any of the CellIDs of the given CellUnion.
-func (cu *CellUnion) Intersects(o CellUnion) bool {
- for _, c := range *cu {
- if o.IntersectsCellID(c) {
- return true
- }
- }
-
- return false
-}
-
-// lowerBound returns the index in this CellUnion to the first element whose value
-// is not considered to go before the given cell id. (i.e., either it is equivalent
-// or comes after the given id.) If there is no match, then end is returned.
-func (cu *CellUnion) lowerBound(begin, end int, id CellID) int {
- for i := begin; i < end; i++ {
- if (*cu)[i] >= id {
- return i
- }
- }
-
- return end
-}
-
-// cellUnionDifferenceInternal adds the difference between the CellID and the union to
-// the result CellUnion. If they intersect but the difference is non-empty, it divides
-// and conquers.
-func (cu *CellUnion) cellUnionDifferenceInternal(id CellID, other *CellUnion) {
- if !other.IntersectsCellID(id) {
- (*cu) = append((*cu), id)
- return
- }
-
- if !other.ContainsCellID(id) {
- for _, child := range id.Children() {
- cu.cellUnionDifferenceInternal(child, other)
- }
- }
-}
-
-// ExpandAtLevel expands this CellUnion by adding a rim of cells at expandLevel
-// around the unions boundary.
-//
-// For each cell c in the union, we add all cells at level
-// expandLevel that abut c. There are typically eight of those
-// (four edge-abutting and four sharing a vertex). However, if c is
-// finer than expandLevel, we add all cells abutting
-// c.Parent(expandLevel) as well as c.Parent(expandLevel) itself,
-// as an expandLevel cell rarely abuts a smaller cell.
-//
-// Note that the size of the output is exponential in
-// expandLevel. For example, if expandLevel == 20 and the input
-// has a cell at level 10, there will be on the order of 4000
-// adjacent cells in the output. For most applications the
-// ExpandByRadius method below is easier to use.
-func (cu *CellUnion) ExpandAtLevel(level int) {
- var output CellUnion
- levelLsb := lsbForLevel(level)
- for i := len(*cu) - 1; i >= 0; i-- {
- id := (*cu)[i]
- if id.lsb() < levelLsb {
- id = id.Parent(level)
- // Optimization: skip over any cells contained by this one. This is
- // especially important when very small regions are being expanded.
- for i > 0 && id.Contains((*cu)[i-1]) {
- i--
- }
- }
- output = append(output, id)
- output = append(output, id.AllNeighbors(level)...)
- }
- sortCellIDs(output)
-
- *cu = output
- cu.Normalize()
-}
-
-// ExpandByRadius expands this CellUnion such that it contains all points whose
-// distance to the CellUnion is at most minRadius, but do not use cells that
-// are more than maxLevelDiff levels higher than the largest cell in the input.
-// The second parameter controls the tradeoff between accuracy and output size
-// when a large region is being expanded by a small amount (e.g. expanding Canada
-// by 1km). For example, if maxLevelDiff == 4 the region will always be expanded
-// by approximately 1/16 the width of its largest cell. Note that in the worst case,
-// the number of cells in the output can be up to 4 * (1 + 2 ** maxLevelDiff) times
-// larger than the number of cells in the input.
-func (cu *CellUnion) ExpandByRadius(minRadius s1.Angle, maxLevelDiff int) {
- minLevel := maxLevel
- for _, cid := range *cu {
- minLevel = minInt(minLevel, cid.Level())
- }
-
- // Find the maximum level such that all cells are at least "minRadius" wide.
- radiusLevel := MinWidthMetric.MaxLevel(minRadius.Radians())
- if radiusLevel == 0 && minRadius.Radians() > MinWidthMetric.Value(0) {
- // The requested expansion is greater than the width of a face cell.
- // The easiest way to handle this is to expand twice.
- cu.ExpandAtLevel(0)
- }
- cu.ExpandAtLevel(minInt(minLevel+maxLevelDiff, radiusLevel))
-}
-
-// Equal reports whether the two CellUnions are equal.
-func (cu CellUnion) Equal(o CellUnion) bool {
- if len(cu) != len(o) {
- return false
- }
- for i := 0; i < len(cu); i++ {
- if cu[i] != o[i] {
- return false
- }
- }
- return true
-}
-
-// AverageArea returns the average area of this CellUnion.
-// This is accurate to within a factor of 1.7.
-func (cu *CellUnion) AverageArea() float64 {
- return AvgAreaMetric.Value(maxLevel) * float64(cu.LeafCellsCovered())
-}
-
-// ApproxArea returns the approximate area of this CellUnion. This method is accurate
-// to within 3% percent for all cell sizes and accurate to within 0.1% for cells
-// at level 5 or higher within the union.
-func (cu *CellUnion) ApproxArea() float64 {
- var area float64
- for _, id := range *cu {
- area += CellFromCellID(id).ApproxArea()
- }
- return area
-}
-
-// ExactArea returns the area of this CellUnion as accurately as possible.
-func (cu *CellUnion) ExactArea() float64 {
- var area float64
- for _, id := range *cu {
- area += CellFromCellID(id).ExactArea()
- }
- return area
-}
-
-// Encode encodes the CellUnion.
-func (cu *CellUnion) Encode(w io.Writer) error {
- e := &encoder{w: w}
- cu.encode(e)
- return e.err
-}
-
-func (cu *CellUnion) encode(e *encoder) {
- e.writeInt8(encodingVersion)
- e.writeInt64(int64(len(*cu)))
- for _, ci := range *cu {
- ci.encode(e)
- }
-}
-
-// Decode decodes the CellUnion.
-func (cu *CellUnion) Decode(r io.Reader) error {
- d := &decoder{r: asByteReader(r)}
- cu.decode(d)
- return d.err
-}
-
-func (cu *CellUnion) decode(d *decoder) {
- version := d.readInt8()
- if d.err != nil {
- return
- }
- if version != encodingVersion {
- d.err = fmt.Errorf("only version %d is supported", encodingVersion)
- return
- }
- n := d.readInt64()
- if d.err != nil {
- return
- }
- const maxCells = 1000000
- if n > maxCells {
- d.err = fmt.Errorf("too many cells (%d; max is %d)", n, maxCells)
- return
- }
- *cu = make([]CellID, n)
- for i := range *cu {
- (*cu)[i].decode(d)
- }
-}