github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geogfn/dwithin_test.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package geogfn 12 13 import ( 14 "fmt" 15 "testing" 16 17 "github.com/cockroachdb/cockroach/pkg/geo" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestDWithin(t *testing.T) { 22 // These are cases where the distance is VERY CLOSE to zero. 23 closeToZeroCases := map[string]struct{}{ 24 "LINESTRING to POINT on the line": {}, 25 } 26 27 for _, tc := range distanceTestCases { 28 t.Run(tc.desc, func(t *testing.T) { 29 a, err := geo.ParseGeography(tc.a) 30 require.NoError(t, err) 31 b, err := geo.ParseGeography(tc.b) 32 require.NoError(t, err) 33 34 for _, subTC := range []struct { 35 desc string 36 expected float64 37 useSphereOrSpheroid UseSphereOrSpheroid 38 }{ 39 {"sphere", tc.expectedSphereDistance, UseSphere}, 40 {"spheroid", tc.expectedSpheroidDistance, UseSpheroid}, 41 } { 42 t.Run(subTC.desc, func(t *testing.T) { 43 if subTC.expected == 0 { 44 zeroValue := float64(0) 45 // Allow a 1cm margin of error for close to zero cases. 46 if _, ok := closeToZeroCases[tc.desc]; ok { 47 zeroValue = 0.01 48 } 49 for _, val := range []float64{zeroValue, 1, 10, 10000} { 50 t.Run(fmt.Sprintf("dwithin:%f", val), func(t *testing.T) { 51 dwithin, err := DWithin(a, b, val, subTC.useSphereOrSpheroid) 52 require.NoError(t, err) 53 require.True(t, dwithin) 54 55 dwithin, err = DWithin(b, a, val, subTC.useSphereOrSpheroid) 56 require.NoError(t, err) 57 require.True(t, dwithin) 58 }) 59 } 60 } else { 61 for _, val := range []float64{ 62 subTC.expected + 0.01, // allow 1cm margin of error 63 subTC.expected + 0.02, 64 subTC.expected + 1, 65 subTC.expected * 2, 66 } { 67 t.Run(fmt.Sprintf("dwithin:%f", val), func(t *testing.T) { 68 dwithin, err := DWithin(a, b, val, subTC.useSphereOrSpheroid) 69 require.NoError(t, err) 70 require.True(t, dwithin) 71 72 dwithin, err = DWithin(b, a, val, subTC.useSphereOrSpheroid) 73 require.NoError(t, err) 74 require.True(t, dwithin) 75 }) 76 } 77 78 for _, val := range []float64{ 79 subTC.expected - 0.01, // allow 1cm margin of error 80 subTC.expected - 0.02, 81 subTC.expected - 1, 82 subTC.expected / 2, 83 } { 84 t.Run(fmt.Sprintf("dwithin:%f", val), func(t *testing.T) { 85 dwithin, err := DWithin(a, b, val, subTC.useSphereOrSpheroid) 86 require.NoError(t, err) 87 require.False(t, dwithin) 88 89 dwithin, err = DWithin(b, a, val, subTC.useSphereOrSpheroid) 90 require.NoError(t, err) 91 require.False(t, dwithin) 92 }) 93 } 94 } 95 }) 96 } 97 }) 98 } 99 100 t.Run("errors if SRIDs mismatch", func(t *testing.T) { 101 _, err := DWithin(mismatchingSRIDGeographyA, mismatchingSRIDGeographyB, 0, UseSpheroid) 102 requireMismatchingSRIDError(t, err) 103 }) 104 105 t.Run("errors if distance < 0", func(t *testing.T) { 106 _, err := DWithin(geo.MustParseGeography("POINT(1.0 2.0)"), geo.MustParseGeography("POINT(3.0 4.0)"), -0.01, UseSpheroid) 107 require.Error(t, err) 108 }) 109 110 t.Run("empty geographies are never dwithin each other", func(t *testing.T) { 111 for _, tc := range []struct { 112 a string 113 b string 114 }{ 115 {"GEOMETRYCOLLECTION EMPTY", "GEOMETRYCOLLECTION EMPTY"}, 116 {"GEOMETRYCOLLECTION EMPTY", "GEOMETRYCOLLECTION (POINT(1.0 1.0), LINESTRING EMPTY)"}, 117 {"POINT(1.0 1.0)", "GEOMETRYCOLLECTION (POINT(1.0 1.0), LINESTRING EMPTY)"}, // This case errors (in a bad way) in PostGIS. 118 } { 119 for _, useSphereOrSpheroid := range []UseSphereOrSpheroid{ 120 UseSphere, 121 UseSpheroid, 122 } { 123 t.Run(fmt.Sprintf("DWithin(%s,%s),spheroid=%t", tc.a, tc.b, useSphereOrSpheroid), func(t *testing.T) { 124 a, err := geo.ParseGeography(tc.a) 125 require.NoError(t, err) 126 b, err := geo.ParseGeography(tc.b) 127 require.NoError(t, err) 128 dwithin, err := DWithin(a, b, 0, useSphereOrSpheroid) 129 require.NoError(t, err) 130 require.False(t, dwithin) 131 }) 132 } 133 } 134 }) 135 }