diff options
author | 2021-08-12 21:03:24 +0200 | |
---|---|---|
committer | 2021-08-12 21:03:24 +0200 | |
commit | 98263a7de64269898a2f81207e38943b5c8e8653 (patch) | |
tree | 743c90f109a6c5d27832d1dcef2388d939f0f77a /vendor/github.com/golang/geo/s2/cell_index.go | |
parent | Text duplication fix (#137) (diff) | |
download | gotosocial-98263a7de64269898a2f81207e38943b5c8e8653.tar.xz |
Grand test fixup (#138)
* start fixing up tests
* fix up tests + automate with drone
* fiddle with linting
* messing about with drone.yml
* some more fiddling
* hmmm
* add cache
* add vendor directory
* verbose
* ci updates
* update some little things
* update sig
Diffstat (limited to 'vendor/github.com/golang/geo/s2/cell_index.go')
-rw-r--r-- | vendor/github.com/golang/geo/s2/cell_index.go | 498 |
1 files changed, 498 insertions, 0 deletions
diff --git a/vendor/github.com/golang/geo/s2/cell_index.go b/vendor/github.com/golang/geo/s2/cell_index.go new file mode 100644 index 000000000..ef16d0895 --- /dev/null +++ b/vendor/github.com/golang/geo/s2/cell_index.go @@ -0,0 +1,498 @@ +// Copyright 2020 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 ( + "sort" +) + +const ( + // A special label indicating that the ContentsIterator done is true. + cellIndexDoneContents = -1 +) + +// cellIndexNode represents a node in the CellIndex. Cells are organized in a +// tree such that the ancestors of a given node contain that node. +type cellIndexNode struct { + cellID CellID + label int32 + parent int32 +} + +// newCellIndexNode returns a node with the appropriate default values. +func newCellIndexNode() cellIndexNode { + return cellIndexNode{ + cellID: 0, + label: cellIndexDoneContents, + parent: -1, + } +} + +// A rangeNode represents a range of leaf CellIDs. The range starts at +// startID (a leaf cell) and ends at the startID field of the next +// rangeNode. contents points to the node of the CellIndex cellTree +// representing the cells that overlap this range. +type rangeNode struct { + startID CellID // First leaf cell contained by this range. + contents int32 // Contents of this node (an index within the cell tree). +} + +// CellIndexIterator is an iterator that visits the entire set of indexed +// (CellID, label) pairs in an unspecified order. +type CellIndexIterator struct { + // TODO(roberts): Implement +} + +// NewCellIndexIterator creates an iterator for the given CellIndex. +func NewCellIndexIterator(index *CellIndex) *CellIndexIterator { + return &CellIndexIterator{} +} + +// CellIndexRangeIterator is an iterator that seeks and iterates over a set of +// non-overlapping leaf cell ranges that cover the entire sphere. The indexed +// (CellID, label) pairs that intersect the current leaf cell range can be +// visited using CellIndexContentsIterator (see below). +type CellIndexRangeIterator struct { + rangeNodes []rangeNode + pos int + nonEmpty bool +} + +// NewCellIndexRangeIterator creates an iterator for the given CellIndex. +// The iterator is initially *unpositioned*; you must call a positioning method +// such as Begin() or Seek() before accessing its contents. +func NewCellIndexRangeIterator(index *CellIndex) *CellIndexRangeIterator { + return &CellIndexRangeIterator{ + rangeNodes: index.rangeNodes, + } +} + +// NewCellIndexNonEmptyRangeIterator creates an iterator for the given CellIndex. +// The iterator is initially *unpositioned*; you must call a positioning method such as +// Begin() or Seek() before accessing its contents. +func NewCellIndexNonEmptyRangeIterator(index *CellIndex) *CellIndexRangeIterator { + return &CellIndexRangeIterator{ + rangeNodes: index.rangeNodes, + nonEmpty: true, + } +} + +// StartID reports the CellID of the start of the current range of leaf CellIDs. +// +// If done is true, this returns the last possible CellID. This property means +// that most loops do not need to test done explicitly. +func (c *CellIndexRangeIterator) StartID() CellID { + return c.rangeNodes[c.pos].startID +} + +// LimitID reports the non-inclusive end of the current range of leaf CellIDs. +// +// This assumes the iterator is not done. +func (c *CellIndexRangeIterator) LimitID() CellID { + return c.rangeNodes[c.pos+1].startID +} + +// IsEmpty reports if no (CellID, label) pairs intersect this range. +// Also returns true if done() is true. +func (c *CellIndexRangeIterator) IsEmpty() bool { + return c.rangeNodes[c.pos].contents == cellIndexDoneContents +} + +// Begin positions the iterator at the first range of leaf cells (if any). +func (c *CellIndexRangeIterator) Begin() { + c.pos = 0 + for c.nonEmpty && c.IsEmpty() && !c.Done() { + c.pos++ + } +} + +// Prev positions the iterator at the previous entry and reports whether it was not +// already positioned at the beginning. +func (c *CellIndexRangeIterator) Prev() bool { + if c.nonEmpty { + return c.nonEmptyPrev() + } + return c.prev() +} + +// prev is used to position the iterator at the previous entry without checking +// if nonEmpty is true to prevent unwanted recursion. +func (c *CellIndexRangeIterator) prev() bool { + if c.pos == 0 { + return false + } + + c.pos-- + return true +} + +// Prev positions the iterator at the previous entry, and reports whether it was +// already positioned at the beginning. +func (c *CellIndexRangeIterator) nonEmptyPrev() bool { + for c.prev() { + if !c.IsEmpty() { + return true + } + } + + // Return the iterator to its original position. + if c.IsEmpty() && !c.Done() { + c.Next() + } + return false +} + +// Next advances the iterator to the next range of leaf cells. +// +// This assumes the iterator is not done. +func (c *CellIndexRangeIterator) Next() { + c.pos++ + for c.nonEmpty && c.IsEmpty() && !c.Done() { + c.pos++ + } +} + +// Advance reports if advancing would leave it positioned on a valid range. If +// the value would not be valid, the positioning is not changed. +func (c *CellIndexRangeIterator) Advance(n int) bool { + // Note that the last element of rangeNodes is a sentinel value. + if n >= len(c.rangeNodes)-1-c.pos { + return false + } + c.pos += n + return true +} + +// Finish positions the iterator so that done is true. +func (c *CellIndexRangeIterator) Finish() { + // Note that the last element of rangeNodes is a sentinel value. + c.pos = len(c.rangeNodes) - 1 +} + +// Done reports if the iterator is positioned beyond the last valid range. +func (c *CellIndexRangeIterator) Done() bool { + return c.pos >= len(c.rangeNodes)-1 +} + +// Seek positions the iterator at the first range with startID >= target. +// Such an entry always exists as long as "target" is a valid leaf cell. +// +// Note that it is valid to access startID even when done is true. +func (c *CellIndexRangeIterator) Seek(target CellID) { + c.pos = sort.Search(len(c.rangeNodes), func(i int) bool { + return c.rangeNodes[i].startID > target + }) - 1 + + // Ensure we don't go beyond the beginning. + if c.pos < 0 { + c.pos = 0 + } + + // Nonempty needs to find the next non-empty entry. + for c.nonEmpty && c.IsEmpty() && !c.Done() { + // c.Next() + c.pos++ + } +} + +// CellIndexContentsIterator is an iterator that visits the (CellID, label) pairs +// that cover a set of leaf cell ranges (see CellIndexRangeIterator). Note that +// when multiple leaf cell ranges are visited, this iterator only guarantees that +// each result will be reported at least once, i.e. duplicate values may be +// suppressed. If you want duplicate values to be reported again, be sure to call +// Clear first. +// +// In particular, the implementation guarantees that when multiple leaf +// cell ranges are visited in monotonically increasing order, then each +// (CellID, label) pair is reported exactly once. +type CellIndexContentsIterator struct { + // The maximum index within the cellTree slice visited during the + // previous call to StartUnion. This is used to eliminate duplicate + // values when StartUnion is called multiple times. + nodeCutoff int32 + + // The maximum index within the cellTree visited during the + // current call to StartUnion. This is used to update nodeCutoff. + nextNodeCutoff int32 + + // The value of startID from the previous call to StartUnion. + // This is used to check whether these values are monotonically + // increasing. + prevStartID CellID + + // The cell tree from CellIndex + cellTree []cellIndexNode + + // A copy of the current node in the cell tree. + node cellIndexNode +} + +// NewCellIndexContentsIterator returns a new contents iterator. +// +// Note that the iterator needs to be positioned using StartUnion before +// it can be safely used. +func NewCellIndexContentsIterator(index *CellIndex) *CellIndexContentsIterator { + it := &CellIndexContentsIterator{ + cellTree: index.cellTree, + prevStartID: 0, + nodeCutoff: -1, + nextNodeCutoff: -1, + node: cellIndexNode{label: cellIndexDoneContents}, + } + return it +} + +// Clear clears all state with respect to which range(s) have been visited. +func (c *CellIndexContentsIterator) Clear() { + c.prevStartID = 0 + c.nodeCutoff = -1 + c.nextNodeCutoff = -1 + c.node.label = cellIndexDoneContents +} + +// CellID returns the current CellID. +func (c *CellIndexContentsIterator) CellID() CellID { + return c.node.cellID +} + +// Label returns the current Label. +func (c *CellIndexContentsIterator) Label() int32 { + return c.node.label +} + +// Next advances the iterator to the next (CellID, label) pair covered by the +// current leaf cell range. +// +// This requires the iterator to not be done. +func (c *CellIndexContentsIterator) Next() { + if c.node.parent <= c.nodeCutoff { + // We have already processed this node and its ancestors. + c.nodeCutoff = c.nextNodeCutoff + c.node.label = cellIndexDoneContents + } else { + c.node = c.cellTree[c.node.parent] + } +} + +// Done reports if all (CellID, label) pairs have been visited. +func (c *CellIndexContentsIterator) Done() bool { + return c.node.label == cellIndexDoneContents +} + +// StartUnion positions the ContentsIterator at the first (cell_id, label) pair +// that covers the given leaf cell range. Note that when multiple leaf cell +// ranges are visited using the same ContentsIterator, duplicate values +// may be suppressed. If you don't want this behavior, call Reset() first. +func (c *CellIndexContentsIterator) StartUnion(r *CellIndexRangeIterator) { + if r.StartID() < c.prevStartID { + c.nodeCutoff = -1 // Can't automatically eliminate duplicates. + } + c.prevStartID = r.StartID() + + contents := r.rangeNodes[r.pos].contents + if contents <= c.nodeCutoff { + c.node.label = cellIndexDoneContents + } else { + c.node = c.cellTree[contents] + } + + // When visiting ancestors, we can stop as soon as the node index is smaller + // than any previously visited node index. Because indexes are assigned + // using a preorder traversal, such nodes are guaranteed to have already + // been reported. + c.nextNodeCutoff = contents +} + +// CellIndex stores a collection of (CellID, label) pairs. +// +// The CellIDs may be overlapping or contain duplicate values. For example, a +// CellIndex could store a collection of CellUnions, where each CellUnion +// gets its own non-negative int32 label. +// +// Similar to ShapeIndex and PointIndex which map each stored element to an +// identifier, CellIndex stores a label that is typically used to map the +// results of queries back to client's specific data. +// +// The zero value for a CellIndex is sufficient when constructing a CellIndex. +// +// To build a CellIndex where each Cell has a distinct label, call Add for each +// (CellID, label) pair, and then Build the index. For example: +// +// // contents is a mapping of an identifier in my system (restaurantID, +// // vehicleID, etc) to a CellID +// var contents = map[int32]CellID{...} +// +// for key, val := range contents { +// index.Add(val, key) +// } +// +// index.Build() +// +// There is also a helper method that adds all elements of CellUnion with the +// same label: +// +// index.AddCellUnion(cellUnion, label) +// +// Note that the index is not dynamic; the contents of the index cannot be +// changed once it has been built. Adding more after calling Build results in +// undefined behavior of the index. +// +// There are several options for retrieving data from the index. The simplest +// is to use a built-in method such as IntersectingLabels (which returns +// the labels of all cells that intersect a given target CellUnion): +// +// labels := index.IntersectingLabels(targetUnion); +// +// Alternatively, you can use a ClosestCellQuery which computes the cell(s) +// that are closest to a given target geometry. +// +// For example, here is how to find all cells that are closer than +// distanceLimit to a given target point: +// +// query := NewClosestCellQuery(cellIndex, opts) +// target := NewMinDistanceToPointTarget(targetPoint); +// for result := range query.FindCells(target) { +// // result.Distance() is the distance to the target. +// // result.CellID() is the indexed CellID. +// // result.Label() is the label associated with the CellID. +// DoSomething(targetPoint, result); +// } +// +// Internally, the index consists of a set of non-overlapping leaf cell ranges +// that subdivide the sphere and such that each range intersects a particular +// set of (cellID, label) pairs. +// +// Most clients should use either the methods such as VisitIntersectingCells +// and IntersectingLabels, or a helper such as ClosestCellQuery. +type CellIndex struct { + // A tree of (cellID, label) pairs such that if X is an ancestor of Y, then + // X.cellID contains Y.cellID. The contents of a given range of leaf + // cells can be represented by pointing to a node of this tree. + cellTree []cellIndexNode + + // The last element of rangeNodes is a sentinel value, which is necessary + // in order to represent the range covered by the previous element. + rangeNodes []rangeNode +} + +// Add adds the given CellID and Label to the index. +func (c *CellIndex) Add(id CellID, label int32) { + if label < 0 { + panic("labels must be non-negative") + } + c.cellTree = append(c.cellTree, cellIndexNode{cellID: id, label: label, parent: -1}) +} + +// AddCellUnion adds all of the elements of the given CellUnion to the index with the same label. +func (c *CellIndex) AddCellUnion(cu CellUnion, label int32) { + if label < 0 { + panic("labels must be non-negative") + } + for _, cell := range cu { + c.Add(cell, label) + } +} + +// Build builds the index for use. This method should only be called once. +func (c *CellIndex) Build() { + // To build the cell tree and leaf cell ranges, we maintain a stack of + // (CellID, label) pairs that contain the current leaf cell. This struct + // represents an instruction to push or pop a (cellID, label) pair. + // + // If label >= 0, the (cellID, label) pair is pushed on the stack. + // If CellID == SentinelCellID, a pair is popped from the stack. + // Otherwise the stack is unchanged but a rangeNode is still emitted. + + // delta represents an entry in a stack of (CellID, label) pairs used in the + // construction of the CellIndex structure. + type delta struct { + startID CellID + cellID CellID + label int32 + } + + deltas := make([]delta, 0, 2*len(c.cellTree)+2) + + // Create two deltas for each (cellID, label) pair: one to add the pair to + // the stack (at the start of its leaf cell range), and one to remove it from + // the stack (at the end of its leaf cell range). + for _, node := range c.cellTree { + deltas = append(deltas, delta{ + startID: node.cellID.RangeMin(), + cellID: node.cellID, + label: node.label, + }) + deltas = append(deltas, delta{ + startID: node.cellID.RangeMax().Next(), + cellID: SentinelCellID, + label: -1, + }) + } + + // We also create two special deltas to ensure that a RangeNode is emitted at + // the beginning and end of the CellID range. + deltas = append(deltas, delta{ + startID: CellIDFromFace(0).ChildBeginAtLevel(maxLevel), + cellID: CellID(0), + label: -1, + }) + deltas = append(deltas, delta{ + startID: CellIDFromFace(5).ChildEndAtLevel(maxLevel), + cellID: CellID(0), + label: -1, + }) + + sort.Slice(deltas, func(i, j int) bool { + // deltas are sorted first by startID, then in reverse order by cellID, + // and then by label. This is necessary to ensure that (1) larger cells + // are pushed on the stack before smaller cells, and (2) cells are popped + // off the stack before any new cells are added. + + if si, sj := deltas[i].startID, deltas[j].startID; si != sj { + return si < sj + } + if si, sj := deltas[i].cellID, deltas[j].cellID; si != sj { + return si > sj + } + return deltas[i].label < deltas[j].label + }) + + // Now walk through the deltas to build the leaf cell ranges and cell tree + // (which is essentially a permanent form of the "stack" described above). + c.cellTree = nil + c.rangeNodes = nil + contents := int32(-1) + for i := 0; i < len(deltas); { + startID := deltas[i].startID + // Process all the deltas associated with the current startID. + for ; i < len(deltas) && deltas[i].startID == startID; i++ { + if deltas[i].label >= 0 { + c.cellTree = append(c.cellTree, cellIndexNode{ + cellID: deltas[i].cellID, + label: deltas[i].label, + parent: contents}) + contents = int32(len(c.cellTree) - 1) + } else if deltas[i].cellID == SentinelCellID { + contents = c.cellTree[contents].parent + } + } + c.rangeNodes = append(c.rangeNodes, rangeNode{startID, contents}) + } +} + +// TODO(roberts): Differences from C++ +// IntersectingLabels +// VisitIntersectingCells +// CellIndexIterator |