Files
mongo/src/third_party/s2/s2.cc

771 lines
33 KiB
C++

// Copyright 2005 Google Inc. All Rights Reserved.
#include "s2.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "util/math/matrix3x3-inl.h"
#include "util/math/vector2-inl.h"
// Define storage for header file constants (the values are not needed
// here for integral constants).
int const S2::kSwapMask = 0x01;
int const S2::kInvertMask = 0x02;
int const S2::kMaxCellLevel = 30;
double const S2::kMaxDetError = 0.8e-15; // 14 * (2**-54)
// Enable debugging checks in s2 code?
bool const S2::debug = DEBUG_MODE;
COMPILE_ASSERT(S2::kSwapMask == 0x01 && S2::kInvertMask == 0x02,
masks_changed);
static const uint32 MIX32 = 0x12b9b0a1UL;
HASH_NAMESPACE_START
// The hash function due to Bob Jenkins (see
// http://burtleburtle.net/bob/hash/index.html).
static inline void mix(uint32& a, uint32& b, uint32& c) { // 32bit version
a -= b; a -= c; a ^= (c>>13);
b -= c; b -= a; b ^= (a<<8);
c -= a; c -= b; c ^= (b>>13);
a -= b; a -= c; a ^= (c>>12);
b -= c; b -= a; b ^= (a<<16);
c -= a; c -= b; c ^= (b>>5);
a -= b; a -= c; a ^= (c>>3);
b -= c; b -= a; b ^= (a<<10);
c -= a; c -= b; c ^= (b>>15);
}
inline uint32 CollapseZero(uint32 bits) {
// IEEE 754 has two representations for zero, positive zero and negative
// zero. These two values compare as equal, and therefore we need them to
// hash to the same value.
//
// We handle this by simply clearing the top bit of every 32-bit value,
// which clears the sign bit on both big-endian and little-endian
// architectures. This creates some additional hash collisions between
// points that differ only in the sign of their components, but this is
// rarely a problem with real data.
//
// The obvious alternative is to explicitly map all occurrences of positive
// zero to negative zero (or vice versa), but this is more expensive and
// makes the average case slower.
//
// We also mask off the low-bit because we've seen differences in
// some floating point operations (specifically 'fcos' on i386)
// between different implementations of the same architecure
// (e.g. 'Xeon 5345' vs. 'Opteron 270'). It's unknown how many bits
// of mask are sufficient to cover real world cases, but the intent
// is to be as conservative as possible in discarding bits.
return bits & 0x7ffffffe;
}
size_t makeHash(S2Point const& p) {
// This function is significantly faster than calling HashTo32().
uint32 const* data = reinterpret_cast<uint32 const*>(p.Data());
DCHECK_EQ((6 * sizeof(*data)), sizeof(p));
// We call CollapseZero() on every 32-bit chunk to avoid having endian
// dependencies.
uint32 a = CollapseZero(data[0]);
uint32 b = CollapseZero(data[1]);
uint32 c = CollapseZero(data[2]) + 0x12b9b0a1UL; // An arbitrary number
mix(a, b, c);
a += CollapseZero(data[3]);
b += CollapseZero(data[4]);
c += CollapseZero(data[5]);
mix(a, b, c);
return c;
}
size_t hash<S2Point>::operator()(S2Point const& p) const {
return makeHash(p);
}
HASH_NAMESPACE_END
bool S2::IsUnitLength(S2Point const& p) {
return fabs(p.Norm2() - 1) <= 1e-15;
}
S2Point S2::Ortho(S2Point const& a) {
#ifdef S2_TEST_DEGENERACIES
// Vector3::Ortho() always returns a point on the X-Y, Y-Z, or X-Z planes.
// This leads to many more degenerate cases in polygon operations.
return a.Ortho();
#else
int k = a.LargestAbsComponent() - 1;
if (k < 0) k = 2;
S2Point temp(0.012, 0.0053, 0.00457);
temp[k] = 1;
return a.CrossProd(temp).Normalize();
#endif
}
void S2::GetFrame(S2Point const& z, Matrix3x3_d* m) {
DCHECK(IsUnitLength(z));
m->SetCol(2, z);
m->SetCol(1, Ortho(z));
m->SetCol(0, m->Col(1).CrossProd(z)); // Already unit-length.
}
S2Point S2::ToFrame(Matrix3x3_d const& m, S2Point const& p) {
// The inverse of an orthonormal matrix is its transpose.
return m.Transpose() * p;
}
S2Point S2::FromFrame(Matrix3x3_d const& m, S2Point const& q) {
return m * q;
}
bool S2::ApproxEquals(S2Point const& a, S2Point const& b, double max_error) {
return a.Angle(b) <= max_error;
}
S2Point S2::RobustCrossProd(S2Point const& a, S2Point const& b) {
// The direction of a.CrossProd(b) becomes unstable as (a + b) or (a - b)
// approaches zero. This leads to situations where a.CrossProd(b) is not
// very orthogonal to "a" and/or "b". We could fix this using Gram-Schmidt,
// but we also want b.RobustCrossProd(a) == -a.RobustCrossProd(b).
//
// The easiest fix is to just compute the cross product of (b+a) and (b-a).
// Mathematically, this cross product is exactly twice the cross product of
// "a" and "b", but it has the numerical advantage that (b+a) and (b-a)
// are always perpendicular (since "a" and "b" are unit length). This
// yields a result that is nearly orthogonal to both "a" and "b" even if
// these two values differ only in the lowest bit of one component.
DCHECK(IsUnitLength(a));
DCHECK(IsUnitLength(b));
S2Point x = (b + a).CrossProd(b - a);
if (x != S2Point(0, 0, 0)) return x;
// The only result that makes sense mathematically is to return zero, but
// we find it more convenient to return an arbitrary orthogonal vector.
return Ortho(a);
}
bool S2::SimpleCCW(S2Point const& a, S2Point const& b, S2Point const& c) {
// We compute the signed volume of the parallelepiped ABC. The usual
// formula for this is (AxB).C, but we compute it here using (CxA).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.CrossProd(y) == -(y.CrossProd(x))
// (2) (-x).DotProd(y) == -(x.DotProd(y))
return c.CrossProd(a).DotProd(b) > 0;
}
int S2::RobustCCW(S2Point const& a, S2Point const& b, S2Point const& c) {
// We don't need RobustCrossProd() here because RobustCCW() does its own
// error estimation and calls ExpensiveCCW() if there is any uncertainty
// about the result.
return RobustCCW(a, b, c, a.CrossProd(b));
}
// Below we define two versions of ExpensiveCCW(). The first version uses
// arbitrary-precision arithmetic (MPFloat) and the "simulation of simplicity"
// technique. It is completely robust (i.e., it returns consistent results
// for all possible inputs). The second version uses normal double-precision
// arithmetic. It is numerically stable and handles many degeneracies well,
// but it is not perfectly robust. It exists mainly for testing purposes, so
// that we can verify that certain tests actually require the more advanced
// techniques implemented by the first version.
#undef SIMULATION_OF_SIMPLICITY
#ifdef SIMULATION_OF_SIMPLICITY
// Below we define a floating-point type with enough precision so that it can
// represent the exact determinant of any 3x3 matrix of floating-point
// numbers. We support two options: MPFloat (which is based on MPFR and is
// therefore subject to an LGPL license) and ExactFloat (which is based on the
// OpenSSL Bignum library and therefore has a permissive BSD-style license).
#ifdef S2_USE_EXACTFLOAT
// ExactFloat only supports exact calculations with floating-point numbers.
#include "util/math/exactfloat/exactfloat.h"
#else // S2_USE_EXACTFLOAT
// MPFloat requires a "maximum precision" to be specified.
//
// To figure out how much precision we need, first observe that any double
// precision number can be represented as an integer by multiplying it by
// 2**1074. This is because the minimum exponent is -1022, and denormalized
// numbers have 52 bits after the leading "0". On the other hand, the largest
// double precision value has the form 1.x * (2**1023), which is a 1024-bit
// integer. Therefore any double precision value can be represented as a
// (1074 + 1024) = 2098 bit integer.
//
// A 3x3 determinant is computed by adding together 6 values, each of which is
// the product of 3 of the input values. When an m-bit integer is multiplied
// by an n-bit integer, the result has at most (m+n) bits. When "k" m-bit
// integers are added together, the result has at most m + ceil(log2(k)) bits.
// Therefore the determinant of any 3x3 matrix can be represented exactly
// using no more than (3*2098)+3 = 6297 bits.
//
// Note that MPFloat only uses as much precision as required to compute the
// exact result, and that typically far fewer bits of precision are used. The
// worst-case estimate above is only achieved for a matrix where every row
// contains both the maximum and minimum possible double precision values
// (i.e. approximately 1e308 and 1e-323). For randomly chosen unit-length
// vectors, the average case uses only about 200 bits of precision.
// The maximum precision must be at least (6297 + 1) so that we can assert
// that the result of the determinant calculation is exact (by checking that
// the actual precision of the result is less than the maximum precision
// specified).
#include "util/math/mpfloat/mpfloat.h"
typedef MPFloat<6300> ExactFloat;
#endif // S2_USE_EXACTFLOAT
typedef Vector3<ExactFloat> Vector3_xf;
// The following function returns the sign of the determinant of three points
// A, B, C under a model where every possible S2Point 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).
//
// 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.
//
// Requirements:
// The 3x3 determinant of A, B, C must be exactly zero.
// The points must be distinct, with A < B < C in lexicographic order.
//
// Returns:
// +1 or -1 according to the sign of the determinant after the symbolic
// perturbations are taken into account.
//
// Reference:
// "Simulation of Simplicity" (Edelsbrunner and Muecke, ACM Transactions on
// Graphics, 1990).
//
static int SymbolicallyPerturbedCCW(
Vector3_xf const& a, Vector3_xf const& b,
Vector3_xf const& c, Vector3_xf const& b_cross_c) {
// This method requires that the points are sorted in lexicographically
// increasing order. This is because every possible S2Point 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.
DCHECK(a < b && b < 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[0]+da[0] a[1]+da[1] a[2]+da[2] |
// | b[0]+db[0] b[1]+db[1] b[2]+db[2] |
// | c[0]+dc[0] c[1]+dc[1] c[2]+dc[2] |
//
// The perturbations are chosen such that
//
// da[2] > da[1] > da[0] > db[2] > db[1] > db[0] > dc[2] > dc[1] > dc[0]
//
// 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[1] unless the coefficient of db[2]*da[0] 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[2] da[1] da[0] db[2] db[1] db[0] dc[2] dc[1] dc[0]
//
// 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[2]*da[0] before db[1] 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[2]*da[1], db[1]*da[1], etc. Furthermore, sometimes different pairs of
// perturbations have the same coefficient in the determinant; for example,
// da[1]*db[0] and db[1]*da[0] have the same coefficient (c[2]). Therefore
// we only need to test this coefficient the first time we encounter it in
// the binary order above (which will be db[1]*da[0]).
//
// 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).
int det_sign = b_cross_c[2].sgn(); // da[2]
if (det_sign != 0) return det_sign;
det_sign = b_cross_c[1].sgn(); // da[1]
if (det_sign != 0) return det_sign;
det_sign = b_cross_c[0].sgn(); // da[0]
if (det_sign != 0) return det_sign;
det_sign = (c[0]*a[1] - c[1]*a[0]).sgn(); // db[2]
if (det_sign != 0) return det_sign;
det_sign = c[0].sgn(); // db[2] * da[1]
if (det_sign != 0) return det_sign;
det_sign = -(c[1].sgn()); // db[2] * da[0]
if (det_sign != 0) return det_sign;
det_sign = (c[2]*a[0] - c[0]*a[2]).sgn(); // db[1]
if (det_sign != 0) return det_sign;
det_sign = c[2].sgn(); // db[1] * da[0]
if (det_sign != 0) return det_sign;
// The following test is listed in the paper, but it is redundant because
// the previous tests guarantee that C == (0, 0, 0).
DCHECK_EQ(0, (c[1]*a[2] - c[2]*a[1]).sgn()); // db[0]
det_sign = (a[0]*b[1] - a[1]*b[0]).sgn(); // dc[2]
if (det_sign != 0) return det_sign;
det_sign = -(b[0].sgn()); // dc[2] * da[1]
if (det_sign != 0) return det_sign;
det_sign = b[1].sgn(); // dc[2] * da[0]
if (det_sign != 0) return det_sign;
det_sign = a[0].sgn(); // dc[2] * db[1]
if (det_sign != 0) return det_sign;
return 1; // dc[2] * db[1] * da[0]
}
int S2::ExpensiveCCW(S2Point const& a, S2Point const& b, S2Point const& c) {
// Return zero if and only if two points are the same. This ensures (1).
if (a == b || b == c || c == a) return 0;
// Sort the three points in lexicographic order, keeping track of the sign
// of the permutation. (Each exchange inverts the sign of the determinant.)
int perm_sign = 1;
S2Point pa = a, pb = b, pc = c;
if (pa > pb) { swap(pa, pb); perm_sign = -perm_sign; }
if (pb > pc) { swap(pb, pc); perm_sign = -perm_sign; }
if (pa > pb) { swap(pa, pb); perm_sign = -perm_sign; }
DCHECK(pa < pb && pb < pc);
// Construct multiple-precision versions of the sorted points and compute
// their exact 3x3 determinant.
Vector3_xf xa = Vector3_xf::Cast(pa);
Vector3_xf xb = Vector3_xf::Cast(pb);
Vector3_xf xc = Vector3_xf::Cast(pc);
Vector3_xf xb_cross_xc = xb.CrossProd(xc);
ExactFloat det = xa.DotProd(xb_cross_xc);
// The precision of ExactFloat is high enough that the result should always
// be exact (no rounding was performed).
DCHECK(!det.is_nan());
DCHECK_LT(det.prec(), det.max_prec());
// If the exact determinant is non-zero, we're done.
int det_sign = det.sgn();
if (det_sign == 0) {
// Otherwise, we need to resort to symbolic perturbations to resolve the
// sign of the determinant.
det_sign = SymbolicallyPerturbedCCW(xa, xb, xc, xb_cross_xc);
}
DCHECK(det_sign != 0);
return perm_sign * det_sign;
}
#else // SIMULATION_OF_SIMPLICITY
static inline int PlanarCCW(Vector2_d const& a, Vector2_d const& b) {
// Return +1 if the edge AB is CCW around the origin, etc.
double sab = (a.DotProd(b) > 0) ? -1 : 1;
Vector2_d vab = a + sab * b;
double da = a.Norm2();
double db = b.Norm2();
double sign;
if (da < db || (da == db && a < b)) {
sign = a.CrossProd(vab) * sab;
} else {
sign = vab.CrossProd(b);
}
if (sign > 0) return 1;
if (sign < 0) return -1;
return 0;
}
static inline int PlanarOrderedCCW(Vector2_d const& a, Vector2_d const& b,
Vector2_d const& c) {
int sum = 0;
sum += PlanarCCW(a, b);
sum += PlanarCCW(b, c);
sum += PlanarCCW(c, a);
if (sum > 0) return 1;
if (sum < 0) return -1;
return 0;
}
int S2::ExpensiveCCW(S2Point const& a, S2Point const& b, S2Point const& c) {
// Return zero if and only if two points are the same. This ensures (1).
if (a == b || b == c || c == a) return 0;
// Now compute the determinant in a stable way. Since all three points are
// unit length and we know that the determinant is very close to zero, this
// means that points are very nearly collinear. Furthermore, the most common
// situation is where two points are nearly identical or nearly antipodal.
// To get the best accuracy in this situation, it is important to
// immediately reduce the magnitude of the arguments by computing either
// A+B or A-B for each pair of points. Note that even if A and B differ
// only in their low bits, A-B can be computed very accurately. On the
// other hand we can't accurately represent an arbitrary linear combination
// of two vectors as would be required for Gaussian elimination. The code
// below chooses the vertex opposite the longest edge as the "origin" for
// the calculation, and computes the different vectors to the other two
// vertices. This minimizes the sum of the lengths of these vectors.
//
// This implementation is very stable numerically, but it still does not
// return consistent results in all cases. For example, if three points are
// spaced far apart from each other along a great circle, the sign of the
// result will basically be random (although it will still satisfy the
// conditions documented in the header file). The only way to return
// consistent results in all cases is to compute the result using
// multiple-precision arithmetic. I considered using the Gnu MP library,
// but this would be very expensive (up to 2000 bits of precision may be
// needed to store the intermediate results) and seems like overkill for
// this problem. The MP library is apparently also quite particular about
// compilers and compilation options and would be a pain to maintain.
// We want to handle the case of nearby points and nearly antipodal points
// accurately, so determine whether A+B or A-B is smaller in each case.
double sab = (a.DotProd(b) > 0) ? -1 : 1;
double sbc = (b.DotProd(c) > 0) ? -1 : 1;
double sca = (c.DotProd(a) > 0) ? -1 : 1;
S2Point vab = a + sab * b;
S2Point vbc = b + sbc * c;
S2Point vca = c + sca * a;
double dab = vab.Norm2();
double dbc = vbc.Norm2();
double dca = vca.Norm2();
// Sort the difference vectors to find the longest edge, and use the
// opposite vertex as the origin. If two difference vectors are the same
// length, we break ties deterministically to ensure that the symmetry
// properties guaranteed in the header file will be true.
double sign;
if (dca < dbc || (dca == dbc && a < b)) {
if (dab < dbc || (dab == dbc && a < c)) {
// The "sab" factor converts A +/- B into B +/- A.
sign = vab.CrossProd(vca).DotProd(a) * sab; // BC is longest edge
} else {
sign = vca.CrossProd(vbc).DotProd(c) * sca; // AB is longest edge
}
} else {
if (dab < dca || (dab == dca && b < c)) {
sign = vbc.CrossProd(vab).DotProd(b) * sbc; // CA is longest edge
} else {
sign = vca.CrossProd(vbc).DotProd(c) * sca; // AB is longest edge
}
}
if (sign > 0) return 1;
if (sign < 0) return -1;
// The points A, B, and C are numerically indistinguishable from coplanar.
// This may be due to roundoff error, or the points may in fact be exactly
// coplanar. We handle this situation by perturbing all of the points by a
// vector (eps, eps**2, eps**3) where "eps" is an infinitesmally small
// positive number (e.g. 1 divided by a googolplex). The perturbation is
// done symbolically, i.e. we compute what would happen if the points were
// perturbed by this amount. It turns out that this is equivalent to
// checking whether the points are ordered CCW around the origin first in
// the Y-Z plane, then in the Z-X plane, and then in the X-Y plane.
int ccw = PlanarOrderedCCW(Vector2_d(a.y(), a.z()), Vector2_d(b.y(), b.z()),
Vector2_d(c.y(), c.z()));
if (ccw == 0) {
ccw = PlanarOrderedCCW(Vector2_d(a.z(), a.x()), Vector2_d(b.z(), b.x()),
Vector2_d(c.z(), c.x()));
if (ccw == 0) {
ccw = PlanarOrderedCCW(Vector2_d(a.x(), a.y()), Vector2_d(b.x(), b.y()),
Vector2_d(c.x(), c.y()));
// There are a few cases where "ccw" may still be zero despite our best
// efforts. For example, two input points may be exactly proportional
// to each other (where both still satisfy IsNormalized()).
}
}
return ccw;
}
#endif // SIMULATION_OF_SIMPLICITY
double S2::Angle(S2Point const& a, S2Point const& b, S2Point const& c) {
return RobustCrossProd(a, b).Angle(RobustCrossProd(c, b));
}
double S2::TurnAngle(S2Point const& a, S2Point const& b, S2Point const& c) {
// This is a bit less efficient because we compute all 3 cross products, but
// it ensures that TurnAngle(a,b,c) == -TurnAngle(c,b,a) for all a,b,c.
double angle = RobustCrossProd(b, a).Angle(RobustCrossProd(c, b));
return (RobustCCW(a, b, c) > 0) ? angle : -angle;
}
double S2::Area(S2Point const& a, S2Point const& b, S2Point const& c) {
DCHECK(IsUnitLength(a));
DCHECK(IsUnitLength(b));
DCHECK(IsUnitLength(c));
// 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.
// We use volatile doubles to force the compiler to truncate all of these
// quantities to 64 bits. Otherwise it may compute a value of dmin > 0
// simply because it chose to spill one of the intermediate values to
// memory but not one of the others.
volatile double sa = b.Angle(c);
volatile double sb = c.Angle(a);
volatile double sc = a.Angle(b);
volatile double s = 0.5 * (sa + sb + sc);
if (s >= 3e-4) {
// Consider whether Girard's formula might be more accurate.
double s2 = s * s;
double dmin = s - max(sa, max(sb, sc));
if (dmin < 1e-2 * s * s2 * s2) {
// This triangle is skinny enough to consider Girard's formula.
double area = GirardArea(a, b, c);
if (dmin < s * (0.1 * area)) return area;
}
}
// Use l'Huilier's formula.
return 4 * atan(sqrt(max(0.0, tan(0.5 * s) * tan(0.5 * (s - sa)) *
tan(0.5 * (s - sb)) * tan(0.5 * (s - sc)))));
}
double S2::GirardArea(S2Point const& a, S2Point const& b, S2Point const& c) {
// 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. The use of RobustCrossProd() makes it much more
// accurate when two vertices are nearly identical or antipodal.
S2Point ab = RobustCrossProd(a, b);
S2Point bc = RobustCrossProd(b, c);
S2Point ac = RobustCrossProd(a, c);
return max(0.0, ab.Angle(ac) - ab.Angle(bc) + bc.Angle(ac));
}
double S2::SignedArea(S2Point const& a, S2Point const& b, S2Point const& c) {
return Area(a, b, c) * RobustCCW(a, b, c);
}
S2Point S2::PlanarCentroid(S2Point const& a, S2Point const& b,
S2Point const& c) {
return (1./3) * (a + b + c);
}
S2Point S2::TrueCentroid(S2Point const& a, S2Point const& b,
S2Point const& c) {
DCHECK(IsUnitLength(a));
DCHECK(IsUnitLength(b));
DCHECK(IsUnitLength(c));
// I couldn't find any references for computing the true centroid of a
// spherical triangle... I have a truly marvellous demonstration of this
// formula which this margin is too narrow to contain :)
// Use Angle() in order to get accurate results for small triangles.
double angle_a = b.Angle(c);
double angle_b = c.Angle(a);
double angle_c = a.Angle(b);
double ra = (angle_a == 0) ? 1 : (angle_a / sin(angle_a));
double rb = (angle_b == 0) ? 1 : (angle_b / sin(angle_b));
double rc = (angle_c == 0) ? 1 : (angle_c / sin(angle_c));
// 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.
//
// TODO(user): 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.
S2Point x(a.x(), b.x() - a.x(), c.x() - a.x());
S2Point y(a.y(), b.y() - a.y(), c.y() - a.y());
S2Point z(a.z(), b.z() - a.z(), c.z() - a.z());
S2Point r(ra, rb - ra, rc - ra);
return 0.5 * S2Point(y.CrossProd(z).DotProd(r),
z.CrossProd(x).DotProd(r),
x.CrossProd(y).DotProd(r));
}
bool S2::OrderedCCW(S2Point const& a, S2Point const& b, S2Point const& c,
S2Point const& o) {
// The last inequality below is ">" rather than ">=" so that we return true
// if A == B or B == C, and otherwise false if A == C. Recall that
// RobustCCW(x,y,z) == -RobustCCW(z,y,x) for all x,y,z.
int sum = 0;
if (RobustCCW(b, o, a) >= 0) ++sum;
if (RobustCCW(c, o, b) >= 0) ++sum;
if (RobustCCW(a, o, c) > 0) ++sum;
return sum >= 2;
}
// kIJtoPos[orientation][ij] -> pos
int const S2::kIJtoPos[4][4] = {
// (0,0) (0,1) (1,0) (1,1)
{ 0, 1, 3, 2 }, // canonical order
{ 0, 3, 1, 2 }, // axes swapped
{ 2, 3, 1, 0 }, // bits inverted
{ 2, 1, 3, 0 }, // swapped & inverted
};
// kPosToIJ[orientation][pos] -> ij
int const S2::kPosToIJ[4][4] = {
// 0 1 2 3
{ 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)
};
// kPosToOrientation[pos] -> orientation_modifier
int const S2::kPosToOrientation[4] = {
kSwapMask,
0,
0,
kInvertMask + kSwapMask,
};
// All of the values below were obtained by a combination of hand analysis and
// Mathematica. In general, S2_TAN_PROJECTION produces the most uniform
// shapes and sizes of cells, S2_LINEAR_PROJECTION is considerably worse, and
// S2_QUADRATIC_PROJECTION is somewhere in between (but generally closer to
// the tangent projection than the linear one).
S2::LengthMetric const S2::kMinAngleSpan(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.0 : // 1.000
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / 2 : // 1.571
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 4. / 3 : // 1.333
0);
S2::LengthMetric const S2::kMaxAngleSpan(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 : // 2.000
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / 2 : // 1.571
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.704897179199218452 : // 1.705
0);
S2::LengthMetric const S2::kAvgAngleSpan(M_PI / 2); // 1.571
// This is true for all projections.
S2::LengthMetric const S2::kMinWidth(
S2_PROJECTION == S2_LINEAR_PROJECTION ? sqrt(2. / 3) : // 0.816
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / (2 * sqrt(2.)) : // 1.111
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2 * sqrt(2.) / 3 : // 0.943
0);
S2::LengthMetric const S2::kMaxWidth(S2::kMaxAngleSpan.deriv());
// This is true for all projections.
S2::LengthMetric const S2::kAvgWidth(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.411459345844456965 : // 1.411
S2_PROJECTION == S2_TAN_PROJECTION ? 1.437318638925160885 : // 1.437
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.434523672886099389 : // 1.435
0);
S2::LengthMetric const S2::kMinEdge(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.) / 3 : // 0.943
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI / (2 * sqrt(2.)) : // 1.111
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2 * sqrt(2.) / 3 : // 0.943
0);
S2::LengthMetric const S2::kMaxEdge(S2::kMaxAngleSpan.deriv());
// This is true for all projections.
S2::LengthMetric const S2::kAvgEdge(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 1.440034192955603643 : // 1.440
S2_PROJECTION == S2_TAN_PROJECTION ? 1.461667032546739266 : // 1.462
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.459213746386106062 : // 1.459
0);
S2::LengthMetric const S2::kMinDiag(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.) / 3 : // 0.943
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * sqrt(2.) / 3 : // 1.481
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 8 * sqrt(2.) / 9 : // 1.257
0);
S2::LengthMetric const S2::kMaxDiag(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 2 * sqrt(2.) : // 2.828
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * sqrt(2. / 3) : // 2.565
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.438654594434021032 : // 2.439
0);
S2::LengthMetric const S2::kAvgDiag(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 2.031817866418812674 : // 2.032
S2_PROJECTION == S2_TAN_PROJECTION ? 2.063623197195635753 : // 2.064
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.060422738998471683 : // 2.060
0);
S2::AreaMetric const S2::kMinArea(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 4 / (3 * sqrt(3.)) : // 0.770
S2_PROJECTION == S2_TAN_PROJECTION ? (M_PI*M_PI) / (4*sqrt(2.)) : // 1.745
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 8 * sqrt(2.) / 9 : // 1.257
0);
S2::AreaMetric const S2::kMaxArea(
S2_PROJECTION == S2_LINEAR_PROJECTION ? 4 : // 4.000
S2_PROJECTION == S2_TAN_PROJECTION ? M_PI * M_PI / 4 : // 2.467
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 2.635799256963161491 : // 2.636
0);
S2::AreaMetric const S2::kAvgArea(4 * M_PI / 6); // 2.094
// This is true for all projections.
double const S2::kMaxEdgeAspect = (
S2_PROJECTION == S2_LINEAR_PROJECTION ? sqrt(2.) : // 1.414
S2_PROJECTION == S2_TAN_PROJECTION ? sqrt(2.) : // 1.414
S2_PROJECTION == S2_QUADRATIC_PROJECTION ? 1.442615274452682920 : // 1.443
0);
double const S2::kMaxDiagAspect = sqrt(3.); // 1.732
// This is true for all projections.