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
This commit is contained in:
Tobi Smethurst
2021-08-12 21:03:24 +02:00
committed by GitHub
parent 329a5e8144
commit 98263a7de6
2677 changed files with 1090869 additions and 219 deletions

202
vendor/github.com/golang/geo/LICENSE generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

20
vendor/github.com/golang/geo/r1/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 r1 implements types and functions for working with geometry in ℝ¹.
See ../s2 for a more detailed overview.
*/
package r1

177
vendor/github.com/golang/geo/r1/interval.go generated vendored Normal file
View File

@ -0,0 +1,177 @@
// 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 r1
import (
"fmt"
"math"
)
// Interval represents a closed interval on .
// Zero-length intervals (where Lo == Hi) represent single points.
// If Lo > Hi then the interval is empty.
type Interval struct {
Lo, Hi float64
}
// EmptyInterval returns an empty interval.
func EmptyInterval() Interval { return Interval{1, 0} }
// IntervalFromPoint returns an interval representing a single point.
func IntervalFromPoint(p float64) Interval { return Interval{p, p} }
// IsEmpty reports whether the interval is empty.
func (i Interval) IsEmpty() bool { return i.Lo > i.Hi }
// Equal returns true iff the interval contains the same points as oi.
func (i Interval) Equal(oi Interval) bool {
return i == oi || i.IsEmpty() && oi.IsEmpty()
}
// Center returns the midpoint of the interval.
// It is undefined for empty intervals.
func (i Interval) Center() float64 { return 0.5 * (i.Lo + i.Hi) }
// Length returns the length of the interval.
// The length of an empty interval is negative.
func (i Interval) Length() float64 { return i.Hi - i.Lo }
// Contains returns true iff the interval contains p.
func (i Interval) Contains(p float64) bool { return i.Lo <= p && p <= i.Hi }
// ContainsInterval returns true iff the interval contains oi.
func (i Interval) ContainsInterval(oi Interval) bool {
if oi.IsEmpty() {
return true
}
return i.Lo <= oi.Lo && oi.Hi <= i.Hi
}
// InteriorContains returns true iff the interval strictly contains p.
func (i Interval) InteriorContains(p float64) bool {
return i.Lo < p && p < i.Hi
}
// InteriorContainsInterval returns true iff the interval strictly contains oi.
func (i Interval) InteriorContainsInterval(oi Interval) bool {
if oi.IsEmpty() {
return true
}
return i.Lo < oi.Lo && oi.Hi < i.Hi
}
// Intersects returns true iff the interval contains any points in common with oi.
func (i Interval) Intersects(oi Interval) bool {
if i.Lo <= oi.Lo {
return oi.Lo <= i.Hi && oi.Lo <= oi.Hi // oi.Lo ∈ i and oi is not empty
}
return i.Lo <= oi.Hi && i.Lo <= i.Hi // i.Lo ∈ oi and i is not empty
}
// InteriorIntersects returns true iff the interior of the interval contains any points in common with oi, including the latter's boundary.
func (i Interval) InteriorIntersects(oi Interval) bool {
return oi.Lo < i.Hi && i.Lo < oi.Hi && i.Lo < i.Hi && oi.Lo <= oi.Hi
}
// Intersection returns the interval containing all points common to i and j.
func (i Interval) Intersection(j Interval) Interval {
// Empty intervals do not need to be special-cased.
return Interval{
Lo: math.Max(i.Lo, j.Lo),
Hi: math.Min(i.Hi, j.Hi),
}
}
// AddPoint returns the interval expanded so that it contains the given point.
func (i Interval) AddPoint(p float64) Interval {
if i.IsEmpty() {
return Interval{p, p}
}
if p < i.Lo {
return Interval{p, i.Hi}
}
if p > i.Hi {
return Interval{i.Lo, p}
}
return i
}
// ClampPoint returns the closest point in the interval to the given point "p".
// The interval must be non-empty.
func (i Interval) ClampPoint(p float64) float64 {
return math.Max(i.Lo, math.Min(i.Hi, p))
}
// Expanded returns an interval that has been expanded on each side by margin.
// If margin is negative, then the function shrinks the interval on
// each side by margin instead. The resulting interval may be empty. Any
// expansion of an empty interval remains empty.
func (i Interval) Expanded(margin float64) Interval {
if i.IsEmpty() {
return i
}
return Interval{i.Lo - margin, i.Hi + margin}
}
// Union returns the smallest interval that contains this interval and the given interval.
func (i Interval) Union(other Interval) Interval {
if i.IsEmpty() {
return other
}
if other.IsEmpty() {
return i
}
return Interval{math.Min(i.Lo, other.Lo), math.Max(i.Hi, other.Hi)}
}
func (i Interval) String() string { return fmt.Sprintf("[%.7f, %.7f]", i.Lo, i.Hi) }
const (
// epsilon is a small number that represents a reasonable level of noise between two
// values that can be considered to be equal.
epsilon = 1e-15
// dblEpsilon is a smaller number for values that require more precision.
// This is the C++ DBL_EPSILON equivalent.
dblEpsilon = 2.220446049250313e-16
)
// ApproxEqual reports whether the interval can be transformed into the
// given interval by moving each endpoint a small distance.
// The empty interval is considered to be positioned arbitrarily on the
// real line, so any interval with a small enough length will match
// the empty interval.
func (i Interval) ApproxEqual(other Interval) bool {
if i.IsEmpty() {
return other.Length() <= 2*epsilon
}
if other.IsEmpty() {
return i.Length() <= 2*epsilon
}
return math.Abs(other.Lo-i.Lo) <= epsilon &&
math.Abs(other.Hi-i.Hi) <= epsilon
}
// DirectedHausdorffDistance returns the Hausdorff distance to the given interval. For two
// intervals x and y, this distance is defined as
// h(x, y) = max_{p in x} min_{q in y} d(p, q).
func (i Interval) DirectedHausdorffDistance(other Interval) float64 {
if i.IsEmpty() {
return 0
}
if other.IsEmpty() {
return math.Inf(1)
}
return math.Max(0, math.Max(i.Hi-other.Hi, other.Lo-i.Lo))
}

20
vendor/github.com/golang/geo/r2/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 r2 implements types and functions for working with geometry in ℝ².
See package s2 for a more detailed overview.
*/
package r2

255
vendor/github.com/golang/geo/r2/rect.go generated vendored Normal file
View File

@ -0,0 +1,255 @@
// 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 r2
import (
"fmt"
"math"
"github.com/golang/geo/r1"
)
// Point represents a point in ℝ².
type Point struct {
X, Y float64
}
// Add returns the sum of p and op.
func (p Point) Add(op Point) Point { return Point{p.X + op.X, p.Y + op.Y} }
// Sub returns the difference of p and op.
func (p Point) Sub(op Point) Point { return Point{p.X - op.X, p.Y - op.Y} }
// Mul returns the scalar product of p and m.
func (p Point) Mul(m float64) Point { return Point{m * p.X, m * p.Y} }
// Ortho returns a counterclockwise orthogonal point with the same norm.
func (p Point) Ortho() Point { return Point{-p.Y, p.X} }
// Dot returns the dot product between p and op.
func (p Point) Dot(op Point) float64 { return p.X*op.X + p.Y*op.Y }
// Cross returns the cross product of p and op.
func (p Point) Cross(op Point) float64 { return p.X*op.Y - p.Y*op.X }
// Norm returns the vector's norm.
func (p Point) Norm() float64 { return math.Hypot(p.X, p.Y) }
// Normalize returns a unit point in the same direction as p.
func (p Point) Normalize() Point {
if p.X == 0 && p.Y == 0 {
return p
}
return p.Mul(1 / p.Norm())
}
func (p Point) String() string { return fmt.Sprintf("(%.12f, %.12f)", p.X, p.Y) }
// Rect represents a closed axis-aligned rectangle in the (x,y) plane.
type Rect struct {
X, Y r1.Interval
}
// RectFromPoints constructs a rect that contains the given points.
func RectFromPoints(pts ...Point) Rect {
// Because the default value on interval is 0,0, we need to manually
// define the interval from the first point passed in as our starting
// interval, otherwise we end up with the case of passing in
// Point{0.2, 0.3} and getting the starting Rect of {0, 0.2}, {0, 0.3}
// instead of the Rect {0.2, 0.2}, {0.3, 0.3} which is not correct.
if len(pts) == 0 {
return Rect{}
}
r := Rect{
X: r1.Interval{Lo: pts[0].X, Hi: pts[0].X},
Y: r1.Interval{Lo: pts[0].Y, Hi: pts[0].Y},
}
for _, p := range pts[1:] {
r = r.AddPoint(p)
}
return r
}
// RectFromCenterSize constructs a rectangle with the given center and size.
// Both dimensions of size must be non-negative.
func RectFromCenterSize(center, size Point) Rect {
return Rect{
r1.Interval{Lo: center.X - size.X/2, Hi: center.X + size.X/2},
r1.Interval{Lo: center.Y - size.Y/2, Hi: center.Y + size.Y/2},
}
}
// EmptyRect constructs the canonical empty rectangle. Use IsEmpty() to test
// for empty rectangles, since they have more than one representation. A Rect{}
// is not the same as the EmptyRect.
func EmptyRect() Rect {
return Rect{r1.EmptyInterval(), r1.EmptyInterval()}
}
// IsValid reports whether the rectangle is valid.
// This requires the width to be empty iff the height is empty.
func (r Rect) IsValid() bool {
return r.X.IsEmpty() == r.Y.IsEmpty()
}
// IsEmpty reports whether the rectangle is empty.
func (r Rect) IsEmpty() bool {
return r.X.IsEmpty()
}
// Vertices returns all four vertices of the rectangle. Vertices are returned in
// CCW direction starting with the lower left corner.
func (r Rect) Vertices() [4]Point {
return [4]Point{
{r.X.Lo, r.Y.Lo},
{r.X.Hi, r.Y.Lo},
{r.X.Hi, r.Y.Hi},
{r.X.Lo, r.Y.Hi},
}
}
// VertexIJ returns the vertex in direction i along the X-axis (0=left, 1=right) and
// direction j along the Y-axis (0=down, 1=up).
func (r Rect) VertexIJ(i, j int) Point {
x := r.X.Lo
if i == 1 {
x = r.X.Hi
}
y := r.Y.Lo
if j == 1 {
y = r.Y.Hi
}
return Point{x, y}
}
// Lo returns the low corner of the rect.
func (r Rect) Lo() Point {
return Point{r.X.Lo, r.Y.Lo}
}
// Hi returns the high corner of the rect.
func (r Rect) Hi() Point {
return Point{r.X.Hi, r.Y.Hi}
}
// Center returns the center of the rectangle in (x,y)-space
func (r Rect) Center() Point {
return Point{r.X.Center(), r.Y.Center()}
}
// Size returns the width and height of this rectangle in (x,y)-space. Empty
// rectangles have a negative width and height.
func (r Rect) Size() Point {
return Point{r.X.Length(), r.Y.Length()}
}
// ContainsPoint reports whether the rectangle contains the given point.
// Rectangles are closed regions, i.e. they contain their boundary.
func (r Rect) ContainsPoint(p Point) bool {
return r.X.Contains(p.X) && r.Y.Contains(p.Y)
}
// InteriorContainsPoint returns true iff the given point is contained in the interior
// of the region (i.e. the region excluding its boundary).
func (r Rect) InteriorContainsPoint(p Point) bool {
return r.X.InteriorContains(p.X) && r.Y.InteriorContains(p.Y)
}
// Contains reports whether the rectangle contains the given rectangle.
func (r Rect) Contains(other Rect) bool {
return r.X.ContainsInterval(other.X) && r.Y.ContainsInterval(other.Y)
}
// InteriorContains reports whether the interior of this rectangle contains all of the
// points of the given other rectangle (including its boundary).
func (r Rect) InteriorContains(other Rect) bool {
return r.X.InteriorContainsInterval(other.X) && r.Y.InteriorContainsInterval(other.Y)
}
// Intersects reports whether this rectangle and the other rectangle have any points in common.
func (r Rect) Intersects(other Rect) bool {
return r.X.Intersects(other.X) && r.Y.Intersects(other.Y)
}
// InteriorIntersects reports whether the interior of this rectangle intersects
// any point (including the boundary) of the given other rectangle.
func (r Rect) InteriorIntersects(other Rect) bool {
return r.X.InteriorIntersects(other.X) && r.Y.InteriorIntersects(other.Y)
}
// AddPoint expands the rectangle to include the given point. The rectangle is
// expanded by the minimum amount possible.
func (r Rect) AddPoint(p Point) Rect {
return Rect{r.X.AddPoint(p.X), r.Y.AddPoint(p.Y)}
}
// AddRect expands the rectangle to include the given rectangle. This is the
// same as replacing the rectangle by the union of the two rectangles, but
// is more efficient.
func (r Rect) AddRect(other Rect) Rect {
return Rect{r.X.Union(other.X), r.Y.Union(other.Y)}
}
// ClampPoint returns the closest point in the rectangle to the given point.
// The rectangle must be non-empty.
func (r Rect) ClampPoint(p Point) Point {
return Point{r.X.ClampPoint(p.X), r.Y.ClampPoint(p.Y)}
}
// Expanded returns a rectangle that has been expanded in the x-direction
// by margin.X, and in y-direction by margin.Y. If either margin is empty,
// then shrink the interval on the corresponding sides instead. The resulting
// rectangle may be empty. Any expansion of an empty rectangle remains empty.
func (r Rect) Expanded(margin Point) Rect {
xx := r.X.Expanded(margin.X)
yy := r.Y.Expanded(margin.Y)
if xx.IsEmpty() || yy.IsEmpty() {
return EmptyRect()
}
return Rect{xx, yy}
}
// ExpandedByMargin returns a Rect that has been expanded by the amount on all sides.
func (r Rect) ExpandedByMargin(margin float64) Rect {
return r.Expanded(Point{margin, margin})
}
// Union returns the smallest rectangle containing the union of this rectangle and
// the given rectangle.
func (r Rect) Union(other Rect) Rect {
return Rect{r.X.Union(other.X), r.Y.Union(other.Y)}
}
// Intersection returns the smallest rectangle containing the intersection of this
// rectangle and the given rectangle.
func (r Rect) Intersection(other Rect) Rect {
xx := r.X.Intersection(other.X)
yy := r.Y.Intersection(other.Y)
if xx.IsEmpty() || yy.IsEmpty() {
return EmptyRect()
}
return Rect{xx, yy}
}
// ApproxEqual returns true if the x- and y-intervals of the two rectangles are
// the same up to the given tolerance.
func (r Rect) ApproxEqual(r2 Rect) bool {
return r.X.ApproxEqual(r2.X) && r.Y.ApproxEqual(r2.Y)
}
func (r Rect) String() string { return fmt.Sprintf("[Lo%s, Hi%s]", r.Lo(), r.Hi()) }

20
vendor/github.com/golang/geo/r3/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 r3 implements types and functions for working with geometry in ℝ³.
See ../s2 for a more detailed overview.
*/
package r3

198
vendor/github.com/golang/geo/r3/precisevector.go generated vendored Normal file
View File

@ -0,0 +1,198 @@
// Copyright 2016 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 r3
import (
"fmt"
"math/big"
)
const (
// prec is the number of bits of precision to use for the Float values.
// To keep things simple, we use the maximum allowable precision on big
// values. This allows us to handle all values we expect in the s2 library.
prec = big.MaxPrec
)
// define some commonly referenced values.
var (
precise0 = precInt(0)
precise1 = precInt(1)
)
// precStr wraps the conversion from a string into a big.Float. For results that
// actually can be represented exactly, this should only be used on values that
// are integer multiples of integer powers of 2.
func precStr(s string) *big.Float {
// Explicitly ignoring the bool return for this usage.
f, _ := new(big.Float).SetPrec(prec).SetString(s)
return f
}
func precInt(i int64) *big.Float {
return new(big.Float).SetPrec(prec).SetInt64(i)
}
func precFloat(f float64) *big.Float {
return new(big.Float).SetPrec(prec).SetFloat64(f)
}
func precAdd(a, b *big.Float) *big.Float {
return new(big.Float).SetPrec(prec).Add(a, b)
}
func precSub(a, b *big.Float) *big.Float {
return new(big.Float).SetPrec(prec).Sub(a, b)
}
func precMul(a, b *big.Float) *big.Float {
return new(big.Float).SetPrec(prec).Mul(a, b)
}
// PreciseVector represents a point in ℝ³ using high-precision values.
// Note that this is NOT a complete implementation because there are some
// operations that Vector supports that are not feasible with arbitrary precision
// math. (e.g., methods that need division like Normalize, or methods needing a
// square root operation such as Norm)
type PreciseVector struct {
X, Y, Z *big.Float
}
// PreciseVectorFromVector creates a high precision vector from the given Vector.
func PreciseVectorFromVector(v Vector) PreciseVector {
return NewPreciseVector(v.X, v.Y, v.Z)
}
// NewPreciseVector creates a high precision vector from the given floating point values.
func NewPreciseVector(x, y, z float64) PreciseVector {
return PreciseVector{
X: precFloat(x),
Y: precFloat(y),
Z: precFloat(z),
}
}
// Vector returns this precise vector converted to a Vector.
func (v PreciseVector) Vector() Vector {
// The accuracy flag is ignored on these conversions back to float64.
x, _ := v.X.Float64()
y, _ := v.Y.Float64()
z, _ := v.Z.Float64()
return Vector{x, y, z}.Normalize()
}
// Equal reports whether v and ov are equal.
func (v PreciseVector) Equal(ov PreciseVector) bool {
return v.X.Cmp(ov.X) == 0 && v.Y.Cmp(ov.Y) == 0 && v.Z.Cmp(ov.Z) == 0
}
func (v PreciseVector) String() string {
return fmt.Sprintf("(%10g, %10g, %10g)", v.X, v.Y, v.Z)
}
// Norm2 returns the square of the norm.
func (v PreciseVector) Norm2() *big.Float { return v.Dot(v) }
// IsUnit reports whether this vector is of unit length.
func (v PreciseVector) IsUnit() bool {
return v.Norm2().Cmp(precise1) == 0
}
// Abs returns the vector with nonnegative components.
func (v PreciseVector) Abs() PreciseVector {
return PreciseVector{
X: new(big.Float).Abs(v.X),
Y: new(big.Float).Abs(v.Y),
Z: new(big.Float).Abs(v.Z),
}
}
// Add returns the standard vector sum of v and ov.
func (v PreciseVector) Add(ov PreciseVector) PreciseVector {
return PreciseVector{
X: precAdd(v.X, ov.X),
Y: precAdd(v.Y, ov.Y),
Z: precAdd(v.Z, ov.Z),
}
}
// Sub returns the standard vector difference of v and ov.
func (v PreciseVector) Sub(ov PreciseVector) PreciseVector {
return PreciseVector{
X: precSub(v.X, ov.X),
Y: precSub(v.Y, ov.Y),
Z: precSub(v.Z, ov.Z),
}
}
// Mul returns the standard scalar product of v and f.
func (v PreciseVector) Mul(f *big.Float) PreciseVector {
return PreciseVector{
X: precMul(v.X, f),
Y: precMul(v.Y, f),
Z: precMul(v.Z, f),
}
}
// MulByFloat64 returns the standard scalar product of v and f.
func (v PreciseVector) MulByFloat64(f float64) PreciseVector {
return v.Mul(precFloat(f))
}
// Dot returns the standard dot product of v and ov.
func (v PreciseVector) Dot(ov PreciseVector) *big.Float {
return precAdd(precMul(v.X, ov.X), precAdd(precMul(v.Y, ov.Y), precMul(v.Z, ov.Z)))
}
// Cross returns the standard cross product of v and ov.
func (v PreciseVector) Cross(ov PreciseVector) PreciseVector {
return PreciseVector{
X: precSub(precMul(v.Y, ov.Z), precMul(v.Z, ov.Y)),
Y: precSub(precMul(v.Z, ov.X), precMul(v.X, ov.Z)),
Z: precSub(precMul(v.X, ov.Y), precMul(v.Y, ov.X)),
}
}
// LargestComponent returns the axis that represents the largest component in this vector.
func (v PreciseVector) LargestComponent() Axis {
t := v.Abs()
if t.X.Cmp(t.Y) > 0 {
if t.X.Cmp(t.Z) > 0 {
return XAxis
}
return ZAxis
}
if t.Y.Cmp(t.Z) > 0 {
return YAxis
}
return ZAxis
}
// SmallestComponent returns the axis that represents the smallest component in this vector.
func (v PreciseVector) SmallestComponent() Axis {
t := v.Abs()
if t.X.Cmp(t.Y) < 0 {
if t.X.Cmp(t.Z) < 0 {
return XAxis
}
return ZAxis
}
if t.Y.Cmp(t.Z) < 0 {
return YAxis
}
return ZAxis
}

183
vendor/github.com/golang/geo/r3/vector.go generated vendored Normal file
View File

@ -0,0 +1,183 @@
// 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 r3
import (
"fmt"
"math"
"github.com/golang/geo/s1"
)
// Vector represents a point in ℝ³.
type Vector struct {
X, Y, Z float64
}
// ApproxEqual reports whether v and ov are equal within a small epsilon.
func (v Vector) ApproxEqual(ov Vector) bool {
const epsilon = 1e-16
return math.Abs(v.X-ov.X) < epsilon && math.Abs(v.Y-ov.Y) < epsilon && math.Abs(v.Z-ov.Z) < epsilon
}
func (v Vector) String() string { return fmt.Sprintf("(%0.24f, %0.24f, %0.24f)", v.X, v.Y, v.Z) }
// Norm returns the vector's norm.
func (v Vector) Norm() float64 { return math.Sqrt(v.Dot(v)) }
// Norm2 returns the square of the norm.
func (v Vector) Norm2() float64 { return v.Dot(v) }
// Normalize returns a unit vector in the same direction as v.
func (v Vector) Normalize() Vector {
n2 := v.Norm2()
if n2 == 0 {
return Vector{0, 0, 0}
}
return v.Mul(1 / math.Sqrt(n2))
}
// IsUnit returns whether this vector is of approximately unit length.
func (v Vector) IsUnit() bool {
const epsilon = 5e-14
return math.Abs(v.Norm2()-1) <= epsilon
}
// Abs returns the vector with nonnegative components.
func (v Vector) Abs() Vector { return Vector{math.Abs(v.X), math.Abs(v.Y), math.Abs(v.Z)} }
// Add returns the standard vector sum of v and ov.
func (v Vector) Add(ov Vector) Vector { return Vector{v.X + ov.X, v.Y + ov.Y, v.Z + ov.Z} }
// Sub returns the standard vector difference of v and ov.
func (v Vector) Sub(ov Vector) Vector { return Vector{v.X - ov.X, v.Y - ov.Y, v.Z - ov.Z} }
// Mul returns the standard scalar product of v and m.
func (v Vector) Mul(m float64) Vector { return Vector{m * v.X, m * v.Y, m * v.Z} }
// Dot returns the standard dot product of v and ov.
func (v Vector) Dot(ov Vector) float64 { return v.X*ov.X + v.Y*ov.Y + v.Z*ov.Z }
// Cross returns the standard cross product of v and ov.
func (v Vector) Cross(ov Vector) Vector {
return Vector{
v.Y*ov.Z - v.Z*ov.Y,
v.Z*ov.X - v.X*ov.Z,
v.X*ov.Y - v.Y*ov.X,
}
}
// Distance returns the Euclidean distance between v and ov.
func (v Vector) Distance(ov Vector) float64 { return v.Sub(ov).Norm() }
// Angle returns the angle between v and ov.
func (v Vector) Angle(ov Vector) s1.Angle {
return s1.Angle(math.Atan2(v.Cross(ov).Norm(), v.Dot(ov))) * s1.Radian
}
// Axis enumerates the 3 axes of ℝ³.
type Axis int
// The three axes of ℝ³.
const (
XAxis Axis = iota
YAxis
ZAxis
)
// Ortho returns a unit vector that is orthogonal to v.
// Ortho(-v) = -Ortho(v) for all v.
func (v Vector) Ortho() Vector {
ov := Vector{0.012, 0.0053, 0.00457}
switch v.LargestComponent() {
case XAxis:
ov.Z = 1
case YAxis:
ov.X = 1
default:
ov.Y = 1
}
return v.Cross(ov).Normalize()
}
// LargestComponent returns the axis that represents the largest component in this vector.
func (v Vector) LargestComponent() Axis {
t := v.Abs()
if t.X > t.Y {
if t.X > t.Z {
return XAxis
}
return ZAxis
}
if t.Y > t.Z {
return YAxis
}
return ZAxis
}
// SmallestComponent returns the axis that represents the smallest component in this vector.
func (v Vector) SmallestComponent() Axis {
t := v.Abs()
if t.X < t.Y {
if t.X < t.Z {
return XAxis
}
return ZAxis
}
if t.Y < t.Z {
return YAxis
}
return ZAxis
}
// Cmp compares v and ov lexicographically and returns:
//
// -1 if v < ov
// 0 if v == ov
// +1 if v > ov
//
// This method is based on C++'s std::lexicographical_compare. Two entities
// are compared element by element with the given operator. The first mismatch
// defines which is less (or greater) than the other. If both have equivalent
// values they are lexicographically equal.
func (v Vector) Cmp(ov Vector) int {
if v.X < ov.X {
return -1
}
if v.X > ov.X {
return 1
}
// First elements were the same, try the next.
if v.Y < ov.Y {
return -1
}
if v.Y > ov.Y {
return 1
}
// Second elements were the same return the final compare.
if v.Z < ov.Z {
return -1
}
if v.Z > ov.Z {
return 1
}
// Both are equal
return 0
}

120
vendor/github.com/golang/geo/s1/angle.go generated vendored Normal file
View File

@ -0,0 +1,120 @@
// 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 s1
import (
"math"
"strconv"
)
// Angle represents a 1D angle. The internal representation is a double precision
// value in radians, so conversion to and from radians is exact.
// Conversions between E5, E6, E7, and Degrees are not always
// exact. For example, Degrees(3.1) is different from E6(3100000) or E7(31000000).
//
// The following conversions between degrees and radians are exact:
//
// Degree*180 == Radian*math.Pi
// Degree*(180/n) == Radian*(math.Pi/n) for n == 0..8
//
// These identities hold when the arguments are scaled up or down by any power
// of 2. Some similar identities are also true, for example,
//
// Degree*60 == Radian*(math.Pi/3)
//
// But be aware that this type of identity does not hold in general. For example,
//
// Degree*3 != Radian*(math.Pi/60)
//
// Similarly, the conversion to radians means that (Angle(x)*Degree).Degrees()
// does not always equal x. For example,
//
// (Angle(45*n)*Degree).Degrees() == 45*n for n == 0..8
//
// but
//
// (60*Degree).Degrees() != 60
//
// When testing for equality, you should allow for numerical errors (ApproxEqual)
// or convert to discrete E5/E6/E7 values first.
type Angle float64
// Angle units.
const (
Radian Angle = 1
Degree = (math.Pi / 180) * Radian
E5 = 1e-5 * Degree
E6 = 1e-6 * Degree
E7 = 1e-7 * Degree
)
// Radians returns the angle in radians.
func (a Angle) Radians() float64 { return float64(a) }
// Degrees returns the angle in degrees.
func (a Angle) Degrees() float64 { return float64(a / Degree) }
// round returns the value rounded to nearest as an int32.
// This does not match C++ exactly for the case of x.5.
func round(val float64) int32 {
if val < 0 {
return int32(val - 0.5)
}
return int32(val + 0.5)
}
// InfAngle returns an angle larger than any finite angle.
func InfAngle() Angle {
return Angle(math.Inf(1))
}
// isInf reports whether this Angle is infinite.
func (a Angle) isInf() bool {
return math.IsInf(float64(a), 0)
}
// E5 returns the angle in hundred thousandths of degrees.
func (a Angle) E5() int32 { return round(a.Degrees() * 1e5) }
// E6 returns the angle in millionths of degrees.
func (a Angle) E6() int32 { return round(a.Degrees() * 1e6) }
// E7 returns the angle in ten millionths of degrees.
func (a Angle) E7() int32 { return round(a.Degrees() * 1e7) }
// Abs returns the absolute value of the angle.
func (a Angle) Abs() Angle { return Angle(math.Abs(float64(a))) }
// Normalized returns an equivalent angle in (-π, π].
func (a Angle) Normalized() Angle {
rad := math.Remainder(float64(a), 2*math.Pi)
if rad <= -math.Pi {
rad = math.Pi
}
return Angle(rad)
}
func (a Angle) String() string {
return strconv.FormatFloat(a.Degrees(), 'f', 7, 64) // like "%.7f"
}
// ApproxEqual reports whether the two angles are the same up to a small tolerance.
func (a Angle) ApproxEqual(other Angle) bool {
return math.Abs(float64(a)-float64(other)) <= epsilon
}
// BUG(dsymonds): The major differences from the C++ version are:
// - no unsigned E5/E6/E7 methods

320
vendor/github.com/golang/geo/s1/chordangle.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
// Copyright 2015 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 s1
import (
"math"
)
// ChordAngle represents the angle subtended by a chord (i.e., the straight
// line segment connecting two points on the sphere). Its representation
// makes it very efficient for computing and comparing distances, but unlike
// Angle it is only capable of representing angles between 0 and π radians.
// Generally, ChordAngle should only be used in loops where many angles need
// to be calculated and compared. Otherwise it is simpler to use Angle.
//
// ChordAngle loses some accuracy as the angle approaches π radians.
// There are several different ways to measure this error, including the
// representational error (i.e., how accurately ChordAngle can represent
// angles near π radians), the conversion error (i.e., how much precision is
// lost when an Angle is converted to an ChordAngle), and the measurement
// error (i.e., how accurate the ChordAngle(a, b) constructor is when the
// points A and B are separated by angles close to π radians). All of these
// errors differ by a small constant factor.
//
// For the measurement error (which is the largest of these errors and also
// the most important in practice), let the angle between A and B be (π - x)
// radians, i.e. A and B are within "x" radians of being antipodal. The
// corresponding chord length is
//
// r = 2 * sin((π - x) / 2) = 2 * cos(x / 2)
//
// For values of x not close to π the relative error in the squared chord
// length is at most 4.5 * dblEpsilon (see MaxPointError below).
// The relative error in "r" is thus at most 2.25 * dblEpsilon ~= 5e-16. To
// convert this error into an equivalent angle, we have
//
// |dr / dx| = sin(x / 2)
//
// and therefore
//
// |dx| = dr / sin(x / 2)
// = 5e-16 * (2 * cos(x / 2)) / sin(x / 2)
// = 1e-15 / tan(x / 2)
//
// The maximum error is attained when
//
// x = |dx|
// = 1e-15 / tan(x / 2)
// ~= 1e-15 / (x / 2)
// ~= sqrt(2e-15)
//
// In summary, the measurement error for an angle (π - x) is at most
//
// dx = min(1e-15 / tan(x / 2), sqrt(2e-15))
// (~= min(2e-15 / x, sqrt(2e-15)) when x is small)
//
// On the Earth's surface (assuming a radius of 6371km), this corresponds to
// the following worst-case measurement errors:
//
// Accuracy: Unless antipodal to within:
// --------- ---------------------------
// 6.4 nanometers 10,000 km (90 degrees)
// 1 micrometer 81.2 kilometers
// 1 millimeter 81.2 meters
// 1 centimeter 8.12 meters
// 28.5 centimeters 28.5 centimeters
//
// The representational and conversion errors referred to earlier are somewhat
// smaller than this. For example, maximum distance between adjacent
// representable ChordAngle values is only 13.5 cm rather than 28.5 cm. To
// see this, observe that the closest representable value to r^2 = 4 is
// r^2 = 4 * (1 - dblEpsilon / 2). Thus r = 2 * (1 - dblEpsilon / 4) and
// the angle between these two representable values is
//
// x = 2 * acos(r / 2)
// = 2 * acos(1 - dblEpsilon / 4)
// ~= 2 * asin(sqrt(dblEpsilon / 2)
// ~= sqrt(2 * dblEpsilon)
// ~= 2.1e-8
//
// which is 13.5 cm on the Earth's surface.
//
// The worst case rounding error occurs when the value halfway between these
// two representable values is rounded up to 4. This halfway value is
// r^2 = (4 * (1 - dblEpsilon / 4)), thus r = 2 * (1 - dblEpsilon / 8) and
// the worst case rounding error is
//
// x = 2 * acos(r / 2)
// = 2 * acos(1 - dblEpsilon / 8)
// ~= 2 * asin(sqrt(dblEpsilon / 4)
// ~= sqrt(dblEpsilon)
// ~= 1.5e-8
//
// which is 9.5 cm on the Earth's surface.
type ChordAngle float64
const (
// NegativeChordAngle represents a chord angle smaller than the zero angle.
// The only valid operations on a NegativeChordAngle are comparisons,
// Angle conversions, and Successor/Predecessor.
NegativeChordAngle = ChordAngle(-1)
// RightChordAngle represents a chord angle of 90 degrees (a "right angle").
RightChordAngle = ChordAngle(2)
// StraightChordAngle represents a chord angle of 180 degrees (a "straight angle").
// This is the maximum finite chord angle.
StraightChordAngle = ChordAngle(4)
// maxLength2 is the square of the maximum length allowed in a ChordAngle.
maxLength2 = 4.0
)
// ChordAngleFromAngle returns a ChordAngle from the given Angle.
func ChordAngleFromAngle(a Angle) ChordAngle {
if a < 0 {
return NegativeChordAngle
}
if a.isInf() {
return InfChordAngle()
}
l := 2 * math.Sin(0.5*math.Min(math.Pi, a.Radians()))
return ChordAngle(l * l)
}
// ChordAngleFromSquaredLength returns a ChordAngle from the squared chord length.
// Note that the argument is automatically clamped to a maximum of 4 to
// handle possible roundoff errors. The argument must be non-negative.
func ChordAngleFromSquaredLength(length2 float64) ChordAngle {
if length2 > maxLength2 {
return StraightChordAngle
}
return ChordAngle(length2)
}
// Expanded returns a new ChordAngle that has been adjusted by the given error
// bound (which can be positive or negative). Error should be the value
// returned by either MaxPointError or MaxAngleError. For example:
// a := ChordAngleFromPoints(x, y)
// a1 := a.Expanded(a.MaxPointError())
func (c ChordAngle) Expanded(e float64) ChordAngle {
// If the angle is special, don't change it. Otherwise clamp it to the valid range.
if c.isSpecial() {
return c
}
return ChordAngle(math.Max(0.0, math.Min(maxLength2, float64(c)+e)))
}
// Angle converts this ChordAngle to an Angle.
func (c ChordAngle) Angle() Angle {
if c < 0 {
return -1 * Radian
}
if c.isInf() {
return InfAngle()
}
return Angle(2 * math.Asin(0.5*math.Sqrt(float64(c))))
}
// InfChordAngle returns a chord angle larger than any finite chord angle.
// The only valid operations on an InfChordAngle are comparisons, Angle
// conversions, and Successor/Predecessor.
func InfChordAngle() ChordAngle {
return ChordAngle(math.Inf(1))
}
// isInf reports whether this ChordAngle is infinite.
func (c ChordAngle) isInf() bool {
return math.IsInf(float64(c), 1)
}
// isSpecial reports whether this ChordAngle is one of the special cases.
func (c ChordAngle) isSpecial() bool {
return c < 0 || c.isInf()
}
// isValid reports whether this ChordAngle is valid or not.
func (c ChordAngle) isValid() bool {
return (c >= 0 && c <= maxLength2) || c.isSpecial()
}
// Successor returns the smallest representable ChordAngle larger than this one.
// This can be used to convert a "<" comparison to a "<=" comparison.
//
// Note the following special cases:
// NegativeChordAngle.Successor == 0
// StraightChordAngle.Successor == InfChordAngle
// InfChordAngle.Successor == InfChordAngle
func (c ChordAngle) Successor() ChordAngle {
if c >= maxLength2 {
return InfChordAngle()
}
if c < 0 {
return 0
}
return ChordAngle(math.Nextafter(float64(c), 10.0))
}
// Predecessor returns the largest representable ChordAngle less than this one.
//
// Note the following special cases:
// InfChordAngle.Predecessor == StraightChordAngle
// ChordAngle(0).Predecessor == NegativeChordAngle
// NegativeChordAngle.Predecessor == NegativeChordAngle
func (c ChordAngle) Predecessor() ChordAngle {
if c <= 0 {
return NegativeChordAngle
}
if c > maxLength2 {
return StraightChordAngle
}
return ChordAngle(math.Nextafter(float64(c), -10.0))
}
// MaxPointError returns the maximum error size for a ChordAngle constructed
// from 2 Points x and y, assuming that x and y are normalized to within the
// bounds guaranteed by s2.Point.Normalize. The error is defined with respect to
// the true distance after the points are projected to lie exactly on the sphere.
func (c ChordAngle) MaxPointError() float64 {
// There is a relative error of (2.5*dblEpsilon) when computing the squared
// distance, plus a relative error of 2 * dblEpsilon, plus an absolute error
// of (16 * dblEpsilon**2) because the lengths of the input points may differ
// from 1 by up to (2*dblEpsilon) each. (This is the maximum error in Normalize).
return 4.5*dblEpsilon*float64(c) + 16*dblEpsilon*dblEpsilon
}
// MaxAngleError returns the maximum error for a ChordAngle constructed
// as an Angle distance.
func (c ChordAngle) MaxAngleError() float64 {
return dblEpsilon * float64(c)
}
// Add adds the other ChordAngle to this one and returns the resulting value.
// This method assumes the ChordAngles are not special.
func (c ChordAngle) Add(other ChordAngle) ChordAngle {
// Note that this method (and Sub) is much more efficient than converting
// the ChordAngle to an Angle and adding those and converting back. It
// requires only one square root plus a few additions and multiplications.
// Optimization for the common case where b is an error tolerance
// parameter that happens to be set to zero.
if other == 0 {
return c
}
// Clamp the angle sum to at most 180 degrees.
if c+other >= maxLength2 {
return StraightChordAngle
}
// Let a and b be the (non-squared) chord lengths, and let c = a+b.
// Let A, B, and C be the corresponding half-angles (a = 2*sin(A), etc).
// Then the formula below can be derived from c = 2 * sin(A+B) and the
// relationships sin(A+B) = sin(A)*cos(B) + sin(B)*cos(A)
// cos(X) = sqrt(1 - sin^2(X))
x := float64(c * (1 - 0.25*other))
y := float64(other * (1 - 0.25*c))
return ChordAngle(math.Min(maxLength2, x+y+2*math.Sqrt(x*y)))
}
// Sub subtracts the other ChordAngle from this one and returns the resulting
// value. This method assumes the ChordAngles are not special.
func (c ChordAngle) Sub(other ChordAngle) ChordAngle {
if other == 0 {
return c
}
if c <= other {
return 0
}
x := float64(c * (1 - 0.25*other))
y := float64(other * (1 - 0.25*c))
return ChordAngle(math.Max(0.0, x+y-2*math.Sqrt(x*y)))
}
// Sin returns the sine of this chord angle. This method is more efficient
// than converting to Angle and performing the computation.
func (c ChordAngle) Sin() float64 {
return math.Sqrt(c.Sin2())
}
// Sin2 returns the square of the sine of this chord angle.
// It is more efficient than Sin.
func (c ChordAngle) Sin2() float64 {
// Let a be the (non-squared) chord length, and let A be the corresponding
// half-angle (a = 2*sin(A)). The formula below can be derived from:
// sin(2*A) = 2 * sin(A) * cos(A)
// cos^2(A) = 1 - sin^2(A)
// This is much faster than converting to an angle and computing its sine.
return float64(c * (1 - 0.25*c))
}
// Cos returns the cosine of this chord angle. This method is more efficient
// than converting to Angle and performing the computation.
func (c ChordAngle) Cos() float64 {
// cos(2*A) = cos^2(A) - sin^2(A) = 1 - 2*sin^2(A)
return float64(1 - 0.5*c)
}
// Tan returns the tangent of this chord angle.
func (c ChordAngle) Tan() float64 {
return c.Sin() / c.Cos()
}
// TODO(roberts): Differences from C++:
// Helpers to/from E5/E6/E7
// Helpers to/from degrees and radians directly.
// FastUpperBoundFrom(angle Angle)

20
vendor/github.com/golang/geo/s1/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 s1 implements types and functions for working with geometry in S¹ (circular geometry).
See ../s2 for a more detailed overview.
*/
package s1

462
vendor/github.com/golang/geo/s1/interval.go generated vendored Normal file
View File

@ -0,0 +1,462 @@
// 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 s1
import (
"math"
"strconv"
)
// An Interval represents a closed interval on a unit circle (also known
// as a 1-dimensional sphere). It is capable of representing the empty
// interval (containing no points), the full interval (containing all
// points), and zero-length intervals (containing a single point).
//
// Points are represented by the angle they make with the positive x-axis in
// the range [-π, π]. An interval is represented by its lower and upper
// bounds (both inclusive, since the interval is closed). The lower bound may
// be greater than the upper bound, in which case the interval is "inverted"
// (i.e. it passes through the point (-1, 0)).
//
// The point (-1, 0) has two valid representations, π and -π. The
// normalized representation of this point is π, so that endpoints
// of normal intervals are in the range (-π, π]. We normalize the latter to
// the former in IntervalFromEndpoints. However, we take advantage of the point
// -π to construct two special intervals:
// The full interval is [-π, π]
// The empty interval is [π, -π].
//
// Treat the exported fields as read-only.
type Interval struct {
Lo, Hi float64
}
// IntervalFromEndpoints constructs a new interval from endpoints.
// Both arguments must be in the range [-π,π]. This function allows inverted intervals
// to be created.
func IntervalFromEndpoints(lo, hi float64) Interval {
i := Interval{lo, hi}
if lo == -math.Pi && hi != math.Pi {
i.Lo = math.Pi
}
if hi == -math.Pi && lo != math.Pi {
i.Hi = math.Pi
}
return i
}
// IntervalFromPointPair returns the minimal interval containing the two given points.
// Both arguments must be in [-π,π].
func IntervalFromPointPair(a, b float64) Interval {
if a == -math.Pi {
a = math.Pi
}
if b == -math.Pi {
b = math.Pi
}
if positiveDistance(a, b) <= math.Pi {
return Interval{a, b}
}
return Interval{b, a}
}
// EmptyInterval returns an empty interval.
func EmptyInterval() Interval { return Interval{math.Pi, -math.Pi} }
// FullInterval returns a full interval.
func FullInterval() Interval { return Interval{-math.Pi, math.Pi} }
// IsValid reports whether the interval is valid.
func (i Interval) IsValid() bool {
return (math.Abs(i.Lo) <= math.Pi && math.Abs(i.Hi) <= math.Pi &&
!(i.Lo == -math.Pi && i.Hi != math.Pi) &&
!(i.Hi == -math.Pi && i.Lo != math.Pi))
}
// IsFull reports whether the interval is full.
func (i Interval) IsFull() bool { return i.Lo == -math.Pi && i.Hi == math.Pi }
// IsEmpty reports whether the interval is empty.
func (i Interval) IsEmpty() bool { return i.Lo == math.Pi && i.Hi == -math.Pi }
// IsInverted reports whether the interval is inverted; that is, whether Lo > Hi.
func (i Interval) IsInverted() bool { return i.Lo > i.Hi }
// Invert returns the interval with endpoints swapped.
func (i Interval) Invert() Interval {
return Interval{i.Hi, i.Lo}
}
// Center returns the midpoint of the interval.
// It is undefined for full and empty intervals.
func (i Interval) Center() float64 {
c := 0.5 * (i.Lo + i.Hi)
if !i.IsInverted() {
return c
}
if c <= 0 {
return c + math.Pi
}
return c - math.Pi
}
// Length returns the length of the interval.
// The length of an empty interval is negative.
func (i Interval) Length() float64 {
l := i.Hi - i.Lo
if l >= 0 {
return l
}
l += 2 * math.Pi
if l > 0 {
return l
}
return -1
}
// Assumes p ∈ (-π,π].
func (i Interval) fastContains(p float64) bool {
if i.IsInverted() {
return (p >= i.Lo || p <= i.Hi) && !i.IsEmpty()
}
return p >= i.Lo && p <= i.Hi
}
// Contains returns true iff the interval contains p.
// Assumes p ∈ [-π,π].
func (i Interval) Contains(p float64) bool {
if p == -math.Pi {
p = math.Pi
}
return i.fastContains(p)
}
// ContainsInterval returns true iff the interval contains oi.
func (i Interval) ContainsInterval(oi Interval) bool {
if i.IsInverted() {
if oi.IsInverted() {
return oi.Lo >= i.Lo && oi.Hi <= i.Hi
}
return (oi.Lo >= i.Lo || oi.Hi <= i.Hi) && !i.IsEmpty()
}
if oi.IsInverted() {
return i.IsFull() || oi.IsEmpty()
}
return oi.Lo >= i.Lo && oi.Hi <= i.Hi
}
// InteriorContains returns true iff the interior of the interval contains p.
// Assumes p ∈ [-π,π].
func (i Interval) InteriorContains(p float64) bool {
if p == -math.Pi {
p = math.Pi
}
if i.IsInverted() {
return p > i.Lo || p < i.Hi
}
return (p > i.Lo && p < i.Hi) || i.IsFull()
}
// InteriorContainsInterval returns true iff the interior of the interval contains oi.
func (i Interval) InteriorContainsInterval(oi Interval) bool {
if i.IsInverted() {
if oi.IsInverted() {
return (oi.Lo > i.Lo && oi.Hi < i.Hi) || oi.IsEmpty()
}
return oi.Lo > i.Lo || oi.Hi < i.Hi
}
if oi.IsInverted() {
return i.IsFull() || oi.IsEmpty()
}
return (oi.Lo > i.Lo && oi.Hi < i.Hi) || i.IsFull()
}
// Intersects returns true iff the interval contains any points in common with oi.
func (i Interval) Intersects(oi Interval) bool {
if i.IsEmpty() || oi.IsEmpty() {
return false
}
if i.IsInverted() {
return oi.IsInverted() || oi.Lo <= i.Hi || oi.Hi >= i.Lo
}
if oi.IsInverted() {
return oi.Lo <= i.Hi || oi.Hi >= i.Lo
}
return oi.Lo <= i.Hi && oi.Hi >= i.Lo
}
// InteriorIntersects returns true iff the interior of the interval contains any points in common with oi, including the latter's boundary.
func (i Interval) InteriorIntersects(oi Interval) bool {
if i.IsEmpty() || oi.IsEmpty() || i.Lo == i.Hi {
return false
}
if i.IsInverted() {
return oi.IsInverted() || oi.Lo < i.Hi || oi.Hi > i.Lo
}
if oi.IsInverted() {
return oi.Lo < i.Hi || oi.Hi > i.Lo
}
return (oi.Lo < i.Hi && oi.Hi > i.Lo) || i.IsFull()
}
// Compute distance from a to b in [0,2π], in a numerically stable way.
func positiveDistance(a, b float64) float64 {
d := b - a
if d >= 0 {
return d
}
return (b + math.Pi) - (a - math.Pi)
}
// Union returns the smallest interval that contains both the interval and oi.
func (i Interval) Union(oi Interval) Interval {
if oi.IsEmpty() {
return i
}
if i.fastContains(oi.Lo) {
if i.fastContains(oi.Hi) {
// Either oi ⊂ i, or i oi is the full interval.
if i.ContainsInterval(oi) {
return i
}
return FullInterval()
}
return Interval{i.Lo, oi.Hi}
}
if i.fastContains(oi.Hi) {
return Interval{oi.Lo, i.Hi}
}
// Neither endpoint of oi is in i. Either i ⊂ oi, or i and oi are disjoint.
if i.IsEmpty() || oi.fastContains(i.Lo) {
return oi
}
// This is the only hard case where we need to find the closest pair of endpoints.
if positiveDistance(oi.Hi, i.Lo) < positiveDistance(i.Hi, oi.Lo) {
return Interval{oi.Lo, i.Hi}
}
return Interval{i.Lo, oi.Hi}
}
// Intersection returns the smallest interval that contains the intersection of the interval and oi.
func (i Interval) Intersection(oi Interval) Interval {
if oi.IsEmpty() {
return EmptyInterval()
}
if i.fastContains(oi.Lo) {
if i.fastContains(oi.Hi) {
// Either oi ⊂ i, or i and oi intersect twice. Neither are empty.
// In the first case we want to return i (which is shorter than oi).
// In the second case one of them is inverted, and the smallest interval
// that covers the two disjoint pieces is the shorter of i and oi.
// We thus want to pick the shorter of i and oi in both cases.
if oi.Length() < i.Length() {
return oi
}
return i
}
return Interval{oi.Lo, i.Hi}
}
if i.fastContains(oi.Hi) {
return Interval{i.Lo, oi.Hi}
}
// Neither endpoint of oi is in i. Either i ⊂ oi, or i and oi are disjoint.
if oi.fastContains(i.Lo) {
return i
}
return EmptyInterval()
}
// AddPoint returns the interval expanded by the minimum amount necessary such
// that it contains the given point "p" (an angle in the range [-π, π]).
func (i Interval) AddPoint(p float64) Interval {
if math.Abs(p) > math.Pi {
return i
}
if p == -math.Pi {
p = math.Pi
}
if i.fastContains(p) {
return i
}
if i.IsEmpty() {
return Interval{p, p}
}
if positiveDistance(p, i.Lo) < positiveDistance(i.Hi, p) {
return Interval{p, i.Hi}
}
return Interval{i.Lo, p}
}
// Define the maximum rounding error for arithmetic operations. Depending on the
// platform the mantissa precision may be different than others, so we choose to
// use specific values to be consistent across all.
// The values come from the C++ implementation.
var (
// epsilon is a small number that represents a reasonable level of noise between two
// values that can be considered to be equal.
epsilon = 1e-15
// dblEpsilon is a smaller number for values that require more precision.
dblEpsilon = 2.220446049e-16
)
// Expanded returns an interval that has been expanded on each side by margin.
// If margin is negative, then the function shrinks the interval on
// each side by margin instead. The resulting interval may be empty or
// full. Any expansion (positive or negative) of a full interval remains
// full, and any expansion of an empty interval remains empty.
func (i Interval) Expanded(margin float64) Interval {
if margin >= 0 {
if i.IsEmpty() {
return i
}
// Check whether this interval will be full after expansion, allowing
// for a rounding error when computing each endpoint.
if i.Length()+2*margin+2*dblEpsilon >= 2*math.Pi {
return FullInterval()
}
} else {
if i.IsFull() {
return i
}
// Check whether this interval will be empty after expansion, allowing
// for a rounding error when computing each endpoint.
if i.Length()+2*margin-2*dblEpsilon <= 0 {
return EmptyInterval()
}
}
result := IntervalFromEndpoints(
math.Remainder(i.Lo-margin, 2*math.Pi),
math.Remainder(i.Hi+margin, 2*math.Pi),
)
if result.Lo <= -math.Pi {
result.Lo = math.Pi
}
return result
}
// ApproxEqual reports whether this interval can be transformed into the given
// interval by moving each endpoint by at most ε, without the
// endpoints crossing (which would invert the interval). Empty and full
// intervals are considered to start at an arbitrary point on the unit circle,
// so any interval with (length <= 2*ε) matches the empty interval, and
// any interval with (length >= 2*π - 2*ε) matches the full interval.
func (i Interval) ApproxEqual(other Interval) bool {
// Full and empty intervals require special cases because the endpoints
// are considered to be positioned arbitrarily.
if i.IsEmpty() {
return other.Length() <= 2*epsilon
}
if other.IsEmpty() {
return i.Length() <= 2*epsilon
}
if i.IsFull() {
return other.Length() >= 2*(math.Pi-epsilon)
}
if other.IsFull() {
return i.Length() >= 2*(math.Pi-epsilon)
}
// The purpose of the last test below is to verify that moving the endpoints
// does not invert the interval, e.g. [-1e20, 1e20] vs. [1e20, -1e20].
return (math.Abs(math.Remainder(other.Lo-i.Lo, 2*math.Pi)) <= epsilon &&
math.Abs(math.Remainder(other.Hi-i.Hi, 2*math.Pi)) <= epsilon &&
math.Abs(i.Length()-other.Length()) <= 2*epsilon)
}
func (i Interval) String() string {
// like "[%.7f, %.7f]"
return "[" + strconv.FormatFloat(i.Lo, 'f', 7, 64) + ", " + strconv.FormatFloat(i.Hi, 'f', 7, 64) + "]"
}
// Complement returns the complement of the interior of the interval. An interval and
// its complement have the same boundary but do not share any interior
// values. The complement operator is not a bijection, since the complement
// of a singleton interval (containing a single value) is the same as the
// complement of an empty interval.
func (i Interval) Complement() Interval {
if i.Lo == i.Hi {
// Singleton. The interval just contains a single point.
return FullInterval()
}
// Handles empty and full.
return Interval{i.Hi, i.Lo}
}
// ComplementCenter returns the midpoint of the complement of the interval. For full and empty
// intervals, the result is arbitrary. For a singleton interval (containing a
// single point), the result is its antipodal point on S1.
func (i Interval) ComplementCenter() float64 {
if i.Lo != i.Hi {
return i.Complement().Center()
}
// Singleton. The interval just contains a single point.
if i.Hi <= 0 {
return i.Hi + math.Pi
}
return i.Hi - math.Pi
}
// DirectedHausdorffDistance returns the Hausdorff distance to the given interval.
// For two intervals i and y, this distance is defined by
// h(i, y) = max_{p in i} min_{q in y} d(p, q),
// where d(.,.) is measured along S1.
func (i Interval) DirectedHausdorffDistance(y Interval) Angle {
if y.ContainsInterval(i) {
return 0 // This includes the case i is empty.
}
if y.IsEmpty() {
return Angle(math.Pi) // maximum possible distance on s1.
}
yComplementCenter := y.ComplementCenter()
if i.Contains(yComplementCenter) {
return Angle(positiveDistance(y.Hi, yComplementCenter))
}
// The Hausdorff distance is realized by either two i.Hi endpoints or two
// i.Lo endpoints, whichever is farther apart.
hiHi := 0.0
if IntervalFromEndpoints(y.Hi, yComplementCenter).Contains(i.Hi) {
hiHi = positiveDistance(y.Hi, i.Hi)
}
loLo := 0.0
if IntervalFromEndpoints(yComplementCenter, y.Lo).Contains(i.Lo) {
loLo = positiveDistance(i.Lo, y.Lo)
}
return Angle(math.Max(hiHi, loLo))
}
// Project returns the closest point in the interval to the given point p.
// The interval must be non-empty.
func (i Interval) Project(p float64) float64 {
if p == -math.Pi {
p = math.Pi
}
if i.fastContains(p) {
return p
}
// Compute distance from p to each endpoint.
dlo := positiveDistance(p, i.Lo)
dhi := positiveDistance(i.Hi, p)
if dlo < dhi {
return i.Lo
}
return i.Hi
}

53
vendor/github.com/golang/geo/s2/bits_go18.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2018 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.
// +build !go1.9
package s2
// This file is for the bit manipulation code pre-Go 1.9.
// findMSBSetNonZero64 returns the index (between 0 and 63) of the most
// significant set bit. Passing zero to this function returns zero.
func findMSBSetNonZero64(x uint64) int {
val := []uint64{0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000}
shift := []uint64{1, 2, 4, 8, 16, 32}
var msbPos uint64
for i := 5; i >= 0; i-- {
if x&val[i] != 0 {
x >>= shift[i]
msbPos |= shift[i]
}
}
return int(msbPos)
}
const deBruijn64 = 0x03f79d71b4ca8b09
const digitMask = uint64(1<<64 - 1)
var deBruijn64Lookup = []byte{
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
}
// findLSBSetNonZero64 returns the index (between 0 and 63) of the least
// significant set bit. Passing zero to this function returns zero.
//
// This code comes from trailingZeroBits in https://golang.org/src/math/big/nat.go
// which references (Knuth, volume 4, section 7.3.1).
func findLSBSetNonZero64(x uint64) int {
return int(deBruijn64Lookup[((x&-x)*(deBruijn64&digitMask))>>58])
}

39
vendor/github.com/golang/geo/s2/bits_go19.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2018 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.
// +build go1.9
package s2
// This file is for the bit manipulation code post-Go 1.9.
import "math/bits"
// findMSBSetNonZero64 returns the index (between 0 and 63) of the most
// significant set bit. Passing zero to this function return zero.
func findMSBSetNonZero64(x uint64) int {
if x == 0 {
return 0
}
return 63 - bits.LeadingZeros64(x)
}
// findLSBSetNonZero64 returns the index (between 0 and 63) of the least
// significant set bit. Passing zero to this function return zero.
func findLSBSetNonZero64(x uint64) int {
if x == 0 {
return 0
}
return bits.TrailingZeros64(x)
}

519
vendor/github.com/golang/geo/s2/cap.go generated vendored Normal file
View File

@ -0,0 +1,519 @@
// 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"
"math"
"github.com/golang/geo/r1"
"github.com/golang/geo/s1"
)
var (
// centerPoint is the default center for Caps
centerPoint = PointFromCoords(1.0, 0, 0)
)
// 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.)
//
// A cap can also be defined by its center point and height. The height is the
// distance from the center point to the cutoff plane. There is also support for
// "empty" and "full" caps, which contain no points and all points respectively.
//
// Here are some useful relationships between the cap height (h), the cap
// radius (r), the maximum chord length from the cap's center (d), and the
// radius of cap's base (a).
//
// h = 1 - cos(r)
// = 2 * sin^2(r/2)
// d^2 = 2 * h
// = a^2 + h^2
//
// The zero value of Cap is an invalid cap. Use EmptyCap to get a valid empty cap.
type Cap struct {
center Point
radius s1.ChordAngle
}
// CapFromPoint constructs a cap containing a single point.
func CapFromPoint(p Point) Cap {
return CapFromCenterChordAngle(p, 0)
}
// CapFromCenterAngle constructs a cap with the given center and angle.
func CapFromCenterAngle(center Point, angle s1.Angle) Cap {
return CapFromCenterChordAngle(center, s1.ChordAngleFromAngle(angle))
}
// CapFromCenterChordAngle constructs a cap where the angle is expressed as an
// s1.ChordAngle. This constructor is more efficient than using an s1.Angle.
func CapFromCenterChordAngle(center Point, radius s1.ChordAngle) Cap {
return Cap{
center: center,
radius: radius,
}
}
// 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.
// The center should be unit length.
func CapFromCenterHeight(center Point, height float64) Cap {
return CapFromCenterChordAngle(center, s1.ChordAngleFromSquaredLength(2*height))
}
// 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 CapFromCenterArea(center Point, area float64) Cap {
return CapFromCenterChordAngle(center, s1.ChordAngleFromSquaredLength(area/math.Pi))
}
// EmptyCap returns a cap that contains no points.
func EmptyCap() Cap {
return CapFromCenterChordAngle(centerPoint, s1.NegativeChordAngle)
}
// FullCap returns a cap that contains all points.
func FullCap() Cap {
return CapFromCenterChordAngle(centerPoint, s1.StraightChordAngle)
}
// IsValid reports whether the Cap is considered valid.
func (c Cap) IsValid() bool {
return c.center.Vector.IsUnit() && c.radius <= s1.StraightChordAngle
}
// IsEmpty reports whether the cap is empty, i.e. it contains no points.
func (c Cap) IsEmpty() bool {
return c.radius < 0
}
// IsFull reports whether the cap is full, i.e. it contains all points.
func (c Cap) IsFull() bool {
return c.radius == s1.StraightChordAngle
}
// Center returns the cap's center point.
func (c Cap) Center() Point {
return c.center
}
// Height returns the height of the cap. This is the distance from the center
// point to the cutoff plane.
func (c Cap) Height() float64 {
return float64(0.5 * c.radius)
}
// Radius returns the cap radius as an s1.Angle. (Note that the cap angle
// is stored internally as a ChordAngle, so this method requires a trigonometric
// operation and may yield a slightly different result than the value passed
// to CapFromCenterAngle).
func (c Cap) Radius() s1.Angle {
return c.radius.Angle()
}
// Area returns the surface area of the Cap on the unit sphere.
func (c Cap) Area() float64 {
return 2.0 * math.Pi * math.Max(0, c.Height())
}
// Contains reports whether this cap contains the other.
func (c Cap) Contains(other Cap) bool {
// In a set containment sense, every cap contains the empty cap.
if c.IsFull() || other.IsEmpty() {
return true
}
return c.radius >= ChordAngleBetweenPoints(c.center, other.center).Add(other.radius)
}
// Intersects reports whether this cap intersects the other cap.
// i.e. whether they have any points in common.
func (c Cap) Intersects(other Cap) bool {
if c.IsEmpty() || other.IsEmpty() {
return false
}
return c.radius.Add(other.radius) >= ChordAngleBetweenPoints(c.center, other.center)
}
// InteriorIntersects reports whether this caps interior intersects the other cap.
func (c Cap) InteriorIntersects(other Cap) bool {
// Make sure this cap has an interior and the other cap is non-empty.
if c.radius <= 0 || other.IsEmpty() {
return false
}
return c.radius.Add(other.radius) > ChordAngleBetweenPoints(c.center, other.center)
}
// ContainsPoint reports whether this cap contains the point.
func (c Cap) ContainsPoint(p Point) bool {
return ChordAngleBetweenPoints(c.center, p) <= c.radius
}
// InteriorContainsPoint reports whether the point is within the interior of this cap.
func (c Cap) InteriorContainsPoint(p Point) bool {
return c.IsFull() || ChordAngleBetweenPoints(c.center, p) < c.radius
}
// 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 (c Cap) Complement() Cap {
if c.IsFull() {
return EmptyCap()
}
if c.IsEmpty() {
return FullCap()
}
return CapFromCenterChordAngle(Point{c.center.Mul(-1)}, s1.StraightChordAngle.Sub(c.radius))
}
// CapBound returns a bounding spherical cap. This is not guaranteed to be exact.
func (c Cap) CapBound() Cap {
return c
}
// RectBound returns a bounding latitude-longitude rectangle.
// The bounds are not guaranteed to be tight.
func (c Cap) RectBound() Rect {
if c.IsEmpty() {
return EmptyRect()
}
capAngle := c.Radius().Radians()
allLongitudes := false
lat := r1.Interval{
Lo: latitude(c.center).Radians() - capAngle,
Hi: latitude(c.center).Radians() + capAngle,
}
lng := s1.FullInterval()
// Check whether cap includes the south pole.
if lat.Lo <= -math.Pi/2 {
lat.Lo = -math.Pi / 2
allLongitudes = true
}
// Check whether cap includes the north pole.
if lat.Hi >= math.Pi/2 {
lat.Hi = math.Pi / 2
allLongitudes = true
}
if !allLongitudes {
// Compute the range of longitudes covered by the cap. We use the law
// of sines for spherical triangles. Consider the triangle ABC where
// A is the north pole, B is the center of the cap, and C is the point
// of tangency between the cap boundary and a line of longitude. Then
// C is a right angle, and letting a,b,c denote the sides opposite A,B,C,
// we have sin(a)/sin(A) = sin(c)/sin(C), or sin(A) = sin(a)/sin(c).
// Here "a" is the cap angle, and "c" is the colatitude (90 degrees
// minus the latitude). This formula also works for negative latitudes.
//
// The formula for sin(a) follows from the relationship h = 1 - cos(a).
sinA := c.radius.Sin()
sinC := math.Cos(latitude(c.center).Radians())
if sinA <= sinC {
angleA := math.Asin(sinA / sinC)
lng.Lo = math.Remainder(longitude(c.center).Radians()-angleA, math.Pi*2)
lng.Hi = math.Remainder(longitude(c.center).Radians()+angleA, math.Pi*2)
}
}
return Rect{lat, lng}
}
// Equal reports whether this cap is equal to the other cap.
func (c Cap) Equal(other Cap) bool {
return (c.radius == other.radius && c.center == other.center) ||
(c.IsEmpty() && other.IsEmpty()) ||
(c.IsFull() && other.IsFull())
}
// ApproxEqual reports whether this cap is equal to the other cap within the given tolerance.
func (c Cap) ApproxEqual(other Cap) bool {
const epsilon = 1e-14
r2 := float64(c.radius)
otherR2 := float64(other.radius)
return c.center.ApproxEqual(other.center) &&
math.Abs(r2-otherR2) <= epsilon ||
c.IsEmpty() && otherR2 <= epsilon ||
other.IsEmpty() && r2 <= epsilon ||
c.IsFull() && otherR2 >= 2-epsilon ||
other.IsFull() && r2 >= 2-epsilon
}
// 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 (c Cap) AddPoint(p Point) Cap {
if c.IsEmpty() {
c.center = p
c.radius = 0
return c
}
// After calling cap.AddPoint(p), cap.Contains(p) must be true. However
// we don't need to do anything special to achieve this because Contains()
// does exactly the same distance calculation that we do here.
if newRad := ChordAngleBetweenPoints(c.center, p); newRad > c.radius {
c.radius = newRad
}
return c
}
// 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 (c Cap) AddCap(other Cap) Cap {
if c.IsEmpty() {
return other
}
if other.IsEmpty() {
return c
}
// We round up the distance to ensure that the cap is actually contained.
// TODO(roberts): Do some error analysis in order to guarantee this.
dist := ChordAngleBetweenPoints(c.center, other.center).Add(other.radius)
if newRad := dist.Expanded(dblEpsilon * float64(dist)); newRad > c.radius {
c.radius = newRad
}
return c
}
// Expanded returns a new cap expanded by the given angle. If the cap is empty,
// it returns an empty cap.
func (c Cap) Expanded(distance s1.Angle) Cap {
if c.IsEmpty() {
return EmptyCap()
}
return CapFromCenterChordAngle(c.center, c.radius.Add(s1.ChordAngleFromAngle(distance)))
}
func (c Cap) String() string {
return fmt.Sprintf("[Center=%v, Radius=%f]", c.center.Vector, c.Radius().Degrees())
}
// radiusToHeight converts an s1.Angle into the height of the cap.
func radiusToHeight(r s1.Angle) float64 {
if r.Radians() < 0 {
return float64(s1.NegativeChordAngle)
}
if r.Radians() >= math.Pi {
return float64(s1.RightChordAngle)
}
return float64(0.5 * s1.ChordAngleFromAngle(r))
}
// ContainsCell reports whether the cap contains the given cell.
func (c Cap) ContainsCell(cell Cell) bool {
// If the cap does not contain all cell vertices, return false.
var vertices [4]Point
for k := 0; k < 4; k++ {
vertices[k] = cell.Vertex(k)
if !c.ContainsPoint(vertices[k]) {
return false
}
}
// Otherwise, return true if the complement of the cap does not intersect the cell.
return !c.Complement().intersects(cell, vertices)
}
// IntersectsCell reports whether the cap intersects the cell.
func (c Cap) IntersectsCell(cell Cell) bool {
// If the cap contains any cell vertex, return true.
var vertices [4]Point
for k := 0; k < 4; k++ {
vertices[k] = cell.Vertex(k)
if c.ContainsPoint(vertices[k]) {
return true
}
}
return c.intersects(cell, vertices)
}
// intersects reports whether the cap intersects any point of the cell excluding
// its vertices (which are assumed to already have been checked).
func (c Cap) intersects(cell Cell, vertices [4]Point) bool {
// If the cap is a hemisphere or larger, the cell and the complement of the cap
// are both convex. Therefore since no vertex of the cell is contained, no other
// interior point of the cell is contained either.
if c.radius >= s1.RightChordAngle {
return false
}
// We need to check for empty caps due to the center check just below.
if c.IsEmpty() {
return false
}
// Optimization: return true if the cell contains the cap center. This allows half
// of the edge checks below to be skipped.
if cell.ContainsPoint(c.center) {
return true
}
// At this point we know that the cell does not contain the cap center, and the cap
// does not contain any cell vertex. The only way that they can intersect is if the
// cap intersects the interior of some edge.
sin2Angle := c.radius.Sin2()
for k := 0; k < 4; k++ {
edge := cell.Edge(k).Vector
dot := c.center.Vector.Dot(edge)
if dot > 0 {
// The center is in the interior half-space defined by the edge. We do not need
// to consider these edges, since if the cap intersects this edge then it also
// intersects the edge on the opposite side of the cell, because the center is
// not contained with the cell.
continue
}
// The Norm2() factor is necessary because "edge" is not normalized.
if dot*dot > sin2Angle*edge.Norm2() {
return false
}
// Otherwise, the great circle containing this edge intersects the interior of the cap. We just
// need to check whether the point of closest approach occurs between the two edge endpoints.
dir := edge.Cross(c.center.Vector)
if dir.Dot(vertices[k].Vector) < 0 && dir.Dot(vertices[(k+1)&3].Vector) > 0 {
return true
}
}
return false
}
// CellUnionBound computes a covering of the Cap. In general the covering
// consists of at most 4 cells except for very large caps, which may need
// up to 6 cells. The output is not sorted.
func (c Cap) CellUnionBound() []CellID {
// TODO(roberts): The covering could be made quite a bit tighter by mapping
// the cap to a rectangle in (i,j)-space and finding a covering for that.
// Find the maximum level such that the cap contains at most one cell vertex
// and such that CellID.AppendVertexNeighbors() can be called.
level := MinWidthMetric.MaxLevel(c.Radius().Radians()) - 1
// If level < 0, more than three face cells are required.
if level < 0 {
cellIDs := make([]CellID, 6)
for face := 0; face < 6; face++ {
cellIDs[face] = CellIDFromFace(face)
}
return cellIDs
}
// The covering consists of the 4 cells at the given level that share the
// cell vertex that is closest to the cap center.
return cellIDFromPoint(c.center).VertexNeighbors(level)
}
// Centroid returns the true centroid of the cap multiplied by its surface area
// The result lies on the ray from the origin through the cap's center, but it
// is not unit length. Note that if you just want the "surface centroid", i.e.
// the normalized result, then it is simpler to call Center.
//
// The reason for multiplying the result by the cap area is to make it
// easier to compute the centroid of more complicated shapes. The centroid
// of a union of disjoint regions can be computed simply by adding their
// Centroid() results. Caveat: for caps that contain a single point
// (i.e., zero radius), this method always returns the origin (0, 0, 0).
// This is because shapes with no area don't affect the centroid of a
// union whose total area is positive.
func (c Cap) Centroid() Point {
// From symmetry, the centroid of the cap must be somewhere on the line
// from the origin to the center of the cap on the surface of the sphere.
// When a sphere is divided into slices of constant thickness by a set of
// parallel planes, all slices have the same surface area. This implies
// that the radial component of the centroid is simply the midpoint of the
// range of radial distances spanned by the cap. That is easily computed
// from the cap height.
if c.IsEmpty() {
return Point{}
}
r := 1 - 0.5*c.Height()
return Point{c.center.Mul(r * c.Area())}
}
// Union returns the smallest cap which encloses this cap and other.
func (c Cap) Union(other Cap) Cap {
// If the other cap is larger, swap c and other for the rest of the computations.
if c.radius < other.radius {
c, other = other, c
}
if c.IsFull() || other.IsEmpty() {
return c
}
// TODO: This calculation would be more efficient using s1.ChordAngles.
cRadius := c.Radius()
otherRadius := other.Radius()
distance := c.center.Distance(other.center)
if cRadius >= distance+otherRadius {
return c
}
resRadius := 0.5 * (distance + cRadius + otherRadius)
resCenter := InterpolateAtDistance(0.5*(distance-cRadius+otherRadius), c.center, other.center)
return CapFromCenterAngle(resCenter, resRadius)
}
// Encode encodes the Cap.
func (c Cap) Encode(w io.Writer) error {
e := &encoder{w: w}
c.encode(e)
return e.err
}
func (c Cap) encode(e *encoder) {
e.writeFloat64(c.center.X)
e.writeFloat64(c.center.Y)
e.writeFloat64(c.center.Z)
e.writeFloat64(float64(c.radius))
}
// Decode decodes the Cap.
func (c *Cap) Decode(r io.Reader) error {
d := &decoder{r: asByteReader(r)}
c.decode(d)
return d.err
}
func (c *Cap) decode(d *decoder) {
c.center.X = d.readFloat64()
c.center.Y = d.readFloat64()
c.center.Z = d.readFloat64()
c.radius = s1.ChordAngle(d.readFloat64())
}

698
vendor/github.com/golang/geo/s2/cell.go generated vendored Normal file
View File

@ -0,0 +1,698 @@
// 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 (
"io"
"math"
"github.com/golang/geo/r1"
"github.com/golang/geo/r2"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// 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.
type Cell struct {
face int8
level int8
orientation int8
id CellID
uv r2.Rect
}
// CellFromCellID constructs a Cell corresponding to the given CellID.
func CellFromCellID(id CellID) Cell {
c := Cell{}
c.id = id
f, i, j, o := c.id.faceIJOrientation()
c.face = int8(f)
c.level = int8(c.id.Level())
c.orientation = int8(o)
c.uv = ijLevelToBoundUV(i, j, int(c.level))
return c
}
// CellFromPoint constructs a cell for the given Point.
func CellFromPoint(p Point) Cell {
return CellFromCellID(cellIDFromPoint(p))
}
// CellFromLatLng constructs a cell for the given LatLng.
func CellFromLatLng(ll LatLng) Cell {
return CellFromCellID(CellIDFromLatLng(ll))
}
// Face returns the face this cell is on.
func (c Cell) Face() int {
return int(c.face)
}
// oppositeFace returns the face opposite the given face.
func oppositeFace(face int) int {
return (face + 3) % 6
}
// Level returns the level of this cell.
func (c Cell) Level() int {
return int(c.level)
}
// ID returns the CellID this cell represents.
func (c Cell) ID() CellID {
return c.id
}
// IsLeaf returns whether this Cell is a leaf or not.
func (c Cell) IsLeaf() bool {
return c.level == maxLevel
}
// SizeIJ returns the edge length of this cell in (i,j)-space.
func (c Cell) SizeIJ() int {
return sizeIJ(int(c.level))
}
// SizeST returns the edge length of this cell in (s,t)-space.
func (c Cell) SizeST() float64 {
return c.id.sizeST(int(c.level))
}
// Vertex returns the k-th vertex of the cell (k = 0,1,2,3) in CCW order
// (lower left, lower right, upper right, upper left in the UV plane).
func (c Cell) Vertex(k int) Point {
return Point{faceUVToXYZ(int(c.face), c.uv.Vertices()[k].X, c.uv.Vertices()[k].Y).Normalize()}
}
// 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) (for k = 0,1,2,3).
func (c Cell) Edge(k int) Point {
switch k {
case 0:
return Point{vNorm(int(c.face), c.uv.Y.Lo).Normalize()} // Bottom
case 1:
return Point{uNorm(int(c.face), c.uv.X.Hi).Normalize()} // Right
case 2:
return Point{vNorm(int(c.face), c.uv.Y.Hi).Mul(-1.0).Normalize()} // Top
default:
return Point{uNorm(int(c.face), c.uv.X.Lo).Mul(-1.0).Normalize()} // Left
}
}
// BoundUV returns the bounds of this cell in (u,v)-space.
func (c Cell) BoundUV() r2.Rect {
return c.uv
}
// Center returns the direction vector corresponding to the center in
// (s,t)-space of the given cell. This is the point at which the cell is
// divided into four subcells; it is not necessarily the centroid of the
// cell in (u,v)-space or (x,y,z)-space
func (c Cell) Center() Point {
return Point{c.id.rawPoint().Normalize()}
}
// Children returns the four direct children of this cell in traversal order
// and returns true. If this is a leaf cell, or the children could not be created,
// false is returned.
// The C++ method is called Subdivide.
func (c Cell) Children() ([4]Cell, bool) {
var children [4]Cell
if c.id.IsLeaf() {
return children, false
}
// Compute the cell midpoint in uv-space.
uvMid := c.id.centerUV()
// Create four children with the appropriate bounds.
cid := c.id.ChildBegin()
for pos := 0; pos < 4; pos++ {
children[pos] = Cell{
face: c.face,
level: c.level + 1,
orientation: c.orientation ^ int8(posToOrientation[pos]),
id: cid,
}
// We want to split the cell in half in u and v. To decide which
// side to set equal to the midpoint value, we look at cell's (i,j)
// position within its parent. The index for i is in bit 1 of ij.
ij := posToIJ[c.orientation][pos]
i := ij >> 1
j := ij & 1
if i == 1 {
children[pos].uv.X.Hi = c.uv.X.Hi
children[pos].uv.X.Lo = uvMid.X
} else {
children[pos].uv.X.Lo = c.uv.X.Lo
children[pos].uv.X.Hi = uvMid.X
}
if j == 1 {
children[pos].uv.Y.Hi = c.uv.Y.Hi
children[pos].uv.Y.Lo = uvMid.Y
} else {
children[pos].uv.Y.Lo = c.uv.Y.Lo
children[pos].uv.Y.Hi = uvMid.Y
}
cid = cid.Next()
}
return children, true
}
// ExactArea returns the area of this cell as accurately as possible.
func (c Cell) ExactArea() float64 {
v0, v1, v2, v3 := c.Vertex(0), c.Vertex(1), c.Vertex(2), c.Vertex(3)
return PointArea(v0, v1, v2) + PointArea(v0, v2, v3)
}
// 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 (c Cell) ApproxArea() float64 {
// All cells at the first two levels have the same area.
if c.level < 2 {
return c.AverageArea()
}
// First, compute the approximate area of the cell when projected
// perpendicular to its normal. The cross product of its diagonals gives
// the normal, and the length of the normal is twice the projected area.
flatArea := 0.5 * (c.Vertex(2).Sub(c.Vertex(0).Vector).
Cross(c.Vertex(3).Sub(c.Vertex(1).Vector)).Norm())
// Now, compensate for the curvature of the cell surface by pretending
// that the cell is shaped like a spherical cap. The ratio of the
// area of a spherical cap to the area of its projected disc turns out
// to be 2 / (1 + sqrt(1 - r*r)) where r is the radius of the disc.
// For example, when r=0 the ratio is 1, and when r=1 the ratio is 2.
// Here we set Pi*r*r == flatArea to find the equivalent disc.
return flatArea * 2 / (1 + math.Sqrt(1-math.Min(1/math.Pi*flatArea, 1)))
}
// AverageArea returns the average area of cells at the level of this cell.
// This is accurate to within a factor of 1.7.
func (c Cell) AverageArea() float64 {
return AvgAreaMetric.Value(int(c.level))
}
// IntersectsCell reports whether the intersection of this cell and the other cell is not nil.
func (c Cell) IntersectsCell(oc Cell) bool {
return c.id.Intersects(oc.id)
}
// ContainsCell reports whether this cell contains the other cell.
func (c Cell) ContainsCell(oc Cell) bool {
return c.id.Contains(oc.id)
}
// CellUnionBound computes a covering of the Cell.
func (c Cell) CellUnionBound() []CellID {
return c.CapBound().CellUnionBound()
}
// latitude returns the latitude of the cell vertex in radians given by (i,j),
// where i and j indicate the Hi (1) or Lo (0) corner.
func (c Cell) latitude(i, j int) float64 {
var u, v float64
switch {
case i == 0 && j == 0:
u = c.uv.X.Lo
v = c.uv.Y.Lo
case i == 0 && j == 1:
u = c.uv.X.Lo
v = c.uv.Y.Hi
case i == 1 && j == 0:
u = c.uv.X.Hi
v = c.uv.Y.Lo
case i == 1 && j == 1:
u = c.uv.X.Hi
v = c.uv.Y.Hi
default:
panic("i and/or j is out of bounds")
}
return latitude(Point{faceUVToXYZ(int(c.face), u, v)}).Radians()
}
// longitude returns the longitude of the cell vertex in radians given by (i,j),
// where i and j indicate the Hi (1) or Lo (0) corner.
func (c Cell) longitude(i, j int) float64 {
var u, v float64
switch {
case i == 0 && j == 0:
u = c.uv.X.Lo
v = c.uv.Y.Lo
case i == 0 && j == 1:
u = c.uv.X.Lo
v = c.uv.Y.Hi
case i == 1 && j == 0:
u = c.uv.X.Hi
v = c.uv.Y.Lo
case i == 1 && j == 1:
u = c.uv.X.Hi
v = c.uv.Y.Hi
default:
panic("i and/or j is out of bounds")
}
return longitude(Point{faceUVToXYZ(int(c.face), u, v)}).Radians()
}
var (
poleMinLat = math.Asin(math.Sqrt(1.0/3)) - 0.5*dblEpsilon
)
// RectBound returns the bounding rectangle of this cell.
func (c Cell) RectBound() Rect {
if c.level > 0 {
// Except for cells at level 0, the latitude and longitude extremes are
// attained at the vertices. Furthermore, the latitude range is
// determined by one pair of diagonally opposite vertices and the
// longitude range is determined by the other pair.
//
// We first determine which corner (i,j) of the cell has the largest
// absolute latitude. To maximize latitude, we want to find the point in
// the cell that has the largest absolute z-coordinate and the smallest
// absolute x- and y-coordinates. To do this we look at each coordinate
// (u and v), and determine whether we want to minimize or maximize that
// coordinate based on the axis direction and the cell's (u,v) quadrant.
u := c.uv.X.Lo + c.uv.X.Hi
v := c.uv.Y.Lo + c.uv.Y.Hi
var i, j int
if uAxis(int(c.face)).Z == 0 {
if u < 0 {
i = 1
}
} else if u > 0 {
i = 1
}
if vAxis(int(c.face)).Z == 0 {
if v < 0 {
j = 1
}
} else if v > 0 {
j = 1
}
lat := r1.IntervalFromPoint(c.latitude(i, j)).AddPoint(c.latitude(1-i, 1-j))
lng := s1.EmptyInterval().AddPoint(c.longitude(i, 1-j)).AddPoint(c.longitude(1-i, j))
// We grow the bounds slightly to make sure that the bounding rectangle
// contains LatLngFromPoint(P) for any point P inside the loop L defined by the
// four *normalized* vertices. Note that normalization of a vector can
// change its direction by up to 0.5 * dblEpsilon radians, and it is not
// enough just to add Normalize calls to the code above because the
// latitude/longitude ranges are not necessarily determined by diagonally
// opposite vertex pairs after normalization.
//
// We would like to bound the amount by which the latitude/longitude of a
// contained point P can exceed the bounds computed above. In the case of
// longitude, the normalization error can change the direction of rounding
// leading to a maximum difference in longitude of 2 * dblEpsilon. In
// the case of latitude, the normalization error can shift the latitude by
// up to 0.5 * dblEpsilon and the other sources of error can cause the
// two latitudes to differ by up to another 1.5 * dblEpsilon, which also
// leads to a maximum difference of 2 * dblEpsilon.
return Rect{lat, lng}.expanded(LatLng{s1.Angle(2 * dblEpsilon), s1.Angle(2 * dblEpsilon)}).PolarClosure()
}
// The 4 cells around the equator extend to +/-45 degrees latitude at the
// midpoints of their top and bottom edges. The two cells covering the
// poles extend down to +/-35.26 degrees at their vertices. The maximum
// error in this calculation is 0.5 * dblEpsilon.
var bound Rect
switch c.face {
case 0:
bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-math.Pi / 4, math.Pi / 4}}
case 1:
bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{math.Pi / 4, 3 * math.Pi / 4}}
case 2:
bound = Rect{r1.Interval{poleMinLat, math.Pi / 2}, s1.FullInterval()}
case 3:
bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{3 * math.Pi / 4, -3 * math.Pi / 4}}
case 4:
bound = Rect{r1.Interval{-math.Pi / 4, math.Pi / 4}, s1.Interval{-3 * math.Pi / 4, -math.Pi / 4}}
default:
bound = Rect{r1.Interval{-math.Pi / 2, -poleMinLat}, s1.FullInterval()}
}
// Finally, we expand the bound to account for the error when a point P is
// converted to an LatLng to test for containment. (The bound should be
// large enough so that it contains the computed LatLng of any contained
// point, not just the infinite-precision version.) We don't need to expand
// longitude because longitude is calculated via a single call to math.Atan2,
// which is guaranteed to be semi-monotonic.
return bound.expanded(LatLng{s1.Angle(dblEpsilon), s1.Angle(0)})
}
// CapBound returns the bounding cap of this cell.
func (c Cell) CapBound() Cap {
// We use the cell center in (u,v)-space as the cap axis. This vector is very close
// to GetCenter() and faster to compute. Neither one of these vectors yields the
// bounding cap with minimal surface area, but they are both pretty close.
cap := CapFromPoint(Point{faceUVToXYZ(int(c.face), c.uv.Center().X, c.uv.Center().Y).Normalize()})
for k := 0; k < 4; k++ {
cap = cap.AddPoint(c.Vertex(k))
}
return cap
}
// 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 (c Cell) ContainsPoint(p Point) bool {
var uv r2.Point
var ok bool
if uv.X, uv.Y, ok = faceXYZToUV(int(c.face), p); !ok {
return false
}
// Expand the (u,v) bound to ensure that
//
// CellFromPoint(p).ContainsPoint(p)
//
// is always true. To do this, we need to account for the error when
// converting from (u,v) coordinates to (s,t) coordinates. In the
// normal case the total error is at most dblEpsilon.
return c.uv.ExpandedByMargin(dblEpsilon).ContainsPoint(uv)
}
// Encode encodes the Cell.
func (c Cell) Encode(w io.Writer) error {
e := &encoder{w: w}
c.encode(e)
return e.err
}
func (c Cell) encode(e *encoder) {
c.id.encode(e)
}
// Decode decodes the Cell.
func (c *Cell) Decode(r io.Reader) error {
d := &decoder{r: asByteReader(r)}
c.decode(d)
return d.err
}
func (c *Cell) decode(d *decoder) {
c.id.decode(d)
*c = CellFromCellID(c.id)
}
// vertexChordDist2 returns the squared chord distance from point P to the
// given corner vertex specified by the Hi or Lo values of each.
func (c Cell) vertexChordDist2(p Point, xHi, yHi bool) s1.ChordAngle {
x := c.uv.X.Lo
y := c.uv.Y.Lo
if xHi {
x = c.uv.X.Hi
}
if yHi {
y = c.uv.Y.Hi
}
return ChordAngleBetweenPoints(p, PointFromCoords(x, y, 1))
}
// uEdgeIsClosest reports whether a point P is closer to the interior of the specified
// Cell edge (either the lower or upper edge of the Cell) or to the endpoints.
func (c Cell) uEdgeIsClosest(p Point, vHi bool) bool {
u0 := c.uv.X.Lo
u1 := c.uv.X.Hi
v := c.uv.Y.Lo
if vHi {
v = c.uv.Y.Hi
}
// These are the normals to the planes that are perpendicular to the edge
// and pass through one of its two endpoints.
dir0 := r3.Vector{v*v + 1, -u0 * v, -u0}
dir1 := r3.Vector{v*v + 1, -u1 * v, -u1}
return p.Dot(dir0) > 0 && p.Dot(dir1) < 0
}
// vEdgeIsClosest reports whether a point P is closer to the interior of the specified
// Cell edge (either the right or left edge of the Cell) or to the endpoints.
func (c Cell) vEdgeIsClosest(p Point, uHi bool) bool {
v0 := c.uv.Y.Lo
v1 := c.uv.Y.Hi
u := c.uv.X.Lo
if uHi {
u = c.uv.X.Hi
}
dir0 := r3.Vector{-u * v0, u*u + 1, -v0}
dir1 := r3.Vector{-u * v1, u*u + 1, -v1}
return p.Dot(dir0) > 0 && p.Dot(dir1) < 0
}
// edgeDistance reports the distance from a Point P to a given Cell edge. The point
// P is given by its dot product, and the uv edge by its normal in the
// given coordinate value.
func edgeDistance(ij, uv float64) s1.ChordAngle {
// Let P by the target point and let R be the closest point on the given
// edge AB. The desired distance PR can be expressed as PR^2 = PQ^2 + QR^2
// where Q is the point P projected onto the plane through the great circle
// through AB. We can compute the distance PQ^2 perpendicular to the plane
// from "dirIJ" (the dot product of the target point P with the edge
// normal) and the squared length the edge normal (1 + uv**2).
pq2 := (ij * ij) / (1 + uv*uv)
// We can compute the distance QR as (1 - OQ) where O is the sphere origin,
// and we can compute OQ^2 = 1 - PQ^2 using the Pythagorean theorem.
// (This calculation loses accuracy as angle POQ approaches Pi/2.)
qr := 1 - math.Sqrt(1-pq2)
return s1.ChordAngleFromSquaredLength(pq2 + qr*qr)
}
// distanceInternal reports the distance from the given point to the interior of
// the cell if toInterior is true or to the boundary of the cell otherwise.
func (c Cell) distanceInternal(targetXYZ Point, toInterior bool) s1.ChordAngle {
// All calculations are done in the (u,v,w) coordinates of this cell's face.
target := faceXYZtoUVW(int(c.face), targetXYZ)
// Compute dot products with all four upward or rightward-facing edge
// normals. dirIJ is the dot product for the edge corresponding to axis
// I, endpoint J. For example, dir01 is the right edge of the Cell
// (corresponding to the upper endpoint of the u-axis).
dir00 := target.X - target.Z*c.uv.X.Lo
dir01 := target.X - target.Z*c.uv.X.Hi
dir10 := target.Y - target.Z*c.uv.Y.Lo
dir11 := target.Y - target.Z*c.uv.Y.Hi
inside := true
if dir00 < 0 {
inside = false // Target is to the left of the cell
if c.vEdgeIsClosest(target, false) {
return edgeDistance(-dir00, c.uv.X.Lo)
}
}
if dir01 > 0 {
inside = false // Target is to the right of the cell
if c.vEdgeIsClosest(target, true) {
return edgeDistance(dir01, c.uv.X.Hi)
}
}
if dir10 < 0 {
inside = false // Target is below the cell
if c.uEdgeIsClosest(target, false) {
return edgeDistance(-dir10, c.uv.Y.Lo)
}
}
if dir11 > 0 {
inside = false // Target is above the cell
if c.uEdgeIsClosest(target, true) {
return edgeDistance(dir11, c.uv.Y.Hi)
}
}
if inside {
if toInterior {
return s1.ChordAngle(0)
}
// Although you might think of Cells as rectangles, they are actually
// arbitrary quadrilaterals after they are projected onto the sphere.
// Therefore the simplest approach is just to find the minimum distance to
// any of the four edges.
return minChordAngle(edgeDistance(-dir00, c.uv.X.Lo),
edgeDistance(dir01, c.uv.X.Hi),
edgeDistance(-dir10, c.uv.Y.Lo),
edgeDistance(dir11, c.uv.Y.Hi))
}
// Otherwise, the closest point is one of the four cell vertices. Note that
// it is *not* trivial to narrow down the candidates based on the edge sign
// tests above, because (1) the edges don't meet at right angles and (2)
// there are points on the far side of the sphere that are both above *and*
// below the cell, etc.
return minChordAngle(c.vertexChordDist2(target, false, false),
c.vertexChordDist2(target, true, false),
c.vertexChordDist2(target, false, true),
c.vertexChordDist2(target, true, true))
}
// Distance reports the distance from the cell to the given point. Returns zero if
// the point is inside the cell.
func (c Cell) Distance(target Point) s1.ChordAngle {
return c.distanceInternal(target, true)
}
// MaxDistance reports the maximum distance from the cell (including its interior) to the
// given point.
func (c Cell) MaxDistance(target Point) s1.ChordAngle {
// First check the 4 cell vertices. If all are within the hemisphere
// centered around target, the max distance will be to one of these vertices.
targetUVW := faceXYZtoUVW(int(c.face), target)
maxDist := maxChordAngle(c.vertexChordDist2(targetUVW, false, false),
c.vertexChordDist2(targetUVW, true, false),
c.vertexChordDist2(targetUVW, false, true),
c.vertexChordDist2(targetUVW, true, true))
if maxDist <= s1.RightChordAngle {
return maxDist
}
// Otherwise, find the minimum distance dMin to the antipodal point and the
// maximum distance will be pi - dMin.
return s1.StraightChordAngle - c.BoundaryDistance(Point{target.Mul(-1)})
}
// BoundaryDistance reports the distance from the cell boundary to the given point.
func (c Cell) BoundaryDistance(target Point) s1.ChordAngle {
return c.distanceInternal(target, false)
}
// DistanceToEdge returns the minimum distance from the cell to the given edge AB. Returns
// zero if the edge intersects the cell interior.
func (c Cell) DistanceToEdge(a, b Point) s1.ChordAngle {
// Possible optimizations:
// - Currently the (cell vertex, edge endpoint) distances are computed
// twice each, and the length of AB is computed 4 times.
// - To fix this, refactor GetDistance(target) so that it skips calculating
// the distance to each cell vertex. Instead, compute the cell vertices
// and distances in this function, and add a low-level UpdateMinDistance
// that allows the XA, XB, and AB distances to be passed in.
// - It might also be more efficient to do all calculations in UVW-space,
// since this would involve transforming 2 points rather than 4.
// First, check the minimum distance to the edge endpoints A and B.
// (This also detects whether either endpoint is inside the cell.)
minDist := minChordAngle(c.Distance(a), c.Distance(b))
if minDist == 0 {
return minDist
}
// Otherwise, check whether the edge crosses the cell boundary.
crosser := NewChainEdgeCrosser(a, b, c.Vertex(3))
for i := 0; i < 4; i++ {
if crosser.ChainCrossingSign(c.Vertex(i)) != DoNotCross {
return 0
}
}
// Finally, check whether the minimum distance occurs between a cell vertex
// and the interior of the edge AB. (Some of this work is redundant, since
// it also checks the distance to the endpoints A and B again.)
//
// Note that we don't need to check the distance from the interior of AB to
// the interior of a cell edge, because the only way that this distance can
// be minimal is if the two edges cross (already checked above).
for i := 0; i < 4; i++ {
minDist, _ = UpdateMinDistance(c.Vertex(i), a, b, minDist)
}
return minDist
}
// MaxDistanceToEdge returns the maximum distance from the cell (including its interior)
// to the given edge AB.
func (c Cell) MaxDistanceToEdge(a, b Point) s1.ChordAngle {
// If the maximum distance from both endpoints to the cell is less than π/2
// then the maximum distance from the edge to the cell is the maximum of the
// two endpoint distances.
maxDist := maxChordAngle(c.MaxDistance(a), c.MaxDistance(b))
if maxDist <= s1.RightChordAngle {
return maxDist
}
return s1.StraightChordAngle - c.DistanceToEdge(Point{a.Mul(-1)}, Point{b.Mul(-1)})
}
// DistanceToCell returns the minimum distance from this cell to the given cell.
// It returns zero if one cell contains the other.
func (c Cell) DistanceToCell(target Cell) s1.ChordAngle {
// If the cells intersect, the distance is zero. We use the (u,v) ranges
// rather than CellID intersects so that cells that share a partial edge or
// corner are considered to intersect.
if c.face == target.face && c.uv.Intersects(target.uv) {
return 0
}
// Otherwise, the minimum distance always occurs between a vertex of one
// cell and an edge of the other cell (including the edge endpoints). This
// represents a total of 32 possible (vertex, edge) pairs.
//
// TODO(roberts): This could be optimized to be at least 5x faster by pruning
// the set of possible closest vertex/edge pairs using the faces and (u,v)
// ranges of both cells.
var va, vb [4]Point
for i := 0; i < 4; i++ {
va[i] = c.Vertex(i)
vb[i] = target.Vertex(i)
}
minDist := s1.InfChordAngle()
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
minDist, _ = UpdateMinDistance(va[i], vb[j], vb[(j+1)&3], minDist)
minDist, _ = UpdateMinDistance(vb[i], va[j], va[(j+1)&3], minDist)
}
}
return minDist
}
// MaxDistanceToCell returns the maximum distance from the cell (including its
// interior) to the given target cell.
func (c Cell) MaxDistanceToCell(target Cell) s1.ChordAngle {
// Need to check the antipodal target for intersection with the cell. If it
// intersects, the distance is the straight ChordAngle.
// antipodalUV is the transpose of the original UV, interpreted within the opposite face.
antipodalUV := r2.Rect{target.uv.Y, target.uv.X}
if int(c.face) == oppositeFace(int(target.face)) && c.uv.Intersects(antipodalUV) {
return s1.StraightChordAngle
}
// Otherwise, the maximum distance always occurs between a vertex of one
// cell and an edge of the other cell (including the edge endpoints). This
// represents a total of 32 possible (vertex, edge) pairs.
//
// TODO(roberts): When the maximum distance is at most π/2, the maximum is
// always attained between a pair of vertices, and this could be made much
// faster by testing each vertex pair once rather than the current 4 times.
var va, vb [4]Point
for i := 0; i < 4; i++ {
va[i] = c.Vertex(i)
vb[i] = target.Vertex(i)
}
maxDist := s1.NegativeChordAngle
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
maxDist, _ = UpdateMaxDistance(va[i], vb[j], vb[(j+1)&3], maxDist)
maxDist, _ = UpdateMaxDistance(vb[i], va[j], va[(j+1)&3], maxDist)
}
}
return maxDist
}

498
vendor/github.com/golang/geo/s2/cell_index.go generated vendored Normal file
View File

@ -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

944
vendor/github.com/golang/geo/s2/cellid.go generated vendored Normal file
View File

@ -0,0 +1,944 @@
// 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 (
"bytes"
"fmt"
"io"
"math"
"sort"
"strconv"
"strings"
"github.com/golang/geo/r1"
"github.com/golang/geo/r2"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// 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.
//
// Sequentially increasing cell IDs follow a continuous space-filling curve
// over the entire sphere. They have the following properties:
//
// - The ID of a cell at level k consists of a 3-bit face number followed
// by k bit pairs that recursively select one of the four children of
// each cell. The next bit is always 1, and all other bits are 0.
// Therefore, the level of a cell is determined by the position of its
// lowest-numbered bit that is turned on (for a cell at level k, this
// position is 2 * (maxLevel - k)).
//
// - The ID of a parent cell is at the midpoint of the range of IDs spanned
// by its children (or by its descendants at any level).
//
// Leaf cells are often used to represent points on the unit sphere, and
// this type provides methods for converting directly between these two
// representations. For cells that represent 2D regions rather than
// discrete point, it is better to use Cells.
type CellID uint64
// SentinelCellID is an invalid cell ID guaranteed to be larger than any
// valid cell ID. It is used primarily by ShapeIndex. The value is also used
// by some S2 types when encoding data.
// Note that the sentinel's RangeMin == RangeMax == itself.
const SentinelCellID = CellID(^uint64(0))
// sortCellIDs sorts the slice of CellIDs in place.
func sortCellIDs(ci []CellID) {
sort.Sort(cellIDs(ci))
}
// cellIDs implements the Sort interface for slices of CellIDs.
type cellIDs []CellID
func (c cellIDs) Len() int { return len(c) }
func (c cellIDs) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c cellIDs) Less(i, j int) bool { return c[i] < c[j] }
// TODO(dsymonds): Some of these constants should probably be exported.
const (
faceBits = 3
numFaces = 6
// This is the number of levels needed to specify a leaf cell.
maxLevel = 30
// The extra position bit (61 rather than 60) lets us encode each cell as its
// Hilbert curve position at the cell center (which is halfway along the
// portion of the Hilbert curve that fills that cell).
posBits = 2*maxLevel + 1
// The maximum index of a valid leaf cell plus one. The range of valid leaf
// cell indices is [0..maxSize-1].
maxSize = 1 << maxLevel
wrapOffset = uint64(numFaces) << posBits
)
// 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 CellIDFromFacePosLevel(face int, pos uint64, level int) CellID {
return CellID(uint64(face)<<posBits + pos | 1).Parent(level)
}
// CellIDFromFace returns the cell corresponding to a given S2 cube face.
func CellIDFromFace(face int) CellID {
return CellID((uint64(face) << posBits) + lsbForLevel(0))
}
// CellIDFromLatLng returns the leaf cell containing ll.
func CellIDFromLatLng(ll LatLng) CellID {
return cellIDFromPoint(PointFromLatLng(ll))
}
// CellIDFromToken returns a cell given a hex-encoded string of its uint64 ID.
func CellIDFromToken(s string) CellID {
if len(s) > 16 {
return CellID(0)
}
n, err := strconv.ParseUint(s, 16, 64)
if err != nil {
return CellID(0)
}
// Equivalent to right-padding string with zeros to 16 characters.
if len(s) < 16 {
n = n << (4 * uint(16-len(s)))
}
return CellID(n)
}
// ToToken returns a hex-encoded string of the uint64 cell id, with leading
// zeros included but trailing zeros stripped.
func (ci CellID) ToToken() string {
s := strings.TrimRight(fmt.Sprintf("%016x", uint64(ci)), "0")
if len(s) == 0 {
return "X"
}
return s
}
// IsValid reports whether ci represents a valid cell.
func (ci CellID) IsValid() bool {
return ci.Face() < numFaces && (ci.lsb()&0x1555555555555555 != 0)
}
// Face returns the cube face for this cell ID, in the range [0,5].
func (ci CellID) Face() int { return int(uint64(ci) >> posBits) }
// Pos returns the position along the Hilbert curve of this cell ID, in the range [0,2^posBits-1].
func (ci CellID) Pos() uint64 { return uint64(ci) & (^uint64(0) >> faceBits) }
// Level returns the subdivision level of this cell ID, in the range [0, maxLevel].
func (ci CellID) Level() int {
return maxLevel - findLSBSetNonZero64(uint64(ci))>>1
}
// IsLeaf returns whether this cell ID is at the deepest level;
// that is, the level at which the cells are smallest.
func (ci CellID) IsLeaf() bool { return uint64(ci)&1 != 0 }
// 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 (ci CellID) ChildPosition(level int) int {
return int(uint64(ci)>>uint64(2*(maxLevel-level)+1)) & 3
}
// lsbForLevel returns the lowest-numbered bit that is on for cells at the given level.
func lsbForLevel(level int) uint64 { return 1 << uint64(2*(maxLevel-level)) }
// Parent returns the cell at the given level, which must be no greater than the current level.
func (ci CellID) Parent(level int) CellID {
lsb := lsbForLevel(level)
return CellID((uint64(ci) & -lsb) | lsb)
}
// immediateParent is cheaper than Parent, but assumes !ci.isFace().
func (ci CellID) immediateParent() CellID {
nlsb := CellID(ci.lsb() << 2)
return (ci & -nlsb) | nlsb
}
// isFace returns whether this is a top-level (face) cell.
func (ci CellID) isFace() bool { return uint64(ci)&(lsbForLevel(0)-1) == 0 }
// lsb returns the least significant bit that is set.
func (ci CellID) lsb() uint64 { return uint64(ci) & -uint64(ci) }
// 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 (ci CellID) Children() [4]CellID {
var ch [4]CellID
lsb := CellID(ci.lsb())
ch[0] = ci - lsb + lsb>>2
lsb >>= 1
ch[1] = ch[0] + lsb
ch[2] = ch[1] + lsb
ch[3] = ch[2] + lsb
return ch
}
func sizeIJ(level int) int {
return 1 << uint(maxLevel-level)
}
// 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 (ci CellID) EdgeNeighbors() [4]CellID {
level := ci.Level()
size := sizeIJ(level)
f, i, j, _ := ci.faceIJOrientation()
return [4]CellID{
cellIDFromFaceIJWrap(f, i, j-size).Parent(level),
cellIDFromFaceIJWrap(f, i+size, j).Parent(level),
cellIDFromFaceIJWrap(f, i, j+size).Parent(level),
cellIDFromFaceIJWrap(f, i-size, j).Parent(level),
}
}
// 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.)
func (ci CellID) VertexNeighbors(level int) []CellID {
halfSize := sizeIJ(level + 1)
size := halfSize << 1
f, i, j, _ := ci.faceIJOrientation()
var isame, jsame bool
var ioffset, joffset int
if i&halfSize != 0 {
ioffset = size
isame = (i + size) < maxSize
} else {
ioffset = -size
isame = (i - size) >= 0
}
if j&halfSize != 0 {
joffset = size
jsame = (j + size) < maxSize
} else {
joffset = -size
jsame = (j - size) >= 0
}
results := []CellID{
ci.Parent(level),
cellIDFromFaceIJSame(f, i+ioffset, j, isame).Parent(level),
cellIDFromFaceIJSame(f, i, j+joffset, jsame).Parent(level),
}
if isame || jsame {
results = append(results, cellIDFromFaceIJSame(f, i+ioffset, j+joffset, isame && jsame).Parent(level))
}
return results
}
// AllNeighbors returns all neighbors of this cell at the given level. Two
// cells X and Y are neighbors if their boundaries intersect but their
// interiors do not. In particular, two cells that intersect at a single
// point are neighbors. Note that for cells adjacent to a face vertex, the
// same neighbor may be returned more than once. There could be up to eight
// neighbors including the diagonal ones that share the vertex.
//
// This requires level >= ci.Level().
func (ci CellID) AllNeighbors(level int) []CellID {
var neighbors []CellID
face, i, j, _ := ci.faceIJOrientation()
// Find the coordinates of the lower left-hand leaf cell. We need to
// normalize (i,j) to a known position within the cell because level
// may be larger than this cell's level.
size := sizeIJ(ci.Level())
i &= -size
j &= -size
nbrSize := sizeIJ(level)
// We compute the top-bottom, left-right, and diagonal neighbors in one
// pass. The loop test is at the end of the loop to avoid 32-bit overflow.
for k := -nbrSize; ; k += nbrSize {
var sameFace bool
if k < 0 {
sameFace = (j+k >= 0)
} else if k >= size {
sameFace = (j+k < maxSize)
} else {
sameFace = true
// Top and bottom neighbors.
neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+k, j-nbrSize,
j-size >= 0).Parent(level))
neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+k, j+size,
j+size < maxSize).Parent(level))
}
// Left, right, and diagonal neighbors.
neighbors = append(neighbors, cellIDFromFaceIJSame(face, i-nbrSize, j+k,
sameFace && i-size >= 0).Parent(level))
neighbors = append(neighbors, cellIDFromFaceIJSame(face, i+size, j+k,
sameFace && i+size < maxSize).Parent(level))
if k >= size {
break
}
}
return neighbors
}
// RangeMin returns the minimum CellID that is contained within this cell.
func (ci CellID) RangeMin() CellID { return CellID(uint64(ci) - (ci.lsb() - 1)) }
// RangeMax returns the maximum CellID that is contained within this cell.
func (ci CellID) RangeMax() CellID { return CellID(uint64(ci) + (ci.lsb() - 1)) }
// Contains returns true iff the CellID contains oci.
func (ci CellID) Contains(oci CellID) bool {
return uint64(ci.RangeMin()) <= uint64(oci) && uint64(oci) <= uint64(ci.RangeMax())
}
// Intersects returns true iff the CellID intersects oci.
func (ci CellID) Intersects(oci CellID) bool {
return uint64(oci.RangeMin()) <= uint64(ci.RangeMax()) && uint64(oci.RangeMax()) >= uint64(ci.RangeMin())
}
// String returns the string representation of the cell ID in the form "1/3210".
func (ci CellID) String() string {
if !ci.IsValid() {
return "Invalid: " + strconv.FormatInt(int64(ci), 16)
}
var b bytes.Buffer
b.WriteByte("012345"[ci.Face()]) // values > 5 will have been picked off by !IsValid above
b.WriteByte('/')
for level := 1; level <= ci.Level(); level++ {
b.WriteByte("0123"[ci.ChildPosition(level)])
}
return b.String()
}
// cellIDFromString returns a CellID from a string in the form "1/3210".
func cellIDFromString(s string) CellID {
level := len(s) - 2
if level < 0 || level > maxLevel {
return CellID(0)
}
face := int(s[0] - '0')
if face < 0 || face > 5 || s[1] != '/' {
return CellID(0)
}
id := CellIDFromFace(face)
for i := 2; i < len(s); i++ {
childPos := s[i] - '0'
if childPos < 0 || childPos > 3 {
return CellID(0)
}
id = id.Children()[childPos]
}
return id
}
// 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 (ci CellID) Point() Point { return Point{ci.rawPoint().Normalize()} }
// LatLng returns the center of the s2 cell on the sphere as a LatLng.
func (ci CellID) LatLng() LatLng { return LatLngFromPoint(Point{ci.rawPoint()}) }
// 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 (ci CellID) ChildBegin() CellID {
ol := ci.lsb()
return CellID(uint64(ci) - ol + ol>>2)
}
// 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.
// See ChildBegin for example use.
func (ci CellID) ChildBeginAtLevel(level int) CellID {
return CellID(uint64(ci) - ci.lsb() + lsbForLevel(level))
}
// 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 (ci CellID) ChildEnd() CellID {
ol := ci.lsb()
return CellID(uint64(ci) + ol + ol>>2)
}
// 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 (ci CellID) ChildEndAtLevel(level int) CellID {
return CellID(uint64(ci) + ci.lsb() + lsbForLevel(level))
}
// Next returns the next cell along the Hilbert curve.
// This is expected to be used with ChildBegin and ChildEnd,
// or ChildBeginAtLevel and ChildEndAtLevel.
func (ci CellID) Next() CellID {
return CellID(uint64(ci) + ci.lsb()<<1)
}
// Prev returns the previous cell along the Hilbert curve.
func (ci CellID) Prev() CellID {
return CellID(uint64(ci) - ci.lsb()<<1)
}
// NextWrap returns the next cell along the Hilbert curve, wrapping from last to
// first as necessary. This should not be used with ChildBegin and ChildEnd.
func (ci CellID) NextWrap() CellID {
n := ci.Next()
if uint64(n) < wrapOffset {
return n
}
return CellID(uint64(n) - wrapOffset)
}
// PrevWrap returns the previous cell along the Hilbert curve, wrapping around from
// first to last as necessary. This should not be used with ChildBegin and ChildEnd.
func (ci CellID) PrevWrap() CellID {
p := ci.Prev()
if uint64(p) < wrapOffset {
return p
}
return CellID(uint64(p) + wrapOffset)
}
// AdvanceWrap advances or retreats the indicated number of steps along the
// Hilbert curve at the current level and returns the new position. The
// position wraps between the first and last faces as necessary.
func (ci CellID) AdvanceWrap(steps int64) CellID {
if steps == 0 {
return ci
}
// We clamp the number of steps if necessary to ensure that we do not
// advance past the End() or before the Begin() of this level.
shift := uint(2*(maxLevel-ci.Level()) + 1)
if steps < 0 {
if min := -int64(uint64(ci) >> shift); steps < min {
wrap := int64(wrapOffset >> shift)
steps %= wrap
if steps < min {
steps += wrap
}
}
} else {
// Unlike Advance(), we don't want to return End(level).
if max := int64((wrapOffset - uint64(ci)) >> shift); steps > max {
wrap := int64(wrapOffset >> shift)
steps %= wrap
if steps > max {
steps -= wrap
}
}
}
// If steps is negative, then shifting it left has undefined behavior.
// Cast to uint64 for a 2's complement answer.
return CellID(uint64(ci) + (uint64(steps) << shift))
}
// Encode encodes the CellID.
func (ci CellID) Encode(w io.Writer) error {
e := &encoder{w: w}
ci.encode(e)
return e.err
}
func (ci CellID) encode(e *encoder) {
e.writeUint64(uint64(ci))
}
// Decode decodes the CellID.
func (ci *CellID) Decode(r io.Reader) error {
d := &decoder{r: asByteReader(r)}
ci.decode(d)
return d.err
}
func (ci *CellID) decode(d *decoder) {
*ci = CellID(d.readUint64())
}
// TODO: the methods below are not exported yet. Settle on the entire API design
// before doing this. Do we want to mirror the C++ one as closely as possible?
// distanceFromBegin returns the number of steps along the Hilbert curve that
// this cell is from the first node in the S2 hierarchy at our level. (i.e.,
// FromFace(0).ChildBeginAtLevel(ci.Level())). This is analogous to Pos(), but
// for this cell's level.
// The return value is always non-negative.
func (ci CellID) distanceFromBegin() int64 {
return int64(ci >> uint64(2*(maxLevel-ci.Level())+1))
}
// rawPoint returns an unnormalized r3 vector from the origin through the center
// of the s2 cell on the sphere.
func (ci CellID) rawPoint() r3.Vector {
face, si, ti := ci.faceSiTi()
return faceUVToXYZ(face, stToUV((0.5/maxSize)*float64(si)), stToUV((0.5/maxSize)*float64(ti)))
}
// faceSiTi returns the Face/Si/Ti coordinates of the center of the cell.
func (ci CellID) faceSiTi() (face int, si, ti uint32) {
face, i, j, _ := ci.faceIJOrientation()
delta := 0
if ci.IsLeaf() {
delta = 1
} else {
if (i^(int(ci)>>2))&1 != 0 {
delta = 2
}
}
return face, uint32(2*i + delta), uint32(2*j + delta)
}
// faceIJOrientation uses the global lookupIJ table to unfiddle the bits of ci.
func (ci CellID) faceIJOrientation() (f, i, j, orientation int) {
f = ci.Face()
orientation = f & swapMask
nbits := maxLevel - 7*lookupBits // first iteration
// Each iteration maps 8 bits of the Hilbert curve position into
// 4 bits of "i" and "j". The lookup table transforms a key of the
// form "ppppppppoo" to a value of the form "iiiijjjjoo", where the
// letters [ijpo] represents bits of "i", "j", the Hilbert curve
// position, and the Hilbert curve orientation respectively.
//
// On the first iteration we need to be careful to clear out the bits
// representing the cube face.
for k := 7; k >= 0; k-- {
orientation += (int(uint64(ci)>>uint64(k*2*lookupBits+1)) & ((1 << uint(2*nbits)) - 1)) << 2
orientation = lookupIJ[orientation]
i += (orientation >> (lookupBits + 2)) << uint(k*lookupBits)
j += ((orientation >> 2) & ((1 << lookupBits) - 1)) << uint(k*lookupBits)
orientation &= (swapMask | invertMask)
nbits = lookupBits // following iterations
}
// The position of a non-leaf cell at level "n" consists of a prefix of
// 2*n bits that identifies the cell, followed by a suffix of
// 2*(maxLevel-n)+1 bits of the form 10*. If n==maxLevel, the suffix is
// just "1" and has no effect. Otherwise, it consists of "10", followed
// by (maxLevel-n-1) repetitions of "00", followed by "0". The "10" has
// no effect, while each occurrence of "00" has the effect of reversing
// the swapMask bit.
if ci.lsb()&0x1111111111111110 != 0 {
orientation ^= swapMask
}
return
}
// cellIDFromFaceIJ returns a leaf cell given its cube face (range 0..5) and IJ coordinates.
func cellIDFromFaceIJ(f, i, j int) CellID {
// Note that this value gets shifted one bit to the left at the end
// of the function.
n := uint64(f) << (posBits - 1)
// Alternating faces have opposite Hilbert curve orientations; this
// is necessary in order for all faces to have a right-handed
// coordinate system.
bits := f & swapMask
// Each iteration maps 4 bits of "i" and "j" into 8 bits of the Hilbert
// curve position. The lookup table transforms a 10-bit key of the form
// "iiiijjjjoo" to a 10-bit value of the form "ppppppppoo", where the
// letters [ijpo] denote bits of "i", "j", Hilbert curve position, and
// Hilbert curve orientation respectively.
for k := 7; k >= 0; k-- {
mask := (1 << lookupBits) - 1
bits += ((i >> uint(k*lookupBits)) & mask) << (lookupBits + 2)
bits += ((j >> uint(k*lookupBits)) & mask) << 2
bits = lookupPos[bits]
n |= uint64(bits>>2) << (uint(k) * 2 * lookupBits)
bits &= (swapMask | invertMask)
}
return CellID(n*2 + 1)
}
func cellIDFromFaceIJWrap(f, i, j int) CellID {
// Convert i and j to the coordinates of a leaf cell just beyond the
// boundary of this face. This prevents 32-bit overflow in the case
// of finding the neighbors of a face cell.
i = clampInt(i, -1, maxSize)
j = clampInt(j, -1, maxSize)
// We want to wrap these coordinates onto the appropriate adjacent face.
// The easiest way to do this is to convert the (i,j) coordinates to (x,y,z)
// (which yields a point outside the normal face boundary), and then call
// xyzToFaceUV to project back onto the correct face.
//
// The code below converts (i,j) to (si,ti), and then (si,ti) to (u,v) using
// the linear projection (u=2*s-1 and v=2*t-1). (The code further below
// converts back using the inverse projection, s=0.5*(u+1) and t=0.5*(v+1).
// Any projection would work here, so we use the simplest.) We also clamp
// the (u,v) coordinates so that the point is barely outside the
// [-1,1]x[-1,1] face rectangle, since otherwise the reprojection step
// (which divides by the new z coordinate) might change the other
// coordinates enough so that we end up in the wrong leaf cell.
const scale = 1.0 / maxSize
limit := math.Nextafter(1, 2)
u := math.Max(-limit, math.Min(limit, scale*float64((i<<1)+1-maxSize)))
v := math.Max(-limit, math.Min(limit, scale*float64((j<<1)+1-maxSize)))
// Find the leaf cell coordinates on the adjacent face, and convert
// them to a cell id at the appropriate level.
f, u, v = xyzToFaceUV(faceUVToXYZ(f, u, v))
return cellIDFromFaceIJ(f, stToIJ(0.5*(u+1)), stToIJ(0.5*(v+1)))
}
func cellIDFromFaceIJSame(f, i, j int, sameFace bool) CellID {
if sameFace {
return cellIDFromFaceIJ(f, i, j)
}
return cellIDFromFaceIJWrap(f, i, j)
}
// ijToSTMin converts the i- or j-index of a leaf cell to the minimum corresponding
// s- or t-value contained by that cell. The argument must be in the range
// [0..2**30], i.e. up to one position beyond the normal range of valid leaf
// cell indices.
func ijToSTMin(i int) float64 {
return float64(i) / float64(maxSize)
}
// stToIJ converts value in ST coordinates to a value in IJ coordinates.
func stToIJ(s float64) int {
return clampInt(int(math.Floor(maxSize*s)), 0, maxSize-1)
}
// cellIDFromPoint returns a leaf cell containing point p. Usually there is
// exactly one such cell, but for points along the edge of a cell, any
// adjacent cell may be (deterministically) chosen. This is because
// s2.CellIDs are considered to be closed sets. The returned cell will
// always contain the given point, i.e.
//
// CellFromPoint(p).ContainsPoint(p)
//
// is always true.
func cellIDFromPoint(p Point) CellID {
f, u, v := xyzToFaceUV(r3.Vector{p.X, p.Y, p.Z})
i := stToIJ(uvToST(u))
j := stToIJ(uvToST(v))
return cellIDFromFaceIJ(f, i, j)
}
// ijLevelToBoundUV returns the bounds in (u,v)-space for the cell at the given
// level containing the leaf cell with the given (i,j)-coordinates.
func ijLevelToBoundUV(i, j, level int) r2.Rect {
cellSize := sizeIJ(level)
xLo := i & -cellSize
yLo := j & -cellSize
return r2.Rect{
X: r1.Interval{
Lo: stToUV(ijToSTMin(xLo)),
Hi: stToUV(ijToSTMin(xLo + cellSize)),
},
Y: r1.Interval{
Lo: stToUV(ijToSTMin(yLo)),
Hi: stToUV(ijToSTMin(yLo + cellSize)),
},
}
}
// Constants related to the bit mangling in the Cell ID.
const (
lookupBits = 4
swapMask = 0x01
invertMask = 0x02
)
// The following lookup tables are used to convert efficiently between an
// (i,j) cell index and the corresponding position along the Hilbert curve.
//
// lookupPos maps 4 bits of "i", 4 bits of "j", and 2 bits representing the
// orientation of the current cell into 8 bits representing the order in which
// that subcell is visited by the Hilbert curve, plus 2 bits indicating the
// new orientation of the Hilbert curve within that subcell. (Cell
// orientations are represented as combination of swapMask and invertMask.)
//
// lookupIJ is an inverted table used for mapping in the opposite
// direction.
//
// We also experimented with looking up 16 bits at a time (14 bits of position
// plus 2 of orientation) but found that smaller lookup tables gave better
// performance. (2KB fits easily in the primary cache.)
var (
ijToPos = [4][4]int{
{0, 1, 3, 2}, // canonical order
{0, 3, 1, 2}, // axes swapped
{2, 3, 1, 0}, // bits inverted
{2, 1, 3, 0}, // swapped & inverted
}
posToIJ = [4][4]int{
{0, 1, 3, 2}, // canonical order: (0,0), (0,1), (1,1), (1,0)
{0, 2, 3, 1}, // axes swapped: (0,0), (1,0), (1,1), (0,1)
{3, 2, 0, 1}, // bits inverted: (1,1), (1,0), (0,0), (0,1)
{3, 1, 0, 2}, // swapped & inverted: (1,1), (0,1), (0,0), (1,0)
}
posToOrientation = [4]int{swapMask, 0, 0, invertMask | swapMask}
lookupIJ [1 << (2*lookupBits + 2)]int
lookupPos [1 << (2*lookupBits + 2)]int
)
func init() {
initLookupCell(0, 0, 0, 0, 0, 0)
initLookupCell(0, 0, 0, swapMask, 0, swapMask)
initLookupCell(0, 0, 0, invertMask, 0, invertMask)
initLookupCell(0, 0, 0, swapMask|invertMask, 0, swapMask|invertMask)
}
// initLookupCell initializes the lookupIJ table at init time.
func initLookupCell(level, i, j, origOrientation, pos, orientation int) {
if level == lookupBits {
ij := (i << lookupBits) + j
lookupPos[(ij<<2)+origOrientation] = (pos << 2) + orientation
lookupIJ[(pos<<2)+origOrientation] = (ij << 2) + orientation
return
}
level++
i <<= 1
j <<= 1
pos <<= 2
r := posToIJ[orientation]
initLookupCell(level, i+(r[0]>>1), j+(r[0]&1), origOrientation, pos, orientation^posToOrientation[0])
initLookupCell(level, i+(r[1]>>1), j+(r[1]&1), origOrientation, pos+1, orientation^posToOrientation[1])
initLookupCell(level, i+(r[2]>>1), j+(r[2]&1), origOrientation, pos+2, orientation^posToOrientation[2])
initLookupCell(level, i+(r[3]>>1), j+(r[3]&1), origOrientation, pos+3, orientation^posToOrientation[3])
}
// CommonAncestorLevel returns the level of the common ancestor of the two S2 CellIDs.
func (ci CellID) CommonAncestorLevel(other CellID) (level int, ok bool) {
bits := uint64(ci ^ other)
if bits < ci.lsb() {
bits = ci.lsb()
}
if bits < other.lsb() {
bits = other.lsb()
}
msbPos := findMSBSetNonZero64(bits)
if msbPos > 60 {
return 0, false
}
return (60 - msbPos) >> 1, true
}
// 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 (ci CellID) Advance(steps int64) CellID {
if steps == 0 {
return ci
}
// We clamp the number of steps if necessary to ensure that we do not
// advance past the End() or before the Begin() of this level. Note that
// minSteps and maxSteps always fit in a signed 64-bit integer.
stepShift := uint(2*(maxLevel-ci.Level()) + 1)
if steps < 0 {
minSteps := -int64(uint64(ci) >> stepShift)
if steps < minSteps {
steps = minSteps
}
} else {
maxSteps := int64((wrapOffset + ci.lsb() - uint64(ci)) >> stepShift)
if steps > maxSteps {
steps = maxSteps
}
}
return ci + CellID(steps)<<stepShift
}
// centerST return the center of the CellID in (s,t)-space.
func (ci CellID) centerST() r2.Point {
_, si, ti := ci.faceSiTi()
return r2.Point{siTiToST(si), siTiToST(ti)}
}
// sizeST returns the edge length of this CellID in (s,t)-space at the given level.
func (ci CellID) sizeST(level int) float64 {
return ijToSTMin(sizeIJ(level))
}
// boundST returns the bound of this CellID in (s,t)-space.
func (ci CellID) boundST() r2.Rect {
s := ci.sizeST(ci.Level())
return r2.RectFromCenterSize(ci.centerST(), r2.Point{s, s})
}
// centerUV returns the center of this CellID in (u,v)-space. Note that
// the center of the cell is defined as the point at which it is recursively
// subdivided into four children; in general, it is not at the midpoint of
// the (u,v) rectangle covered by the cell.
func (ci CellID) centerUV() r2.Point {
_, si, ti := ci.faceSiTi()
return r2.Point{stToUV(siTiToST(si)), stToUV(siTiToST(ti))}
}
// boundUV returns the bound of this CellID in (u,v)-space.
func (ci CellID) boundUV() r2.Rect {
_, i, j, _ := ci.faceIJOrientation()
return ijLevelToBoundUV(i, j, ci.Level())
}
// expandEndpoint returns a new u-coordinate u' such that the distance from the
// line u=u' to the given edge (u,v0)-(u,v1) is exactly the given distance
// (which is specified as the sine of the angle corresponding to the distance).
func expandEndpoint(u, maxV, sinDist float64) float64 {
// This is based on solving a spherical right triangle, similar to the
// calculation in Cap.RectBound.
// Given an edge of the form (u,v0)-(u,v1), let maxV = max(abs(v0), abs(v1)).
sinUShift := sinDist * math.Sqrt((1+u*u+maxV*maxV)/(1+u*u))
cosUShift := math.Sqrt(1 - sinUShift*sinUShift)
// The following is an expansion of tan(atan(u) + asin(sinUShift)).
return (cosUShift*u + sinUShift) / (cosUShift - sinUShift*u)
}
// expandedByDistanceUV returns a rectangle expanded in (u,v)-space so that it
// contains all points within the given distance of the boundary, and return the
// smallest such rectangle. If the distance is negative, then instead shrink this
// rectangle so that it excludes all points within the given absolute distance
// of the boundary.
//
// Distances are measured *on the sphere*, not in (u,v)-space. For example,
// you can use this method to expand the (u,v)-bound of an CellID so that
// it contains all points within 5km of the original cell. You can then
// test whether a point lies within the expanded bounds like this:
//
// if u, v, ok := faceXYZtoUV(face, point); ok && bound.ContainsPoint(r2.Point{u,v}) { ... }
//
// Limitations:
//
// - Because the rectangle is drawn on one of the six cube-face planes
// (i.e., {x,y,z} = +/-1), it can cover at most one hemisphere. This
// limits the maximum amount that a rectangle can be expanded. For
// example, CellID bounds can be expanded safely by at most 45 degrees
// (about 5000 km on the Earth's surface).
//
// - The implementation is not exact for negative distances. The resulting
// rectangle will exclude all points within the given distance of the
// boundary but may be slightly smaller than necessary.
func expandedByDistanceUV(uv r2.Rect, distance s1.Angle) r2.Rect {
// Expand each of the four sides of the rectangle just enough to include all
// points within the given distance of that side. (The rectangle may be
// expanded by a different amount in (u,v)-space on each side.)
maxU := math.Max(math.Abs(uv.X.Lo), math.Abs(uv.X.Hi))
maxV := math.Max(math.Abs(uv.Y.Lo), math.Abs(uv.Y.Hi))
sinDist := math.Sin(float64(distance))
return r2.Rect{
X: r1.Interval{expandEndpoint(uv.X.Lo, maxV, -sinDist),
expandEndpoint(uv.X.Hi, maxV, sinDist)},
Y: r1.Interval{expandEndpoint(uv.Y.Lo, maxU, -sinDist),
expandEndpoint(uv.Y.Hi, maxU, sinDist)}}
}
// MaxTile returns the largest cell with the same RangeMin such that
// RangeMax < limit.RangeMin. It returns limit if no such cell exists.
// This method can be used to generate a small set of CellIDs that covers
// a given range (a tiling). This example shows how to generate a tiling
// for a semi-open range of leaf cells [start, limit):
//
// for id := start.MaxTile(limit); id != limit; id = id.Next().MaxTile(limit)) { ... }
//
// Note that in general the cells in the tiling will be of different sizes;
// they gradually get larger (near the middle of the range) and then
// gradually get smaller as limit is approached.
func (ci CellID) MaxTile(limit CellID) CellID {
start := ci.RangeMin()
if start >= limit.RangeMin() {
return limit
}
if ci.RangeMax() >= limit {
// The cell is too large, shrink it. Note that when generating coverings
// of CellID ranges, this loop usually executes only once. Also because
// ci.RangeMin() < limit.RangeMin(), we will always exit the loop by the
// time we reach a leaf cell.
for {
ci = ci.Children()[0]
if ci.RangeMax() < limit {
break
}
}
return ci
}
// The cell may be too small. Grow it if necessary. Note that generally
// this loop only iterates once.
for !ci.isFace() {
parent := ci.immediateParent()
if parent.RangeMin() != start || parent.RangeMax() >= limit {
break
}
ci = parent
}
return ci
}
// centerFaceSiTi returns the (face, si, ti) coordinates of the center of the cell.
// Note that although (si,ti) coordinates span the range [0,2**31] in general,
// the cell center coordinates are always in the range [1,2**31-1] and
// therefore can be represented using a signed 32-bit integer.
func (ci CellID) centerFaceSiTi() (face, si, ti int) {
// First we compute the discrete (i,j) coordinates of a leaf cell contained
// within the given cell. Given that cells are represented by the Hilbert
// curve position corresponding at their center, it turns out that the cell
// returned by faceIJOrientation is always one of two leaf cells closest
// to the center of the cell (unless the given cell is a leaf cell itself,
// in which case there is only one possibility).
//
// Given a cell of size s >= 2 (i.e. not a leaf cell), and letting (imin,
// jmin) be the coordinates of its lower left-hand corner, the leaf cell
// returned by faceIJOrientation is either (imin + s/2, jmin + s/2)
// (imin + s/2 - 1, jmin + s/2 - 1). The first case is the one we want.
// We can distinguish these two cases by looking at the low bit of i or
// j. In the second case the low bit is one, unless s == 2 (i.e. the
// level just above leaf cells) in which case the low bit is zero.
//
// In the code below, the expression ((i ^ (int(id) >> 2)) & 1) is true
// if we are in the second case described above.
face, i, j, _ := ci.faceIJOrientation()
delta := 0
if ci.IsLeaf() {
delta = 1
} else if (int64(i)^(int64(ci)>>2))&1 == 1 {
delta = 2
}
// Note that (2 * {i,j} + delta) will never overflow a 32-bit integer.
return face, 2*i + delta, 2*j + delta
}

590
vendor/github.com/golang/geo/s2/cellunion.go generated vendored Normal file
View File

@ -0,0 +1,590 @@
// 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)
}
}

133
vendor/github.com/golang/geo/s2/centroids.go generated vendored Normal file
View File

@ -0,0 +1,133 @@
// Copyright 2018 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 (
"math"
"github.com/golang/geo/r3"
)
// There are several notions of the "centroid" of a triangle. First, there
// is the planar centroid, which is simply the centroid of the ordinary
// (non-spherical) triangle defined by the three vertices. Second, there is
// the surface centroid, which is defined as the intersection of the three
// medians of the spherical triangle. It is possible to show that this
// point is simply the planar centroid projected to the surface of the
// sphere. Finally, there is the true centroid (mass centroid), which 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.
//
// Also 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.
//
// TrueCentroid returns the true centroid of the spherical triangle ABC
// multiplied by the signed area of spherical triangle ABC. 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.
//
// Note that the result of this function is defined to be Point(0, 0, 0) if
// the triangle is degenerate.
func TrueCentroid(a, b, c Point) Point {
// Use Distance to get accurate results for small triangles.
ra := float64(1)
if sa := float64(b.Distance(c)); sa != 0 {
ra = sa / math.Sin(sa)
}
rb := float64(1)
if sb := float64(c.Distance(a)); sb != 0 {
rb = sb / math.Sin(sb)
}
rc := float64(1)
if sc := float64(a.Distance(b)); sc != 0 {
rc = sc / math.Sin(sc)
}
// Now compute a point M such that:
//
// [Ax Ay Az] [Mx] [ra]
// [Bx By Bz] [My] = 0.5 * det(A,B,C) * [rb]
// [Cx Cy Cz] [Mz] [rc]
//
// To improve the numerical stability we subtract the first row (A) from the
// other two rows; this reduces the cancellation error when A, B, and C are
// very close together. Then we solve it using Cramer's rule.
//
// The result is the true centroid of the triangle multiplied by the
// triangle's area.
//
// This code still isn't as numerically stable as it could be.
// The biggest potential improvement is to compute B-A and C-A more
// accurately so that (B-A)x(C-A) is always inside triangle ABC.
x := r3.Vector{a.X, b.X - a.X, c.X - a.X}
y := r3.Vector{a.Y, b.Y - a.Y, c.Y - a.Y}
z := r3.Vector{a.Z, b.Z - a.Z, c.Z - a.Z}
r := r3.Vector{ra, rb - ra, rc - ra}
return Point{r3.Vector{y.Cross(z).Dot(r), z.Cross(x).Dot(r), x.Cross(y).Dot(r)}.Mul(0.5)}
}
// EdgeTrueCentroid returns the true centroid of the spherical geodesic edge AB
// multiplied by the length of the edge AB. As with triangles, the true centroid
// of a collection of line segments may be computed simply by summing the result
// of this method for each segment.
//
// Note that the planar centroid of a line segment is simply 0.5 * (a + b),
// while the surface centroid is (a + b).Normalize(). However neither of
// these values is appropriate for computing the centroid of a collection of
// edges (such as a polyline).
//
// Also note that the result of this function is defined to be Point(0, 0, 0)
// if the edge is degenerate.
func EdgeTrueCentroid(a, b Point) Point {
// The centroid (multiplied by length) is a vector toward the midpoint
// of the edge, whose length is twice the sine of half the angle between
// the two vertices. Defining theta to be this angle, we have:
vDiff := a.Sub(b.Vector) // Length == 2*sin(theta)
vSum := a.Add(b.Vector) // Length == 2*cos(theta)
sin2 := vDiff.Norm2()
cos2 := vSum.Norm2()
if cos2 == 0 {
return Point{} // Ignore antipodal edges.
}
return Point{vSum.Mul(math.Sqrt(sin2 / cos2))} // Length == 2*sin(theta)
}
// PlanarCentroid returns the centroid of the planar triangle ABC. This 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".
func PlanarCentroid(a, b, c Point) Point {
return Point{a.Add(b.Vector).Add(c.Vector).Mul(1. / 3)}
}

190
vendor/github.com/golang/geo/s2/contains_point_query.go generated vendored Normal file
View File

@ -0,0 +1,190 @@
// Copyright 2018 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
// VertexModel defines whether shapes are considered to contain their vertices.
// Note that these definitions differ from the ones used by BooleanOperation.
//
// Note that points other than vertices are never contained by polylines.
// If you want need this behavior, use ClosestEdgeQuery's IsDistanceLess
// with a suitable distance threshold instead.
type VertexModel int
const (
// VertexModelOpen means no shapes contain their vertices (not even
// points). Therefore Contains(Point) returns true if and only if the
// point is in the interior of some polygon.
VertexModelOpen VertexModel = iota
// VertexModelSemiOpen means that polygon point containment is defined
// such that if several polygons tile the region around a vertex, then
// exactly one of those polygons contains that vertex. Points and
// polylines still do not contain any vertices.
VertexModelSemiOpen
// VertexModelClosed means all shapes contain their vertices (including
// points and polylines).
VertexModelClosed
)
// ContainsPointQuery determines whether one or more shapes in a ShapeIndex
// contain a given Point. The ShapeIndex may contain any number of points,
// polylines, and/or polygons (possibly overlapping). Shape boundaries may be
// modeled as Open, SemiOpen, or Closed (this affects whether or not shapes are
// considered to contain their vertices).
//
// This type is not safe for concurrent use.
//
// However, note that if you need to do a large number of point containment
// tests, it is more efficient to re-use the query rather than creating a new
// one each time.
type ContainsPointQuery struct {
model VertexModel
index *ShapeIndex
iter *ShapeIndexIterator
}
// NewContainsPointQuery creates a new instance of the ContainsPointQuery for the index
// and given vertex model choice.
func NewContainsPointQuery(index *ShapeIndex, model VertexModel) *ContainsPointQuery {
return &ContainsPointQuery{
index: index,
model: model,
iter: index.Iterator(),
}
}
// Contains reports whether any shape in the queries index contains the point p
// under the queries vertex model (Open, SemiOpen, or Closed).
func (q *ContainsPointQuery) Contains(p Point) bool {
if !q.iter.LocatePoint(p) {
return false
}
cell := q.iter.IndexCell()
for _, clipped := range cell.shapes {
if q.shapeContains(clipped, q.iter.Center(), p) {
return true
}
}
return false
}
// shapeContains reports whether the clippedShape from the iterator's center position contains
// the given point.
func (q *ContainsPointQuery) shapeContains(clipped *clippedShape, center, p Point) bool {
inside := clipped.containsCenter
numEdges := clipped.numEdges()
if numEdges <= 0 {
return inside
}
shape := q.index.Shape(clipped.shapeID)
if shape.Dimension() != 2 {
// Points and polylines can be ignored unless the vertex model is Closed.
if q.model != VertexModelClosed {
return false
}
// Otherwise, the point is contained if and only if it matches a vertex.
for _, edgeID := range clipped.edges {
edge := shape.Edge(edgeID)
if edge.V0 == p || edge.V1 == p {
return true
}
}
return false
}
// Test containment by drawing a line segment from the cell center to the
// given point and counting edge crossings.
crosser := NewEdgeCrosser(center, p)
for _, edgeID := range clipped.edges {
edge := shape.Edge(edgeID)
sign := crosser.CrossingSign(edge.V0, edge.V1)
if sign == DoNotCross {
continue
}
if sign == MaybeCross {
// For the Open and Closed models, check whether p is a vertex.
if q.model != VertexModelSemiOpen && (edge.V0 == p || edge.V1 == p) {
return (q.model == VertexModelClosed)
}
// C++ plays fast and loose with the int <-> bool conversions here.
if VertexCrossing(crosser.a, crosser.b, edge.V0, edge.V1) {
sign = Cross
} else {
sign = DoNotCross
}
}
inside = inside != (sign == Cross)
}
return inside
}
// ShapeContains reports whether the given shape contains the point under this
// queries vertex model (Open, SemiOpen, or Closed).
//
// This requires the shape belongs to this queries index.
func (q *ContainsPointQuery) ShapeContains(shape Shape, p Point) bool {
if !q.iter.LocatePoint(p) {
return false
}
clipped := q.iter.IndexCell().findByShapeID(q.index.idForShape(shape))
if clipped == nil {
return false
}
return q.shapeContains(clipped, q.iter.Center(), p)
}
// shapeVisitorFunc is a type of function that can be called against shaped in an index.
type shapeVisitorFunc func(shape Shape) bool
// visitContainingShapes visits all shapes in the given index that contain the
// given point p, terminating early if the given visitor function returns false,
// in which case visitContainingShapes returns false. Each shape is
// visited at most once.
func (q *ContainsPointQuery) visitContainingShapes(p Point, f shapeVisitorFunc) bool {
// This function returns false only if the algorithm terminates early
// because the visitor function returned false.
if !q.iter.LocatePoint(p) {
return true
}
cell := q.iter.IndexCell()
for _, clipped := range cell.shapes {
if q.shapeContains(clipped, q.iter.Center(), p) &&
!f(q.index.Shape(clipped.shapeID)) {
return false
}
}
return true
}
// ContainingShapes returns a slice of all shapes that contain the given point.
func (q *ContainsPointQuery) ContainingShapes(p Point) []Shape {
var shapes []Shape
q.visitContainingShapes(p, func(shape Shape) bool {
shapes = append(shapes, shape)
return true
})
return shapes
}
// TODO(roberts): Remaining methods from C++
// type edgeVisitorFunc func(shape ShapeEdge) bool
// func (q *ContainsPointQuery) visitIncidentEdges(p Point, v edgeVisitorFunc) bool

View File

@ -0,0 +1,63 @@
// Copyright 2017 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
// ContainsVertexQuery is used to track the edges entering and leaving the
// given vertex of a Polygon in order to be able to determine if the point is
// contained by the Polygon.
//
// Point containment is defined according to the semi-open boundary model
// which means that if several polygons tile the region around a vertex,
// then exactly one of those polygons contains that vertex.
type ContainsVertexQuery struct {
target Point
edgeMap map[Point]int
}
// NewContainsVertexQuery returns a new query for the given vertex whose
// containment will be determined.
func NewContainsVertexQuery(target Point) *ContainsVertexQuery {
return &ContainsVertexQuery{
target: target,
edgeMap: make(map[Point]int),
}
}
// AddEdge adds the edge between target and v with the given direction.
// (+1 = outgoing, -1 = incoming, 0 = degenerate).
func (q *ContainsVertexQuery) AddEdge(v Point, direction int) {
q.edgeMap[v] += direction
}
// ContainsVertex reports a +1 if the target vertex is contained, -1 if it is
// not contained, and 0 if the incident edges consisted of matched sibling pairs.
func (q *ContainsVertexQuery) ContainsVertex() int {
// Find the unmatched edge that is immediately clockwise from Ortho(P).
referenceDir := Point{q.target.Ortho()}
bestPoint := referenceDir
bestDir := 0
for k, v := range q.edgeMap {
if v == 0 {
continue // This is a "matched" edge.
}
if OrderedCCW(referenceDir, bestPoint, k, q.target) {
bestPoint = k
bestDir = v
}
}
return bestDir
}

258
vendor/github.com/golang/geo/s2/convex_hull_query.go generated vendored Normal file
View File

@ -0,0 +1,258 @@
// Copyright 2018 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"
"github.com/golang/geo/r3"
)
// ConvexHullQuery builds the convex hull of any collection of points,
// polylines, loops, and polygons. It returns a single convex loop.
//
// The convex hull is defined as the smallest convex region on the sphere that
// contains all of your input geometry. Recall that a region is "convex" if
// for every pair of points inside the region, the straight edge between them
// is also inside the region. In our case, a "straight" edge is a geodesic,
// i.e. the shortest path on the sphere between two points.
//
// Containment of input geometry is defined as follows:
//
// - Each input loop and polygon is contained by the convex hull exactly
// (i.e., according to Polygon's Contains(Polygon)).
//
// - Each input point is either contained by the convex hull or is a vertex
// of the convex hull. (Recall that S2Loops do not necessarily contain their
// vertices.)
//
// - For each input polyline, the convex hull contains all of its vertices
// according to the rule for points above. (The definition of convexity
// then ensures that the convex hull also contains the polyline edges.)
//
// To use this type, call the various Add... methods to add your input geometry, and
// then call ConvexHull. Note that ConvexHull does *not* reset the
// state; you can continue adding geometry if desired and compute the convex
// hull again. If you want to start from scratch, simply create a new
// ConvexHullQuery value.
//
// This implement Andrew's monotone chain algorithm, which is a variant of the
// Graham scan (see https://en.wikipedia.org/wiki/Graham_scan). The time
// complexity is O(n log n), and the space required is O(n). In fact only the
// call to "sort" takes O(n log n) time; the rest of the algorithm is linear.
//
// Demonstration of the algorithm and code:
// en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain
//
// This type is not safe for concurrent use.
type ConvexHullQuery struct {
bound Rect
points []Point
}
// NewConvexHullQuery creates a new ConvexHullQuery.
func NewConvexHullQuery() *ConvexHullQuery {
return &ConvexHullQuery{
bound: EmptyRect(),
}
}
// AddPoint adds the given point to the input geometry.
func (q *ConvexHullQuery) AddPoint(p Point) {
q.bound = q.bound.AddPoint(LatLngFromPoint(p))
q.points = append(q.points, p)
}
// AddPolyline adds the given polyline to the input geometry.
func (q *ConvexHullQuery) AddPolyline(p *Polyline) {
q.bound = q.bound.Union(p.RectBound())
q.points = append(q.points, (*p)...)
}
// AddLoop adds the given loop to the input geometry.
func (q *ConvexHullQuery) AddLoop(l *Loop) {
q.bound = q.bound.Union(l.RectBound())
if l.isEmptyOrFull() {
return
}
q.points = append(q.points, l.vertices...)
}
// AddPolygon adds the given polygon to the input geometry.
func (q *ConvexHullQuery) AddPolygon(p *Polygon) {
q.bound = q.bound.Union(p.RectBound())
for _, l := range p.loops {
// Only loops at depth 0 can contribute to the convex hull.
if l.depth == 0 {
q.AddLoop(l)
}
}
}
// CapBound returns a bounding cap for the input geometry provided.
//
// Note that this method does not clear the geometry; you can continue
// adding to it and call this method again if desired.
func (q *ConvexHullQuery) CapBound() Cap {
// We keep track of a rectangular bound rather than a spherical cap because
// it is easy to compute a tight bound for a union of rectangles, whereas it
// is quite difficult to compute a tight bound around a union of caps.
// Also, polygons and polylines implement CapBound() in terms of
// RectBound() for this same reason, so it is much better to keep track
// of a rectangular bound as we go along and convert it at the end.
//
// TODO(roberts): We could compute an optimal bound by implementing Welzl's
// algorithm. However we would still need to have special handling of loops
// and polygons, since if a loop spans more than 180 degrees in any
// direction (i.e., if it contains two antipodal points), then it is not
// enough just to bound its vertices. In this case the only convex bounding
// cap is FullCap(), and the only convex bounding loop is the full loop.
return q.bound.CapBound()
}
// ConvexHull returns a Loop representing the convex hull of the input geometry provided.
//
// If there is no geometry, this method returns an empty loop containing no
// points.
//
// If the geometry spans more than half of the sphere, this method returns a
// full loop containing the entire sphere.
//
// If the geometry contains 1 or 2 points, or a single edge, this method
// returns a very small loop consisting of three vertices (which are a
// superset of the input vertices).
//
// Note that this method does not clear the geometry; you can continue
// adding to the query and call this method again.
func (q *ConvexHullQuery) ConvexHull() *Loop {
c := q.CapBound()
if c.Height() >= 1 {
// The bounding cap is not convex. The current bounding cap
// implementation is not optimal, but nevertheless it is likely that the
// input geometry itself is not contained by any convex polygon. In any
// case, we need a convex bounding cap to proceed with the algorithm below
// (in order to construct a point "origin" that is definitely outside the
// convex hull).
return FullLoop()
}
// Remove duplicates. We need to do this before checking whether there are
// fewer than 3 points.
x := make(map[Point]bool)
r, w := 0, 0 // read/write indexes
for ; r < len(q.points); r++ {
if x[q.points[r]] {
continue
}
q.points[w] = q.points[r]
x[q.points[r]] = true
w++
}
q.points = q.points[:w]
// This code implements Andrew's monotone chain algorithm, which is a simple
// variant of the Graham scan. Rather than sorting by x-coordinate, instead
// we sort the points in CCW order around an origin O such that all points
// are guaranteed to be on one side of some geodesic through O. This
// ensures that as we scan through the points, each new point can only
// belong at the end of the chain (i.e., the chain is monotone in terms of
// the angle around O from the starting point).
origin := Point{c.Center().Ortho()}
sort.Slice(q.points, func(i, j int) bool {
return RobustSign(origin, q.points[i], q.points[j]) == CounterClockwise
})
// Special cases for fewer than 3 points.
switch len(q.points) {
case 0:
return EmptyLoop()
case 1:
return singlePointLoop(q.points[0])
case 2:
return singleEdgeLoop(q.points[0], q.points[1])
}
// Generate the lower and upper halves of the convex hull. Each half
// consists of the maximal subset of vertices such that the edge chain
// makes only left (CCW) turns.
lower := q.monotoneChain()
// reverse the points
for left, right := 0, len(q.points)-1; left < right; left, right = left+1, right-1 {
q.points[left], q.points[right] = q.points[right], q.points[left]
}
upper := q.monotoneChain()
// Remove the duplicate vertices and combine the chains.
lower = lower[:len(lower)-1]
upper = upper[:len(upper)-1]
lower = append(lower, upper...)
return LoopFromPoints(lower)
}
// monotoneChain iterates through the points, selecting the maximal subset of points
// such that the edge chain makes only left (CCW) turns.
func (q *ConvexHullQuery) monotoneChain() []Point {
var output []Point
for _, p := range q.points {
// Remove any points that would cause the chain to make a clockwise turn.
for len(output) >= 2 && RobustSign(output[len(output)-2], output[len(output)-1], p) != CounterClockwise {
output = output[:len(output)-1]
}
output = append(output, p)
}
return output
}
// singlePointLoop constructs a 3-vertex polygon consisting of "p" and two nearby
// vertices. Note that ContainsPoint(p) may be false for the resulting loop.
func singlePointLoop(p Point) *Loop {
const offset = 1e-15
d0 := p.Ortho()
d1 := p.Cross(d0)
vertices := []Point{
p,
{p.Add(d0.Mul(offset)).Normalize()},
{p.Add(d1.Mul(offset)).Normalize()},
}
return LoopFromPoints(vertices)
}
// singleEdgeLoop constructs a loop consisting of the two vertices and their midpoint.
func singleEdgeLoop(a, b Point) *Loop {
// If the points are exactly antipodal we return the full loop.
//
// Note that we could use the code below even in this case (which would
// return a zero-area loop that follows the edge AB), except that (1) the
// direction of AB is defined using symbolic perturbations and therefore is
// not predictable by ordinary users, and (2) Loop disallows anitpodal
// adjacent vertices and so we would need to use 4 vertices to define the
// degenerate loop. (Note that the Loop antipodal vertex restriction is
// historical and now could easily be removed, however it would still have
// the problem that the edge direction is not easily predictable.)
if a.Add(b.Vector) == (r3.Vector{}) {
return FullLoop()
}
// Construct a loop consisting of the two vertices and their midpoint. We
// use Interpolate() to ensure that the midpoint is very close to
// the edge even when its endpoints nearly antipodal.
vertices := []Point{a, b, Interpolate(0.5, a, b)}
loop := LoopFromPoints(vertices)
// The resulting loop may be clockwise, so invert it if necessary.
loop.Normalize()
return loop
}

409
vendor/github.com/golang/geo/s2/crossing_edge_query.go generated vendored Normal file
View File

@ -0,0 +1,409 @@
// Copyright 2017 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"
"github.com/golang/geo/r2"
)
// CrossingEdgeQuery is used to find the Edge IDs of Shapes that are crossed by
// a given edge(s).
//
// Note that if you need to query many edges, it is more efficient to declare
// a single CrossingEdgeQuery instance and reuse it.
//
// If you want to find *all* the pairs of crossing edges, it is more efficient to
// use the not yet implemented VisitCrossings in shapeutil.
type CrossingEdgeQuery struct {
index *ShapeIndex
// temporary values used while processing a query.
a, b r2.Point
iter *ShapeIndexIterator
// candidate cells generated when finding crossings.
cells []*ShapeIndexCell
}
// NewCrossingEdgeQuery creates a CrossingEdgeQuery for the given index.
func NewCrossingEdgeQuery(index *ShapeIndex) *CrossingEdgeQuery {
c := &CrossingEdgeQuery{
index: index,
iter: index.Iterator(),
}
return c
}
// Crossings returns the set of edge of the shape S that intersect the given edge AB.
// If the CrossingType is Interior, then only intersections at a point interior to both
// edges are reported, while if it is CrossingTypeAll then edges that share a vertex
// are also reported.
func (c *CrossingEdgeQuery) Crossings(a, b Point, shape Shape, crossType CrossingType) []int {
edges := c.candidates(a, b, shape)
if len(edges) == 0 {
return nil
}
crosser := NewEdgeCrosser(a, b)
out := 0
n := len(edges)
for in := 0; in < n; in++ {
b := shape.Edge(edges[in])
sign := crosser.CrossingSign(b.V0, b.V1)
if crossType == CrossingTypeAll && (sign == MaybeCross || sign == Cross) || crossType != CrossingTypeAll && sign == Cross {
edges[out] = edges[in]
out++
}
}
if out < n {
edges = edges[0:out]
}
return edges
}
// EdgeMap stores a sorted set of edge ids for each shape.
type EdgeMap map[Shape][]int
// CrossingsEdgeMap returns the set of all edges in the index that intersect the given
// edge AB. If crossType is CrossingTypeInterior, then only intersections at a
// point interior to both edges are reported, while if it is CrossingTypeAll
// then edges that share a vertex are also reported.
//
// The edges are returned as a mapping from shape to the edges of that shape
// that intersect AB. Every returned shape has at least one crossing edge.
func (c *CrossingEdgeQuery) CrossingsEdgeMap(a, b Point, crossType CrossingType) EdgeMap {
edgeMap := c.candidatesEdgeMap(a, b)
if len(edgeMap) == 0 {
return nil
}
crosser := NewEdgeCrosser(a, b)
for shape, edges := range edgeMap {
out := 0
n := len(edges)
for in := 0; in < n; in++ {
edge := shape.Edge(edges[in])
sign := crosser.CrossingSign(edge.V0, edge.V1)
if (crossType == CrossingTypeAll && (sign == MaybeCross || sign == Cross)) || (crossType != CrossingTypeAll && sign == Cross) {
edgeMap[shape][out] = edges[in]
out++
}
}
if out == 0 {
delete(edgeMap, shape)
} else {
if out < n {
edgeMap[shape] = edgeMap[shape][0:out]
}
}
}
return edgeMap
}
// candidates returns a superset of the edges of the given shape that intersect
// the edge AB.
func (c *CrossingEdgeQuery) candidates(a, b Point, shape Shape) []int {
var edges []int
// For small loops it is faster to use brute force. The threshold below was
// determined using benchmarks.
const maxBruteForceEdges = 27
maxEdges := shape.NumEdges()
if maxEdges <= maxBruteForceEdges {
edges = make([]int, maxEdges)
for i := 0; i < maxEdges; i++ {
edges[i] = i
}
return edges
}
// Compute the set of index cells intersected by the query edge.
c.getCellsForEdge(a, b)
if len(c.cells) == 0 {
return nil
}
// Gather all the edges that intersect those cells and sort them.
// TODO(roberts): Shapes don't track their ID, so we need to range over
// the index to find the ID manually.
var shapeID int32
for k, v := range c.index.shapes {
if v == shape {
shapeID = k
}
}
for _, cell := range c.cells {
if cell == nil {
continue
}
clipped := cell.findByShapeID(shapeID)
if clipped == nil {
continue
}
edges = append(edges, clipped.edges...)
}
if len(c.cells) > 1 {
edges = uniqueInts(edges)
}
return edges
}
// uniqueInts returns the sorted uniqued values from the given input.
func uniqueInts(in []int) []int {
var edges []int
m := make(map[int]bool)
for _, i := range in {
if m[i] {
continue
}
m[i] = true
edges = append(edges, i)
}
sort.Ints(edges)
return edges
}
// candidatesEdgeMap returns a map from shapes to the superse of edges for that
// shape that intersect the edge AB.
//
// CAVEAT: This method may return shapes that have an empty set of candidate edges.
// However the return value is non-empty only if at least one shape has a candidate edge.
func (c *CrossingEdgeQuery) candidatesEdgeMap(a, b Point) EdgeMap {
edgeMap := make(EdgeMap)
// If there are only a few edges then it's faster to use brute force. We
// only bother with this optimization when there is a single shape.
if len(c.index.shapes) == 1 {
// Typically this method is called many times, so it is worth checking
// whether the edge map is empty or already consists of a single entry for
// this shape, and skip clearing edge map in that case.
shape := c.index.Shape(0)
// Note that we leave the edge map non-empty even if there are no candidates
// (i.e., there is a single entry with an empty set of edges).
edgeMap[shape] = c.candidates(a, b, shape)
return edgeMap
}
// Compute the set of index cells intersected by the query edge.
c.getCellsForEdge(a, b)
if len(c.cells) == 0 {
return edgeMap
}
// Gather all the edges that intersect those cells and sort them.
for _, cell := range c.cells {
for _, clipped := range cell.shapes {
s := c.index.Shape(clipped.shapeID)
for j := 0; j < clipped.numEdges(); j++ {
edgeMap[s] = append(edgeMap[s], clipped.edges[j])
}
}
}
if len(c.cells) > 1 {
for s, edges := range edgeMap {
edgeMap[s] = uniqueInts(edges)
}
}
return edgeMap
}
// getCells returns the set of ShapeIndexCells that might contain edges intersecting
// the edge AB in the given cell root. This method is used primarily by loop and shapeutil.
func (c *CrossingEdgeQuery) getCells(a, b Point, root *PaddedCell) []*ShapeIndexCell {
aUV, bUV, ok := ClipToFace(a, b, root.id.Face())
if ok {
c.a = aUV
c.b = bUV
edgeBound := r2.RectFromPoints(c.a, c.b)
if root.Bound().Intersects(edgeBound) {
c.computeCellsIntersected(root, edgeBound)
}
}
if len(c.cells) == 0 {
return nil
}
return c.cells
}
// getCellsForEdge populates the cells field to the set of index cells intersected by an edge AB.
func (c *CrossingEdgeQuery) getCellsForEdge(a, b Point) {
c.cells = nil
segments := FaceSegments(a, b)
for _, segment := range segments {
c.a = segment.a
c.b = segment.b
// Optimization: rather than always starting the recursive subdivision at
// the top level face cell, instead we start at the smallest S2CellId that
// contains the edge (the edge root cell). This typically lets us skip
// quite a few levels of recursion since most edges are short.
edgeBound := r2.RectFromPoints(c.a, c.b)
pcell := PaddedCellFromCellID(CellIDFromFace(segment.face), 0)
edgeRoot := pcell.ShrinkToFit(edgeBound)
// Now we need to determine how the edge root cell is related to the cells
// in the spatial index (cellMap). There are three cases:
//
// 1. edgeRoot is an index cell or is contained within an index cell.
// In this case we only need to look at the contents of that cell.
// 2. edgeRoot is subdivided into one or more index cells. In this case
// we recursively subdivide to find the cells intersected by AB.
// 3. edgeRoot does not intersect any index cells. In this case there
// is nothing to do.
relation := c.iter.LocateCellID(edgeRoot)
if relation == Indexed {
// edgeRoot is an index cell or is contained by an index cell (case 1).
c.cells = append(c.cells, c.iter.IndexCell())
} else if relation == Subdivided {
// edgeRoot is subdivided into one or more index cells (case 2). We
// find the cells intersected by AB using recursive subdivision.
if !edgeRoot.isFace() {
pcell = PaddedCellFromCellID(edgeRoot, 0)
}
c.computeCellsIntersected(pcell, edgeBound)
}
}
}
// computeCellsIntersected computes the index cells intersected by the current
// edge that are descendants of pcell and adds them to this queries set of cells.
func (c *CrossingEdgeQuery) computeCellsIntersected(pcell *PaddedCell, edgeBound r2.Rect) {
c.iter.seek(pcell.id.RangeMin())
if c.iter.Done() || c.iter.CellID() > pcell.id.RangeMax() {
// The index does not contain pcell or any of its descendants.
return
}
if c.iter.CellID() == pcell.id {
// The index contains this cell exactly.
c.cells = append(c.cells, c.iter.IndexCell())
return
}
// Otherwise, split the edge among the four children of pcell.
center := pcell.Middle().Lo()
if edgeBound.X.Hi < center.X {
// Edge is entirely contained in the two left children.
c.clipVAxis(edgeBound, center.Y, 0, pcell)
return
} else if edgeBound.X.Lo >= center.X {
// Edge is entirely contained in the two right children.
c.clipVAxis(edgeBound, center.Y, 1, pcell)
return
}
childBounds := c.splitUBound(edgeBound, center.X)
if edgeBound.Y.Hi < center.Y {
// Edge is entirely contained in the two lower children.
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 0, 0), childBounds[0])
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 1, 0), childBounds[1])
} else if edgeBound.Y.Lo >= center.Y {
// Edge is entirely contained in the two upper children.
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 0, 1), childBounds[0])
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, 1, 1), childBounds[1])
} else {
// The edge bound spans all four children. The edge itself intersects
// at most three children (since no padding is being used).
c.clipVAxis(childBounds[0], center.Y, 0, pcell)
c.clipVAxis(childBounds[1], center.Y, 1, pcell)
}
}
// clipVAxis computes the intersected cells recursively for a given padded cell.
// Given either the left (i=0) or right (i=1) side of a padded cell pcell,
// determine whether the current edge intersects the lower child, upper child,
// or both children, and call c.computeCellsIntersected recursively on those children.
// The center is the v-coordinate at the center of pcell.
func (c *CrossingEdgeQuery) clipVAxis(edgeBound r2.Rect, center float64, i int, pcell *PaddedCell) {
if edgeBound.Y.Hi < center {
// Edge is entirely contained in the lower child.
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 0), edgeBound)
} else if edgeBound.Y.Lo >= center {
// Edge is entirely contained in the upper child.
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 1), edgeBound)
} else {
// The edge intersects both children.
childBounds := c.splitVBound(edgeBound, center)
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 0), childBounds[0])
c.computeCellsIntersected(PaddedCellFromParentIJ(pcell, i, 1), childBounds[1])
}
}
// splitUBound returns the bound for two children as a result of spliting the
// current edge at the given value U.
func (c *CrossingEdgeQuery) splitUBound(edgeBound r2.Rect, u float64) [2]r2.Rect {
v := edgeBound.Y.ClampPoint(interpolateFloat64(u, c.a.X, c.b.X, c.a.Y, c.b.Y))
// diag indicates which diagonal of the bounding box is spanned by AB:
// it is 0 if AB has positive slope, and 1 if AB has negative slope.
var diag int
if (c.a.X > c.b.X) != (c.a.Y > c.b.Y) {
diag = 1
}
return splitBound(edgeBound, 0, diag, u, v)
}
// splitVBound returns the bound for two children as a result of spliting the
// current edge into two child edges at the given value V.
func (c *CrossingEdgeQuery) splitVBound(edgeBound r2.Rect, v float64) [2]r2.Rect {
u := edgeBound.X.ClampPoint(interpolateFloat64(v, c.a.Y, c.b.Y, c.a.X, c.b.X))
var diag int
if (c.a.X > c.b.X) != (c.a.Y > c.b.Y) {
diag = 1
}
return splitBound(edgeBound, diag, 0, u, v)
}
// splitBound returns the bounds for the two childrenn as a result of spliting
// the current edge into two child edges at the given point (u,v). uEnd and vEnd
// indicate which bound endpoints of the first child will be updated.
func splitBound(edgeBound r2.Rect, uEnd, vEnd int, u, v float64) [2]r2.Rect {
var childBounds = [2]r2.Rect{
edgeBound,
edgeBound,
}
if uEnd == 1 {
childBounds[0].X.Lo = u
childBounds[1].X.Hi = u
} else {
childBounds[0].X.Hi = u
childBounds[1].X.Lo = u
}
if vEnd == 1 {
childBounds[0].Y.Lo = v
childBounds[1].Y.Hi = v
} else {
childBounds[0].Y.Hi = v
childBounds[1].Y.Lo = v
}
return childBounds
}

149
vendor/github.com/golang/geo/s2/distance_target.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
// Copyright 2019 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 (
"github.com/golang/geo/s1"
)
// The distance interface represents a set of common methods used by algorithms
// that compute distances between various S2 types.
type distance interface {
// chordAngle returns this type as a ChordAngle.
chordAngle() s1.ChordAngle
// fromChordAngle is used to type convert a ChordAngle to this type.
// This is to work around needing to be clever in parts of the code
// where a distanceTarget interface method expects distances, but the
// user only supplies a ChordAngle, and we need to dynamically cast it
// to an appropriate distance interface types.
fromChordAngle(o s1.ChordAngle) distance
// zero returns a zero distance.
zero() distance
// negative returns a value smaller than any valid value.
negative() distance
// infinity returns a value larger than any valid value.
infinity() distance
// less is similar to the Less method in Sort. To get minimum values,
// this would be a less than type operation. For maximum, this would
// be a greater than type operation.
less(other distance) bool
// sub subtracts the other value from this one and returns the new value.
// This is done as a method and not simple mathematical operation to
// allow closest and furthest to implement this in opposite ways.
sub(other distance) distance
// chordAngleBound reports the upper bound on a ChordAngle corresponding
// to this distance. For example, if distance measures WGS84 ellipsoid
// distance then the corresponding angle needs to be 0.56% larger.
chordAngleBound() s1.ChordAngle
// updateDistance may update the value this distance represents
// based on the given input. The updated value and a boolean reporting
// if the value was changed are returned.
updateDistance(other distance) (distance, bool)
}
// distanceTarget is an interface that represents a geometric type to which distances
// are measured.
//
// For example, there are implementations that measure distances to a Point,
// an Edge, a Cell, a CellUnion, and even to an arbitrary collection of geometry
// stored in ShapeIndex.
//
// The distanceTarget types are provided for the benefit of types that measure
// distances and/or find nearby geometry, such as ClosestEdgeQuery, FurthestEdgeQuery,
// ClosestPointQuery, and ClosestCellQuery, etc.
type distanceTarget interface {
// capBound returns a Cap that bounds the set of points whose distance to the
// target is distance.zero().
capBound() Cap
// updateDistanceToPoint updates the distance if the distance to
// the point P is within than the given dist.
// The boolean reports if the value was updated.
updateDistanceToPoint(p Point, dist distance) (distance, bool)
// updateDistanceToEdge updates the distance if the distance to
// the edge E is within than the given dist.
// The boolean reports if the value was updated.
updateDistanceToEdge(e Edge, dist distance) (distance, bool)
// updateDistanceToCell updates the distance if the distance to the cell C
// (including its interior) is within than the given dist.
// The boolean reports if the value was updated.
updateDistanceToCell(c Cell, dist distance) (distance, bool)
// setMaxError potentially updates the value of MaxError, and reports if
// the specific type supports altering it. Whenever one of the
// updateDistanceTo... methods above returns true, the returned distance
// is allowed to be up to maxError larger than the true minimum distance.
// In other words, it gives this target object permission to terminate its
// distance calculation as soon as it has determined that (1) the minimum
// distance is less than minDist and (2) the best possible further
// improvement is less than maxError.
//
// If the target takes advantage of maxError to optimize its distance
// calculation, this method must return true. (Most target types will
// default to return false.)
setMaxError(maxErr s1.ChordAngle) bool
// maxBruteForceIndexSize reports the maximum number of indexed objects for
// which it is faster to compute the distance by brute force (e.g., by testing
// every edge) rather than by using an index.
//
// The following method is provided as a convenience for types that compute
// distances to a collection of indexed geometry, such as ClosestEdgeQuery
// and ClosestPointQuery.
//
// Types that do not support this should return a -1.
maxBruteForceIndexSize() int
// distance returns an instance of the underlying distance type this
// target uses. This is to work around the use of Templates in the C++.
distance() distance
// visitContainingShapes finds all polygons in the given index that
// completely contain a connected component of the target geometry. (For
// example, if the target consists of 10 points, this method finds
// polygons that contain any of those 10 points.) For each such polygon,
// the visit function is called with the Shape of the polygon along with
// a point of the target geometry that is contained by that polygon.
//
// Optionally, any polygon that intersects the target geometry may also be
// returned. In other words, this method returns all polygons that
// contain any connected component of the target, along with an arbitrary
// subset of the polygons that intersect the target.
//
// For example, suppose that the index contains two abutting polygons
// A and B. If the target consists of two points "a" contained by A and
// "b" contained by B, then both A and B are returned. But if the target
// consists of the edge "ab", then any subset of {A, B} could be returned
// (because both polygons intersect the target but neither one contains
// the edge "ab").
//
// If the visit function returns false, this method terminates early and
// returns false as well. Otherwise returns true.
//
// NOTE(roberts): This method exists only for the purpose of implementing
// edgeQuery IncludeInteriors efficiently.
visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool
}
// shapePointVisitorFunc defines a type of function the visitContainingShapes can call.
type shapePointVisitorFunc func(containingShape Shape, targetPoint Point) bool

29
vendor/github.com/golang/geo/s2/doc.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// 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 is a library for working with geometry in S² (spherical geometry).
Its related packages, parallel to this one, are s1 (operates on S¹), r1 (operates on ℝ¹),
r2 (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).
More information including an in-depth introduction to S2 can be found on the
S2 website https://s2geometry.io/
*/
package s2

672
vendor/github.com/golang/geo/s2/edge_clipping.go generated vendored Normal file
View File

@ -0,0 +1,672 @@
// Copyright 2017 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
// This file contains a collection of methods for:
//
// (1) Robustly clipping geodesic edges to the faces of the S2 biunit cube
// (see s2stuv), and
//
// (2) Robustly clipping 2D edges against 2D rectangles.
//
// These functions can be used to efficiently find the set of CellIDs that
// are intersected by a geodesic edge (e.g., see CrossingEdgeQuery).
import (
"math"
"github.com/golang/geo/r1"
"github.com/golang/geo/r2"
"github.com/golang/geo/r3"
)
const (
// edgeClipErrorUVCoord is the maximum error in a u- or v-coordinate
// compared to the exact result, assuming that the points A and B are in
// the rectangle [-1,1]x[1,1] or slightly outside it (by 1e-10 or less).
edgeClipErrorUVCoord = 2.25 * dblEpsilon
// edgeClipErrorUVDist is the maximum distance from a clipped point to
// the corresponding exact result. It is equal to the error in a single
// coordinate because at most one coordinate is subject to error.
edgeClipErrorUVDist = 2.25 * dblEpsilon
// faceClipErrorRadians is the maximum angle between a returned vertex
// and the nearest point on the exact edge AB. It is equal to the
// maximum directional error in PointCross, plus the error when
// projecting points onto a cube face.
faceClipErrorRadians = 3 * dblEpsilon
// faceClipErrorDist is the same angle expressed as a maximum distance
// in (u,v)-space. In other words, a returned vertex is at most this far
// from the exact edge AB projected into (u,v)-space.
faceClipErrorUVDist = 9 * dblEpsilon
// faceClipErrorUVCoord is the maximum angle between a returned vertex
// and the nearest point on the exact edge AB expressed as the maximum error
// in an individual u- or v-coordinate. In other words, for each
// returned vertex there is a point on the exact edge AB whose u- and
// v-coordinates differ from the vertex by at most this amount.
faceClipErrorUVCoord = 9.0 * (1.0 / math.Sqrt2) * dblEpsilon
// intersectsRectErrorUVDist is the maximum error when computing if a point
// intersects with a given Rect. If some point of AB is inside the
// rectangle by at least this distance, the result is guaranteed to be true;
// if all points of AB are outside the rectangle by at least this distance,
// the result is guaranteed to be false. This bound assumes that rect is
// a subset of the rectangle [-1,1]x[-1,1] or extends slightly outside it
// (e.g., by 1e-10 or less).
intersectsRectErrorUVDist = 3 * math.Sqrt2 * dblEpsilon
)
// 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 ClipToFace(a, b Point, face int) (aUV, bUV r2.Point, intersects bool) {
return ClipToPaddedFace(a, b, face, 0.0)
}
// 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 ClipToPaddedFace(a, b Point, f int, padding float64) (aUV, bUV r2.Point, intersects bool) {
// Fast path: both endpoints are on the given face.
if face(a.Vector) == f && face(b.Vector) == f {
au, av := validFaceXYZToUV(f, a.Vector)
bu, bv := validFaceXYZToUV(f, b.Vector)
return r2.Point{au, av}, r2.Point{bu, bv}, true
}
// Convert everything into the (u,v,w) coordinates of the given face. Note
// that the cross product *must* be computed in the original (x,y,z)
// coordinate system because PointCross (unlike the mathematical cross
// product) can produce different results in different coordinate systems
// when one argument is a linear multiple of the other, due to the use of
// symbolic perturbations.
normUVW := pointUVW(faceXYZtoUVW(f, a.PointCross(b)))
aUVW := pointUVW(faceXYZtoUVW(f, a))
bUVW := pointUVW(faceXYZtoUVW(f, b))
// Padding is handled by scaling the u- and v-components of the normal.
// Letting R=1+padding, this means that when we compute the dot product of
// the normal with a cube face vertex (such as (-1,-1,1)), we will actually
// compute the dot product with the scaled vertex (-R,-R,1). This allows
// methods such as intersectsFace, exitAxis, etc, to handle padding
// with no further modifications.
scaleUV := 1 + padding
scaledN := pointUVW{r3.Vector{X: scaleUV * normUVW.X, Y: scaleUV * normUVW.Y, Z: normUVW.Z}}
if !scaledN.intersectsFace() {
return aUV, bUV, false
}
// TODO(roberts): This is a workaround for extremely small vectors where some
// loss of precision can occur in Normalize causing underflow. When PointCross
// is updated to work around this, this can be removed.
if math.Max(math.Abs(normUVW.X), math.Max(math.Abs(normUVW.Y), math.Abs(normUVW.Z))) < math.Ldexp(1, -511) {
normUVW = pointUVW{normUVW.Mul(math.Ldexp(1, 563))}
}
normUVW = pointUVW{normUVW.Normalize()}
aTan := pointUVW{normUVW.Cross(aUVW.Vector)}
bTan := pointUVW{bUVW.Cross(normUVW.Vector)}
// As described in clipDestination, if the sum of the scores from clipping the two
// endpoints is 3 or more, then the segment does not intersect this face.
aUV, aScore := clipDestination(bUVW, aUVW, pointUVW{scaledN.Mul(-1)}, bTan, aTan, scaleUV)
bUV, bScore := clipDestination(aUVW, bUVW, scaledN, aTan, bTan, scaleUV)
return aUV, bUV, aScore+bScore < 3
}
// ClipEdge returns the portion of the edge defined by AB that is contained by the
// given rectangle. If there is no intersection, false is returned and aClip and bClip
// are undefined.
func ClipEdge(a, b r2.Point, clip r2.Rect) (aClip, bClip r2.Point, intersects bool) {
// Compute the bounding rectangle of AB, clip it, and then extract the new
// endpoints from the clipped bound.
bound := r2.RectFromPoints(a, b)
if bound, intersects = clipEdgeBound(a, b, clip, bound); !intersects {
return aClip, bClip, false
}
ai := 0
if a.X > b.X {
ai = 1
}
aj := 0
if a.Y > b.Y {
aj = 1
}
return bound.VertexIJ(ai, aj), bound.VertexIJ(1-ai, 1-aj), true
}
// The three functions below (sumEqual, intersectsFace, intersectsOppositeEdges)
// all compare a sum (u + v) to a third value w. They are implemented in such a
// way that they produce an exact result even though all calculations are done
// with ordinary floating-point operations. Here are the principles on which these
// functions are based:
//
// A. If u + v < w in floating-point, then u + v < w in exact arithmetic.
//
// B. If u + v < w in exact arithmetic, then at least one of the following
// expressions is true in floating-point:
// u + v < w
// u < w - v
// v < w - u
//
// Proof: By rearranging terms and substituting ">" for "<", we can assume
// that all values are non-negative. Now clearly "w" is not the smallest
// value, so assume WLOG that "u" is the smallest. We want to show that
// u < w - v in floating-point. If v >= w/2, the calculation of w - v is
// exact since the result is smaller in magnitude than either input value,
// so the result holds. Otherwise we have u <= v < w/2 and w - v >= w/2
// (even in floating point), so the result also holds.
// sumEqual reports whether u + v == w exactly.
func sumEqual(u, v, w float64) bool {
return (u+v == w) && (u == w-v) && (v == w-u)
}
// pointUVW represents a Point in (u,v,w) coordinate space of a cube face.
type pointUVW Point
// intersectsFace reports whether a given directed line L intersects the cube face F.
// The line L is defined by its normal N in the (u,v,w) coordinates of F.
func (p pointUVW) intersectsFace() bool {
// L intersects the [-1,1]x[-1,1] square in (u,v) if and only if the dot
// products of N with the four corner vertices (-1,-1,1), (1,-1,1), (1,1,1),
// and (-1,1,1) do not all have the same sign. This is true exactly when
// |Nu| + |Nv| >= |Nw|. The code below evaluates this expression exactly.
u := math.Abs(p.X)
v := math.Abs(p.Y)
w := math.Abs(p.Z)
// We only need to consider the cases where u or v is the smallest value,
// since if w is the smallest then both expressions below will have a
// positive LHS and a negative RHS.
return (v >= w-u) && (u >= w-v)
}
// intersectsOppositeEdges reports whether a directed line L intersects two
// opposite edges of a cube face F. This includs the case where L passes
// exactly through a corner vertex of F. The directed line L is defined
// by its normal N in the (u,v,w) coordinates of F.
func (p pointUVW) intersectsOppositeEdges() bool {
// The line L intersects opposite edges of the [-1,1]x[-1,1] (u,v) square if
// and only exactly two of the corner vertices lie on each side of L. This
// is true exactly when ||Nu| - |Nv|| >= |Nw|. The code below evaluates this
// expression exactly.
u := math.Abs(p.X)
v := math.Abs(p.Y)
w := math.Abs(p.Z)
// If w is the smallest, the following line returns an exact result.
if math.Abs(u-v) != w {
return math.Abs(u-v) >= w
}
// Otherwise u - v = w exactly, or w is not the smallest value. In either
// case the following returns the correct result.
if u >= v {
return u-w >= v
}
return v-w >= u
}
// axis represents the possible results of exitAxis.
type axis int
const (
axisU axis = iota
axisV
)
// exitAxis reports which axis the directed line L exits the cube face F on.
// The directed line L is represented by its CCW normal N in the (u,v,w) coordinates
// of F. It returns axisU if L exits through the u=-1 or u=+1 edge, and axisV if L exits
// through the v=-1 or v=+1 edge. Either result is acceptable if L exits exactly
// through a corner vertex of the cube face.
func (p pointUVW) exitAxis() axis {
if p.intersectsOppositeEdges() {
// The line passes through through opposite edges of the face.
// It exits through the v=+1 or v=-1 edge if the u-component of N has a
// larger absolute magnitude than the v-component.
if math.Abs(p.X) >= math.Abs(p.Y) {
return axisV
}
return axisU
}
// The line passes through through two adjacent edges of the face.
// It exits the v=+1 or v=-1 edge if an even number of the components of N
// are negative. We test this using signbit() rather than multiplication
// to avoid the possibility of underflow.
var x, y, z int
if math.Signbit(p.X) {
x = 1
}
if math.Signbit(p.Y) {
y = 1
}
if math.Signbit(p.Z) {
z = 1
}
if x^y^z == 0 {
return axisV
}
return axisU
}
// exitPoint returns the UV coordinates of the point where a directed line L (represented
// by the CCW normal of this point), exits the cube face this point is derived from along
// the given axis.
func (p pointUVW) exitPoint(a axis) r2.Point {
if a == axisU {
u := -1.0
if p.Y > 0 {
u = 1.0
}
return r2.Point{u, (-u*p.X - p.Z) / p.Y}
}
v := -1.0
if p.X < 0 {
v = 1.0
}
return r2.Point{(-v*p.Y - p.Z) / p.X, v}
}
// clipDestination returns a score which is used to indicate if the clipped edge AB
// on the given face intersects the face at all. This function returns the score for
// the given endpoint, which is an integer ranging from 0 to 3. If the sum of the scores
// from both of the endpoints is 3 or more, then edge AB does not intersect this face.
//
// First, it clips the line segment AB to find the clipped destination B' on a given
// face. (The face is specified implicitly by expressing *all arguments* in the (u,v,w)
// coordinates of that face.) Second, it partially computes whether the segment AB
// intersects this face at all. The actual condition is fairly complicated, but it
// turns out that it can be expressed as a "score" that can be computed independently
// when clipping the two endpoints A and B.
func clipDestination(a, b, scaledN, aTan, bTan pointUVW, scaleUV float64) (r2.Point, int) {
var uv r2.Point
// Optimization: if B is within the safe region of the face, use it.
maxSafeUVCoord := 1 - faceClipErrorUVCoord
if b.Z > 0 {
uv = r2.Point{b.X / b.Z, b.Y / b.Z}
if math.Max(math.Abs(uv.X), math.Abs(uv.Y)) <= maxSafeUVCoord {
return uv, 0
}
}
// Otherwise find the point B' where the line AB exits the face.
uv = scaledN.exitPoint(scaledN.exitAxis()).Mul(scaleUV)
p := pointUVW(Point{r3.Vector{uv.X, uv.Y, 1.0}})
// Determine if the exit point B' is contained within the segment. We do this
// by computing the dot products with two inward-facing tangent vectors at A
// and B. If either dot product is negative, we say that B' is on the "wrong
// side" of that point. As the point B' moves around the great circle AB past
// the segment endpoint B, it is initially on the wrong side of B only; as it
// moves further it is on the wrong side of both endpoints; and then it is on
// the wrong side of A only. If the exit point B' is on the wrong side of
// either endpoint, we can't use it; instead the segment is clipped at the
// original endpoint B.
//
// We reject the segment if the sum of the scores of the two endpoints is 3
// or more. Here is what that rule encodes:
// - If B' is on the wrong side of A, then the other clipped endpoint A'
// must be in the interior of AB (otherwise AB' would go the wrong way
// around the circle). There is a similar rule for A'.
// - If B' is on the wrong side of either endpoint (and therefore we must
// use the original endpoint B instead), then it must be possible to
// project B onto this face (i.e., its w-coordinate must be positive).
// This rule is only necessary to handle certain zero-length edges (A=B).
score := 0
if p.Sub(a.Vector).Dot(aTan.Vector) < 0 {
score = 2 // B' is on wrong side of A.
} else if p.Sub(b.Vector).Dot(bTan.Vector) < 0 {
score = 1 // B' is on wrong side of B.
}
if score > 0 { // B' is not in the interior of AB.
if b.Z <= 0 {
score = 3 // B cannot be projected onto this face.
} else {
uv = r2.Point{b.X / b.Z, b.Y / b.Z}
}
}
return uv, score
}
// updateEndpoint returns the interval with the specified endpoint updated to
// the given value. If the value lies beyond the opposite endpoint, nothing is
// changed and false is returned.
func updateEndpoint(bound r1.Interval, highEndpoint bool, value float64) (r1.Interval, bool) {
if !highEndpoint {
if bound.Hi < value {
return bound, false
}
if bound.Lo < value {
bound.Lo = value
}
return bound, true
}
if bound.Lo > value {
return bound, false
}
if bound.Hi > value {
bound.Hi = value
}
return bound, true
}
// clipBoundAxis returns the clipped versions of the bounding intervals for the given
// axes for the line segment from (a0,a1) to (b0,b1) so that neither extends beyond the
// given clip interval. negSlope is a precomputed helper variable that indicates which
// diagonal of the bounding box is spanned by AB; it is false if AB has positive slope,
// and true if AB has negative slope. If the clipping interval doesn't overlap the bounds,
// false is returned.
func clipBoundAxis(a0, b0 float64, bound0 r1.Interval, a1, b1 float64, bound1 r1.Interval,
negSlope bool, clip r1.Interval) (bound0c, bound1c r1.Interval, updated bool) {
if bound0.Lo < clip.Lo {
// If the upper bound is below the clips lower bound, there is nothing to do.
if bound0.Hi < clip.Lo {
return bound0, bound1, false
}
// narrow the intervals lower bound to the clip bound.
bound0.Lo = clip.Lo
if bound1, updated = updateEndpoint(bound1, negSlope, interpolateFloat64(clip.Lo, a0, b0, a1, b1)); !updated {
return bound0, bound1, false
}
}
if bound0.Hi > clip.Hi {
// If the lower bound is above the clips upper bound, there is nothing to do.
if bound0.Lo > clip.Hi {
return bound0, bound1, false
}
// narrow the intervals upper bound to the clip bound.
bound0.Hi = clip.Hi
if bound1, updated = updateEndpoint(bound1, !negSlope, interpolateFloat64(clip.Hi, a0, b0, a1, b1)); !updated {
return bound0, bound1, false
}
}
return bound0, bound1, true
}
// edgeIntersectsRect reports whether the edge defined by AB intersects the
// given closed rectangle to within the error bound.
func edgeIntersectsRect(a, b r2.Point, r r2.Rect) bool {
// First check whether the bounds of a Rect around AB intersects the given rect.
if !r.Intersects(r2.RectFromPoints(a, b)) {
return false
}
// Otherwise AB intersects the rect if and only if all four vertices of rect
// do not lie on the same side of the extended line AB. We test this by finding
// the two vertices of rect with minimum and maximum projections onto the normal
// of AB, and computing their dot products with the edge normal.
n := b.Sub(a).Ortho()
i := 0
if n.X >= 0 {
i = 1
}
j := 0
if n.Y >= 0 {
j = 1
}
max := n.Dot(r.VertexIJ(i, j).Sub(a))
min := n.Dot(r.VertexIJ(1-i, 1-j).Sub(a))
return (max >= 0) && (min <= 0)
}
// clippedEdgeBound returns the bounding rectangle of the portion of the edge defined
// by AB intersected by clip. The resulting bound may be empty. This is a convenience
// function built on top of clipEdgeBound.
func clippedEdgeBound(a, b r2.Point, clip r2.Rect) r2.Rect {
bound := r2.RectFromPoints(a, b)
if b1, intersects := clipEdgeBound(a, b, clip, bound); intersects {
return b1
}
return r2.EmptyRect()
}
// clipEdgeBound clips an edge AB to sequence of rectangles efficiently.
// It represents the clipped edges by their bounding boxes rather than as a pair of
// endpoints. Specifically, let A'B' be some portion of an edge AB, and let bound be
// a tight bound of A'B'. This function returns the bound that is a tight bound
// of A'B' intersected with a given rectangle. If A'B' does not intersect clip,
// it returns false and the original bound.
func clipEdgeBound(a, b r2.Point, clip, bound r2.Rect) (r2.Rect, bool) {
// negSlope indicates which diagonal of the bounding box is spanned by AB: it
// is false if AB has positive slope, and true if AB has negative slope. This is
// used to determine which interval endpoints need to be updated each time
// the edge is clipped.
negSlope := (a.X > b.X) != (a.Y > b.Y)
b0x, b0y, up1 := clipBoundAxis(a.X, b.X, bound.X, a.Y, b.Y, bound.Y, negSlope, clip.X)
if !up1 {
return bound, false
}
b1y, b1x, up2 := clipBoundAxis(a.Y, b.Y, b0y, a.X, b.X, b0x, negSlope, clip.Y)
if !up2 {
return r2.Rect{b0x, b0y}, false
}
return r2.Rect{X: b1x, Y: b1y}, true
}
// interpolateFloat64 returns a value with the same combination of a1 and b1 as the
// given value x is of a and b. This function makes the following guarantees:
// - If x == a, then x1 = a1 (exactly).
// - If x == b, then x1 = b1 (exactly).
// - If a <= x <= b, then a1 <= x1 <= b1 (even if a1 == b1).
// This requires a != b.
func interpolateFloat64(x, a, b, a1, b1 float64) float64 {
// To get results that are accurate near both A and B, we interpolate
// starting from the closer of the two points.
if math.Abs(a-x) <= math.Abs(b-x) {
return a1 + (b1-a1)*(x-a)/(b-a)
}
return b1 + (a1-b1)*(x-b)/(a-b)
}
// FaceSegment represents an edge AB clipped to an S2 cube face. It is
// represented by a face index and a pair of (u,v) coordinates.
type FaceSegment struct {
face int
a, b r2.Point
}
// FaceSegments subdivides the given edge AB at every point where it crosses the
// boundary between two S2 cube faces and returns the corresponding FaceSegments.
// The segments are returned in order from A toward B. The input points must be
// unit length.
//
// This function guarantees that the returned segments form a continuous path
// from A to B, and that all vertices are within faceClipErrorUVDist of the
// line AB. All vertices lie within the [-1,1]x[-1,1] cube face rectangles.
// The results are consistent with Sign, i.e. the edge is well-defined even its
// endpoints are antipodal.
// TODO(roberts): Extend the implementation of PointCross so that this is true.
func FaceSegments(a, b Point) []FaceSegment {
var segment FaceSegment
// Fast path: both endpoints are on the same face.
var aFace, bFace int
aFace, segment.a.X, segment.a.Y = xyzToFaceUV(a.Vector)
bFace, segment.b.X, segment.b.Y = xyzToFaceUV(b.Vector)
if aFace == bFace {
segment.face = aFace
return []FaceSegment{segment}
}
// Starting at A, we follow AB from face to face until we reach the face
// containing B. The following code is designed to ensure that we always
// reach B, even in the presence of numerical errors.
//
// First we compute the normal to the plane containing A and B. This normal
// becomes the ultimate definition of the line AB; it is used to resolve all
// questions regarding where exactly the line goes. Unfortunately due to
// numerical errors, the line may not quite intersect the faces containing
// the original endpoints. We handle this by moving A and/or B slightly if
// necessary so that they are on faces intersected by the line AB.
ab := a.PointCross(b)
aFace, segment.a = moveOriginToValidFace(aFace, a, ab, segment.a)
bFace, segment.b = moveOriginToValidFace(bFace, b, Point{ab.Mul(-1)}, segment.b)
// Now we simply follow AB from face to face until we reach B.
var segments []FaceSegment
segment.face = aFace
bSaved := segment.b
for face := aFace; face != bFace; {
// Complete the current segment by finding the point where AB
// exits the current face.
z := faceXYZtoUVW(face, ab)
n := pointUVW{z.Vector}
exitAxis := n.exitAxis()
segment.b = n.exitPoint(exitAxis)
segments = append(segments, segment)
// Compute the next face intersected by AB, and translate the exit
// point of the current segment into the (u,v) coordinates of the
// next face. This becomes the first point of the next segment.
exitXyz := faceUVToXYZ(face, segment.b.X, segment.b.Y)
face = nextFace(face, segment.b, exitAxis, n, bFace)
exitUvw := faceXYZtoUVW(face, Point{exitXyz})
segment.face = face
segment.a = r2.Point{exitUvw.X, exitUvw.Y}
}
// Finish the last segment.
segment.b = bSaved
return append(segments, segment)
}
// moveOriginToValidFace updates the origin point to a valid face if necessary.
// Given a line segment AB whose origin A has been projected onto a given cube
// face, determine whether it is necessary to project A onto a different face
// instead. This can happen because the normal of the line AB is not computed
// exactly, so that the line AB (defined as the set of points perpendicular to
// the normal) may not intersect the cube face containing A. Even if it does
// intersect the face, the exit point of the line from that face may be on
// the wrong side of A (i.e., in the direction away from B). If this happens,
// we reproject A onto the adjacent face where the line AB approaches A most
// closely. This moves the origin by a small amount, but never more than the
// error tolerances.
func moveOriginToValidFace(face int, a, ab Point, aUV r2.Point) (int, r2.Point) {
// Fast path: if the origin is sufficiently far inside the face, it is
// always safe to use it.
const maxSafeUVCoord = 1 - faceClipErrorUVCoord
if math.Max(math.Abs((aUV).X), math.Abs((aUV).Y)) <= maxSafeUVCoord {
return face, aUV
}
// Otherwise check whether the normal AB even intersects this face.
z := faceXYZtoUVW(face, ab)
n := pointUVW{z.Vector}
if n.intersectsFace() {
// Check whether the point where the line AB exits this face is on the
// wrong side of A (by more than the acceptable error tolerance).
uv := n.exitPoint(n.exitAxis())
exit := faceUVToXYZ(face, uv.X, uv.Y)
aTangent := ab.Normalize().Cross(a.Vector)
// We can use the given face.
if exit.Sub(a.Vector).Dot(aTangent) >= -faceClipErrorRadians {
return face, aUV
}
}
// Otherwise we reproject A to the nearest adjacent face. (If line AB does
// not pass through a given face, it must pass through all adjacent faces.)
var dir int
if math.Abs((aUV).X) >= math.Abs((aUV).Y) {
// U-axis
if aUV.X > 0 {
dir = 1
}
face = uvwFace(face, 0, dir)
} else {
// V-axis
if aUV.Y > 0 {
dir = 1
}
face = uvwFace(face, 1, dir)
}
aUV.X, aUV.Y = validFaceXYZToUV(face, a.Vector)
aUV.X = math.Max(-1.0, math.Min(1.0, aUV.X))
aUV.Y = math.Max(-1.0, math.Min(1.0, aUV.Y))
return face, aUV
}
// nextFace returns the next face that should be visited by FaceSegments, given that
// we have just visited face and we are following the line AB (represented
// by its normal N in the (u,v,w) coordinates of that face). The other
// arguments include the point where AB exits face, the corresponding
// exit axis, and the target face containing the destination point B.
func nextFace(face int, exit r2.Point, axis axis, n pointUVW, targetFace int) int {
// this bit is to work around C++ cleverly casting bools to ints for you.
exitA := exit.X
exit1MinusA := exit.Y
if axis == axisV {
exitA = exit.Y
exit1MinusA = exit.X
}
exitAPos := 0
if exitA > 0 {
exitAPos = 1
}
exit1MinusAPos := 0
if exit1MinusA > 0 {
exit1MinusAPos = 1
}
// We return the face that is adjacent to the exit point along the given
// axis. If line AB exits *exactly* through a corner of the face, there are
// two possible next faces. If one is the target face containing B, then
// we guarantee that we advance to that face directly.
//
// The three conditions below check that (1) AB exits approximately through
// a corner, (2) the adjacent face along the non-exit axis is the target
// face, and (3) AB exits *exactly* through the corner. (The sumEqual
// code checks whether the dot product of (u,v,1) and n is exactly zero.)
if math.Abs(exit1MinusA) == 1 &&
uvwFace(face, int(1-axis), exit1MinusAPos) == targetFace &&
sumEqual(exit.X*n.X, exit.Y*n.Y, -n.Z) {
return targetFace
}
// Otherwise return the face that is adjacent to the exit point in the
// direction of the exit axis.
return uvwFace(face, int(axis), exitAPos)
}

227
vendor/github.com/golang/geo/s2/edge_crosser.go generated vendored Normal file
View File

@ -0,0 +1,227 @@
// Copyright 2017 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 (
"math"
)
// 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, ...
//
// Example usage:
//
// func CountIntersections(a, b Point, edges []Edge) int {
// count := 0
// crosser := NewEdgeCrosser(a, b)
// for _, edge := range edges {
// if crosser.CrossingSign(&edge.First, &edge.Second) != DoNotCross {
// count++
// }
// }
// return count
// }
//
type EdgeCrosser struct {
a Point
b Point
aXb Point
// To reduce the number of calls to expensiveSign, we compute an
// outward-facing tangent at A and B if necessary. If the plane
// perpendicular to one of these tangents separates AB from CD (i.e., one
// edge on each side) then there is no intersection.
aTangent Point // Outward-facing tangent at A.
bTangent Point // Outward-facing tangent at B.
// The fields below are updated for each vertex in the chain.
c Point // Previous vertex in the vertex chain.
acb Direction // The orientation of triangle ACB.
}
// NewEdgeCrosser returns an EdgeCrosser with the fixed edge AB.
func NewEdgeCrosser(a, b Point) *EdgeCrosser {
norm := a.PointCross(b)
return &EdgeCrosser{
a: a,
b: b,
aXb: Point{a.Cross(b.Vector)},
aTangent: Point{a.Cross(norm.Vector)},
bTangent: Point{norm.Cross(b.Vector)},
}
}
// 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 either 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 (e *EdgeCrosser) CrossingSign(c, d Point) Crossing {
if c != e.c {
e.RestartAt(c)
}
return e.ChainCrossingSign(d)
}
// 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 (e *EdgeCrosser) EdgeOrVertexCrossing(c, d Point) bool {
if c != e.c {
e.RestartAt(c)
}
return e.EdgeOrVertexChainCrossing(d)
}
// 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 NewChainEdgeCrosser(a, b, c Point) *EdgeCrosser {
e := NewEdgeCrosser(a, b)
e.RestartAt(c)
return e
}
// 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.
func (e *EdgeCrosser) RestartAt(c Point) {
e.c = c
e.acb = -triageSign(e.a, e.b, e.c)
}
// 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 (e *EdgeCrosser) ChainCrossingSign(d Point) Crossing {
// For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must
// all be oriented the same way (CW or CCW). We keep the orientation of ACB
// as part of our state. When each new point D arrives, we compute the
// orientation of BDA and check whether it matches ACB. This checks whether
// the points C and D are on opposite sides of the great circle through AB.
// Recall that triageSign is invariant with respect to rotating its
// arguments, i.e. ABD has the same orientation as BDA.
bda := triageSign(e.a, e.b, d)
if e.acb == -bda && bda != Indeterminate {
// The most common case -- triangles have opposite orientations. Save the
// current vertex D as the next vertex C, and also save the orientation of
// the new triangle ACB (which is opposite to the current triangle BDA).
e.c = d
e.acb = -bda
return DoNotCross
}
return e.crossingSign(d, bda)
}
// 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 (e *EdgeCrosser) EdgeOrVertexChainCrossing(d Point) bool {
// We need to copy e.c since it is clobbered by ChainCrossingSign.
c := e.c
switch e.ChainCrossingSign(d) {
case DoNotCross:
return false
case Cross:
return true
}
return VertexCrossing(e.a, e.b, c, d)
}
// crossingSign handle the slow path of CrossingSign.
func (e *EdgeCrosser) crossingSign(d Point, bda Direction) Crossing {
// Compute the actual result, and then save the current vertex D as the next
// vertex C, and save the orientation of the next triangle ACB (which is
// opposite to the current triangle BDA).
defer func() {
e.c = d
e.acb = -bda
}()
// At this point, a very common situation is that A,B,C,D are four points on
// a line such that AB does not overlap CD. (For example, this happens when
// a line or curve is sampled finely, or when geometry is constructed by
// computing the union of S2CellIds.) Most of the time, we can determine
// that AB and CD do not intersect using the two outward-facing
// tangents at A and B (parallel to AB) and testing whether AB and CD are on
// opposite sides of the plane perpendicular to one of these tangents. This
// is moderately expensive but still much cheaper than expensiveSign.
// The error in RobustCrossProd is insignificant. The maximum error in
// the call to CrossProd (i.e., the maximum norm of the error vector) is
// (0.5 + 1/sqrt(3)) * dblEpsilon. The maximum error in each call to
// DotProd below is dblEpsilon. (There is also a small relative error
// term that is insignificant because we are comparing the result against a
// constant that is very close to zero.)
maxError := (1.5 + 1/math.Sqrt(3)) * dblEpsilon
if (e.c.Dot(e.aTangent.Vector) > maxError && d.Dot(e.aTangent.Vector) > maxError) || (e.c.Dot(e.bTangent.Vector) > maxError && d.Dot(e.bTangent.Vector) > maxError) {
return DoNotCross
}
// Otherwise, eliminate the cases where two vertices from different edges are
// equal. (These cases could be handled in the code below, but we would rather
// avoid calling ExpensiveSign if possible.)
if e.a == e.c || e.a == d || e.b == e.c || e.b == d {
return MaybeCross
}
// Eliminate the cases where an input edge is degenerate. (Note that in
// most cases, if CD is degenerate then this method is not even called
// because acb and bda have different signs.)
if e.a == e.b || e.c == d {
return DoNotCross
}
// Otherwise it's time to break out the big guns.
if e.acb == Indeterminate {
e.acb = -expensiveSign(e.a, e.b, e.c)
}
if bda == Indeterminate {
bda = expensiveSign(e.a, e.b, d)
}
if bda != e.acb {
return DoNotCross
}
cbd := -RobustSign(e.c, d, e.b)
if cbd != e.acb {
return DoNotCross
}
dac := RobustSign(e.c, d, e.a)
if dac != e.acb {
return DoNotCross
}
return Cross
}

396
vendor/github.com/golang/geo/s2/edge_crossings.go generated vendored Normal file
View File

@ -0,0 +1,396 @@
// Copyright 2017 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"
"math"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
const (
// intersectionError can be set somewhat arbitrarily, because the algorithm
// uses more precision if necessary in order to achieve the specified error.
// The only strict requirement is that intersectionError >= dblEpsilon
// radians. However, using a larger error tolerance makes the algorithm more
// efficient because it reduces the number of cases where exact arithmetic is
// needed.
intersectionError = s1.Angle(8 * dblError)
// intersectionMergeRadius is used to ensure that intersection points that
// are supposed to be coincident are merged back together into a single
// vertex. This is required in order for various polygon operations (union,
// intersection, etc) to work correctly. It is twice the intersection error
// because two coincident intersection points might have errors in
// opposite directions.
intersectionMergeRadius = 2 * intersectionError
)
// A Crossing indicates how edges cross.
type Crossing int
const (
// Cross means the edges cross.
Cross Crossing = iota
// MaybeCross means two vertices from different edges are the same.
MaybeCross
// DoNotCross means the edges do not cross.
DoNotCross
)
func (c Crossing) String() string {
switch c {
case Cross:
return "Cross"
case MaybeCross:
return "MaybeCross"
case DoNotCross:
return "DoNotCross"
default:
return fmt.Sprintf("(BAD CROSSING %d)", c)
}
}
// CrossingSign reports whether the edge AB intersects the edge CD.
// If AB crosses CD at a point that is interior to both edges, Cross is returned.
// If any two vertices from different edges are the same it returns MaybeCross.
// Otherwise it returns DoNotCross.
// If either edge is degenerate (A == B or C == D), the return value is MaybeCross
// if two vertices from different edges are the same and DoNotCross otherwise.
//
// 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
//
// This method implements an exact, consistent perturbation model such
// that no three points are ever considered to be collinear. This means
// that even if you have 4 points A, B, C, D that lie exactly in a line
// (say, around the equator), C and D will be treated as being slightly to
// one side or the other of AB. This is done in a way such that the
// results are always consistent (see RobustSign).
func CrossingSign(a, b, c, d Point) Crossing {
crosser := NewChainEdgeCrosser(a, b, c)
return crosser.ChainCrossingSign(d)
}
// 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.
func VertexCrossing(a, b, c, d Point) bool {
// If A == B or C == D there is no intersection. We need to check this
// case first in case 3 or more input points are identical.
if a == b || c == d {
return false
}
// If any other pair of vertices is equal, there is a crossing if and only
// if OrderedCCW indicates that the edge AB is further CCW around the
// shared vertex O (either A or B) than the edge CD, starting from an
// arbitrary fixed reference point.
// Optimization: if AB=CD or AB=DC, we can avoid most of the calculations.
switch {
case a == c:
return (b == d) || OrderedCCW(Point{a.Ortho()}, d, b, a)
case b == d:
return OrderedCCW(Point{b.Ortho()}, c, a, b)
case a == d:
return (b == c) || OrderedCCW(Point{a.Ortho()}, c, b, a)
case b == c:
return OrderedCCW(Point{b.Ortho()}, d, a, b)
}
return false
}
// EdgeOrVertexCrossing is a convenience function that calls CrossingSign to
// handle cases where all four vertices are distinct, and VertexCrossing to
// handle cases where two or more vertices are the same. This defines a crossing
// function such that point-in-polygon containment tests can be implemented
// by simply counting edge crossings.
func EdgeOrVertexCrossing(a, b, c, d Point) bool {
switch CrossingSign(a, b, c, d) {
case DoNotCross:
return false
case Cross:
return true
default:
return VertexCrossing(a, b, c, d)
}
}
// Intersection returns the intersection point of two edges AB and CD that cross
// (CrossingSign(a,b,c,d) == Crossing).
//
// Useful properties of Intersection:
//
// (1) Intersection(b,a,c,d) == Intersection(a,b,d,c) == Intersection(a,b,c,d)
// (2) Intersection(c,d,a,b) == Intersection(a,b,c,d)
//
// The returned intersection point X is guaranteed to be very close to the
// true intersection point of AB and CD, even if the edges intersect at a
// very small angle.
func Intersection(a0, a1, b0, b1 Point) Point {
// It is difficult to compute the intersection point of two edges accurately
// when the angle between the edges is very small. Previously we handled
// this by only guaranteeing that the returned intersection point is within
// intersectionError of each edge. However, this means that when the edges
// cross at a very small angle, the computed result may be very far from the
// true intersection point.
//
// Instead this function now guarantees that the result is always within
// intersectionError of the true intersection. This requires using more
// sophisticated techniques and in some cases extended precision.
//
// - intersectionStable computes the intersection point using
// projection and interpolation, taking care to minimize cancellation
// error.
//
// - intersectionExact computes the intersection point using precision
// arithmetic and converts the final result back to an Point.
pt, ok := intersectionStable(a0, a1, b0, b1)
if !ok {
pt = intersectionExact(a0, a1, b0, b1)
}
// Make sure the intersection point is on the correct side of the sphere.
// Since all vertices are unit length, and edges are less than 180 degrees,
// (a0 + a1) and (b0 + b1) both have positive dot product with the
// intersection point. We use the sum of all vertices to make sure that the
// result is unchanged when the edges are swapped or reversed.
if pt.Dot((a0.Add(a1.Vector)).Add(b0.Add(b1.Vector))) < 0 {
pt = Point{pt.Mul(-1)}
}
return pt
}
// Computes the cross product of two vectors, normalized to be unit length.
// Also returns the length of the cross
// product before normalization, which is useful for estimating the amount of
// error in the result. For numerical stability, the vectors should both be
// approximately unit length.
func robustNormalWithLength(x, y r3.Vector) (r3.Vector, float64) {
var pt r3.Vector
// This computes 2 * (x.Cross(y)), but has much better numerical
// stability when x and y are unit length.
tmp := x.Sub(y).Cross(x.Add(y))
length := tmp.Norm()
if length != 0 {
pt = tmp.Mul(1 / length)
}
return pt, 0.5 * length // Since tmp == 2 * (x.Cross(y))
}
/*
// intersectionSimple is not used by the C++ so it is skipped here.
*/
// projection returns the projection of aNorm onto X (x.Dot(aNorm)), and a bound
// on the error in the result. aNorm is not necessarily unit length.
//
// The remaining parameters (the length of aNorm (aNormLen) and the edge endpoints
// a0 and a1) allow this dot product to be computed more accurately and efficiently.
func projection(x, aNorm r3.Vector, aNormLen float64, a0, a1 Point) (proj, bound float64) {
// The error in the dot product is proportional to the lengths of the input
// vectors, so rather than using x itself (a unit-length vector) we use
// the vectors from x to the closer of the two edge endpoints. This
// typically reduces the error by a huge factor.
x0 := x.Sub(a0.Vector)
x1 := x.Sub(a1.Vector)
x0Dist2 := x0.Norm2()
x1Dist2 := x1.Norm2()
// If both distances are the same, we need to be careful to choose one
// endpoint deterministically so that the result does not change if the
// order of the endpoints is reversed.
var dist float64
if x0Dist2 < x1Dist2 || (x0Dist2 == x1Dist2 && x0.Cmp(x1) == -1) {
dist = math.Sqrt(x0Dist2)
proj = x0.Dot(aNorm)
} else {
dist = math.Sqrt(x1Dist2)
proj = x1.Dot(aNorm)
}
// This calculation bounds the error from all sources: the computation of
// the normal, the subtraction of one endpoint, and the dot product itself.
// dblError appears because the input points are assumed to be
// normalized in double precision.
//
// For reference, the bounds that went into this calculation are:
// ||N'-N|| <= ((1 + 2 * sqrt(3))||N|| + 32 * sqrt(3) * dblError) * epsilon
// |(A.B)'-(A.B)| <= (1.5 * (A.B) + 1.5 * ||A|| * ||B||) * epsilon
// ||(X-Y)'-(X-Y)|| <= ||X-Y|| * epsilon
bound = (((3.5+2*math.Sqrt(3))*aNormLen+32*math.Sqrt(3)*dblError)*dist + 1.5*math.Abs(proj)) * epsilon
return proj, bound
}
// compareEdges reports whether (a0,a1) is less than (b0,b1) with respect to a total
// ordering on edges that is invariant under edge reversals.
func compareEdges(a0, a1, b0, b1 Point) bool {
if a0.Cmp(a1.Vector) != -1 {
a0, a1 = a1, a0
}
if b0.Cmp(b1.Vector) != -1 {
b0, b1 = b1, b0
}
return a0.Cmp(b0.Vector) == -1 || (a0 == b0 && b0.Cmp(b1.Vector) == -1)
}
// intersectionStable returns the intersection point of the edges (a0,a1) and
// (b0,b1) if it can be computed to within an error of at most intersectionError
// by this function.
//
// The intersection point is not guaranteed to have the correct sign because we
// choose to use the longest of the two edges first. The sign is corrected by
// Intersection.
func intersectionStable(a0, a1, b0, b1 Point) (Point, bool) {
// Sort the two edges so that (a0,a1) is longer, breaking ties in a
// deterministic way that does not depend on the ordering of the endpoints.
// This is desirable for two reasons:
// - So that the result doesn't change when edges are swapped or reversed.
// - It reduces error, since the first edge is used to compute the edge
// normal (where a longer edge means less error), and the second edge
// is used for interpolation (where a shorter edge means less error).
aLen2 := a1.Sub(a0.Vector).Norm2()
bLen2 := b1.Sub(b0.Vector).Norm2()
if aLen2 < bLen2 || (aLen2 == bLen2 && compareEdges(a0, a1, b0, b1)) {
return intersectionStableSorted(b0, b1, a0, a1)
}
return intersectionStableSorted(a0, a1, b0, b1)
}
// intersectionStableSorted is a helper function for intersectionStable.
// It expects that the edges (a0,a1) and (b0,b1) have been sorted so that
// the first edge passed in is longer.
func intersectionStableSorted(a0, a1, b0, b1 Point) (Point, bool) {
var pt Point
// Compute the normal of the plane through (a0, a1) in a stable way.
aNorm := a0.Sub(a1.Vector).Cross(a0.Add(a1.Vector))
aNormLen := aNorm.Norm()
bLen := b1.Sub(b0.Vector).Norm()
// Compute the projection (i.e., signed distance) of b0 and b1 onto the
// plane through (a0, a1). Distances are scaled by the length of aNorm.
b0Dist, b0Error := projection(b0.Vector, aNorm, aNormLen, a0, a1)
b1Dist, b1Error := projection(b1.Vector, aNorm, aNormLen, a0, a1)
// The total distance from b0 to b1 measured perpendicularly to (a0,a1) is
// |b0Dist - b1Dist|. Note that b0Dist and b1Dist generally have
// opposite signs because b0 and b1 are on opposite sides of (a0, a1). The
// code below finds the intersection point by interpolating along the edge
// (b0, b1) to a fractional distance of b0Dist / (b0Dist - b1Dist).
//
// It can be shown that the maximum error in the interpolation fraction is
//
// (b0Dist * b1Error - b1Dist * b0Error) / (distSum * (distSum - errorSum))
//
// We save ourselves some work by scaling the result and the error bound by
// "distSum", since the result is normalized to be unit length anyway.
distSum := math.Abs(b0Dist - b1Dist)
errorSum := b0Error + b1Error
if distSum <= errorSum {
return pt, false // Error is unbounded in this case.
}
x := b1.Mul(b0Dist).Sub(b0.Mul(b1Dist))
err := bLen*math.Abs(b0Dist*b1Error-b1Dist*b0Error)/
(distSum-errorSum) + 2*distSum*epsilon
// Finally we normalize the result, compute the corresponding error, and
// check whether the total error is acceptable.
xLen := x.Norm()
maxError := intersectionError
if err > (float64(maxError)-epsilon)*xLen {
return pt, false
}
return Point{x.Mul(1 / xLen)}, true
}
// intersectionExact returns the intersection point of (a0, a1) and (b0, b1)
// using precise arithmetic. Note that the result is not exact because it is
// rounded down to double precision at the end. Also, the intersection point
// is not guaranteed to have the correct sign (i.e., the return value may need
// to be negated).
func intersectionExact(a0, a1, b0, b1 Point) Point {
// Since we are using presice arithmetic, we don't need to worry about
// numerical stability.
a0P := r3.PreciseVectorFromVector(a0.Vector)
a1P := r3.PreciseVectorFromVector(a1.Vector)
b0P := r3.PreciseVectorFromVector(b0.Vector)
b1P := r3.PreciseVectorFromVector(b1.Vector)
aNormP := a0P.Cross(a1P)
bNormP := b0P.Cross(b1P)
xP := aNormP.Cross(bNormP)
// The final Normalize() call is done in double precision, which creates a
// directional error of up to 2*dblError. (Precise conversion and Normalize()
// each contribute up to dblError of directional error.)
x := xP.Vector()
if x == (r3.Vector{}) {
// The two edges are exactly collinear, but we still consider them to be
// "crossing" because of simulation of simplicity. Out of the four
// endpoints, exactly two lie in the interior of the other edge. Of
// those two we return the one that is lexicographically smallest.
x = r3.Vector{10, 10, 10} // Greater than any valid S2Point
aNorm := Point{aNormP.Vector()}
bNorm := Point{bNormP.Vector()}
if OrderedCCW(b0, a0, b1, bNorm) && a0.Cmp(x) == -1 {
return a0
}
if OrderedCCW(b0, a1, b1, bNorm) && a1.Cmp(x) == -1 {
return a1
}
if OrderedCCW(a0, b0, a1, aNorm) && b0.Cmp(x) == -1 {
return b0
}
if OrderedCCW(a0, b1, a1, aNorm) && b1.Cmp(x) == -1 {
return b1
}
}
return Point{x}
}

408
vendor/github.com/golang/geo/s2/edge_distances.go generated vendored Normal file
View File

@ -0,0 +1,408 @@
// Copyright 2017 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
// This file defines a collection of methods for computing the distance to an edge,
// interpolating along an edge, projecting points onto edges, etc.
import (
"math"
"github.com/golang/geo/s1"
)
// DistanceFromSegment returns the distance of point X from line segment AB.
// The points are expected to be normalized. The result is very accurate for small
// distances but may have some numerical error if the distance is large
// (approximately pi/2 or greater). The case A == B is handled correctly.
func DistanceFromSegment(x, a, b Point) s1.Angle {
var minDist s1.ChordAngle
minDist, _ = updateMinDistance(x, a, b, minDist, true)
return minDist.Angle()
}
// IsDistanceLess reports whether the distance from X to the edge AB is less
// than limit. (For less than or equal to, specify limit.Successor()).
// This method is faster than DistanceFromSegment(). If you want to
// compare against a fixed s1.Angle, you should convert it to an s1.ChordAngle
// once and save the value, since this conversion is relatively expensive.
func IsDistanceLess(x, a, b Point, limit s1.ChordAngle) bool {
_, less := UpdateMinDistance(x, a, b, limit)
return less
}
// UpdateMinDistance checks if the distance from X to the edge AB is less
// than minDist, and if so, returns the updated value and true.
// The case A == B is handled correctly.
//
// Use this method when you want to compute many distances and keep track of
// the minimum. It is significantly faster than using DistanceFromSegment
// because (1) using s1.ChordAngle is much faster than s1.Angle, and (2) it
// can save a lot of work by not actually computing the distance when it is
// obviously larger than the current minimum.
func UpdateMinDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
return updateMinDistance(x, a, b, minDist, false)
}
// UpdateMaxDistance checks if the distance from X to the edge AB is greater
// than maxDist, and if so, returns the updated value and true.
// Otherwise it returns false. The case A == B is handled correctly.
func UpdateMaxDistance(x, a, b Point, maxDist s1.ChordAngle) (s1.ChordAngle, bool) {
dist := maxChordAngle(ChordAngleBetweenPoints(x, a), ChordAngleBetweenPoints(x, b))
if dist > s1.RightChordAngle {
dist, _ = updateMinDistance(Point{x.Mul(-1)}, a, b, dist, true)
dist = s1.StraightChordAngle - dist
}
if maxDist < dist {
return dist, true
}
return maxDist, false
}
// IsInteriorDistanceLess reports whether the minimum distance from X to the edge
// AB is attained at an interior point of AB (i.e., not an endpoint), and that
// distance is less than limit. (Specify limit.Successor() for less than or equal to).
func IsInteriorDistanceLess(x, a, b Point, limit s1.ChordAngle) bool {
_, less := UpdateMinInteriorDistance(x, a, b, limit)
return less
}
// UpdateMinInteriorDistance reports whether the minimum distance from X to AB
// is attained at an interior point of AB (i.e., not an endpoint), and that distance
// is less than minDist. If so, the value of minDist is updated and true is returned.
// Otherwise it is unchanged and returns false.
func UpdateMinInteriorDistance(x, a, b Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
return interiorDist(x, a, b, minDist, false)
}
// Project returns the point along the edge AB that is closest to the point X.
// The fractional distance of this point along the edge AB can be obtained
// using DistanceFraction.
//
// This requires that all points are unit length.
func Project(x, a, b Point) Point {
aXb := a.PointCross(b)
// Find the closest point to X along the great circle through AB.
p := x.Sub(aXb.Mul(x.Dot(aXb.Vector) / aXb.Vector.Norm2()))
// If this point is on the edge AB, then it's the closest point.
if Sign(aXb, a, Point{p}) && Sign(Point{p}, b, aXb) {
return Point{p.Normalize()}
}
// Otherwise, the closest point is either A or B.
if x.Sub(a.Vector).Norm2() <= x.Sub(b.Vector).Norm2() {
return a
}
return b
}
// DistanceFraction returns the distance ratio of the point X along an edge AB.
// If X is on the line segment AB, this is the fraction T such
// that X == Interpolate(T, A, B).
//
// This requires that A and B are distinct.
func DistanceFraction(x, a, b Point) float64 {
d0 := x.Angle(a.Vector)
d1 := x.Angle(b.Vector)
return float64(d0 / (d0 + d1))
}
// 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 Interpolate(t float64, a, b Point) Point {
if t == 0 {
return a
}
if t == 1 {
return b
}
ab := a.Angle(b.Vector)
return InterpolateAtDistance(s1.Angle(t)*ab, a, b)
}
// InterpolateAtDistance returns the point X along the line segment AB whose
// distance from A is the angle ax.
func InterpolateAtDistance(ax s1.Angle, a, b Point) Point {
aRad := ax.Radians()
// Use PointCross to compute the tangent vector at A towards B. The
// result is always perpendicular to A, even if A=B or A=-B, but it is not
// necessarily unit length. (We effectively normalize it below.)
normal := a.PointCross(b)
tangent := normal.Vector.Cross(a.Vector)
// Now compute the appropriate linear combination of A and "tangent". With
// infinite precision the result would always be unit length, but we
// normalize it anyway to ensure that the error is within acceptable bounds.
// (Otherwise errors can build up when the result of one interpolation is
// fed into another interpolation.)
return Point{(a.Mul(math.Cos(aRad)).Add(tangent.Mul(math.Sin(aRad) / tangent.Norm()))).Normalize()}
}
// minUpdateDistanceMaxError returns the maximum error in the result of
// UpdateMinDistance (and the associated functions such as
// UpdateMinInteriorDistance, IsDistanceLess, etc), assuming that all
// input points are normalized to within the bounds guaranteed by r3.Vector's
// Normalize. The error can be added or subtracted from an s1.ChordAngle
// using its Expanded method.
func minUpdateDistanceMaxError(dist s1.ChordAngle) float64 {
// There are two cases for the maximum error in UpdateMinDistance(),
// depending on whether the closest point is interior to the edge.
return math.Max(minUpdateInteriorDistanceMaxError(dist), dist.MaxPointError())
}
// minUpdateInteriorDistanceMaxError returns the maximum error in the result of
// UpdateMinInteriorDistance, assuming that all input points are normalized
// to within the bounds guaranteed by Point's Normalize. The error can be added
// or subtracted from an s1.ChordAngle using its Expanded method.
//
// Note that accuracy goes down as the distance approaches 0 degrees or 180
// degrees (for different reasons). Near 0 degrees the error is acceptable
// for all practical purposes (about 1.2e-15 radians ~= 8 nanometers). For
// exactly antipodal points the maximum error is quite high (0.5 meters),
// but this error drops rapidly as the points move away from antipodality
// (approximately 1 millimeter for points that are 50 meters from antipodal,
// and 1 micrometer for points that are 50km from antipodal).
//
// TODO(roberts): Currently the error bound does not hold for edges whose endpoints
// are antipodal to within about 1e-15 radians (less than 1 micron). This could
// be fixed by extending PointCross to use higher precision when necessary.
func minUpdateInteriorDistanceMaxError(dist s1.ChordAngle) float64 {
// If a point is more than 90 degrees from an edge, then the minimum
// distance is always to one of the endpoints, not to the edge interior.
if dist >= s1.RightChordAngle {
return 0.0
}
// This bound includes all source of error, assuming that the input points
// are normalized. a and b are components of chord length that are
// perpendicular and parallel to a plane containing the edge respectively.
b := math.Min(1.0, 0.5*float64(dist))
a := math.Sqrt(b * (2 - b))
return ((2.5+2*math.Sqrt(3)+8.5*a)*a +
(2+2*math.Sqrt(3)/3+6.5*(1-b))*b +
(23+16/math.Sqrt(3))*dblEpsilon) * dblEpsilon
}
// updateMinDistance computes the distance from a point X to a line segment AB,
// and if either the distance was less than the given minDist, or alwaysUpdate is
// true, the value and whether it was updated are returned.
func updateMinDistance(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) {
if d, ok := interiorDist(x, a, b, minDist, alwaysUpdate); ok {
// Minimum distance is attained along the edge interior.
return d, true
}
// Otherwise the minimum distance is to one of the endpoints.
xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2()
dist := s1.ChordAngle(math.Min(xa2, xb2))
if !alwaysUpdate && dist >= minDist {
return minDist, false
}
return dist, true
}
// interiorDist returns the shortest distance from point x to edge ab, assuming
// that the closest point to X is interior to AB. If the closest point is not
// interior to AB, interiorDist returns (minDist, false). If alwaysUpdate is set to
// false, the distance is only updated when the value exceeds certain the given minDist.
func interiorDist(x, a, b Point, minDist s1.ChordAngle, alwaysUpdate bool) (s1.ChordAngle, bool) {
// Chord distance of x to both end points a and b.
xa2, xb2 := (x.Sub(a.Vector)).Norm2(), x.Sub(b.Vector).Norm2()
// The closest point on AB could either be one of the two vertices (the
// vertex case) or in the interior (the interior case). Let C = A x B.
// If X is in the spherical wedge extending from A to B around the axis
// through C, then we are in the interior case. Otherwise we are in the
// vertex case.
//
// Check whether we might be in the interior case. For this to be true, XAB
// and XBA must both be acute angles. Checking this condition exactly is
// expensive, so instead we consider the planar triangle ABX (which passes
// through the sphere's interior). The planar angles XAB and XBA are always
// less than the corresponding spherical angles, so if we are in the
// interior case then both of these angles must be acute.
//
// We check this by computing the squared edge lengths of the planar
// triangle ABX, and testing whether angles XAB and XBA are both acute using
// the law of cosines:
//
// | XA^2 - XB^2 | < AB^2 (*)
//
// This test must be done conservatively (taking numerical errors into
// account) since otherwise we might miss a situation where the true minimum
// distance is achieved by a point on the edge interior.
//
// There are two sources of error in the expression above (*). The first is
// that points are not normalized exactly; they are only guaranteed to be
// within 2 * dblEpsilon of unit length. Under the assumption that the two
// sides of (*) are nearly equal, the total error due to normalization errors
// can be shown to be at most
//
// 2 * dblEpsilon * (XA^2 + XB^2 + AB^2) + 8 * dblEpsilon ^ 2 .
//
// The other source of error is rounding of results in the calculation of (*).
// Each of XA^2, XB^2, AB^2 has a maximum relative error of 2.5 * dblEpsilon,
// plus an additional relative error of 0.5 * dblEpsilon in the final
// subtraction which we further bound as 0.25 * dblEpsilon * (XA^2 + XB^2 +
// AB^2) for convenience. This yields a final error bound of
//
// 4.75 * dblEpsilon * (XA^2 + XB^2 + AB^2) + 8 * dblEpsilon ^ 2 .
ab2 := a.Sub(b.Vector).Norm2()
maxError := (4.75*dblEpsilon*(xa2+xb2+ab2) + 8*dblEpsilon*dblEpsilon)
if math.Abs(xa2-xb2) >= ab2+maxError {
return minDist, false
}
// The minimum distance might be to a point on the edge interior. Let R
// be closest point to X that lies on the great circle through AB. Rather
// than computing the geodesic distance along the surface of the sphere,
// instead we compute the "chord length" through the sphere's interior.
//
// The squared chord length XR^2 can be expressed as XQ^2 + QR^2, where Q
// is the point X projected onto the plane through the great circle AB.
// The distance XQ^2 can be written as (X.C)^2 / |C|^2 where C = A x B.
// We ignore the QR^2 term and instead use XQ^2 as a lower bound, since it
// is faster and the corresponding distance on the Earth's surface is
// accurate to within 1% for distances up to about 1800km.
c := a.PointCross(b)
c2 := c.Norm2()
xDotC := x.Dot(c.Vector)
xDotC2 := xDotC * xDotC
if !alwaysUpdate && xDotC2 > c2*float64(minDist) {
// The closest point on the great circle AB is too far away. We need to
// test this using ">" rather than ">=" because the actual minimum bound
// on the distance is (xDotC2 / c2), which can be rounded differently
// than the (more efficient) multiplicative test above.
return minDist, false
}
// Otherwise we do the exact, more expensive test for the interior case.
// This test is very likely to succeed because of the conservative planar
// test we did initially.
//
// TODO(roberts): Ensure that the errors in test are accurately reflected in the
// minUpdateInteriorDistanceMaxError.
cx := c.Cross(x.Vector)
if a.Sub(x.Vector).Dot(cx) >= 0 || b.Sub(x.Vector).Dot(cx) <= 0 {
return minDist, false
}
// Compute the squared chord length XR^2 = XQ^2 + QR^2 (see above).
// This calculation has good accuracy for all chord lengths since it
// is based on both the dot product and cross product (rather than
// deriving one from the other). However, note that the chord length
// representation itself loses accuracy as the angle approaches π.
qr := 1 - math.Sqrt(cx.Norm2()/c2)
dist := s1.ChordAngle((xDotC2 / c2) + (qr * qr))
if !alwaysUpdate && dist >= minDist {
return minDist, false
}
return dist, true
}
// updateEdgePairMinDistance computes the minimum distance between the given
// pair of edges. If the two edges cross, the distance is zero. The cases
// a0 == a1 and b0 == b1 are handled correctly.
func updateEdgePairMinDistance(a0, a1, b0, b1 Point, minDist s1.ChordAngle) (s1.ChordAngle, bool) {
if minDist == 0 {
return 0, false
}
if CrossingSign(a0, a1, b0, b1) == Cross {
minDist = 0
return 0, true
}
// Otherwise, the minimum distance is achieved at an endpoint of at least
// one of the two edges. We ensure that all four possibilities are always checked.
//
// The calculation below computes each of the six vertex-vertex distances
// twice (this could be optimized).
var ok1, ok2, ok3, ok4 bool
minDist, ok1 = UpdateMinDistance(a0, b0, b1, minDist)
minDist, ok2 = UpdateMinDistance(a1, b0, b1, minDist)
minDist, ok3 = UpdateMinDistance(b0, a0, a1, minDist)
minDist, ok4 = UpdateMinDistance(b1, a0, a1, minDist)
return minDist, ok1 || ok2 || ok3 || ok4
}
// updateEdgePairMaxDistance reports the minimum distance between the given pair of edges.
// If one edge crosses the antipodal reflection of the other, the distance is pi.
func updateEdgePairMaxDistance(a0, a1, b0, b1 Point, maxDist s1.ChordAngle) (s1.ChordAngle, bool) {
if maxDist == s1.StraightChordAngle {
return s1.StraightChordAngle, false
}
if CrossingSign(a0, a1, Point{b0.Mul(-1)}, Point{b1.Mul(-1)}) == Cross {
return s1.StraightChordAngle, true
}
// Otherwise, the maximum distance is achieved at an endpoint of at least
// one of the two edges. We ensure that all four possibilities are always checked.
//
// The calculation below computes each of the six vertex-vertex distances
// twice (this could be optimized).
var ok1, ok2, ok3, ok4 bool
maxDist, ok1 = UpdateMaxDistance(a0, b0, b1, maxDist)
maxDist, ok2 = UpdateMaxDistance(a1, b0, b1, maxDist)
maxDist, ok3 = UpdateMaxDistance(b0, a0, a1, maxDist)
maxDist, ok4 = UpdateMaxDistance(b1, a0, a1, maxDist)
return maxDist, ok1 || ok2 || ok3 || ok4
}
// EdgePairClosestPoints returns the pair of points (a, b) that achieves the
// minimum distance between edges a0a1 and b0b1, where a is a point on a0a1 and
// b is a point on b0b1. If the two edges intersect, a and b are both equal to
// the intersection point. Handles a0 == a1 and b0 == b1 correctly.
func EdgePairClosestPoints(a0, a1, b0, b1 Point) (Point, Point) {
if CrossingSign(a0, a1, b0, b1) == Cross {
x := Intersection(a0, a1, b0, b1)
return x, x
}
// We save some work by first determining which vertex/edge pair achieves
// the minimum distance, and then computing the closest point on that edge.
var minDist s1.ChordAngle
var ok bool
minDist, ok = updateMinDistance(a0, b0, b1, minDist, true)
closestVertex := 0
if minDist, ok = UpdateMinDistance(a1, b0, b1, minDist); ok {
closestVertex = 1
}
if minDist, ok = UpdateMinDistance(b0, a0, a1, minDist); ok {
closestVertex = 2
}
if minDist, ok = UpdateMinDistance(b1, a0, a1, minDist); ok {
closestVertex = 3
}
switch closestVertex {
case 0:
return a0, Project(a0, b0, b1)
case 1:
return a1, Project(a1, b0, b1)
case 2:
return Project(b0, a0, a1), b0
case 3:
return Project(b1, a0, a1), b1
default:
panic("illegal case reached")
}
}

803
vendor/github.com/golang/geo/s2/edge_query.go generated vendored Normal file
View File

@ -0,0 +1,803 @@
// Copyright 2019 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"
"github.com/golang/geo/s1"
)
// EdgeQueryOptions holds the options for controlling how EdgeQuery operates.
//
// Options can be chained together builder-style:
//
// opts = NewClosestEdgeQueryOptions().
// MaxResults(1).
// DistanceLimit(s1.ChordAngleFromAngle(3 * s1.Degree)).
// MaxError(s1.ChordAngleFromAngle(0.001 * s1.Degree))
// query = NewClosestEdgeQuery(index, opts)
//
// or set individually:
//
// opts = NewClosestEdgeQueryOptions()
// opts.IncludeInteriors(true)
//
// or just inline:
//
// query = NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions().MaxResults(3))
//
// If you pass a nil as the options you get the default values for the options.
type EdgeQueryOptions struct {
common *queryOptions
}
// DistanceLimit specifies that only edges whose distance to the target is
// within, this distance should be returned. Edges whose distance is equal
// are not returned. To include values that are equal, specify the limit with
// the next largest representable distance. i.e. limit.Successor().
func (e *EdgeQueryOptions) DistanceLimit(limit s1.ChordAngle) *EdgeQueryOptions {
e.common = e.common.DistanceLimit(limit)
return e
}
// IncludeInteriors specifies whether polygon interiors should be
// included when measuring distances.
func (e *EdgeQueryOptions) IncludeInteriors(x bool) *EdgeQueryOptions {
e.common = e.common.IncludeInteriors(x)
return e
}
// UseBruteForce sets or disables the use of brute force in a query.
func (e *EdgeQueryOptions) UseBruteForce(x bool) *EdgeQueryOptions {
e.common = e.common.UseBruteForce(x)
return e
}
// MaxError specifies that edges up to dist away than the true
// matching edges may be substituted in the result set, as long as such
// edges satisfy all the remaining search criteria (such as DistanceLimit).
// This option only has an effect if MaxResults is also specified;
// otherwise all edges closer than MaxDistance will always be returned.
func (e *EdgeQueryOptions) MaxError(dist s1.ChordAngle) *EdgeQueryOptions {
e.common = e.common.MaxError(dist)
return e
}
// MaxResults specifies that at most MaxResults edges should be returned.
// This must be at least 1.
func (e *EdgeQueryOptions) MaxResults(n int) *EdgeQueryOptions {
e.common = e.common.MaxResults(n)
return e
}
// NewClosestEdgeQueryOptions returns a set of edge query options suitable
// for performing closest edge queries.
func NewClosestEdgeQueryOptions() *EdgeQueryOptions {
return &EdgeQueryOptions{
common: newQueryOptions(minDistance(0)),
}
}
// NewFurthestEdgeQueryOptions returns a set of edge query options suitable
// for performing furthest edge queries.
func NewFurthestEdgeQueryOptions() *EdgeQueryOptions {
return &EdgeQueryOptions{
common: newQueryOptions(maxDistance(0)),
}
}
// EdgeQueryResult represents an edge that meets the target criteria for the
// query. Note the following special cases:
//
// - ShapeID >= 0 && EdgeID < 0 represents the interior of a shape.
// Such results may be returned when the option IncludeInteriors is true.
//
// - ShapeID < 0 && EdgeID < 0 is returned to indicate that no edge
// satisfies the requested query options.
type EdgeQueryResult struct {
distance distance
shapeID int32
edgeID int32
}
// Distance reports the distance between the edge in this shape that satisfied
// the query's parameters.
func (e EdgeQueryResult) Distance() s1.ChordAngle { return e.distance.chordAngle() }
// ShapeID reports the ID of the Shape this result is for.
func (e EdgeQueryResult) ShapeID() int32 { return e.shapeID }
// EdgeID reports the ID of the edge in the results Shape.
func (e EdgeQueryResult) EdgeID() int32 { return e.edgeID }
// newEdgeQueryResult returns a result instance with default values.
func newEdgeQueryResult(target distanceTarget) EdgeQueryResult {
return EdgeQueryResult{
distance: target.distance().infinity(),
shapeID: -1,
edgeID: -1,
}
}
// IsInterior reports if this result represents the interior of a Shape.
func (e EdgeQueryResult) IsInterior() bool {
return e.shapeID >= 0 && e.edgeID < 0
}
// IsEmpty reports if this has no edge that satisfies the given edge query options.
// This result is only returned in one special case, namely when FindEdge() does
// not find any suitable edges.
func (e EdgeQueryResult) IsEmpty() bool {
return e.shapeID < 0
}
// Less reports if this results is less that the other first by distance,
// then by (shapeID, edgeID). This is used for sorting.
func (e EdgeQueryResult) Less(other EdgeQueryResult) bool {
if e.distance.chordAngle() != other.distance.chordAngle() {
return e.distance.less(other.distance)
}
if e.shapeID != other.shapeID {
return e.shapeID < other.shapeID
}
return e.edgeID < other.edgeID
}
// EdgeQuery is used to find the edge(s) between two geometries that match a
// given set of options. It is flexible enough so that it can be adapted to
// compute maximum distances and even potentially Hausdorff distances.
//
// By using the appropriate options, this type can answer questions such as:
//
// - Find the minimum distance between two geometries A and B.
// - Find all edges of geometry A that are within a distance D of geometry B.
// - Find the k edges of geometry A that are closest to a given point P.
//
// You can also specify whether polygons should include their interiors (i.e.,
// if a point is contained by a polygon, should the distance be zero or should
// it be measured to the polygon boundary?)
//
// The input geometries may consist of any number of points, polylines, and
// polygons (collectively referred to as "shapes"). Shapes do not need to be
// disjoint; they may overlap or intersect arbitrarily. The implementation is
// designed to be fast for both simple and complex geometries.
type EdgeQuery struct {
index *ShapeIndex
opts *queryOptions
target distanceTarget
// True if opts.maxError must be subtracted from ShapeIndex cell distances
// in order to ensure that such distances are measured conservatively. This
// is true only if the target takes advantage of maxError in order to
// return faster results, and 0 < maxError < distanceLimit.
useConservativeCellDistance bool
// The decision about whether to use the brute force algorithm is based on
// counting the total number of edges in the index. However if the index
// contains a large number of shapes, this in itself might take too long.
// So instead we only count edges up to (maxBruteForceIndexSize() + 1)
// for the current target type (stored as indexNumEdgesLimit).
indexNumEdges int
indexNumEdgesLimit int
// The distance beyond which we can safely ignore further candidate edges.
// (Candidates that are exactly at the limit are ignored; this is more
// efficient for UpdateMinDistance and should not affect clients since
// distance measurements have a small amount of error anyway.)
//
// Initially this is the same as the maximum distance specified by the user,
// but it can also be updated by the algorithm (see maybeAddResult).
distanceLimit distance
// The current set of results of the query.
results []EdgeQueryResult
// This field is true when duplicates must be avoided explicitly. This
// is achieved by maintaining a separate set keyed by (shapeID, edgeID)
// only, and checking whether each edge is in that set before computing the
// distance to it.
avoidDuplicates bool
// testedEdges tracks the set of shape and edges that have already been tested.
testedEdges map[ShapeEdgeID]uint32
// For the optimized algorihm we precompute the top-level CellIDs that
// will be added to the priority queue. There can be at most 6 of these
// cells. Essentially this is just a covering of the indexed edges, except
// that we also store pointers to the corresponding ShapeIndexCells to
// reduce the number of index seeks required.
indexCovering []CellID
indexCells []*ShapeIndexCell
// The algorithm maintains a priority queue of unprocessed CellIDs, sorted
// in increasing order of distance from the target.
queue *queryQueue
iter *ShapeIndexIterator
maxDistanceCovering []CellID
initialCells []CellID
}
// NewClosestEdgeQuery returns an EdgeQuery that is used for finding the
// closest edge(s) to a given Point, Edge, Cell, or geometry collection.
//
// You can find either the k closest edges, or all edges within a given
// radius, or both (i.e., the k closest edges up to a given maximum radius).
// E.g. to find all the edges within 5 kilometers, set the DistanceLimit in
// the options.
//
// By default *all* edges are returned, so you should always specify either
// MaxResults or DistanceLimit options or both.
//
// Note that by default, distances are measured to the boundary and interior
// of polygons. For example, if a point is inside a polygon then its distance
// is zero. To change this behavior, set the IncludeInteriors option to false.
//
// If you only need to test whether the distance is above or below a given
// threshold (e.g., 10 km), you can use the IsDistanceLess() method. This is
// much faster than actually calculating the distance with FindEdge,
// since the implementation can stop as soon as it can prove that the minimum
// distance is either above or below the threshold.
func NewClosestEdgeQuery(index *ShapeIndex, opts *EdgeQueryOptions) *EdgeQuery {
if opts == nil {
opts = NewClosestEdgeQueryOptions()
}
e := &EdgeQuery{
testedEdges: make(map[ShapeEdgeID]uint32),
index: index,
opts: opts.common,
queue: newQueryQueue(),
}
return e
}
// NewFurthestEdgeQuery returns an EdgeQuery that is used for finding the
// furthest edge(s) to a given Point, Edge, Cell, or geometry collection.
//
// The furthest edge is defined as the one which maximizes the
// distance from any point on that edge to any point on the target geometry.
//
// Similar to the example in NewClosestEdgeQuery, to find the 5 furthest edges
// from a given Point:
func NewFurthestEdgeQuery(index *ShapeIndex, opts *EdgeQueryOptions) *EdgeQuery {
if opts == nil {
opts = NewFurthestEdgeQueryOptions()
}
e := &EdgeQuery{
testedEdges: make(map[ShapeEdgeID]uint32),
index: index,
opts: opts.common,
queue: newQueryQueue(),
}
return e
}
// Reset resets the state of this EdgeQuery.
func (e *EdgeQuery) Reset() {
e.indexNumEdges = 0
e.indexNumEdgesLimit = 0
e.indexCovering = nil
e.indexCells = nil
}
// FindEdges returns the edges for the given target that satisfy the current options.
//
// Note that if opts.IncludeInteriors is true, the results may include some
// entries with edge_id == -1. This indicates that the target intersects
// the indexed polygon with the given ShapeID.
func (e *EdgeQuery) FindEdges(target distanceTarget) []EdgeQueryResult {
return e.findEdges(target, e.opts)
}
// Distance reports the distance to the target. If the index or target is empty,
// returns the EdgeQuery's maximal sentinel.
//
// Use IsDistanceLess()/IsDistanceGreater() if you only want to compare the
// distance against a threshold value, since it is often much faster.
func (e *EdgeQuery) Distance(target distanceTarget) s1.ChordAngle {
return e.findEdge(target, e.opts).Distance()
}
// IsDistanceLess reports if the distance to target is less than the given limit.
//
// This method is usually much faster than Distance(), since it is much
// less work to determine whether the minimum distance is above or below a
// threshold than it is to calculate the actual minimum distance.
//
// If you wish to check if the distance is less than or equal to the limit, use:
//
// query.IsDistanceLess(target, limit.Successor())
//
func (e *EdgeQuery) IsDistanceLess(target distanceTarget, limit s1.ChordAngle) bool {
opts := e.opts
opts = opts.MaxResults(1).
DistanceLimit(limit).
MaxError(s1.StraightChordAngle)
return !e.findEdge(target, opts).IsEmpty()
}
// IsDistanceGreater reports if the distance to target is greater than limit.
//
// This method is usually much faster than Distance, since it is much
// less work to determine whether the maximum distance is above or below a
// threshold than it is to calculate the actual maximum distance.
// If you wish to check if the distance is less than or equal to the limit, use:
//
// query.IsDistanceGreater(target, limit.Predecessor())
//
func (e *EdgeQuery) IsDistanceGreater(target distanceTarget, limit s1.ChordAngle) bool {
return e.IsDistanceLess(target, limit)
}
// IsConservativeDistanceLessOrEqual reports if the distance to target is less
// or equal to the limit, where the limit has been expanded by the maximum error
// for the distance calculation.
//
// For example, suppose that we want to test whether two geometries might
// intersect each other after they are snapped together using Builder
// (using the IdentitySnapFunction with a given "snap radius"). Since
// Builder uses exact distance predicates (s2predicates), we need to
// measure the distance between the two geometries conservatively. If the
// distance is definitely greater than "snap radius", then the geometries
// are guaranteed to not intersect after snapping.
func (e *EdgeQuery) IsConservativeDistanceLessOrEqual(target distanceTarget, limit s1.ChordAngle) bool {
return e.IsDistanceLess(target, limit.Expanded(minUpdateDistanceMaxError(limit)))
}
// IsConservativeDistanceGreaterOrEqual reports if the distance to the target is greater
// than or equal to the given limit with some small tolerance.
func (e *EdgeQuery) IsConservativeDistanceGreaterOrEqual(target distanceTarget, limit s1.ChordAngle) bool {
return e.IsDistanceGreater(target, limit.Expanded(-minUpdateDistanceMaxError(limit)))
}
// findEdges returns the closest edges to the given target that satisfy the given options.
//
// Note that if opts.includeInteriors is true, the results may include some
// entries with edgeID == -1. This indicates that the target intersects the
// indexed polygon with the given shapeID.
func (e *EdgeQuery) findEdges(target distanceTarget, opts *queryOptions) []EdgeQueryResult {
e.findEdgesInternal(target, opts)
// TODO(roberts): Revisit this if there is a heap or other sorted and
// uniquing datastructure we can use instead of just a slice.
e.results = sortAndUniqueResults(e.results)
if len(e.results) > e.opts.maxResults {
e.results = e.results[:e.opts.maxResults]
}
return e.results
}
func sortAndUniqueResults(results []EdgeQueryResult) []EdgeQueryResult {
if len(results) <= 1 {
return results
}
sort.Slice(results, func(i, j int) bool { return results[i].Less(results[j]) })
j := 0
for i := 1; i < len(results); i++ {
if results[j] == results[i] {
continue
}
j++
results[j] = results[i]
}
return results[:j+1]
}
// findEdge is a convenience method that returns exactly one edge, and if no
// edges satisfy the given search criteria, then a default Result is returned.
//
// This is primarily to ease the usage of a number of the methods in the DistanceTargets
// and in EdgeQuery.
func (e *EdgeQuery) findEdge(target distanceTarget, opts *queryOptions) EdgeQueryResult {
opts.MaxResults(1)
e.findEdges(target, opts)
if len(e.results) > 0 {
return e.results[0]
}
return newEdgeQueryResult(target)
}
// findEdgesInternal does the actual work for find edges that match the given options.
func (e *EdgeQuery) findEdgesInternal(target distanceTarget, opts *queryOptions) {
e.target = target
e.opts = opts
e.testedEdges = make(map[ShapeEdgeID]uint32)
e.distanceLimit = target.distance().fromChordAngle(opts.distanceLimit)
e.results = make([]EdgeQueryResult, 0)
if e.distanceLimit == target.distance().zero() {
return
}
if opts.includeInteriors {
shapeIDs := map[int32]struct{}{}
e.target.visitContainingShapes(e.index, func(containingShape Shape, targetPoint Point) bool {
shapeIDs[e.index.idForShape(containingShape)] = struct{}{}
return len(shapeIDs) < opts.maxResults
})
for shapeID := range shapeIDs {
e.addResult(EdgeQueryResult{target.distance().zero(), shapeID, -1})
}
if e.distanceLimit == target.distance().zero() {
return
}
}
// If maxError > 0 and the target takes advantage of this, then we may
// need to adjust the distance estimates to ShapeIndex cells to ensure
// that they are always a lower bound on the true distance. For example,
// suppose max_distance == 100, maxError == 30, and we compute the distance
// to the target from some cell C0 as d(C0) == 80. Then because the target
// takes advantage of maxError, the true distance could be as low as 50.
// In order not to miss edges contained by such cells, we need to subtract
// maxError from the distance estimates. This behavior is controlled by
// the useConservativeCellDistance flag.
//
// However there is one important case where this adjustment is not
// necessary, namely when distanceLimit < maxError, This is because
// maxError only affects the algorithm once at least maxEdges edges
// have been found that satisfy the given distance limit. At that point,
// maxError is subtracted from distanceLimit in order to ensure that
// any further matches are closer by at least that amount. But when
// distanceLimit < maxError, this reduces the distance limit to 0,
// i.e. all remaining candidate cells and edges can safely be discarded.
// (This is how IsDistanceLess() and friends are implemented.)
targetUsesMaxError := opts.maxError != target.distance().zero().chordAngle() &&
e.target.setMaxError(opts.maxError)
// Note that we can't compare maxError and distanceLimit directly
// because one is a Delta and one is a Distance. Instead we subtract them.
e.useConservativeCellDistance = targetUsesMaxError &&
(e.distanceLimit == target.distance().infinity() ||
target.distance().zero().less(e.distanceLimit.sub(target.distance().fromChordAngle(opts.maxError))))
// Use the brute force algorithm if the index is small enough. To avoid
// spending too much time counting edges when there are many shapes, we stop
// counting once there are too many edges. We may need to recount the edges
// if we later see a target with a larger brute force edge threshold.
minOptimizedEdges := e.target.maxBruteForceIndexSize() + 1
if minOptimizedEdges > e.indexNumEdgesLimit && e.indexNumEdges >= e.indexNumEdgesLimit {
e.indexNumEdges = e.index.NumEdgesUpTo(minOptimizedEdges)
e.indexNumEdgesLimit = minOptimizedEdges
}
if opts.useBruteForce || e.indexNumEdges < minOptimizedEdges {
// The brute force algorithm already considers each edge exactly once.
e.avoidDuplicates = false
e.findEdgesBruteForce()
} else {
// If the target takes advantage of maxError then we need to avoid
// duplicate edges explicitly. (Otherwise it happens automatically.)
e.avoidDuplicates = targetUsesMaxError && opts.maxResults > 1
e.findEdgesOptimized()
}
}
func (e *EdgeQuery) addResult(r EdgeQueryResult) {
e.results = append(e.results, r)
if e.opts.maxResults == 1 {
// Optimization for the common case where only the closest edge is wanted.
e.distanceLimit = r.distance.sub(e.target.distance().fromChordAngle(e.opts.maxError))
}
// TODO(roberts): Add the other if/else cases when a different data structure
// is used for the results.
}
func (e *EdgeQuery) maybeAddResult(shape Shape, edgeID int32) {
if _, ok := e.testedEdges[ShapeEdgeID{e.index.idForShape(shape), edgeID}]; e.avoidDuplicates && !ok {
return
}
edge := shape.Edge(int(edgeID))
dist := e.distanceLimit
if dist, ok := e.target.updateDistanceToEdge(edge, dist); ok {
e.addResult(EdgeQueryResult{dist, e.index.idForShape(shape), edgeID})
}
}
func (e *EdgeQuery) findEdgesBruteForce() {
// Range over all shapes in the index. Does order matter here? if so
// switch to for i = 0 .. n?
for _, shape := range e.index.shapes {
// TODO(roberts): can this happen if we are only ranging over current entries?
if shape == nil {
continue
}
for edgeID := int32(0); edgeID < int32(shape.NumEdges()); edgeID++ {
e.maybeAddResult(shape, edgeID)
}
}
}
func (e *EdgeQuery) findEdgesOptimized() {
e.initQueue()
// Repeatedly find the closest Cell to "target" and either split it into
// its four children or process all of its edges.
for e.queue.size() > 0 {
// We need to copy the top entry before removing it, and we need to
// remove it before adding any new entries to the queue.
entry := e.queue.pop()
if !entry.distance.less(e.distanceLimit) {
e.queue.reset() // Clear any remaining entries.
break
}
// If this is already known to be an index cell, just process it.
if entry.indexCell != nil {
e.processEdges(entry)
continue
}
// Otherwise split the cell into its four children. Before adding a
// child back to the queue, we first check whether it is empty. We do
// this in two seek operations rather than four by seeking to the key
// between children 0 and 1 and to the key between children 2 and 3.
id := entry.id
ch := id.Children()
e.iter.seek(ch[1].RangeMin())
if !e.iter.Done() && e.iter.CellID() <= ch[1].RangeMax() {
e.processOrEnqueueCell(ch[1])
}
if e.iter.Prev() && e.iter.CellID() >= id.RangeMin() {
e.processOrEnqueueCell(ch[0])
}
e.iter.seek(ch[3].RangeMin())
if !e.iter.Done() && e.iter.CellID() <= id.RangeMax() {
e.processOrEnqueueCell(ch[3])
}
if e.iter.Prev() && e.iter.CellID() >= ch[2].RangeMin() {
e.processOrEnqueueCell(ch[2])
}
}
}
func (e *EdgeQuery) processOrEnqueueCell(id CellID) {
if e.iter.CellID() == id {
e.processOrEnqueue(id, e.iter.IndexCell())
} else {
e.processOrEnqueue(id, nil)
}
}
func (e *EdgeQuery) initQueue() {
if len(e.indexCovering) == 0 {
// We delay iterator initialization until now to make queries on very
// small indexes a bit faster (i.e., where brute force is used).
e.iter = NewShapeIndexIterator(e.index)
}
// Optimization: if the user is searching for just the closest edge, and the
// center of the target's bounding cap happens to intersect an index cell,
// then we try to limit the search region to a small disc by first
// processing the edges in that cell. This sets distance_limit_ based on
// the closest edge in that cell, which we can then use to limit the search
// area. This means that the cell containing "target" will be processed
// twice, but in general this is still faster.
//
// TODO(roberts): Even if the cap center is not contained, we could still
// process one or both of the adjacent index cells in CellID order,
// provided that those cells are closer than distanceLimit.
cb := e.target.capBound()
if cb.IsEmpty() {
return // Empty target.
}
if e.opts.maxResults == 1 && e.iter.LocatePoint(cb.Center()) {
e.processEdges(&queryQueueEntry{
distance: e.target.distance().zero(),
id: e.iter.CellID(),
indexCell: e.iter.IndexCell(),
})
// Skip the rest of the algorithm if we found an intersecting edge.
if e.distanceLimit == e.target.distance().zero() {
return
}
}
if len(e.indexCovering) == 0 {
e.initCovering()
}
if e.distanceLimit == e.target.distance().infinity() {
// Start with the precomputed index covering.
for i := range e.indexCovering {
e.processOrEnqueue(e.indexCovering[i], e.indexCells[i])
}
} else {
// Compute a covering of the search disc and intersect it with the
// precomputed index covering.
coverer := &RegionCoverer{MaxCells: 4, LevelMod: 1, MaxLevel: maxLevel}
radius := cb.Radius() + e.distanceLimit.chordAngleBound().Angle()
searchCB := CapFromCenterAngle(cb.Center(), radius)
maxDistCover := coverer.FastCovering(searchCB)
e.initialCells = CellUnionFromIntersection(e.indexCovering, maxDistCover)
// Now we need to clean up the initial cells to ensure that they all
// contain at least one cell of the ShapeIndex. (Some may not intersect
// the index at all, while other may be descendants of an index cell.)
i, j := 0, 0
for i < len(e.initialCells) {
idI := e.initialCells[i]
// Find the top-level cell that contains this initial cell.
for e.indexCovering[j].RangeMax() < idI {
j++
}
idJ := e.indexCovering[j]
if idI == idJ {
// This initial cell is one of the top-level cells. Use the
// precomputed ShapeIndexCell pointer to avoid an index seek.
e.processOrEnqueue(idJ, e.indexCells[j])
i++
j++
} else {
// This initial cell is a proper descendant of a top-level cell.
// Check how it is related to the cells of the ShapeIndex.
r := e.iter.LocateCellID(idI)
if r == Indexed {
// This cell is a descendant of an index cell.
// Enqueue it and skip any other initial cells
// that are also descendants of this cell.
e.processOrEnqueue(e.iter.CellID(), e.iter.IndexCell())
lastID := e.iter.CellID().RangeMax()
for i < len(e.initialCells) && e.initialCells[i] <= lastID {
i++
}
} else {
// Enqueue the cell only if it contains at least one index cell.
if r == Subdivided {
e.processOrEnqueue(idI, nil)
}
i++
}
}
}
}
}
func (e *EdgeQuery) initCovering() {
// Find the range of Cells spanned by the index and choose a level such
// that the entire index can be covered with just a few cells. These are
// the "top-level" cells. There are two cases:
//
// - If the index spans more than one face, then there is one top-level cell
// per spanned face, just big enough to cover the index cells on that face.
//
// - If the index spans only one face, then we find the smallest cell "C"
// that covers the index cells on that face (just like the case above).
// Then for each of the 4 children of "C", if the child contains any index
// cells then we create a top-level cell that is big enough to just fit
// those index cells (i.e., shrinking the child as much as possible to fit
// its contents). This essentially replicates what would happen if we
// started with "C" as the top-level cell, since "C" would immediately be
// split, except that we take the time to prune the children further since
// this will save work on every subsequent query.
e.indexCovering = make([]CellID, 0, 6)
// TODO(roberts): Use a single iterator below and save position
// information using pair {CellID, ShapeIndexCell}.
next := NewShapeIndexIterator(e.index, IteratorBegin)
last := NewShapeIndexIterator(e.index, IteratorEnd)
last.Prev()
if next.CellID() != last.CellID() {
// The index has at least two cells. Choose a level such that the entire
// index can be spanned with at most 6 cells (if the index spans multiple
// faces) or 4 cells (it the index spans a single face).
level, ok := next.CellID().CommonAncestorLevel(last.CellID())
if !ok {
level = 0
} else {
level++
}
// Visit each potential top-level cell except the last (handled below).
lastID := last.CellID().Parent(level)
for id := next.CellID().Parent(level); id != lastID; id = id.Next() {
// Skip any top-level cells that don't contain any index cells.
if id.RangeMax() < next.CellID() {
continue
}
// Find the range of index cells contained by this top-level cell and
// then shrink the cell if necessary so that it just covers them.
cellFirst := next.clone()
next.seek(id.RangeMax().Next())
cellLast := next.clone()
cellLast.Prev()
e.addInitialRange(cellFirst, cellLast)
break
}
}
e.addInitialRange(next, last)
}
// addInitialRange adds an entry to the indexCovering and indexCells that covers the given
// inclusive range of cells.
//
// This requires that first and last cells have a common ancestor.
func (e *EdgeQuery) addInitialRange(first, last *ShapeIndexIterator) {
if first.CellID() == last.CellID() {
// The range consists of a single index cell.
e.indexCovering = append(e.indexCovering, first.CellID())
e.indexCells = append(e.indexCells, first.IndexCell())
} else {
// Add the lowest common ancestor of the given range.
level, _ := first.CellID().CommonAncestorLevel(last.CellID())
e.indexCovering = append(e.indexCovering, first.CellID().Parent(level))
e.indexCells = append(e.indexCells, nil)
}
}
// processEdges processes all the edges of the given index cell.
func (e *EdgeQuery) processEdges(entry *queryQueueEntry) {
for _, clipped := range entry.indexCell.shapes {
shape := e.index.Shape(clipped.shapeID)
for j := 0; j < clipped.numEdges(); j++ {
e.maybeAddResult(shape, int32(clipped.edges[j]))
}
}
}
// processOrEnqueue the given cell id and indexCell.
func (e *EdgeQuery) processOrEnqueue(id CellID, indexCell *ShapeIndexCell) {
if indexCell != nil {
// If this index cell has only a few edges, then it is faster to check
// them directly rather than computing the minimum distance to the Cell
// and inserting it into the queue.
const minEdgesToEnqueue = 10
numEdges := indexCell.numEdges()
if numEdges == 0 {
return
}
if numEdges < minEdgesToEnqueue {
// Set "distance" to zero to avoid the expense of computing it.
e.processEdges(&queryQueueEntry{
distance: e.target.distance().zero(),
id: id,
indexCell: indexCell,
})
return
}
}
// Otherwise compute the minimum distance to any point in the cell and add
// it to the priority queue.
cell := CellFromCellID(id)
dist := e.distanceLimit
var ok bool
if dist, ok = e.target.updateDistanceToCell(cell, dist); !ok {
return
}
if e.useConservativeCellDistance {
// Ensure that "distance" is a lower bound on the true distance to the cell.
dist = dist.sub(e.target.distance().fromChordAngle(e.opts.maxError))
}
e.queue.push(&queryQueueEntry{
distance: dist,
id: id,
indexCell: indexCell,
})
}
// TODO(roberts): Remaining pieces
// GetEdge
// Project

291
vendor/github.com/golang/geo/s2/edge_tessellator.go generated vendored Normal file
View File

@ -0,0 +1,291 @@
// Copyright 2018 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 (
"github.com/golang/geo/r2"
"github.com/golang/geo/s1"
)
// Tessellation is implemented by subdividing the edge until the estimated
// maximum error is below the given tolerance. Estimating error is a hard
// problem, especially when the only methods available are point evaluation of
// the projection and its inverse. (These are the only methods that
// Projection provides, which makes it easier and less error-prone to
// implement new projections.)
//
// One technique that significantly increases robustness is to treat the
// geodesic and projected edges as parametric curves rather than geometric ones.
// Given a spherical edge AB and a projection p:S2->R2, let f(t) be the
// normalized arc length parametrization of AB and let g(t) be the normalized
// arc length parameterization of the projected edge p(A)p(B). (In other words,
// f(0)=A, f(1)=B, g(0)=p(A), g(1)=p(B).) We now define the geometric error as
// the maximum distance from the point p^-1(g(t)) to the geodesic edge AB for
// any t in [0,1], where p^-1 denotes the inverse projection. In other words,
// the geometric error is the maximum distance from any point on the projected
// edge (mapped back onto the sphere) to the geodesic edge AB. On the other
// hand we define the parametric error as the maximum distance between the
// points f(t) and p^-1(g(t)) for any t in [0,1], i.e. the maximum distance
// (measured on the sphere) between the geodesic and projected points at the
// same interpolation fraction t.
//
// The easiest way to estimate the parametric error is to simply evaluate both
// edges at their midpoints and measure the distance between them (the "midpoint
// method"). This is very fast and works quite well for most edges, however it
// has one major drawback: it doesn't handle points of inflection (i.e., points
// where the curvature changes sign). For example, edges in the Mercator and
// Plate Carree projections always curve towards the equator relative to the
// corresponding geodesic edge, so in these projections there is a point of
// inflection whenever the projected edge crosses the equator. The worst case
// occurs when the edge endpoints have different longitudes but the same
// absolute latitude, since in that case the error is non-zero but the edges
// have exactly the same midpoint (on the equator).
//
// One solution to this problem is to split the input edges at all inflection
// points (i.e., along the equator in the case of the Mercator and Plate Carree
// projections). However for general projections these inflection points can
// occur anywhere on the sphere (e.g., consider the Transverse Mercator
// projection). This could be addressed by adding methods to the S2Projection
// interface to split edges at inflection points but this would make it harder
// and more error-prone to implement new projections.
//
// Another problem with this approach is that the midpoint method sometimes
// underestimates the true error even when edges do not cross the equator.
// For the Plate Carree and Mercator projections, the midpoint method can
// underestimate the error by up to 3%.
//
// Both of these problems can be solved as follows. We assume that the error
// can be modeled as a convex combination of two worst-case functions, one
// where the error is maximized at the edge midpoint and another where the
// error is *minimized* (i.e., zero) at the edge midpoint. For example, we
// could choose these functions as:
//
// E1(x) = 1 - x^2
// E2(x) = x * (1 - x^2)
//
// where for convenience we use an interpolation parameter "x" in the range
// [-1, 1] rather than the original "t" in the range [0, 1]. Note that both
// error functions must have roots at x = {-1, 1} since the error must be zero
// at the edge endpoints. E1 is simply a parabola whose maximum value is 1
// attained at x = 0, while E2 is a cubic with an additional root at x = 0,
// and whose maximum value is 2 * sqrt(3) / 9 attained at x = 1 / sqrt(3).
//
// Next, it is convenient to scale these functions so that the both have a
// maximum value of 1. E1 already satisfies this requirement, and we simply
// redefine E2 as
//
// E2(x) = x * (1 - x^2) / (2 * sqrt(3) / 9)
//
// Now define x0 to be the point where these two functions intersect, i.e. the
// point in the range (-1, 1) where E1(x0) = E2(x0). This value has the very
// convenient property that if we evaluate the actual error E(x0), then the
// maximum error on the entire interval [-1, 1] is bounded by
//
// E(x) <= E(x0) / E1(x0)
//
// since whether the error is modeled using E1 or E2, the resulting function
// has the same maximum value (namely E(x0) / E1(x0)). If it is modeled as
// some other convex combination of E1 and E2, the maximum value can only
// decrease.
//
// Finally, since E2 is not symmetric about the y-axis, we must also allow for
// the possibility that the error is a convex combination of E1 and -E2. This
// can be handled by evaluating the error at E(-x0) as well, and then
// computing the final error bound as
//
// E(x) <= max(E(x0), E(-x0)) / E1(x0) .
//
// Effectively, this method is simply evaluating the error at two points about
// 1/3 and 2/3 of the way along the edges, and then scaling the maximum of
// these two errors by a constant factor. Intuitively, the reason this works
// is that if the two edges cross somewhere in the interior, then at least one
// of these points will be far from the crossing.
//
// The actual algorithm implemented below has some additional refinements.
// First, edges longer than 90 degrees are always subdivided; this avoids
// various unusual situations that can happen with very long edges, and there
// is really no reason to avoid adding vertices to edges that are so long.
//
// Second, the error function E1 above needs to be modified to take into
// account spherical distortions. (It turns out that spherical distortions are
// beneficial in the case of E2, i.e. they only make its error estimates
// slightly more conservative.) To do this, we model E1 as the maximum error
// in a Plate Carree edge of length 90 degrees or less. This turns out to be
// an edge from 45:-90 to 45:90 (in lat:lng format). The corresponding error
// as a function of "x" in the range [-1, 1] can be computed as the distance
// between the Plate Caree edge point (45, 90 * x) and the geodesic
// edge point (90 - 45 * abs(x), 90 * sgn(x)). Using the Haversine formula,
// the corresponding function E1 (normalized to have a maximum value of 1) is:
//
// E1(x) =
// asin(sqrt(sin(Pi / 8 * (1 - x)) ^ 2 +
// sin(Pi / 4 * (1 - x)) ^ 2 * cos(Pi / 4) * sin(Pi / 4 * x))) /
// asin(sqrt((1 - 1 / sqrt(2)) / 2))
//
// Note that this function does not need to be evaluated at runtime, it
// simply affects the calculation of the value x0 where E1(x0) = E2(x0)
// and the corresponding scaling factor C = 1 / E1(x0).
//
// ------------------------------------------------------------------
//
// In the case of the Mercator and Plate Carree projections this strategy
// produces a conservative upper bound (verified using 10 million random
// edges). Furthermore the bound is nearly tight; the scaling constant is
// C = 1.19289, whereas the maximum observed value was 1.19254.
//
// Compared to the simpler midpoint evaluation method, this strategy requires
// more function evaluations (currently twice as many, but with a smarter
// tessellation algorithm it will only be 50% more). It also results in a
// small amount of additional tessellation (about 1.5%) compared to the
// midpoint method, but this is due almost entirely to the fact that the
// midpoint method does not yield conservative error estimates.
//
// For random edges with a tolerance of 1 meter, the expected amount of
// overtessellation is as follows:
//
// Midpoint Method Cubic Method
// Plate Carree 1.8% 3.0%
// Mercator 15.8% 17.4%
const (
// tessellationInterpolationFraction is the fraction at which the two edges
// are evaluated in order to measure the error between them. (Edges are
// evaluated at two points measured this fraction from either end.)
tessellationInterpolationFraction = 0.31215691082248312
tessellationScaleFactor = 0.83829992569888509
// minTessellationTolerance is the minimum supported tolerance (which
// corresponds to a distance less than 1 micrometer on the Earth's
// surface, but is still much larger than the expected projection and
// interpolation errors).
minTessellationTolerance s1.Angle = 1e-13
)
// EdgeTessellator converts an edge in a given projection (e.g., Mercator) into
// a chain of spherical geodesic edges such that the maximum distance between
// the original edge and the geodesic edge chain is at most the requested
// tolerance. Similarly, it can convert a spherical geodesic edge into a chain
// of edges in a given 2D projection such that the maximum distance between the
// geodesic edge and the chain of projected edges is at most the requested tolerance.
//
// Method | Input | Output
// ------------|------------------------|-----------------------
// Projected | S2 geodesics | Planar projected edges
// Unprojected | Planar projected edges | S2 geodesics
type EdgeTessellator struct {
projection Projection
// The given tolerance scaled by a constant fraction so that it can be
// compared against the result returned by estimateMaxError.
scaledTolerance s1.ChordAngle
}
// NewEdgeTessellator creates a new edge tessellator for the given projection and tolerance.
func NewEdgeTessellator(p Projection, tolerance s1.Angle) *EdgeTessellator {
return &EdgeTessellator{
projection: p,
scaledTolerance: s1.ChordAngleFromAngle(maxAngle(tolerance, minTessellationTolerance)),
}
}
// AppendProjected converts the spherical geodesic edge AB to a chain of planar edges
// in the given projection and returns the corresponding vertices.
//
// If the given projection has one or more coordinate axes that wrap, then
// every vertex's coordinates will be as close as possible to the previous
// vertex's coordinates. Note that this may yield vertices whose
// coordinates are outside the usual range. For example, tessellating the
// edge (0:170, 0:-170) (in lat:lng notation) yields (0:170, 0:190).
func (e *EdgeTessellator) AppendProjected(a, b Point, vertices []r2.Point) []r2.Point {
pa := e.projection.Project(a)
if len(vertices) == 0 {
vertices = []r2.Point{pa}
} else {
pa = e.projection.WrapDestination(vertices[len(vertices)-1], pa)
}
pb := e.projection.Project(b)
return e.appendProjected(pa, a, pb, b, vertices)
}
// appendProjected splits a geodesic edge AB as necessary and returns the
// projected vertices appended to the given vertices.
//
// The maximum recursion depth is (math.Pi / minTessellationTolerance) < 45
func (e *EdgeTessellator) appendProjected(pa r2.Point, a Point, pbIn r2.Point, b Point, vertices []r2.Point) []r2.Point {
pb := e.projection.WrapDestination(pa, pbIn)
if e.estimateMaxError(pa, a, pb, b) <= e.scaledTolerance {
return append(vertices, pb)
}
mid := Point{a.Add(b.Vector).Normalize()}
pmid := e.projection.WrapDestination(pa, e.projection.Project(mid))
vertices = e.appendProjected(pa, a, pmid, mid, vertices)
return e.appendProjected(pmid, mid, pb, b, vertices)
}
// AppendUnprojected converts the planar edge AB in the given projection to a chain of
// spherical geodesic edges and returns the vertices.
//
// Note that to construct a Loop, you must eliminate the duplicate first and last
// vertex. Note also that if the given projection involves coordinate wrapping
// (e.g. across the 180 degree meridian) then the first and last vertices may not
// be exactly the same.
func (e *EdgeTessellator) AppendUnprojected(pa, pb r2.Point, vertices []Point) []Point {
a := e.projection.Unproject(pa)
b := e.projection.Unproject(pb)
if len(vertices) == 0 {
vertices = []Point{a}
}
// Note that coordinate wrapping can create a small amount of error. For
// example in the edge chain "0:-175, 0:179, 0:-177", the first edge is
// transformed into "0:-175, 0:-181" while the second is transformed into
// "0:179, 0:183". The two coordinate pairs for the middle vertex
// ("0:-181" and "0:179") may not yield exactly the same S2Point.
return e.appendUnprojected(pa, a, pb, b, vertices)
}
// appendUnprojected interpolates a projected edge and appends the corresponding
// points on the sphere.
func (e *EdgeTessellator) appendUnprojected(pa r2.Point, a Point, pbIn r2.Point, b Point, vertices []Point) []Point {
pb := e.projection.WrapDestination(pa, pbIn)
if e.estimateMaxError(pa, a, pb, b) <= e.scaledTolerance {
return append(vertices, b)
}
pmid := e.projection.Interpolate(0.5, pa, pb)
mid := e.projection.Unproject(pmid)
vertices = e.appendUnprojected(pa, a, pmid, mid, vertices)
return e.appendUnprojected(pmid, mid, pb, b, vertices)
}
func (e *EdgeTessellator) estimateMaxError(pa r2.Point, a Point, pb r2.Point, b Point) s1.ChordAngle {
// See the algorithm description at the top of this file.
// We always tessellate edges longer than 90 degrees on the sphere, since the
// approximation below is not robust enough to handle such edges.
if a.Dot(b.Vector) < -1e-14 {
return s1.InfChordAngle()
}
t1 := tessellationInterpolationFraction
t2 := 1 - tessellationInterpolationFraction
mid1 := Interpolate(t1, a, b)
mid2 := Interpolate(t2, a, b)
pmid1 := e.projection.Unproject(e.projection.Interpolate(t1, pa, pb))
pmid2 := e.projection.Unproject(e.projection.Interpolate(t2, pa, pb))
return maxChordAngle(ChordAngleBetweenPoints(mid1, pmid1), ChordAngleBetweenPoints(mid2, pmid2))
}

224
vendor/github.com/golang/geo/s2/encode.go generated vendored Normal file
View File

@ -0,0 +1,224 @@
// Copyright 2017 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 (
"encoding/binary"
"io"
"math"
)
const (
// encodingVersion is the current version of the encoding
// format that is compatible with C++ and other S2 libraries.
encodingVersion = int8(1)
// encodingCompressedVersion is the current version of the
// compressed format.
encodingCompressedVersion = int8(4)
)
// encoder handles the specifics of encoding for S2 types.
type encoder struct {
w io.Writer // the real writer passed to Encode
err error
}
func (e *encoder) writeUvarint(x uint64) {
if e.err != nil {
return
}
var buf [binary.MaxVarintLen64]byte
n := binary.PutUvarint(buf[:], x)
_, e.err = e.w.Write(buf[:n])
}
func (e *encoder) writeBool(x bool) {
if e.err != nil {
return
}
var val int8
if x {
val = 1
}
e.err = binary.Write(e.w, binary.LittleEndian, val)
}
func (e *encoder) writeInt8(x int8) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeInt16(x int16) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeInt32(x int32) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeInt64(x int64) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeUint8(x uint8) {
if e.err != nil {
return
}
_, e.err = e.w.Write([]byte{x})
}
func (e *encoder) writeUint32(x uint32) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeUint64(x uint64) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeFloat32(x float32) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
func (e *encoder) writeFloat64(x float64) {
if e.err != nil {
return
}
e.err = binary.Write(e.w, binary.LittleEndian, x)
}
type byteReader interface {
io.Reader
io.ByteReader
}
// byteReaderAdapter embellishes an io.Reader with a ReadByte method,
// so that it implements the io.ByteReader interface.
type byteReaderAdapter struct {
io.Reader
}
func (b byteReaderAdapter) ReadByte() (byte, error) {
buf := []byte{0}
_, err := io.ReadFull(b, buf)
return buf[0], err
}
func asByteReader(r io.Reader) byteReader {
if br, ok := r.(byteReader); ok {
return br
}
return byteReaderAdapter{r}
}
type decoder struct {
r byteReader // the real reader passed to Decode
err error
buf []byte
}
// Get a buffer of size 8, to avoid allocating over and over.
func (d *decoder) buffer() []byte {
if d.buf == nil {
d.buf = make([]byte, 8)
}
return d.buf
}
func (d *decoder) readBool() (x bool) {
if d.err != nil {
return
}
var val int8
d.err = binary.Read(d.r, binary.LittleEndian, &val)
return val == 1
}
func (d *decoder) readInt8() (x int8) {
if d.err != nil {
return
}
d.err = binary.Read(d.r, binary.LittleEndian, &x)
return
}
func (d *decoder) readInt64() (x int64) {
if d.err != nil {
return
}
d.err = binary.Read(d.r, binary.LittleEndian, &x)
return
}
func (d *decoder) readUint8() (x uint8) {
if d.err != nil {
return
}
x, d.err = d.r.ReadByte()
return
}
func (d *decoder) readUint32() (x uint32) {
if d.err != nil {
return
}
d.err = binary.Read(d.r, binary.LittleEndian, &x)
return
}
func (d *decoder) readUint64() (x uint64) {
if d.err != nil {
return
}
d.err = binary.Read(d.r, binary.LittleEndian, &x)
return
}
func (d *decoder) readFloat64() float64 {
if d.err != nil {
return 0
}
buf := d.buffer()
_, d.err = io.ReadFull(d.r, buf)
return math.Float64frombits(binary.LittleEndian.Uint64(buf))
}
func (d *decoder) readUvarint() (x uint64) {
if d.err != nil {
return
}
x, d.err = binary.ReadUvarint(d.r)
return
}

143
vendor/github.com/golang/geo/s2/interleave.go generated vendored Normal file
View File

@ -0,0 +1,143 @@
// Copyright 2017 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
/*
The lookup table below can convert a sequence of interleaved 8 bits into
non-interleaved 4 bits. The table can convert both odd and even bits at the
same time, and lut[x & 0x55] converts the even bits (bits 0, 2, 4 and 6),
while lut[x & 0xaa] converts the odd bits (bits 1, 3, 5 and 7).
The lookup table below was generated using the following python code:
def deinterleave(bits):
if bits == 0: return 0
if bits < 4: return 1
return deinterleave(bits / 4) * 2 + deinterleave(bits & 3)
for i in range(256): print "0x%x," % deinterleave(i),
*/
var deinterleaveLookup = [256]uint32{
0x0, 0x1, 0x1, 0x1, 0x2, 0x3, 0x3, 0x3,
0x2, 0x3, 0x3, 0x3, 0x2, 0x3, 0x3, 0x3,
0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
0x4, 0x5, 0x5, 0x5, 0x6, 0x7, 0x7, 0x7,
0x6, 0x7, 0x7, 0x7, 0x6, 0x7, 0x7, 0x7,
0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0x8, 0x9, 0x9, 0x9, 0xa, 0xb, 0xb, 0xb,
0xa, 0xb, 0xb, 0xb, 0xa, 0xb, 0xb, 0xb,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
0xc, 0xd, 0xd, 0xd, 0xe, 0xf, 0xf, 0xf,
0xe, 0xf, 0xf, 0xf, 0xe, 0xf, 0xf, 0xf,
}
// deinterleaveUint32 decodes the interleaved values.
func deinterleaveUint32(code uint64) (uint32, uint32) {
x := (deinterleaveLookup[code&0x55]) |
(deinterleaveLookup[(code>>8)&0x55] << 4) |
(deinterleaveLookup[(code>>16)&0x55] << 8) |
(deinterleaveLookup[(code>>24)&0x55] << 12) |
(deinterleaveLookup[(code>>32)&0x55] << 16) |
(deinterleaveLookup[(code>>40)&0x55] << 20) |
(deinterleaveLookup[(code>>48)&0x55] << 24) |
(deinterleaveLookup[(code>>56)&0x55] << 28)
y := (deinterleaveLookup[code&0xaa]) |
(deinterleaveLookup[(code>>8)&0xaa] << 4) |
(deinterleaveLookup[(code>>16)&0xaa] << 8) |
(deinterleaveLookup[(code>>24)&0xaa] << 12) |
(deinterleaveLookup[(code>>32)&0xaa] << 16) |
(deinterleaveLookup[(code>>40)&0xaa] << 20) |
(deinterleaveLookup[(code>>48)&0xaa] << 24) |
(deinterleaveLookup[(code>>56)&0xaa] << 28)
return x, y
}
var interleaveLookup = [256]uint64{
0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555,
}
// interleaveUint32 interleaves the given arguments into the return value.
//
// The 0-bit in val0 will be the 0-bit in the return value.
// The 0-bit in val1 will be the 1-bit in the return value.
// The 1-bit of val0 will be the 2-bit in the return value, and so on.
func interleaveUint32(x, y uint32) uint64 {
return (interleaveLookup[x&0xff]) |
(interleaveLookup[(x>>8)&0xff] << 16) |
(interleaveLookup[(x>>16)&0xff] << 32) |
(interleaveLookup[x>>24] << 48) |
(interleaveLookup[y&0xff] << 1) |
(interleaveLookup[(y>>8)&0xff] << 17) |
(interleaveLookup[(y>>16)&0xff] << 33) |
(interleaveLookup[y>>24] << 49)
}

101
vendor/github.com/golang/geo/s2/latlng.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
// 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"
"math"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
const (
northPoleLat = s1.Angle(math.Pi/2) * s1.Radian
southPoleLat = -northPoleLat
)
// LatLng represents a point on the unit sphere as a pair of angles.
type LatLng struct {
Lat, Lng s1.Angle
}
// LatLngFromDegrees returns a LatLng for the coordinates given in degrees.
func LatLngFromDegrees(lat, lng float64) LatLng {
return LatLng{s1.Angle(lat) * s1.Degree, s1.Angle(lng) * s1.Degree}
}
// IsValid returns true iff the LatLng is normalized, with Lat ∈ [-π/2,π/2] and Lng ∈ [-π,π].
func (ll LatLng) IsValid() bool {
return math.Abs(ll.Lat.Radians()) <= math.Pi/2 && math.Abs(ll.Lng.Radians()) <= math.Pi
}
// Normalized returns the normalized version of the LatLng,
// with Lat clamped to [-π/2,π/2] and Lng wrapped in [-π,π].
func (ll LatLng) Normalized() LatLng {
lat := ll.Lat
if lat > northPoleLat {
lat = northPoleLat
} else if lat < southPoleLat {
lat = southPoleLat
}
lng := s1.Angle(math.Remainder(ll.Lng.Radians(), 2*math.Pi)) * s1.Radian
return LatLng{lat, lng}
}
func (ll LatLng) String() string { return fmt.Sprintf("[%v, %v]", ll.Lat, ll.Lng) }
// Distance returns the angle between two LatLngs.
func (ll LatLng) Distance(ll2 LatLng) s1.Angle {
// Haversine formula, as used in C++ S2LatLng::GetDistance.
lat1, lat2 := ll.Lat.Radians(), ll2.Lat.Radians()
lng1, lng2 := ll.Lng.Radians(), ll2.Lng.Radians()
dlat := math.Sin(0.5 * (lat2 - lat1))
dlng := math.Sin(0.5 * (lng2 - lng1))
x := dlat*dlat + dlng*dlng*math.Cos(lat1)*math.Cos(lat2)
return s1.Angle(2*math.Atan2(math.Sqrt(x), math.Sqrt(math.Max(0, 1-x)))) * s1.Radian
}
// NOTE(mikeperrow): The C++ implementation publicly exposes latitude/longitude
// functions. Let's see if that's really necessary before exposing the same functionality.
func latitude(p Point) s1.Angle {
return s1.Angle(math.Atan2(p.Z, math.Sqrt(p.X*p.X+p.Y*p.Y))) * s1.Radian
}
func longitude(p Point) s1.Angle {
return s1.Angle(math.Atan2(p.Y, p.X)) * s1.Radian
}
// 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 PointFromLatLng(ll LatLng) Point {
phi := ll.Lat.Radians()
theta := ll.Lng.Radians()
cosphi := math.Cos(phi)
return Point{r3.Vector{math.Cos(theta) * cosphi, math.Sin(theta) * cosphi, math.Sin(phi)}}
}
// LatLngFromPoint returns an LatLng for a given Point.
func LatLngFromPoint(p Point) LatLng {
return LatLng{latitude(p), longitude(p)}
}
// ApproxEqual reports whether the latitude and longitude of the two LatLngs
// are the same up to a small tolerance.
func (ll LatLng) ApproxEqual(other LatLng) bool {
return ll.Lat.ApproxEqual(other.Lat) && ll.Lng.ApproxEqual(other.Lng)
}

175
vendor/github.com/golang/geo/s2/lexicon.go generated vendored Normal file
View File

@ -0,0 +1,175 @@
// 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 (
"encoding/binary"
"hash/adler32"
"math"
"sort"
)
// TODO(roberts): If any of these are worth making public, change the
// method signatures and type names.
// emptySetID represents the last ID that will ever be generated.
// (Non-negative IDs are reserved for singleton sets.)
var emptySetID = int32(math.MinInt32)
// idSetLexicon compactly represents a set of non-negative
// integers such as array indices ("ID sets"). It is especially suitable when
// either (1) there are many duplicate sets, or (2) there are many singleton
// or empty sets. See also sequenceLexicon.
//
// Each distinct ID set is mapped to a 32-bit integer. Empty and singleton
// sets take up no additional space; the set itself is represented
// by the unique ID assigned to the set. Duplicate sets are automatically
// eliminated. Note also that ID sets are referred to using 32-bit integers
// rather than pointers.
type idSetLexicon struct {
idSets *sequenceLexicon
}
func newIDSetLexicon() *idSetLexicon {
return &idSetLexicon{
idSets: newSequenceLexicon(),
}
}
// add adds the given set of integers to the lexicon if it is not already
// present, and return the unique ID for this set. The values are automatically
// sorted and duplicates are removed.
//
// The primary difference between this and sequenceLexicon are:
// 1. Empty and singleton sets are represented implicitly; they use no space.
// 2. Sets are represented rather than sequences; the ordering of values is
// not important and duplicates are removed.
// 3. The values must be 32-bit non-negative integers only.
func (l *idSetLexicon) add(ids ...int32) int32 {
// Empty sets have a special ID chosen not to conflict with other IDs.
if len(ids) == 0 {
return emptySetID
}
// Singleton sets are represented by their element.
if len(ids) == 1 {
return ids[0]
}
// Canonicalize the set by sorting and removing duplicates.
//
// Creates a new slice in order to not alter the supplied values.
set := uniqueInt32s(ids)
// Non-singleton sets are represented by the bitwise complement of the ID
// returned by the sequenceLexicon
return ^l.idSets.add(set)
}
// idSet returns the set of integers corresponding to an ID returned by add.
func (l *idSetLexicon) idSet(setID int32) []int32 {
if setID >= 0 {
return []int32{setID}
}
if setID == emptySetID {
return []int32{}
}
return l.idSets.sequence(^setID)
}
func (l *idSetLexicon) clear() {
l.idSets.clear()
}
// sequenceLexicon compactly represents a sequence of values (e.g., tuples).
// It automatically eliminates duplicates slices, and maps the remaining
// sequences to sequentially increasing integer IDs. See also idSetLexicon.
//
// Each distinct sequence is mapped to a 32-bit integer.
type sequenceLexicon struct {
values []int32
begins []uint32
// idSet is a mapping of a sequence hash to sequence index in the lexicon.
idSet map[uint32]int32
}
func newSequenceLexicon() *sequenceLexicon {
return &sequenceLexicon{
begins: []uint32{0},
idSet: make(map[uint32]int32),
}
}
// clears all data from the lexicon.
func (l *sequenceLexicon) clear() {
l.values = nil
l.begins = []uint32{0}
l.idSet = make(map[uint32]int32)
}
// add adds the given value to the lexicon if it is not already present, and
// returns its ID. IDs are assigned sequentially starting from zero.
func (l *sequenceLexicon) add(ids []int32) int32 {
if id, ok := l.idSet[hashSet(ids)]; ok {
return id
}
for _, v := range ids {
l.values = append(l.values, v)
}
l.begins = append(l.begins, uint32(len(l.values)))
id := int32(len(l.begins)) - 2
l.idSet[hashSet(ids)] = id
return id
}
// sequence returns the original sequence of values for the given ID.
func (l *sequenceLexicon) sequence(id int32) []int32 {
return l.values[l.begins[id]:l.begins[id+1]]
}
// size reports the number of value sequences in the lexicon.
func (l *sequenceLexicon) size() int {
// Subtract one because the list of begins starts out with the first element set to 0.
return len(l.begins) - 1
}
// hash returns a hash of this sequence of int32s.
func hashSet(s []int32) uint32 {
// TODO(roberts): We just need a way to nicely hash all the values down to
// a 32-bit value. To ensure no unnecessary dependencies we use the core
// library types available to do this. Is there a better option?
a := adler32.New()
binary.Write(a, binary.LittleEndian, s)
return a.Sum32()
}
// uniqueInt32s returns the sorted and uniqued set of int32s from the input.
func uniqueInt32s(in []int32) []int32 {
var vals []int32
m := make(map[int32]bool)
for _, i := range in {
if m[i] {
continue
}
m[i] = true
vals = append(vals, i)
}
sort.Slice(vals, func(i, j int) bool { return vals[i] < vals[j] })
return vals
}

1833
vendor/github.com/golang/geo/s2/loop.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

127
vendor/github.com/golang/geo/s2/matrix3x3.go generated vendored Normal file
View File

@ -0,0 +1,127 @@
// Copyright 2015 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"
"github.com/golang/geo/r3"
)
// matrix3x3 represents a traditional 3x3 matrix of floating point values.
// This is not a full fledged matrix. It only contains the pieces needed
// to satisfy the computations done within the s2 package.
type matrix3x3 [3][3]float64
// col returns the given column as a Point.
func (m *matrix3x3) col(col int) Point {
return Point{r3.Vector{m[0][col], m[1][col], m[2][col]}}
}
// row returns the given row as a Point.
func (m *matrix3x3) row(row int) Point {
return Point{r3.Vector{m[row][0], m[row][1], m[row][2]}}
}
// setCol sets the specified column to the value in the given Point.
func (m *matrix3x3) setCol(col int, p Point) *matrix3x3 {
m[0][col] = p.X
m[1][col] = p.Y
m[2][col] = p.Z
return m
}
// setRow sets the specified row to the value in the given Point.
func (m *matrix3x3) setRow(row int, p Point) *matrix3x3 {
m[row][0] = p.X
m[row][1] = p.Y
m[row][2] = p.Z
return m
}
// scale multiplies the matrix by the given value.
func (m *matrix3x3) scale(f float64) *matrix3x3 {
return &matrix3x3{
[3]float64{f * m[0][0], f * m[0][1], f * m[0][2]},
[3]float64{f * m[1][0], f * m[1][1], f * m[1][2]},
[3]float64{f * m[2][0], f * m[2][1], f * m[2][2]},
}
}
// mul returns the multiplication of m by the Point p and converts the
// resulting 1x3 matrix into a Point.
func (m *matrix3x3) mul(p Point) Point {
return Point{r3.Vector{
m[0][0]*p.X + m[0][1]*p.Y + m[0][2]*p.Z,
m[1][0]*p.X + m[1][1]*p.Y + m[1][2]*p.Z,
m[2][0]*p.X + m[2][1]*p.Y + m[2][2]*p.Z,
}}
}
// det returns the determinant of this matrix.
func (m *matrix3x3) det() float64 {
// | a b c |
// det | d e f | = aei + bfg + cdh - ceg - bdi - afh
// | g h i |
return m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] + m[0][2]*m[1][0]*m[2][1] -
m[0][2]*m[1][1]*m[2][0] - m[0][1]*m[1][0]*m[2][2] - m[0][0]*m[1][2]*m[2][1]
}
// transpose reflects the matrix along its diagonal and returns the result.
func (m *matrix3x3) transpose() *matrix3x3 {
m[0][1], m[1][0] = m[1][0], m[0][1]
m[0][2], m[2][0] = m[2][0], m[0][2]
m[1][2], m[2][1] = m[2][1], m[1][2]
return m
}
// String formats the matrix into an easier to read layout.
func (m *matrix3x3) String() string {
return fmt.Sprintf("[ %0.4f %0.4f %0.4f ] [ %0.4f %0.4f %0.4f ] [ %0.4f %0.4f %0.4f ]",
m[0][0], m[0][1], m[0][2],
m[1][0], m[1][1], m[1][2],
m[2][0], m[2][1], m[2][2],
)
}
// getFrame returns the orthonormal frame for the given point on the unit sphere.
func getFrame(p Point) matrix3x3 {
// Given the point p on the unit sphere, extend this into a right-handed
// coordinate frame of unit-length column vectors m = (x,y,z). Note that
// the vectors (x,y) are an orthonormal frame for the tangent space at point p,
// while p itself is an orthonormal frame for the normal space at p.
m := matrix3x3{}
m.setCol(2, p)
m.setCol(1, Point{p.Ortho()})
m.setCol(0, Point{m.col(1).Cross(p.Vector)})
return m
}
// toFrame returns the coordinates of the given point with respect to its orthonormal basis m.
// The resulting point q satisfies the identity (m * q == p).
func toFrame(m matrix3x3, p Point) Point {
// The inverse of an orthonormal matrix is its transpose.
return m.transpose().mul(p)
}
// fromFrame returns the coordinates of the given point in standard axis-aligned basis
// from its orthonormal basis m.
// The resulting point p satisfies the identity (p == m * q).
func fromFrame(m matrix3x3, q Point) Point {
return m.mul(q)
}

306
vendor/github.com/golang/geo/s2/max_distance_targets.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// Copyright 2019 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 (
"math"
"github.com/golang/geo/s1"
)
// maxDistance implements distance as the supplementary distance (Pi - x) to find
// results that are the furthest using the distance related algorithms.
type maxDistance s1.ChordAngle
func (m maxDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) }
func (m maxDistance) zero() distance { return maxDistance(s1.StraightChordAngle) }
func (m maxDistance) negative() distance { return maxDistance(s1.InfChordAngle()) }
func (m maxDistance) infinity() distance { return maxDistance(s1.NegativeChordAngle) }
func (m maxDistance) less(other distance) bool { return m.chordAngle() > other.chordAngle() }
func (m maxDistance) sub(other distance) distance {
return maxDistance(m.chordAngle() + other.chordAngle())
}
func (m maxDistance) chordAngleBound() s1.ChordAngle {
return s1.StraightChordAngle - m.chordAngle()
}
func (m maxDistance) updateDistance(dist distance) (distance, bool) {
if dist.less(m) {
m = maxDistance(dist.chordAngle())
return m, true
}
return m, false
}
func (m maxDistance) fromChordAngle(o s1.ChordAngle) distance {
return maxDistance(o)
}
// MaxDistanceToPointTarget is used for computing the maximum distance to a Point.
type MaxDistanceToPointTarget struct {
point Point
dist distance
}
// NewMaxDistanceToPointTarget returns a new target for the given Point.
func NewMaxDistanceToPointTarget(point Point) *MaxDistanceToPointTarget {
m := maxDistance(0)
return &MaxDistanceToPointTarget{point: point, dist: &m}
}
func (m *MaxDistanceToPointTarget) capBound() Cap {
return CapFromCenterChordAngle(Point{m.point.Mul(-1)}, (s1.ChordAngle(0)))
}
func (m *MaxDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(ChordAngleBetweenPoints(p, m.point)))
}
func (m *MaxDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
if d, ok := UpdateMaxDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(maxDistance(d))
return dist, true
}
return dist, false
}
func (m *MaxDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(cell.MaxDistance(m.point)))
}
func (m *MaxDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// For furthest points, we visit the polygons whose interior contains
// the antipode of the target point. These are the polygons whose
// distance to the target is maxDistance.zero()
q := NewContainsPointQuery(index, VertexModelSemiOpen)
return q.visitContainingShapes(Point{m.point.Mul(-1)}, func(shape Shape) bool {
return v(shape, m.point)
})
}
func (m *MaxDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MaxDistanceToPointTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MaxDistanceToPointTarget) distance() distance { return m.dist }
// MaxDistanceToEdgeTarget is used for computing the maximum distance to an Edge.
type MaxDistanceToEdgeTarget struct {
e Edge
dist distance
}
// NewMaxDistanceToEdgeTarget returns a new target for the given Edge.
func NewMaxDistanceToEdgeTarget(e Edge) *MaxDistanceToEdgeTarget {
m := maxDistance(0)
return &MaxDistanceToEdgeTarget{e: e, dist: m}
}
// capBound returns a Cap that bounds the antipode of the target. (This
// is the set of points whose maxDistance to the target is maxDistance.zero)
func (m *MaxDistanceToEdgeTarget) capBound() Cap {
// The following computes a radius equal to half the edge length in an
// efficient and numerically stable way.
d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1))
r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2))
return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Mul(-1).Normalize()}, s1.ChordAngleFromSquaredLength(r2))
}
func (m *MaxDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
if d, ok := UpdateMaxDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(maxDistance(d))
return dist, true
}
return dist, false
}
func (m *MaxDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
if d, ok := updateEdgePairMaxDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(maxDistance(d))
return dist, true
}
return dist, false
}
func (m *MaxDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(cell.MaxDistanceToEdge(m.e.V0, m.e.V1)))
}
func (m *MaxDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// We only need to test one edge point. That is because the method *must*
// visit a polygon if it fully contains the target, and *is allowed* to
// visit a polygon if it intersects the target. If the tested vertex is not
// contained, we know the full edge is not contained; if the tested vertex is
// contained, then the edge either is fully contained (must be visited) or it
// intersects (is allowed to be visited). We visit the center of the edge so
// that edge AB gives identical results to BA.
target := NewMaxDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
return target.visitContainingShapes(index, v)
}
func (m *MaxDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MaxDistanceToEdgeTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MaxDistanceToEdgeTarget) distance() distance { return m.dist }
// MaxDistanceToCellTarget is used for computing the maximum distance to a Cell.
type MaxDistanceToCellTarget struct {
cell Cell
dist distance
}
// NewMaxDistanceToCellTarget returns a new target for the given Cell.
func NewMaxDistanceToCellTarget(cell Cell) *MaxDistanceToCellTarget {
m := maxDistance(0)
return &MaxDistanceToCellTarget{cell: cell, dist: m}
}
func (m *MaxDistanceToCellTarget) capBound() Cap {
c := m.cell.CapBound()
return CapFromCenterAngle(Point{c.Center().Mul(-1)}, c.Radius())
}
func (m *MaxDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(m.cell.MaxDistance(p)))
}
func (m *MaxDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(m.cell.MaxDistanceToEdge(edge.V0, edge.V1)))
}
func (m *MaxDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
return dist.updateDistance(maxDistance(m.cell.MaxDistanceToCell(cell)))
}
func (m *MaxDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// We only need to check one point here - cell center is simplest.
// See comment at MaxDistanceToEdgeTarget's visitContainingShapes.
target := NewMaxDistanceToPointTarget(m.cell.Center())
return target.visitContainingShapes(index, v)
}
func (m *MaxDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MaxDistanceToCellTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MaxDistanceToCellTarget) distance() distance { return m.dist }
// MaxDistanceToShapeIndexTarget is used for computing the maximum distance to a ShapeIndex.
type MaxDistanceToShapeIndexTarget struct {
index *ShapeIndex
query *EdgeQuery
dist distance
}
// NewMaxDistanceToShapeIndexTarget returns a new target for the given ShapeIndex.
func NewMaxDistanceToShapeIndexTarget(index *ShapeIndex) *MaxDistanceToShapeIndexTarget {
m := maxDistance(0)
return &MaxDistanceToShapeIndexTarget{
index: index,
dist: m,
query: NewFurthestEdgeQuery(index, NewFurthestEdgeQueryOptions()),
}
}
// capBound returns a Cap that bounds the antipode of the target. This
// is the set of points whose maxDistance to the target is maxDistance.zero()
func (m *MaxDistanceToShapeIndexTarget) capBound() Cap {
// TODO(roberts): Depends on ShapeIndexRegion
// c := makeShapeIndexRegion(m.index).CapBound()
// return CapFromCenterRadius(Point{c.Center.Mul(-1)}, c.Radius())
panic("not implemented yet")
}
func (m *MaxDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMaxDistanceToPointTarget(p)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
func (m *MaxDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMaxDistanceToEdgeTarget(edge)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
func (m *MaxDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMaxDistanceToCellTarget(cell)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
// visitContainingShapes returns the polygons containing the antipodal
// reflection of *any* connected component for target types consisting of
// multiple connected components. It is sufficient to test containment of
// one vertex per connected component, since this allows us to also return
// any polygon whose boundary has distance.zero() to the target.
func (m *MaxDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// It is sufficient to find the set of chain starts in the target index
// (i.e., one vertex per connected component of edges) that are contained by
// the query index, except for one special case to handle full polygons.
//
// TODO(roberts): Do this by merge-joining the two ShapeIndexes and share
// the code with BooleanOperation.
for _, shape := range m.index.shapes {
numChains := shape.NumChains()
// Shapes that don't have any edges require a special case (below).
testedPoint := false
for c := 0; c < numChains; c++ {
chain := shape.Chain(c)
if chain.Length == 0 {
continue
}
testedPoint = true
target := NewMaxDistanceToPointTarget(shape.ChainEdge(c, 0).V0)
if !target.visitContainingShapes(index, v) {
return false
}
}
if !testedPoint {
// Special case to handle full polygons.
ref := shape.ReferencePoint()
if !ref.Contained {
continue
}
target := NewMaxDistanceToPointTarget(ref.Point)
if !target.visitContainingShapes(index, v) {
return false
}
}
}
return true
}
func (m *MaxDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool {
m.query.opts.maxError = maxErr
return true
}
func (m *MaxDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MaxDistanceToShapeIndexTarget) distance() distance { return m.dist }
func (m *MaxDistanceToShapeIndexTarget) setIncludeInteriors(b bool) {
m.query.opts.includeInteriors = b
}
func (m *MaxDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b }
// TODO(roberts): Remaining methods
//
// func (m *MaxDistanceToShapeIndexTarget) capBound() Cap {
// CellUnionTarget

164
vendor/github.com/golang/geo/s2/metric.go generated vendored Normal file
View File

@ -0,0 +1,164 @@
// Copyright 2015 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
// This file implements functions for various S2 measurements.
import "math"
// A Metric is a measure for cells. It is used to describe the shape and size
// of cells. They are useful for deciding which cell level to use in order to
// satisfy a given condition (e.g. that cell vertices must be no further than
// "x" apart). You can use the Value(level) method to compute the corresponding
// length or area on the unit sphere for cells at a given level. The minimum
// and maximum bounds are valid for cells at all levels, but they may be
// somewhat conservative for very large cells (e.g. face cells).
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
}
// Defined metrics.
// Of the projection methods defined in C++, Go only supports the quadratic projection.
// Each cell is bounded by four planes passing through its four edges and
// the center of the sphere. These metrics relate to the angle between each
// pair of opposite bounding planes, or equivalently, between the planes
// corresponding to two different s-values or two different t-values.
var (
MinAngleSpanMetric = Metric{1, 4.0 / 3}
AvgAngleSpanMetric = Metric{1, math.Pi / 2}
MaxAngleSpanMetric = Metric{1, 1.704897179199218452}
)
// The width of geometric figure is defined as the distance between two
// parallel bounding lines in a given direction. For cells, the minimum
// width is always attained between two opposite edges, and the maximum
// width is attained between two opposite vertices. However, for our
// purposes we redefine the width of a cell as the perpendicular distance
// between a pair of opposite edges. A cell therefore has two widths, one
// in each direction. The minimum width according to this definition agrees
// with the classic geometric one, but the maximum width is different. (The
// maximum geometric width corresponds to MaxDiag defined below.)
//
// The average width in both directions for all cells at level k is approximately
// AvgWidthMetric.Value(k).
//
// The width is useful for bounding the minimum or maximum distance from a
// point on one edge of a cell to the closest point on the opposite edge.
// For example, this is useful when growing regions by a fixed distance.
var (
MinWidthMetric = Metric{1, 2 * math.Sqrt2 / 3}
AvgWidthMetric = Metric{1, 1.434523672886099389}
MaxWidthMetric = Metric{1, MaxAngleSpanMetric.Deriv}
)
// The edge length metrics can be used to bound the minimum, maximum,
// or average distance from the center of one cell to the center of one of
// its edge neighbors. In particular, it can be used to bound the distance
// between adjacent cell centers along the space-filling Hilbert curve for
// cells at any given level.
var (
MinEdgeMetric = Metric{1, 2 * math.Sqrt2 / 3}
AvgEdgeMetric = Metric{1, 1.459213746386106062}
MaxEdgeMetric = Metric{1, MaxAngleSpanMetric.Deriv}
// MaxEdgeAspect is the maximum edge aspect ratio over all cells at any level,
// where the edge aspect ratio of a cell is defined as the ratio of its longest
// edge length to its shortest edge length.
MaxEdgeAspect = 1.442615274452682920
MinAreaMetric = Metric{2, 8 * math.Sqrt2 / 9}
AvgAreaMetric = Metric{2, 4 * math.Pi / 6}
MaxAreaMetric = Metric{2, 2.635799256963161491}
)
// The maximum diagonal is also the maximum diameter of any cell,
// and also the maximum geometric width (see the comment for widths). For
// example, the distance from an arbitrary point to the closest cell center
// at a given level is at most half the maximum diagonal length.
var (
MinDiagMetric = Metric{1, 8 * math.Sqrt2 / 9}
AvgDiagMetric = Metric{1, 2.060422738998471683}
MaxDiagMetric = Metric{1, 2.438654594434021032}
// MaxDiagAspect is the maximum diagonal aspect ratio over all cells at any
// level, where the diagonal aspect ratio of a cell is defined as the ratio
// of its longest diagonal length to its shortest diagonal length.
MaxDiagAspect = math.Sqrt(3)
)
// Value returns the value of the metric at the given level.
func (m Metric) Value(level int) float64 {
return math.Ldexp(m.Deriv, -m.Dim*level)
}
// MinLevel returns the minimum level such that the metric is at most
// the given value, or maxLevel (30) if there is no such level.
//
// For example, MinLevel(0.1) returns the minimum level such that all cell diagonal
// lengths are 0.1 or smaller. The returned value is always a valid level.
//
// In C++, this is called GetLevelForMaxValue.
func (m Metric) MinLevel(val float64) int {
if val < 0 {
return maxLevel
}
level := -(math.Ilogb(val/m.Deriv) >> uint(m.Dim-1))
if level > maxLevel {
level = maxLevel
}
if level < 0 {
level = 0
}
return level
}
// MaxLevel returns the maximum level such that the metric is at least
// the given value, or zero if there is no such level.
//
// For example, MaxLevel(0.1) returns the maximum level such that all cells have a
// minimum width of 0.1 or larger. The returned value is always a valid level.
//
// In C++, this is called GetLevelForMinValue.
func (m Metric) MaxLevel(val float64) int {
if val <= 0 {
return maxLevel
}
level := math.Ilogb(m.Deriv/val) >> uint(m.Dim-1)
if level > maxLevel {
level = maxLevel
}
if level < 0 {
level = 0
}
return level
}
// ClosestLevel returns the level at which the metric has approximately the given
// value. The return value is always a valid level. For example,
// AvgEdgeMetric.ClosestLevel(0.1) returns the level at which the average cell edge
// length is approximately 0.1.
func (m Metric) ClosestLevel(val float64) int {
x := math.Sqrt2
if m.Dim == 2 {
x = 2
}
return m.MinLevel(x * val)
}

362
vendor/github.com/golang/geo/s2/min_distance_targets.go generated vendored Normal file
View File

@ -0,0 +1,362 @@
// Copyright 2019 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 (
"math"
"github.com/golang/geo/s1"
)
// minDistance implements distance interface to find closest distance types.
type minDistance s1.ChordAngle
func (m minDistance) chordAngle() s1.ChordAngle { return s1.ChordAngle(m) }
func (m minDistance) zero() distance { return minDistance(0) }
func (m minDistance) negative() distance { return minDistance(s1.NegativeChordAngle) }
func (m minDistance) infinity() distance { return minDistance(s1.InfChordAngle()) }
func (m minDistance) less(other distance) bool { return m.chordAngle() < other.chordAngle() }
func (m minDistance) sub(other distance) distance {
return minDistance(m.chordAngle() - other.chordAngle())
}
func (m minDistance) chordAngleBound() s1.ChordAngle {
return m.chordAngle().Expanded(m.chordAngle().MaxAngleError())
}
// updateDistance updates its own value if the other value is less() than it is,
// and reports if it updated.
func (m minDistance) updateDistance(dist distance) (distance, bool) {
if dist.less(m) {
m = minDistance(dist.chordAngle())
return m, true
}
return m, false
}
func (m minDistance) fromChordAngle(o s1.ChordAngle) distance {
return minDistance(o)
}
// MinDistanceToPointTarget is a type for computing the minimum distance to a Point.
type MinDistanceToPointTarget struct {
point Point
dist distance
}
// NewMinDistanceToPointTarget returns a new target for the given Point.
func NewMinDistanceToPointTarget(point Point) *MinDistanceToPointTarget {
m := minDistance(0)
return &MinDistanceToPointTarget{point: point, dist: &m}
}
func (m *MinDistanceToPointTarget) capBound() Cap {
return CapFromCenterChordAngle(m.point, s1.ChordAngle(0))
}
func (m *MinDistanceToPointTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
var ok bool
dist, ok = dist.updateDistance(minDistance(ChordAngleBetweenPoints(p, m.point)))
return dist, ok
}
func (m *MinDistanceToPointTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
if d, ok := UpdateMinDistance(m.point, edge.V0, edge.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(minDistance(d))
return dist, true
}
return dist, false
}
func (m *MinDistanceToPointTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
var ok bool
dist, ok = dist.updateDistance(minDistance(cell.Distance(m.point)))
return dist, ok
}
func (m *MinDistanceToPointTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// For furthest points, we visit the polygons whose interior contains
// the antipode of the target point. These are the polygons whose
// distance to the target is maxDistance.zero()
q := NewContainsPointQuery(index, VertexModelSemiOpen)
return q.visitContainingShapes(m.point, func(shape Shape) bool {
return v(shape, m.point)
})
}
func (m *MinDistanceToPointTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MinDistanceToPointTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MinDistanceToPointTarget) distance() distance { return m.dist }
// ----------------------------------------------------------
// MinDistanceToEdgeTarget is a type for computing the minimum distance to an Edge.
type MinDistanceToEdgeTarget struct {
e Edge
dist distance
}
// NewMinDistanceToEdgeTarget returns a new target for the given Edge.
func NewMinDistanceToEdgeTarget(e Edge) *MinDistanceToEdgeTarget {
m := minDistance(0)
return &MinDistanceToEdgeTarget{e: e, dist: m}
}
// capBound returns a Cap that bounds the antipode of the target. (This
// is the set of points whose maxDistance to the target is maxDistance.zero)
func (m *MinDistanceToEdgeTarget) capBound() Cap {
// The following computes a radius equal to half the edge length in an
// efficient and numerically stable way.
d2 := float64(ChordAngleBetweenPoints(m.e.V0, m.e.V1))
r2 := (0.5 * d2) / (1 + math.Sqrt(1-0.25*d2))
return CapFromCenterChordAngle(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()}, s1.ChordAngleFromSquaredLength(r2))
}
func (m *MinDistanceToEdgeTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
if d, ok := UpdateMinDistance(p, m.e.V0, m.e.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(minDistance(d))
return dist, true
}
return dist, false
}
func (m *MinDistanceToEdgeTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
if d, ok := updateEdgePairMinDistance(m.e.V0, m.e.V1, edge.V0, edge.V1, dist.chordAngle()); ok {
dist, _ = dist.updateDistance(minDistance(d))
return dist, true
}
return dist, false
}
func (m *MinDistanceToEdgeTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
return dist.updateDistance(minDistance(cell.DistanceToEdge(m.e.V0, m.e.V1)))
}
func (m *MinDistanceToEdgeTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// We test the center of the edge in order to ensure that edge targets AB
// and BA yield identical results (which is not guaranteed by the API but
// users might expect). Other options would be to test both endpoints, or
// return different results for AB and BA in some cases.
target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
return target.visitContainingShapes(index, v)
}
func (m *MinDistanceToEdgeTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MinDistanceToEdgeTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MinDistanceToEdgeTarget) distance() distance { return m.dist }
// ----------------------------------------------------------
// MinDistanceToCellTarget is a type for computing the minimum distance to a Cell.
type MinDistanceToCellTarget struct {
cell Cell
dist distance
}
// NewMinDistanceToCellTarget returns a new target for the given Cell.
func NewMinDistanceToCellTarget(cell Cell) *MinDistanceToCellTarget {
m := minDistance(0)
return &MinDistanceToCellTarget{cell: cell, dist: m}
}
func (m *MinDistanceToCellTarget) capBound() Cap {
return m.cell.CapBound()
}
func (m *MinDistanceToCellTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
return dist.updateDistance(minDistance(m.cell.Distance(p)))
}
func (m *MinDistanceToCellTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
return dist.updateDistance(minDistance(m.cell.DistanceToEdge(edge.V0, edge.V1)))
}
func (m *MinDistanceToCellTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
return dist.updateDistance(minDistance(m.cell.DistanceToCell(cell)))
}
func (m *MinDistanceToCellTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// The simplest approach is simply to return the polygons that contain the
// cell center. Alternatively, if the index cell is smaller than the target
// cell then we could return all polygons that are present in the
// shapeIndexCell, but since the index is built conservatively this may
// include some polygons that don't quite intersect the cell. So we would
// either need to recheck for intersection more accurately, or weaken the
// VisitContainingShapes contract so that it only guarantees approximate
// intersection, neither of which seems like a good tradeoff.
target := NewMinDistanceToPointTarget(m.cell.Center())
return target.visitContainingShapes(index, v)
}
func (m *MinDistanceToCellTarget) setMaxError(maxErr s1.ChordAngle) bool { return false }
func (m *MinDistanceToCellTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MinDistanceToCellTarget) distance() distance { return m.dist }
// ----------------------------------------------------------
/*
// MinDistanceToCellUnionTarget is a type for computing the minimum distance to a CellUnion.
type MinDistanceToCellUnionTarget struct {
cu CellUnion
query *ClosestCellQuery
dist distance
}
// NewMinDistanceToCellUnionTarget returns a new target for the given CellUnion.
func NewMinDistanceToCellUnionTarget(cu CellUnion) *MinDistanceToCellUnionTarget {
m := minDistance(0)
return &MinDistanceToCellUnionTarget{cu: cu, dist: m}
}
func (m *MinDistanceToCellUnionTarget) capBound() Cap {
return m.cu.CapBound()
}
func (m *MinDistanceToCellUnionTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
m.query.opts.DistanceLimit = dist.chordAngle()
target := NewMinDistanceToPointTarget(p)
r := m.query.findEdge(target)
if r.ShapeID < 0 {
return dist, false
}
return minDistance(r.Distance), true
}
func (m *MinDistanceToCellUnionTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// We test the center of the edge in order to ensure that edge targets AB
// and BA yield identical results (which is not guaranteed by the API but
// users might expect). Other options would be to test both endpoints, or
// return different results for AB and BA in some cases.
target := NewMinDistanceToPointTarget(Point{m.e.V0.Add(m.e.V1.Vector).Normalize()})
return target.visitContainingShapes(index, v)
}
func (m *MinDistanceToCellUnionTarget) setMaxError(maxErr s1.ChordAngle) bool {
m.query.opts.MaxError = maxErr
return true
}
func (m *MinDistanceToCellUnionTarget) maxBruteForceIndexSize() int { return 30 }
func (m *MinDistanceToCellUnionTarget) distance() distance { return m.dist }
*/
// ----------------------------------------------------------
// MinDistanceToShapeIndexTarget is a type for computing the minimum distance to a ShapeIndex.
type MinDistanceToShapeIndexTarget struct {
index *ShapeIndex
query *EdgeQuery
dist distance
}
// NewMinDistanceToShapeIndexTarget returns a new target for the given ShapeIndex.
func NewMinDistanceToShapeIndexTarget(index *ShapeIndex) *MinDistanceToShapeIndexTarget {
m := minDistance(0)
return &MinDistanceToShapeIndexTarget{
index: index,
dist: m,
query: NewClosestEdgeQuery(index, NewClosestEdgeQueryOptions()),
}
}
func (m *MinDistanceToShapeIndexTarget) capBound() Cap {
// TODO(roberts): Depends on ShapeIndexRegion existing.
// c := makeS2ShapeIndexRegion(m.index).CapBound()
// return CapFromCenterRadius(Point{c.Center.Mul(-1)}, c.Radius())
panic("not implemented yet")
}
func (m *MinDistanceToShapeIndexTarget) updateDistanceToPoint(p Point, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMinDistanceToPointTarget(p)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
func (m *MinDistanceToShapeIndexTarget) updateDistanceToEdge(edge Edge, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMinDistanceToEdgeTarget(edge)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
func (m *MinDistanceToShapeIndexTarget) updateDistanceToCell(cell Cell, dist distance) (distance, bool) {
m.query.opts.distanceLimit = dist.chordAngle()
target := NewMinDistanceToCellTarget(cell)
r := m.query.findEdge(target, m.query.opts)
if r.shapeID < 0 {
return dist, false
}
return r.distance, true
}
// For target types consisting of multiple connected components (such as this one),
// this method should return the polygons containing the antipodal reflection of
// *any* connected component. (It is sufficient to test containment of one vertex per
// connected component, since this allows us to also return any polygon whose
// boundary has distance.zero() to the target.)
func (m *MinDistanceToShapeIndexTarget) visitContainingShapes(index *ShapeIndex, v shapePointVisitorFunc) bool {
// It is sufficient to find the set of chain starts in the target index
// (i.e., one vertex per connected component of edges) that are contained by
// the query index, except for one special case to handle full polygons.
//
// TODO(roberts): Do this by merge-joining the two ShapeIndexes.
for _, shape := range m.index.shapes {
numChains := shape.NumChains()
// Shapes that don't have any edges require a special case (below).
testedPoint := false
for c := 0; c < numChains; c++ {
chain := shape.Chain(c)
if chain.Length == 0 {
continue
}
testedPoint = true
target := NewMinDistanceToPointTarget(shape.ChainEdge(c, 0).V0)
if !target.visitContainingShapes(index, v) {
return false
}
}
if !testedPoint {
// Special case to handle full polygons.
ref := shape.ReferencePoint()
if !ref.Contained {
continue
}
target := NewMinDistanceToPointTarget(ref.Point)
if !target.visitContainingShapes(index, v) {
return false
}
}
}
return true
}
func (m *MinDistanceToShapeIndexTarget) setMaxError(maxErr s1.ChordAngle) bool {
m.query.opts.maxError = maxErr
return true
}
func (m *MinDistanceToShapeIndexTarget) maxBruteForceIndexSize() int { return 25 }
func (m *MinDistanceToShapeIndexTarget) distance() distance { return m.dist }
func (m *MinDistanceToShapeIndexTarget) setIncludeInteriors(b bool) {
m.query.opts.includeInteriors = b
}
func (m *MinDistanceToShapeIndexTarget) setUseBruteForce(b bool) { m.query.opts.useBruteForce = b }
// TODO(roberts): Remaining methods
//
// func (m *MinDistanceToShapeIndexTarget) capBound() Cap {
// CellUnionTarget

88
vendor/github.com/golang/geo/s2/nthderivative.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
// Copyright 2017 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
// nthDerivativeCoder provides Nth Derivative Coding.
// (In signal processing disciplines, this is known as N-th Delta Coding.)
//
// Good for varint coding integer sequences with polynomial trends.
//
// Instead of coding a sequence of values directly, code its nth-order discrete
// derivative. Overflow in integer addition and subtraction makes this a
// lossless transform.
//
// constant linear quadratic
// trend trend trend
// / \ / \ / \_
// input |0 0 0 0 1 2 3 4 9 16 25 36
// 0th derivative(identity) |0 0 0 0 1 2 3 4 9 16 25 36
// 1st derivative(delta coding) | 0 0 0 1 1 1 1 5 7 9 11
// 2nd derivative(linear prediction) | 0 0 1 0 0 0 4 2 2 2
// -------------------------------------
// 0 1 2 3 4 5 6 7 8 9 10 11
// n in sequence
//
// Higher-order codings can break even or be detrimental on other sequences.
//
// random oscillating
// / \ / \_
// input |5 9 6 1 8 8 2 -2 4 -4 6 -6
// 0th derivative(identity) |5 9 6 1 8 8 2 -2 4 -4 6 -6
// 1st derivative(delta coding) | 4 -3 -5 7 0 -6 -4 6 -8 10 -12
// 2nd derivative(linear prediction) | -7 -2 12 -7 -6 2 10 -14 18 -22
// ---------------------------------------
// 0 1 2 3 4 5 6 7 8 9 10 11
// n in sequence
//
// Note that the nth derivative isn't available until sequence item n. Earlier
// values are coded at lower order. For the above table, read 5 4 -7 -2 12 ...
type nthDerivativeCoder struct {
n, m int
memory [10]int32
}
// newNthDerivativeCoder returns a new coder, where n is the derivative order of the encoder (the N in NthDerivative).
// n must be within [0,10].
func newNthDerivativeCoder(n int) *nthDerivativeCoder {
c := &nthDerivativeCoder{n: n}
if n < 0 || n > len(c.memory) {
panic("unsupported n. Must be within [0,10].")
}
return c
}
func (c *nthDerivativeCoder) encode(k int32) int32 {
for i := 0; i < c.m; i++ {
delta := k - c.memory[i]
c.memory[i] = k
k = delta
}
if c.m < c.n {
c.memory[c.m] = k
c.m++
}
return k
}
func (c *nthDerivativeCoder) decode(k int32) int32 {
if c.m < c.n {
c.m++
}
for i := c.m - 1; i >= 0; i-- {
c.memory[i] += k
k = c.memory[i]
}
return k
}

252
vendor/github.com/golang/geo/s2/paddedcell.go generated vendored Normal file
View File

@ -0,0 +1,252 @@
// Copyright 2016 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 (
"github.com/golang/geo/r1"
"github.com/golang/geo/r2"
)
// PaddedCell represents a Cell whose (u,v)-range has been expanded on
// all sides by a given amount of "padding". Unlike Cell, its methods and
// representation are optimized for clipping edges against Cell boundaries
// to determine which cells are intersected by a given set of edges.
type PaddedCell struct {
id CellID
padding float64
bound r2.Rect
middle r2.Rect // A rect in (u, v)-space that belongs to all four children.
iLo, jLo int // Minimum (i,j)-coordinates of this cell before padding
orientation int // Hilbert curve orientation of this cell.
level int
}
// PaddedCellFromCellID constructs a padded cell with the given padding.
func PaddedCellFromCellID(id CellID, padding float64) *PaddedCell {
p := &PaddedCell{
id: id,
padding: padding,
middle: r2.EmptyRect(),
}
// Fast path for constructing a top-level face (the most common case).
if id.isFace() {
limit := padding + 1
p.bound = r2.Rect{r1.Interval{-limit, limit}, r1.Interval{-limit, limit}}
p.middle = r2.Rect{r1.Interval{-padding, padding}, r1.Interval{-padding, padding}}
p.orientation = id.Face() & 1
return p
}
_, p.iLo, p.jLo, p.orientation = id.faceIJOrientation()
p.level = id.Level()
p.bound = ijLevelToBoundUV(p.iLo, p.jLo, p.level).ExpandedByMargin(padding)
ijSize := sizeIJ(p.level)
p.iLo &= -ijSize
p.jLo &= -ijSize
return p
}
// PaddedCellFromParentIJ constructs the child of parent with the given (i,j) index.
// The four child cells have indices of (0,0), (0,1), (1,0), (1,1), where the i and j
// indices correspond to increasing u- and v-values respectively.
func PaddedCellFromParentIJ(parent *PaddedCell, i, j int) *PaddedCell {
// Compute the position and orientation of the child incrementally from the
// orientation of the parent.
pos := ijToPos[parent.orientation][2*i+j]
p := &PaddedCell{
id: parent.id.Children()[pos],
padding: parent.padding,
bound: parent.bound,
orientation: parent.orientation ^ posToOrientation[pos],
level: parent.level + 1,
middle: r2.EmptyRect(),
}
ijSize := sizeIJ(p.level)
p.iLo = parent.iLo + i*ijSize
p.jLo = parent.jLo + j*ijSize
// For each child, one corner of the bound is taken directly from the parent
// while the diagonally opposite corner is taken from middle().
middle := parent.Middle()
if i == 1 {
p.bound.X.Lo = middle.X.Lo
} else {
p.bound.X.Hi = middle.X.Hi
}
if j == 1 {
p.bound.Y.Lo = middle.Y.Lo
} else {
p.bound.Y.Hi = middle.Y.Hi
}
return p
}
// CellID returns the CellID this padded cell represents.
func (p PaddedCell) CellID() CellID {
return p.id
}
// Padding returns the amount of padding on this cell.
func (p PaddedCell) Padding() float64 {
return p.padding
}
// Level returns the level this cell is at.
func (p PaddedCell) Level() int {
return p.level
}
// Center returns the center of this cell.
func (p PaddedCell) Center() Point {
ijSize := sizeIJ(p.level)
si := uint32(2*p.iLo + ijSize)
ti := uint32(2*p.jLo + ijSize)
return Point{faceSiTiToXYZ(p.id.Face(), si, ti).Normalize()}
}
// Middle returns the rectangle in the middle of this cell that belongs to
// all four of its children in (u,v)-space.
func (p *PaddedCell) Middle() r2.Rect {
// We compute this field lazily because it is not needed the majority of the
// time (i.e., for cells where the recursion terminates).
if p.middle.IsEmpty() {
ijSize := sizeIJ(p.level)
u := stToUV(siTiToST(uint32(2*p.iLo + ijSize)))
v := stToUV(siTiToST(uint32(2*p.jLo + ijSize)))
p.middle = r2.Rect{
r1.Interval{u - p.padding, u + p.padding},
r1.Interval{v - p.padding, v + p.padding},
}
}
return p.middle
}
// Bound returns the bounds for this cell in (u,v)-space including padding.
func (p PaddedCell) Bound() r2.Rect {
return p.bound
}
// ChildIJ returns the (i,j) coordinates for the child cell at the given traversal
// position. The traversal position corresponds to the order in which child
// cells are visited by the Hilbert curve.
func (p PaddedCell) ChildIJ(pos int) (i, j int) {
ij := posToIJ[p.orientation][pos]
return ij >> 1, ij & 1
}
// EntryVertex return the vertex where the space-filling curve enters this cell.
func (p PaddedCell) EntryVertex() Point {
// The curve enters at the (0,0) vertex unless the axis directions are
// reversed, in which case it enters at the (1,1) vertex.
i := p.iLo
j := p.jLo
if p.orientation&invertMask != 0 {
ijSize := sizeIJ(p.level)
i += ijSize
j += ijSize
}
return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
}
// ExitVertex returns the vertex where the space-filling curve exits this cell.
func (p PaddedCell) ExitVertex() Point {
// The curve exits at the (1,0) vertex unless the axes are swapped or
// inverted but not both, in which case it exits at the (0,1) vertex.
i := p.iLo
j := p.jLo
ijSize := sizeIJ(p.level)
if p.orientation == 0 || p.orientation == swapMask+invertMask {
i += ijSize
} else {
j += ijSize
}
return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
}
// ShrinkToFit returns the smallest CellID that contains all descendants of this
// padded cell whose bounds intersect the given rect. For algorithms that use
// recursive subdivision to find the cells that intersect a particular object, this
// method can be used to skip all of the initial subdivision steps where only
// one child needs to be expanded.
//
// Note that this method is not the same as returning the smallest cell that contains
// the intersection of this cell with rect. Because of the padding, even if one child
// completely contains rect it is still possible that a neighboring child may also
// intersect the given rect.
//
// The provided Rect must intersect the bounds of this cell.
func (p *PaddedCell) ShrinkToFit(rect r2.Rect) CellID {
// Quick rejection test: if rect contains the center of this cell along
// either axis, then no further shrinking is possible.
if p.level == 0 {
// Fast path (most calls to this function start with a face cell).
if rect.X.Contains(0) || rect.Y.Contains(0) {
return p.id
}
}
ijSize := sizeIJ(p.level)
if rect.X.Contains(stToUV(siTiToST(uint32(2*p.iLo+ijSize)))) ||
rect.Y.Contains(stToUV(siTiToST(uint32(2*p.jLo+ijSize)))) {
return p.id
}
// Otherwise we expand rect by the given padding on all sides and find
// the range of coordinates that it spans along the i- and j-axes. We then
// compute the highest bit position at which the min and max coordinates
// differ. This corresponds to the first cell level at which at least two
// children intersect rect.
// Increase the padding to compensate for the error in uvToST.
// (The constant below is a provable upper bound on the additional error.)
padded := rect.ExpandedByMargin(p.padding + 1.5*dblEpsilon)
iMin, jMin := p.iLo, p.jLo // Min i- or j- coordinate spanned by padded
var iXor, jXor int // XOR of the min and max i- or j-coordinates
if iMin < stToIJ(uvToST(padded.X.Lo)) {
iMin = stToIJ(uvToST(padded.X.Lo))
}
if a, b := p.iLo+ijSize-1, stToIJ(uvToST(padded.X.Hi)); a <= b {
iXor = iMin ^ a
} else {
iXor = iMin ^ b
}
if jMin < stToIJ(uvToST(padded.Y.Lo)) {
jMin = stToIJ(uvToST(padded.Y.Lo))
}
if a, b := p.jLo+ijSize-1, stToIJ(uvToST(padded.Y.Hi)); a <= b {
jXor = jMin ^ a
} else {
jXor = jMin ^ b
}
// Compute the highest bit position where the two i- or j-endpoints differ,
// and then choose the cell level that includes both of these endpoints. So
// if both pairs of endpoints are equal we choose maxLevel; if they differ
// only at bit 0, we choose (maxLevel - 1), and so on.
levelMSB := uint64(((iXor | jXor) << 1) + 1)
level := maxLevel - findMSBSetNonZero64(levelMSB)
if level <= p.level {
return p.id
}
return cellIDFromFaceIJ(p.id.Face(), iMin, jMin).Parent(level)
}

258
vendor/github.com/golang/geo/s2/point.go generated vendored Normal file
View File

@ -0,0 +1,258 @@
// 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"
"math"
"sort"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// Point represents a point on the unit sphere as a normalized 3D vector.
// Fields should be treated as read-only. Use one of the factory methods for creation.
type Point struct {
r3.Vector
}
// sortPoints sorts the slice of Points in place.
func sortPoints(e []Point) {
sort.Sort(points(e))
}
// points implements the Sort interface for slices of Point.
type points []Point
func (p points) Len() int { return len(p) }
func (p points) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p points) Less(i, j int) bool { return p[i].Cmp(p[j].Vector) == -1 }
// 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 PointFromCoords(x, y, z float64) Point {
if x == 0 && y == 0 && z == 0 {
return OriginPoint()
}
return Point{r3.Vector{x, y, z}.Normalize()}
}
// 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 OriginPoint() Point {
return Point{r3.Vector{-0.0099994664350250197, 0.0025924542609324121, 0.99994664350250195}}
}
// 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.
//
// 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
func (p Point) PointCross(op Point) Point {
// NOTE(dnadasi): In the C++ API the equivalent method here was known as "RobustCrossProd",
// but PointCross more accurately describes how this method is used.
x := p.Add(op.Vector).Cross(op.Sub(p.Vector))
// Compare exactly to the 0 vector.
if x == (r3.Vector{}) {
// The only result that makes sense mathematically is to return zero, but
// we find it more convenient to return an arbitrary orthogonal vector.
return Point{p.Ortho()}
}
return Point{x}
}
// 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 OrderedCCW(a, b, c, o Point) bool {
sum := 0
if RobustSign(b, o, a) != Clockwise {
sum++
}
if RobustSign(c, o, b) != Clockwise {
sum++
}
if RobustSign(a, o, c) == CounterClockwise {
sum++
}
return sum >= 2
}
// Distance returns the angle between two points.
func (p Point) Distance(b Point) s1.Angle {
return p.Vector.Angle(b.Vector)
}
// ApproxEqual reports whether the two points are similar enough to be equal.
func (p Point) ApproxEqual(other Point) bool {
return p.approxEqual(other, s1.Angle(epsilon))
}
// approxEqual reports whether the two points are within the given epsilon.
func (p Point) approxEqual(other Point, eps s1.Angle) bool {
return p.Vector.Angle(other.Vector) <= eps
}
// ChordAngleBetweenPoints constructs a ChordAngle corresponding to the distance
// between the two given points. The points must be unit length.
func ChordAngleBetweenPoints(x, y Point) s1.ChordAngle {
return s1.ChordAngle(math.Min(4.0, x.Sub(y.Vector).Norm2()))
}
// regularPoints generates a slice of points shaped as a regular polygon with
// the numVertices vertices, all located on a circle of the specified angular radius
// around the center. The radius is the actual distance from center to each vertex.
func regularPoints(center Point, radius s1.Angle, numVertices int) []Point {
return regularPointsForFrame(getFrame(center), radius, numVertices)
}
// regularPointsForFrame generates a slice of points shaped as a regular polygon
// with numVertices vertices, all on a circle of the specified angular radius around
// the center. The radius is the actual distance from the center to each vertex.
func regularPointsForFrame(frame matrix3x3, radius s1.Angle, numVertices int) []Point {
// We construct the loop in the given frame coordinates, with the center at
// (0, 0, 1). For a loop of radius r, the loop vertices have the form
// (x, y, z) where x^2 + y^2 = sin(r) and z = cos(r). The distance on the
// sphere (arc length) from each vertex to the center is acos(cos(r)) = r.
z := math.Cos(radius.Radians())
r := math.Sin(radius.Radians())
radianStep := 2 * math.Pi / float64(numVertices)
var vertices []Point
for i := 0; i < numVertices; i++ {
angle := float64(i) * radianStep
p := Point{r3.Vector{r * math.Cos(angle), r * math.Sin(angle), z}}
vertices = append(vertices, Point{fromFrame(frame, p).Normalize()})
}
return vertices
}
// CapBound returns a bounding cap for this point.
func (p Point) CapBound() Cap {
return CapFromPoint(p)
}
// RectBound returns a bounding latitude-longitude rectangle from this point.
func (p Point) RectBound() Rect {
return RectFromLatLng(LatLngFromPoint(p))
}
// ContainsCell returns false as Points do not contain any other S2 types.
func (p Point) ContainsCell(c Cell) bool { return false }
// IntersectsCell reports whether this Point intersects the given cell.
func (p Point) IntersectsCell(c Cell) bool {
return c.ContainsPoint(p)
}
// ContainsPoint reports if this Point contains the other Point.
// (This method is named to satisfy the Region interface.)
func (p Point) ContainsPoint(other Point) bool {
return p.Contains(other)
}
// CellUnionBound computes a covering of the Point.
func (p Point) CellUnionBound() []CellID {
return p.CapBound().CellUnionBound()
}
// Contains reports if this Point contains the other Point.
// (This method matches all other s2 types where the reflexive Contains
// method does not contain the type's name.)
func (p Point) Contains(other Point) bool { return p == other }
// Encode encodes the Point.
func (p Point) Encode(w io.Writer) error {
e := &encoder{w: w}
p.encode(e)
return e.err
}
func (p Point) encode(e *encoder) {
e.writeInt8(encodingVersion)
e.writeFloat64(p.X)
e.writeFloat64(p.Y)
e.writeFloat64(p.Z)
}
// Decode decodes the Point.
func (p *Point) Decode(r io.Reader) error {
d := &decoder{r: asByteReader(r)}
p.decode(d)
return d.err
}
func (p *Point) 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
}
p.X = d.readFloat64()
p.Y = d.readFloat64()
p.Z = d.readFloat64()
}
// Rotate the given point about the given axis by the given angle. p and
// axis must be unit length; angle has no restrictions (e.g., it can be
// positive, negative, greater than 360 degrees, etc).
func Rotate(p, axis Point, angle s1.Angle) Point {
// Let M be the plane through P that is perpendicular to axis, and let
// center be the point where M intersects axis. We construct a
// right-handed orthogonal frame (dx, dy, center) such that dx is the
// vector from center to P, and dy has the same length as dx. The
// result can then be expressed as (cos(angle)*dx + sin(angle)*dy + center).
center := axis.Mul(p.Dot(axis.Vector))
dx := p.Sub(center)
dy := axis.Cross(p.Vector)
// Mathematically the result is unit length, but normalization is necessary
// to ensure that numerical errors don't accumulate.
return Point{dx.Mul(math.Cos(angle.Radians())).Add(dy.Mul(math.Sin(angle.Radians()))).Add(center).Normalize()}
}

149
vendor/github.com/golang/geo/s2/point_measures.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
// Copyright 2018 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 (
"math"
"github.com/golang/geo/s1"
)
// PointArea returns the area of triangle ABC. This method combines two different
// algorithms to get accurate results for both large and small triangles.
// The maximum error is about 5e-15 (about 0.25 square meters on the Earth's
// surface), the same as GirardArea below, but unlike that method it is
// also accurate for small triangles. Example: when the true area is 100
// square meters, PointArea yields an error about 1 trillion times smaller than
// GirardArea.
//
// All points should be unit length, and no two points should be antipodal.
// The area is always positive.
func PointArea(a, b, c Point) float64 {
// 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.
sa := float64(b.Angle(c.Vector))
sb := float64(c.Angle(a.Vector))
sc := float64(a.Angle(b.Vector))
s := 0.5 * (sa + sb + sc)
if s >= 3e-4 {
// Consider whether Girard's formula might be more accurate.
dmin := s - math.Max(sa, math.Max(sb, sc))
if dmin < 1e-2*s*s*s*s*s {
// This triangle is skinny enough to use Girard's formula.
area := GirardArea(a, b, c)
if dmin < s*0.1*area {
return area
}
}
}
// Use l'Huilier's formula.
return 4 * math.Atan(math.Sqrt(math.Max(0.0, math.Tan(0.5*s)*math.Tan(0.5*(s-sa))*
math.Tan(0.5*(s-sb))*math.Tan(0.5*(s-sc)))))
}
// GirardArea returns the area of the triangle computed using Girard's formula.
// All points should be unit length, and no two points should be antipodal.
//
// This method is about twice as fast as PointArea() but has poor relative
// accuracy for small triangles. The maximum error is about 5e-15 (about
// 0.25 square meters on the Earth's surface) and the average error is about
// 1e-15. These bounds apply to triangles of any size, even as the maximum
// edge length of the triangle approaches 180 degrees. But note that for
// such triangles, tiny perturbations of the input points can change the
// true mathematical area dramatically.
func GirardArea(a, b, c Point) float64 {
// This is equivalent to the usual Girard's formula but is slightly more
// accurate, faster to compute, and handles a == b == c without a special
// case. PointCross is necessary to get good accuracy when two of
// the input points are very close together.
ab := a.PointCross(b)
bc := b.PointCross(c)
ac := a.PointCross(c)
area := float64(ab.Angle(ac.Vector) - ab.Angle(bc.Vector) + bc.Angle(ac.Vector))
if area < 0 {
area = 0
}
return area
}
// SignedArea returns a positive value for counterclockwise triangles and a negative
// value otherwise (similar to PointArea).
func SignedArea(a, b, c Point) float64 {
return float64(RobustSign(a, b, c)) * PointArea(a, b, c)
}
// Angle returns the interior angle at the vertex B in the triangle ABC. The
// return value is always in the range [0, pi]. All points should be
// normalized. Ensures that Angle(a,b,c) == Angle(c,b,a) for all a,b,c.
//
// The angle is undefined if A or C is diametrically opposite from B, and
// becomes numerically unstable as the length of edge AB or BC approaches
// 180 degrees.
func Angle(a, b, c Point) s1.Angle {
// PointCross is necessary to get good accuracy when two of the input
// points are very close together.
return a.PointCross(b).Angle(c.PointCross(b).Vector)
}
// TurnAngle returns the exterior angle at vertex B in the triangle ABC. The
// return value is positive if ABC is counterclockwise and negative otherwise.
// If you imagine an ant walking from A to B to C, this is the angle that the
// ant turns at vertex B (positive = left = CCW, negative = right = CW).
// This quantity is also known as the "geodesic curvature" at B.
//
// Ensures that TurnAngle(a,b,c) == -TurnAngle(c,b,a) for all distinct
// a,b,c. The result is undefined if (a == b || b == c), but is either
// -Pi or Pi if (a == c). All points should be normalized.
func TurnAngle(a, b, c Point) s1.Angle {
// We use PointCross to get good accuracy when two points are very
// close together, and RobustSign to ensure that the sign is correct for
// turns that are close to 180 degrees.
angle := a.PointCross(b).Angle(b.PointCross(c).Vector)
// Don't return RobustSign * angle because it is legal to have (a == c).
if RobustSign(a, b, c) == CounterClockwise {
return angle
}
return -angle
}

42
vendor/github.com/golang/geo/s2/point_vector.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2017 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
// Shape interface enforcement
var (
_ Shape = (*PointVector)(nil)
)
// PointVector is a Shape representing a set of Points. Each point
// is represented as a degenerate edge with the same starting and ending
// vertices.
//
// This type is useful for adding a collection of points to an ShapeIndex.
//
// Its methods are on *PointVector due to implementation details of ShapeIndex.
type PointVector []Point
func (p *PointVector) NumEdges() int { return len(*p) }
func (p *PointVector) Edge(i int) Edge { return Edge{(*p)[i], (*p)[i]} }
func (p *PointVector) ReferencePoint() ReferencePoint { return OriginReferencePoint(false) }
func (p *PointVector) NumChains() int { return len(*p) }
func (p *PointVector) Chain(i int) Chain { return Chain{i, 1} }
func (p *PointVector) ChainEdge(i, j int) Edge { return Edge{(*p)[i], (*p)[j]} }
func (p *PointVector) ChainPosition(e int) ChainPosition { return ChainPosition{e, 0} }
func (p *PointVector) Dimension() int { return 0 }
func (p *PointVector) IsEmpty() bool { return defaultShapeIsEmpty(p) }
func (p *PointVector) IsFull() bool { return defaultShapeIsFull(p) }
func (p *PointVector) typeTag() typeTag { return typeTagPointVector }
func (p *PointVector) privateInterface() {}

319
vendor/github.com/golang/geo/s2/pointcompression.go generated vendored Normal file
View File

@ -0,0 +1,319 @@
// Copyright 2017 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 (
"errors"
"fmt"
"github.com/golang/geo/r3"
)
// maxEncodedVertices is the maximum number of vertices, in a row, to be encoded or decoded.
// On decode, this defends against malicious encodings that try and have us exceed RAM.
const maxEncodedVertices = 50000000
// xyzFaceSiTi represents the The XYZ and face,si,ti coordinates of a Point
// and, if this point is equal to the center of a Cell, the level of this cell
// (-1 otherwise). This is used for Loops and Polygons to store data in a more
// compressed format.
type xyzFaceSiTi struct {
xyz Point
face int
si, ti uint32
level int
}
const derivativeEncodingOrder = 2
func appendFace(faces []faceRun, face int) []faceRun {
if len(faces) == 0 || faces[len(faces)-1].face != face {
return append(faces, faceRun{face, 1})
}
faces[len(faces)-1].count++
return faces
}
// encodePointsCompressed uses an optimized compressed format to encode the given values.
func encodePointsCompressed(e *encoder, vertices []xyzFaceSiTi, level int) {
var faces []faceRun
for _, v := range vertices {
faces = appendFace(faces, v.face)
}
encodeFaces(e, faces)
type piQi struct {
pi, qi uint32
}
verticesPiQi := make([]piQi, len(vertices))
for i, v := range vertices {
verticesPiQi[i] = piQi{siTitoPiQi(v.si, level), siTitoPiQi(v.ti, level)}
}
piCoder, qiCoder := newNthDerivativeCoder(derivativeEncodingOrder), newNthDerivativeCoder(derivativeEncodingOrder)
for i, v := range verticesPiQi {
f := encodePointCompressed
if i == 0 {
// The first point will be just the (pi, qi) coordinates
// of the Point. NthDerivativeCoder will not save anything
// in that case, so we encode in fixed format rather than varint
// to avoid the varint overhead.
f = encodeFirstPointFixedLength
}
f(e, v.pi, v.qi, level, piCoder, qiCoder)
}
var offCenter []int
for i, v := range vertices {
if v.level != level {
offCenter = append(offCenter, i)
}
}
e.writeUvarint(uint64(len(offCenter)))
for _, idx := range offCenter {
e.writeUvarint(uint64(idx))
e.writeFloat64(vertices[idx].xyz.X)
e.writeFloat64(vertices[idx].xyz.Y)
e.writeFloat64(vertices[idx].xyz.Z)
}
}
func encodeFirstPointFixedLength(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) {
// Do not ZigZagEncode the first point, since it cannot be negative.
codedPi, codedQi := piCoder.encode(int32(pi)), qiCoder.encode(int32(qi))
// Interleave to reduce overhead from two partial bytes to one.
interleaved := interleaveUint32(uint32(codedPi), uint32(codedQi))
// Write as little endian.
bytesRequired := (level + 7) / 8 * 2
for i := 0; i < bytesRequired; i++ {
e.writeUint8(uint8(interleaved))
interleaved >>= 8
}
}
// encodePointCompressed encodes points into e.
// Given a sequence of Points assumed to be the center of level-k cells,
// compresses it into a stream using the following method:
// - decompose the points into (face, si, ti) tuples.
// - run-length encode the faces, combining face number and count into a
// varint32. See the faceRun struct.
// - right shift the (si, ti) to remove the part that's constant for all cells
// of level-k. The result is called the (pi, qi) space.
// - 2nd derivative encode the pi and qi sequences (linear prediction)
// - zig-zag encode all derivative values but the first, which cannot be
// negative
// - interleave the zig-zag encoded values
// - encode the first interleaved value in a fixed length encoding
// (varint would make this value larger)
// - encode the remaining interleaved values as varint64s, as the
// derivative encoding should make the values small.
// In addition, provides a lossless method to compress a sequence of points even
// if some points are not the center of level-k cells. These points are stored
// exactly, using 3 double precision values, after the above encoded string,
// together with their index in the sequence (this leads to some redundancy - it
// is expected that only a small fraction of the points are not cell centers).
//
// To encode leaf cells, this requires 8 bytes for the first vertex plus
// an average of 3.8 bytes for each additional vertex, when computed on
// Google's geographic repository.
func encodePointCompressed(e *encoder, pi, qi uint32, level int, piCoder, qiCoder *nthDerivativeCoder) {
// ZigZagEncode, as varint requires the maximum number of bytes for
// negative numbers.
zzPi := zigzagEncode(piCoder.encode(int32(pi)))
zzQi := zigzagEncode(qiCoder.encode(int32(qi)))
// Interleave to reduce overhead from two partial bytes to one.
interleaved := interleaveUint32(zzPi, zzQi)
e.writeUvarint(interleaved)
}
type faceRun struct {
face, count int
}
func decodeFaceRun(d *decoder) faceRun {
faceAndCount := d.readUvarint()
ret := faceRun{
face: int(faceAndCount % numFaces),
count: int(faceAndCount / numFaces),
}
if ret.count <= 0 && d.err == nil {
d.err = errors.New("non-positive count for face run")
}
return ret
}
func decodeFaces(numVertices int, d *decoder) []faceRun {
var frs []faceRun
for nparsed := 0; nparsed < numVertices; {
fr := decodeFaceRun(d)
if d.err != nil {
return nil
}
frs = append(frs, fr)
nparsed += fr.count
}
return frs
}
// encodeFaceRun encodes each faceRun as a varint64 with value numFaces * count + face.
func encodeFaceRun(e *encoder, fr faceRun) {
// It isn't necessary to encode the number of faces left for the last run,
// but since this would only help if there were more than 21 faces, it will
// be a small overall savings, much smaller than the bound encoding.
coded := numFaces*uint64(fr.count) + uint64(fr.face)
e.writeUvarint(coded)
}
func encodeFaces(e *encoder, frs []faceRun) {
for _, fr := range frs {
encodeFaceRun(e, fr)
}
}
type facesIterator struct {
faces []faceRun
// How often have we yet shown the current face?
numCurrentFaceShown int
curFace int
}
func (fi *facesIterator) next() (ok bool) {
if len(fi.faces) == 0 {
return false
}
fi.curFace = fi.faces[0].face
fi.numCurrentFaceShown++
// Advance fs if needed.
if fi.faces[0].count <= fi.numCurrentFaceShown {
fi.faces = fi.faces[1:]
fi.numCurrentFaceShown = 0
}
return true
}
func decodePointsCompressed(d *decoder, level int, target []Point) {
faces := decodeFaces(len(target), d)
piCoder := newNthDerivativeCoder(derivativeEncodingOrder)
qiCoder := newNthDerivativeCoder(derivativeEncodingOrder)
iter := facesIterator{faces: faces}
for i := range target {
decodeFn := decodePointCompressed
if i == 0 {
decodeFn = decodeFirstPointFixedLength
}
pi, qi := decodeFn(d, level, piCoder, qiCoder)
if ok := iter.next(); !ok && d.err == nil {
d.err = fmt.Errorf("ran out of faces at target %d", i)
return
}
target[i] = Point{facePiQitoXYZ(iter.curFace, pi, qi, level)}
}
numOffCenter := int(d.readUvarint())
if d.err != nil {
return
}
if numOffCenter > len(target) {
d.err = fmt.Errorf("numOffCenter = %d, should be at most len(target) = %d", numOffCenter, len(target))
return
}
for i := 0; i < numOffCenter; i++ {
idx := int(d.readUvarint())
if d.err != nil {
return
}
if idx >= len(target) {
d.err = fmt.Errorf("off center index = %d, should be < len(target) = %d", idx, len(target))
return
}
target[idx].X = d.readFloat64()
target[idx].Y = d.readFloat64()
target[idx].Z = d.readFloat64()
}
}
func decodeFirstPointFixedLength(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) {
bytesToRead := (level + 7) / 8 * 2
var interleaved uint64
for i := 0; i < bytesToRead; i++ {
rr := d.readUint8()
interleaved |= (uint64(rr) << uint(i*8))
}
piCoded, qiCoded := deinterleaveUint32(interleaved)
return uint32(piCoder.decode(int32(piCoded))), uint32(qiCoder.decode(int32(qiCoded)))
}
func zigzagEncode(x int32) uint32 {
return (uint32(x) << 1) ^ uint32(x>>31)
}
func zigzagDecode(x uint32) int32 {
return int32((x >> 1) ^ uint32((int32(x&1)<<31)>>31))
}
func decodePointCompressed(d *decoder, level int, piCoder, qiCoder *nthDerivativeCoder) (pi, qi uint32) {
interleavedZigZagEncodedDerivPiQi := d.readUvarint()
piZigzag, qiZigzag := deinterleaveUint32(interleavedZigZagEncodedDerivPiQi)
return uint32(piCoder.decode(zigzagDecode(piZigzag))), uint32(qiCoder.decode(zigzagDecode(qiZigzag)))
}
// We introduce a new coordinate system (pi, qi), which is (si, ti)
// with the bits that are constant for cells of that level shifted
// off to the right.
// si = round(s * 2^31)
// pi = si >> (31 - level)
// = floor(s * 2^level)
// If the point has been snapped to the level, the bits that are
// shifted off will be a 1 in the msb, then 0s after that, so the
// fractional part discarded by the cast is (close to) 0.5.
// stToPiQi returns the value transformed to the PiQi coordinate space.
func stToPiQi(s float64, level uint) uint32 {
return uint32(s * float64(int(1)<<level))
}
// siTiToPiQi returns the value transformed into the PiQi coordinate spade.
// encodeFirstPointFixedLength encodes the return value using level bits,
// so we clamp si to the range [0, 2**level - 1] before trying to encode
// it. This is okay because if si == maxSiTi, then it is not a cell center
// anyway and will be encoded separately as an off-center point.
func siTitoPiQi(siTi uint32, level int) uint32 {
s := uint(siTi)
const max = maxSiTi - 1
if s > max {
s = max
}
return uint32(s >> (maxLevel + 1 - uint(level)))
}
// piQiToST returns the value transformed to ST space.
func piQiToST(pi uint32, level int) float64 {
// We want to recover the position at the center of the cell. If the point
// was snapped to the center of the cell, then math.Modf(s * 2^level) == 0.5.
// Inverting STtoPiQi gives:
// s = (pi + 0.5) / 2^level.
return (float64(pi) + 0.5) / float64(int(1)<<uint(level))
}
func facePiQitoXYZ(face int, pi, qi uint32, level int) r3.Vector {
return faceUVToXYZ(face, stToUV(piQiToST(pi, level)), stToUV(piQiToST(qi, level))).Normalize()
}

1213
vendor/github.com/golang/geo/s2/polygon.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

589
vendor/github.com/golang/geo/s2/polyline.go generated vendored Normal file
View File

@ -0,0 +1,589 @@
// Copyright 2016 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"
"math"
"github.com/golang/geo/s1"
)
// Polyline represents a sequence of zero or more vertices connected by
// straight edges (geodesics). Edges of length 0 and 180 degrees are not
// allowed, i.e. adjacent vertices should not be identical or antipodal.
type Polyline []Point
// PolylineFromLatLngs creates a new Polyline from the given LatLngs.
func PolylineFromLatLngs(points []LatLng) *Polyline {
p := make(Polyline, len(points))
for k, v := range points {
p[k] = PointFromLatLng(v)
}
return &p
}
// Reverse reverses the order of the Polyline vertices.
func (p *Polyline) Reverse() {
for i := 0; i < len(*p)/2; i++ {
(*p)[i], (*p)[len(*p)-i-1] = (*p)[len(*p)-i-1], (*p)[i]
}
}
// Length returns the length of this Polyline.
func (p *Polyline) Length() s1.Angle {
var length s1.Angle
for i := 1; i < len(*p); i++ {
length += (*p)[i-1].Distance((*p)[i])
}
return length
}
// Centroid returns the true centroid of the polyline multiplied by the length of the
// polyline. The result is not unit length, so you may wish to normalize it.
//
// Scaling by the Polyline length makes it easy to compute the centroid
// of several Polylines (by simply adding up their centroids).
func (p *Polyline) Centroid() Point {
var centroid Point
for i := 1; i < len(*p); i++ {
// The centroid (multiplied by length) is a vector toward the midpoint
// of the edge, whose length is twice the sin of half the angle between
// the two vertices. Defining theta to be this angle, we have:
vSum := (*p)[i-1].Add((*p)[i].Vector) // Length == 2*cos(theta)
vDiff := (*p)[i-1].Sub((*p)[i].Vector) // Length == 2*sin(theta)
// Length == 2*sin(theta)
centroid = Point{centroid.Add(vSum.Mul(math.Sqrt(vDiff.Norm2() / vSum.Norm2())))}
}
return centroid
}
// Equal reports whether the given Polyline is exactly the same as this one.
func (p *Polyline) Equal(b *Polyline) bool {
if len(*p) != len(*b) {
return false
}
for i, v := range *p {
if v != (*b)[i] {
return false
}
}
return true
}
// ApproxEqual reports whether two polylines have the same number of vertices,
// and corresponding vertex pairs are separated by no more the standard margin.
func (p *Polyline) ApproxEqual(o *Polyline) bool {
return p.approxEqual(o, s1.Angle(epsilon))
}
// approxEqual reports whether two polylines are equal within the given margin.
func (p *Polyline) approxEqual(o *Polyline, maxError s1.Angle) bool {
if len(*p) != len(*o) {
return false
}
for offset, val := range *p {
if !val.approxEqual((*o)[offset], maxError) {
return false
}
}
return true
}
// CapBound returns the bounding Cap for this Polyline.
func (p *Polyline) CapBound() Cap {
return p.RectBound().CapBound()
}
// RectBound returns the bounding Rect for this Polyline.
func (p *Polyline) RectBound() Rect {
rb := NewRectBounder()
for _, v := range *p {
rb.AddPoint(v)
}
return rb.RectBound()
}
// ContainsCell reports whether this Polyline contains the given Cell. Always returns false
// because "containment" is not numerically well-defined except at the Polyline vertices.
func (p *Polyline) ContainsCell(cell Cell) bool {
return false
}
// IntersectsCell reports whether this Polyline intersects the given Cell.
func (p *Polyline) IntersectsCell(cell Cell) bool {
if len(*p) == 0 {
return false
}
// We only need to check whether the cell contains vertex 0 for correctness,
// but these tests are cheap compared to edge crossings so we might as well
// check all the vertices.
for _, v := range *p {
if cell.ContainsPoint(v) {
return true
}
}
cellVertices := []Point{
cell.Vertex(0),
cell.Vertex(1),
cell.Vertex(2),
cell.Vertex(3),
}
for j := 0; j < 4; j++ {
crosser := NewChainEdgeCrosser(cellVertices[j], cellVertices[(j+1)&3], (*p)[0])
for i := 1; i < len(*p); i++ {
if crosser.ChainCrossingSign((*p)[i]) != DoNotCross {
// There is a proper crossing, or two vertices were the same.
return true
}
}
}
return false
}
// ContainsPoint returns false since Polylines are not closed.
func (p *Polyline) ContainsPoint(point Point) bool {
return false
}
// CellUnionBound computes a covering of the Polyline.
func (p *Polyline) CellUnionBound() []CellID {
return p.CapBound().CellUnionBound()
}
// NumEdges returns the number of edges in this shape.
func (p *Polyline) NumEdges() int {
if len(*p) == 0 {
return 0
}
return len(*p) - 1
}
// Edge returns endpoints for the given edge index.
func (p *Polyline) Edge(i int) Edge {
return Edge{(*p)[i], (*p)[i+1]}
}
// ReferencePoint returns the default reference point with negative containment because Polylines are not closed.
func (p *Polyline) ReferencePoint() ReferencePoint {
return OriginReferencePoint(false)
}
// NumChains reports the number of contiguous edge chains in this Polyline.
func (p *Polyline) NumChains() int {
return minInt(1, p.NumEdges())
}
// Chain returns the i-th edge Chain in the Shape.
func (p *Polyline) Chain(chainID int) Chain {
return Chain{0, p.NumEdges()}
}
// ChainEdge returns the j-th edge of the i-th edge Chain.
func (p *Polyline) ChainEdge(chainID, offset int) Edge {
return Edge{(*p)[offset], (*p)[offset+1]}
}
// ChainPosition returns a pair (i, j) such that edgeID is the j-th edge
func (p *Polyline) ChainPosition(edgeID int) ChainPosition {
return ChainPosition{0, edgeID}
}
// Dimension returns the dimension of the geometry represented by this Polyline.
func (p *Polyline) Dimension() int { return 1 }
// IsEmpty reports whether this shape contains no points.
func (p *Polyline) IsEmpty() bool { return defaultShapeIsEmpty(p) }
// IsFull reports whether this shape contains all points on the sphere.
func (p *Polyline) IsFull() bool { return defaultShapeIsFull(p) }
func (p *Polyline) typeTag() typeTag { return typeTagPolyline }
func (p *Polyline) privateInterface() {}
// findEndVertex reports the maximal end index such that the line segment between
// the start index and this one such that the line segment between these two
// vertices passes within the given tolerance of all interior vertices, in order.
func findEndVertex(p Polyline, tolerance s1.Angle, index int) int {
// The basic idea is to keep track of the "pie wedge" of angles
// from the starting vertex such that a ray from the starting
// vertex at that angle will pass through the discs of radius
// tolerance centered around all vertices processed so far.
//
// First we define a coordinate frame for the tangent and normal
// spaces at the starting vertex. Essentially this means picking
// three orthonormal vectors X,Y,Z such that X and Y span the
// tangent plane at the starting vertex, and Z is up. We use
// the coordinate frame to define a mapping from 3D direction
// vectors to a one-dimensional ray angle in the range (-π,
// π]. The angle of a direction vector is computed by
// transforming it into the X,Y,Z basis, and then calculating
// atan2(y,x). This mapping allows us to represent a wedge of
// angles as a 1D interval. Since the interval wraps around, we
// represent it as an Interval, i.e. an interval on the unit
// circle.
origin := p[index]
frame := getFrame(origin)
// As we go along, we keep track of the current wedge of angles
// and the distance to the last vertex (which must be
// non-decreasing).
currentWedge := s1.FullInterval()
var lastDistance s1.Angle
for index++; index < len(p); index++ {
candidate := p[index]
distance := origin.Distance(candidate)
// We don't allow simplification to create edges longer than
// 90 degrees, to avoid numeric instability as lengths
// approach 180 degrees. We do need to allow for original
// edges longer than 90 degrees, though.
if distance > math.Pi/2 && lastDistance > 0 {
break
}
// Vertices must be in increasing order along the ray, except
// for the initial disc around the origin.
if distance < lastDistance && lastDistance > tolerance {
break
}
lastDistance = distance
// Points that are within the tolerance distance of the origin
// do not constrain the ray direction, so we can ignore them.
if distance <= tolerance {
continue
}
// If the current wedge of angles does not contain the angle
// to this vertex, then stop right now. Note that the wedge
// of possible ray angles is not necessarily empty yet, but we
// can't continue unless we are willing to backtrack to the
// last vertex that was contained within the wedge (since we
// don't create new vertices). This would be more complicated
// and also make the worst-case running time more than linear.
direction := toFrame(frame, candidate)
center := math.Atan2(direction.Y, direction.X)
if !currentWedge.Contains(center) {
break
}
// To determine how this vertex constrains the possible ray
// angles, consider the triangle ABC where A is the origin, B
// is the candidate vertex, and C is one of the two tangent
// points between A and the spherical cap of radius
// tolerance centered at B. Then from the spherical law of
// sines, sin(a)/sin(A) = sin(c)/sin(C), where a and c are
// the lengths of the edges opposite A and C. In our case C
// is a 90 degree angle, therefore A = asin(sin(a) / sin(c)).
// Angle A is the half-angle of the allowable wedge.
halfAngle := math.Asin(math.Sin(tolerance.Radians()) / math.Sin(distance.Radians()))
target := s1.IntervalFromPointPair(center, center).Expanded(halfAngle)
currentWedge = currentWedge.Intersection(target)
}
// We break out of the loop when we reach a vertex index that
// can't be included in the line segment, so back up by one
// vertex.
return index - 1
}
// SubsampleVertices returns a subsequence of vertex indices such that the
// polyline connecting these vertices is never further than the given tolerance from
// the original polyline. Provided the first and last vertices are distinct,
// they are always preserved; if they are not, the subsequence may contain
// only a single index.
//
// Some useful properties of the algorithm:
//
// - It runs in linear time.
//
// - The output always represents a valid polyline. In particular, adjacent
// output vertices are never identical or antipodal.
//
// - The method is not optimal, but it tends to produce 2-3% fewer
// vertices than the Douglas-Peucker algorithm with the same tolerance.
//
// - The output is parametrically equivalent to the original polyline to
// within the given tolerance. For example, if a polyline backtracks on
// itself and then proceeds onwards, the backtracking will be preserved
// (to within the given tolerance). This is different than the
// Douglas-Peucker algorithm which only guarantees geometric equivalence.
func (p *Polyline) SubsampleVertices(tolerance s1.Angle) []int {
var result []int
if len(*p) < 1 {
return result
}
result = append(result, 0)
clampedTolerance := s1.Angle(math.Max(tolerance.Radians(), 0))
for index := 0; index+1 < len(*p); {
nextIndex := findEndVertex(*p, clampedTolerance, index)
// Don't create duplicate adjacent vertices.
if (*p)[nextIndex] != (*p)[index] {
result = append(result, nextIndex)
}
index = nextIndex
}
return result
}
// Encode encodes the Polyline.
func (p Polyline) Encode(w io.Writer) error {
e := &encoder{w: w}
p.encode(e)
return e.err
}
func (p Polyline) encode(e *encoder) {
e.writeInt8(encodingVersion)
e.writeUint32(uint32(len(p)))
for _, v := range p {
e.writeFloat64(v.X)
e.writeFloat64(v.Y)
e.writeFloat64(v.Z)
}
}
// Decode decodes the polyline.
func (p *Polyline) Decode(r io.Reader) error {
d := decoder{r: asByteReader(r)}
p.decode(d)
return d.err
}
func (p *Polyline) decode(d decoder) {
version := d.readInt8()
if d.err != nil {
return
}
if int(version) != int(encodingVersion) {
d.err = fmt.Errorf("can't decode version %d; my version: %d", version, encodingVersion)
return
}
nvertices := d.readUint32()
if d.err != nil {
return
}
if nvertices > maxEncodedVertices {
d.err = fmt.Errorf("too many vertices (%d; max is %d)", nvertices, maxEncodedVertices)
return
}
*p = make([]Point, nvertices)
for i := range *p {
(*p)[i].X = d.readFloat64()
(*p)[i].Y = d.readFloat64()
(*p)[i].Z = d.readFloat64()
}
}
// Project returns a point on the polyline that is closest to the given point,
// and the index of the next vertex after the projected point. The
// value of that index is always in the range [1, len(polyline)].
// The polyline must not be empty.
func (p *Polyline) Project(point Point) (Point, int) {
if len(*p) == 1 {
// If there is only one vertex, it is always closest to any given point.
return (*p)[0], 1
}
// Initial value larger than any possible distance on the unit sphere.
minDist := 10 * s1.Radian
minIndex := -1
// Find the line segment in the polyline that is closest to the point given.
for i := 1; i < len(*p); i++ {
if dist := DistanceFromSegment(point, (*p)[i-1], (*p)[i]); dist < minDist {
minDist = dist
minIndex = i
}
}
// Compute the point on the segment found that is closest to the point given.
closest := Project(point, (*p)[minIndex-1], (*p)[minIndex])
if closest == (*p)[minIndex] {
minIndex++
}
return closest, minIndex
}
// IsOnRight reports whether the point given is on the right hand side of the
// polyline, using a naive definition of "right-hand-sideness" where the point
// is on the RHS of the polyline iff the point is on the RHS of the line segment
// in the polyline which it is closest to.
// The polyline must have at least 2 vertices.
func (p *Polyline) IsOnRight(point Point) bool {
// If the closest point C is an interior vertex of the polyline, let B and D
// be the previous and next vertices. The given point P is on the right of
// the polyline (locally) if B, P, D are ordered CCW around vertex C.
closest, next := p.Project(point)
if closest == (*p)[next-1] && next > 1 && next < len(*p) {
if point == (*p)[next-1] {
// Polyline vertices are not on the RHS.
return false
}
return OrderedCCW((*p)[next-2], point, (*p)[next], (*p)[next-1])
}
// Otherwise, the closest point C is incident to exactly one polyline edge.
// We test the point P against that edge.
if next == len(*p) {
next--
}
return Sign(point, (*p)[next], (*p)[next-1])
}
// Validate checks whether this is a valid polyline or not.
func (p *Polyline) Validate() error {
// All vertices must be unit length.
for i, pt := range *p {
if !pt.IsUnit() {
return fmt.Errorf("vertex %d is not unit length", i)
}
}
// Adjacent vertices must not be identical or antipodal.
for i := 1; i < len(*p); i++ {
prev, cur := (*p)[i-1], (*p)[i]
if prev == cur {
return fmt.Errorf("vertices %d and %d are identical", i-1, i)
}
if prev == (Point{cur.Mul(-1)}) {
return fmt.Errorf("vertices %d and %d are antipodal", i-1, i)
}
}
return nil
}
// Intersects reports whether this polyline intersects the given polyline. If
// the polylines share a vertex they are considered to be intersecting. When a
// polyline endpoint is the only intersection with the other polyline, the
// function may return true or false arbitrarily.
//
// The running time is quadratic in the number of vertices.
func (p *Polyline) Intersects(o *Polyline) bool {
if len(*p) == 0 || len(*o) == 0 {
return false
}
if !p.RectBound().Intersects(o.RectBound()) {
return false
}
// TODO(roberts): Use ShapeIndex here.
for i := 1; i < len(*p); i++ {
crosser := NewChainEdgeCrosser((*p)[i-1], (*p)[i], (*o)[0])
for j := 1; j < len(*o); j++ {
if crosser.ChainCrossingSign((*o)[j]) != DoNotCross {
return true
}
}
}
return false
}
// Interpolate returns the point whose distance from vertex 0 along the polyline is
// the given fraction of the polyline's total length, and the index of
// the next vertex after the interpolated point P. Fractions less than zero
// or greater than one are clamped. The return value is unit length. The cost of
// this function is currently linear in the number of vertices.
//
// This method allows the caller to easily construct a given suffix of the
// polyline by concatenating P with the polyline vertices starting at that next
// vertex. Note that P is guaranteed to be different than the point at the next
// vertex, so this will never result in a duplicate vertex.
//
// The polyline must not be empty. Note that if fraction >= 1.0, then the next
// vertex will be set to len(p) (indicating that no vertices from the polyline
// need to be appended). The value of the next vertex is always between 1 and
// len(p).
//
// This method can also be used to construct a prefix of the polyline, by
// taking the polyline vertices up to next vertex-1 and appending the
// returned point P if it is different from the last vertex (since in this
// case there is no guarantee of distinctness).
func (p *Polyline) Interpolate(fraction float64) (Point, int) {
// We intentionally let the (fraction >= 1) case fall through, since
// we need to handle it in the loop below in any case because of
// possible roundoff errors.
if fraction <= 0 {
return (*p)[0], 1
}
target := s1.Angle(fraction) * p.Length()
for i := 1; i < len(*p); i++ {
length := (*p)[i-1].Distance((*p)[i])
if target < length {
// This interpolates with respect to arc length rather than
// straight-line distance, and produces a unit-length result.
result := InterpolateAtDistance(target, (*p)[i-1], (*p)[i])
// It is possible that (result == vertex(i)) due to rounding errors.
if result == (*p)[i] {
return result, i + 1
}
return result, i
}
target -= length
}
return (*p)[len(*p)-1], len(*p)
}
// Uninterpolate is the inverse operation of Interpolate. Given a point on the
// polyline, it returns the ratio of the distance to the point from the
// beginning of the polyline over the length of the polyline. The return
// value is always betwen 0 and 1 inclusive.
//
// The polyline should not be empty. If it has fewer than 2 vertices, the
// return value is zero.
func (p *Polyline) Uninterpolate(point Point, nextVertex int) float64 {
if len(*p) < 2 {
return 0
}
var sum s1.Angle
for i := 1; i < nextVertex; i++ {
sum += (*p)[i-1].Distance((*p)[i])
}
lengthToPoint := sum + (*p)[nextVertex-1].Distance(point)
for i := nextVertex; i < len(*p); i++ {
sum += (*p)[i-1].Distance((*p)[i])
}
// The ratio can be greater than 1.0 due to rounding errors or because the
// point is not exactly on the polyline.
return minFloat64(1.0, float64(lengthToPoint/sum))
}
// TODO(roberts): Differences from C++.
// NearlyCoversPolyline
// InitToSnapped
// InitToSimplified
// SnapLevel
// encode/decode compressed

53
vendor/github.com/golang/geo/s2/polyline_measures.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2018 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
// This file defines various measures for polylines on the sphere. These are
// low-level methods that work directly with arrays of Points. They are used to
// implement the methods in various other measures files.
import (
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// polylineLength returns the length of the given Polyline.
// It returns 0 for polylines with fewer than two vertices.
func polylineLength(p []Point) s1.Angle {
var length s1.Angle
for i := 1; i < len(p); i++ {
length += p[i-1].Distance(p[i])
}
return length
}
// polylineCentroid returns the true centroid of the polyline multiplied by the
// length of the polyline. The result is not unit length, so you may wish to
// normalize it.
//
// Scaling by the Polyline length makes it easy to compute the centroid
// of several Polylines (by simply adding up their centroids).
//
// Note that for degenerate Polylines (e.g., AA) this returns Point(0, 0, 0).
// (This answer is correct; the result of this function is a line integral over
// the polyline, whose value is always zero if the polyline is degenerate.)
func polylineCentroid(p []Point) Point {
var centroid r3.Vector
for i := 1; i < len(p); i++ {
centroid = centroid.Add(EdgeTrueCentroid(p[i-1], p[i]).Vector)
}
return Point{centroid}
}

701
vendor/github.com/golang/geo/s2/predicates.go generated vendored Normal file
View File

@ -0,0 +1,701 @@
// Copyright 2016 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
// This file contains various predicates that are guaranteed to produce
// correct, consistent results. They are also relatively efficient. This is
// achieved by computing conservative error bounds and falling back to high
// precision or even exact arithmetic when the result is uncertain. Such
// predicates are useful in implementing robust algorithms.
//
// See also EdgeCrosser, which implements various exact
// edge-crossing predicates more efficiently than can be done here.
import (
"math"
"math/big"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
const (
// If any other machine architectures need to be suppported, these next three
// values will need to be updated.
// epsilon is a small number that represents a reasonable level of noise between two
// values that can be considered to be equal.
epsilon = 1e-15
// dblEpsilon is a smaller number for values that require more precision.
// This is the C++ DBL_EPSILON equivalent.
dblEpsilon = 2.220446049250313e-16
// dblError is the C++ value for S2 rounding_epsilon().
dblError = 1.110223024625156e-16
// maxDeterminantError is the maximum error in computing (AxB).C where all vectors
// are unit length. Using standard inequalities, it can be shown that
//
// fl(AxB) = AxB + D where |D| <= (|AxB| + (2/sqrt(3))*|A|*|B|) * e
//
// where "fl()" denotes a calculation done in floating-point arithmetic,
// |x| denotes either absolute value or the L2-norm as appropriate, and
// e is a reasonably small value near the noise level of floating point
// number accuracy. Similarly,
//
// fl(B.C) = B.C + d where |d| <= (|B.C| + 2*|B|*|C|) * e .
//
// Applying these bounds to the unit-length vectors A,B,C and neglecting
// relative error (which does not affect the sign of the result), we get
//
// fl((AxB).C) = (AxB).C + d where |d| <= (3 + 2/sqrt(3)) * e
maxDeterminantError = 1.8274 * dblEpsilon
// detErrorMultiplier is the factor to scale the magnitudes by when checking
// for the sign of set of points with certainty. Using a similar technique to
// the one used for maxDeterminantError, the error is at most:
//
// |d| <= (3 + 6/sqrt(3)) * |A-C| * |B-C| * e
//
// If the determinant magnitude is larger than this value then we know
// its sign with certainty.
detErrorMultiplier = 3.2321 * dblEpsilon
)
// Direction is an indication of the ordering of a set of points.
type Direction int
// These are the three options for the direction of a set of points.
const (
Clockwise Direction = -1
Indeterminate Direction = 0
CounterClockwise Direction = 1
)
// newBigFloat constructs a new big.Float with maximum precision.
func newBigFloat() *big.Float { return new(big.Float).SetPrec(big.MaxPrec) }
// 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 Sign(a, b, c Point) bool {
// NOTE(dnadasi): In the C++ API the equivalent method here was known as "SimpleSign".
// We compute the signed volume of the parallelepiped ABC. The usual
// formula for this is (A B) · C, but we compute it here using (C A) · B
// in order to ensure that ABC and CBA are not both CCW. This follows
// from the following identities (which are true numerically, not just
// mathematically):
//
// (1) x y == -(y x)
// (2) -x · y == -(x · y)
return c.Cross(a.Vector).Dot(b.Vector) > 0
}
// 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.
func RobustSign(a, b, c Point) Direction {
sign := triageSign(a, b, c)
if sign == Indeterminate {
sign = expensiveSign(a, b, c)
}
return sign
}
// stableSign reports the direction sign of the points in a numerically stable way.
// Unlike triageSign, this method can usually compute the correct determinant sign
// even when all three points are as collinear as possible. For example if three
// points are spaced 1km apart along a random line on the Earth's surface using
// the nearest representable points, there is only a 0.4% chance that this method
// will not be able to find the determinant sign. The probability of failure
// decreases as the points get closer together; if the collinear points are 1 meter
// apart, the failure rate drops to 0.0004%.
//
// This method could be extended to also handle nearly-antipodal points, but antipodal
// points are rare in practice so it seems better to simply fall back to
// exact arithmetic in that case.
func stableSign(a, b, c Point) Direction {
ab := b.Sub(a.Vector)
ab2 := ab.Norm2()
bc := c.Sub(b.Vector)
bc2 := bc.Norm2()
ca := a.Sub(c.Vector)
ca2 := ca.Norm2()
// Now compute the determinant ((A-C)x(B-C)).C, where the vertices have been
// cyclically permuted if necessary so that AB is the longest edge. (This
// minimizes the magnitude of cross product.) At the same time we also
// compute the maximum error in the determinant.
// The two shortest edges, pointing away from their common point.
var e1, e2, op r3.Vector
if ab2 >= bc2 && ab2 >= ca2 {
// AB is the longest edge.
e1, e2, op = ca, bc, c.Vector
} else if bc2 >= ca2 {
// BC is the longest edge.
e1, e2, op = ab, ca, a.Vector
} else {
// CA is the longest edge.
e1, e2, op = bc, ab, b.Vector
}
det := -e1.Cross(e2).Dot(op)
maxErr := detErrorMultiplier * math.Sqrt(e1.Norm2()*e2.Norm2())
// If the determinant isn't zero, within maxErr, we know definitively the point ordering.
if det > maxErr {
return CounterClockwise
}
if det < -maxErr {
return Clockwise
}
return Indeterminate
}
// triageSign returns the direction sign of the points. It returns Indeterminate if two
// points are identical or the result is uncertain. Uncertain cases can be resolved, if
// desired, by calling expensiveSign.
//
// The purpose of this method is to allow additional cheap tests to be done without
// calling expensiveSign.
func triageSign(a, b, c Point) Direction {
det := a.Cross(b.Vector).Dot(c.Vector)
if det > maxDeterminantError {
return CounterClockwise
}
if det < -maxDeterminantError {
return Clockwise
}
return Indeterminate
}
// expensiveSign reports the direction sign of the points. It returns Indeterminate
// if two of the input points are the same. It uses multiple-precision arithmetic
// to ensure that its results are always self-consistent.
func expensiveSign(a, b, c Point) Direction {
// Return Indeterminate if and only if two points are the same.
// This ensures RobustSign(a,b,c) == Indeterminate if and only if a == b, b == c, or c == a.
// ie. Property 1 of RobustSign.
if a == b || b == c || c == a {
return Indeterminate
}
// Next we try recomputing the determinant still using floating-point
// arithmetic but in a more precise way. This is more expensive than the
// simple calculation done by triageSign, but it is still *much* cheaper
// than using arbitrary-precision arithmetic. This optimization is able to
// compute the correct determinant sign in virtually all cases except when
// the three points are truly collinear (e.g., three points on the equator).
detSign := stableSign(a, b, c)
if detSign != Indeterminate {
return detSign
}
// Otherwise fall back to exact arithmetic and symbolic permutations.
return exactSign(a, b, c, true)
}
// exactSign reports the direction sign of the points computed using high-precision
// arithmetic and/or symbolic perturbations.
func exactSign(a, b, c Point, perturb bool) Direction {
// Sort the three points in lexicographic order, keeping track of the sign
// of the permutation. (Each exchange inverts the sign of the determinant.)
permSign := CounterClockwise
pa := &a
pb := &b
pc := &c
if pa.Cmp(pb.Vector) > 0 {
pa, pb = pb, pa
permSign = -permSign
}
if pb.Cmp(pc.Vector) > 0 {
pb, pc = pc, pb
permSign = -permSign
}
if pa.Cmp(pb.Vector) > 0 {
pa, pb = pb, pa
permSign = -permSign
}
// Construct multiple-precision versions of the sorted points and compute
// their precise 3x3 determinant.
xa := r3.PreciseVectorFromVector(pa.Vector)
xb := r3.PreciseVectorFromVector(pb.Vector)
xc := r3.PreciseVectorFromVector(pc.Vector)
xbCrossXc := xb.Cross(xc)
det := xa.Dot(xbCrossXc)
// The precision of big.Float is high enough that the result should always
// be exact enough (no rounding was performed).
// If the exact determinant is non-zero, we're done.
detSign := Direction(det.Sign())
if detSign == Indeterminate && perturb {
// Otherwise, we need to resort to symbolic perturbations to resolve the
// sign of the determinant.
detSign = symbolicallyPerturbedSign(xa, xb, xc, xbCrossXc)
}
return permSign * detSign
}
// symbolicallyPerturbedSign reports the sign of the determinant of three points
// A, B, C under a model where every possible Point is slightly perturbed by
// a unique infinitesmal amount such that no three perturbed points are
// collinear and no four points are coplanar. The perturbations are so small
// that they do not change the sign of any determinant that was non-zero
// before the perturbations, and therefore can be safely ignored unless the
// determinant of three points is exactly zero (using multiple-precision
// arithmetic). This returns CounterClockwise or Clockwise according to the
// sign of the determinant after the symbolic perturbations are taken into account.
//
// Since the symbolic perturbation of a given point is fixed (i.e., the
// perturbation is the same for all calls to this method and does not depend
// on the other two arguments), the results of this method are always
// self-consistent. It will never return results that would correspond to an
// impossible configuration of non-degenerate points.
//
// This requires that the 3x3 determinant of A, B, C must be exactly zero.
// And the points must be distinct, with A < B < C in lexicographic order.
//
// Reference:
// "Simulation of Simplicity" (Edelsbrunner and Muecke, ACM Transactions on
// Graphics, 1990).
//
func symbolicallyPerturbedSign(a, b, c, bCrossC r3.PreciseVector) Direction {
// This method requires that the points are sorted in lexicographically
// increasing order. This is because every possible Point has its own
// symbolic perturbation such that if A < B then the symbolic perturbation
// for A is much larger than the perturbation for B.
//
// Alternatively, we could sort the points in this method and keep track of
// the sign of the permutation, but it is more efficient to do this before
// converting the inputs to the multi-precision representation, and this
// also lets us re-use the result of the cross product B x C.
//
// Every input coordinate x[i] is assigned a symbolic perturbation dx[i].
// We then compute the sign of the determinant of the perturbed points,
// i.e.
// | a.X+da.X a.Y+da.Y a.Z+da.Z |
// | b.X+db.X b.Y+db.Y b.Z+db.Z |
// | c.X+dc.X c.Y+dc.Y c.Z+dc.Z |
//
// The perturbations are chosen such that
//
// da.Z > da.Y > da.X > db.Z > db.Y > db.X > dc.Z > dc.Y > dc.X
//
// where each perturbation is so much smaller than the previous one that we
// don't even need to consider it unless the coefficients of all previous
// perturbations are zero. In fact, it is so small that we don't need to
// consider it unless the coefficient of all products of the previous
// perturbations are zero. For example, we don't need to consider the
// coefficient of db.Y unless the coefficient of db.Z *da.X is zero.
//
// The follow code simply enumerates the coefficients of the perturbations
// (and products of perturbations) that appear in the determinant above, in
// order of decreasing perturbation magnitude. The first non-zero
// coefficient determines the sign of the result. The easiest way to
// enumerate the coefficients in the correct order is to pretend that each
// perturbation is some tiny value "eps" raised to a power of two:
//
// eps** 1 2 4 8 16 32 64 128 256
// da.Z da.Y da.X db.Z db.Y db.X dc.Z dc.Y dc.X
//
// Essentially we can then just count in binary and test the corresponding
// subset of perturbations at each step. So for example, we must test the
// coefficient of db.Z*da.X before db.Y because eps**12 > eps**16.
//
// Of course, not all products of these perturbations appear in the
// determinant above, since the determinant only contains the products of
// elements in distinct rows and columns. Thus we don't need to consider
// da.Z*da.Y, db.Y *da.Y, etc. Furthermore, sometimes different pairs of
// perturbations have the same coefficient in the determinant; for example,
// da.Y*db.X and db.Y*da.X have the same coefficient (c.Z). Therefore
// we only need to test this coefficient the first time we encounter it in
// the binary order above (which will be db.Y*da.X).
//
// The sequence of tests below also appears in Table 4-ii of the paper
// referenced above, if you just want to look it up, with the following
// translations: [a,b,c] -> [i,j,k] and [0,1,2] -> [1,2,3]. Also note that
// some of the signs are different because the opposite cross product is
// used (e.g., B x C rather than C x B).
detSign := bCrossC.Z.Sign() // da.Z
if detSign != 0 {
return Direction(detSign)
}
detSign = bCrossC.Y.Sign() // da.Y
if detSign != 0 {
return Direction(detSign)
}
detSign = bCrossC.X.Sign() // da.X
if detSign != 0 {
return Direction(detSign)
}
detSign = newBigFloat().Sub(newBigFloat().Mul(c.X, a.Y), newBigFloat().Mul(c.Y, a.X)).Sign() // db.Z
if detSign != 0 {
return Direction(detSign)
}
detSign = c.X.Sign() // db.Z * da.Y
if detSign != 0 {
return Direction(detSign)
}
detSign = -(c.Y.Sign()) // db.Z * da.X
if detSign != 0 {
return Direction(detSign)
}
detSign = newBigFloat().Sub(newBigFloat().Mul(c.Z, a.X), newBigFloat().Mul(c.X, a.Z)).Sign() // db.Y
if detSign != 0 {
return Direction(detSign)
}
detSign = c.Z.Sign() // db.Y * da.X
if detSign != 0 {
return Direction(detSign)
}
// The following test is listed in the paper, but it is redundant because
// the previous tests guarantee that C == (0, 0, 0).
// (c.Y*a.Z - c.Z*a.Y).Sign() // db.X
detSign = newBigFloat().Sub(newBigFloat().Mul(a.X, b.Y), newBigFloat().Mul(a.Y, b.X)).Sign() // dc.Z
if detSign != 0 {
return Direction(detSign)
}
detSign = -(b.X.Sign()) // dc.Z * da.Y
if detSign != 0 {
return Direction(detSign)
}
detSign = b.Y.Sign() // dc.Z * da.X
if detSign != 0 {
return Direction(detSign)
}
detSign = a.X.Sign() // dc.Z * db.Y
if detSign != 0 {
return Direction(detSign)
}
return CounterClockwise // dc.Z * db.Y * da.X
}
// CompareDistances returns -1, 0, or +1 according to whether AX < BX, A == B,
// or AX > BX respectively. Distances are measured with respect to the positions
// of X, A, and B as though they were reprojected to lie exactly on the surface of
// the unit sphere. Furthermore, this method uses symbolic perturbations to
// ensure that the result is non-zero whenever A != B, even when AX == BX
// exactly, or even when A and B project to the same point on the sphere.
// Such results are guaranteed to be self-consistent, i.e. if AB < BC and
// BC < AC, then AB < AC.
func CompareDistances(x, a, b Point) int {
// We start by comparing distances using dot products (i.e., cosine of the
// angle), because (1) this is the cheapest technique, and (2) it is valid
// over the entire range of possible angles. (We can only use the sin^2
// technique if both angles are less than 90 degrees or both angles are
// greater than 90 degrees.)
sign := triageCompareCosDistances(x, a, b)
if sign != 0 {
return sign
}
// Optimization for (a == b) to avoid falling back to exact arithmetic.
if a == b {
return 0
}
// It is much better numerically to compare distances using cos(angle) if
// the distances are near 90 degrees and sin^2(angle) if the distances are
// near 0 or 180 degrees. We only need to check one of the two angles when
// making this decision because the fact that the test above failed means
// that angles "a" and "b" are very close together.
cosAX := a.Dot(x.Vector)
if cosAX > 1/math.Sqrt2 {
// Angles < 45 degrees.
sign = triageCompareSin2Distances(x, a, b)
} else if cosAX < -1/math.Sqrt2 {
// Angles > 135 degrees. sin^2(angle) is decreasing in this range.
sign = -triageCompareSin2Distances(x, a, b)
}
// C++ adds an additional check here using 80-bit floats.
// This is skipped in Go because we only have 32 and 64 bit floats.
if sign != 0 {
return sign
}
sign = exactCompareDistances(r3.PreciseVectorFromVector(x.Vector), r3.PreciseVectorFromVector(a.Vector), r3.PreciseVectorFromVector(b.Vector))
if sign != 0 {
return sign
}
return symbolicCompareDistances(x, a, b)
}
// cosDistance returns cos(XY) where XY is the angle between X and Y, and the
// maximum error amount in the result. This requires X and Y be normalized.
func cosDistance(x, y Point) (cos, err float64) {
cos = x.Dot(y.Vector)
return cos, 9.5*dblError*math.Abs(cos) + 1.5*dblError
}
// sin2Distance returns sin**2(XY), where XY is the angle between X and Y,
// and the maximum error amount in the result. This requires X and Y be normalized.
func sin2Distance(x, y Point) (sin2, err float64) {
// The (x-y).Cross(x+y) trick eliminates almost all of error due to x
// and y being not quite unit length. This method is extremely accurate
// for small distances; the *relative* error in the result is O(dblError) for
// distances as small as dblError.
n := x.Sub(y.Vector).Cross(x.Add(y.Vector))
sin2 = 0.25 * n.Norm2()
err = ((21+4*math.Sqrt(3))*dblError*sin2 +
32*math.Sqrt(3)*dblError*dblError*math.Sqrt(sin2) +
768*dblError*dblError*dblError*dblError)
return sin2, err
}
// triageCompareCosDistances returns -1, 0, or +1 according to whether AX < BX,
// A == B, or AX > BX by comparing the distances between them using cosDistance.
func triageCompareCosDistances(x, a, b Point) int {
cosAX, cosAXerror := cosDistance(a, x)
cosBX, cosBXerror := cosDistance(b, x)
diff := cosAX - cosBX
err := cosAXerror + cosBXerror
if diff > err {
return -1
}
if diff < -err {
return 1
}
return 0
}
// triageCompareSin2Distances returns -1, 0, or +1 according to whether AX < BX,
// A == B, or AX > BX by comparing the distances between them using sin2Distance.
func triageCompareSin2Distances(x, a, b Point) int {
sin2AX, sin2AXerror := sin2Distance(a, x)
sin2BX, sin2BXerror := sin2Distance(b, x)
diff := sin2AX - sin2BX
err := sin2AXerror + sin2BXerror
if diff > err {
return 1
}
if diff < -err {
return -1
}
return 0
}
// exactCompareDistances returns -1, 0, or 1 after comparing using the values as
// PreciseVectors.
func exactCompareDistances(x, a, b r3.PreciseVector) int {
// This code produces the same result as though all points were reprojected
// to lie exactly on the surface of the unit sphere. It is based on testing
// whether x.Dot(a.Normalize()) < x.Dot(b.Normalize()), reformulated
// so that it can be evaluated using exact arithmetic.
cosAX := x.Dot(a)
cosBX := x.Dot(b)
// If the two values have different signs, we need to handle that case now
// before squaring them below.
aSign := cosAX.Sign()
bSign := cosBX.Sign()
if aSign != bSign {
// If cos(AX) > cos(BX), then AX < BX.
if aSign > bSign {
return -1
}
return 1
}
cosAX2 := newBigFloat().Mul(cosAX, cosAX)
cosBX2 := newBigFloat().Mul(cosBX, cosBX)
cmp := newBigFloat().Sub(cosBX2.Mul(cosBX2, a.Norm2()), cosAX2.Mul(cosAX2, b.Norm2()))
return aSign * cmp.Sign()
}
// symbolicCompareDistances returns -1, 0, or +1 given three points such that AX == BX
// (exactly) according to whether AX < BX, AX == BX, or AX > BX after symbolic
// perturbations are taken into account.
func symbolicCompareDistances(x, a, b Point) int {
// Our symbolic perturbation strategy is based on the following model.
// Similar to "simulation of simplicity", we assign a perturbation to every
// point such that if A < B, then the symbolic perturbation for A is much,
// much larger than the symbolic perturbation for B. We imagine that
// rather than projecting every point to lie exactly on the unit sphere,
// instead each point is positioned on its own tiny pedestal that raises it
// just off the surface of the unit sphere. This means that the distance AX
// is actually the true distance AX plus the (symbolic) heights of the
// pedestals for A and X. The pedestals are infinitesmally thin, so they do
// not affect distance measurements except at the two endpoints. If several
// points project to exactly the same point on the unit sphere, we imagine
// that they are placed on separate pedestals placed close together, where
// the distance between pedestals is much, much less than the height of any
// pedestal. (There are a finite number of Points, and therefore a finite
// number of pedestals, so this is possible.)
//
// If A < B, then A is on a higher pedestal than B, and therefore AX > BX.
switch a.Cmp(b.Vector) {
case -1:
return 1
case 1:
return -1
default:
return 0
}
}
var (
// ca45Degrees is a predefined ChordAngle representing (approximately) 45 degrees.
ca45Degrees = s1.ChordAngleFromSquaredLength(2 - math.Sqrt2)
)
// CompareDistance returns -1, 0, or +1 according to whether the distance XY is
// respectively less than, equal to, or greater than the provided chord angle. Distances are measured
// with respect to the positions of all points as though they are projected to lie
// exactly on the surface of the unit sphere.
func CompareDistance(x, y Point, r s1.ChordAngle) int {
// As with CompareDistances, we start by comparing dot products because
// the sin^2 method is only valid when the distance XY and the limit "r" are
// both less than 90 degrees.
sign := triageCompareCosDistance(x, y, float64(r))
if sign != 0 {
return sign
}
// Unlike with CompareDistances, it's not worth using the sin^2 method
// when the distance limit is near 180 degrees because the ChordAngle
// representation itself has has a rounding error of up to 2e-8 radians for
// distances near 180 degrees.
if r < ca45Degrees {
sign = triageCompareSin2Distance(x, y, float64(r))
if sign != 0 {
return sign
}
}
return exactCompareDistance(r3.PreciseVectorFromVector(x.Vector), r3.PreciseVectorFromVector(y.Vector), big.NewFloat(float64(r)).SetPrec(big.MaxPrec))
}
// triageCompareCosDistance returns -1, 0, or +1 according to whether the distance XY is
// less than, equal to, or greater than r2 respectively using cos distance.
func triageCompareCosDistance(x, y Point, r2 float64) int {
cosXY, cosXYError := cosDistance(x, y)
cosR := 1.0 - 0.5*r2
cosRError := 2.0 * dblError * cosR
diff := cosXY - cosR
err := cosXYError + cosRError
if diff > err {
return -1
}
if diff < -err {
return 1
}
return 0
}
// triageCompareSin2Distance returns -1, 0, or +1 according to whether the distance XY is
// less than, equal to, or greater than r2 respectively using sin^2 distance.
func triageCompareSin2Distance(x, y Point, r2 float64) int {
// Only valid for distance limits < 90 degrees.
sin2XY, sin2XYError := sin2Distance(x, y)
sin2R := r2 * (1.0 - 0.25*r2)
sin2RError := 3.0 * dblError * sin2R
diff := sin2XY - sin2R
err := sin2XYError + sin2RError
if diff > err {
return 1
}
if diff < -err {
return -1
}
return 0
}
var (
bigOne = big.NewFloat(1.0).SetPrec(big.MaxPrec)
bigHalf = big.NewFloat(0.5).SetPrec(big.MaxPrec)
)
// exactCompareDistance returns -1, 0, or +1 after comparing using PreciseVectors.
func exactCompareDistance(x, y r3.PreciseVector, r2 *big.Float) int {
// This code produces the same result as though all points were reprojected
// to lie exactly on the surface of the unit sphere. It is based on
// comparing the cosine of the angle XY (when both points are projected to
// lie exactly on the sphere) to the given threshold.
cosXY := x.Dot(y)
cosR := newBigFloat().Sub(bigOne, newBigFloat().Mul(bigHalf, r2))
// If the two values have different signs, we need to handle that case now
// before squaring them below.
xySign := cosXY.Sign()
rSign := cosR.Sign()
if xySign != rSign {
if xySign > rSign {
return -1
}
return 1 // If cos(XY) > cos(r), then XY < r.
}
cmp := newBigFloat().Sub(
newBigFloat().Mul(
newBigFloat().Mul(cosR, cosR), newBigFloat().Mul(x.Norm2(), y.Norm2())),
newBigFloat().Mul(cosXY, cosXY))
return xySign * cmp.Sign()
}
// TODO(roberts): Differences from C++
// CompareEdgeDistance
// CompareEdgeDirections
// EdgeCircumcenterSign
// GetVoronoiSiteExclusion
// GetClosestVertex
// TriageCompareLineSin2Distance
// TriageCompareLineCos2Distance
// TriageCompareLineDistance
// TriageCompareEdgeDistance
// ExactCompareLineDistance
// ExactCompareEdgeDistance
// TriageCompareEdgeDirections
// ExactCompareEdgeDirections
// ArePointsAntipodal
// ArePointsLinearlyDependent
// GetCircumcenter
// TriageEdgeCircumcenterSign
// ExactEdgeCircumcenterSign
// UnperturbedSign
// SymbolicEdgeCircumcenterSign
// ExactVoronoiSiteExclusion

241
vendor/github.com/golang/geo/s2/projections.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
// Copyright 2018 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 (
"math"
"github.com/golang/geo/r2"
"github.com/golang/geo/s1"
)
// Projection defines an interface for different ways of mapping between s2 and r2 Points.
// It can also define the coordinate wrapping behavior along each axis.
type Projection interface {
// Project converts a point on the sphere to a projected 2D point.
Project(p Point) r2.Point
// Unproject converts a projected 2D point to a point on the sphere.
//
// If wrapping is defined for a given axis (see below), then this method
// should accept any real number for the corresponding coordinate.
Unproject(p r2.Point) Point
// FromLatLng is a convenience function equivalent to Project(LatLngToPoint(ll)),
// but the implementation is more efficient.
FromLatLng(ll LatLng) r2.Point
// ToLatLng is a convenience function equivalent to LatLngFromPoint(Unproject(p)),
// but the implementation is more efficient.
ToLatLng(p r2.Point) LatLng
// Interpolate returns the point obtained by interpolating the given
// fraction of the distance along the line from A to B.
// Fractions < 0 or > 1 result in extrapolation instead.
Interpolate(f float64, a, b r2.Point) r2.Point
// WrapDistance reports the coordinate wrapping distance along each axis.
// If this value is non-zero for a given axis, the coordinates are assumed
// to "wrap" with the given period. For example, if WrapDistance.Y == 360
// then (x, y) and (x, y + 360) should map to the same Point.
//
// This information is used to ensure that edges takes the shortest path
// between two given points. For example, if coordinates represent
// (latitude, longitude) pairs in degrees and WrapDistance().Y == 360,
// then the edge (5:179, 5:-179) would be interpreted as spanning 2 degrees
// of longitude rather than 358 degrees.
//
// If a given axis does not wrap, its WrapDistance should be set to zero.
WrapDistance() r2.Point
// WrapDestination that wraps the coordinates of B if necessary in order to
// obtain the shortest edge AB. For example, suppose that A = [170, 20],
// B = [-170, 20], and the projection wraps so that [x, y] == [x + 360, y].
// Then this function would return [190, 20] for point B (reducing the edge
// length in the "x" direction from 340 to 20).
WrapDestination(a, b r2.Point) r2.Point
// We do not support implementations of this interface outside this package.
privateInterface()
}
// PlateCarreeProjection defines the "plate carree" (square plate) projection,
// which converts points on the sphere to (longitude, latitude) pairs.
// Coordinates can be scaled so that they represent radians, degrees, etc, but
// the projection is always centered around (latitude=0, longitude=0).
//
// Note that (x, y) coordinates are backwards compared to the usual (latitude,
// longitude) ordering, in order to match the usual convention for graphs in
// which "x" is horizontal and "y" is vertical.
type PlateCarreeProjection struct {
xWrap float64
toRadians float64 // Multiplier to convert coordinates to radians.
fromRadians float64 // Multiplier to convert coordinates from radians.
}
// NewPlateCarreeProjection constructs a plate carree projection where the
// x-coordinates (lng) span [-xScale, xScale] and the y coordinates (lat)
// span [-xScale/2, xScale/2]. For example if xScale==180 then the x
// range is [-180, 180] and the y range is [-90, 90].
//
// By default coordinates are expressed in radians, i.e. the x range is
// [-Pi, Pi] and the y range is [-Pi/2, Pi/2].
func NewPlateCarreeProjection(xScale float64) Projection {
return &PlateCarreeProjection{
xWrap: 2 * xScale,
toRadians: math.Pi / xScale,
fromRadians: xScale / math.Pi,
}
}
// Project converts a point on the sphere to a projected 2D point.
func (p *PlateCarreeProjection) Project(pt Point) r2.Point {
return p.FromLatLng(LatLngFromPoint(pt))
}
// Unproject converts a projected 2D point to a point on the sphere.
func (p *PlateCarreeProjection) Unproject(pt r2.Point) Point {
return PointFromLatLng(p.ToLatLng(pt))
}
// FromLatLng returns the LatLng projected into an R2 Point.
func (p *PlateCarreeProjection) FromLatLng(ll LatLng) r2.Point {
return r2.Point{
X: p.fromRadians * ll.Lng.Radians(),
Y: p.fromRadians * ll.Lat.Radians(),
}
}
// ToLatLng returns the LatLng projected from the given R2 Point.
func (p *PlateCarreeProjection) ToLatLng(pt r2.Point) LatLng {
return LatLng{
Lat: s1.Angle(p.toRadians * pt.Y),
Lng: s1.Angle(p.toRadians * math.Remainder(pt.X, p.xWrap)),
}
}
// Interpolate returns the point obtained by interpolating the given
// fraction of the distance along the line from A to B.
func (p *PlateCarreeProjection) Interpolate(f float64, a, b r2.Point) r2.Point {
return a.Mul(1 - f).Add(b.Mul(f))
}
// WrapDistance reports the coordinate wrapping distance along each axis.
func (p *PlateCarreeProjection) WrapDistance() r2.Point {
return r2.Point{p.xWrap, 0}
}
// WrapDestination wraps the points if needed to get the shortest edge.
func (p *PlateCarreeProjection) WrapDestination(a, b r2.Point) r2.Point {
return wrapDestination(a, b, p.WrapDistance)
}
func (p *PlateCarreeProjection) privateInterface() {}
// MercatorProjection defines the spherical Mercator projection. Google Maps
// uses this projection together with WGS84 coordinates, in which case it is
// known as the "Web Mercator" projection (see Wikipedia). This class makes
// no assumptions regarding the coordinate system of its input points, but
// simply applies the spherical Mercator projection to them.
//
// The Mercator projection is finite in width (x) but infinite in height (y).
// "x" corresponds to longitude, and spans a finite range such as [-180, 180]
// (with coordinate wrapping), while "y" is a function of latitude and spans
// an infinite range. (As "y" coordinates get larger, points get closer to
// the north pole but never quite reach it.) The north and south poles have
// infinite "y" values. (Note that this will cause problems if you tessellate
// a Mercator edge where one endpoint is a pole. If you need to do this, clip
// the edge first so that the "y" coordinate is no more than about 5 * maxX.)
type MercatorProjection struct {
xWrap float64
toRadians float64 // Multiplier to convert coordinates to radians.
fromRadians float64 // Multiplier to convert coordinates from radians.
}
// NewMercatorProjection constructs a Mercator projection with the given maximum
// longitude axis value corresponding to a range of [-maxLng, maxLng].
// The horizontal and vertical axes are scaled equally.
func NewMercatorProjection(maxLng float64) Projection {
return &MercatorProjection{
xWrap: 2 * maxLng,
toRadians: math.Pi / maxLng,
fromRadians: maxLng / math.Pi,
}
}
// Project converts a point on the sphere to a projected 2D point.
func (p *MercatorProjection) Project(pt Point) r2.Point {
return p.FromLatLng(LatLngFromPoint(pt))
}
// Unproject converts a projected 2D point to a point on the sphere.
func (p *MercatorProjection) Unproject(pt r2.Point) Point {
return PointFromLatLng(p.ToLatLng(pt))
}
// FromLatLng returns the LatLng projected into an R2 Point.
func (p *MercatorProjection) FromLatLng(ll LatLng) r2.Point {
// This formula is more accurate near zero than the log(tan()) version.
// Note that latitudes of +/- 90 degrees yield "y" values of +/- infinity.
sinPhi := math.Sin(float64(ll.Lat))
y := 0.5 * math.Log((1+sinPhi)/(1-sinPhi))
return r2.Point{p.fromRadians * float64(ll.Lng), p.fromRadians * y}
}
// ToLatLng returns the LatLng projected from the given R2 Point.
func (p *MercatorProjection) ToLatLng(pt r2.Point) LatLng {
// This formula is more accurate near zero than the atan(exp()) version.
x := p.toRadians * math.Remainder(pt.X, p.xWrap)
k := math.Exp(2 * p.toRadians * pt.Y)
var y float64
if math.IsInf(k, 0) {
y = math.Pi / 2
} else {
y = math.Asin((k - 1) / (k + 1))
}
return LatLng{s1.Angle(y), s1.Angle(x)}
}
// Interpolate returns the point obtained by interpolating the given
// fraction of the distance along the line from A to B.
func (p *MercatorProjection) Interpolate(f float64, a, b r2.Point) r2.Point {
return a.Mul(1 - f).Add(b.Mul(f))
}
// WrapDistance reports the coordinate wrapping distance along each axis.
func (p *MercatorProjection) WrapDistance() r2.Point {
return r2.Point{p.xWrap, 0}
}
// WrapDestination wraps the points if needed to get the shortest edge.
func (p *MercatorProjection) WrapDestination(a, b r2.Point) r2.Point {
return wrapDestination(a, b, p.WrapDistance)
}
func (p *MercatorProjection) privateInterface() {}
func wrapDestination(a, b r2.Point, wrapDistance func() r2.Point) r2.Point {
wrap := wrapDistance()
x := b.X
y := b.Y
// The code below ensures that "b" is unmodified unless wrapping is required.
if wrap.X > 0 && math.Abs(x-a.X) > 0.5*wrap.X {
x = a.X + math.Remainder(x-a.X, wrap.X)
}
if wrap.Y > 0 && math.Abs(y-a.Y) > 0.5*wrap.Y {
y = a.Y + math.Remainder(y-a.Y, wrap.Y)
}
return r2.Point{x, y}
}

93
vendor/github.com/golang/geo/s2/query_entry.go generated vendored Normal file
View File

@ -0,0 +1,93 @@
// 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 "container/heap"
// A queryQueueEntry stores CellIDs and distance from a target. It is used by the
// different S2 Query types to efficiently build their internal priority queue
// in the optimized algorithm implementations.
type queryQueueEntry struct {
// A lower bound on the distance from the target to ID. This is the key
// of the priority queue.
distance distance
// The cell being queued.
id CellID
// If the CellID belongs to a ShapeIndex, this field stores the
// corresponding ShapeIndexCell. Otherwise ID is a proper ancestor of
// one or more ShapeIndexCells and this field stores is nil.
indexCell *ShapeIndexCell
}
// queryQueue is used by the optimized algorithm to maintain a priority queue of
// unprocessed CellIDs, sorted in increasing order of distance from the target.
type queryQueue struct {
queue queryPQ
}
// newQueryQueue returns a new initialized queryQueue.
func newQueryQueue() *queryQueue {
q := &queryQueue{
queue: make(queryPQ, 0),
}
heap.Init(&q.queue)
return q
}
// push adds the given entry to the top of this queue.
func (q *queryQueue) push(e *queryQueueEntry) {
heap.Push(&q.queue, e)
}
// pop returns the top element of this queue.
func (q *queryQueue) pop() *queryQueueEntry {
return heap.Pop(&q.queue).(*queryQueueEntry)
}
func (q *queryQueue) size() int {
return q.queue.Len()
}
func (q *queryQueue) reset() {
q.queue = q.queue[:0]
}
// queryPQ is a priority queue that implements the heap interface.
type queryPQ []*queryQueueEntry
func (q queryPQ) Len() int { return len(q) }
func (q queryPQ) Less(i, j int) bool {
return q[i].distance.less(q[j].distance)
}
// Swap swaps the two entries.
func (q queryPQ) Swap(i, j int) {
q[i], q[j] = q[j], q[i]
}
// Push adds the given entry to the queue.
func (q *queryPQ) Push(x interface{}) {
item := x.(*queryQueueEntry)
*q = append(*q, item)
}
// Pop returns the top element of the queue.
func (q *queryPQ) Pop() interface{} {
item := (*q)[len(*q)-1]
*q = (*q)[:len(*q)-1]
return item
}

196
vendor/github.com/golang/geo/s2/query_options.go generated vendored Normal file
View File

@ -0,0 +1,196 @@
// Copyright 2019 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 (
"math"
"github.com/golang/geo/s1"
)
const maxQueryResults = math.MaxInt32
// queryOptions represents the set of all configurable parameters used by all of
// the Query types. Most of these fields have non-zero defaults, so initialization
// is handled within each Query type. All of the exported methods accept user
// supplied sets of options to set or adjust as necessary.
//
// Several of the defaults depend on the distance interface type being used
// (e.g. minDistance, maxDistance, etc.)
//
// If a user sets an option value that a given query type doesn't use, it is ignored.
type queryOptions struct {
// maxResults specifies that at most MaxResults edges should be returned.
// This must be at least 1.
//
// The default value is to return all results.
maxResults int
// distanceLimit specifies that only edges whose distance to the target is
// within this distance should be returned.
//
// Note that edges whose distance is exactly equal to this are
// not returned. In most cases this doesn't matter (since distances are
// not computed exactly in the first place), but if such edges are needed
// then you can retrieve them by specifying the distance as the next
// largest representable distance. i.e. distanceLimit.Successor().
//
// The default value is the infinity value, such that all results will be
// returned.
distanceLimit s1.ChordAngle
// maxError specifies that edges up to MaxError further away than the true
// closest edges may be substituted in the result set, as long as such
// edges satisfy all the remaining search criteria (such as DistanceLimit).
// This option only has an effect if MaxResults is also specified;
// otherwise all edges closer than MaxDistance will always be returned.
//
// Note that this does not affect how the distance between edges is
// computed; it simply gives the algorithm permission to stop the search
// early as soon as the best possible improvement drops below MaxError.
//
// This can be used to implement distance predicates efficiently. For
// example, to determine whether the minimum distance is less than D, set
// MaxResults == 1 and MaxDistance == MaxError == D. This causes
// the algorithm to terminate as soon as it finds any edge whose distance
// is less than D, rather than continuing to search for an edge that is
// even closer.
//
// The default value is zero.
maxError s1.ChordAngle
// includeInteriors specifies that polygon interiors should be included
// when measuring distances. In other words, polygons that contain the target
// should have a distance of zero. (For targets consisting of multiple connected
// components, the distance is zero if any component is contained.) This
// is indicated in the results by returning a (ShapeID, EdgeID) pair
// with EdgeID == -1, i.e. this value denotes the polygons's interior.
//
// Note that for efficiency, any polygon that intersects the target may or
// may not have an EdgeID == -1 result. Such results are optional
// because in that case the distance to the polygon is already zero.
//
// The default value is true.
includeInteriors bool
// specifies that distances should be computed by examining every edge
// rather than using the ShapeIndex.
//
// TODO(roberts): When optimized is implemented, update the default to false.
// The default value is true.
useBruteForce bool
// region specifies that results must intersect the given Region.
//
// Note that if you want to set the region to a disc around a target
// point, it is faster to use a PointTarget with distanceLimit set
// instead. You can also set a distance limit and also require that results
// lie within a given rectangle.
//
// The default is nil (no region limits).
region Region
}
// UseBruteForce sets or disables the use of brute force in a query.
func (q *queryOptions) UseBruteForce(x bool) *queryOptions {
q.useBruteForce = x
return q
}
// IncludeInteriors specifies whether polygon interiors should be
// included when measuring distances.
func (q *queryOptions) IncludeInteriors(x bool) *queryOptions {
q.includeInteriors = x
return q
}
// MaxError specifies that edges up to dist away than the true
// matching edges may be substituted in the result set, as long as such
// edges satisfy all the remaining search criteria (such as DistanceLimit).
// This option only has an effect if MaxResults is also specified;
// otherwise all edges closer than MaxDistance will always be returned.
func (q *queryOptions) MaxError(x s1.ChordAngle) *queryOptions {
q.maxError = x
return q
}
// MaxResults specifies that at most MaxResults edges should be returned.
// This must be at least 1.
func (q *queryOptions) MaxResults(x int) *queryOptions {
// TODO(roberts): What should be done if the value is <= 0?
q.maxResults = int(x)
return q
}
// DistanceLimit specifies that only edges whose distance to the target is
// within, this distance should be returned. Edges whose distance is equal
// are not returned.
//
// To include values that are equal, specify the limit with the next largest
// representable distance such as limit.Successor(), or set the option with
// Furthest/ClosestInclusiveDistanceLimit.
func (q *queryOptions) DistanceLimit(x s1.ChordAngle) *queryOptions {
q.distanceLimit = x
return q
}
// ClosestInclusiveDistanceLimit sets the distance limit such that results whose
// distance is exactly equal to the limit are also returned.
func (q *queryOptions) ClosestInclusiveDistanceLimit(limit s1.ChordAngle) *queryOptions {
q.distanceLimit = limit.Successor()
return q
}
// FurthestInclusiveDistanceLimit sets the distance limit such that results whose
// distance is exactly equal to the limit are also returned.
func (q *queryOptions) FurthestInclusiveDistanceLimit(limit s1.ChordAngle) *queryOptions {
q.distanceLimit = limit.Predecessor()
return q
}
// ClosestConservativeDistanceLimit sets the distance limit such that results
// also incorporates the error in distance calculations. This ensures that all
// edges whose true distance is less than or equal to limit will be returned
// (along with some edges whose true distance is slightly greater).
//
// Algorithms that need to do exact distance comparisons can use this
// option to find a set of candidate edges that can then be filtered
// further (e.g., using CompareDistance).
func (q *queryOptions) ClosestConservativeDistanceLimit(limit s1.ChordAngle) *queryOptions {
q.distanceLimit = limit.Expanded(minUpdateDistanceMaxError(limit))
return q
}
// FurthestConservativeDistanceLimit sets the distance limit such that results
// also incorporates the error in distance calculations. This ensures that all
// edges whose true distance is greater than or equal to limit will be returned
// (along with some edges whose true distance is slightly less).
func (q *queryOptions) FurthestConservativeDistanceLimit(limit s1.ChordAngle) *queryOptions {
q.distanceLimit = limit.Expanded(-minUpdateDistanceMaxError(limit))
return q
}
// newQueryOptions returns a set of options using the given distance type
// with the proper default values.
func newQueryOptions(d distance) *queryOptions {
return &queryOptions{
maxResults: maxQueryResults,
distanceLimit: d.infinity().chordAngle(),
maxError: 0,
includeInteriors: true,
useBruteForce: false,
region: nil,
}
}

710
vendor/github.com/golang/geo/s2/rect.go generated vendored Normal file
View File

@ -0,0 +1,710 @@
// 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"
"math"
"github.com/golang/geo/r1"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// Rect represents a closed latitude-longitude rectangle.
type Rect struct {
Lat r1.Interval
Lng s1.Interval
}
var (
validRectLatRange = r1.Interval{-math.Pi / 2, math.Pi / 2}
validRectLngRange = s1.FullInterval()
)
// EmptyRect returns the empty rectangle.
func EmptyRect() Rect { return Rect{r1.EmptyInterval(), s1.EmptyInterval()} }
// FullRect returns the full rectangle.
func FullRect() Rect { return Rect{validRectLatRange, validRectLngRange} }
// RectFromLatLng constructs a rectangle containing a single point p.
func RectFromLatLng(p LatLng) Rect {
return Rect{
Lat: r1.Interval{p.Lat.Radians(), p.Lat.Radians()},
Lng: s1.Interval{p.Lng.Radians(), p.Lng.Radians()},
}
}
// 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 RectFromCenterSize(center, size LatLng) Rect {
half := LatLng{size.Lat / 2, size.Lng / 2}
return RectFromLatLng(center).expanded(half)
}
// IsValid returns true iff the rectangle is valid.
// This requires Lat ⊆ [-π/2,π/2] and Lng ⊆ [-π,π], and Lat = ∅ iff Lng = ∅
func (r Rect) IsValid() bool {
return math.Abs(r.Lat.Lo) <= math.Pi/2 &&
math.Abs(r.Lat.Hi) <= math.Pi/2 &&
r.Lng.IsValid() &&
r.Lat.IsEmpty() == r.Lng.IsEmpty()
}
// IsEmpty reports whether the rectangle is empty.
func (r Rect) IsEmpty() bool { return r.Lat.IsEmpty() }
// IsFull reports whether the rectangle is full.
func (r Rect) IsFull() bool { return r.Lat.Equal(validRectLatRange) && r.Lng.IsFull() }
// IsPoint reports whether the rectangle is a single point.
func (r Rect) IsPoint() bool { return r.Lat.Lo == r.Lat.Hi && r.Lng.Lo == r.Lng.Hi }
// Vertex returns the i-th vertex of the rectangle (i = 0,1,2,3) in CCW order
// (lower left, lower right, upper right, upper left).
func (r Rect) Vertex(i int) LatLng {
var lat, lng float64
switch i {
case 0:
lat = r.Lat.Lo
lng = r.Lng.Lo
case 1:
lat = r.Lat.Lo
lng = r.Lng.Hi
case 2:
lat = r.Lat.Hi
lng = r.Lng.Hi
case 3:
lat = r.Lat.Hi
lng = r.Lng.Lo
}
return LatLng{s1.Angle(lat) * s1.Radian, s1.Angle(lng) * s1.Radian}
}
// Lo returns one corner of the rectangle.
func (r Rect) Lo() LatLng {
return LatLng{s1.Angle(r.Lat.Lo) * s1.Radian, s1.Angle(r.Lng.Lo) * s1.Radian}
}
// Hi returns the other corner of the rectangle.
func (r Rect) Hi() LatLng {
return LatLng{s1.Angle(r.Lat.Hi) * s1.Radian, s1.Angle(r.Lng.Hi) * s1.Radian}
}
// Center returns the center of the rectangle.
func (r Rect) Center() LatLng {
return LatLng{s1.Angle(r.Lat.Center()) * s1.Radian, s1.Angle(r.Lng.Center()) * s1.Radian}
}
// Size returns the size of the Rect.
func (r Rect) Size() LatLng {
return LatLng{s1.Angle(r.Lat.Length()) * s1.Radian, s1.Angle(r.Lng.Length()) * s1.Radian}
}
// Area returns the surface area of the Rect.
func (r Rect) Area() float64 {
if r.IsEmpty() {
return 0
}
capDiff := math.Abs(math.Sin(r.Lat.Hi) - math.Sin(r.Lat.Lo))
return r.Lng.Length() * capDiff
}
// AddPoint increases the size of the rectangle to include the given point.
func (r Rect) AddPoint(ll LatLng) Rect {
if !ll.IsValid() {
return r
}
return Rect{
Lat: r.Lat.AddPoint(ll.Lat.Radians()),
Lng: r.Lng.AddPoint(ll.Lng.Radians()),
}
}
// expanded returns a rectangle that has been expanded by margin.Lat on each side
// in the latitude direction, and by margin.Lng on each side in the longitude
// direction. If either margin is negative, then it shrinks the rectangle on
// the corresponding sides instead. The resulting rectangle may be empty.
//
// The latitude-longitude space has the topology of a cylinder. Longitudes
// "wrap around" at +/-180 degrees, while latitudes are clamped to range [-90, 90].
// This means that any expansion (positive or negative) of the full longitude range
// remains full (since the "rectangle" is actually a continuous band around the
// cylinder), while expansion of the full latitude range remains full only if the
// margin is positive.
//
// If either the latitude or longitude interval becomes empty after
// expansion by a negative margin, the result is empty.
//
// Note that if an expanded rectangle contains a pole, it may not contain
// all possible lat/lng representations of that pole, e.g., both points [π/2,0]
// and [π/2,1] represent the same pole, but they might not be contained by the
// same Rect.
//
// If you are trying to grow a rectangle by a certain distance on the
// sphere (e.g. 5km), refer to the ExpandedByDistance() C++ method implementation
// instead.
func (r Rect) expanded(margin LatLng) Rect {
lat := r.Lat.Expanded(margin.Lat.Radians())
lng := r.Lng.Expanded(margin.Lng.Radians())
if lat.IsEmpty() || lng.IsEmpty() {
return EmptyRect()
}
return Rect{
Lat: lat.Intersection(validRectLatRange),
Lng: lng,
}
}
func (r Rect) String() string { return fmt.Sprintf("[Lo%v, Hi%v]", r.Lo(), r.Hi()) }
// 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.
func (r Rect) PolarClosure() Rect {
if r.Lat.Lo == -math.Pi/2 || r.Lat.Hi == math.Pi/2 {
return Rect{r.Lat, s1.FullInterval()}
}
return r
}
// Union returns the smallest Rect containing the union of this rectangle and the given rectangle.
func (r Rect) Union(other Rect) Rect {
return Rect{
Lat: r.Lat.Union(other.Lat),
Lng: r.Lng.Union(other.Lng),
}
}
// 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 (r Rect) Intersection(other Rect) Rect {
lat := r.Lat.Intersection(other.Lat)
lng := r.Lng.Intersection(other.Lng)
if lat.IsEmpty() || lng.IsEmpty() {
return EmptyRect()
}
return Rect{lat, lng}
}
// Intersects reports whether this rectangle and the other have any points in common.
func (r Rect) Intersects(other Rect) bool {
return r.Lat.Intersects(other.Lat) && r.Lng.Intersects(other.Lng)
}
// CapBound returns a cap that contains Rect.
func (r Rect) CapBound() Cap {
// We consider two possible bounding caps, one whose axis passes
// through the center of the lat-long rectangle and one whose axis
// is the north or south pole. We return the smaller of the two caps.
if r.IsEmpty() {
return EmptyCap()
}
var poleZ, poleAngle float64
if r.Lat.Hi+r.Lat.Lo < 0 {
// South pole axis yields smaller cap.
poleZ = -1
poleAngle = math.Pi/2 + r.Lat.Hi
} else {
poleZ = 1
poleAngle = math.Pi/2 - r.Lat.Lo
}
poleCap := CapFromCenterAngle(Point{r3.Vector{0, 0, poleZ}}, s1.Angle(poleAngle)*s1.Radian)
// For bounding rectangles that span 180 degrees or less in longitude, the
// maximum cap size is achieved at one of the rectangle vertices. For
// rectangles that are larger than 180 degrees, we punt and always return a
// bounding cap centered at one of the two poles.
if math.Remainder(r.Lng.Hi-r.Lng.Lo, 2*math.Pi) >= 0 && r.Lng.Hi-r.Lng.Lo < 2*math.Pi {
midCap := CapFromPoint(PointFromLatLng(r.Center())).AddPoint(PointFromLatLng(r.Lo())).AddPoint(PointFromLatLng(r.Hi()))
if midCap.Height() < poleCap.Height() {
return midCap
}
}
return poleCap
}
// RectBound returns itself.
func (r Rect) RectBound() Rect {
return r
}
// Contains reports whether this Rect contains the other Rect.
func (r Rect) Contains(other Rect) bool {
return r.Lat.ContainsInterval(other.Lat) && r.Lng.ContainsInterval(other.Lng)
}
// ContainsCell reports whether the given Cell is contained by this Rect.
func (r Rect) ContainsCell(c Cell) bool {
// A latitude-longitude rectangle contains a cell if and only if it contains
// the cell's bounding rectangle. This test is exact from a mathematical
// point of view, assuming that the bounds returned by Cell.RectBound()
// are tight. However, note that there can be a loss of precision when
// converting between representations -- for example, if an s2.Cell is
// converted to a polygon, the polygon's bounding rectangle may not contain
// the cell's bounding rectangle. This has some slightly unexpected side
// effects; for instance, if one creates an s2.Polygon from an s2.Cell, the
// polygon will contain the cell, but the polygon's bounding box will not.
return r.Contains(c.RectBound())
}
// ContainsLatLng reports whether the given LatLng is within the Rect.
func (r Rect) ContainsLatLng(ll LatLng) bool {
if !ll.IsValid() {
return false
}
return r.Lat.Contains(ll.Lat.Radians()) && r.Lng.Contains(ll.Lng.Radians())
}
// ContainsPoint reports whether the given Point is within the Rect.
func (r Rect) ContainsPoint(p Point) bool {
return r.ContainsLatLng(LatLngFromPoint(p))
}
// CellUnionBound computes a covering of the Rect.
func (r Rect) CellUnionBound() []CellID {
return r.CapBound().CellUnionBound()
}
// intersectsLatEdge reports whether the edge AB intersects the given edge of constant
// latitude. Requires the points to have unit length.
func intersectsLatEdge(a, b Point, lat s1.Angle, lng s1.Interval) bool {
// Unfortunately, lines of constant latitude are curves on
// the sphere. They can intersect a straight edge in 0, 1, or 2 points.
// First, compute the normal to the plane AB that points vaguely north.
z := Point{a.PointCross(b).Normalize()}
if z.Z < 0 {
z = Point{z.Mul(-1)}
}
// Extend this to an orthonormal frame (x,y,z) where x is the direction
// where the great circle through AB achieves its maximium latitude.
y := Point{z.PointCross(PointFromCoords(0, 0, 1)).Normalize()}
x := y.Cross(z.Vector)
// Compute the angle "theta" from the x-axis (in the x-y plane defined
// above) where the great circle intersects the given line of latitude.
sinLat := math.Sin(float64(lat))
if math.Abs(sinLat) >= x.Z {
// The great circle does not reach the given latitude.
return false
}
cosTheta := sinLat / x.Z
sinTheta := math.Sqrt(1 - cosTheta*cosTheta)
theta := math.Atan2(sinTheta, cosTheta)
// The candidate intersection points are located +/- theta in the x-y
// plane. For an intersection to be valid, we need to check that the
// intersection point is contained in the interior of the edge AB and
// also that it is contained within the given longitude interval "lng".
// Compute the range of theta values spanned by the edge AB.
abTheta := s1.IntervalFromPointPair(
math.Atan2(a.Dot(y.Vector), a.Dot(x)),
math.Atan2(b.Dot(y.Vector), b.Dot(x)))
if abTheta.Contains(theta) {
// Check if the intersection point is also in the given lng interval.
isect := x.Mul(cosTheta).Add(y.Mul(sinTheta))
if lng.Contains(math.Atan2(isect.Y, isect.X)) {
return true
}
}
if abTheta.Contains(-theta) {
// Check if the other intersection point is also in the given lng interval.
isect := x.Mul(cosTheta).Sub(y.Mul(sinTheta))
if lng.Contains(math.Atan2(isect.Y, isect.X)) {
return true
}
}
return false
}
// intersectsLngEdge reports whether the edge AB intersects the given edge of constant
// longitude. Requires the points to have unit length.
func intersectsLngEdge(a, b Point, lat r1.Interval, lng s1.Angle) bool {
// The nice thing about edges of constant longitude is that
// they are straight lines on the sphere (geodesics).
return CrossingSign(a, b, PointFromLatLng(LatLng{s1.Angle(lat.Lo), lng}),
PointFromLatLng(LatLng{s1.Angle(lat.Hi), lng})) == Cross
}
// IntersectsCell reports whether this rectangle intersects the given cell. This is an
// exact test and may be fairly expensive.
func (r Rect) IntersectsCell(c Cell) bool {
// First we eliminate the cases where one region completely contains the
// other. Once these are disposed of, then the regions will intersect
// if and only if their boundaries intersect.
if r.IsEmpty() {
return false
}
if r.ContainsPoint(Point{c.id.rawPoint()}) {
return true
}
if c.ContainsPoint(PointFromLatLng(r.Center())) {
return true
}
// Quick rejection test (not required for correctness).
if !r.Intersects(c.RectBound()) {
return false
}
// Precompute the cell vertices as points and latitude-longitudes. We also
// check whether the Cell contains any corner of the rectangle, or
// vice-versa, since the edge-crossing tests only check the edge interiors.
vertices := [4]Point{}
latlngs := [4]LatLng{}
for i := range vertices {
vertices[i] = c.Vertex(i)
latlngs[i] = LatLngFromPoint(vertices[i])
if r.ContainsLatLng(latlngs[i]) {
return true
}
if c.ContainsPoint(PointFromLatLng(r.Vertex(i))) {
return true
}
}
// Now check whether the boundaries intersect. Unfortunately, a
// latitude-longitude rectangle does not have straight edges: two edges
// are curved, and at least one of them is concave.
for i := range vertices {
edgeLng := s1.IntervalFromEndpoints(latlngs[i].Lng.Radians(), latlngs[(i+1)&3].Lng.Radians())
if !r.Lng.Intersects(edgeLng) {
continue
}
a := vertices[i]
b := vertices[(i+1)&3]
if edgeLng.Contains(r.Lng.Lo) && intersectsLngEdge(a, b, r.Lat, s1.Angle(r.Lng.Lo)) {
return true
}
if edgeLng.Contains(r.Lng.Hi) && intersectsLngEdge(a, b, r.Lat, s1.Angle(r.Lng.Hi)) {
return true
}
if intersectsLatEdge(a, b, s1.Angle(r.Lat.Lo), r.Lng) {
return true
}
if intersectsLatEdge(a, b, s1.Angle(r.Lat.Hi), r.Lng) {
return true
}
}
return false
}
// Encode encodes the Rect.
func (r Rect) Encode(w io.Writer) error {
e := &encoder{w: w}
r.encode(e)
return e.err
}
func (r Rect) encode(e *encoder) {
e.writeInt8(encodingVersion)
e.writeFloat64(r.Lat.Lo)
e.writeFloat64(r.Lat.Hi)
e.writeFloat64(r.Lng.Lo)
e.writeFloat64(r.Lng.Hi)
}
// Decode decodes a rectangle.
func (r *Rect) Decode(rd io.Reader) error {
d := &decoder{r: asByteReader(rd)}
r.decode(d)
return d.err
}
func (r *Rect) decode(d *decoder) {
if version := d.readUint8(); int8(version) != encodingVersion && d.err == nil {
d.err = fmt.Errorf("can't decode version %d; my version: %d", version, encodingVersion)
return
}
r.Lat.Lo = d.readFloat64()
r.Lat.Hi = d.readFloat64()
r.Lng.Lo = d.readFloat64()
r.Lng.Hi = d.readFloat64()
return
}
// DistanceToLatLng returns the minimum distance (measured along the surface of the sphere)
// from a given point to the rectangle (both its boundary and its interior).
// If r is empty, the result is meaningless.
// The latlng must be valid.
func (r Rect) DistanceToLatLng(ll LatLng) s1.Angle {
if r.Lng.Contains(float64(ll.Lng)) {
return maxAngle(0, ll.Lat-s1.Angle(r.Lat.Hi), s1.Angle(r.Lat.Lo)-ll.Lat)
}
i := s1.IntervalFromEndpoints(r.Lng.Hi, r.Lng.ComplementCenter())
rectLng := r.Lng.Lo
if i.Contains(float64(ll.Lng)) {
rectLng = r.Lng.Hi
}
lo := LatLng{s1.Angle(r.Lat.Lo) * s1.Radian, s1.Angle(rectLng) * s1.Radian}
hi := LatLng{s1.Angle(r.Lat.Hi) * s1.Radian, s1.Angle(rectLng) * s1.Radian}
return DistanceFromSegment(PointFromLatLng(ll), PointFromLatLng(lo), PointFromLatLng(hi))
}
// DirectedHausdorffDistance returns the directed Hausdorff distance (measured along the
// surface of the sphere) to the given Rect. The directed Hausdorff
// distance from rectangle A to rectangle B is given by
// h(A, B) = max_{p in A} min_{q in B} d(p, q).
func (r Rect) DirectedHausdorffDistance(other Rect) s1.Angle {
if r.IsEmpty() {
return 0 * s1.Radian
}
if other.IsEmpty() {
return math.Pi * s1.Radian
}
lng := r.Lng.DirectedHausdorffDistance(other.Lng)
return directedHausdorffDistance(lng, r.Lat, other.Lat)
}
// HausdorffDistance returns the undirected Hausdorff distance (measured along the
// surface of the sphere) to the given Rect.
// The Hausdorff distance between rectangle A and rectangle B is given by
// H(A, B) = max{h(A, B), h(B, A)}.
func (r Rect) HausdorffDistance(other Rect) s1.Angle {
return maxAngle(r.DirectedHausdorffDistance(other),
other.DirectedHausdorffDistance(r))
}
// ApproxEqual reports whether the latitude and longitude intervals of the two rectangles
// are the same up to a small tolerance.
func (r Rect) ApproxEqual(other Rect) bool {
return r.Lat.ApproxEqual(other.Lat) && r.Lng.ApproxEqual(other.Lng)
}
// directedHausdorffDistance returns the directed Hausdorff distance
// from one longitudinal edge spanning latitude range 'a' to the other
// longitudinal edge spanning latitude range 'b', with their longitudinal
// difference given by 'lngDiff'.
func directedHausdorffDistance(lngDiff s1.Angle, a, b r1.Interval) s1.Angle {
// By symmetry, we can assume a's longitude is 0 and b's longitude is
// lngDiff. Call b's two endpoints bLo and bHi. Let H be the hemisphere
// containing a and delimited by the longitude line of b. The Voronoi diagram
// of b on H has three edges (portions of great circles) all orthogonal to b
// and meeting at bLo cross bHi.
// E1: (bLo, bLo cross bHi)
// E2: (bHi, bLo cross bHi)
// E3: (-bMid, bLo cross bHi), where bMid is the midpoint of b
//
// They subdivide H into three Voronoi regions. Depending on how longitude 0
// (which contains edge a) intersects these regions, we distinguish two cases:
// Case 1: it intersects three regions. This occurs when lngDiff <= π/2.
// Case 2: it intersects only two regions. This occurs when lngDiff > π/2.
//
// In the first case, the directed Hausdorff distance to edge b can only be
// realized by the following points on a:
// A1: two endpoints of a.
// A2: intersection of a with the equator, if b also intersects the equator.
//
// In the second case, the directed Hausdorff distance to edge b can only be
// realized by the following points on a:
// B1: two endpoints of a.
// B2: intersection of a with E3
// B3: farthest point from bLo to the interior of D, and farthest point from
// bHi to the interior of U, if any, where D (resp. U) is the portion
// of edge a below (resp. above) the intersection point from B2.
if lngDiff < 0 {
panic("impossible: negative lngDiff")
}
if lngDiff > math.Pi {
panic("impossible: lngDiff > Pi")
}
if lngDiff == 0 {
return s1.Angle(a.DirectedHausdorffDistance(b))
}
// Assumed longitude of b.
bLng := lngDiff
// Two endpoints of b.
bLo := PointFromLatLng(LatLng{s1.Angle(b.Lo), bLng})
bHi := PointFromLatLng(LatLng{s1.Angle(b.Hi), bLng})
// Cases A1 and B1.
aLo := PointFromLatLng(LatLng{s1.Angle(a.Lo), 0})
aHi := PointFromLatLng(LatLng{s1.Angle(a.Hi), 0})
maxDistance := maxAngle(
DistanceFromSegment(aLo, bLo, bHi),
DistanceFromSegment(aHi, bLo, bHi))
if lngDiff <= math.Pi/2 {
// Case A2.
if a.Contains(0) && b.Contains(0) {
maxDistance = maxAngle(maxDistance, lngDiff)
}
return maxDistance
}
// Case B2.
p := bisectorIntersection(b, bLng)
pLat := LatLngFromPoint(p).Lat
if a.Contains(float64(pLat)) {
maxDistance = maxAngle(maxDistance, p.Angle(bLo.Vector))
}
// Case B3.
if pLat > s1.Angle(a.Lo) {
intDist, ok := interiorMaxDistance(r1.Interval{a.Lo, math.Min(float64(pLat), a.Hi)}, bLo)
if ok {
maxDistance = maxAngle(maxDistance, intDist)
}
}
if pLat < s1.Angle(a.Hi) {
intDist, ok := interiorMaxDistance(r1.Interval{math.Max(float64(pLat), a.Lo), a.Hi}, bHi)
if ok {
maxDistance = maxAngle(maxDistance, intDist)
}
}
return maxDistance
}
// interiorMaxDistance returns the max distance from a point b to the segment spanning latitude range
// aLat on longitude 0 if the max occurs in the interior of aLat. Otherwise, returns (0, false).
func interiorMaxDistance(aLat r1.Interval, b Point) (a s1.Angle, ok bool) {
// Longitude 0 is in the y=0 plane. b.X >= 0 implies that the maximum
// does not occur in the interior of aLat.
if aLat.IsEmpty() || b.X >= 0 {
return 0, false
}
// Project b to the y=0 plane. The antipodal of the normalized projection is
// the point at which the maxium distance from b occurs, if it is contained
// in aLat.
intersectionPoint := PointFromCoords(-b.X, 0, -b.Z)
if !aLat.InteriorContains(float64(LatLngFromPoint(intersectionPoint).Lat)) {
return 0, false
}
return b.Angle(intersectionPoint.Vector), true
}
// bisectorIntersection return the intersection of longitude 0 with the bisector of an edge
// on longitude 'lng' and spanning latitude range 'lat'.
func bisectorIntersection(lat r1.Interval, lng s1.Angle) Point {
lng = s1.Angle(math.Abs(float64(lng)))
latCenter := s1.Angle(lat.Center())
// A vector orthogonal to the bisector of the given longitudinal edge.
orthoBisector := LatLng{latCenter - math.Pi/2, lng}
if latCenter < 0 {
orthoBisector = LatLng{-latCenter - math.Pi/2, lng - math.Pi}
}
// A vector orthogonal to longitude 0.
orthoLng := Point{r3.Vector{0, -1, 0}}
return orthoLng.PointCross(PointFromLatLng(orthoBisector))
}
// Centroid returns the true centroid of the given Rect multiplied by its
// surface area. The result is not unit length, so you may want to normalize it.
// Note that in general the centroid is *not* at the center of the rectangle, and
// in fact it may not even be contained by the rectangle. (It is the "center of
// mass" of the rectangle viewed as subset of the unit sphere, i.e. it is the
// point in space about which this curved shape would rotate.)
//
// The reason for multiplying the result by the rectangle area is to make it
// easier to compute the centroid of more complicated shapes. The centroid
// of a union of disjoint regions can be computed simply by adding their
// Centroid results.
func (r Rect) Centroid() Point {
// When a sphere is divided into slices of constant thickness by a set
// of parallel planes, all slices have the same surface area. This
// implies that the z-component of the centroid is simply the midpoint
// of the z-interval spanned by the Rect.
//
// Similarly, it is easy to see that the (x,y) of the centroid lies in
// the plane through the midpoint of the rectangle's longitude interval.
// We only need to determine the distance "d" of this point from the
// z-axis.
//
// Let's restrict our attention to a particular z-value. In this
// z-plane, the Rect is a circular arc. The centroid of this arc
// lies on a radial line through the midpoint of the arc, and at a
// distance from the z-axis of
//
// r * (sin(alpha) / alpha)
//
// where r = sqrt(1-z^2) is the radius of the arc, and "alpha" is half
// of the arc length (i.e., the arc covers longitudes [-alpha, alpha]).
//
// To find the centroid distance from the z-axis for the entire
// rectangle, we just need to integrate over the z-interval. This gives
//
// d = Integrate[sqrt(1-z^2)*sin(alpha)/alpha, z1..z2] / (z2 - z1)
//
// where [z1, z2] is the range of z-values covered by the rectangle.
// This simplifies to
//
// d = sin(alpha)/(2*alpha*(z2-z1))*(z2*r2 - z1*r1 + theta2 - theta1)
//
// where [theta1, theta2] is the latitude interval, z1=sin(theta1),
// z2=sin(theta2), r1=cos(theta1), and r2=cos(theta2).
//
// Finally, we want to return not the centroid itself, but the centroid
// scaled by the area of the rectangle. The area of the rectangle is
//
// A = 2 * alpha * (z2 - z1)
//
// which fortunately appears in the denominator of "d".
if r.IsEmpty() {
return Point{}
}
z1 := math.Sin(r.Lat.Lo)
z2 := math.Sin(r.Lat.Hi)
r1 := math.Cos(r.Lat.Lo)
r2 := math.Cos(r.Lat.Hi)
alpha := 0.5 * r.Lng.Length()
r0 := math.Sin(alpha) * (r2*z2 - r1*z1 + r.Lat.Length())
lng := r.Lng.Center()
z := alpha * (z2 + z1) * (z2 - z1) // scaled by the area
return Point{r3.Vector{r0 * math.Cos(lng), r0 * math.Sin(lng), z}}
}
// BUG: The major differences from the C++ version are:
// - Get*Distance, Vertex, InteriorContains(LatLng|Rect|Point)

352
vendor/github.com/golang/geo/s2/rect_bounder.go generated vendored Normal file
View File

@ -0,0 +1,352 @@
// Copyright 2017 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 (
"math"
"github.com/golang/geo/r1"
"github.com/golang/geo/r3"
"github.com/golang/geo/s1"
)
// 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)).
type RectBounder struct {
// The previous vertex in the chain.
a Point
// The previous vertex latitude longitude.
aLL LatLng
bound Rect
}
// NewRectBounder returns a new instance of a RectBounder.
func NewRectBounder() *RectBounder {
return &RectBounder{
bound: EmptyRect(),
}
}
// maxErrorForTests returns the maximum error in RectBound provided that the
// result does not include either pole. It is only used for testing purposes
func (r *RectBounder) maxErrorForTests() LatLng {
// The maximum error in the latitude calculation is
// 3.84 * dblEpsilon for the PointCross calculation
// 0.96 * dblEpsilon for the Latitude calculation
// 5 * dblEpsilon added by AddPoint/RectBound to compensate for error
// -----------------
// 9.80 * dblEpsilon maximum error in result
//
// The maximum error in the longitude calculation is dblEpsilon. RectBound
// does not do any expansion because this isn't necessary in order to
// bound the *rounded* longitudes of contained points.
return LatLng{10 * dblEpsilon * s1.Radian, 1 * dblEpsilon * s1.Radian}
}
// AddPoint adds the given point to the chain. The Point must be unit length.
func (r *RectBounder) AddPoint(b Point) {
bLL := LatLngFromPoint(b)
if r.bound.IsEmpty() {
r.a = b
r.aLL = bLL
r.bound = r.bound.AddPoint(bLL)
return
}
// First compute the cross product N = A x B robustly. This is the normal
// to the great circle through A and B. We don't use RobustSign
// since that method returns an arbitrary vector orthogonal to A if the two
// vectors are proportional, and we want the zero vector in that case.
n := r.a.Sub(b.Vector).Cross(r.a.Add(b.Vector)) // N = 2 * (A x B)
// The relative error in N gets large as its norm gets very small (i.e.,
// when the two points are nearly identical or antipodal). We handle this
// by choosing a maximum allowable error, and if the error is greater than
// this we fall back to a different technique. Since it turns out that
// the other sources of error in converting the normal to a maximum
// latitude add up to at most 1.16 * dblEpsilon, and it is desirable to
// have the total error be a multiple of dblEpsilon, we have chosen to
// limit the maximum error in the normal to be 3.84 * dblEpsilon.
// It is possible to show that the error is less than this when
//
// n.Norm() >= 8 * sqrt(3) / (3.84 - 0.5 - sqrt(3)) * dblEpsilon
// = 1.91346e-15 (about 8.618 * dblEpsilon)
nNorm := n.Norm()
if nNorm < 1.91346e-15 {
// A and B are either nearly identical or nearly antipodal (to within
// 4.309 * dblEpsilon, or about 6 nanometers on the earth's surface).
if r.a.Dot(b.Vector) < 0 {
// The two points are nearly antipodal. The easiest solution is to
// assume that the edge between A and B could go in any direction
// around the sphere.
r.bound = FullRect()
} else {
// The two points are nearly identical (to within 4.309 * dblEpsilon).
// In this case we can just use the bounding rectangle of the points,
// since after the expansion done by GetBound this Rect is
// guaranteed to include the (lat,lng) values of all points along AB.
r.bound = r.bound.Union(RectFromLatLng(r.aLL).AddPoint(bLL))
}
r.a = b
r.aLL = bLL
return
}
// Compute the longitude range spanned by AB.
lngAB := s1.EmptyInterval().AddPoint(r.aLL.Lng.Radians()).AddPoint(bLL.Lng.Radians())
if lngAB.Length() >= math.Pi-2*dblEpsilon {
// The points lie on nearly opposite lines of longitude to within the
// maximum error of the calculation. The easiest solution is to assume
// that AB could go on either side of the pole.
lngAB = s1.FullInterval()
}
// Next we compute the latitude range spanned by the edge AB. We start
// with the range spanning the two endpoints of the edge:
latAB := r1.IntervalFromPoint(r.aLL.Lat.Radians()).AddPoint(bLL.Lat.Radians())
// This is the desired range unless the edge AB crosses the plane
// through N and the Z-axis (which is where the great circle through A
// and B attains its minimum and maximum latitudes). To test whether AB
// crosses this plane, we compute a vector M perpendicular to this
// plane and then project A and B onto it.
m := n.Cross(r3.Vector{0, 0, 1})
mA := m.Dot(r.a.Vector)
mB := m.Dot(b.Vector)
// We want to test the signs of "mA" and "mB", so we need to bound
// the error in these calculations. It is possible to show that the
// total error is bounded by
//
// (1 + sqrt(3)) * dblEpsilon * nNorm + 8 * sqrt(3) * (dblEpsilon**2)
// = 6.06638e-16 * nNorm + 6.83174e-31
mError := 6.06638e-16*nNorm + 6.83174e-31
if mA*mB < 0 || math.Abs(mA) <= mError || math.Abs(mB) <= mError {
// Minimum/maximum latitude *may* occur in the edge interior.
//
// The maximum latitude is 90 degrees minus the latitude of N. We
// compute this directly using atan2 in order to get maximum accuracy
// near the poles.
//
// Our goal is compute a bound that contains the computed latitudes of
// all S2Points P that pass the point-in-polygon containment test.
// There are three sources of error we need to consider:
// - the directional error in N (at most 3.84 * dblEpsilon)
// - converting N to a maximum latitude
// - computing the latitude of the test point P
// The latter two sources of error are at most 0.955 * dblEpsilon
// individually, but it is possible to show by a more complex analysis
// that together they can add up to at most 1.16 * dblEpsilon, for a
// total error of 5 * dblEpsilon.
//
// We add 3 * dblEpsilon to the bound here, and GetBound() will pad
// the bound by another 2 * dblEpsilon.
maxLat := math.Min(
math.Atan2(math.Sqrt(n.X*n.X+n.Y*n.Y), math.Abs(n.Z))+3*dblEpsilon,
math.Pi/2)
// In order to get tight bounds when the two points are close together,
// we also bound the min/max latitude relative to the latitudes of the
// endpoints A and B. First we compute the distance between A and B,
// and then we compute the maximum change in latitude between any two
// points along the great circle that are separated by this distance.
// This gives us a latitude change "budget". Some of this budget must
// be spent getting from A to B; the remainder bounds the round-trip
// distance (in latitude) from A or B to the min or max latitude
// attained along the edge AB.
latBudget := 2 * math.Asin(0.5*(r.a.Sub(b.Vector)).Norm()*math.Sin(maxLat))
maxDelta := 0.5*(latBudget-latAB.Length()) + dblEpsilon
// Test whether AB passes through the point of maximum latitude or
// minimum latitude. If the dot product(s) are small enough then the
// result may be ambiguous.
if mA <= mError && mB >= -mError {
latAB.Hi = math.Min(maxLat, latAB.Hi+maxDelta)
}
if mB <= mError && mA >= -mError {
latAB.Lo = math.Max(-maxLat, latAB.Lo-maxDelta)
}
}
r.a = b
r.aLL = bLL
r.bound = r.bound.Union(Rect{latAB, lngAB})
}
// 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.
func (r *RectBounder) RectBound() Rect {
return r.bound.expanded(LatLng{s1.Angle(2 * dblEpsilon), 0}).PolarClosure()
}
// 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 ExpandForSubregions(bound Rect) Rect {
// Empty bounds don't need expansion.
if bound.IsEmpty() {
return bound
}
// First we need to check whether the bound B contains any nearly-antipodal
// points (to within 4.309 * dblEpsilon). If so then we need to return
// FullRect, since the subregion might have an edge between two
// such points, and AddPoint returns Full for such edges. Note that
// this can happen even if B is not Full for example, consider a loop
// that defines a 10km strip straddling the equator extending from
// longitudes -100 to +100 degrees.
//
// It is easy to check whether B contains any antipodal points, but checking
// for nearly-antipodal points is trickier. Essentially we consider the
// original bound B and its reflection through the origin B', and then test
// whether the minimum distance between B and B' is less than 4.309 * dblEpsilon.
// lngGap is a lower bound on the longitudinal distance between B and its
// reflection B'. (2.5 * dblEpsilon is the maximum combined error of the
// endpoint longitude calculations and the Length call.)
lngGap := math.Max(0, math.Pi-bound.Lng.Length()-2.5*dblEpsilon)
// minAbsLat is the minimum distance from B to the equator (if zero or
// negative, then B straddles the equator).
minAbsLat := math.Max(bound.Lat.Lo, -bound.Lat.Hi)
// latGapSouth and latGapNorth measure the minimum distance from B to the
// south and north poles respectively.
latGapSouth := math.Pi/2 + bound.Lat.Lo
latGapNorth := math.Pi/2 - bound.Lat.Hi
if minAbsLat >= 0 {
// The bound B does not straddle the equator. In this case the minimum
// distance is between one endpoint of the latitude edge in B closest to
// the equator and the other endpoint of that edge in B'. The latitude
// distance between these two points is 2*minAbsLat, and the longitude
// distance is lngGap. We could compute the distance exactly using the
// Haversine formula, but then we would need to bound the errors in that
// calculation. Since we only need accuracy when the distance is very
// small (close to 4.309 * dblEpsilon), we substitute the Euclidean
// distance instead. This gives us a right triangle XYZ with two edges of
// length x = 2*minAbsLat and y ~= lngGap. The desired distance is the
// length of the third edge z, and we have
//
// z ~= sqrt(x^2 + y^2) >= (x + y) / sqrt(2)
//
// Therefore the region may contain nearly antipodal points only if
//
// 2*minAbsLat + lngGap < sqrt(2) * 4.309 * dblEpsilon
// ~= 1.354e-15
//
// Note that because the given bound B is conservative, minAbsLat and
// lngGap are both lower bounds on their true values so we do not need
// to make any adjustments for their errors.
if 2*minAbsLat+lngGap < 1.354e-15 {
return FullRect()
}
} else if lngGap >= math.Pi/2 {
// B spans at most Pi/2 in longitude. The minimum distance is always
// between one corner of B and the diagonally opposite corner of B'. We
// use the same distance approximation that we used above; in this case
// we have an obtuse triangle XYZ with two edges of length x = latGapSouth
// and y = latGapNorth, and angle Z >= Pi/2 between them. We then have
//
// z >= sqrt(x^2 + y^2) >= (x + y) / sqrt(2)
//
// Unlike the case above, latGapSouth and latGapNorth are not lower bounds
// (because of the extra addition operation, and because math.Pi/2 is not
// exactly equal to Pi/2); they can exceed their true values by up to
// 0.75 * dblEpsilon. Putting this all together, the region may contain
// nearly antipodal points only if
//
// latGapSouth + latGapNorth < (sqrt(2) * 4.309 + 1.5) * dblEpsilon
// ~= 1.687e-15
if latGapSouth+latGapNorth < 1.687e-15 {
return FullRect()
}
} else {
// Otherwise we know that (1) the bound straddles the equator and (2) its
// width in longitude is at least Pi/2. In this case the minimum
// distance can occur either between a corner of B and the diagonally
// opposite corner of B' (as in the case above), or between a corner of B
// and the opposite longitudinal edge reflected in B'. It is sufficient
// to only consider the corner-edge case, since this distance is also a
// lower bound on the corner-corner distance when that case applies.
// Consider the spherical triangle XYZ where X is a corner of B with
// minimum absolute latitude, Y is the closest pole to X, and Z is the
// point closest to X on the opposite longitudinal edge of B'. This is a
// right triangle (Z = Pi/2), and from the spherical law of sines we have
//
// sin(z) / sin(Z) = sin(y) / sin(Y)
// sin(maxLatGap) / 1 = sin(dMin) / sin(lngGap)
// sin(dMin) = sin(maxLatGap) * sin(lngGap)
//
// where "maxLatGap" = max(latGapSouth, latGapNorth) and "dMin" is the
// desired minimum distance. Now using the facts that sin(t) >= (2/Pi)*t
// for 0 <= t <= Pi/2, that we only need an accurate approximation when
// at least one of "maxLatGap" or lngGap is extremely small (in which
// case sin(t) ~= t), and recalling that "maxLatGap" has an error of up
// to 0.75 * dblEpsilon, we want to test whether
//
// maxLatGap * lngGap < (4.309 + 0.75) * (Pi/2) * dblEpsilon
// ~= 1.765e-15
if math.Max(latGapSouth, latGapNorth)*lngGap < 1.765e-15 {
return FullRect()
}
}
// Next we need to check whether the subregion might contain any edges that
// span (math.Pi - 2 * dblEpsilon) radians or more in longitude, since AddPoint
// sets the longitude bound to Full in that case. This corresponds to
// testing whether (lngGap <= 0) in lngExpansion below.
// Otherwise, the maximum latitude error in AddPoint is 4.8 * dblEpsilon.
// In the worst case, the errors when computing the latitude bound for a
// subregion could go in the opposite direction as the errors when computing
// the bound for the original region, so we need to double this value.
// (More analysis shows that it's okay to round down to a multiple of
// dblEpsilon.)
//
// For longitude, we rely on the fact that atan2 is correctly rounded and
// therefore no additional bounds expansion is necessary.
latExpansion := 9 * dblEpsilon
lngExpansion := 0.0
if lngGap <= 0 {
lngExpansion = math.Pi
}
return bound.expanded(LatLng{s1.Angle(latExpansion), s1.Angle(lngExpansion)}).PolarClosure()
}

71
vendor/github.com/golang/geo/s2/region.go generated vendored Normal file
View File

@ -0,0 +1,71 @@
// 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
// 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 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
// ContainsPoint reports whether the region contains the given point or not.
// The point should be unit length, although some implementations may relax
// this restriction.
ContainsPoint(p Point) bool
// CellUnionBound returns a small collection of CellIDs whose union covers
// the region. The cells are not sorted, may have redundancies (such as cells
// that contain other cells), and may cover much more area than necessary.
//
// This method is not intended for direct use by client code. Clients
// should typically use Covering, which has options to control the size and
// accuracy of the covering. Alternatively, if you want a fast covering and
// don't care about accuracy, consider calling FastCovering (which returns a
// cleaned-up version of the covering computed by this method).
//
// CellUnionBound implementations should attempt to return a small
// covering (ideally 4 cells or fewer) that covers the region and can be
// computed quickly. The result is used by RegionCoverer as a starting
// point for further refinement.
CellUnionBound() []CellID
}
// Enforce Region interface satisfaction.
var (
_ Region = Cap{}
_ Region = Cell{}
_ Region = (*CellUnion)(nil)
_ Region = (*Loop)(nil)
_ Region = Point{}
_ Region = (*Polygon)(nil)
_ Region = (*Polyline)(nil)
_ Region = Rect{}
)

615
vendor/github.com/golang/geo/s2/regioncoverer.go generated vendored Normal file
View File

@ -0,0 +1,615 @@
// Copyright 2015 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 (
"container/heap"
"sort"
)
// 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 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.
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.
}
// NewRegionCoverer returns a region coverer with the appropriate defaults.
func NewRegionCoverer() *RegionCoverer {
return &RegionCoverer{
MinLevel: 0,
MaxLevel: maxLevel,
LevelMod: 1,
MaxCells: 8,
}
}
type coverer 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.
region Region
result CellUnion
pq priorityQueue
interiorCovering bool
}
type candidate struct {
cell Cell
terminal bool // Cell should not be expanded further.
numChildren int // Number of children that intersect the region.
children []*candidate // Actual size may be 0, 4, 16, or 64 elements.
priority int // Priority of the candidate.
}
type priorityQueue []*candidate
func (pq priorityQueue) Len() int {
return len(pq)
}
func (pq priorityQueue) Less(i, j int) bool {
// We want Pop to give us the highest, not lowest, priority so we use greater than here.
return pq[i].priority > pq[j].priority
}
func (pq priorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}
func (pq *priorityQueue) Push(x interface{}) {
item := x.(*candidate)
*pq = append(*pq, item)
}
func (pq *priorityQueue) Pop() interface{} {
item := (*pq)[len(*pq)-1]
*pq = (*pq)[:len(*pq)-1]
return item
}
func (pq *priorityQueue) Reset() {
*pq = (*pq)[:0]
}
// newCandidate returns a new candidate with no children if the cell intersects the given region.
// The candidate is marked as terminal if it should not be expanded further.
func (c *coverer) newCandidate(cell Cell) *candidate {
if !c.region.IntersectsCell(cell) {
return nil
}
cand := &candidate{cell: cell}
level := int(cell.level)
if level >= c.minLevel {
if c.interiorCovering {
if c.region.ContainsCell(cell) {
cand.terminal = true
} else if level+c.levelMod > c.maxLevel {
return nil
}
} else if level+c.levelMod > c.maxLevel || c.region.ContainsCell(cell) {
cand.terminal = true
}
}
return cand
}
// expandChildren populates the children of the candidate by expanding the given number of
// levels from the given cell. Returns the number of children that were marked "terminal".
func (c *coverer) expandChildren(cand *candidate, cell Cell, numLevels int) int {
numLevels--
var numTerminals int
last := cell.id.ChildEnd()
for ci := cell.id.ChildBegin(); ci != last; ci = ci.Next() {
childCell := CellFromCellID(ci)
if numLevels > 0 {
if c.region.IntersectsCell(childCell) {
numTerminals += c.expandChildren(cand, childCell, numLevels)
}
continue
}
if child := c.newCandidate(childCell); child != nil {
cand.children = append(cand.children, child)
cand.numChildren++
if child.terminal {
numTerminals++
}
}
}
return numTerminals
}
// addCandidate adds the given candidate to the result if it is marked as "terminal",
// otherwise expands its children and inserts it into the priority queue.
// Passing an argument of nil does nothing.
func (c *coverer) addCandidate(cand *candidate) {
if cand == nil {
return
}
if cand.terminal {
c.result = append(c.result, cand.cell.id)
return
}
// Expand one level at a time until we hit minLevel to ensure that we don't skip over it.
numLevels := c.levelMod
level := int(cand.cell.level)
if level < c.minLevel {
numLevels = 1
}
numTerminals := c.expandChildren(cand, cand.cell, numLevels)
maxChildrenShift := uint(2 * c.levelMod)
if cand.numChildren == 0 {
return
} else if !c.interiorCovering && numTerminals == 1<<maxChildrenShift && level >= c.minLevel {
// Optimization: add the parent cell rather than all of its children.
// We can't do this for interior coverings, since the children just
// intersect the region, but may not be contained by it - we need to
// subdivide them further.
cand.terminal = true
c.addCandidate(cand)
} else {
// We negate the priority so that smaller absolute priorities are returned
// first. The heuristic is designed to refine the largest cells first,
// since those are where we have the largest potential gain. Among cells
// of the same size, we prefer the cells with the fewest children.
// Finally, among cells with equal numbers of children we prefer those
// with the smallest number of children that cannot be refined further.
cand.priority = -(((level<<maxChildrenShift)+cand.numChildren)<<maxChildrenShift + numTerminals)
heap.Push(&c.pq, cand)
}
}
// adjustLevel returns the reduced "level" so that it satisfies levelMod. Levels smaller than minLevel
// are not affected (since cells at these levels are eventually expanded).
func (c *coverer) adjustLevel(level int) int {
if c.levelMod > 1 && level > c.minLevel {
level -= (level - c.minLevel) % c.levelMod
}
return level
}
// adjustCellLevels ensures that all cells with level > minLevel also satisfy levelMod,
// by replacing them with an ancestor if necessary. Cell levels smaller
// than minLevel are not modified (see AdjustLevel). The output is
// then normalized to ensure that no redundant cells are present.
func (c *coverer) adjustCellLevels(cells *CellUnion) {
if c.levelMod == 1 {
return
}
var out int
for _, ci := range *cells {
level := ci.Level()
newLevel := c.adjustLevel(level)
if newLevel != level {
ci = ci.Parent(newLevel)
}
if out > 0 && (*cells)[out-1].Contains(ci) {
continue
}
for out > 0 && ci.Contains((*cells)[out-1]) {
out--
}
(*cells)[out] = ci
out++
}
*cells = (*cells)[:out]
}
// initialCandidates computes a set of initial candidates that cover the given region.
func (c *coverer) initialCandidates() {
// Optimization: start with a small (usually 4 cell) covering of the region's bounding cap.
temp := &RegionCoverer{MaxLevel: c.maxLevel, LevelMod: 1, MaxCells: minInt(4, c.maxCells)}
cells := temp.FastCovering(c.region)
c.adjustCellLevels(&cells)
for _, ci := range cells {
c.addCandidate(c.newCandidate(CellFromCellID(ci)))
}
}
// coveringInternal generates a covering and stores it in result.
// Strategy: Start with the 6 faces of the cube. Discard any
// that do not intersect the shape. Then repeatedly choose the
// largest cell that intersects the shape and subdivide it.
//
// result contains the cells that will be part of the output, while pq
// contains cells that we may still subdivide further. Cells that are
// entirely contained within the region are immediately added to the output,
// while cells that do not intersect the region are immediately discarded.
// Therefore pq only contains cells that partially intersect the region.
// Candidates are prioritized first according to cell size (larger cells
// first), then by the number of intersecting children they have (fewest
// children first), and then by the number of fully contained children
// (fewest children first).
func (c *coverer) coveringInternal(region Region) {
c.region = region
c.initialCandidates()
for c.pq.Len() > 0 && (!c.interiorCovering || len(c.result) < c.maxCells) {
cand := heap.Pop(&c.pq).(*candidate)
// For interior covering we keep subdividing no matter how many children
// candidate has. If we reach MaxCells before expanding all children,
// we will just use some of them.
// For exterior covering we cannot do this, because result has to cover the
// whole region, so all children have to be used.
// candidate.numChildren == 1 case takes care of the situation when we
// already have more than MaxCells in result (minLevel is too high).
// Subdividing of the candidate with one child does no harm in this case.
if c.interiorCovering || int(cand.cell.level) < c.minLevel || cand.numChildren == 1 || len(c.result)+c.pq.Len()+cand.numChildren <= c.maxCells {
for _, child := range cand.children {
if !c.interiorCovering || len(c.result) < c.maxCells {
c.addCandidate(child)
}
}
} else {
cand.terminal = true
c.addCandidate(cand)
}
}
c.pq.Reset()
c.region = nil
// Rather than just returning the raw list of cell ids, we construct a cell
// union and then denormalize it. This has the effect of replacing four
// child cells with their parent whenever this does not violate the covering
// parameters specified (min_level, level_mod, etc). This significantly
// reduces the number of cells returned in many cases, and it is cheap
// compared to computing the covering in the first place.
c.result.Normalize()
if c.minLevel > 0 || c.levelMod > 1 {
c.result.Denormalize(c.minLevel, c.levelMod)
}
}
// newCoverer returns an instance of coverer.
func (rc *RegionCoverer) newCoverer() *coverer {
return &coverer{
minLevel: maxInt(0, minInt(maxLevel, rc.MinLevel)),
maxLevel: maxInt(0, minInt(maxLevel, rc.MaxLevel)),
levelMod: maxInt(1, minInt(3, rc.LevelMod)),
maxCells: rc.MaxCells,
}
}
// Covering returns a CellUnion that covers the given region and satisfies the various restrictions.
func (rc *RegionCoverer) Covering(region Region) CellUnion {
covering := rc.CellUnion(region)
covering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod)))
return covering
}
// InteriorCovering returns a CellUnion that is contained within the given region and satisfies the various restrictions.
func (rc *RegionCoverer) InteriorCovering(region Region) CellUnion {
intCovering := rc.InteriorCellUnion(region)
intCovering.Denormalize(maxInt(0, minInt(maxLevel, rc.MinLevel)), maxInt(1, minInt(3, rc.LevelMod)))
return intCovering
}
// 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 (rc *RegionCoverer) CellUnion(region Region) CellUnion {
c := rc.newCoverer()
c.coveringInternal(region)
cu := c.result
cu.Normalize()
return cu
}
// 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 (rc *RegionCoverer) InteriorCellUnion(region Region) CellUnion {
c := rc.newCoverer()
c.interiorCovering = true
c.coveringInternal(region)
cu := c.result
cu.Normalize()
return cu
}
// 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 (rc *RegionCoverer) FastCovering(region Region) CellUnion {
c := rc.newCoverer()
cu := CellUnion(region.CellUnionBound())
c.normalizeCovering(&cu)
return cu
}
// IsCanonical reports whether the given CellUnion represents a valid covering
// that conforms to the current covering parameters. In particular:
//
// - All CellIDs must be valid.
//
// - CellIDs must be sorted and non-overlapping.
//
// - CellID levels must satisfy MinLevel, MaxLevel, and LevelMod.
//
// - If the covering has more than MaxCells, there must be no two cells with
// a common ancestor at MinLevel or higher.
//
// - There must be no sequence of cells that could be replaced by an
// ancestor (i.e. with LevelMod == 1, the 4 child cells of a parent).
func (rc *RegionCoverer) IsCanonical(covering CellUnion) bool {
return rc.newCoverer().isCanonical(covering)
}
// normalizeCovering normalizes the "covering" so that it conforms to the
// current covering parameters (maxCells, minLevel, maxLevel, and levelMod).
// This method makes no attempt to be optimal. In particular, if
// minLevel > 0 or levelMod > 1 then it may return more than the
// desired number of cells even when this isn't necessary.
//
// Note that when the covering parameters have their default values, almost
// all of the code in this function is skipped.
func (c *coverer) normalizeCovering(covering *CellUnion) {
// If any cells are too small, or don't satisfy levelMod, then replace them with ancestors.
if c.maxLevel < maxLevel || c.levelMod > 1 {
for i, ci := range *covering {
level := ci.Level()
newLevel := c.adjustLevel(minInt(level, c.maxLevel))
if newLevel != level {
(*covering)[i] = ci.Parent(newLevel)
}
}
}
// Sort the cells and simplify them.
covering.Normalize()
// Make sure that the covering satisfies minLevel and levelMod,
// possibly at the expense of satisfying MaxCells.
if c.minLevel > 0 || c.levelMod > 1 {
covering.Denormalize(c.minLevel, c.levelMod)
}
// If there are too many cells and the covering is very large, use the
// RegionCoverer to compute a new covering. (This avoids possible O(n^2)
// behavior of the simpler algorithm below.)
excess := len(*covering) - c.maxCells
if excess <= 0 || c.isCanonical(*covering) {
return
}
if excess*len(*covering) > 10000 {
rc := NewRegionCoverer()
(*covering) = rc.Covering(covering)
return
}
// If there are still too many cells, then repeatedly replace two adjacent
// cells in CellID order by their lowest common ancestor.
for len(*covering) > c.maxCells {
bestIndex := -1
bestLevel := -1
for i := 0; i+1 < len(*covering); i++ {
level, ok := (*covering)[i].CommonAncestorLevel((*covering)[i+1])
if !ok {
continue
}
level = c.adjustLevel(level)
if level > bestLevel {
bestLevel = level
bestIndex = i
}
}
if bestLevel < c.minLevel {
break
}
// Replace all cells contained by the new ancestor cell.
id := (*covering)[bestIndex].Parent(bestLevel)
(*covering) = c.replaceCellsWithAncestor(*covering, id)
// Now repeatedly check whether all children of the parent cell are
// present, in which case we can replace those cells with their parent.
for bestLevel > c.minLevel {
bestLevel -= c.levelMod
id = id.Parent(bestLevel)
if !c.containsAllChildren(*covering, id) {
break
}
(*covering) = c.replaceCellsWithAncestor(*covering, id)
}
}
}
// isCanonical reports whether the covering is canonical.
func (c *coverer) isCanonical(covering CellUnion) bool {
trueMax := c.maxLevel
if c.levelMod != 1 {
trueMax = c.maxLevel - (c.maxLevel-c.minLevel)%c.levelMod
}
tooManyCells := len(covering) > c.maxCells
sameParentCount := 1
prevID := CellID(0)
for _, id := range covering {
if !id.IsValid() {
return false
}
// Check that the CellID level is acceptable.
level := id.Level()
if level < c.minLevel || level > trueMax {
return false
}
if c.levelMod > 1 && (level-c.minLevel)%c.levelMod != 0 {
return false
}
if prevID != 0 {
// Check that cells are sorted and non-overlapping.
if prevID.RangeMax() >= id.RangeMin() {
return false
}
lev, ok := id.CommonAncestorLevel(prevID)
// If there are too many cells, check that no pair of adjacent cells
// could be replaced by an ancestor.
if tooManyCells && (ok && lev >= c.minLevel) {
return false
}
// Check that there are no sequences of (4 ** level_mod) cells that all
// have the same parent (considering only multiples of "level_mod").
pLevel := level - c.levelMod
if pLevel < c.minLevel || level != prevID.Level() ||
id.Parent(pLevel) != prevID.Parent(pLevel) {
sameParentCount = 1
} else {
sameParentCount++
if sameParentCount == 1<<uint(2*c.levelMod) {
return false
}
}
}
prevID = id
}
return true
}
func (c *coverer) containsAllChildren(covering []CellID, id CellID) bool {
pos := sort.Search(len(covering), func(i int) bool { return (covering)[i] >= id.RangeMin() })
level := id.Level() + c.levelMod
for child := id.ChildBeginAtLevel(level); child != id.ChildEndAtLevel(level); child = child.Next() {
if pos == len(covering) || covering[pos] != child {
return false
}
pos++
}
return true
}
// replaceCellsWithAncestor replaces all descendants of the given id in covering
// with id. This requires the covering contains at least one descendant of id.
func (c *coverer) replaceCellsWithAncestor(covering []CellID, id CellID) []CellID {
begin := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMin() })
end := sort.Search(len(covering), func(i int) bool { return covering[i] > id.RangeMax() })
return append(append(covering[:begin], id), covering[end:]...)
}
// SimpleRegionCovering returns a set of cells at the given level that cover
// the connected region and a starting point on the boundary or inside the
// region. The cells are returned in arbitrary order.
//
// Note that this method is not faster than the regular Covering
// method for most region types, such as Cap or Polygon, and in fact it
// can be much slower when the output consists of a large number of cells.
// Currently it can be faster at generating coverings of long narrow regions
// such as polylines, but this may change in the future.
func SimpleRegionCovering(region Region, start Point, level int) []CellID {
return FloodFillRegionCovering(region, cellIDFromPoint(start).Parent(level))
}
// FloodFillRegionCovering returns all edge-connected cells at the same level as
// the given CellID that intersect the given region, in arbitrary order.
func FloodFillRegionCovering(region Region, start CellID) []CellID {
var output []CellID
all := map[CellID]bool{
start: true,
}
frontier := []CellID{start}
for len(frontier) > 0 {
id := frontier[len(frontier)-1]
frontier = frontier[:len(frontier)-1]
if !region.IntersectsCell(CellFromCellID(id)) {
continue
}
output = append(output, id)
for _, nbr := range id.EdgeNeighbors() {
if !all[nbr] {
all[nbr] = true
frontier = append(frontier, nbr)
}
}
}
return output
}

66
vendor/github.com/golang/geo/s2/regionunion.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// 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
// A RegionUnion represents a union of possibly overlapping regions.
// It is convenient for computing a covering of a set of regions.
type RegionUnion []Region
// CapBound returns a bounding cap for this RegionUnion.
func (ru RegionUnion) CapBound() Cap { return ru.RectBound().CapBound() }
// RectBound returns a bounding latitude-longitude rectangle for this RegionUnion.
func (ru RegionUnion) RectBound() Rect {
ret := EmptyRect()
for _, reg := range ru {
ret = ret.Union(reg.RectBound())
}
return ret
}
// ContainsCell reports whether the given Cell is contained by this RegionUnion.
func (ru RegionUnion) ContainsCell(c Cell) bool {
for _, reg := range ru {
if reg.ContainsCell(c) {
return true
}
}
return false
}
// IntersectsCell reports whether this RegionUnion intersects the given cell.
func (ru RegionUnion) IntersectsCell(c Cell) bool {
for _, reg := range ru {
if reg.IntersectsCell(c) {
return true
}
}
return false
}
// ContainsPoint reports whether this RegionUnion contains the Point.
func (ru RegionUnion) ContainsPoint(p Point) bool {
for _, reg := range ru {
if reg.ContainsPoint(p) {
return true
}
}
return false
}
// CellUnionBound computes a covering of the RegionUnion.
func (ru RegionUnion) CellUnionBound() []CellID {
return ru.CapBound().CellUnionBound()
}

263
vendor/github.com/golang/geo/s2/shape.go generated vendored Normal file
View File

@ -0,0 +1,263 @@
// Copyright 2017 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"
)
// Edge represents a geodesic edge consisting of two vertices. Zero-length edges are
// allowed, and can be used to represent points.
type Edge struct {
V0, V1 Point
}
// Cmp compares the two edges using the underlying Points Cmp method and returns
//
// -1 if e < other
// 0 if e == other
// +1 if e > other
//
// The two edges are compared by first vertex, and then by the second vertex.
func (e Edge) Cmp(other Edge) int {
if v0cmp := e.V0.Cmp(other.V0.Vector); v0cmp != 0 {
return v0cmp
}
return e.V1.Cmp(other.V1.Vector)
}
// sortEdges sorts the slice of Edges in place.
func sortEdges(e []Edge) {
sort.Sort(edges(e))
}
// edges implements the Sort interface for slices of Edge.
type edges []Edge
func (e edges) Len() int { return len(e) }
func (e edges) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e edges) Less(i, j int) bool { return e[i].Cmp(e[j]) == -1 }
// ShapeEdgeID is a unique identifier for an Edge within an ShapeIndex,
// consisting of a (shapeID, edgeID) pair.
type ShapeEdgeID struct {
ShapeID int32
EdgeID int32
}
// Cmp compares the two ShapeEdgeIDs and returns
//
// -1 if s < other
// 0 if s == other
// +1 if s > other
//
// The two are compared first by shape id and then by edge id.
func (s ShapeEdgeID) Cmp(other ShapeEdgeID) int {
switch {
case s.ShapeID < other.ShapeID:
return -1
case s.ShapeID > other.ShapeID:
return 1
}
switch {
case s.EdgeID < other.EdgeID:
return -1
case s.EdgeID > other.EdgeID:
return 1
}
return 0
}
// ShapeEdge represents a ShapeEdgeID with the two endpoints of that Edge.
type ShapeEdge struct {
ID ShapeEdgeID
Edge Edge
}
// Chain represents a range of edge IDs corresponding to a chain of connected
// edges, specified as a (start, length) pair. The chain is defined to consist of
// edge IDs {start, start + 1, ..., start + length - 1}.
type Chain struct {
Start, Length int
}
// ChainPosition represents the position of an edge within a given edge chain,
// specified as a (chainID, offset) pair. Chains are numbered sequentially
// starting from zero, and offsets are measured from the start of each chain.
type ChainPosition struct {
ChainID, Offset int
}
// A ReferencePoint consists of a point and a boolean indicating whether the point
// is contained by a particular shape.
type ReferencePoint struct {
Point Point
Contained bool
}
// OriginReferencePoint returns a ReferencePoint with the given value for
// contained and the origin point. It should be used when all points or no
// points are contained.
func OriginReferencePoint(contained bool) ReferencePoint {
return ReferencePoint{Point: OriginPoint(), Contained: contained}
}
// typeTag is a 32-bit tag that can be used to identify the type of an encoded
// Shape. All encodable types have a non-zero type tag. The tag associated with
type typeTag uint32
const (
// Indicates that a given Shape type cannot be encoded.
typeTagNone typeTag = 0
typeTagPolygon typeTag = 1
typeTagPolyline typeTag = 2
typeTagPointVector typeTag = 3
typeTagLaxPolyline typeTag = 4
typeTagLaxPolygon typeTag = 5
// The minimum allowable tag for future user-defined Shape types.
typeTagMinUser typeTag = 8192
)
// Shape represents polygonal geometry in a flexible way. It is organized as a
// collection of edges that optionally defines an interior. All geometry
// represented by a given Shape must have the same dimension, which means that
// an Shape can represent either a set of points, a set of polylines, or a set
// of polygons.
//
// Shape is defined as an interface in order to give clients control over the
// underlying data representation. Sometimes an Shape does not have any data of
// its own, but instead wraps some other type.
//
// Shape operations are typically defined on a ShapeIndex rather than
// individual shapes. An ShapeIndex is simply a collection of Shapes,
// possibly of different dimensions (e.g. 10 points and 3 polygons), organized
// into a data structure for efficient edge access.
//
// The edges of a Shape are indexed by a contiguous range of edge IDs
// starting at 0. The edges are further subdivided into chains, where each
// chain consists of a sequence of edges connected end-to-end (a polyline).
// For example, a Shape representing two polylines AB and CDE would have
// three edges (AB, CD, DE) grouped into two chains: (AB) and (CD, DE).
// Similarly, an Shape representing 5 points would have 5 chains consisting
// of one edge each.
//
// Shape has methods that allow edges to be accessed either using the global
// numbering (edge ID) or within a particular chain. The global numbering is
// sufficient for most purposes, but the chain representation is useful for
// certain algorithms such as intersection (see BooleanOperation).
type Shape interface {
// NumEdges returns the number of edges in this shape.
NumEdges() int
// Edge returns the edge for the given edge index.
Edge(i int) Edge
// ReferencePoint returns an arbitrary reference point for the shape. (The
// containment boolean value must be false for shapes that do not have an interior.)
//
// This reference point may then be used to compute the containment of other
// points by counting edge crossings.
ReferencePoint() ReferencePoint
// NumChains reports the number of contiguous edge chains in the shape.
// For example, a shape whose edges are [AB, BC, CD, AE, EF] would consist
// of two chains (AB,BC,CD and AE,EF). Every chain is assigned a chain Id
// numbered sequentially starting from zero.
//
// Note that it is always acceptable to implement this method by returning
// NumEdges, i.e. every chain consists of a single edge, but this may
// reduce the efficiency of some algorithms.
NumChains() int
// Chain returns the range of edge IDs corresponding to the given edge chain.
// Edge chains must form contiguous, non-overlapping ranges that cover
// the entire range of edge IDs. This is spelled out more formally below:
//
// 0 <= i < NumChains()
// Chain(i).length > 0, for all i
// Chain(0).start == 0
// Chain(i).start + Chain(i).length == Chain(i+1).start, for i < NumChains()-1
// Chain(i).start + Chain(i).length == NumEdges(), for i == NumChains()-1
Chain(chainID int) Chain
// ChainEdgeReturns the edge at offset "offset" within edge chain "chainID".
// Equivalent to "shape.Edge(shape.Chain(chainID).start + offset)"
// but more efficient.
ChainEdge(chainID, offset int) Edge
// ChainPosition finds the chain containing the given edge, and returns the
// position of that edge as a ChainPosition(chainID, offset) pair.
//
// shape.Chain(pos.chainID).start + pos.offset == edgeID
// shape.Chain(pos.chainID+1).start > edgeID
//
// where pos == shape.ChainPosition(edgeID).
ChainPosition(edgeID int) ChainPosition
// Dimension returns the dimension of the geometry represented by this shape,
// either 0, 1 or 2 for point, polyline and polygon geometry respectively.
//
// 0 - Point geometry. Each point is represented as a degenerate edge.
//
// 1 - Polyline geometry. Polyline edges may be degenerate. A shape may
// represent any number of polylines. Polylines edges may intersect.
//
// 2 - Polygon geometry. Edges should be oriented such that the polygon
// interior is always on the left. In theory the edges may be returned
// in any order, but typically the edges are organized as a collection
// of edge chains where each chain represents one polygon loop.
// Polygons may have degeneracies (e.g., degenerate edges or sibling
// pairs consisting of an edge and its corresponding reversed edge).
// A polygon loop may also be full (containing all points on the
// sphere); by convention this is represented as a chain with no edges.
// (See laxPolygon for details.)
//
// This method allows degenerate geometry of different dimensions
// to be distinguished, e.g. it allows a point to be distinguished from a
// polyline or polygon that has been simplified to a single point.
Dimension() int
// IsEmpty reports whether the Shape contains no points. (Note that the full
// polygon is represented as a chain with zero edges.)
IsEmpty() bool
// IsFull reports whether the Shape contains all points on the sphere.
IsFull() bool
// typeTag returns a value that can be used to identify the type of an
// encoded Shape.
typeTag() typeTag
// We do not support implementations of this interface outside this package.
privateInterface()
}
// defaultShapeIsEmpty reports whether this shape contains no points.
func defaultShapeIsEmpty(s Shape) bool {
return s.NumEdges() == 0 && (s.Dimension() != 2 || s.NumChains() == 0)
}
// defaultShapeIsFull reports whether this shape contains all points on the sphere.
func defaultShapeIsFull(s Shape) bool {
return s.NumEdges() == 0 && s.Dimension() == 2 && s.NumChains() > 0
}
// A minimal check for types that should satisfy the Shape interface.
var (
_ Shape = &Loop{}
_ Shape = &Polygon{}
_ Shape = &Polyline{}
)

1526
vendor/github.com/golang/geo/s2/shapeindex.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

228
vendor/github.com/golang/geo/s2/shapeutil.go generated vendored Normal file
View File

@ -0,0 +1,228 @@
// Copyright 2017 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
// CrossingType defines different ways of reporting edge intersections.
type CrossingType int
const (
// CrossingTypeInterior reports intersections that occur at a point
// interior to both edges (i.e., not at a vertex).
CrossingTypeInterior CrossingType = iota
// CrossingTypeAll reports all intersections, even those where two edges
// intersect only because they share a common vertex.
CrossingTypeAll
// CrossingTypeNonAdjacent reports all intersections except for pairs of
// the form (AB, BC) where both edges are from the same ShapeIndex.
CrossingTypeNonAdjacent
)
// rangeIterator is a wrapper over ShapeIndexIterator with extra methods
// that are useful for merging the contents of two or more ShapeIndexes.
type rangeIterator struct {
it *ShapeIndexIterator
// The min and max leaf cell ids covered by the current cell. If done() is
// true, these methods return a value larger than any valid cell id.
rangeMin CellID
rangeMax CellID
}
// newRangeIterator creates a new rangeIterator positioned at the first cell of the given index.
func newRangeIterator(index *ShapeIndex) *rangeIterator {
r := &rangeIterator{
it: index.Iterator(),
}
r.refresh()
return r
}
func (r *rangeIterator) cellID() CellID { return r.it.CellID() }
func (r *rangeIterator) indexCell() *ShapeIndexCell { return r.it.IndexCell() }
func (r *rangeIterator) next() { r.it.Next(); r.refresh() }
func (r *rangeIterator) done() bool { return r.it.Done() }
// seekTo positions the iterator at the first cell that overlaps or follows
// the current range minimum of the target iterator, i.e. such that its
// rangeMax >= target.rangeMin.
func (r *rangeIterator) seekTo(target *rangeIterator) {
r.it.seek(target.rangeMin)
// If the current cell does not overlap target, it is possible that the
// previous cell is the one we are looking for. This can only happen when
// the previous cell contains target but has a smaller CellID.
if r.it.Done() || r.it.CellID().RangeMin() > target.rangeMax {
if r.it.Prev() && r.it.CellID().RangeMax() < target.cellID() {
r.it.Next()
}
}
r.refresh()
}
// seekBeyond positions the iterator at the first cell that follows the current
// range minimum of the target iterator. i.e. the first cell such that its
// rangeMin > target.rangeMax.
func (r *rangeIterator) seekBeyond(target *rangeIterator) {
r.it.seek(target.rangeMax.Next())
if !r.it.Done() && r.it.CellID().RangeMin() <= target.rangeMax {
r.it.Next()
}
r.refresh()
}
// refresh updates the iterators min and max values.
func (r *rangeIterator) refresh() {
r.rangeMin = r.cellID().RangeMin()
r.rangeMax = r.cellID().RangeMax()
}
// referencePointForShape is a helper function for implementing various Shapes
// ReferencePoint functions.
//
// Given a shape consisting of closed polygonal loops, the interior of the
// shape is defined as the region to the left of all edges (which must be
// oriented consistently). This function then chooses an arbitrary point and
// returns true if that point is contained by the shape.
//
// Unlike Loop and Polygon, this method allows duplicate vertices and
// edges, which requires some extra care with definitions. The rule that we
// apply is that an edge and its reverse edge cancel each other: the result
// is the same as if that edge pair were not present. Therefore shapes that
// consist only of degenerate loop(s) are either empty or full; by convention,
// the shape is considered full if and only if it contains an empty loop (see
// laxPolygon for details).
//
// Determining whether a loop on the sphere contains a point is harder than
// the corresponding problem in 2D plane geometry. It cannot be implemented
// just by counting edge crossings because there is no such thing as a point
// at infinity that is guaranteed to be outside the loop.
//
// This function requires that the given Shape have an interior.
func referencePointForShape(shape Shape) ReferencePoint {
if shape.NumEdges() == 0 {
// A shape with no edges is defined to be full if and only if it
// contains at least one chain.
return OriginReferencePoint(shape.NumChains() > 0)
}
// Define a "matched" edge as one that can be paired with a corresponding
// reversed edge. Define a vertex as "balanced" if all of its edges are
// matched. In order to determine containment, we must find an unbalanced
// vertex. Often every vertex is unbalanced, so we start by trying an
// arbitrary vertex.
edge := shape.Edge(0)
if ref, ok := referencePointAtVertex(shape, edge.V0); ok {
return ref
}
// That didn't work, so now we do some extra work to find an unbalanced
// vertex (if any). Essentially we gather a list of edges and a list of
// reversed edges, and then sort them. The first edge that appears in one
// list but not the other is guaranteed to be unmatched.
n := shape.NumEdges()
var edges = make([]Edge, n)
var revEdges = make([]Edge, n)
for i := 0; i < n; i++ {
edge := shape.Edge(i)
edges[i] = edge
revEdges[i] = Edge{V0: edge.V1, V1: edge.V0}
}
sortEdges(edges)
sortEdges(revEdges)
for i := 0; i < n; i++ {
if edges[i].Cmp(revEdges[i]) == -1 { // edges[i] is unmatched
if ref, ok := referencePointAtVertex(shape, edges[i].V0); ok {
return ref
}
}
if revEdges[i].Cmp(edges[i]) == -1 { // revEdges[i] is unmatched
if ref, ok := referencePointAtVertex(shape, revEdges[i].V0); ok {
return ref
}
}
}
// All vertices are balanced, so this polygon is either empty or full except
// for degeneracies. By convention it is defined to be full if it contains
// any chain with no edges.
for i := 0; i < shape.NumChains(); i++ {
if shape.Chain(i).Length == 0 {
return OriginReferencePoint(true)
}
}
return OriginReferencePoint(false)
}
// referencePointAtVertex reports whether the given vertex is unbalanced, and
// returns a ReferencePoint indicating if the point is contained.
// Otherwise returns false.
func referencePointAtVertex(shape Shape, vTest Point) (ReferencePoint, bool) {
var ref ReferencePoint
// Let P be an unbalanced vertex. Vertex P is defined to be inside the
// region if the region contains a particular direction vector starting from
// P, namely the direction p.Ortho(). This can be calculated using
// ContainsVertexQuery.
containsQuery := NewContainsVertexQuery(vTest)
n := shape.NumEdges()
for e := 0; e < n; e++ {
edge := shape.Edge(e)
if edge.V0 == vTest {
containsQuery.AddEdge(edge.V1, 1)
}
if edge.V1 == vTest {
containsQuery.AddEdge(edge.V0, -1)
}
}
containsSign := containsQuery.ContainsVertex()
if containsSign == 0 {
return ref, false // There are no unmatched edges incident to this vertex.
}
ref.Point = vTest
ref.Contained = containsSign > 0
return ref, true
}
// containsBruteForce reports whether the given shape contains the given point.
// Most clients should not use this method, since its running time is linear in
// the number of shape edges. Instead clients should create a ShapeIndex and use
// ContainsPointQuery, since this strategy is much more efficient when many
// points need to be tested.
//
// Polygon boundaries are treated as being semi-open (see ContainsPointQuery
// and VertexModel for other options).
func containsBruteForce(shape Shape, point Point) bool {
if shape.Dimension() != 2 {
return false
}
refPoint := shape.ReferencePoint()
if refPoint.Point == point {
return refPoint.Contained
}
crosser := NewEdgeCrosser(refPoint.Point, point)
inside := refPoint.Contained
for e := 0; e < shape.NumEdges(); e++ {
edge := shape.Edge(e)
inside = inside != crosser.EdgeOrVertexCrossing(edge.V0, edge.V1)
}
return inside
}

View File

@ -0,0 +1,72 @@
// 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
// EdgeIterator is an iterator that advances through all edges in an ShapeIndex.
// This is different to the ShapeIndexIterator, which advances through the cells in the
// ShapeIndex.
type EdgeIterator struct {
index *ShapeIndex
shapeID int32
numEdges int32
edgeID int32
}
// NewEdgeIterator creates a new edge iterator for the given index.
func NewEdgeIterator(index *ShapeIndex) *EdgeIterator {
e := &EdgeIterator{
index: index,
shapeID: -1,
edgeID: -1,
}
e.Next()
return e
}
// ShapeID returns the current shape ID.
func (e *EdgeIterator) ShapeID() int32 { return e.shapeID }
// EdgeID returns the current edge ID.
func (e *EdgeIterator) EdgeID() int32 { return e.edgeID }
// ShapeEdgeID returns the current (shapeID, edgeID).
func (e *EdgeIterator) ShapeEdgeID() ShapeEdgeID { return ShapeEdgeID{e.shapeID, e.edgeID} }
// Edge returns the current edge.
func (e *EdgeIterator) Edge() Edge {
return e.index.Shape(e.shapeID).Edge(int(e.edgeID))
}
// Done reports if the iterator is positioned at or after the last index edge.
func (e *EdgeIterator) Done() bool { return e.shapeID >= int32(len(e.index.shapes)) }
// Next positions the iterator at the next index edge.
func (e *EdgeIterator) Next() {
e.edgeID++
for ; e.edgeID >= e.numEdges; e.edgeID++ {
e.shapeID++
if e.shapeID >= int32(len(e.index.shapes)) {
break
}
shape := e.index.Shape(e.shapeID)
if shape == nil {
e.numEdges = 0
} else {
e.numEdges = int32(shape.NumEdges())
}
e.edgeID = -1
}
}

427
vendor/github.com/golang/geo/s2/stuv.go generated vendored Normal file
View File

@ -0,0 +1,427 @@
// 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 (
"math"
"github.com/golang/geo/r3"
)
//
// This file contains documentation of the various coordinate systems used
// throughout the library. Most importantly, S2 defines a framework for
// decomposing the unit sphere into a hierarchy of "cells". Each cell is a
// quadrilateral bounded by four geodesics. The top level of the hierarchy is
// obtained by projecting the six faces of a cube onto the unit sphere, and
// lower levels are obtained by subdividing each cell into four children
// recursively. Cells are numbered such that sequentially increasing cells
// follow a continuous space-filling curve over the entire sphere. The
// transformation is designed to make the cells at each level fairly uniform
// in size.
//
////////////////////////// S2 Cell Decomposition /////////////////////////
//
// The following methods define the cube-to-sphere projection used by
// the Cell decomposition.
//
// In the process of converting a latitude-longitude pair to a 64-bit cell
// id, the following coordinate systems are used:
//
// (id)
// An CellID is a 64-bit encoding of a face and a Hilbert curve position
// on that face. The Hilbert curve position implicitly encodes both the
// position of a cell and its subdivision level (see s2cellid.go).
//
// (face, i, j)
// Leaf-cell coordinates. "i" and "j" are integers in the range
// [0,(2**30)-1] that identify a particular leaf cell on the given face.
// The (i, j) coordinate system is right-handed on each face, and the
// faces are oriented such that Hilbert curves connect continuously from
// one face to the next.
//
// (face, s, t)
// Cell-space coordinates. "s" and "t" are real numbers in the range
// [0,1] that identify a point on the given face. For example, the point
// (s, t) = (0.5, 0.5) corresponds to the center of the top-level face
// cell. This point is also a vertex of exactly four cells at each
// subdivision level greater than zero.
//
// (face, si, ti)
// Discrete cell-space coordinates. These are obtained by multiplying
// "s" and "t" by 2**31 and rounding to the nearest unsigned integer.
// Discrete coordinates lie in the range [0,2**31]. This coordinate
// system can represent the edge and center positions of all cells with
// no loss of precision (including non-leaf cells). In binary, each
// coordinate of a level-k cell center ends with a 1 followed by
// (30 - k) 0s. The coordinates of its edges end with (at least)
// (31 - k) 0s.
//
// (face, u, v)
// Cube-space coordinates in the range [-1,1]. To make the cells at each
// level more uniform in size after they are projected onto the sphere,
// we apply a nonlinear transformation of the form u=f(s), v=f(t).
// The (u, v) coordinates after this transformation give the actual
// coordinates on the cube face (modulo some 90 degree rotations) before
// it is projected onto the unit sphere.
//
// (face, u, v, w)
// Per-face coordinate frame. This is an extension of the (face, u, v)
// cube-space coordinates that adds a third axis "w" in the direction of
// the face normal. It is always a right-handed 3D coordinate system.
// Cube-space coordinates can be converted to this frame by setting w=1,
// while (u,v,w) coordinates can be projected onto the cube face by
// dividing by w, i.e. (face, u/w, v/w).
//
// (x, y, z)
// Direction vector (Point). Direction vectors are not necessarily unit
// length, and are often chosen to be points on the biunit cube
// [-1,+1]x[-1,+1]x[-1,+1]. They can be be normalized to obtain the
// corresponding point on the unit sphere.
//
// (lat, lng)
// Latitude and longitude (LatLng). Latitudes must be between -90 and
// 90 degrees inclusive, and longitudes must be between -180 and 180
// degrees inclusive.
//
// Note that the (i, j), (s, t), (si, ti), and (u, v) coordinate systems are
// right-handed on all six faces.
//
//
// There are a number of different projections from cell-space (s,t) to
// cube-space (u,v): linear, quadratic, and tangent. They have the following
// tradeoffs:
//
// Linear - This is the fastest transformation, but also produces the least
// uniform cell sizes. Cell areas vary by a factor of about 5.2, with the
// largest cells at the center of each face and the smallest cells in
// the corners.
//
// Tangent - Transforming the coordinates via Atan makes the cell sizes
// more uniform. The areas vary by a maximum ratio of 1.4 as opposed to a
// maximum ratio of 5.2. However, each call to Atan is about as expensive
// as all of the other calculations combined when converting from points to
// cell ids, i.e. it reduces performance by a factor of 3.
//
// Quadratic - This is an approximation of the tangent projection that
// is much faster and produces cells that are almost as uniform in size.
// It is about 3 times faster than the tangent projection for converting
// cell ids to points or vice versa. Cell areas vary by a maximum ratio of
// about 2.1.
//
// Here is a table comparing the cell uniformity using each projection. Area
// Ratio is the maximum ratio over all subdivision levels of the largest cell
// area to the smallest cell area at that level, Edge Ratio is the maximum
// ratio of the longest edge of any cell to the shortest edge of any cell at
// the same level, and Diag Ratio is the ratio of the longest diagonal of
// any cell to the shortest diagonal of any cell at the same level.
//
// Area Edge Diag
// Ratio Ratio Ratio
// -----------------------------------
// Linear: 5.200 2.117 2.959
// Tangent: 1.414 1.414 1.704
// Quadratic: 2.082 1.802 1.932
//
// The worst-case cell aspect ratios are about the same with all three
// projections. The maximum ratio of the longest edge to the shortest edge
// within the same cell is about 1.4 and the maximum ratio of the diagonals
// within the same cell is about 1.7.
//
// For Go we have chosen to use only the Quadratic approach. Other language
// implementations may offer other choices.
const (
// maxSiTi is the maximum value of an si- or ti-coordinate.
// It is one shift more than maxSize. The range of valid (si,ti)
// values is [0..maxSiTi].
maxSiTi = maxSize << 1
)
// siTiToST converts an si- or ti-value to the corresponding s- or t-value.
// Value is capped at 1.0 because there is no DCHECK in Go.
func siTiToST(si uint32) float64 {
if si > maxSiTi {
return 1.0
}
return float64(si) / float64(maxSiTi)
}
// stToSiTi converts the s- or t-value to the nearest si- or ti-coordinate.
// The result may be outside the range of valid (si,ti)-values. Value of
// 0.49999999999999994 (math.NextAfter(0.5, -1)), will be incorrectly rounded up.
func stToSiTi(s float64) uint32 {
if s < 0 {
return uint32(s*maxSiTi - 0.5)
}
return uint32(s*maxSiTi + 0.5)
}
// stToUV converts an s or t value to the corresponding u or v value.
// This is a non-linear transformation from [-1,1] to [-1,1] that
// attempts to make the cell sizes more uniform.
// This uses what the C++ version calls 'the quadratic transform'.
func stToUV(s float64) float64 {
if s >= 0.5 {
return (1 / 3.) * (4*s*s - 1)
}
return (1 / 3.) * (1 - 4*(1-s)*(1-s))
}
// uvToST is the inverse of the stToUV transformation. Note that it
// is not always true that uvToST(stToUV(x)) == x due to numerical
// errors.
func uvToST(u float64) float64 {
if u >= 0 {
return 0.5 * math.Sqrt(1+3*u)
}
return 1 - 0.5*math.Sqrt(1-3*u)
}
// face returns face ID from 0 to 5 containing the r. For points on the
// boundary between faces, the result is arbitrary but deterministic.
func face(r r3.Vector) int {
f := r.LargestComponent()
switch {
case f == r3.XAxis && r.X < 0:
f += 3
case f == r3.YAxis && r.Y < 0:
f += 3
case f == r3.ZAxis && r.Z < 0:
f += 3
}
return int(f)
}
// validFaceXYZToUV given a valid face for the given point r (meaning that
// dot product of r with the face normal is positive), returns
// the corresponding u and v values, which may lie outside the range [-1,1].
func validFaceXYZToUV(face int, r r3.Vector) (float64, float64) {
switch face {
case 0:
return r.Y / r.X, r.Z / r.X
case 1:
return -r.X / r.Y, r.Z / r.Y
case 2:
return -r.X / r.Z, -r.Y / r.Z
case 3:
return r.Z / r.X, r.Y / r.X
case 4:
return r.Z / r.Y, -r.X / r.Y
}
return -r.Y / r.Z, -r.X / r.Z
}
// xyzToFaceUV converts a direction vector (not necessarily unit length) to
// (face, u, v) coordinates.
func xyzToFaceUV(r r3.Vector) (f int, u, v float64) {
f = face(r)
u, v = validFaceXYZToUV(f, r)
return f, u, v
}
// faceUVToXYZ turns face and UV coordinates into an unnormalized 3 vector.
func faceUVToXYZ(face int, u, v float64) r3.Vector {
switch face {
case 0:
return r3.Vector{1, u, v}
case 1:
return r3.Vector{-u, 1, v}
case 2:
return r3.Vector{-u, -v, 1}
case 3:
return r3.Vector{-1, -v, -u}
case 4:
return r3.Vector{v, -1, -u}
default:
return r3.Vector{v, u, -1}
}
}
// faceXYZToUV returns the u and v values (which may lie outside the range
// [-1, 1]) if the dot product of the point p with the given face normal is positive.
func faceXYZToUV(face int, p Point) (u, v float64, ok bool) {
switch face {
case 0:
if p.X <= 0 {
return 0, 0, false
}
case 1:
if p.Y <= 0 {
return 0, 0, false
}
case 2:
if p.Z <= 0 {
return 0, 0, false
}
case 3:
if p.X >= 0 {
return 0, 0, false
}
case 4:
if p.Y >= 0 {
return 0, 0, false
}
default:
if p.Z >= 0 {
return 0, 0, false
}
}
u, v = validFaceXYZToUV(face, p.Vector)
return u, v, true
}
// faceXYZtoUVW transforms the given point P to the (u,v,w) coordinate frame of the given
// face where the w-axis represents the face normal.
func faceXYZtoUVW(face int, p Point) Point {
// The result coordinates are simply the dot products of P with the (u,v,w)
// axes for the given face (see faceUVWAxes).
switch face {
case 0:
return Point{r3.Vector{p.Y, p.Z, p.X}}
case 1:
return Point{r3.Vector{-p.X, p.Z, p.Y}}
case 2:
return Point{r3.Vector{-p.X, -p.Y, p.Z}}
case 3:
return Point{r3.Vector{-p.Z, -p.Y, -p.X}}
case 4:
return Point{r3.Vector{-p.Z, p.X, -p.Y}}
default:
return Point{r3.Vector{p.Y, p.X, -p.Z}}
}
}
// faceSiTiToXYZ transforms the (si, ti) coordinates to a (not necessarily
// unit length) Point on the given face.
func faceSiTiToXYZ(face int, si, ti uint32) Point {
return Point{faceUVToXYZ(face, stToUV(siTiToST(si)), stToUV(siTiToST(ti)))}
}
// xyzToFaceSiTi transforms the (not necessarily unit length) Point to
// (face, si, ti) coordinates and the level the Point is at.
func xyzToFaceSiTi(p Point) (face int, si, ti uint32, level int) {
face, u, v := xyzToFaceUV(p.Vector)
si = stToSiTi(uvToST(u))
ti = stToSiTi(uvToST(v))
// If the levels corresponding to si,ti are not equal, then p is not a cell
// center. The si,ti values of 0 and maxSiTi need to be handled specially
// because they do not correspond to cell centers at any valid level; they
// are mapped to level -1 by the code at the end.
level = maxLevel - findLSBSetNonZero64(uint64(si|maxSiTi))
if level < 0 || level != maxLevel-findLSBSetNonZero64(uint64(ti|maxSiTi)) {
return face, si, ti, -1
}
// In infinite precision, this test could be changed to ST == SiTi. However,
// due to rounding errors, uvToST(xyzToFaceUV(faceUVToXYZ(stToUV(...)))) is
// not idempotent. On the other hand, the center is computed exactly the same
// way p was originally computed (if it is indeed the center of a Cell);
// the comparison can be exact.
if p.Vector == faceSiTiToXYZ(face, si, ti).Normalize() {
return face, si, ti, level
}
return face, si, ti, -1
}
// uNorm returns the right-handed normal (not necessarily unit length) for an
// edge in the direction of the positive v-axis at the given u-value on
// the given face. (This vector is perpendicular to the plane through
// the sphere origin that contains the given edge.)
func uNorm(face int, u float64) r3.Vector {
switch face {
case 0:
return r3.Vector{u, -1, 0}
case 1:
return r3.Vector{1, u, 0}
case 2:
return r3.Vector{1, 0, u}
case 3:
return r3.Vector{-u, 0, 1}
case 4:
return r3.Vector{0, -u, 1}
default:
return r3.Vector{0, -1, -u}
}
}
// vNorm returns the right-handed normal (not necessarily unit length) for an
// edge in the direction of the positive u-axis at the given v-value on
// the given face.
func vNorm(face int, v float64) r3.Vector {
switch face {
case 0:
return r3.Vector{-v, 0, 1}
case 1:
return r3.Vector{0, -v, 1}
case 2:
return r3.Vector{0, -1, -v}
case 3:
return r3.Vector{v, -1, 0}
case 4:
return r3.Vector{1, v, 0}
default:
return r3.Vector{1, 0, v}
}
}
// faceUVWAxes are the U, V, and W axes for each face.
var faceUVWAxes = [6][3]Point{
{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{1, 0, 0}}},
{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, 0, 1}}, Point{r3.Vector{0, 1, 0}}},
{Point{r3.Vector{-1, 0, 0}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{0, 0, 1}}},
{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{0, -1, 0}}, Point{r3.Vector{-1, 0, 0}}},
{Point{r3.Vector{0, 0, -1}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, -1, 0}}},
{Point{r3.Vector{0, 1, 0}}, Point{r3.Vector{1, 0, 0}}, Point{r3.Vector{0, 0, -1}}},
}
// faceUVWFaces are the precomputed neighbors of each face.
var faceUVWFaces = [6][3][2]int{
{{4, 1}, {5, 2}, {3, 0}},
{{0, 3}, {5, 2}, {4, 1}},
{{0, 3}, {1, 4}, {5, 2}},
{{2, 5}, {1, 4}, {0, 3}},
{{2, 5}, {3, 0}, {1, 4}},
{{4, 1}, {3, 0}, {2, 5}},
}
// uvwAxis returns the given axis of the given face.
func uvwAxis(face, axis int) Point {
return faceUVWAxes[face][axis]
}
// uvwFaces returns the face in the (u,v,w) coordinate system on the given axis
// in the given direction.
func uvwFace(face, axis, direction int) int {
return faceUVWFaces[face][axis][direction]
}
// uAxis returns the u-axis for the given face.
func uAxis(face int) Point {
return uvwAxis(face, 0)
}
// vAxis returns the v-axis for the given face.
func vAxis(face int) Point {
return uvwAxis(face, 1)
}
// Return the unit-length normal for the given face.
func unitNorm(face int) Point {
return uvwAxis(face, 2)
}

125
vendor/github.com/golang/geo/s2/util.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
// Copyright 2017 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 "github.com/golang/geo/s1"
// roundAngle returns the value rounded to nearest as an int32.
// This does not match C++ exactly for the case of x.5.
func roundAngle(val s1.Angle) int32 {
if val < 0 {
return int32(val - 0.5)
}
return int32(val + 0.5)
}
// minAngle returns the smallest of the given values.
func minAngle(x s1.Angle, others ...s1.Angle) s1.Angle {
min := x
for _, y := range others {
if y < min {
min = y
}
}
return min
}
// maxAngle returns the largest of the given values.
func maxAngle(x s1.Angle, others ...s1.Angle) s1.Angle {
max := x
for _, y := range others {
if y > max {
max = y
}
}
return max
}
// minChordAngle returns the smallest of the given values.
func minChordAngle(x s1.ChordAngle, others ...s1.ChordAngle) s1.ChordAngle {
min := x
for _, y := range others {
if y < min {
min = y
}
}
return min
}
// maxChordAngle returns the largest of the given values.
func maxChordAngle(x s1.ChordAngle, others ...s1.ChordAngle) s1.ChordAngle {
max := x
for _, y := range others {
if y > max {
max = y
}
}
return max
}
// minFloat64 returns the smallest of the given values.
func minFloat64(x float64, others ...float64) float64 {
min := x
for _, y := range others {
if y < min {
min = y
}
}
return min
}
// maxFloat64 returns the largest of the given values.
func maxFloat64(x float64, others ...float64) float64 {
max := x
for _, y := range others {
if y > max {
max = y
}
}
return max
}
// minInt returns the smallest of the given values.
func minInt(x int, others ...int) int {
min := x
for _, y := range others {
if y < min {
min = y
}
}
return min
}
// maxInt returns the largest of the given values.
func maxInt(x int, others ...int) int {
max := x
for _, y := range others {
if y > max {
max = y
}
}
return max
}
// clampInt returns the number closest to x within the range min..max.
func clampInt(x, min, max int) int {
if x < min {
return min
}
if x > max {
return max
}
return x
}

97
vendor/github.com/golang/geo/s2/wedge_relations.go generated vendored Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2017 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
// WedgeRel enumerates the possible relation between two wedges A and B.
type WedgeRel int
// Define the different possible relationships between two wedges.
//
// Given an edge chain (x0, x1, x2), the wedge at x1 is the region to the
// left of the edges. More precisely, it is the set of all rays from x1x0
// (inclusive) to x1x2 (exclusive) in the *clockwise* direction.
const (
WedgeEquals WedgeRel = iota // A and B are equal.
WedgeProperlyContains // A is a strict superset of B.
WedgeIsProperlyContained // A is a strict subset of B.
WedgeProperlyOverlaps // A-B, B-A, and A intersect B are non-empty.
WedgeIsDisjoint // A and B are disjoint.
)
// WedgeRelation reports the relation between two non-empty wedges
// A=(a0, ab1, a2) and B=(b0, ab1, b2).
func WedgeRelation(a0, ab1, a2, b0, b2 Point) WedgeRel {
// There are 6 possible edge orderings at a shared vertex (all
// of these orderings are circular, i.e. abcd == bcda):
//
// (1) a2 b2 b0 a0: A contains B
// (2) a2 a0 b0 b2: B contains A
// (3) a2 a0 b2 b0: A and B are disjoint
// (4) a2 b0 a0 b2: A and B intersect in one wedge
// (5) a2 b2 a0 b0: A and B intersect in one wedge
// (6) a2 b0 b2 a0: A and B intersect in two wedges
//
// We do not distinguish between 4, 5, and 6.
// We pay extra attention when some of the edges overlap. When edges
// overlap, several of these orderings can be satisfied, and we take
// the most specific.
if a0 == b0 && a2 == b2 {
return WedgeEquals
}
// Cases 1, 2, 5, and 6
if OrderedCCW(a0, a2, b2, ab1) {
// The cases with this vertex ordering are 1, 5, and 6,
if OrderedCCW(b2, b0, a0, ab1) {
return WedgeProperlyContains
}
// We are in case 5 or 6, or case 2 if a2 == b2.
if a2 == b2 {
return WedgeIsProperlyContained
}
return WedgeProperlyOverlaps
}
// We are in case 2, 3, or 4.
if OrderedCCW(a0, b0, b2, ab1) {
return WedgeIsProperlyContained
}
if OrderedCCW(a0, b0, a2, ab1) {
return WedgeIsDisjoint
}
return WedgeProperlyOverlaps
}
// WedgeContains reports whether non-empty wedge A=(a0, ab1, a2) contains B=(b0, ab1, b2).
// Equivalent to WedgeRelation == WedgeProperlyContains || WedgeEquals.
func WedgeContains(a0, ab1, a2, b0, b2 Point) bool {
// For A to contain B (where each loop interior is defined to be its left
// side), the CCW edge order around ab1 must be a2 b2 b0 a0. We split
// this test into two parts that test three vertices each.
return OrderedCCW(a2, b2, b0, ab1) && OrderedCCW(b0, a0, a2, ab1)
}
// WedgeIntersects reports whether non-empty wedge A=(a0, ab1, a2) intersects B=(b0, ab1, b2).
// Equivalent but faster than WedgeRelation != WedgeIsDisjoint
func WedgeIntersects(a0, ab1, a2, b0, b2 Point) bool {
// For A not to intersect B (where each loop interior is defined to be
// its left side), the CCW edge order around ab1 must be a0 b2 b0 a2.
// Note that it's important to write these conditions as negatives
// (!OrderedCCW(a,b,c,o) rather than Ordered(c,b,a,o)) to get correct
// results when two vertices are the same.
return !(OrderedCCW(a0, b2, b0, ab1) && OrderedCCW(b0, a2, a0, ab1))
}

3
vendor/github.com/golang/protobuf/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

3
vendor/github.com/golang/protobuf/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

28
vendor/github.com/golang/protobuf/LICENSE generated vendored Normal file
View File

@ -0,0 +1,28 @@
Copyright 2010 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

324
vendor/github.com/golang/protobuf/proto/buffer.go generated vendored Normal file
View File

@ -0,0 +1,324 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"errors"
"fmt"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/runtime/protoimpl"
)
const (
WireVarint = 0
WireFixed32 = 5
WireFixed64 = 1
WireBytes = 2
WireStartGroup = 3
WireEndGroup = 4
)
// EncodeVarint returns the varint encoded bytes of v.
func EncodeVarint(v uint64) []byte {
return protowire.AppendVarint(nil, v)
}
// SizeVarint returns the length of the varint encoded bytes of v.
// This is equal to len(EncodeVarint(v)).
func SizeVarint(v uint64) int {
return protowire.SizeVarint(v)
}
// DecodeVarint parses a varint encoded integer from b,
// returning the integer value and the length of the varint.
// It returns (0, 0) if there is a parse error.
func DecodeVarint(b []byte) (uint64, int) {
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return 0, 0
}
return v, n
}
// Buffer is a buffer for encoding and decoding the protobuf wire format.
// It may be reused between invocations to reduce memory usage.
type Buffer struct {
buf []byte
idx int
deterministic bool
}
// NewBuffer allocates a new Buffer initialized with buf,
// where the contents of buf are considered the unread portion of the buffer.
func NewBuffer(buf []byte) *Buffer {
return &Buffer{buf: buf}
}
// SetDeterministic specifies whether to use deterministic serialization.
//
// Deterministic serialization guarantees that for a given binary, equal
// messages will always be serialized to the same bytes. This implies:
//
// - Repeated serialization of a message will return the same bytes.
// - Different processes of the same binary (which may be executing on
// different machines) will serialize equal messages to the same bytes.
//
// Note that the deterministic serialization is NOT canonical across
// languages. It is not guaranteed to remain stable over time. It is unstable
// across different builds with schema changes due to unknown fields.
// Users who need canonical serialization (e.g., persistent storage in a
// canonical form, fingerprinting, etc.) should define their own
// canonicalization specification and implement their own serializer rather
// than relying on this API.
//
// If deterministic serialization is requested, map entries will be sorted
// by keys in lexographical order. This is an implementation detail and
// subject to change.
func (b *Buffer) SetDeterministic(deterministic bool) {
b.deterministic = deterministic
}
// SetBuf sets buf as the internal buffer,
// where the contents of buf are considered the unread portion of the buffer.
func (b *Buffer) SetBuf(buf []byte) {
b.buf = buf
b.idx = 0
}
// Reset clears the internal buffer of all written and unread data.
func (b *Buffer) Reset() {
b.buf = b.buf[:0]
b.idx = 0
}
// Bytes returns the internal buffer.
func (b *Buffer) Bytes() []byte {
return b.buf
}
// Unread returns the unread portion of the buffer.
func (b *Buffer) Unread() []byte {
return b.buf[b.idx:]
}
// Marshal appends the wire-format encoding of m to the buffer.
func (b *Buffer) Marshal(m Message) error {
var err error
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
return err
}
// Unmarshal parses the wire-format message in the buffer and
// places the decoded results in m.
// It does not reset m before unmarshaling.
func (b *Buffer) Unmarshal(m Message) error {
err := UnmarshalMerge(b.Unread(), m)
b.idx = len(b.buf)
return err
}
type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields }
func (m *unknownFields) String() string { panic("not implemented") }
func (m *unknownFields) Reset() { panic("not implemented") }
func (m *unknownFields) ProtoMessage() { panic("not implemented") }
// DebugPrint dumps the encoded bytes of b with a header and footer including s
// to stdout. This is only intended for debugging.
func (*Buffer) DebugPrint(s string, b []byte) {
m := MessageReflect(new(unknownFields))
m.SetUnknown(b)
b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface())
fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s)
}
// EncodeVarint appends an unsigned varint encoding to the buffer.
func (b *Buffer) EncodeVarint(v uint64) error {
b.buf = protowire.AppendVarint(b.buf, v)
return nil
}
// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer.
func (b *Buffer) EncodeZigzag32(v uint64) error {
return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
}
// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer.
func (b *Buffer) EncodeZigzag64(v uint64) error {
return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63))))
}
// EncodeFixed32 appends a 32-bit little-endian integer to the buffer.
func (b *Buffer) EncodeFixed32(v uint64) error {
b.buf = protowire.AppendFixed32(b.buf, uint32(v))
return nil
}
// EncodeFixed64 appends a 64-bit little-endian integer to the buffer.
func (b *Buffer) EncodeFixed64(v uint64) error {
b.buf = protowire.AppendFixed64(b.buf, uint64(v))
return nil
}
// EncodeRawBytes appends a length-prefixed raw bytes to the buffer.
func (b *Buffer) EncodeRawBytes(v []byte) error {
b.buf = protowire.AppendBytes(b.buf, v)
return nil
}
// EncodeStringBytes appends a length-prefixed raw bytes to the buffer.
// It does not validate whether v contains valid UTF-8.
func (b *Buffer) EncodeStringBytes(v string) error {
b.buf = protowire.AppendString(b.buf, v)
return nil
}
// EncodeMessage appends a length-prefixed encoded message to the buffer.
func (b *Buffer) EncodeMessage(m Message) error {
var err error
b.buf = protowire.AppendVarint(b.buf, uint64(Size(m)))
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
return err
}
// DecodeVarint consumes an encoded unsigned varint from the buffer.
func (b *Buffer) DecodeVarint() (uint64, error) {
v, n := protowire.ConsumeVarint(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer.
func (b *Buffer) DecodeZigzag32() (uint64, error) {
v, err := b.DecodeVarint()
if err != nil {
return 0, err
}
return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil
}
// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer.
func (b *Buffer) DecodeZigzag64() (uint64, error) {
v, err := b.DecodeVarint()
if err != nil {
return 0, err
}
return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil
}
// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer.
func (b *Buffer) DecodeFixed32() (uint64, error) {
v, n := protowire.ConsumeFixed32(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer.
func (b *Buffer) DecodeFixed64() (uint64, error) {
v, n := protowire.ConsumeFixed64(b.buf[b.idx:])
if n < 0 {
return 0, protowire.ParseError(n)
}
b.idx += n
return uint64(v), nil
}
// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer.
// If alloc is specified, it returns a copy the raw bytes
// rather than a sub-slice of the buffer.
func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) {
v, n := protowire.ConsumeBytes(b.buf[b.idx:])
if n < 0 {
return nil, protowire.ParseError(n)
}
b.idx += n
if alloc {
v = append([]byte(nil), v...)
}
return v, nil
}
// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer.
// It does not validate whether the raw bytes contain valid UTF-8.
func (b *Buffer) DecodeStringBytes() (string, error) {
v, n := protowire.ConsumeString(b.buf[b.idx:])
if n < 0 {
return "", protowire.ParseError(n)
}
b.idx += n
return v, nil
}
// DecodeMessage consumes a length-prefixed message from the buffer.
// It does not reset m before unmarshaling.
func (b *Buffer) DecodeMessage(m Message) error {
v, err := b.DecodeRawBytes(false)
if err != nil {
return err
}
return UnmarshalMerge(v, m)
}
// DecodeGroup consumes a message group from the buffer.
// It assumes that the start group marker has already been consumed and
// consumes all bytes until (and including the end group marker).
// It does not reset m before unmarshaling.
func (b *Buffer) DecodeGroup(m Message) error {
v, n, err := consumeGroup(b.buf[b.idx:])
if err != nil {
return err
}
b.idx += n
return UnmarshalMerge(v, m)
}
// consumeGroup parses b until it finds an end group marker, returning
// the raw bytes of the message (excluding the end group marker) and the
// the total length of the message (including the end group marker).
func consumeGroup(b []byte) ([]byte, int, error) {
b0 := b
depth := 1 // assume this follows a start group marker
for {
_, wtyp, tagLen := protowire.ConsumeTag(b)
if tagLen < 0 {
return nil, 0, protowire.ParseError(tagLen)
}
b = b[tagLen:]
var valLen int
switch wtyp {
case protowire.VarintType:
_, valLen = protowire.ConsumeVarint(b)
case protowire.Fixed32Type:
_, valLen = protowire.ConsumeFixed32(b)
case protowire.Fixed64Type:
_, valLen = protowire.ConsumeFixed64(b)
case protowire.BytesType:
_, valLen = protowire.ConsumeBytes(b)
case protowire.StartGroupType:
depth++
case protowire.EndGroupType:
depth--
default:
return nil, 0, errors.New("proto: cannot parse reserved wire type")
}
if valLen < 0 {
return nil, 0, protowire.ParseError(valLen)
}
b = b[valLen:]
if depth == 0 {
return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil
}
}
}

63
vendor/github.com/golang/protobuf/proto/defaults.go generated vendored Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// SetDefaults sets unpopulated scalar fields to their default values.
// Fields within a oneof are not set even if they have a default value.
// SetDefaults is recursively called upon any populated message fields.
func SetDefaults(m Message) {
if m != nil {
setDefaults(MessageReflect(m))
}
}
func setDefaults(m protoreflect.Message) {
fds := m.Descriptor().Fields()
for i := 0; i < fds.Len(); i++ {
fd := fds.Get(i)
if !m.Has(fd) {
if fd.HasDefault() && fd.ContainingOneof() == nil {
v := fd.Default()
if fd.Kind() == protoreflect.BytesKind {
v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
}
m.Set(fd, v)
}
continue
}
}
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
switch {
// Handle singular message.
case fd.Cardinality() != protoreflect.Repeated:
if fd.Message() != nil {
setDefaults(m.Get(fd).Message())
}
// Handle list of messages.
case fd.IsList():
if fd.Message() != nil {
ls := m.Get(fd).List()
for i := 0; i < ls.Len(); i++ {
setDefaults(ls.Get(i).Message())
}
}
// Handle map of messages.
case fd.IsMap():
if fd.MapValue().Message() != nil {
ms := m.Get(fd).Map()
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
setDefaults(v.Message())
return true
})
}
}
return true
})
}

113
vendor/github.com/golang/protobuf/proto/deprecated.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"encoding/json"
"errors"
"fmt"
"strconv"
protoV2 "google.golang.org/protobuf/proto"
)
var (
// Deprecated: No longer returned.
ErrNil = errors.New("proto: Marshal called with nil")
// Deprecated: No longer returned.
ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
// Deprecated: No longer returned.
ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
)
// Deprecated: Do not use.
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
// Deprecated: Do not use.
func GetStats() Stats { return Stats{} }
// Deprecated: Do not use.
func MarshalMessageSet(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func UnmarshalMessageSet([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
return nil, errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func UnmarshalMessageSetJSON([]byte, interface{}) error {
return errors.New("proto: not implemented")
}
// Deprecated: Do not use.
func RegisterMessageSetType(Message, int32, string) {}
// Deprecated: Do not use.
func EnumName(m map[int32]string, v int32) string {
s, ok := m[v]
if ok {
return s
}
return strconv.Itoa(int(v))
}
// Deprecated: Do not use.
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
if data[0] == '"' {
// New style: enums are strings.
var repr string
if err := json.Unmarshal(data, &repr); err != nil {
return -1, err
}
val, ok := m[repr]
if !ok {
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
}
return val, nil
}
// Old style: enums are ints.
var val int32
if err := json.Unmarshal(data, &val); err != nil {
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
}
return val, nil
}
// Deprecated: Do not use; this type existed for intenal-use only.
type InternalMessageInfo struct{}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) DiscardUnknown(m Message) {
DiscardUnknown(m)
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) {
return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Merge(dst, src Message) {
protoV2.Merge(MessageV2(dst), MessageV2(src))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Size(m Message) int {
return protoV2.Size(MessageV2(m))
}
// Deprecated: Do not use; this method existed for intenal-use only.
func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error {
return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m))
}

58
vendor/github.com/golang/protobuf/proto/discard.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// DiscardUnknown recursively discards all unknown fields from this message
// and all embedded messages.
//
// When unmarshaling a message with unrecognized fields, the tags and values
// of such fields are preserved in the Message. This allows a later call to
// marshal to be able to produce a message that continues to have those
// unrecognized fields. To avoid this, DiscardUnknown is used to
// explicitly clear the unknown fields after unmarshaling.
func DiscardUnknown(m Message) {
if m != nil {
discardUnknown(MessageReflect(m))
}
}
func discardUnknown(m protoreflect.Message) {
m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
switch {
// Handle singular message.
case fd.Cardinality() != protoreflect.Repeated:
if fd.Message() != nil {
discardUnknown(m.Get(fd).Message())
}
// Handle list of messages.
case fd.IsList():
if fd.Message() != nil {
ls := m.Get(fd).List()
for i := 0; i < ls.Len(); i++ {
discardUnknown(ls.Get(i).Message())
}
}
// Handle map of messages.
case fd.IsMap():
if fd.MapValue().Message() != nil {
ms := m.Get(fd).Map()
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
discardUnknown(v.Message())
return true
})
}
}
return true
})
// Discard unknown fields.
if len(m.GetUnknown()) > 0 {
m.SetUnknown(nil)
}
}

356
vendor/github.com/golang/protobuf/proto/extensions.go generated vendored Normal file
View File

@ -0,0 +1,356 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"errors"
"fmt"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoiface"
"google.golang.org/protobuf/runtime/protoimpl"
)
type (
// ExtensionDesc represents an extension descriptor and
// is used to interact with an extension field in a message.
//
// Variables of this type are generated in code by protoc-gen-go.
ExtensionDesc = protoimpl.ExtensionInfo
// ExtensionRange represents a range of message extensions.
// Used in code generated by protoc-gen-go.
ExtensionRange = protoiface.ExtensionRangeV1
// Deprecated: Do not use; this is an internal type.
Extension = protoimpl.ExtensionFieldV1
// Deprecated: Do not use; this is an internal type.
XXX_InternalExtensions = protoimpl.ExtensionFields
)
// ErrMissingExtension reports whether the extension was not present.
var ErrMissingExtension = errors.New("proto: missing extension")
var errNotExtendable = errors.New("proto: not an extendable proto.Message")
// HasExtension reports whether the extension field is present in m
// either as an explicitly populated field or as an unknown field.
func HasExtension(m Message, xt *ExtensionDesc) (has bool) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return false
}
// Check whether any populated known field matches the field number.
xtd := xt.TypeDescriptor()
if isValidExtension(mr.Descriptor(), xtd) {
has = mr.Has(xtd)
} else {
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
has = int32(fd.Number()) == xt.Field
return !has
})
}
// Check whether any unknown field matches the field number.
for b := mr.GetUnknown(); !has && len(b) > 0; {
num, _, n := protowire.ConsumeField(b)
has = int32(num) == xt.Field
b = b[n:]
}
return has
}
// ClearExtension removes the extension field from m
// either as an explicitly populated field or as an unknown field.
func ClearExtension(m Message, xt *ExtensionDesc) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
xtd := xt.TypeDescriptor()
if isValidExtension(mr.Descriptor(), xtd) {
mr.Clear(xtd)
} else {
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
if int32(fd.Number()) == xt.Field {
mr.Clear(fd)
return false
}
return true
})
}
clearUnknown(mr, fieldNum(xt.Field))
}
// ClearAllExtensions clears all extensions from m.
// This includes populated fields and unknown fields in the extension range.
func ClearAllExtensions(m Message) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
if fd.IsExtension() {
mr.Clear(fd)
}
return true
})
clearUnknown(mr, mr.Descriptor().ExtensionRanges())
}
// GetExtension retrieves a proto2 extended field from m.
//
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
// then GetExtension parses the encoded field and returns a Go value of the specified type.
// If the field is not present, then the default value is returned (if one is specified),
// otherwise ErrMissingExtension is reported.
//
// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil),
// then GetExtension returns the raw encoded bytes for the extension field.
func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return nil, errNotExtendable
}
// Retrieve the unknown fields for this extension field.
var bo protoreflect.RawFields
for bi := mr.GetUnknown(); len(bi) > 0; {
num, _, n := protowire.ConsumeField(bi)
if int32(num) == xt.Field {
bo = append(bo, bi[:n]...)
}
bi = bi[n:]
}
// For type incomplete descriptors, only retrieve the unknown fields.
if xt.ExtensionType == nil {
return []byte(bo), nil
}
// If the extension field only exists as unknown fields, unmarshal it.
// This is rarely done since proto.Unmarshal eagerly unmarshals extensions.
xtd := xt.TypeDescriptor()
if !isValidExtension(mr.Descriptor(), xtd) {
return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
}
if !mr.Has(xtd) && len(bo) > 0 {
m2 := mr.New()
if err := (proto.UnmarshalOptions{
Resolver: extensionResolver{xt},
}.Unmarshal(bo, m2.Interface())); err != nil {
return nil, err
}
if m2.Has(xtd) {
mr.Set(xtd, m2.Get(xtd))
clearUnknown(mr, fieldNum(xt.Field))
}
}
// Check whether the message has the extension field set or a default.
var pv protoreflect.Value
switch {
case mr.Has(xtd):
pv = mr.Get(xtd)
case xtd.HasDefault():
pv = xtd.Default()
default:
return nil, ErrMissingExtension
}
v := xt.InterfaceOf(pv)
rv := reflect.ValueOf(v)
if isScalarKind(rv.Kind()) {
rv2 := reflect.New(rv.Type())
rv2.Elem().Set(rv)
v = rv2.Interface()
}
return v, nil
}
// extensionResolver is a custom extension resolver that stores a single
// extension type that takes precedence over the global registry.
type extensionResolver struct{ xt protoreflect.ExtensionType }
func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field {
return r.xt, nil
}
return protoregistry.GlobalTypes.FindExtensionByName(field)
}
func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field {
return r.xt, nil
}
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
}
// GetExtensions returns a list of the extensions values present in m,
// corresponding with the provided list of extension descriptors, xts.
// If an extension is missing in m, the corresponding value is nil.
func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return nil, errNotExtendable
}
vs := make([]interface{}, len(xts))
for i, xt := range xts {
v, err := GetExtension(m, xt)
if err != nil {
if err == ErrMissingExtension {
continue
}
return vs, err
}
vs[i] = v
}
return vs, nil
}
// SetExtension sets an extension field in m to the provided value.
func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return errNotExtendable
}
rv := reflect.ValueOf(v)
if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) {
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType)
}
if rv.Kind() == reflect.Ptr {
if rv.IsNil() {
return fmt.Errorf("proto: SetExtension called with nil value of type %T", v)
}
if isScalarKind(rv.Elem().Kind()) {
v = rv.Elem().Interface()
}
}
xtd := xt.TypeDescriptor()
if !isValidExtension(mr.Descriptor(), xtd) {
return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
}
mr.Set(xtd, xt.ValueOf(v))
clearUnknown(mr, fieldNum(xt.Field))
return nil
}
// SetRawExtension inserts b into the unknown fields of m.
//
// Deprecated: Use Message.ProtoReflect.SetUnknown instead.
func SetRawExtension(m Message, fnum int32, b []byte) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return
}
// Verify that the raw field is valid.
for b0 := b; len(b0) > 0; {
num, _, n := protowire.ConsumeField(b0)
if int32(num) != fnum {
panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum))
}
b0 = b0[n:]
}
ClearExtension(m, &ExtensionDesc{Field: fnum})
mr.SetUnknown(append(mr.GetUnknown(), b...))
}
// ExtensionDescs returns a list of extension descriptors found in m,
// containing descriptors for both populated extension fields in m and
// also unknown fields of m that are in the extension range.
// For the later case, an type incomplete descriptor is provided where only
// the ExtensionDesc.Field field is populated.
// The order of the extension descriptors is undefined.
func ExtensionDescs(m Message) ([]*ExtensionDesc, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
return nil, errNotExtendable
}
// Collect a set of known extension descriptors.
extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc)
mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if fd.IsExtension() {
xt := fd.(protoreflect.ExtensionTypeDescriptor)
if xd, ok := xt.Type().(*ExtensionDesc); ok {
extDescs[fd.Number()] = xd
}
}
return true
})
// Collect a set of unknown extension descriptors.
extRanges := mr.Descriptor().ExtensionRanges()
for b := mr.GetUnknown(); len(b) > 0; {
num, _, n := protowire.ConsumeField(b)
if extRanges.Has(num) && extDescs[num] == nil {
extDescs[num] = nil
}
b = b[n:]
}
// Transpose the set of descriptors into a list.
var xts []*ExtensionDesc
for num, xt := range extDescs {
if xt == nil {
xt = &ExtensionDesc{Field: int32(num)}
}
xts = append(xts, xt)
}
return xts, nil
}
// isValidExtension reports whether xtd is a valid extension descriptor for md.
func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool {
return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number())
}
// isScalarKind reports whether k is a protobuf scalar kind (except bytes).
// This function exists for historical reasons since the representation of
// scalars differs between v1 and v2, where v1 uses *T and v2 uses T.
func isScalarKind(k reflect.Kind) bool {
switch k {
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
return true
default:
return false
}
}
// clearUnknown removes unknown fields from m where remover.Has reports true.
func clearUnknown(m protoreflect.Message, remover interface {
Has(protoreflect.FieldNumber) bool
}) {
var bo protoreflect.RawFields
for bi := m.GetUnknown(); len(bi) > 0; {
num, _, n := protowire.ConsumeField(bi)
if !remover.Has(num) {
bo = append(bo, bi[:n]...)
}
bi = bi[n:]
}
if bi := m.GetUnknown(); len(bi) != len(bo) {
m.SetUnknown(bo)
}
}
type fieldNum protoreflect.FieldNumber
func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool {
return protoreflect.FieldNumber(n1) == n2
}

306
vendor/github.com/golang/protobuf/proto/properties.go generated vendored Normal file
View File

@ -0,0 +1,306 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"fmt"
"reflect"
"strconv"
"strings"
"sync"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoimpl"
)
// StructProperties represents protocol buffer type information for a
// generated protobuf message in the open-struct API.
//
// Deprecated: Do not use.
type StructProperties struct {
// Prop are the properties for each field.
//
// Fields belonging to a oneof are stored in OneofTypes instead, with a
// single Properties representing the parent oneof held here.
//
// The order of Prop matches the order of fields in the Go struct.
// Struct fields that are not related to protobufs have a "XXX_" prefix
// in the Properties.Name and must be ignored by the user.
Prop []*Properties
// OneofTypes contains information about the oneof fields in this message.
// It is keyed by the protobuf field name.
OneofTypes map[string]*OneofProperties
}
// Properties represents the type information for a protobuf message field.
//
// Deprecated: Do not use.
type Properties struct {
// Name is a placeholder name with little meaningful semantic value.
// If the name has an "XXX_" prefix, the entire Properties must be ignored.
Name string
// OrigName is the protobuf field name or oneof name.
OrigName string
// JSONName is the JSON name for the protobuf field.
JSONName string
// Enum is a placeholder name for enums.
// For historical reasons, this is neither the Go name for the enum,
// nor the protobuf name for the enum.
Enum string // Deprecated: Do not use.
// Weak contains the full name of the weakly referenced message.
Weak string
// Wire is a string representation of the wire type.
Wire string
// WireType is the protobuf wire type for the field.
WireType int
// Tag is the protobuf field number.
Tag int
// Required reports whether this is a required field.
Required bool
// Optional reports whether this is a optional field.
Optional bool
// Repeated reports whether this is a repeated field.
Repeated bool
// Packed reports whether this is a packed repeated field of scalars.
Packed bool
// Proto3 reports whether this field operates under the proto3 syntax.
Proto3 bool
// Oneof reports whether this field belongs within a oneof.
Oneof bool
// Default is the default value in string form.
Default string
// HasDefault reports whether the field has a default value.
HasDefault bool
// MapKeyProp is the properties for the key field for a map field.
MapKeyProp *Properties
// MapValProp is the properties for the value field for a map field.
MapValProp *Properties
}
// OneofProperties represents the type information for a protobuf oneof.
//
// Deprecated: Do not use.
type OneofProperties struct {
// Type is a pointer to the generated wrapper type for the field value.
// This is nil for messages that are not in the open-struct API.
Type reflect.Type
// Field is the index into StructProperties.Prop for the containing oneof.
Field int
// Prop is the properties for the field.
Prop *Properties
}
// String formats the properties in the protobuf struct field tag style.
func (p *Properties) String() string {
s := p.Wire
s += "," + strconv.Itoa(p.Tag)
if p.Required {
s += ",req"
}
if p.Optional {
s += ",opt"
}
if p.Repeated {
s += ",rep"
}
if p.Packed {
s += ",packed"
}
s += ",name=" + p.OrigName
if p.JSONName != "" {
s += ",json=" + p.JSONName
}
if len(p.Enum) > 0 {
s += ",enum=" + p.Enum
}
if len(p.Weak) > 0 {
s += ",weak=" + p.Weak
}
if p.Proto3 {
s += ",proto3"
}
if p.Oneof {
s += ",oneof"
}
if p.HasDefault {
s += ",def=" + p.Default
}
return s
}
// Parse populates p by parsing a string in the protobuf struct field tag style.
func (p *Properties) Parse(tag string) {
// For example: "bytes,49,opt,name=foo,def=hello!"
for len(tag) > 0 {
i := strings.IndexByte(tag, ',')
if i < 0 {
i = len(tag)
}
switch s := tag[:i]; {
case strings.HasPrefix(s, "name="):
p.OrigName = s[len("name="):]
case strings.HasPrefix(s, "json="):
p.JSONName = s[len("json="):]
case strings.HasPrefix(s, "enum="):
p.Enum = s[len("enum="):]
case strings.HasPrefix(s, "weak="):
p.Weak = s[len("weak="):]
case strings.Trim(s, "0123456789") == "":
n, _ := strconv.ParseUint(s, 10, 32)
p.Tag = int(n)
case s == "opt":
p.Optional = true
case s == "req":
p.Required = true
case s == "rep":
p.Repeated = true
case s == "varint" || s == "zigzag32" || s == "zigzag64":
p.Wire = s
p.WireType = WireVarint
case s == "fixed32":
p.Wire = s
p.WireType = WireFixed32
case s == "fixed64":
p.Wire = s
p.WireType = WireFixed64
case s == "bytes":
p.Wire = s
p.WireType = WireBytes
case s == "group":
p.Wire = s
p.WireType = WireStartGroup
case s == "packed":
p.Packed = true
case s == "proto3":
p.Proto3 = true
case s == "oneof":
p.Oneof = true
case strings.HasPrefix(s, "def="):
// The default tag is special in that everything afterwards is the
// default regardless of the presence of commas.
p.HasDefault = true
p.Default, i = tag[len("def="):], len(tag)
}
tag = strings.TrimPrefix(tag[i:], ",")
}
}
// Init populates the properties from a protocol buffer struct tag.
//
// Deprecated: Do not use.
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
p.Name = name
p.OrigName = name
if tag == "" {
return
}
p.Parse(tag)
if typ != nil && typ.Kind() == reflect.Map {
p.MapKeyProp = new(Properties)
p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
p.MapValProp = new(Properties)
p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
}
}
var propertiesCache sync.Map // map[reflect.Type]*StructProperties
// GetProperties returns the list of properties for the type represented by t,
// which must be a generated protocol buffer message in the open-struct API,
// where protobuf message fields are represented by exported Go struct fields.
//
// Deprecated: Use protobuf reflection instead.
func GetProperties(t reflect.Type) *StructProperties {
if p, ok := propertiesCache.Load(t); ok {
return p.(*StructProperties)
}
p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
return p.(*StructProperties)
}
func newProperties(t reflect.Type) *StructProperties {
if t.Kind() != reflect.Struct {
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
}
var hasOneof bool
prop := new(StructProperties)
// Construct a list of properties for each field in the struct.
for i := 0; i < t.NumField(); i++ {
p := new(Properties)
f := t.Field(i)
tagField := f.Tag.Get("protobuf")
p.Init(f.Type, f.Name, tagField, &f)
tagOneof := f.Tag.Get("protobuf_oneof")
if tagOneof != "" {
hasOneof = true
p.OrigName = tagOneof
}
// Rename unrelated struct fields with the "XXX_" prefix since so much
// user code simply checks for this to exclude special fields.
if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
p.Name = "XXX_" + p.Name
p.OrigName = "XXX_" + p.OrigName
} else if p.Weak != "" {
p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
}
prop.Prop = append(prop.Prop, p)
}
// Construct a mapping of oneof field names to properties.
if hasOneof {
var oneofWrappers []interface{}
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
}
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
}
if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
oneofWrappers = m.ProtoMessageInfo().OneofWrappers
}
}
prop.OneofTypes = make(map[string]*OneofProperties)
for _, wrapper := range oneofWrappers {
p := &OneofProperties{
Type: reflect.ValueOf(wrapper).Type(), // *T
Prop: new(Properties),
}
f := p.Type.Elem().Field(0)
p.Prop.Name = f.Name
p.Prop.Parse(f.Tag.Get("protobuf"))
// Determine the struct field that contains this oneof.
// Each wrapper is assignable to exactly one parent field.
var foundOneof bool
for i := 0; i < t.NumField() && !foundOneof; i++ {
if p.Type.AssignableTo(t.Field(i).Type) {
p.Field = i
foundOneof = true
}
}
if !foundOneof {
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
}
prop.OneofTypes[p.Prop.OrigName] = p
}
}
return prop
}
func (sp *StructProperties) Len() int { return len(sp.Prop) }
func (sp *StructProperties) Less(i, j int) bool { return false }
func (sp *StructProperties) Swap(i, j int) { return }

167
vendor/github.com/golang/protobuf/proto/proto.go generated vendored Normal file
View File

@ -0,0 +1,167 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package proto provides functionality for handling protocol buffer messages.
// In particular, it provides marshaling and unmarshaling between a protobuf
// message and the binary wire format.
//
// See https://developers.google.com/protocol-buffers/docs/gotutorial for
// more information.
//
// Deprecated: Use the "google.golang.org/protobuf/proto" package instead.
package proto
import (
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
"google.golang.org/protobuf/runtime/protoimpl"
)
const (
ProtoPackageIsVersion1 = true
ProtoPackageIsVersion2 = true
ProtoPackageIsVersion3 = true
ProtoPackageIsVersion4 = true
)
// GeneratedEnum is any enum type generated by protoc-gen-go
// which is a named int32 kind.
// This type exists for documentation purposes.
type GeneratedEnum interface{}
// GeneratedMessage is any message type generated by protoc-gen-go
// which is a pointer to a named struct kind.
// This type exists for documentation purposes.
type GeneratedMessage interface{}
// Message is a protocol buffer message.
//
// This is the v1 version of the message interface and is marginally better
// than an empty interface as it lacks any method to programatically interact
// with the contents of the message.
//
// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
// exposes protobuf reflection as a first-class feature of the interface.
//
// To convert a v1 message to a v2 message, use the MessageV2 function.
// To convert a v2 message to a v1 message, use the MessageV1 function.
type Message = protoiface.MessageV1
// MessageV1 converts either a v1 or v2 message to a v1 message.
// It returns nil if m is nil.
func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
return protoimpl.X.ProtoMessageV1Of(m)
}
// MessageV2 converts either a v1 or v2 message to a v2 message.
// It returns nil if m is nil.
func MessageV2(m GeneratedMessage) protoV2.Message {
return protoimpl.X.ProtoMessageV2Of(m)
}
// MessageReflect returns a reflective view for a message.
// It returns nil if m is nil.
func MessageReflect(m Message) protoreflect.Message {
return protoimpl.X.MessageOf(m)
}
// Marshaler is implemented by messages that can marshal themselves.
// This interface is used by the following functions: Size, Marshal,
// Buffer.Marshal, and Buffer.EncodeMessage.
//
// Deprecated: Do not implement.
type Marshaler interface {
// Marshal formats the encoded bytes of the message.
// It should be deterministic and emit valid protobuf wire data.
// The caller takes ownership of the returned buffer.
Marshal() ([]byte, error)
}
// Unmarshaler is implemented by messages that can unmarshal themselves.
// This interface is used by the following functions: Unmarshal, UnmarshalMerge,
// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup.
//
// Deprecated: Do not implement.
type Unmarshaler interface {
// Unmarshal parses the encoded bytes of the protobuf wire input.
// The provided buffer is only valid for during method call.
// It should not reset the receiver message.
Unmarshal([]byte) error
}
// Merger is implemented by messages that can merge themselves.
// This interface is used by the following functions: Clone and Merge.
//
// Deprecated: Do not implement.
type Merger interface {
// Merge merges the contents of src into the receiver message.
// It clones all data structures in src such that it aliases no mutable
// memory referenced by src.
Merge(src Message)
}
// RequiredNotSetError is an error type returned when
// marshaling or unmarshaling a message with missing required fields.
type RequiredNotSetError struct {
err error
}
func (e *RequiredNotSetError) Error() string {
if e.err != nil {
return e.err.Error()
}
return "proto: required field not set"
}
func (e *RequiredNotSetError) RequiredNotSet() bool {
return true
}
func checkRequiredNotSet(m protoV2.Message) error {
if err := protoV2.CheckInitialized(m); err != nil {
return &RequiredNotSetError{err: err}
}
return nil
}
// Clone returns a deep copy of src.
func Clone(src Message) Message {
return MessageV1(protoV2.Clone(MessageV2(src)))
}
// Merge merges src into dst, which must be messages of the same type.
//
// Populated scalar fields in src are copied to dst, while populated
// singular messages in src are merged into dst by recursively calling Merge.
// The elements of every list field in src is appended to the corresponded
// list fields in dst. The entries of every map field in src is copied into
// the corresponding map field in dst, possibly replacing existing entries.
// The unknown fields of src are appended to the unknown fields of dst.
func Merge(dst, src Message) {
protoV2.Merge(MessageV2(dst), MessageV2(src))
}
// Equal reports whether two messages are equal.
// If two messages marshal to the same bytes under deterministic serialization,
// then Equal is guaranteed to report true.
//
// Two messages are equal if they are the same protobuf message type,
// have the same set of populated known and extension field values,
// and the same set of unknown fields values.
//
// Scalar values are compared with the equivalent of the == operator in Go,
// except bytes values which are compared using bytes.Equal and
// floating point values which specially treat NaNs as equal.
// Message values are compared by recursively calling Equal.
// Lists are equal if each element value is also equal.
// Maps are equal if they have the same set of keys, where the pair of values
// for each key is also equal.
func Equal(x, y Message) bool {
return protoV2.Equal(MessageV2(x), MessageV2(y))
}
func isMessageSet(md protoreflect.MessageDescriptor) bool {
ms, ok := md.(interface{ IsMessageSet() bool })
return ok && ms.IsMessageSet()
}

317
vendor/github.com/golang/protobuf/proto/registry.go generated vendored Normal file
View File

@ -0,0 +1,317 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"reflect"
"strings"
"sync"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/runtime/protoimpl"
)
// filePath is the path to the proto source file.
type filePath = string // e.g., "google/protobuf/descriptor.proto"
// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto.
type fileDescGZIP = []byte
var fileCache sync.Map // map[filePath]fileDescGZIP
// RegisterFile is called from generated code to register the compressed
// FileDescriptorProto with the file path for a proto source file.
//
// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead.
func RegisterFile(s filePath, d fileDescGZIP) {
// Decompress the descriptor.
zr, err := gzip.NewReader(bytes.NewReader(d))
if err != nil {
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
}
b, err := ioutil.ReadAll(zr)
if err != nil {
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
}
// Construct a protoreflect.FileDescriptor from the raw descriptor.
// Note that DescBuilder.Build automatically registers the constructed
// file descriptor with the v2 registry.
protoimpl.DescBuilder{RawDescriptor: b}.Build()
// Locally cache the raw descriptor form for the file.
fileCache.Store(s, d)
}
// FileDescriptor returns the compressed FileDescriptorProto given the file path
// for a proto source file. It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead.
func FileDescriptor(s filePath) fileDescGZIP {
if v, ok := fileCache.Load(s); ok {
return v.(fileDescGZIP)
}
// Find the descriptor in the v2 registry.
var b []byte
if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil {
b, _ = Marshal(protodesc.ToFileDescriptorProto(fd))
}
// Locally cache the raw descriptor form for the file.
if len(b) > 0 {
v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b))
return v.(fileDescGZIP)
}
return nil
}
// enumName is the name of an enum. For historical reasons, the enum name is
// neither the full Go name nor the full protobuf name of the enum.
// The name is the dot-separated combination of just the proto package that the
// enum is declared within followed by the Go type name of the generated enum.
type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum"
// enumsByName maps enum values by name to their numeric counterpart.
type enumsByName = map[string]int32
// enumsByNumber maps enum values by number to their name counterpart.
type enumsByNumber = map[int32]string
var enumCache sync.Map // map[enumName]enumsByName
var numFilesCache sync.Map // map[protoreflect.FullName]int
// RegisterEnum is called from the generated code to register the mapping of
// enum value names to enum numbers for the enum identified by s.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead.
func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) {
if _, ok := enumCache.Load(s); ok {
panic("proto: duplicate enum registered: " + s)
}
enumCache.Store(s, m)
// This does not forward registration to the v2 registry since this API
// lacks sufficient information to construct a complete v2 enum descriptor.
}
// EnumValueMap returns the mapping from enum value names to enum numbers for
// the enum of the given name. It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead.
func EnumValueMap(s enumName) enumsByName {
if v, ok := enumCache.Load(s); ok {
return v.(enumsByName)
}
// Check whether the cache is stale. If the number of files in the current
// package differs, then it means that some enums may have been recently
// registered upstream that we do not know about.
var protoPkg protoreflect.FullName
if i := strings.LastIndexByte(s, '.'); i >= 0 {
protoPkg = protoreflect.FullName(s[:i])
}
v, _ := numFilesCache.Load(protoPkg)
numFiles, _ := v.(int)
if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles {
return nil // cache is up-to-date; was not found earlier
}
// Update the enum cache for all enums declared in the given proto package.
numFiles = 0
protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool {
walkEnums(fd, func(ed protoreflect.EnumDescriptor) {
name := protoimpl.X.LegacyEnumName(ed)
if _, ok := enumCache.Load(name); !ok {
m := make(enumsByName)
evs := ed.Values()
for i := evs.Len() - 1; i >= 0; i-- {
ev := evs.Get(i)
m[string(ev.Name())] = int32(ev.Number())
}
enumCache.LoadOrStore(name, m)
}
})
numFiles++
return true
})
numFilesCache.Store(protoPkg, numFiles)
// Check cache again for enum map.
if v, ok := enumCache.Load(s); ok {
return v.(enumsByName)
}
return nil
}
// walkEnums recursively walks all enums declared in d.
func walkEnums(d interface {
Enums() protoreflect.EnumDescriptors
Messages() protoreflect.MessageDescriptors
}, f func(protoreflect.EnumDescriptor)) {
eds := d.Enums()
for i := eds.Len() - 1; i >= 0; i-- {
f(eds.Get(i))
}
mds := d.Messages()
for i := mds.Len() - 1; i >= 0; i-- {
walkEnums(mds.Get(i), f)
}
}
// messageName is the full name of protobuf message.
type messageName = string
var messageTypeCache sync.Map // map[messageName]reflect.Type
// RegisterType is called from generated code to register the message Go type
// for a message of the given name.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead.
func RegisterType(m Message, s messageName) {
mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s))
if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil {
panic(err)
}
messageTypeCache.Store(s, reflect.TypeOf(m))
}
// RegisterMapType is called from generated code to register the Go map type
// for a protobuf message representing a map entry.
//
// Deprecated: Do not use.
func RegisterMapType(m interface{}, s messageName) {
t := reflect.TypeOf(m)
if t.Kind() != reflect.Map {
panic(fmt.Sprintf("invalid map kind: %v", t))
}
if _, ok := messageTypeCache.Load(s); ok {
panic(fmt.Errorf("proto: duplicate proto message registered: %s", s))
}
messageTypeCache.Store(s, t)
}
// MessageType returns the message type for a named message.
// It returns nil if not found.
//
// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead.
func MessageType(s messageName) reflect.Type {
if v, ok := messageTypeCache.Load(s); ok {
return v.(reflect.Type)
}
// Derive the message type from the v2 registry.
var t reflect.Type
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil {
t = messageGoType(mt)
}
// If we could not get a concrete type, it is possible that it is a
// pseudo-message for a map entry.
if t == nil {
d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s))
if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() {
kt := goTypeForField(md.Fields().ByNumber(1))
vt := goTypeForField(md.Fields().ByNumber(2))
t = reflect.MapOf(kt, vt)
}
}
// Locally cache the message type for the given name.
if t != nil {
v, _ := messageTypeCache.LoadOrStore(s, t)
return v.(reflect.Type)
}
return nil
}
func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type {
switch k := fd.Kind(); k {
case protoreflect.EnumKind:
if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil {
return enumGoType(et)
}
return reflect.TypeOf(protoreflect.EnumNumber(0))
case protoreflect.MessageKind, protoreflect.GroupKind:
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil {
return messageGoType(mt)
}
return reflect.TypeOf((*protoreflect.Message)(nil)).Elem()
default:
return reflect.TypeOf(fd.Default().Interface())
}
}
func enumGoType(et protoreflect.EnumType) reflect.Type {
return reflect.TypeOf(et.New(0))
}
func messageGoType(mt protoreflect.MessageType) reflect.Type {
return reflect.TypeOf(MessageV1(mt.Zero().Interface()))
}
// MessageName returns the full protobuf name for the given message type.
//
// Deprecated: Use protoreflect.MessageDescriptor.FullName instead.
func MessageName(m Message) messageName {
if m == nil {
return ""
}
if m, ok := m.(interface{ XXX_MessageName() messageName }); ok {
return m.XXX_MessageName()
}
return messageName(protoimpl.X.MessageDescriptorOf(m).FullName())
}
// RegisterExtension is called from the generated code to register
// the extension descriptor.
//
// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead.
func RegisterExtension(d *ExtensionDesc) {
if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil {
panic(err)
}
}
type extensionsByNumber = map[int32]*ExtensionDesc
var extensionCache sync.Map // map[messageName]extensionsByNumber
// RegisteredExtensions returns a map of the registered extensions for the
// provided protobuf message, indexed by the extension field number.
//
// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead.
func RegisteredExtensions(m Message) extensionsByNumber {
// Check whether the cache is stale. If the number of extensions for
// the given message differs, then it means that some extensions were
// recently registered upstream that we do not know about.
s := MessageName(m)
v, _ := extensionCache.Load(s)
xs, _ := v.(extensionsByNumber)
if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) {
return xs // cache is up-to-date
}
// Cache is stale, re-compute the extensions map.
xs = make(extensionsByNumber)
protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool {
if xd, ok := xt.(*ExtensionDesc); ok {
xs[int32(xt.TypeDescriptor().Number())] = xd
} else {
// TODO: This implies that the protoreflect.ExtensionType is a
// custom type not generated by protoc-gen-go. We could try and
// convert the type to an ExtensionDesc.
}
return true
})
extensionCache.Store(s, xs)
return xs
}

801
vendor/github.com/golang/protobuf/proto/text_decode.go generated vendored Normal file
View File

@ -0,0 +1,801 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"encoding"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"unicode/utf8"
"google.golang.org/protobuf/encoding/prototext"
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapTextUnmarshalV2 = false
// ParseError is returned by UnmarshalText.
type ParseError struct {
Message string
// Deprecated: Do not use.
Line, Offset int
}
func (e *ParseError) Error() string {
if wrapTextUnmarshalV2 {
return e.Message
}
if e.Line == 1 {
return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message)
}
return fmt.Sprintf("line %d: %v", e.Line, e.Message)
}
// UnmarshalText parses a proto text formatted string into m.
func UnmarshalText(s string, m Message) error {
if u, ok := m.(encoding.TextUnmarshaler); ok {
return u.UnmarshalText([]byte(s))
}
m.Reset()
mi := MessageV2(m)
if wrapTextUnmarshalV2 {
err := prototext.UnmarshalOptions{
AllowPartial: true,
}.Unmarshal([]byte(s), mi)
if err != nil {
return &ParseError{Message: err.Error()}
}
return checkRequiredNotSet(mi)
} else {
if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil {
return err
}
return checkRequiredNotSet(mi)
}
}
type textParser struct {
s string // remaining input
done bool // whether the parsing is finished (success or error)
backed bool // whether back() was called
offset, line int
cur token
}
type token struct {
value string
err *ParseError
line int // line number
offset int // byte number from start of input, not start of line
unquoted string // the unquoted version of value, if it was a quoted string
}
func newTextParser(s string) *textParser {
p := new(textParser)
p.s = s
p.line = 1
p.cur.line = 1
return p
}
func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) {
md := m.Descriptor()
fds := md.Fields()
// A struct is a sequence of "name: value", terminated by one of
// '>' or '}', or the end of the input. A name may also be
// "[extension]" or "[type/url]".
//
// The whole struct can also be an expanded Any message, like:
// [type/url] < ... struct contents ... >
seen := make(map[protoreflect.FieldNumber]bool)
for {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value == terminator {
break
}
if tok.value == "[" {
if err := p.unmarshalExtensionOrAny(m, seen); err != nil {
return err
}
continue
}
// This is a normal, non-extension field.
name := protoreflect.Name(tok.value)
fd := fds.ByName(name)
switch {
case fd == nil:
gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name))))
if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name {
fd = gd
}
case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name:
fd = nil
case fd.IsWeak() && fd.Message().IsPlaceholder():
fd = nil
}
if fd == nil {
typeName := string(md.FullName())
if m, ok := m.Interface().(Message); ok {
t := reflect.TypeOf(m)
if t.Kind() == reflect.Ptr {
typeName = t.Elem().String()
}
}
return p.errorf("unknown field name %q in %v", name, typeName)
}
if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil {
return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name())
}
if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] {
return p.errorf("non-repeated field %q was repeated", fd.Name())
}
seen[fd.Number()] = true
// Consume any colon.
if err := p.checkForColon(fd); err != nil {
return err
}
// Parse into the field.
v := m.Get(fd)
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
v = m.Mutable(fd)
}
if v, err = p.unmarshalValue(v, fd); err != nil {
return err
}
m.Set(fd, v)
if err := p.consumeOptionalSeparator(); err != nil {
return err
}
}
return nil
}
func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error {
name, err := p.consumeExtensionOrAnyName()
if err != nil {
return err
}
// If it contains a slash, it's an Any type URL.
if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 {
tok := p.next()
if tok.err != nil {
return tok.err
}
// consume an optional colon
if tok.value == ":" {
tok = p.next()
if tok.err != nil {
return tok.err
}
}
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return p.errorf("expected '{' or '<', found %q", tok.value)
}
mt, err := protoregistry.GlobalTypes.FindMessageByURL(name)
if err != nil {
return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):])
}
m2 := mt.New()
if err := p.unmarshalMessage(m2, terminator); err != nil {
return err
}
b, err := protoV2.Marshal(m2.Interface())
if err != nil {
return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err)
}
urlFD := m.Descriptor().Fields().ByName("type_url")
valFD := m.Descriptor().Fields().ByName("value")
if seen[urlFD.Number()] {
return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name())
}
if seen[valFD.Number()] {
return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name())
}
m.Set(urlFD, protoreflect.ValueOfString(name))
m.Set(valFD, protoreflect.ValueOfBytes(b))
seen[urlFD.Number()] = true
seen[valFD.Number()] = true
return nil
}
xname := protoreflect.FullName(name)
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
if xt == nil && isMessageSet(m.Descriptor()) {
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
}
if xt == nil {
return p.errorf("unrecognized extension %q", name)
}
fd := xt.TypeDescriptor()
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName())
}
if err := p.checkForColon(fd); err != nil {
return err
}
v := m.Get(fd)
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
v = m.Mutable(fd)
}
v, err = p.unmarshalValue(v, fd)
if err != nil {
return err
}
m.Set(fd, v)
return p.consumeOptionalSeparator()
}
func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "" {
return v, p.errorf("unexpected EOF")
}
switch {
case fd.IsList():
lv := v.List()
var err error
if tok.value == "[" {
// Repeated field with list notation, like [1,2,3].
for {
vv := lv.NewElement()
vv, err = p.unmarshalSingularValue(vv, fd)
if err != nil {
return v, err
}
lv.Append(vv)
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "]" {
break
}
if tok.value != "," {
return v, p.errorf("Expected ']' or ',' found %q", tok.value)
}
}
return v, nil
}
// One value of the repeated field.
p.back()
vv := lv.NewElement()
vv, err = p.unmarshalSingularValue(vv, fd)
if err != nil {
return v, err
}
lv.Append(vv)
return v, nil
case fd.IsMap():
// The map entry should be this sequence of tokens:
// < key : KEY value : VALUE >
// However, implementations may omit key or value, and technically
// we should support them in any order.
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return v, p.errorf("expected '{' or '<', found %q", tok.value)
}
keyFD := fd.MapKey()
valFD := fd.MapValue()
mv := v.Map()
kv := keyFD.Default()
vv := mv.NewValue()
for {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == terminator {
break
}
var err error
switch tok.value {
case "key":
if err := p.consumeToken(":"); err != nil {
return v, err
}
if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil {
return v, err
}
if err := p.consumeOptionalSeparator(); err != nil {
return v, err
}
case "value":
if err := p.checkForColon(valFD); err != nil {
return v, err
}
if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil {
return v, err
}
if err := p.consumeOptionalSeparator(); err != nil {
return v, err
}
default:
p.back()
return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
}
}
mv.Set(kv.MapKey(), vv)
return v, nil
default:
p.back()
return p.unmarshalSingularValue(v, fd)
}
}
func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
tok := p.next()
if tok.err != nil {
return v, tok.err
}
if tok.value == "" {
return v, p.errorf("unexpected EOF")
}
switch fd.Kind() {
case protoreflect.BoolKind:
switch tok.value {
case "true", "1", "t", "True":
return protoreflect.ValueOfBool(true), nil
case "false", "0", "f", "False":
return protoreflect.ValueOfBool(false), nil
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfInt32(int32(x)), nil
}
// The C++ parser accepts large positive hex numbers that uses
// two's complement arithmetic to represent negative numbers.
// This feature is here for backwards compatibility with C++.
if strings.HasPrefix(tok.value, "0x") {
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil
}
}
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfInt64(int64(x)), nil
}
// The C++ parser accepts large positive hex numbers that uses
// two's complement arithmetic to represent negative numbers.
// This feature is here for backwards compatibility with C++.
if strings.HasPrefix(tok.value, "0x") {
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil
}
}
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfUint32(uint32(x)), nil
}
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
return protoreflect.ValueOfUint64(uint64(x)), nil
}
case protoreflect.FloatKind:
// Ignore 'f' for compatibility with output generated by C++,
// but don't remove 'f' when the value is "-inf" or "inf".
v := tok.value
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
v = v[:len(v)-len("f")]
}
if x, err := strconv.ParseFloat(v, 32); err == nil {
return protoreflect.ValueOfFloat32(float32(x)), nil
}
case protoreflect.DoubleKind:
// Ignore 'f' for compatibility with output generated by C++,
// but don't remove 'f' when the value is "-inf" or "inf".
v := tok.value
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
v = v[:len(v)-len("f")]
}
if x, err := strconv.ParseFloat(v, 64); err == nil {
return protoreflect.ValueOfFloat64(float64(x)), nil
}
case protoreflect.StringKind:
if isQuote(tok.value[0]) {
return protoreflect.ValueOfString(tok.unquoted), nil
}
case protoreflect.BytesKind:
if isQuote(tok.value[0]) {
return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil
}
case protoreflect.EnumKind:
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil
}
vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value))
if vd != nil {
return protoreflect.ValueOfEnum(vd.Number()), nil
}
case protoreflect.MessageKind, protoreflect.GroupKind:
var terminator string
switch tok.value {
case "{":
terminator = "}"
case "<":
terminator = ">"
default:
return v, p.errorf("expected '{' or '<', found %q", tok.value)
}
err := p.unmarshalMessage(v.Message(), terminator)
return v, err
default:
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
}
return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value)
}
// Consume a ':' from the input stream (if the next token is a colon),
// returning an error if a colon is needed but not present.
func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != ":" {
if fd.Message() == nil {
return p.errorf("expected ':', found %q", tok.value)
}
p.back()
}
return nil
}
// consumeExtensionOrAnyName consumes an extension name or an Any type URL and
// the following ']'. It returns the name or URL consumed.
func (p *textParser) consumeExtensionOrAnyName() (string, error) {
tok := p.next()
if tok.err != nil {
return "", tok.err
}
// If extension name or type url is quoted, it's a single token.
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
if err != nil {
return "", err
}
return name, p.consumeToken("]")
}
// Consume everything up to "]"
var parts []string
for tok.value != "]" {
parts = append(parts, tok.value)
tok = p.next()
if tok.err != nil {
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
}
if p.done && tok.value != "]" {
return "", p.errorf("unclosed type_url or extension name")
}
}
return strings.Join(parts, ""), nil
}
// consumeOptionalSeparator consumes an optional semicolon or comma.
// It is used in unmarshalMessage to provide backward compatibility.
func (p *textParser) consumeOptionalSeparator() error {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != ";" && tok.value != "," {
p.back()
}
return nil
}
func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
p.cur.err = pe
p.done = true
return pe
}
func (p *textParser) skipWhitespace() {
i := 0
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
if p.s[i] == '#' {
// comment; skip to end of line or input
for i < len(p.s) && p.s[i] != '\n' {
i++
}
if i == len(p.s) {
break
}
}
if p.s[i] == '\n' {
p.line++
}
i++
}
p.offset += i
p.s = p.s[i:len(p.s)]
if len(p.s) == 0 {
p.done = true
}
}
func (p *textParser) advance() {
// Skip whitespace
p.skipWhitespace()
if p.done {
return
}
// Start of non-whitespace
p.cur.err = nil
p.cur.offset, p.cur.line = p.offset, p.line
p.cur.unquoted = ""
switch p.s[0] {
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
// Single symbol
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
case '"', '\'':
// Quoted string
i := 1
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
if p.s[i] == '\\' && i+1 < len(p.s) {
// skip escaped char
i++
}
i++
}
if i >= len(p.s) || p.s[i] != p.s[0] {
p.errorf("unmatched quote")
return
}
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
if err != nil {
p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
return
}
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
p.cur.unquoted = unq
default:
i := 0
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
i++
}
if i == 0 {
p.errorf("unexpected byte %#x", p.s[0])
return
}
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
}
p.offset += len(p.cur.value)
}
// Back off the parser by one token. Can only be done between calls to next().
// It makes the next advance() a no-op.
func (p *textParser) back() { p.backed = true }
// Advances the parser and returns the new current token.
func (p *textParser) next() *token {
if p.backed || p.done {
p.backed = false
return &p.cur
}
p.advance()
if p.done {
p.cur.value = ""
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
// Look for multiple quoted strings separated by whitespace,
// and concatenate them.
cat := p.cur
for {
p.skipWhitespace()
if p.done || !isQuote(p.s[0]) {
break
}
p.advance()
if p.cur.err != nil {
return &p.cur
}
cat.value += " " + p.cur.value
cat.unquoted += p.cur.unquoted
}
p.done = false // parser may have seen EOF, but we want to return cat
p.cur = cat
}
return &p.cur
}
func (p *textParser) consumeToken(s string) error {
tok := p.next()
if tok.err != nil {
return tok.err
}
if tok.value != s {
p.back()
return p.errorf("expected %q, found %q", s, tok.value)
}
return nil
}
var errBadUTF8 = errors.New("proto: bad UTF-8")
func unquoteC(s string, quote rune) (string, error) {
// This is based on C++'s tokenizer.cc.
// Despite its name, this is *not* parsing C syntax.
// For instance, "\0" is an invalid quoted string.
// Avoid allocation in trivial cases.
simple := true
for _, r := range s {
if r == '\\' || r == quote {
simple = false
break
}
}
if simple {
return s, nil
}
buf := make([]byte, 0, 3*len(s)/2)
for len(s) > 0 {
r, n := utf8.DecodeRuneInString(s)
if r == utf8.RuneError && n == 1 {
return "", errBadUTF8
}
s = s[n:]
if r != '\\' {
if r < utf8.RuneSelf {
buf = append(buf, byte(r))
} else {
buf = append(buf, string(r)...)
}
continue
}
ch, tail, err := unescape(s)
if err != nil {
return "", err
}
buf = append(buf, ch...)
s = tail
}
return string(buf), nil
}
func unescape(s string) (ch string, tail string, err error) {
r, n := utf8.DecodeRuneInString(s)
if r == utf8.RuneError && n == 1 {
return "", "", errBadUTF8
}
s = s[n:]
switch r {
case 'a':
return "\a", s, nil
case 'b':
return "\b", s, nil
case 'f':
return "\f", s, nil
case 'n':
return "\n", s, nil
case 'r':
return "\r", s, nil
case 't':
return "\t", s, nil
case 'v':
return "\v", s, nil
case '?':
return "?", s, nil // trigraph workaround
case '\'', '"', '\\':
return string(r), s, nil
case '0', '1', '2', '3', '4', '5', '6', '7':
if len(s) < 2 {
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
}
ss := string(r) + s[:2]
s = s[2:]
i, err := strconv.ParseUint(ss, 8, 8)
if err != nil {
return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
}
return string([]byte{byte(i)}), s, nil
case 'x', 'X', 'u', 'U':
var n int
switch r {
case 'x', 'X':
n = 2
case 'u':
n = 4
case 'U':
n = 8
}
if len(s) < n {
return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
}
ss := s[:n]
s = s[n:]
i, err := strconv.ParseUint(ss, 16, 64)
if err != nil {
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
}
if r == 'x' || r == 'X' {
return string([]byte{byte(i)}), s, nil
}
if i > utf8.MaxRune {
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
}
return string(rune(i)), s, nil
}
return "", "", fmt.Errorf(`unknown escape \%c`, r)
}
func isIdentOrNumberChar(c byte) bool {
switch {
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
return true
case '0' <= c && c <= '9':
return true
}
switch c {
case '-', '+', '.', '_':
return true
}
return false
}
func isWhitespace(c byte) bool {
switch c {
case ' ', '\t', '\n', '\r':
return true
}
return false
}
func isQuote(c byte) bool {
switch c {
case '"', '\'':
return true
}
return false
}

560
vendor/github.com/golang/protobuf/proto/text_encode.go generated vendored Normal file
View File

@ -0,0 +1,560 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
"bytes"
"encoding"
"fmt"
"io"
"math"
"sort"
"strings"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
const wrapTextMarshalV2 = false
// TextMarshaler is a configurable text format marshaler.
type TextMarshaler struct {
Compact bool // use compact text format (one line)
ExpandAny bool // expand google.protobuf.Any messages of known types
}
// Marshal writes the proto text format of m to w.
func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
b, err := tm.marshal(m)
if len(b) > 0 {
if _, err := w.Write(b); err != nil {
return err
}
}
return err
}
// Text returns a proto text formatted string of m.
func (tm *TextMarshaler) Text(m Message) string {
b, _ := tm.marshal(m)
return string(b)
}
func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
mr := MessageReflect(m)
if mr == nil || !mr.IsValid() {
return []byte("<nil>"), nil
}
if wrapTextMarshalV2 {
if m, ok := m.(encoding.TextMarshaler); ok {
return m.MarshalText()
}
opts := prototext.MarshalOptions{
AllowPartial: true,
EmitUnknown: true,
}
if !tm.Compact {
opts.Indent = " "
}
if !tm.ExpandAny {
opts.Resolver = (*protoregistry.Types)(nil)
}
return opts.Marshal(mr.Interface())
} else {
w := &textWriter{
compact: tm.Compact,
expandAny: tm.ExpandAny,
complete: true,
}
if m, ok := m.(encoding.TextMarshaler); ok {
b, err := m.MarshalText()
if err != nil {
return nil, err
}
w.Write(b)
return w.buf, nil
}
err := w.writeMessage(mr)
return w.buf, err
}
}
var (
defaultTextMarshaler = TextMarshaler{}
compactTextMarshaler = TextMarshaler{Compact: true}
)
// MarshalText writes the proto text format of m to w.
func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
// MarshalTextString returns a proto text formatted string of m.
func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
// CompactText writes the compact proto text format of m to w.
func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
// CompactTextString returns a compact proto text formatted string of m.
func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
var (
newline = []byte("\n")
endBraceNewline = []byte("}\n")
posInf = []byte("inf")
negInf = []byte("-inf")
nan = []byte("nan")
)
// textWriter is an io.Writer that tracks its indentation level.
type textWriter struct {
compact bool // same as TextMarshaler.Compact
expandAny bool // same as TextMarshaler.ExpandAny
complete bool // whether the current position is a complete line
indent int // indentation level; never negative
buf []byte
}
func (w *textWriter) Write(p []byte) (n int, _ error) {
newlines := bytes.Count(p, newline)
if newlines == 0 {
if !w.compact && w.complete {
w.writeIndent()
}
w.buf = append(w.buf, p...)
w.complete = false
return len(p), nil
}
frags := bytes.SplitN(p, newline, newlines+1)
if w.compact {
for i, frag := range frags {
if i > 0 {
w.buf = append(w.buf, ' ')
n++
}
w.buf = append(w.buf, frag...)
n += len(frag)
}
return n, nil
}
for i, frag := range frags {
if w.complete {
w.writeIndent()
}
w.buf = append(w.buf, frag...)
n += len(frag)
if i+1 < len(frags) {
w.buf = append(w.buf, '\n')
n++
}
}
w.complete = len(frags[len(frags)-1]) == 0
return n, nil
}
func (w *textWriter) WriteByte(c byte) error {
if w.compact && c == '\n' {
c = ' '
}
if !w.compact && w.complete {
w.writeIndent()
}
w.buf = append(w.buf, c)
w.complete = c == '\n'
return nil
}
func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
if !w.compact && w.complete {
w.writeIndent()
}
w.complete = false
if fd.Kind() != protoreflect.GroupKind {
w.buf = append(w.buf, fd.Name()...)
w.WriteByte(':')
} else {
// Use message type name for group field name.
w.buf = append(w.buf, fd.Message().Name()...)
}
if !w.compact {
w.WriteByte(' ')
}
}
func requiresQuotes(u string) bool {
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
for _, ch := range u {
switch {
case ch == '.' || ch == '/' || ch == '_':
continue
case '0' <= ch && ch <= '9':
continue
case 'A' <= ch && ch <= 'Z':
continue
case 'a' <= ch && ch <= 'z':
continue
default:
return true
}
}
return false
}
// writeProto3Any writes an expanded google.protobuf.Any message.
//
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
// required messages are not linked in).
//
// It returns (true, error) when sv was written in expanded format or an error
// was encountered.
func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
md := m.Descriptor()
fdURL := md.Fields().ByName("type_url")
fdVal := md.Fields().ByName("value")
url := m.Get(fdURL).String()
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
if err != nil {
return false, nil
}
b := m.Get(fdVal).Bytes()
m2 := mt.New()
if err := proto.Unmarshal(b, m2.Interface()); err != nil {
return false, nil
}
w.Write([]byte("["))
if requiresQuotes(url) {
w.writeQuotedString(url)
} else {
w.Write([]byte(url))
}
if w.compact {
w.Write([]byte("]:<"))
} else {
w.Write([]byte("]: <\n"))
w.indent++
}
if err := w.writeMessage(m2); err != nil {
return true, err
}
if w.compact {
w.Write([]byte("> "))
} else {
w.indent--
w.Write([]byte(">\n"))
}
return true, nil
}
func (w *textWriter) writeMessage(m protoreflect.Message) error {
md := m.Descriptor()
if w.expandAny && md.FullName() == "google.protobuf.Any" {
if canExpand, err := w.writeProto3Any(m); canExpand {
return err
}
}
fds := md.Fields()
for i := 0; i < fds.Len(); {
fd := fds.Get(i)
if od := fd.ContainingOneof(); od != nil {
fd = m.WhichOneof(od)
i += od.Fields().Len()
} else {
i++
}
if fd == nil || !m.Has(fd) {
continue
}
switch {
case fd.IsList():
lv := m.Get(fd).List()
for j := 0; j < lv.Len(); j++ {
w.writeName(fd)
v := lv.Get(j)
if err := w.writeSingularValue(v, fd); err != nil {
return err
}
w.WriteByte('\n')
}
case fd.IsMap():
kfd := fd.MapKey()
vfd := fd.MapValue()
mv := m.Get(fd).Map()
type entry struct{ key, val protoreflect.Value }
var entries []entry
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
entries = append(entries, entry{k.Value(), v})
return true
})
sort.Slice(entries, func(i, j int) bool {
switch kfd.Kind() {
case protoreflect.BoolKind:
return !entries[i].key.Bool() && entries[j].key.Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return entries[i].key.Int() < entries[j].key.Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return entries[i].key.Uint() < entries[j].key.Uint()
case protoreflect.StringKind:
return entries[i].key.String() < entries[j].key.String()
default:
panic("invalid kind")
}
})
for _, entry := range entries {
w.writeName(fd)
w.WriteByte('<')
if !w.compact {
w.WriteByte('\n')
}
w.indent++
w.writeName(kfd)
if err := w.writeSingularValue(entry.key, kfd); err != nil {
return err
}
w.WriteByte('\n')
w.writeName(vfd)
if err := w.writeSingularValue(entry.val, vfd); err != nil {
return err
}
w.WriteByte('\n')
w.indent--
w.WriteByte('>')
w.WriteByte('\n')
}
default:
w.writeName(fd)
if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
return err
}
w.WriteByte('\n')
}
}
if b := m.GetUnknown(); len(b) > 0 {
w.writeUnknownFields(b)
}
return w.writeExtensions(m)
}
func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
switch fd.Kind() {
case protoreflect.FloatKind, protoreflect.DoubleKind:
switch vf := v.Float(); {
case math.IsInf(vf, +1):
w.Write(posInf)
case math.IsInf(vf, -1):
w.Write(negInf)
case math.IsNaN(vf):
w.Write(nan)
default:
fmt.Fprint(w, v.Interface())
}
case protoreflect.StringKind:
// NOTE: This does not validate UTF-8 for historical reasons.
w.writeQuotedString(string(v.String()))
case protoreflect.BytesKind:
w.writeQuotedString(string(v.Bytes()))
case protoreflect.MessageKind, protoreflect.GroupKind:
var bra, ket byte = '<', '>'
if fd.Kind() == protoreflect.GroupKind {
bra, ket = '{', '}'
}
w.WriteByte(bra)
if !w.compact {
w.WriteByte('\n')
}
w.indent++
m := v.Message()
if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
b, err := m2.MarshalText()
if err != nil {
return err
}
w.Write(b)
} else {
w.writeMessage(m)
}
w.indent--
w.WriteByte(ket)
case protoreflect.EnumKind:
if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
fmt.Fprint(w, ev.Name())
} else {
fmt.Fprint(w, v.Enum())
}
default:
fmt.Fprint(w, v.Interface())
}
return nil
}
// writeQuotedString writes a quoted string in the protocol buffer text format.
func (w *textWriter) writeQuotedString(s string) {
w.WriteByte('"')
for i := 0; i < len(s); i++ {
switch c := s[i]; c {
case '\n':
w.buf = append(w.buf, `\n`...)
case '\r':
w.buf = append(w.buf, `\r`...)
case '\t':
w.buf = append(w.buf, `\t`...)
case '"':
w.buf = append(w.buf, `\"`...)
case '\\':
w.buf = append(w.buf, `\\`...)
default:
if isPrint := c >= 0x20 && c < 0x7f; isPrint {
w.buf = append(w.buf, c)
} else {
w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
}
}
}
w.WriteByte('"')
}
func (w *textWriter) writeUnknownFields(b []byte) {
if !w.compact {
fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
}
for len(b) > 0 {
num, wtyp, n := protowire.ConsumeTag(b)
if n < 0 {
return
}
b = b[n:]
if wtyp == protowire.EndGroupType {
w.indent--
w.Write(endBraceNewline)
continue
}
fmt.Fprint(w, num)
if wtyp != protowire.StartGroupType {
w.WriteByte(':')
}
if !w.compact || wtyp == protowire.StartGroupType {
w.WriteByte(' ')
}
switch wtyp {
case protowire.VarintType:
v, n := protowire.ConsumeVarint(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.Fixed32Type:
v, n := protowire.ConsumeFixed32(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.Fixed64Type:
v, n := protowire.ConsumeFixed64(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprint(w, v)
case protowire.BytesType:
v, n := protowire.ConsumeBytes(b)
if n < 0 {
return
}
b = b[n:]
fmt.Fprintf(w, "%q", v)
case protowire.StartGroupType:
w.WriteByte('{')
w.indent++
default:
fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
}
w.WriteByte('\n')
}
}
// writeExtensions writes all the extensions in m.
func (w *textWriter) writeExtensions(m protoreflect.Message) error {
md := m.Descriptor()
if md.ExtensionRanges().Len() == 0 {
return nil
}
type ext struct {
desc protoreflect.FieldDescriptor
val protoreflect.Value
}
var exts []ext
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
if fd.IsExtension() {
exts = append(exts, ext{fd, v})
}
return true
})
sort.Slice(exts, func(i, j int) bool {
return exts[i].desc.Number() < exts[j].desc.Number()
})
for _, ext := range exts {
// For message set, use the name of the message as the extension name.
name := string(ext.desc.FullName())
if isMessageSet(ext.desc.ContainingMessage()) {
name = strings.TrimSuffix(name, ".message_set_extension")
}
if !ext.desc.IsList() {
if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
return err
}
} else {
lv := ext.val.List()
for i := 0; i < lv.Len(); i++ {
if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
return err
}
}
}
}
return nil
}
func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
fmt.Fprintf(w, "[%s]:", name)
if !w.compact {
w.WriteByte(' ')
}
if err := w.writeSingularValue(v, fd); err != nil {
return err
}
w.WriteByte('\n')
return nil
}
func (w *textWriter) writeIndent() {
if !w.complete {
return
}
for i := 0; i < w.indent*2; i++ {
w.buf = append(w.buf, ' ')
}
w.complete = false
}

78
vendor/github.com/golang/protobuf/proto/wire.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
import (
protoV2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/runtime/protoiface"
)
// Size returns the size in bytes of the wire-format encoding of m.
func Size(m Message) int {
if m == nil {
return 0
}
mi := MessageV2(m)
return protoV2.Size(mi)
}
// Marshal returns the wire-format encoding of m.
func Marshal(m Message) ([]byte, error) {
b, err := marshalAppend(nil, m, false)
if b == nil {
b = zeroBytes
}
return b, err
}
var zeroBytes = make([]byte, 0, 0)
func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) {
if m == nil {
return nil, ErrNil
}
mi := MessageV2(m)
nbuf, err := protoV2.MarshalOptions{
Deterministic: deterministic,
AllowPartial: true,
}.MarshalAppend(buf, mi)
if err != nil {
return buf, err
}
if len(buf) == len(nbuf) {
if !mi.ProtoReflect().IsValid() {
return buf, ErrNil
}
}
return nbuf, checkRequiredNotSet(mi)
}
// Unmarshal parses a wire-format message in b and places the decoded results in m.
//
// Unmarshal resets m before starting to unmarshal, so any existing data in m is always
// removed. Use UnmarshalMerge to preserve and append to existing data.
func Unmarshal(b []byte, m Message) error {
m.Reset()
return UnmarshalMerge(b, m)
}
// UnmarshalMerge parses a wire-format message in b and places the decoded results in m.
func UnmarshalMerge(b []byte, m Message) error {
mi := MessageV2(m)
out, err := protoV2.UnmarshalOptions{
AllowPartial: true,
Merge: true,
}.UnmarshalState(protoiface.UnmarshalInput{
Buf: b,
Message: mi.ProtoReflect(),
})
if err != nil {
return err
}
if out.Flags&protoiface.UnmarshalInitialized > 0 {
return nil
}
return checkRequiredNotSet(mi)
}

34
vendor/github.com/golang/protobuf/proto/wrappers.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package proto
// Bool stores v in a new bool value and returns a pointer to it.
func Bool(v bool) *bool { return &v }
// Int stores v in a new int32 value and returns a pointer to it.
//
// Deprecated: Use Int32 instead.
func Int(v int) *int32 { return Int32(int32(v)) }
// Int32 stores v in a new int32 value and returns a pointer to it.
func Int32(v int32) *int32 { return &v }
// Int64 stores v in a new int64 value and returns a pointer to it.
func Int64(v int64) *int64 { return &v }
// Uint32 stores v in a new uint32 value and returns a pointer to it.
func Uint32(v uint32) *uint32 { return &v }
// Uint64 stores v in a new uint64 value and returns a pointer to it.
func Uint64(v uint64) *uint64 { return &v }
// Float32 stores v in a new float32 value and returns a pointer to it.
func Float32(v float32) *float32 { return &v }
// Float64 stores v in a new float64 value and returns a pointer to it.
func Float64(v float64) *float64 { return &v }
// String stores v in a new string value and returns a pointer to it.
func String(v string) *string { return &v }