mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[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
This commit is contained in:
362
vendor/github.com/golang/geo/s2/min_distance_targets.go
generated
vendored
362
vendor/github.com/golang/geo/s2/min_distance_targets.go
generated
vendored
@ -1,362 +0,0 @@
|
||||
// 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
|
Reference in New Issue
Block a user