Documentation ¶
Overview ¶
Package s2 implements types and functions for working with geometry in S² (spherical geometry).
Its related packages, parallel to this one, are s1 (operates on S¹), r1 (operates on ℝ¹) and r3 (operates on ℝ³).
This package provides types and functions for the S2 cell hierarchy and coordinate systems. The S2 cell hierarchy is a hierarchical decomposition of the surface of a unit sphere (S²) into “cells”; it is highly efficient, scales from continental size to under 1 cm² and preserves spatial locality (nearby cells have close IDs).
A presentation that gives an overview of S2 is https://docs.google.com/presentation/d/1Hl4KapfAENAOf4gv-pSngKwvS_jwNVHRPZTTDzXXn6Q/view.
Index ¶
- Constants
- Variables
- func ClipToFace(a, b Point, face int) (aUV, bUV r2.Point, intersects bool)
- func ClipToPaddedFace(a, b Point, f int, padding float64) (aUV, bUV r2.Point, intersects bool)
- func OrderedCCW(a, b, c, o Point) bool
- func PointArea(a, b, c Point) float64
- func Sign(a, b, c Point) bool
- func SimpleCrossing(a, b, c, d Point) bool
- func VertexCrossing(a, b, c, d Point) bool
- type Cap
- func (c Cap) AddCap(other Cap) Cap
- func (c Cap) AddPoint(p Point) Cap
- func (c Cap) ApproxEqual(other Cap) bool
- func (c Cap) Area() float64
- func (c Cap) CapBound() Cap
- func (c Cap) Center() Point
- func (c Cap) Complement() Cap
- func (c Cap) Contains(other Cap) bool
- func (c Cap) ContainsCell(cell Cell) bool
- func (c Cap) ContainsPoint(p Point) bool
- func (c Cap) Expanded(distance s1.Angle) Cap
- func (c Cap) Height() float64
- func (c Cap) InteriorContainsPoint(p Point) bool
- func (c Cap) InteriorIntersects(other Cap) bool
- func (c Cap) Intersects(other Cap) bool
- func (c Cap) IntersectsCell(cell Cell) bool
- func (c Cap) IsEmpty() bool
- func (c Cap) IsFull() bool
- func (c Cap) IsValid() bool
- func (c Cap) Radius() s1.Angle
- func (c Cap) RectBound() Rect
- func (c Cap) String() string
- type Cell
- func (c Cell) ApproxArea() float64
- func (c Cell) AverageArea() float64
- func (c Cell) CapBound() Cap
- func (c Cell) ContainsCell(oc Cell) bool
- func (c Cell) ContainsPoint(p Point) bool
- func (c Cell) Edge(k int) Point
- func (c Cell) ExactArea() float64
- func (c Cell) IntersectsCell(oc Cell) bool
- func (c Cell) IsLeaf() bool
- func (c Cell) RectBound() Rect
- func (c Cell) SizeIJ() int
- func (c Cell) Vertex(k int) Point
- type CellID
- func (ci CellID) Advance(steps int64) CellID
- func (ci CellID) ChildBegin() CellID
- func (ci CellID) ChildBeginAtLevel(level int) CellID
- func (ci CellID) ChildEnd() CellID
- func (ci CellID) ChildEndAtLevel(level int) CellID
- func (ci CellID) ChildPosition(level int) int
- func (ci CellID) Children() [4]CellID
- func (ci CellID) CommonAncestorLevel(other CellID) (level int, ok bool)
- func (ci CellID) Contains(oci CellID) bool
- func (ci CellID) EdgeNeighbors() [4]CellID
- func (ci CellID) Face() int
- func (ci CellID) Intersects(oci CellID) bool
- func (ci CellID) IsLeaf() bool
- func (ci CellID) IsValid() bool
- func (ci CellID) LatLng() LatLng
- func (ci CellID) Level() int
- func (ci CellID) Next() CellID
- func (ci CellID) Parent(level int) CellID
- func (ci CellID) Point() Point
- func (ci CellID) Pos() uint64
- func (ci CellID) Prev() CellID
- func (ci CellID) RangeMax() CellID
- func (ci CellID) RangeMin() CellID
- func (ci CellID) String() string
- func (ci CellID) ToToken() string
- func (ci CellID) VertexNeighbors(level int) []CellID
- type CellRelation
- type CellUnion
- func (cu *CellUnion) CapBound() Cap
- func (cu *CellUnion) ContainsCell(c Cell) bool
- func (cu *CellUnion) ContainsCellID(id CellID) bool
- func (cu *CellUnion) Denormalize(minLevel, levelMod int)
- func (cu *CellUnion) IntersectsCell(c Cell) bool
- func (cu *CellUnion) IntersectsCellID(id CellID) bool
- func (cu *CellUnion) LeafCellsCovered() int64
- func (cu *CellUnion) Normalize()
- func (cu *CellUnion) RectBound() Rect
- type Crossing
- type Direction
- type EdgeCrosser
- type LatLng
- type Loop
- func (l Loop) CapBound() Cap
- func (l Loop) ContainsCell(c Cell) bool
- func (l Loop) ContainsLoop(l2 Loop) bool
- func (l Loop) ContainsOrigin() bool
- func (l Loop) ContainsPoint(p Point) bool
- func (l Loop) Edge(i int) (a, b Point)
- func (l Loop) HasInterior() bool
- func (l Loop) IntersectsCell(c Cell) bool
- func (l Loop) IntersectsLoop(l2 Loop) bool
- func (l Loop) IsEmpty() bool
- func (l Loop) IsFull() bool
- func (l Loop) NumEdges() int
- func (l Loop) RectBound() Rect
- func (l Loop) Vertex(i int) Point
- func (l Loop) Vertices() []Point
- type Metric
- type Point
- type Polygon
- type Rect
- func (r Rect) AddPoint(ll LatLng) Rect
- func (r Rect) Area() float64
- func (r Rect) CapBound() Cap
- func (r Rect) Center() LatLng
- func (r Rect) Contains(other Rect) bool
- func (r Rect) ContainsCell(c Cell) bool
- func (r Rect) ContainsLatLng(ll LatLng) bool
- func (r Rect) ContainsPoint(p Point) bool
- func (r Rect) Hi() LatLng
- func (r Rect) Intersection(other Rect) Rect
- func (r Rect) Intersects(other Rect) bool
- func (r Rect) IntersectsCell(c Cell) bool
- func (r Rect) IsEmpty() bool
- func (r Rect) IsFull() bool
- func (r Rect) IsPoint() bool
- func (r Rect) IsValid() bool
- func (r Rect) Lo() LatLng
- func (r Rect) PolarClosure() Rect
- func (r Rect) RectBound() Rect
- func (r Rect) Size() LatLng
- func (r Rect) String() string
- func (r Rect) Union(other Rect) Rect
- func (r Rect) Vertex(i int) LatLng
- type RectBounder
- type Region
- type RegionCoverer
- func (rc *RegionCoverer) CellUnion(region Region) CellUnion
- func (rc *RegionCoverer) Covering(region Region) CellUnion
- func (rc *RegionCoverer) FastCovering(cap Cap) CellUnion
- func (rc *RegionCoverer) InteriorCellUnion(region Region) CellUnion
- func (rc *RegionCoverer) InteriorCovering(region Region) CellUnion
- type Shape
- type ShapeIndex
- Bugs
Constants ¶
const ( Clockwise Direction = -1 Indeterminate = 0 CounterClockwise = 1 )
These are the three options for the direction of a set of points.
Variables ¶
var ( MinWidthMetric = Metric{1, 2 * math.Sqrt2 / 3} MaxWidthMetric = Metric{1, 1.704897179199218452} MinAreaMetric = Metric{2, 8 * math.Sqrt2 / 9} AvgAreaMetric = Metric{2, 4 * math.Pi / 6} MaxAreaMetric = Metric{2, 2.635799256963161491} )
Defined metrics. We only support the quadratic projection.
Functions ¶
func ClipToFace ¶
ClipToFace returns the (u,v) coordinates for the portion of the edge AB that intersects the given face, or false if the edge AB does not intersect. This method guarantees that the clipped vertices lie within the [-1,1]x[-1,1] cube face rectangle and are within faceClipErrorUVDist of the line AB, but the results may differ from those produced by faceSegments.
func ClipToPaddedFace ¶
ClipToPaddedFace returns the (u,v) coordinates for the portion of the edge AB that intersects the given face, but rather than clipping to the square [-1,1]x[-1,1] in (u,v) space, this method clips to [-R,R]x[-R,R] where R=(1+padding). Padding must be non-negative.
func OrderedCCW ¶
OrderedCCW returns true if the edges OA, OB, and OC are encountered in that order while sweeping CCW around the point O.
You can think of this as testing whether A <= B <= C with respect to the CCW ordering around O that starts at A, or equivalently, whether B is contained in the range of angles (inclusive) that starts at A and extends CCW to C. Properties:
(1) If OrderedCCW(a,b,c,o) && OrderedCCW(b,a,c,o), then a == b (2) If OrderedCCW(a,b,c,o) && OrderedCCW(a,c,b,o), then b == c (3) If OrderedCCW(a,b,c,o) && OrderedCCW(c,b,a,o), then a == b == c (4) If a == b or b == c, then OrderedCCW(a,b,c,o) is true (5) Otherwise if a == c, then OrderedCCW(a,b,c,o) is false
func PointArea ¶
PointArea returns the area on the unit sphere for the triangle defined by the given points.
This method is based on l'Huilier's theorem,
tan(E/4) = sqrt(tan(s/2) tan((s-a)/2) tan((s-b)/2) tan((s-c)/2))
where E is the spherical excess of the triangle (i.e. its area),
a, b, c are the side lengths, and s is the semiperimeter (a + b + c) / 2.
The only significant source of error using l'Huilier's method is the cancellation error of the terms (s-a), (s-b), (s-c). This leads to a *relative* error of about 1e-16 * s / min(s-a, s-b, s-c). This compares to a relative error of about 1e-15 / E using Girard's formula, where E is the true area of the triangle. Girard's formula can be even worse than this for very small triangles, e.g. a triangle with a true area of 1e-30 might evaluate to 1e-5.
So, we prefer l'Huilier's formula unless dmin < s * (0.1 * E), where dmin = min(s-a, s-b, s-c). This basically includes all triangles except for extremely long and skinny ones.
Since we don't know E, we would like a conservative upper bound on the triangle area in terms of s and dmin. It's possible to show that E <= k1 * s * sqrt(s * dmin), where k1 = 2*sqrt(3)/Pi (about 1). Using this, it's easy to show that we should always use l'Huilier's method if dmin >= k2 * s^5, where k2 is about 1e-2. Furthermore, if dmin < k2 * s^5, the triangle area is at most k3 * s^4, where k3 is about 0.1. Since the best case error using Girard's formula is about 1e-15, this means that we shouldn't even consider it unless s >= 3e-4 or so.
func Sign ¶
Sign returns true if the points A, B, C are strictly counterclockwise, and returns false if the points are clockwise or collinear (i.e. if they are all contained on some great circle).
Due to numerical errors, situations may arise that are mathematically impossible, e.g. ABC may be considered strictly CCW while BCA is not. However, the implementation guarantees the following:
If Sign(a,b,c), then !Sign(c,b,a) for all a,b,c.
func SimpleCrossing ¶
SimpleCrossing reports whether edge AB crosses CD at a point that is interior to both edges. Properties:
(1) SimpleCrossing(b,a,c,d) == SimpleCrossing(a,b,c,d) (2) SimpleCrossing(c,d,a,b) == SimpleCrossing(a,b,c,d)
func VertexCrossing ¶
VertexCrossing reports whether two edges "cross" in such a way that point-in-polygon containment tests can be implemented by counting the number of edge crossings.
Given two edges AB and CD where at least two vertices are identical (i.e. CrossingSign(a,b,c,d) == 0), the basic rule is that a "crossing" occurs if AB is encountered after CD during a CCW sweep around the shared vertex starting from a fixed reference point.
Note that according to this rule, if AB crosses CD then in general CD does not cross AB. However, this leads to the correct result when counting polygon edge crossings. For example, suppose that A,B,C are three consecutive vertices of a CCW polygon. If we now consider the edge crossings of a segment BP as P sweeps around B, the crossing number changes parity exactly when BP crosses BA or BC.
Useful properties of VertexCrossing (VC):
(1) VC(a,a,c,d) == VC(a,b,c,c) == false (2) VC(a,b,a,b) == VC(a,b,b,a) == true (3) VC(a,b,c,d) == VC(a,b,d,c) == VC(b,a,c,d) == VC(b,a,d,c) (3) If exactly one of a,b equals one of c,d, then exactly one of VC(a,b,c,d) and VC(c,d,a,b) is true
It is an error to call this method with 4 distinct vertices.
Types ¶
type Cap ¶
type Cap struct {
// contains filtered or unexported fields
}
Cap represents a disc-shaped region defined by a center and radius. Technically this shape is called a "spherical cap" (rather than disc) because it is not planar; the cap represents a portion of the sphere that has been cut off by a plane. The boundary of the cap is the circle defined by the intersection of the sphere and the plane. For containment purposes, the cap is a closed set, i.e. it contains its boundary.
For the most part, you can use a spherical cap wherever you would use a disc in planar geometry. The radius of the cap is measured along the surface of the sphere (rather than the straight-line distance through the interior). Thus a cap of radius π/2 is a hemisphere, and a cap of radius π covers the entire sphere.
The center is a point on the surface of the unit sphere. (Hence the need for it to be of unit length.)
Internally, the cap is represented by its center and "height". The height is the distance from the center point to the cutoff plane. This representation is much more efficient for containment tests than the (center, radius) representation. There is also support for "empty" and "full" caps, which contain no points and all points respectively.
The zero value of Cap is an invalid cap. Use EmptyCap to get a valid empty cap.
func CapFromCenterAngle ¶
CapFromCenterAngle constructs a cap with the given center and angle.
func CapFromCenterArea ¶
CapFromCenterArea constructs a cap with the given center and surface area. Note that the area can also be interpreted as the solid angle subtended by the cap (because the sphere has unit radius). A negative area yields an empty cap; an area of 4*π or more yields a full cap.
func CapFromCenterHeight ¶
CapFromCenterHeight constructs a cap with the given center and height. A negative height yields an empty cap; a height of 2 or more yields a full cap.
func CapFromPoint ¶
CapFromPoint constructs a cap containing a single point.
func (Cap) AddCap ¶
AddCap increases the cap height if necessary to include the other cap. If this cap is empty, it is set to the other cap.
func (Cap) AddPoint ¶
AddPoint increases the cap if necessary to include the given point. If this cap is empty, then the center is set to the point with a zero height. p must be unit-length.
func (Cap) ApproxEqual ¶
ApproxEqual reports if this caps' center and height are within a reasonable epsilon from the other cap.
func (Cap) CapBound ¶
CapBound returns a bounding spherical cap. This is not guaranteed to be exact.
func (Cap) Complement ¶
Complement returns the complement of the interior of the cap. A cap and its complement have the same boundary but do not share any interior points. The complement operator is not a bijection because the complement of a singleton cap (containing a single point) is the same as the complement of an empty cap.
func (Cap) ContainsCell ¶
ContainsCell reports whether the cap contains the given cell.
func (Cap) ContainsPoint ¶
ContainsPoint reports whether this cap contains the point.
func (Cap) Expanded ¶
Expanded returns a new cap expanded by the given angle. If the cap is empty, it returns an empty cap.
func (Cap) InteriorContainsPoint ¶
InteriorContainsPoint reports whether the point is within the interior of this cap.
func (Cap) InteriorIntersects ¶
InteriorIntersects reports whether this caps interior intersects the other cap.
func (Cap) Intersects ¶
Intersects reports whether this cap intersects the other cap. i.e. whether they have any points in common.
func (Cap) IntersectsCell ¶
IntersectsCell reports whether the cap intersects the cell.
func (Cap) IsValid ¶
IsValid reports whether the Cap is considered valid. Heights are normalized so that they do not exceed 2.
type Cell ¶
type Cell struct {
// contains filtered or unexported fields
}
Cell is an S2 region object that represents a cell. Unlike CellIDs, it supports efficient containment and intersection tests. However, it is also a more expensive representation.
func CellFromCellID ¶
CellFromCellID constructs a Cell corresponding to the given CellID.
func CellFromLatLng ¶
CellFromLatLng constructs a cell for the given LatLng.
func CellFromPoint ¶
CellFromPoint constructs a cell for the given Point.
func (Cell) ApproxArea ¶
ApproxArea returns the approximate area of this cell. 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 (i.e. squares 350km to a side or smaller on the Earth's surface). It is moderately cheap to compute.
func (Cell) AverageArea ¶
AverageArea returns the average area of cells at the level of this cell. This is accurate to within a factor of 1.7.
func (Cell) ContainsCell ¶
ContainsCell reports whether this cell contains the other cell.
func (Cell) ContainsPoint ¶
ContainsPoint reports whether this cell contains the given point. Note that unlike Loop/Polygon, a Cell is considered to be a closed set. This means that a point on a Cell's edge or vertex belong to the Cell and the relevant adjacent Cells too.
If you want every point to be contained by exactly one Cell, you will need to convert the Cell to a Loop.
func (Cell) Edge ¶
Edge returns the inward-facing normal of the great circle passing through the CCW ordered edge from vertex k to vertex k+1 (mod 4).
func (Cell) IntersectsCell ¶
IntersectsCell reports whether the intersection of this cell and the other cell is not nil.
type CellID ¶
type CellID uint64
CellID uniquely identifies a cell in the S2 cell decomposition. The most significant 3 bits encode the face number (0-5). The remaining 61 bits encode the position of the center of this cell along the Hilbert curve on that face. The zero value and the value (1<<64)-1 are invalid cell IDs. The first compares less than any valid cell ID, the second as greater than any valid cell ID.
func CellIDFromFace ¶
CellIDFromFace returns the cell corresponding to a given S2 cube face.
func CellIDFromFacePosLevel ¶
CellIDFromFacePosLevel returns a cell given its face in the range [0,5], the 61-bit Hilbert curve position pos within that face, and the level in the range [0,maxLevel]. The position in the cell ID will be truncated to correspond to the Hilbert curve position at the center of the returned cell.
func CellIDFromLatLng ¶
CellIDFromLatLng returns the leaf cell containing ll.
func CellIDFromToken ¶
CellIDFromToken returns a cell given a hex-encoded string of its uint64 ID.
func (CellID) Advance ¶
Advance advances or retreats the indicated number of steps along the Hilbert curve at the current level, and returns the new position. The position is never advanced past End() or before Begin().
func (CellID) ChildBegin ¶
ChildBegin returns the first child in a traversal of the children of this cell, in Hilbert curve order.
for ci := c.ChildBegin(); ci != c.ChildEnd(); ci = ci.Next() { ... }
func (CellID) ChildBeginAtLevel ¶
ChildBeginAtLevel returns the first cell in a traversal of children a given level deeper than this cell, in Hilbert curve order. The given level must be no smaller than the cell's level.
func (CellID) ChildEnd ¶
ChildEnd returns the first cell after a traversal of the children of this cell in Hilbert curve order. The returned cell may be invalid.
func (CellID) ChildEndAtLevel ¶
ChildEndAtLevel returns the first cell after the last child in a traversal of children a given level deeper than this cell, in Hilbert curve order. The given level must be no smaller than the cell's level. The returned cell may be invalid.
func (CellID) ChildPosition ¶
ChildPosition returns the child position (0..3) of this cell's ancestor at the given level, relative to its parent. The argument should be in the range 1..kMaxLevel. For example, ChildPosition(1) returns the position of this cell's level-1 ancestor within its top-level face cell.
func (CellID) Children ¶
Children returns the four immediate children of this cell. If ci is a leaf cell, it returns four identical cells that are not the children.
func (CellID) CommonAncestorLevel ¶
CommonAncestorLevel returns the level of the common ancestor of the two S2 CellIDs.
func (CellID) EdgeNeighbors ¶
EdgeNeighbors returns the four cells that are adjacent across the cell's four edges. Edges 0, 1, 2, 3 are in the down, right, up, left directions in the face space. All neighbors are guaranteed to be distinct.
func (CellID) Intersects ¶
Intersects returns true iff the CellID intersects oci.
func (CellID) IsLeaf ¶
IsLeaf returns whether this cell ID is at the deepest level; that is, the level at which the cells are smallest.
func (CellID) Level ¶
Level returns the subdivision level of this cell ID, in the range [0, maxLevel].
func (CellID) Next ¶
Next returns the next cell along the Hilbert curve. This is expected to be used with ChildStart and ChildEnd.
func (CellID) Parent ¶
Parent returns the cell at the given level, which must be no greater than the current level.
func (CellID) Point ¶
Point returns the center of the s2 cell on the sphere as a Point. The maximum directional error in Point (compared to the exact mathematical result) is 1.5 * dblEpsilon radians, and the maximum length error is 2 * dblEpsilon (the same as Normalize).
func (CellID) Pos ¶
Pos returns the position along the Hilbert curve of this cell ID, in the range [0,2^posBits-1].
func (CellID) String ¶
String returns the string representation of the cell ID in the form "1/3210".
func (CellID) ToToken ¶
ToToken returns a hex-encoded string of the uint64 cell id, with leading zeros included but trailing zeros stripped.
func (CellID) VertexNeighbors ¶
VertexNeighbors returns the neighboring cellIDs with vertex closest to this cell at the given level. (Normally there are four neighbors, but the closest vertex may only have three neighbors if it is one of the 8 cube vertices.)
type CellRelation ¶
type CellRelation int
CellRelation describes the possible relationships between a target cell and the cells of the ShapeIndex. If the target is an index cell or is contained by an index cell, it is Indexed. If the target is subdivided into one or more index cells, it is Subdivided. Otherwise it is Disjoint.
const ( Indexed CellRelation = iota Subdivided Disjoint )
The possible CellRelations for a ShapeIndex.
type CellUnion ¶
type CellUnion []CellID
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.
func (*CellUnion) ContainsCell ¶
ContainsCell reports whether this cell union contains the given cell.
func (*CellUnion) ContainsCellID ¶
ContainsCellID reports whether the cell union contains the given cell ID. Containment is defined with respect to regions, e.g. a cell contains its 4 children.
This method assumes that the CellUnion has been normalized.
func (*CellUnion) Denormalize ¶
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 (*CellUnion) IntersectsCell ¶
IntersectsCell reports whether this cell union intersects the given cell.
func (*CellUnion) IntersectsCellID ¶
IntersectsCellID reports whether this cell union intersects the given cell ID.
This method assumes that the CellUnion has been normalized.
func (*CellUnion) LeafCellsCovered ¶
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.
type Direction ¶
type Direction int
Direction is an indication of the ordering of a set of points
func RobustSign ¶
RobustSign returns a Direction representing the ordering of the points. CounterClockwise is returned if the points are in counter-clockwise order, Clockwise for clockwise, and Indeterminate if any two points are the same (collinear), or the sign could not completely be determined.
This function has additional logic to make sure that the above properties hold even when the three points are coplanar, and to deal with the limitations of floating-point arithmetic.
RobustSign satisfies the following conditions:
(1) RobustSign(a,b,c) == Indeterminate if and only if a == b, b == c, or c == a (2) RobustSign(b,c,a) == RobustSign(a,b,c) for all a,b,c (3) RobustSign(c,b,a) == -RobustSign(a,b,c) for all a,b,c
In other words:
(1) The result is Indeterminate if and only if two points are the same. (2) Rotating the order of the arguments does not affect the result. (3) Exchanging any two arguments inverts the result.
On the other hand, note that it is not true in general that RobustSign(-a,b,c) == -RobustSign(a,b,c), or any similar identities involving antipodal points.
type EdgeCrosser ¶
type EdgeCrosser struct {
// contains filtered or unexported fields
}
EdgeCrosser allows edges to be efficiently tested for intersection with a given fixed edge AB. It is especially efficient when testing for intersection with an edge chain connecting vertices v0, v1, v2, ...
func NewChainEdgeCrosser ¶
func NewChainEdgeCrosser(a, b, c Point) *EdgeCrosser
NewChainEdgeCrosser is a convenience constructor that uses AB as the fixed edge, and C as the first vertex of the vertex chain (equivalent to calling RestartAt(c)).
You don't need to use this or any of the chain functions unless you're trying to squeeze out every last drop of performance. Essentially all you are saving is a test whether the first vertex of the current edge is the same as the second vertex of the previous edge.
func NewEdgeCrosser ¶
func NewEdgeCrosser(a, b Point) *EdgeCrosser
NewEdgeCrosser returns an EdgeCrosser with the fixed edge AB.
func (*EdgeCrosser) ChainCrossingSign ¶
func (e *EdgeCrosser) ChainCrossingSign(d Point) Crossing
ChainCrossingSign is like CrossingSign, but uses the last vertex passed to one of the crossing methods (or RestartAt) as the first vertex of the current edge.
func (*EdgeCrosser) CrossingSign ¶
func (e *EdgeCrosser) CrossingSign(c, d Point) Crossing
CrossingSign reports whether the edge AB intersects the edge CD. If any two vertices from different edges are the same, returns MaybeCross. If either edge is degenerate (A == B or C == D), returns DoNotCross or MaybeCross.
Properties of CrossingSign:
(1) CrossingSign(b,a,c,d) == CrossingSign(a,b,c,d) (2) CrossingSign(c,d,a,b) == CrossingSign(a,b,c,d) (3) CrossingSign(a,b,c,d) == MaybeCross if a==c, a==d, b==c, b==d (3) CrossingSign(a,b,c,d) == DoNotCross or MaybeCross if a==b or c==d
Note that if you want to check an edge against a chain of other edges, it is slightly more efficient to use the single-argument version ChainCrossingSign below.
func (*EdgeCrosser) EdgeOrVertexChainCrossing ¶
func (e *EdgeCrosser) EdgeOrVertexChainCrossing(d Point) bool
EdgeOrVertexChainCrossing is like EdgeOrVertexCrossing, but uses the last vertex passed to one of the crossing methods (or RestartAt) as the first vertex of the current edge.
func (*EdgeCrosser) EdgeOrVertexCrossing ¶
func (e *EdgeCrosser) EdgeOrVertexCrossing(c, d Point) bool
EdgeOrVertexCrossing reports whether if CrossingSign(c, d) > 0, or AB and CD share a vertex and VertexCrossing(a, b, c, d) is true.
This method extends the concept of a "crossing" to the case where AB and CD have a vertex in common. The two edges may or may not cross, according to the rules defined in VertexCrossing above. The rules are designed so that point containment tests can be implemented simply by counting edge crossings. Similarly, determining whether one edge chain crosses another edge chain can be implemented by counting.
func (*EdgeCrosser) RestartAt ¶
func (e *EdgeCrosser) RestartAt(c Point)
RestartAt sets the current point of the edge crosser to be c. Call this method when your chain 'jumps' to a new place. The argument must point to a value that persists until the next call.
type LatLng ¶
LatLng represents a point on the unit sphere as a pair of angles.
func LatLngFromDegrees ¶
LatLngFromDegrees returns a LatLng for the coordinates given in degrees.
func LatLngFromPoint ¶
LatLngFromPoint returns an LatLng for a given Point.
func (LatLng) IsValid ¶
IsValid returns true iff the LatLng is normalized, with Lat ∈ [-π/2,π/2] and Lng ∈ [-π,π].
func (LatLng) Normalized ¶
Normalized returns the normalized version of the LatLng, with Lat clamped to [-π/2,π/2] and Lng wrapped in [-π,π].
type Loop ¶
type Loop struct {
// contains filtered or unexported fields
}
Loop represents a simple spherical polygon. It consists of a sequence of vertices where the first vertex is implicitly connected to the last. All loops are defined to have a CCW orientation, i.e. the interior of the loop is on the left side of the edges. This implies that a clockwise loop enclosing a small area is interpreted to be a CCW loop enclosing a very large area.
Loops are not allowed to have any duplicate vertices (whether adjacent or not), and non-adjacent edges are not allowed to intersect. Loops must have at least 3 vertices (except for the "empty" and "full" loops discussed below).
There are two special loops: the "empty" loop contains no points and the "full" loop contains all points. These loops do not have any edges, but to preserve the invariant that every loop can be represented as a vertex chain, they are defined as having exactly one vertex each (see EmptyLoop and FullLoop).
func LoopFromCell ¶
LoopFromCell constructs a loop corresponding to the given cell.
Note that the loop and cell *do not* contain exactly the same set of points, because Loop and Cell have slightly different definitions of point containment. For example, a Cell vertex is contained by all four neighboring Cells, but it is contained by exactly one of four Loops constructed from those cells. As another example, the cell coverings of cell and LoopFromCell(cell) will be different, because the loop contains points on its boundary that actually belong to other cells (i.e., the covering will include a layer of neighboring cells).
func LoopFromPoints ¶
LoopFromPoints constructs a loop from the given points.
func (Loop) CapBound ¶
CapBound returns a bounding cap that may have more padding than the corresponding RectBound. The bound is conservative such that if the loop contains a point P, the bound also contains it.
func (Loop) ContainsCell ¶
ContainsCell checks whether the cell is completely enclosed by this loop. Does not count for loop interior and uses raycasting.
func (Loop) ContainsLoop ¶
func (Loop) ContainsOrigin ¶
ContainsOrigin reports true if this loop contains s2.OriginPoint().
func (Loop) ContainsPoint ¶
ContainsPoint returns true if the loop contains the point.
func (Loop) HasInterior ¶
HasInterior returns true because all loops have an interior.
func (Loop) IntersectsCell ¶
IntersectsCell checks if any edge of the cell intersects the loop. Does not count for loop interior and uses raycasting.
func (Loop) IntersectsLoop ¶
IntersectsLoop checks if any edge of the given loop intersects the loop. Does not count for loop interior and uses raycasting
func (Loop) IsEmpty ¶
IsEmpty reports true if this is the special "empty" loop that contains no points.
func (Loop) IsFull ¶
IsFull reports true if this is the special "full" loop that contains all points.
func (Loop) RectBound ¶
RectBound returns a tight bounding rectangle. If the loop contains the point, the bound also contains it.
type Metric ¶
type Metric struct { // Dim is either 1 or 2, for a 1D or 2D metric respectively. Dim int // Deriv is the scaling factor for the metric. Deriv float64 }
A Metric is a measure for cells.
func (Metric) MaxLevel ¶
MaxLevel returns the maximum level such that the metric is at least the given value, or zero if there is no such level.
type Point ¶
Point represents a point on the unit sphere as a normalized 3D vector.
Points are guaranteed to be close to normalized.
Fields should be treated as read-only. Use one of the factory methods for creation.
func Interpolate ¶
Interpolate returns the point X along the line segment AB whose distance from A is the given fraction "t" of the distance AB. Does NOT require that "t" be between 0 and 1. Note that all distances are measured on the surface of the sphere, so this is more complicated than just computing (1-t)*a + t*b and normalizing the result.
func InterpolateAtDistance ¶
InterpolateAtDistance returns the point X along the line segment AB whose distance from A is the angle ax.
func OriginPoint ¶
func OriginPoint() Point
OriginPoint returns a unique "origin" on the sphere for operations that need a fixed reference point. In particular, this is the "point at infinity" used for point-in-polygon testing (by counting the number of edge crossings).
It should *not* be a point that is commonly used in edge tests in order to avoid triggering code to handle degenerate cases (this rules out the north and south poles). It should also not be on the boundary of any low-level S2Cell for the same reason.
func PlanarCentroid ¶
PlanarCentroid returns the centroid of the planar triangle ABC, which is not normalized. It can be normalized to unit length to obtain the "surface centroid" of the corresponding spherical triangle, i.e. the intersection of the three medians. However, note that for large spherical triangles the surface centroid may be nowhere near the intuitive "center" (see example in TrueCentroid comments).
Note that the surface centroid may be nowhere near the intuitive "center" of a spherical triangle. For example, consider the triangle with vertices A=(1,eps,0), B=(0,0,1), C=(-1,eps,0) (a quarter-sphere). The surface centroid of this triangle is at S=(0, 2*eps, 1), which is within a distance of 2*eps of the vertex B. Note that the median from A (the segment connecting A to the midpoint of BC) passes through S, since this is the shortest path connecting the two endpoints. On the other hand, the true centroid is at M=(0, 0.5, 0.5), which when projected onto the surface is a much more reasonable interpretation of the "center" of this triangle.
func PointFromCoords ¶
PointFromCoords creates a new normalized point from coordinates.
This always returns a valid point. If the given coordinates can not be normalized the origin point will be returned.
This behavior is different from the C++ construction of a S2Point from coordinates (i.e. S2Point(x, y, z)) in that in C++ they do not Normalize.
func PointFromLatLng ¶
PointFromLatLng returns an Point for the given LatLng. The maximum error in the result is 1.5 * dblEpsilon. (This does not include the error of converting degrees, E5, E6, or E7 into radians.)
func TrueCentroid ¶
TrueCentroid returns the true centroid of the spherical triangle ABC multiplied by the signed area of spherical triangle ABC. The result is not normalized. The reasons for multiplying by the signed area are (1) this is the quantity that needs to be summed to compute the centroid of a union or difference of triangles, and (2) it's actually easier to calculate this way. All points must have unit length.
The true centroid (mass centroid) is defined as the surface integral over the spherical triangle of (x,y,z) divided by the triangle area. This is the point that the triangle would rotate around if it was spinning in empty space.
The best centroid for most purposes is the true centroid. Unlike the planar and surface centroids, the true centroid behaves linearly as regions are added or subtracted. That is, if you split a triangle into pieces and compute the average of their centroids (weighted by triangle area), the result equals the centroid of the original triangle. This is not true of the other centroids.
func (Point) ApproxEqual ¶
ApproxEqual reports if the two points are similar enough to be equal.
func (Point) PointCross ¶
PointCross returns a Point that is orthogonal to both p and op. This is similar to p.Cross(op) (the true cross product) except that it does a better job of ensuring orthogonality when the Point is nearly parallel to op, it returns a non-zero result even when p == op or p == -op and the result is a Point, so it will have norm 1.
It satisfies the following properties (f == PointCross):
(1) f(p, op) != 0 for all p, op (2) f(op,p) == -f(p,op) unless p == op or p == -op (3) f(-p,op) == -f(p,op) unless p == op or p == -op (4) f(p,-op) == -f(p,op) unless p == op or p == -op
type Polygon ¶
type Polygon struct {
// contains filtered or unexported fields
}
Polygon represents a sequence of zero or more loops; recall that the interior of a loop is defined to be its left-hand side (see Loop).
When the polygon is initialized, the given loops are automatically converted into a canonical form consisting of "shells" and "holes". Shells and holes are both oriented CCW, and are nested hierarchically. The loops are reordered to correspond to a preorder traversal of the nesting hierarchy.
Polygons may represent any region of the sphere with a polygonal boundary, including the entire sphere (known as the "full" polygon). The full polygon consists of a single full loop (see Loop), whereas the empty polygon has no loops at all.
Use FullPolygon() to construct a full polygon. The zero value of Polygon is treated as the empty polygon.
Polygons have the following restrictions:
Loops may not cross, i.e. the boundary of a loop may not intersect both the interior and exterior of any other loop.
Loops may not share edges, i.e. if a loop contains an edge AB, then no other loop may contain AB or BA.
Loops may share vertices, however no vertex may appear twice in a single loop (see Loop).
No loop may be empty. The full loop may appear only in the full polygon.
func PolygonFromLoops ¶
PolygonFromLoops constructs a polygon from the given hierarchically nested loops. The polygon interior consists of the points contained by an odd number of loops. (Recall that a loop contains the set of points on its left-hand side.)
This method figures out the loop nesting hierarchy and assigns every loop a depth. Shells have even depths, and holes have odd depths.
NOTE: this function is NOT YET IMPLEMENTED for more than one loop and will panic if given a slice of length > 1.
func (*Polygon) IsEmpty ¶
IsEmpty reports whether this is the special "empty" polygon (consisting of no loops).
type Rect ¶
Rect represents a closed latitude-longitude rectangle.
func ExpandForSubregions ¶
ExpandForSubregions expands a bounding Rect so that it is guaranteed to contain the bounds of any subregion whose bounds are computed using ComputeRectBound. For example, consider a loop L that defines a square. GetBound ensures that if a point P is contained by this square, then LatLngFromPoint(P) is contained by the bound. But now consider a diamond shaped loop S contained by L. It is possible that GetBound returns a *larger* bound for S than it does for L, due to rounding errors. This method expands the bound for L so that it is guaranteed to contain the bounds of any subregion S.
More precisely, if L is a loop that does not contain either pole, and S is a loop such that L.Contains(S), then
ExpandForSubregions(L.RectBound).Contains(S.RectBound).
func RectFromCenterSize ¶
RectFromCenterSize constructs a rectangle with the given size and center. center needs to be normalized, but size does not. The latitude interval of the result is clamped to [-90,90] degrees, and the longitude interval of the result is FullRect() if and only if the longitude size is 360 degrees or more.
Examples of clamping (in degrees):
center=(80,170), size=(40,60) -> lat=[60,90], lng=[140,-160] center=(10,40), size=(210,400) -> lat=[-90,90], lng=[-180,180] center=(-90,180), size=(20,50) -> lat=[-90,-80], lng=[155,-155]
func RectFromLatLng ¶
RectFromLatLng constructs a rectangle containing a single point p.
func (Rect) ContainsCell ¶
ContainsCell reports whether the given Cell is contained by this Rect.
func (Rect) ContainsLatLng ¶
ContainsLatLng reports whether the given LatLng is within the Rect.
func (Rect) ContainsPoint ¶
ContainsPoint reports whether the given Point is within the Rect.
func (Rect) Intersection ¶
Intersection returns the smallest rectangle containing the intersection of this rectangle and the given rectangle. Note that the region of intersection may consist of two disjoint rectangles, in which case a single rectangle spanning both of them is returned.
func (Rect) Intersects ¶
Intersects reports whether this rectangle and the other have any points in common.
func (Rect) IntersectsCell ¶
IntersectsCell reports whether this rectangle intersects the given cell. This is an exact test and may be fairly expensive.
func (Rect) IsValid ¶
IsValid returns true iff the rectangle is valid. This requires Lat ⊆ [-π/2,π/2] and Lng ⊆ [-π,π], and Lat = ∅ iff Lng = ∅
func (Rect) PolarClosure ¶
PolarClosure returns the rectangle unmodified if it does not include either pole. If it includes either pole, PolarClosure returns an expansion of the rectangle along the longitudinal range to include all possible representations of the contained poles.
type RectBounder ¶
type RectBounder struct {
// contains filtered or unexported fields
}
RectBounder is used to compute a bounding rectangle that contains all edges defined by a vertex chain (v0, v1, v2, ...). All vertices must be unit length. Note that the bounding rectangle of an edge can be larger than the bounding rectangle of its endpoints, e.g. consider an edge that passes through the North Pole.
The bounds are calculated conservatively to account for numerical errors when points are converted to LatLngs. More precisely, this function guarantees the following: Let L be a closed edge chain (Loop) such that the interior of the loop does not contain either pole. Now if P is any point such that L.ContainsPoint(P), then RectBound(L).ContainsPoint(LatLngFromPoint(P)).
func NewRectBounder ¶
func NewRectBounder() *RectBounder
NewRectBounder returns a new instance of a RectBounder.
func (*RectBounder) AddPoint ¶
func (r *RectBounder) AddPoint(b Point)
AddPoint adds the given point to the chain. The Point must be unit length.
func (*RectBounder) RectBound ¶
func (r *RectBounder) RectBound() Rect
RectBound returns the bounding rectangle of the edge chain that connects the vertices defined so far. This bound satisfies the guarantee made above, i.e. if the edge chain defines a Loop, then the bound contains the LatLng coordinates of all Points contained by the loop.
type Region ¶
type Region interface { // CapBound returns a bounding spherical cap. This is not guaranteed to be exact. CapBound() Cap // RectBound returns a bounding latitude-longitude rectangle that contains // the region. The bounds are not guaranteed to be tight. RectBound() Rect // ContainsCell reports whether the region completely contains the given region. // It returns false if containment could not be determined. ContainsCell(c Cell) bool // IntersectsCell reports whether the region intersects the given cell or // if intersection could not be determined. It returns false if the region // does not intersect. IntersectsCell(c Cell) bool }
A Region represents a two-dimensional region on the unit sphere.
The purpose of this interface is to allow complex regions to be approximated as simpler regions. The interface is restricted to methods that are useful for computing approximations.
type RegionCoverer ¶
type RegionCoverer struct { MinLevel int // the minimum cell level to be used. MaxLevel int // the maximum cell level to be used. LevelMod int // the LevelMod to be used. MaxCells int // the maximum desired number of cells in the approximation. }
RegionCoverer allows arbitrary regions to be approximated as unions of cells (CellUnion). This is useful for implementing various sorts of search and precomputation operations.
Typical usage:
rc := &s2.RegionCoverer{MaxLevel: 30, MaxCells: 5} r := s2.Region(CapFromCenterArea(center, area)) covering := rc.Covering(r)
This yields a CellUnion of at most 5 cells that is guaranteed to cover the given region (a disc-shaped region on the sphere).
For covering, only cells where (level - MinLevel) is a multiple of LevelMod will be used. This effectively allows the branching factor of the S2 CellID hierarchy to be increased. Currently the only parameter values allowed are 0/1, 2, or 3, corresponding to branching factors of 4, 16, and 64 respectively.
Note the following:
MinLevel takes priority over MaxCells, i.e. cells below the given level will never be used even if this causes a large number of cells to be returned.
For any setting of MaxCells, up to 6 cells may be returned if that is the minimum number of cells required (e.g. if the region intersects all six face cells). Up to 3 cells may be returned even for very tiny convex regions if they happen to be located at the intersection of three cube faces.
For any setting of MaxCells, an arbitrary number of cells may be returned if MinLevel is too high for the region being approximated.
If MaxCells is less than 4, the area of the covering may be arbitrarily large compared to the area of the original region even if the region is convex (e.g. a Cap or Rect).
The approximation algorithm is not optimal but does a pretty good job in practice. The output does not always use the maximum number of cells allowed, both because this would not always yield a better approximation, and because MaxCells is a limit on how much work is done exploring the possible covering as well as a limit on the final output size.
Because it is an approximation algorithm, one should not rely on the stability of the output. In particular, the output of the covering algorithm may change across different versions of the library.
One can also generate interior coverings, which are sets of cells which are entirely contained within a region. Interior coverings can be empty, even for non-empty regions, if there are no cells that satisfy the provided constraints and are contained by the region. Note that for performance reasons, it is wise to specify a MaxLevel when computing interior coverings - otherwise for regions with small or zero area, the algorithm may spend a lot of time subdividing cells all the way to leaf level to try to find contained cells.
func (*RegionCoverer) CellUnion ¶
func (rc *RegionCoverer) CellUnion(region Region) CellUnion
CellUnion returns a normalized CellUnion that covers the given region and satisfies the restrictions except for minLevel and levelMod. These criteria cannot be satisfied using a cell union because cell unions are automatically normalized by replacing four child cells with their parent whenever possible. (Note that the list of cell ids passed to the CellUnion constructor does in fact satisfy all the given restrictions.)
func (*RegionCoverer) Covering ¶
func (rc *RegionCoverer) Covering(region Region) CellUnion
Covering returns a CellUnion that covers the given region and satisfies the various restrictions.
func (*RegionCoverer) FastCovering ¶
func (rc *RegionCoverer) FastCovering(cap Cap) CellUnion
FastCovering returns a CellUnion that covers the given region similar to Covering, except that this method is much faster and the coverings are not as tight. All of the usual parameters are respected (MaxCells, MinLevel, MaxLevel, and LevelMod), except that the implementation makes no attempt to take advantage of large values of MaxCells. (A small number of cells will always be returned.)
This function is useful as a starting point for algorithms that recursively subdivide cells.
func (*RegionCoverer) InteriorCellUnion ¶
func (rc *RegionCoverer) InteriorCellUnion(region Region) CellUnion
InteriorCellUnion returns a normalized CellUnion that is contained within the given region and satisfies the restrictions except for minLevel and levelMod. These criteria cannot be satisfied using a cell union because cell unions are automatically normalized by replacing four child cells with their parent whenever possible. (Note that the list of cell ids passed to the CellUnion constructor does in fact satisfy all the given restrictions.)
func (*RegionCoverer) InteriorCovering ¶
func (rc *RegionCoverer) InteriorCovering(region Region) CellUnion
InteriorCovering returns a CellUnion that is contained within the given region and satisfies the various restrictions.
type Shape ¶
type Shape interface { // NumEdges returns the number of edges in this shape. NumEdges() int // Edge returns endpoints for the given edge index. Edge(i int) (a, b Point) // HasInterior returns true if this shape has an interior. // i.e. the Shape consists of one or more closed non-intersecting loops. HasInterior() bool // ContainsOrigin returns true if this shape contains s2.Origin. // Shapes that do not have an interior will return false. ContainsOrigin() bool }
Shape defines an interface for any s2 type that needs to be indexable.
type ShapeIndex ¶
type ShapeIndex struct {
// contains filtered or unexported fields
}
ShapeIndex indexes a set of Shapes, where a Shape is some collection of edges. A shape can be as simple as a single edge, or as complex as a set of loops. For Shapes that have interiors, the index makes it very fast to determine which Shape(s) contain a given point or region.
func (*ShapeIndex) Add ¶
func (s *ShapeIndex) Add(shape Shape)
Add adds the given shape to the index and assign an ID to it.
func (*ShapeIndex) Len ¶
func (s *ShapeIndex) Len() int
Len reports the number of Shapes in this index.
func (*ShapeIndex) Remove ¶
func (s *ShapeIndex) Remove(shape Shape)
Remove removes the given shape from the index.
func (*ShapeIndex) Reset ¶
func (s *ShapeIndex) Reset()
Reset clears the contents of the index and resets it to its original state.
Notes ¶
Bugs ¶
The major differences from the C++ version is that barely anything is implemented.
The differences from the C++ version FloodFill, SimpleCovering