mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-23 12:16:38 +00:00
197 lines
7.8 KiB
Go
197 lines
7.8 KiB
Go
|
// 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,
|
||
|
}
|
||
|
}
|