public void testIntersectionTolerance() { // We repeatedly construct two edges that cross near a random point "p", // and measure the distance from the actual intersection point "x" to the // the expected intersection point "p" and also to the edges that cross // near "p". // // Note that getIntersection() does not guarantee that "x" and "p" will be // close together (since the intersection point is numerically unstable // when the edges cross at a very small angle), but it does guarantee that // "x" will be close to both of the edges that cross. var maxPointDist = new S1Angle(); var maxEdgeDist = new S1Angle(); for (var i = 0; i < 1000; ++i) { // We construct two edges AB and CD that intersect near "p". The angle // between AB and CD (expressed as a slope) is chosen randomly between // 1e-15 and 1.0 such that its logarithm is uniformly distributed. This // implies that small values are much more likely to be chosen. // // Once the slope is chosen, the four points ABCD must be offset from P // by at least (1e-15 / slope) so that the points are guaranteed to have // the correct circular ordering around P. This is the distance from P // at which the two edges are separated by about 1e-15, which is // approximately the minimum distance at which we can expect computed // points on the two lines to be distinct and have the correct ordering. // // The actual offset distance from P is chosen randomly in the range // [1e-15 / slope, 1.0], again uniformly distributing the logarithm. // This ensures that we test both long and very short segments that // intersect at both large and very small angles. var points = getRandomFrame(); var p = points[0]; var d1 = points[1]; var d2 = points[2]; var slope = Math.Pow(1e-15, rand.NextDouble()); d2 = d1 + (d2 * slope); var a = S2Point.Normalize(p + (d1 * Math.Pow(1e-15 / slope, rand.NextDouble()))); var b = S2Point.Normalize(p - (d1 * Math.Pow(1e-15 / slope, rand.NextDouble()))); var c = S2Point.Normalize(p + (d2 * Math.Pow(1e-15 / slope, rand.NextDouble()))); var d = S2Point.Normalize(p - (d2 * Math.Pow(1e-15 / slope, rand.NextDouble()))); var x = S2EdgeUtil.GetIntersection(a, b, c, d); var distAb = S2EdgeUtil.GetDistance(x, a, b); var distCd = S2EdgeUtil.GetDistance(x, c, d); assertTrue(distAb < S2EdgeUtil.DefaultIntersectionTolerance); assertTrue(distCd < S2EdgeUtil.DefaultIntersectionTolerance); // test getIntersection() post conditions assertTrue(S2.OrderedCcw(a, x, b, S2Point.Normalize(S2.RobustCrossProd(a, b)))); assertTrue(S2.OrderedCcw(c, x, d, S2Point.Normalize(S2.RobustCrossProd(c, d)))); maxEdgeDist = S1Angle.Max(maxEdgeDist, S1Angle.Max(distAb, distCd)); maxPointDist = S1Angle.Max(maxPointDist, new S1Angle(p, x)); } }
private void dumpCrossings(S2Loop loop) { Console.WriteLine("Ortho(v1): " + S2.Ortho(loop.Vertex(1))); Console.WriteLine("Contains(kOrigin): {0}\n", loop.Contains(S2.Origin)); for (var i = 1; i <= loop.NumVertices; ++i) { var a = S2.Ortho(loop.Vertex(i)); var b = loop.Vertex(i - 1); var c = loop.Vertex(i + 1); var o = loop.Vertex(i); Console.WriteLine("Vertex {0}: [%.17g, %.17g, %.17g], " + "%d%dR=%d, %d%d%d=%d, R%d%d=%d, inside: %b\n", i, loop.Vertex(i).X, loop.Vertex(i).Y, loop.Vertex(i).Z, i - 1, i, S2.RobustCcw(b, o, a), i + 1, i, i - 1, S2.RobustCcw(c, o, b), i, i + 1, S2.RobustCcw(a, o, c), S2.OrderedCcw(a, b, c, o)); } for (var i = 0; i < loop.NumVertices + 2; ++i) { var orig = S2.Origin; S2Point dest; if (i < loop.NumVertices) { dest = loop.Vertex(i); Console.WriteLine("Origin->{0} crosses:", i); } else { dest = new S2Point(0, 0, 1); if (i == loop.NumVertices + 1) { orig = loop.Vertex(1); } Console.WriteLine("Case {0}:", i); } for (var j = 0; j < loop.NumVertices; ++j) { Console.WriteLine( " " + S2EdgeUtil.EdgeOrVertexCrossing(orig, dest, loop.Vertex(j), loop.Vertex(j + 1))); } Console.WriteLine(); } for (var i = 0; i <= 2; i += 2) { Console.WriteLine("Origin->v1 crossing v{0}->v1: ", i); var a = S2.Ortho(loop.Vertex(1)); var b = loop.Vertex(i); var c = S2.Origin; var o = loop.Vertex(1); Console.WriteLine("{0}1R={1}, M1{2}={3}, R1M={4}, crosses: {5}\n", i, S2.RobustCcw(b, o, a), i, S2.RobustCcw(c, o, b), S2.RobustCcw(a, o, c), S2EdgeUtil.EdgeOrVertexCrossing(c, o, b, a)); } }