github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geogfn/intersects_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 "testing" 15 16 "github.com/cockroachdb/cockroach/pkg/geo" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestIntersects(t *testing.T) { 21 testCases := []struct { 22 desc string 23 a string 24 b string 25 expected bool 26 }{ 27 { 28 "POINTs which are the same intersect", 29 "POINT(1.0 1.0)", 30 "POINT(1.0 1.0)", 31 true, 32 }, 33 { 34 "POINTs which are different do not intersect", 35 "POINT(1.0 1.0)", 36 "POINT(1.0 1.1)", 37 false, 38 }, 39 { 40 "POINTs intersect with a vertex on a LINESTRING", 41 "POINT(2.0 2.0)", 42 "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", 43 true, 44 }, 45 { 46 "POINTs intersect with a point along the LINESTRING", 47 "POINT(1.5 1.5001714)", 48 "LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0)", 49 true, 50 }, 51 { 52 "POINTs do not intersect with point outside the LINESTRING", 53 "POINT(1.5 1.6001714)", 54 "LINESTRING(0.0 0.0, 1.0 1.0, 2.0 2.0, 3.0 3.0)", 55 false, 56 }, 57 { 58 "POINTs intersect with vertex along a POLYGON", 59 "POLYGON((1.0 1.0, 2.0 2.0, 0.0 2.0, 1.0 1.0))", 60 "POINT(2.0 2.0)", 61 true, 62 }, 63 { 64 "POINTs intersect with edge along a POLYGON", 65 "POLYGON((1.0 1.0, 2.0 2.0, 0.0 2.0, 1.0 1.0))", 66 "POINT(1.5 1.5001714)", 67 true, 68 }, 69 { 70 "POINTs intersect inside a POLYGON", 71 "POLYGON((1.0 1.0, 2.0 2.0, 0.0 2.0, 1.0 1.0))", 72 "POINT(1.5 1.9)", 73 true, 74 }, 75 { 76 "POINTs do not intersect with any hole inside the polygon", 77 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0), (0.2 0.2, 0.2 0.4, 0.4 0.4, 0.4 0.2, 0.2 0.2))", 78 "POINT(0.3 0.3)", 79 false, 80 }, 81 { 82 "LINESTRING intersects itself", 83 "LINESTRING(2.0 2.0, 3.0 3.0)", 84 "LINESTRING(2.0 2.0, 3.0 3.0)", 85 true, 86 }, 87 { 88 "LINESTRING intersects LINESTRING at ends", 89 "LINESTRING(1.0 1.0, 1.5 1.5, 2.0 2.0)", 90 "LINESTRING(2.0 2.0, 3.0 3.0)", 91 true, 92 }, 93 { 94 "LINESTRING intersects LINESTRING subline not at vertex", 95 "LINESTRING(1.0 1.0, 2.0 2.0)", 96 "LINESTRING(1.5499860 1.5501575, 3.0 3.0)", 97 true, 98 }, 99 { 100 "LINESTRING intersects LINESTRING with subline completely inside LINESTRING", 101 "LINESTRING(1.0 1.0, 2.0 2.0)", 102 "LINESTRING(1.5499860 1.5501575, 1.5 1.5001714)", 103 true, 104 }, 105 { 106 "LINESTRING intersects LINESTRING at some edge", 107 "LINESTRING(1.0 1.0, 1.5 1.5, 2.0 2.0)", 108 "LINESTRING(1.0 2.0, 2.0 1.0)", 109 true, 110 }, 111 { 112 "LINESTRING does not intersect LINESTRING", 113 "LINESTRING(1.0 1.0, 1.5 1.5, 2.0 2.0)", 114 "LINESTRING(1.0 2.0, 1.0 4.0)", 115 false, 116 }, 117 { 118 "LINESTRING intersects POLYGON at a vertex", 119 "LINESTRING(1.0 1.0, 1.5 1.5, 2.0 2.0)", 120 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 121 true, 122 }, 123 { 124 "LINESTRING contained within POLYGON", 125 "LINESTRING(0.2 0.2, 0.4 0.4)", 126 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 127 true, 128 }, 129 { 130 "LINESTRING intersects POLYGON at an edge", 131 "LINESTRING(-0.5 0.5, 0.5 0.5)", 132 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 133 true, 134 }, 135 { 136 "LINESTRING intersects POLYGON through the whole thing", 137 "LINESTRING(-0.5 0.5, 1.5 0.5)", 138 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 139 true, 140 }, 141 { 142 "LINESTRING missing the POLYGON does not intersect", 143 "LINESTRING(-0.5 0.5, -1.5 -1.5)", 144 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 145 false, 146 }, 147 { 148 "LINESTRING does not intersect POLYGON if contained within the hole", 149 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0), (0.2 0.2, 0.2 0.4, 0.4 0.4, 0.4 0.2, 0.2 0.2))", 150 "LINESTRING(0.3 0.3, 0.35 0.35)", 151 false, 152 }, 153 { 154 "LINESTRING intersects POLYGON through the hole", 155 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0), (0.2 0.2, 0.2 0.4, 0.4 0.4, 0.4 0.2, 0.2 0.2))", 156 "LINESTRING(0.3 0.3, 0.5 0.5)", 157 true, 158 }, 159 { 160 "LINESTRING intersects POLYGON through touching holes", 161 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0), (0.3 0.3, 0.4 0.2, 0.5 0.3, 0.4 0.4, 0.3 0.3), (0.5 0.3, 0.6 0.2, 0.7 0.3, 0.6 0.4, 0.5 0.3))", 162 "LINESTRING(0.4 0.3, 0.6 0.3)", 163 true, 164 }, 165 { 166 "POLYGON intersects itself", 167 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 168 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 169 true, 170 }, 171 { 172 "POLYGON intersects a window of itself (with edges touches)", 173 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 174 "POLYGON((0.2 0.2, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.2 0.2))", 175 true, 176 }, 177 { 178 "POLYGON intersects a nested version of itself", 179 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 180 "POLYGON((0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.2, 0.1 0.1))", 181 true, 182 }, 183 { 184 "POLYGON intersects POLYGON intersecting", 185 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 186 "POLYGON((-1.0 0.0, 1.0 0.0, 1.0 1.0, -1.0 1.0, -1.0 0.0))", 187 true, 188 }, 189 { 190 "POLYGON does not intersect POLYGON totally out of range", 191 "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0))", 192 "POLYGON((3.0 3.0, 4.0 3.0, 4.0 4.0, 3.0 4.0, 3.0 3.0))", 193 false, 194 }, 195 { 196 "MULTIPOINT intersects single MULTIPOINT", 197 "MULTIPOINT((1.0 1.0), (2.0 2.0))", 198 "MULTIPOINT((2.0 2.0))", 199 true, 200 }, 201 { 202 "MULTILINESTRING intersects one of the MULTIPOINTs", 203 "MULTILINESTRING((1.0 1.0, 1.1 1.1), (2.0 2.0, 2.1 2.1))", 204 "MULTIPOINT((4.0 5.0), (66.0 66.0), (2.1 2.1))", 205 true, 206 }, 207 { 208 "MULTILINESTRING does not intersect with MULTIPOINTS out of the range", 209 "MULTILINESTRING((1.0 1.0, 1.1 1.1), (2.0 2.0, 2.1 2.1))", 210 "MULTIPOINT((55.0 55.0), (66.0 66.0))", 211 false, 212 }, 213 { 214 "MULTILINESTRING intersects MULTILINESTRING", 215 "MULTILINESTRING((1.0 1.0, 2.0 2.0), (2.0 2.0, 2.1 2.1), (3.0 3.0, 3.1 3.1))", 216 "MULTILINESTRING((0.0 0.5001714, -1.0 -1.0), (1.5 1.5001714, 2.0 2.0))", 217 true, 218 }, 219 { 220 "MULTILINESTRING does not intersect all MULTILINESTRING", 221 "MULTILINESTRING((1.0 1.0, 1.1 1.1), (2.0 2.0, 2.1 2.1), (3.0 3.0, 3.1 3.1))", 222 "MULTILINESTRING((25.0 25.0, 25.1 25.1), (4.0 3.0, 3.12 3.12))", 223 false, 224 }, 225 { 226 "MULTIPOLYGON intersects MULTIPOINT", 227 "MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))", 228 "MULTIPOINT((30 20), (30 30))", 229 true, 230 }, 231 { 232 "MULTIPOLYGON does not intersect MULTIPOINT", 233 "MULTIPOLYGON (((15 5, 40 10, 10 20, 5 10, 15 5)),((30 20, 45 40, 10 40, 30 20)))", 234 "MULTIPOINT((30 -20), (-30 30), (45 66))", 235 false, 236 }, 237 { 238 "MULTIPOLYGON intersects MULTILINESTRING", 239 "MULTIPOLYGON (((15 5, 40 10, 10 20, 5 10, 15 5)),((30 20, 45 40, 10 40, 30 20)))", 240 "MULTILINESTRING((65 40, 60 40), (45 40, 10 40, 30 20))", 241 true, 242 }, 243 { 244 "MULTIPOLYGON does not intersect MULTILINESTRING", 245 "MULTIPOLYGON (((15 5, 40 10, 10 20, 5 10, 15 5)),((30 20, 45 40, 10 40, 30 20)))", 246 "MULTILINESTRING((45 41, 60 80), (-45 -40, -10 -40))", 247 false, 248 }, 249 { 250 "MULTIPOLYGON intersects MULTIPOLYGON", 251 "MULTIPOLYGON (((15 5, 40 10, 10 20, 5 10, 15 5)),((30 20, 45 40, 10 40, 30 20)))", 252 "MULTIPOLYGON (((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0)), ((30 20, 45 40, 10 40, 30 20)))", 253 true, 254 }, 255 { 256 "MULTIPOLYGON does not intersect MULTIPOLYGON", 257 "MULTIPOLYGON (((15 5, 40 10, 10 20, 5 10, 15 5)),((30 20, 45 40, 10 40, 30 20)))", 258 "MULTIPOLYGON (((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 1.0, 0.0 0.0)))", 259 false, 260 }, 261 { 262 "GEOMETRYCOLLECTION EMPTY do not intersect with each other", 263 "GEOMETRYCOLLECTION EMPTY", 264 "GEOMETRYCOLLECTION EMPTY", 265 false, 266 }, 267 { 268 "GEOMETRYCOLLECTION EMPTY do not intersect with a point", 269 "POINT(1.0 2.0)", 270 "GEOMETRYCOLLECTION EMPTY", 271 false, 272 }, 273 { 274 "GEOMETRYCOLLECTION EMPTY and POINT intersect", 275 "POINT(1.0 2.0)", 276 "GEOMETRYCOLLECTION (LINESTRING EMPTY, POINT(1.0 2.0))", 277 true, 278 }, 279 } 280 281 for _, tc := range testCases { 282 t.Run(tc.desc, func(t *testing.T) { 283 a, err := geo.ParseGeography(tc.a) 284 require.NoError(t, err) 285 b, err := geo.ParseGeography(tc.b) 286 require.NoError(t, err) 287 288 intersects, err := Intersects(a, b) 289 require.NoError(t, err) 290 require.Equal(t, tc.expected, intersects) 291 292 // Relationships should be reciprocal. 293 intersects, err = Intersects(b, a) 294 require.NoError(t, err) 295 require.Equal(t, tc.expected, intersects) 296 }) 297 } 298 299 t.Run("errors if SRIDs mismatch", func(t *testing.T) { 300 _, err := Intersects(mismatchingSRIDGeographyA, mismatchingSRIDGeographyB) 301 requireMismatchingSRIDError(t, err) 302 }) 303 }