diff options
Diffstat (limited to 'vendor/github.com/golang/geo/s1/interval.go')
-rw-r--r-- | vendor/github.com/golang/geo/s1/interval.go | 462 |
1 files changed, 0 insertions, 462 deletions
diff --git a/vendor/github.com/golang/geo/s1/interval.go b/vendor/github.com/golang/geo/s1/interval.go deleted file mode 100644 index 6fea5221f..000000000 --- a/vendor/github.com/golang/geo/s1/interval.go +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2014 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package 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 -} |