diff options
author | 2024-07-12 09:39:47 +0000 | |
---|---|---|
committer | 2024-07-12 09:39:47 +0000 | |
commit | cde2fb6244a791b3c5b746112e3a8be3a79f39a4 (patch) | |
tree | 6079d6fb66d90ffbe8c1623525bb86829c162459 /vendor/github.com/golang/geo/s2/edge_distances.go | |
parent | [chore] Add interaction policy gtsmodels (#3075) (diff) | |
download | gotosocial-cde2fb6244a791b3c5b746112e3a8be3a79f39a4.tar.xz |
[feature] support processing of (many) more media types (#3090)
* initial work replacing our media decoding / encoding pipeline with ffprobe + ffmpeg
* specify the video codec to use when generating static image from emoji
* update go-storage library (fixes incompatibility after updating go-iotools)
* maintain image aspect ratio when generating a thumbnail for it
* update readme to show go-ffmpreg
* fix a bunch of media tests, move filesize checking to callers of media manager for more flexibility
* remove extra debug from error message
* fix up incorrect function signatures
* update PutFile to just use regular file copy, as changes are file is on separate partition
* fix remaining tests, remove some unneeded tests now we're working with ffmpeg/ffprobe
* update more tests, add more code comments
* add utilities to generate processed emoji / media outputs
* fix remaining tests
* add test for opus media file, add license header to utility cmds
* limit the number of concurrently available ffmpeg / ffprobe instances
* reduce number of instances
* further reduce number of instances
* fix envparsing test with configuration variables
* update docs and configuration with new media-{local,remote}-max-size variables
Diffstat (limited to 'vendor/github.com/golang/geo/s2/edge_distances.go')
-rw-r--r-- | vendor/github.com/golang/geo/s2/edge_distances.go | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/vendor/github.com/golang/geo/s2/edge_distances.go b/vendor/github.com/golang/geo/s2/edge_distances.go deleted file mode 100644 index ca197af1d..000000000 --- a/vendor/github.com/golang/geo/s2/edge_distances.go +++ /dev/null @@ -1,408 +0,0 @@ -// 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") - } -} |