public void Test_S1ChordAngle_GetS2PointConstructorMaxError() { // Check that the error bound returned by GetS2PointConstructorMaxError() is // large enough. for (var iter = 0; iter < 100000; ++iter) { S2Testing.Random.Reset(iter); // Easier to reproduce a specific case. var x = S2Testing.RandomPoint(); var y = S2Testing.RandomPoint(); if (S2Testing.Random.OneIn(10)) { // Occasionally test a point pair that is nearly identical or antipodal. var r = S1Angle.FromRadians(S2.DoubleError * S2Testing.Random.RandDouble()); y = S2.GetPointOnLine(x, y, r); if (S2Testing.Random.OneIn(2)) { y = -y; } } S1ChordAngle dist = new(x, y); var error = dist.GetS2PointConstructorMaxError(); var er1 = S2Pred.CompareDistance(x, y, dist.PlusError(error)); if (er1 > 0) { } Assert.True(er1 <= 0); var er2 = S2Pred.CompareDistance(x, y, dist.PlusError(-error)); if (er2 < 0) { } Assert.True(er2 >= 0); } }
private static void TestInterpolate(S2Point a, S2Point b, double t, S2Point expected) { a = a.Normalize(); b = b.Normalize(); expected = expected.Normalize(); // We allow a bit more than the usual 1e-15 error tolerance because // interpolation uses trig functions. S1Angle kError = S1Angle.FromRadians(3e-15); Assert.True(new S1Angle(S2.Interpolate(a, b, t), expected) <= kError); // Now test the other interpolation functions. S1Angle r = t * new S1Angle(a, b); Assert.True(new S1Angle(S2.GetPointOnLine(a, b, r), expected) <= kError); if (a.DotProd(b) == 0) { // Common in the test cases below. Assert.True(new S1Angle(S2.GetPointOnRay(a, b, r), expected) <= kError); } if (r.Radians >= 0 && r.Radians < 0.99 * S2.M_PI) { S1ChordAngle r_ca = new(r); Assert.True(new S1Angle(S2.GetPointOnLine(a, b, r_ca), expected) <= kError); if (a.DotProd(b) == 0) { Assert.True(new S1Angle(S2.GetPointOnRay(a, b, r_ca), expected) <= kError); } } }
public void Test_S2_GetUpdateMinInteriorDistanceMaxError() { // Check that the error bound returned by // GetUpdateMinInteriorDistanceMaxError() is large enough. for (int iter = 0; iter < 10000; ++iter) { S2Point a0 = S2Testing.RandomPoint(); var lenRadians = Math.PI * Math.Pow(1e-20, S2Testing.Random.RandDouble()); S1Angle len = S1Angle.FromRadians(lenRadians); if (S2Testing.Random.OneIn(4)) { len = S1Angle.FromRadians(S2.M_PI) - len; } S2Point a1 = S2.GetPointOnLine(a0, S2Testing.RandomPoint(), len); // TODO(ericv): The error bound holds for antipodal points, but the S2 // predicates used to test the error do not support antipodal points yet. if (a1 == -a0) { continue; } S2Point n = S2.RobustCrossProd(a0, a1).Normalize(); double f = Math.Pow(1e-20, S2Testing.Random.RandDouble()); S2Point a = ((1 - f) * a0 + f * a1).Normalize(); var rRadians = S2.M_PI_2 * Math.Pow(1e-20, S2Testing.Random.RandDouble()); S1Angle r = S1Angle.FromRadians(rRadians); if (S2Testing.Random.OneIn(2)) { r = S1Angle.FromRadians(S2.M_PI_2) - r; } S2Point x = S2.GetPointOnLine(a, n, r); S1ChordAngle min_dist = S1ChordAngle.Infinity; if (!S2.UpdateMinInteriorDistance(x, a0, a1, ref min_dist)) { --iter; continue; } double error = S2.GetUpdateMinDistanceMaxError(min_dist); Assert.True(S2Pred.CompareEdgeDistance(x, a0, a1, min_dist.PlusError(error)) <= 0); Assert.True(S2Pred.CompareEdgeDistance(x, a0, a1, min_dist.PlusError(-error)) >= 0); } }