github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/spatial/st_within_test.go (about) 1 // Copyright 2023 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package spatial 16 17 import ( 18 "testing" 19 20 "github.com/stretchr/testify/require" 21 22 "github.com/dolthub/go-mysql-server/sql" 23 "github.com/dolthub/go-mysql-server/sql/expression" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 func TestPointWithinPoint(t *testing.T) { 28 t.Run("point within point", func(t *testing.T) { 29 require := require.New(t) 30 p := types.Point{X: 1, Y: 2} 31 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(p, types.PointType{})) 32 v, err := f.Eval(sql.NewEmptyContext(), nil) 33 require.NoError(err) 34 require.Equal(true, v) 35 }) 36 37 t.Run("point not within point", func(t *testing.T) { 38 require := require.New(t) 39 p1 := types.Point{X: 1, Y: 2} 40 p2 := types.Point{X: 123, Y: 456} 41 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(p2, types.PointType{})) 42 v, err := f.Eval(sql.NewEmptyContext(), nil) 43 require.NoError(err) 44 require.Equal(false, v) 45 }) 46 } 47 48 func TestPointWithinLineString(t *testing.T) { 49 t.Run("point within linestring", func(t *testing.T) { 50 require := require.New(t) 51 p := types.Point{X: 1, Y: 1} 52 l := types.LineString{Points: []types.Point{{X: 0, Y: 0}, {X: 2, Y: 2}}} 53 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(l, types.LineStringType{})) 54 v, err := f.Eval(sql.NewEmptyContext(), nil) 55 require.NoError(err) 56 require.Equal(true, v) 57 }) 58 59 t.Run("point within closed linestring of length 0", func(t *testing.T) { 60 require := require.New(t) 61 p := types.Point{X: 123, Y: 456} 62 l := types.LineString{Points: []types.Point{p, p}} 63 64 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(l, types.PointType{})) 65 v, err := f.Eval(sql.NewEmptyContext(), nil) 66 require.NoError(err) 67 require.Equal(true, v) 68 69 l = types.LineString{Points: []types.Point{p, p, p, p, p}} 70 f = NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(l, types.PointType{})) 71 v, err = f.Eval(sql.NewEmptyContext(), nil) 72 require.NoError(err) 73 require.Equal(true, v) 74 }) 75 76 t.Run("point not within linestring", func(t *testing.T) { 77 require := require.New(t) 78 p := types.Point{X: 100, Y: 200} 79 l := types.LineString{Points: []types.Point{{X: 0, Y: 0}, {X: 2, Y: 2}}} 80 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(l, types.PointType{})) 81 v, err := f.Eval(sql.NewEmptyContext(), nil) 82 require.NoError(err) 83 require.Equal(false, v) 84 }) 85 86 t.Run("terminal points are not within linestring", func(t *testing.T) { 87 require := require.New(t) 88 f := NewWithin(expression.NewLiteral(simpleLineString.Points[0], types.PointType{}), expression.NewLiteral(simpleLineString, types.PointType{})) 89 v, err := f.Eval(sql.NewEmptyContext(), nil) 90 require.NoError(err) 91 require.Equal(false, v) 92 93 f = NewWithin(expression.NewLiteral(simpleLineString.Points[2], types.PointType{}), expression.NewLiteral(simpleLineString, types.PointType{})) 94 v, err = f.Eval(sql.NewEmptyContext(), nil) 95 require.NoError(err) 96 require.Equal(false, v) 97 }) 98 99 t.Run("overlapping terminal points are not within linestring", func(t *testing.T) { 100 require := require.New(t) 101 102 // it looks like two triangles: 103 // /\ | /\ 104 // /__s_|_e__\ 105 s := types.Point{X: -1, Y: 0} 106 p1 := types.Point{X: -2, Y: 1} 107 p2 := types.Point{X: -3, Y: 0} 108 p3 := types.Point{X: 3, Y: 0} 109 p4 := types.Point{X: 2, Y: 1} 110 e := types.Point{X: 1, Y: 0} 111 112 l := types.LineString{Points: []types.Point{s, p1, p2, p3, p4, e}} 113 114 f := NewWithin(expression.NewLiteral(s, types.PointType{}), expression.NewLiteral(l, types.PointType{})) 115 v, err := f.Eval(sql.NewEmptyContext(), nil) 116 require.NoError(err) 117 require.Equal(false, v) 118 119 f = NewWithin(expression.NewLiteral(e, types.PointType{}), expression.NewLiteral(l, types.PointType{})) 120 v, err = f.Eval(sql.NewEmptyContext(), nil) 121 require.NoError(err) 122 require.Equal(false, v) 123 }) 124 } 125 126 func TestPointWithinPolygon(t *testing.T) { 127 t.Run("point within polygon", func(t *testing.T) { 128 require := require.New(t) 129 f := NewWithin(expression.NewLiteral(types.Point{}, types.PointType{}), expression.NewLiteral(square, types.PolygonType{})) 130 v, err := f.Eval(sql.NewEmptyContext(), nil) 131 require.NoError(err) 132 require.Equal(true, v) 133 }) 134 135 t.Run("point within polygon intersects vertex", func(t *testing.T) { 136 require := require.New(t) 137 p := types.Point{X: 0, Y: 0} 138 a := types.Point{X: -1, Y: 0} 139 b := types.Point{X: 0, Y: 1} 140 c := types.Point{X: 1, Y: 0} 141 d := types.Point{X: 0, Y: -1} 142 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 143 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(poly, types.PolygonType{})) 144 v, err := f.Eval(sql.NewEmptyContext(), nil) 145 require.NoError(err) 146 require.Equal(true, v) 147 }) 148 149 t.Run("point within polygon (square) with hole", func(t *testing.T) { 150 require := require.New(t) 151 // passes through segments c2d2, a1b1, and a2b2; overlaps segment d2a2 152 p1 := types.Point{X: -3, Y: 2} 153 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 154 v, err := f.Eval(sql.NewEmptyContext(), nil) 155 require.NoError(err) 156 require.Equal(true, v) 157 158 // passes through segments c2d2, a1b1, and a2b2 159 p2 := types.Point{X: -3, Y: 0} 160 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 161 v, err = f.Eval(sql.NewEmptyContext(), nil) 162 require.NoError(err) 163 require.Equal(true, v) 164 165 // passes through segments c2d2, a1b1, and a2b2; overlaps segment b2c2 166 p3 := types.Point{X: -3, Y: -2} 167 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 168 v, err = f.Eval(sql.NewEmptyContext(), nil) 169 require.NoError(err) 170 require.Equal(true, v) 171 }) 172 173 t.Run("point within polygon (diamond) with hole", func(t *testing.T) { 174 require := require.New(t) 175 176 p1 := types.Point{X: -3, Y: 0} 177 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 178 v, err := f.Eval(sql.NewEmptyContext(), nil) 179 require.NoError(err) 180 require.Equal(true, v) 181 182 // passes through vertex a2 and segment a1b1 183 p2 := types.Point{X: -1, Y: 2} 184 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 185 v, err = f.Eval(sql.NewEmptyContext(), nil) 186 require.NoError(err) 187 require.Equal(true, v) 188 189 p3 := types.Point{X: -1, Y: -2} 190 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 191 v, err = f.Eval(sql.NewEmptyContext(), nil) 192 require.NoError(err) 193 require.Equal(true, v) 194 }) 195 196 t.Run("point on polygon boundary not within", func(t *testing.T) { 197 require := require.New(t) 198 199 f := NewWithin(expression.NewLiteral(diamond.Lines[0].Points[0], types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 200 v, err := f.Eval(sql.NewEmptyContext(), nil) 201 require.NoError(err) 202 require.Equal(false, v) 203 204 f = NewWithin(expression.NewLiteral(diamond.Lines[0].Points[1], types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 205 v, err = f.Eval(sql.NewEmptyContext(), nil) 206 require.NoError(err) 207 require.Equal(false, v) 208 209 f = NewWithin(expression.NewLiteral(diamond.Lines[0].Points[2], types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 210 v, err = f.Eval(sql.NewEmptyContext(), nil) 211 require.NoError(err) 212 require.Equal(false, v) 213 214 f = NewWithin(expression.NewLiteral(diamond.Lines[0].Points[3], types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 215 v, err = f.Eval(sql.NewEmptyContext(), nil) 216 require.NoError(err) 217 require.Equal(false, v) 218 }) 219 220 t.Run("point not within polygon intersects vertex", func(t *testing.T) { 221 require := require.New(t) 222 223 // passes through vertex b 224 p1 := types.Point{X: -1, Y: 4} 225 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 226 v, err := f.Eval(sql.NewEmptyContext(), nil) 227 require.NoError(err) 228 require.Equal(false, v) 229 230 // passes through vertex a and c 231 p2 := types.Point{X: -5, Y: 0} 232 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 233 v, err = f.Eval(sql.NewEmptyContext(), nil) 234 require.NoError(err) 235 require.Equal(false, v) 236 237 // passes through vertex d 238 p3 := types.Point{X: -1, Y: -4} 239 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(diamond, types.PolygonType{})) 240 v, err = f.Eval(sql.NewEmptyContext(), nil) 241 require.NoError(err) 242 require.Equal(false, v) 243 }) 244 245 t.Run("point not within polygon (square) with hole", func(t *testing.T) { 246 require := require.New(t) 247 248 // passes through segments a1b1 and a2b2 249 p1 := types.Point{X: 0, Y: 0} 250 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 251 v, err := f.Eval(sql.NewEmptyContext(), nil) 252 require.NoError(err) 253 require.Equal(false, v) 254 255 // passes through segments c1d1, c2d2, a1b1, and a2b2; overlaps segment d2a2 256 p2 := types.Point{X: -5, Y: 2} 257 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 258 v, err = f.Eval(sql.NewEmptyContext(), nil) 259 require.NoError(err) 260 require.Equal(false, v) 261 262 // passes through segments c1d1, c2d2, a1b1, and a2b2; overlaps segment b2c2 263 p3 := types.Point{X: -5, Y: -2} 264 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(squareWithHole, types.PolygonType{})) 265 v, err = f.Eval(sql.NewEmptyContext(), nil) 266 require.NoError(err) 267 require.Equal(false, v) 268 }) 269 270 t.Run("point not within polygon (diamond) with hole", func(t *testing.T) { 271 require := require.New(t) 272 273 // passes through vertexes d2, b2, and b1 274 p1 := types.Point{X: -3, Y: 0} 275 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 276 v, err := f.Eval(sql.NewEmptyContext(), nil) 277 require.NoError(err) 278 require.Equal(true, v) 279 280 // passes through vertex a2 and segment a1b1 281 p2 := types.Point{X: -1, Y: 2} 282 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 283 v, err = f.Eval(sql.NewEmptyContext(), nil) 284 require.NoError(err) 285 require.Equal(true, v) 286 287 // passes through vertex c2 and segment b1c1 288 p3 := types.Point{X: -1, Y: -2} 289 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(diamondWithHole, types.PolygonType{})) 290 v, err = f.Eval(sql.NewEmptyContext(), nil) 291 require.NoError(err) 292 require.Equal(true, v) 293 }) 294 295 t.Run("point not within polygon (square) with hole in hole", func(t *testing.T) { 296 require := require.New(t) 297 298 a3 := types.Point{X: 1, Y: 1} 299 b3 := types.Point{X: 1, Y: -1} 300 c3 := types.Point{X: -1, Y: -1} 301 d3 := types.Point{X: -1, Y: 1} 302 303 l3 := types.LineString{Points: []types.Point{a3, b3, c3, d3, a3}} 304 poly := types.Polygon{Lines: []types.LineString{squareWithHole.Lines[0], squareWithHole.Lines[1], l3}} 305 306 // passes through segments a1b1 and a2b2 307 p1 := types.Point{X: 0, Y: 0} 308 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(poly, types.PolygonType{})) 309 v, err := f.Eval(sql.NewEmptyContext(), nil) 310 require.NoError(err) 311 require.Equal(false, v) 312 313 // passes through segments c1d1, c2d2, a1b1, and a2b2; overlaps segment d2a2 314 p2 := types.Point{X: -5, Y: 2} 315 f = NewWithin(expression.NewLiteral(p2, types.PointType{}), expression.NewLiteral(poly, types.PolygonType{})) 316 v, err = f.Eval(sql.NewEmptyContext(), nil) 317 require.NoError(err) 318 require.Equal(false, v) 319 320 // passes through segments c1d1, c2d2, a1b1, and a2b2; overlaps segment b2c2 321 p3 := types.Point{X: -5, Y: -2} 322 f = NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(poly, types.PolygonType{})) 323 v, err = f.Eval(sql.NewEmptyContext(), nil) 324 require.NoError(err) 325 require.Equal(false, v) 326 }) 327 328 t.Run("point within non-simple polygon", func(t *testing.T) { 329 require := require.New(t) 330 // looks like a bowtie 331 a := types.Point{X: -2, Y: 2} 332 b := types.Point{X: 2, Y: 2} 333 c := types.Point{X: 2, Y: -2} 334 d := types.Point{X: -2, Y: -2} 335 l := types.LineString{Points: []types.Point{a, c, b, d, a}} 336 p := types.Polygon{Lines: []types.LineString{l}} 337 338 o := types.Point{} 339 w := types.Point{X: -1, Y: 0} 340 x := types.Point{X: 0, Y: 1} 341 y := types.Point{X: 1, Y: 0} 342 z := types.Point{X: 0, Y: -1} 343 344 f := NewWithin(expression.NewLiteral(o, types.PointType{}), expression.NewLiteral(p, types.PolygonType{})) 345 v, err := f.Eval(sql.NewEmptyContext(), nil) 346 require.NoError(err) 347 require.Equal(false, v) 348 349 f = NewWithin(expression.NewLiteral(w, types.PointType{}), expression.NewLiteral(p, types.PolygonType{})) 350 v, err = f.Eval(sql.NewEmptyContext(), nil) 351 require.NoError(err) 352 require.Equal(true, v) 353 354 f = NewWithin(expression.NewLiteral(x, types.PointType{}), expression.NewLiteral(p, types.PolygonType{})) 355 v, err = f.Eval(sql.NewEmptyContext(), nil) 356 require.NoError(err) 357 require.Equal(false, v) 358 359 f = NewWithin(expression.NewLiteral(y, types.PointType{}), expression.NewLiteral(p, types.PolygonType{})) 360 v, err = f.Eval(sql.NewEmptyContext(), nil) 361 require.NoError(err) 362 require.Equal(true, v) 363 364 f = NewWithin(expression.NewLiteral(z, types.PointType{}), expression.NewLiteral(p, types.PolygonType{})) 365 v, err = f.Eval(sql.NewEmptyContext(), nil) 366 require.NoError(err) 367 require.Equal(false, v) 368 }) 369 } 370 371 func TestPointWithinMultiPoint(t *testing.T) { 372 t.Run("points within multipoint", func(t *testing.T) { 373 require := require.New(t) 374 375 f := NewWithin(expression.NewLiteral(simpleMultiPoint.Points[0], types.PointType{}), expression.NewLiteral(simpleMultiPoint, types.MultiPointType{})) 376 v, err := f.Eval(sql.NewEmptyContext(), nil) 377 require.NoError(err) 378 require.Equal(true, v) 379 380 f = NewWithin(expression.NewLiteral(simpleMultiPoint.Points[0], types.PointType{}), expression.NewLiteral(simpleMultiPoint, types.MultiPointType{})) 381 v, err = f.Eval(sql.NewEmptyContext(), nil) 382 require.NoError(err) 383 require.Equal(true, v) 384 385 f = NewWithin(expression.NewLiteral(simpleMultiPoint.Points[0], types.PointType{}), expression.NewLiteral(simpleMultiPoint, types.MultiPointType{})) 386 v, err = f.Eval(sql.NewEmptyContext(), nil) 387 require.NoError(err) 388 require.Equal(true, v) 389 }) 390 391 t.Run("point not within multipoint", func(t *testing.T) { 392 require := require.New(t) 393 394 f := NewWithin(expression.NewLiteral(types.Point{}, types.PointType{}), expression.NewLiteral(simpleMultiPoint, types.MultiPointType{})) 395 v, err := f.Eval(sql.NewEmptyContext(), nil) 396 require.NoError(err) 397 require.Equal(false, v) 398 }) 399 } 400 401 func TestPointWithinMultiLineString(t *testing.T) { 402 t.Run("points within multilinestring", func(t *testing.T) { 403 require := require.New(t) 404 p1 := types.Point{X: -1, Y: -1} 405 p2 := types.Point{X: 1, Y: 1} 406 p3 := types.Point{X: 123, Y: 456} 407 l1 := types.LineString{Points: []types.Point{p1, p2}} 408 l2 := types.LineString{Points: []types.Point{p3, p3}} 409 ml := types.MultiLineString{Lines: []types.LineString{l1, l2}} 410 411 f := NewWithin(expression.NewLiteral(p3, types.PointType{}), expression.NewLiteral(ml, types.MultiPointType{})) 412 v, err := f.Eval(sql.NewEmptyContext(), nil) 413 require.NoError(err) 414 require.Equal(true, v) 415 416 p := types.Point{X: 0, Y: 0} 417 f = NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(ml, types.MultiPointType{})) 418 v, err = f.Eval(sql.NewEmptyContext(), nil) 419 require.NoError(err) 420 require.Equal(true, v) 421 }) 422 423 t.Run("points not within multilinestring", func(t *testing.T) { 424 require := require.New(t) 425 p1 := types.Point{X: -1, Y: -1} 426 p2 := types.Point{X: 1, Y: 1} 427 p3 := types.Point{X: 123, Y: 456} 428 l1 := types.LineString{Points: []types.Point{p1, p2}} 429 l2 := types.LineString{Points: []types.Point{p3, p3}} 430 ml := types.MultiLineString{Lines: []types.LineString{l1, l2}} 431 432 f := NewWithin(expression.NewLiteral(p1, types.PointType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 433 v, err := f.Eval(sql.NewEmptyContext(), nil) 434 require.NoError(err) 435 require.Equal(false, v) 436 437 p := types.Point{X: 100, Y: 1000} 438 f = NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 439 v, err = f.Eval(sql.NewEmptyContext(), nil) 440 require.NoError(err) 441 require.Equal(false, v) 442 }) 443 } 444 445 func TestPointWithinMultiPolygon(t *testing.T) { 446 t.Run("point within multipolygon", func(t *testing.T) { 447 require := require.New(t) 448 f := NewWithin(expression.NewLiteral(types.Point{}, types.PointType{}), expression.NewLiteral(simpleMultiPolygon, types.MultiLineStringType{})) 449 v, err := f.Eval(sql.NewEmptyContext(), nil) 450 require.NoError(err) 451 require.Equal(true, v) 452 }) 453 454 t.Run("points not within multipolygon", func(t *testing.T) { 455 // TODO: fix this one 456 require := require.New(t) 457 p := types.Point{X: 100, Y: 100} 458 459 a1 := types.Point{X: 4, Y: 4} 460 b1 := types.Point{X: 4, Y: -4} 461 c1 := types.Point{X: -4, Y: -4} 462 d1 := types.Point{X: -4, Y: 4} 463 464 a2 := types.Point{X: 2, Y: 2} 465 b2 := types.Point{X: 2, Y: -2} 466 c2 := types.Point{X: -2, Y: -2} 467 d2 := types.Point{X: -2, Y: 2} 468 469 l1 := types.LineString{Points: []types.Point{a1, b1, c1, d1, a1}} 470 l2 := types.LineString{Points: []types.Point{a2, b2, c2, d2, a2}} 471 mp := types.MultiPolygon{Polygons: []types.Polygon{{Lines: []types.LineString{l1}}, {Lines: []types.LineString{l2}}}} 472 473 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(mp, types.MultiLineStringType{})) 474 v, err := f.Eval(sql.NewEmptyContext(), nil) 475 require.NoError(err) 476 require.Equal(false, v) 477 }) 478 } 479 480 func TestPointWithinGeometryCollection(t *testing.T) { 481 t.Run("point within empty geometrycollection returns null", func(t *testing.T) { 482 require := require.New(t) 483 p := types.Point{X: 0, Y: 0} 484 gc := types.GeomColl{} 485 486 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(gc, types.GeomCollType{})) 487 v, err := f.Eval(sql.NewEmptyContext(), nil) 488 require.NoError(err) 489 require.Equal(nil, v) 490 }) 491 492 t.Run("point within geometrycollection", func(t *testing.T) { 493 require := require.New(t) 494 p := types.Point{X: 0, Y: 0} 495 gc := types.GeomColl{Geoms: []types.GeometryValue{p}} 496 497 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(gc, types.GeomCollType{})) 498 v, err := f.Eval(sql.NewEmptyContext(), nil) 499 require.NoError(err) 500 require.Equal(true, v) 501 }) 502 503 t.Run("point not within geometrycollection", func(t *testing.T) { 504 require := require.New(t) 505 p := types.Point{X: 0, Y: 0} 506 a := types.Point{X: 1, Y: 0} 507 gc := types.GeomColl{Geoms: []types.GeometryValue{a}} 508 509 f := NewWithin(expression.NewLiteral(p, types.PointType{}), expression.NewLiteral(gc, types.GeomCollType{})) 510 v, err := f.Eval(sql.NewEmptyContext(), nil) 511 require.NoError(err) 512 require.Equal(false, v) 513 }) 514 } 515 516 func TestWithin(t *testing.T) { 517 t.Skip("these are all the cases that haven't been implemented yet") 518 519 // LineString vs Point 520 t.Run("linestring never within point", func(t *testing.T) { 521 require := require.New(t) 522 f := NewWithin(expression.NewLiteral(emptyLineString, types.LineStringType{}), expression.NewLiteral(types.Point{}, types.PointType{})) 523 v, err := f.Eval(sql.NewEmptyContext(), nil) 524 require.NoError(err) 525 require.Equal(false, v) 526 }) 527 528 // LineString vs LineString 529 t.Run("linestring within linestring", func(t *testing.T) { 530 require := require.New(t) 531 a := types.Point{X: 0, Y: 0} 532 b := types.Point{X: 1, Y: 1} 533 c := types.Point{X: -5, Y: -5} 534 d := types.Point{X: 5, Y: 5} 535 l1 := types.LineString{Points: []types.Point{a, b}} 536 l2 := types.LineString{Points: []types.Point{c, d}} 537 f := NewWithin(expression.NewLiteral(l1, types.LineStringType{}), expression.NewLiteral(l2, types.LineStringType{})) 538 v, err := f.Eval(sql.NewEmptyContext(), nil) 539 require.NoError(err) 540 require.Equal(true, v) 541 }) 542 543 t.Run("linestring within itself", func(t *testing.T) { 544 require := require.New(t) 545 f := NewWithin(expression.NewLiteral(simpleLineString, types.LineStringType{}), expression.NewLiteral(simpleLineString, types.LineStringType{})) 546 v, err := f.Eval(sql.NewEmptyContext(), nil) 547 require.NoError(err) 548 require.Equal(true, v) 549 }) 550 551 t.Run("many line segments within larger line segment", func(t *testing.T) { 552 require := require.New(t) 553 p := types.Point{X: 0, Y: 0} 554 q := types.Point{X: 4, Y: 4} 555 l := types.LineString{Points: []types.Point{p, q}} 556 557 f := NewWithin(expression.NewLiteral(simpleLineString, types.LineStringType{}), expression.NewLiteral(l, types.LineStringType{})) 558 v, err := f.Eval(sql.NewEmptyContext(), nil) 559 require.NoError(err) 560 require.Equal(true, v) 561 }) 562 563 t.Run("larger line segment within many small line segments", func(t *testing.T) { 564 require := require.New(t) 565 566 a := types.Point{X: 0, Y: 0} 567 b := types.Point{X: 1, Y: 1} 568 c := types.Point{X: 2, Y: 2} 569 d := types.Point{X: 3, Y: 3} 570 e := types.Point{X: 4, Y: 4} 571 l1 := types.LineString{Points: []types.Point{b, d}} 572 l2 := types.LineString{Points: []types.Point{a, b, c, d, e}} 573 574 f := NewWithin(expression.NewLiteral(l1, types.LineStringType{}), expression.NewLiteral(l2, types.LineStringType{})) 575 v, err := f.Eval(sql.NewEmptyContext(), nil) 576 require.NoError(err) 577 require.Equal(true, v) 578 }) 579 580 t.Run("alternating line segments", func(t *testing.T) { 581 require := require.New(t) 582 583 a := types.Point{X: 0, Y: 0} 584 b := types.Point{X: 1, Y: 1} 585 c := types.Point{X: 2, Y: 2} 586 d := types.Point{X: 3, Y: 3} 587 e := types.Point{X: 4, Y: 4} 588 l1 := types.LineString{Points: []types.Point{b, d}} 589 l2 := types.LineString{Points: []types.Point{a, c, e}} 590 591 f := NewWithin(expression.NewLiteral(l1, types.LineStringType{}), expression.NewLiteral(l2, types.LineStringType{})) 592 v, err := f.Eval(sql.NewEmptyContext(), nil) 593 require.NoError(err) 594 require.Equal(true, v) 595 }) 596 597 t.Run("linestring not within perpendicular linestring", func(t *testing.T) { 598 require := require.New(t) 599 a := types.Point{X: 0, Y: 0} 600 b := types.Point{X: 1, Y: 1} 601 c := types.Point{X: 1, Y: 0} 602 d := types.Point{X: 0, Y: 1} 603 l1 := types.LineString{Points: []types.Point{a, b}} 604 l2 := types.LineString{Points: []types.Point{c, d}} 605 f := NewWithin(expression.NewLiteral(l1, types.LineStringType{}), expression.NewLiteral(l2, types.LineStringType{})) 606 v, err := f.Eval(sql.NewEmptyContext(), nil) 607 require.NoError(err) 608 require.Equal(false, v) 609 f = NewWithin(expression.NewLiteral(l2, types.LineStringType{}), expression.NewLiteral(l1, types.LineStringType{})) 610 v, err = f.Eval(sql.NewEmptyContext(), nil) 611 require.NoError(err) 612 require.Equal(false, v) 613 }) 614 615 t.Run("axis-aligned perpendicular linestring not within", func(t *testing.T) { 616 require := require.New(t) 617 a := types.Point{X: 0, Y: 0} 618 b := types.Point{X: 0, Y: 1} 619 c := types.Point{X: 1, Y: 0} 620 l1 := types.LineString{Points: []types.Point{a, b}} 621 l2 := types.LineString{Points: []types.Point{a, c}} 622 f := NewWithin(expression.NewLiteral(l1, types.LineStringType{}), expression.NewLiteral(l2, types.LineStringType{})) 623 v, err := f.Eval(sql.NewEmptyContext(), nil) 624 require.NoError(err) 625 require.Equal(false, v) 626 f = NewWithin(expression.NewLiteral(l2, types.LineStringType{}), expression.NewLiteral(l1, types.LineStringType{})) 627 v, err = f.Eval(sql.NewEmptyContext(), nil) 628 require.NoError(err) 629 require.Equal(false, v) 630 }) 631 632 t.Run("terminal line points not in line", func(t *testing.T) { 633 require := require.New(t) 634 a := types.Point{X: 0, Y: 0} 635 b := types.Point{X: 1, Y: 1} 636 l := types.LineString{Points: []types.Point{a, b}} 637 la := types.LineString{Points: []types.Point{a, a}} 638 lb := types.LineString{Points: []types.Point{b, b}} 639 f := NewWithin(expression.NewLiteral(la, types.LineStringType{}), expression.NewLiteral(l, types.LineStringType{})) 640 v, err := f.Eval(sql.NewEmptyContext(), nil) 641 require.NoError(err) 642 require.Equal(false, v) 643 f = NewWithin(expression.NewLiteral(lb, types.LineStringType{}), expression.NewLiteral(l, types.LineStringType{})) 644 v, err = f.Eval(sql.NewEmptyContext(), nil) 645 require.NoError(err) 646 require.Equal(false, v) 647 }) 648 649 // LineString vs Polygon 650 t.Run("linestring within polygon", func(t *testing.T) { 651 require := require.New(t) 652 i := types.Point{X: -1, Y: -1} 653 j := types.Point{X: 1, Y: 1} 654 l := types.LineString{Points: []types.Point{i, j}} 655 656 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(square, types.LineStringType{})) 657 v, err := f.Eval(sql.NewEmptyContext(), nil) 658 require.NoError(err) 659 require.Equal(true, v) 660 }) 661 662 t.Run("linestring touching boundary is within polygon", func(t *testing.T) { 663 require := require.New(t) 664 a := types.Point{X: -1, Y: -1} 665 b := types.Point{X: 1, Y: 1} 666 c := types.Point{X: 4, Y: 4} 667 d := types.Point{X: -4, Y: 4} 668 l := types.LineString{Points: []types.Point{a, b, c, d}} 669 670 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(square, types.LineStringType{})) 671 v, err := f.Eval(sql.NewEmptyContext(), nil) 672 require.NoError(err) 673 require.Equal(true, v) 674 }) 675 676 t.Run("linestring is not within polygon", func(t *testing.T) { 677 require := require.New(t) 678 a := types.Point{X: -100, Y: 100} 679 b := types.Point{X: 100, Y: 100} 680 c := types.Point{X: 4, Y: 4} 681 d := types.Point{X: -4, Y: 4} 682 l := types.LineString{Points: []types.Point{a, b, c, d}} 683 684 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(square, types.LineStringType{})) 685 v, err := f.Eval(sql.NewEmptyContext(), nil) 686 require.NoError(err) 687 require.Equal(false, v) 688 }) 689 690 t.Run("linestring crosses through polygon", func(t *testing.T) { 691 require := require.New(t) 692 i := types.Point{X: -100, Y: -100} 693 j := types.Point{X: 100, Y: 100} 694 l := types.LineString{Points: []types.Point{i, j}} 695 696 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(square, types.LineStringType{})) 697 v, err := f.Eval(sql.NewEmptyContext(), nil) 698 require.NoError(err) 699 require.Equal(false, v) 700 }) 701 702 t.Run("linestring boundary is not within polygon", func(t *testing.T) { 703 require := require.New(t) 704 f := NewWithin(expression.NewLiteral(square.Lines[0], types.LineStringType{}), expression.NewLiteral(square, types.LineStringType{})) 705 v, err := f.Eval(sql.NewEmptyContext(), nil) 706 require.NoError(err) 707 require.Equal(false, v) 708 }) 709 710 t.Run("linestring in hole is not within polygon", func(t *testing.T) { 711 require := require.New(t) 712 i := types.Point{X: -1, Y: -1} 713 j := types.Point{X: 1, Y: 1} 714 l := types.LineString{Points: []types.Point{i, j}} 715 716 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(squareWithHole, types.LineStringType{})) 717 v, err := f.Eval(sql.NewEmptyContext(), nil) 718 require.NoError(err) 719 require.Equal(false, v) 720 }) 721 722 t.Run("linestring crosses exterior not within polygon", func(t *testing.T) { 723 require := require.New(t) 724 a := types.Point{X: 4, Y: 0} 725 b := types.Point{X: -4, Y: 0} 726 c := types.Point{X: -2, Y: 4} 727 d := types.Point{X: 0, Y: 2} 728 e := types.Point{X: 2, Y: 4} 729 l1 := types.LineString{Points: []types.Point{a, b, c, d, e, a}} 730 p := types.Polygon{Lines: []types.LineString{l1}} 731 732 i := types.Point{X: -2, Y: 3} 733 j := types.Point{X: 2, Y: 3} 734 l := types.LineString{Points: []types.Point{i, j}} 735 736 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(p, types.LineStringType{})) 737 v, err := f.Eval(sql.NewEmptyContext(), nil) 738 require.NoError(err) 739 require.Equal(false, v) 740 }) 741 742 t.Run("linestring within non-simple polygon", func(t *testing.T) { 743 require := require.New(t) 744 // looks like a bowtie 745 a := types.Point{X: -2, Y: 2} 746 b := types.Point{X: 2, Y: 2} 747 c := types.Point{X: 2, Y: -2} 748 d := types.Point{X: -2, Y: -2} 749 l := types.LineString{Points: []types.Point{a, b, c, d, a}} 750 p := types.Polygon{Lines: []types.LineString{l}} 751 752 w := types.Point{X: -1, Y: 0} 753 x := types.Point{X: 0, Y: 1} 754 y := types.Point{X: 1, Y: 0} 755 z := types.Point{X: 0, Y: -1} 756 757 wx := types.LineString{Points: []types.Point{w, x}} 758 yz := types.LineString{Points: []types.Point{y, z}} 759 wy := types.LineString{Points: []types.Point{w, y}} 760 xz := types.LineString{Points: []types.Point{x, z}} 761 762 f := NewWithin(expression.NewLiteral(wx, types.LineStringType{}), expression.NewLiteral(p, types.PolygonType{})) 763 v, err := f.Eval(sql.NewEmptyContext(), nil) 764 require.NoError(err) 765 require.Equal(false, v) 766 767 f = NewWithin(expression.NewLiteral(yz, types.LineStringType{}), expression.NewLiteral(p, types.PolygonType{})) 768 v, err = f.Eval(sql.NewEmptyContext(), nil) 769 require.NoError(err) 770 require.Equal(false, v) 771 772 f = NewWithin(expression.NewLiteral(wy, types.LineStringType{}), expression.NewLiteral(p, types.PolygonType{})) 773 v, err = f.Eval(sql.NewEmptyContext(), nil) 774 require.NoError(err) 775 require.Equal(false, v) 776 777 // Oddly, the LineString that is completely out of the Polygon is the one that is true 778 f = NewWithin(expression.NewLiteral(xz, types.LineStringType{}), expression.NewLiteral(p, types.PolygonType{})) 779 v, err = f.Eval(sql.NewEmptyContext(), nil) 780 require.NoError(err) 781 require.Equal(true, v) 782 }) 783 784 // LineString vs MultiPoint 785 t.Run("linestring never within multipoint", func(t *testing.T) { 786 require := require.New(t) 787 a := types.Point{X: 4, Y: 4} 788 b := types.Point{X: 4, Y: -4} 789 c := types.Point{X: -4, Y: -4} 790 d := types.Point{X: -4, Y: 4} 791 l := types.LineString{Points: []types.Point{a, b, c, d}} 792 mp := types.MultiPoint{Points: []types.Point{a, b, c, d}} 793 794 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(mp, types.MultiPointType{})) 795 v, err := f.Eval(sql.NewEmptyContext(), nil) 796 require.NoError(err) 797 require.Equal(false, v) 798 }) 799 800 // LineString vs MultiLineString 801 t.Run("linestring within multilinestring", func(t *testing.T) { 802 require := require.New(t) 803 a := types.Point{X: 0, Y: 0} 804 b := types.Point{X: 1, Y: 1} 805 c := types.Point{X: 2, Y: 2} 806 l := types.LineString{Points: []types.Point{a, b, c}} 807 ml := types.MultiLineString{Lines: []types.LineString{l}} 808 809 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 810 v, err := f.Eval(sql.NewEmptyContext(), nil) 811 require.NoError(err) 812 require.Equal(true, v) 813 }) 814 815 // TODO: need to do that weird even odd thing... 816 t.Run("linestring within split multilinestring", func(t *testing.T) { 817 require := require.New(t) 818 a := types.Point{X: 0, Y: 0} 819 b := types.Point{X: 1, Y: 1} 820 c := types.Point{X: 2, Y: 2} 821 l1 := types.LineString{Points: []types.Point{a, b}} 822 l2 := types.LineString{Points: []types.Point{b, c}} 823 ml := types.MultiLineString{Lines: []types.LineString{l1, l2}} 824 l := types.LineString{Points: []types.Point{a, c}} 825 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 826 v, err := f.Eval(sql.NewEmptyContext(), nil) 827 require.NoError(err) 828 require.Equal(true, v) 829 }) 830 831 t.Run("terminal line points not with in multilinestring", func(t *testing.T) { 832 require := require.New(t) 833 a := types.Point{X: 0, Y: 0} 834 b := types.Point{X: 1, Y: 1} 835 c := types.Point{X: 2, Y: 2} 836 ab := types.LineString{Points: []types.Point{a, b}} 837 bc := types.LineString{Points: []types.Point{b, c}} 838 ml := types.MultiLineString{Lines: []types.LineString{ab, bc}} 839 840 aa := types.LineString{Points: []types.Point{a, a}} 841 bb := types.LineString{Points: []types.Point{b, b}} 842 cc := types.LineString{Points: []types.Point{c, c}} 843 f := NewWithin(expression.NewLiteral(aa, types.LineStringType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 844 v, err := f.Eval(sql.NewEmptyContext(), nil) 845 require.NoError(err) 846 require.Equal(false, v) 847 f = NewWithin(expression.NewLiteral(bb, types.LineStringType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 848 v, err = f.Eval(sql.NewEmptyContext(), nil) 849 require.NoError(err) 850 require.Equal(true, v) 851 f = NewWithin(expression.NewLiteral(cc, types.LineStringType{}), expression.NewLiteral(ml, types.MultiLineStringType{})) 852 v, err = f.Eval(sql.NewEmptyContext(), nil) 853 require.NoError(err) 854 require.Equal(false, v) 855 }) 856 857 // LineString vs MultiPolygon 858 t.Run("linestring within two separate touching polygons", func(t *testing.T) { 859 require := require.New(t) 860 a := types.Point{X: -2, Y: 1} 861 b := types.Point{X: 0, Y: 1} 862 c := types.Point{X: 0, Y: -1} 863 d := types.Point{X: -2, Y: -1} 864 e := types.Point{X: 2, Y: 1} 865 f := types.Point{X: 2, Y: -1} 866 // these are two rectangles that share a side on the y axis 867 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 868 p2 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{b, e, f, c, b}}}} 869 mp := types.MultiPolygon{Polygons: []types.Polygon{p1, p2}} 870 871 l := types.LineString{Points: []types.Point{{X: -1, Y: 0}, {X: 1, Y: 0}}} 872 ff := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(mp, types.MultiLineStringType{})) 873 v, err := ff.Eval(sql.NewEmptyContext(), nil) 874 require.NoError(err) 875 require.Equal(true, v) 876 877 l = types.LineString{Points: []types.Point{{X: -3, Y: 0}, {X: 3, Y: 0}}} 878 ff = NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(mp, types.MultiLineStringType{})) 879 v, err = ff.Eval(sql.NewEmptyContext(), nil) 880 require.NoError(err) 881 require.Equal(false, v) 882 }) 883 884 t.Run("linestring within two separate not touching polygons", func(t *testing.T) { 885 require := require.New(t) 886 // triangle 887 a := types.Point{X: -3, Y: 0} 888 b := types.Point{X: -2, Y: 2} 889 c := types.Point{X: -1, Y: 0} 890 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, a}}}} 891 892 // triangle 893 d := types.Point{X: 1, Y: 0} 894 e := types.Point{X: 2, Y: 2} 895 f := types.Point{X: 3, Y: 0} 896 p2 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{d, e, f, d}}}} 897 898 mp := types.MultiPolygon{Polygons: []types.Polygon{p1, p2}} 899 900 l := types.LineString{Points: []types.Point{{X: -2, Y: 1}, {X: 2, Y: 1}}} 901 ff := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(mp, types.MultiLineStringType{})) 902 v, err := ff.Eval(sql.NewEmptyContext(), nil) 903 require.NoError(err) 904 require.Equal(false, v) 905 }) 906 907 // LineString vs GeometryCollection 908 t.Run("linestring within empty geometrycollection returns null", func(t *testing.T) { 909 require := require.New(t) 910 l := types.LineString{Points: []types.Point{{}, {}}} 911 gc := types.GeomColl{} 912 913 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(gc, types.GeomCollType{})) 914 v, err := f.Eval(sql.NewEmptyContext(), nil) 915 require.NoError(err) 916 require.Equal(nil, v) 917 }) 918 919 t.Run("linestring within geometrycollection", func(t *testing.T) { 920 require := require.New(t) 921 l := types.LineString{Points: []types.Point{{}, {}}} 922 gc := types.GeomColl{Geoms: []types.GeometryValue{l}} 923 924 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(gc, types.GeomCollType{})) 925 v, err := f.Eval(sql.NewEmptyContext(), nil) 926 require.NoError(err) 927 require.Equal(true, v) 928 }) 929 930 t.Run("linestring not within geometrycollection", func(t *testing.T) { 931 require := require.New(t) 932 l := types.LineString{Points: []types.Point{{}, {}}} 933 l1 := types.LineString{Points: []types.Point{{X: 1, Y: 1}, {}}} 934 gc := types.GeomColl{Geoms: []types.GeometryValue{l1}} 935 936 f := NewWithin(expression.NewLiteral(l, types.LineStringType{}), expression.NewLiteral(gc, types.GeomCollType{})) 937 v, err := f.Eval(sql.NewEmptyContext(), nil) 938 require.NoError(err) 939 require.Equal(false, v) 940 }) 941 942 // LineString vs GeometryCollection 943 944 // Polygon vs Point 945 t.Run("polygon never within point", func(t *testing.T) { 946 require := require.New(t) 947 p := types.Point{X: 0, Y: 0} 948 l := types.LineString{Points: []types.Point{p, p, p, p}} 949 poly := types.Polygon{Lines: []types.LineString{l}} 950 951 f := NewWithin(expression.NewLiteral(poly, types.PolygonType{}), expression.NewLiteral(p, types.PointType{})) 952 v, err := f.Eval(sql.NewEmptyContext(), nil) 953 require.NoError(err) 954 require.Equal(false, v) 955 }) 956 957 // Polygon vs LineString 958 t.Run("polygon never within linestring", func(t *testing.T) { 959 require := require.New(t) 960 p := types.Point{X: 0, Y: 0} 961 l := types.LineString{Points: []types.Point{p, p, p, p}} 962 poly := types.Polygon{Lines: []types.LineString{l}} 963 964 f := NewWithin(expression.NewLiteral(poly, types.PolygonType{}), expression.NewLiteral(l, types.LineStringType{})) 965 v, err := f.Eval(sql.NewEmptyContext(), nil) 966 require.NoError(err) 967 require.Equal(false, v) 968 }) 969 970 // Polygon vs Polygon 971 t.Run("empty polygon within polygon", func(t *testing.T) { 972 require := require.New(t) 973 974 f := NewWithin(expression.NewLiteral(emptyPolygon, types.PolygonType{}), expression.NewLiteral(square, types.PolygonType{})) 975 v, err := f.Eval(sql.NewEmptyContext(), nil) 976 require.NoError(err) 977 require.Equal(true, v) 978 }) 979 980 t.Run("polygon within polygon touching border", func(t *testing.T) { 981 require := require.New(t) 982 // triangle inside polygon 983 a := types.Point{X: -1, Y: 1} 984 b := types.Point{X: 1, Y: 1} 985 c := types.Point{X: 1, Y: -1} 986 d := types.Point{X: -1, Y: -1} 987 l := types.LineString{Points: []types.Point{a, b, c, d, a}} 988 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, {}, a}}}} 989 p2 := types.Polygon{Lines: []types.LineString{l}} 990 991 f := NewWithin(expression.NewLiteral(p1, types.PolygonType{}), expression.NewLiteral(p2, types.PolygonType{})) 992 v, err := f.Eval(sql.NewEmptyContext(), nil) 993 require.NoError(err) 994 require.Equal(true, v) 995 }) 996 997 t.Run("empty polygon on vertex not within polygon", func(t *testing.T) { 998 require := require.New(t) 999 1000 a := types.Point{X: -1, Y: 1} 1001 b := types.Point{X: 1, Y: 1} 1002 c := types.Point{X: 1, Y: -1} 1003 d := types.Point{X: -1, Y: -1} 1004 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, a, a, a}}}} 1005 l := types.LineString{Points: []types.Point{a, b, c, d, a}} 1006 p2 := types.Polygon{Lines: []types.LineString{l}} 1007 1008 f := NewWithin(expression.NewLiteral(p1, types.PolygonType{}), expression.NewLiteral(p2, types.PolygonType{})) 1009 v, err := f.Eval(sql.NewEmptyContext(), nil) 1010 require.NoError(err) 1011 require.Equal(false, v) 1012 }) 1013 1014 t.Run("empty polygon not within itself", func(t *testing.T) { 1015 require := require.New(t) 1016 p := types.Polygon{Lines: []types.LineString{{Points: []types.Point{{}, {}, {}, {}}}}} 1017 1018 f := NewWithin(expression.NewLiteral(p, types.PolygonType{}), expression.NewLiteral(p, types.PolygonType{})) 1019 v, err := f.Eval(sql.NewEmptyContext(), nil) 1020 require.NoError(err) 1021 require.Equal(false, v) 1022 }) 1023 1024 t.Run("polygon not within overlapping polygon", func(t *testing.T) { 1025 require := require.New(t) 1026 // right triangles 1027 a := types.Point{X: -1, Y: 1} 1028 b := types.Point{X: 1, Y: 0} 1029 c := types.Point{X: -1, Y: 0} 1030 d := types.Point{X: 1, Y: 1} 1031 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, a}}}} 1032 p2 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{b, c, d, b}}}} 1033 1034 f := NewWithin(expression.NewLiteral(p1, types.LineStringType{}), expression.NewLiteral(p2, types.MultiLineStringType{})) 1035 v, err := f.Eval(sql.NewEmptyContext(), nil) 1036 require.NoError(err) 1037 require.Equal(false, v) 1038 1039 f = NewWithin(expression.NewLiteral(p2, types.LineStringType{}), expression.NewLiteral(p1, types.MultiLineStringType{})) 1040 v, err = f.Eval(sql.NewEmptyContext(), nil) 1041 require.NoError(err) 1042 require.Equal(false, v) 1043 }) 1044 1045 // Polygon vs MultiPoint 1046 t.Run("polygon never within point", func(t *testing.T) { 1047 require := require.New(t) 1048 p := types.Point{X: 0, Y: 0} 1049 l := types.LineString{Points: []types.Point{p, p, p, p}} 1050 poly := types.Polygon{Lines: []types.LineString{l}} 1051 1052 f := NewWithin(expression.NewLiteral(poly, types.PolygonType{}), expression.NewLiteral(p, types.PointType{})) 1053 v, err := f.Eval(sql.NewEmptyContext(), nil) 1054 require.NoError(err) 1055 require.Equal(false, v) 1056 }) 1057 1058 // Polygon vs MultiLineString 1059 t.Run("polygon never within multilinestring", func(t *testing.T) { 1060 require := require.New(t) 1061 p := types.Point{X: 0, Y: 0} 1062 l := types.LineString{Points: []types.Point{p, p, p, p}} 1063 ml := types.MultiLineString{Lines: []types.LineString{l}} 1064 poly := types.Polygon{Lines: []types.LineString{l}} 1065 1066 f := NewWithin(expression.NewLiteral(poly, types.PolygonType{}), expression.NewLiteral(ml, types.PointType{})) 1067 v, err := f.Eval(sql.NewEmptyContext(), nil) 1068 require.NoError(err) 1069 require.Equal(false, v) 1070 }) 1071 1072 // Polygon vs MultiPolygon 1073 t.Run("polygon not within split touching multipolygon", func(t *testing.T) { 1074 require := require.New(t) 1075 a1 := types.Point{X: -1, Y: 1} 1076 b1 := types.Point{X: 1, Y: 1} 1077 c1 := types.Point{X: 1, Y: -1} 1078 d1 := types.Point{X: -1, Y: -1} 1079 l1 := types.LineString{Points: []types.Point{a1, b1, c1, d1, a1}} 1080 p1 := types.Polygon{Lines: []types.LineString{l1}} 1081 1082 a2 := types.Point{X: -2, Y: 2} 1083 b2 := types.Point{X: 2, Y: 2} 1084 c2 := types.Point{X: 2, Y: -2} 1085 d2 := types.Point{X: -2, Y: -2} 1086 e2 := types.Point{X: 0, Y: 2} 1087 f2 := types.Point{X: 0, Y: -2} 1088 l2 := types.LineString{Points: []types.Point{a2, e2, f2, d2, a1}} 1089 p2 := types.Polygon{Lines: []types.LineString{l2}} 1090 l3 := types.LineString{Points: []types.Point{e2, b2, c2, f2, e2}} 1091 p3 := types.Polygon{Lines: []types.LineString{l3}} 1092 mp := types.MultiPolygon{Polygons: []types.Polygon{p2, p3}} 1093 1094 f := NewWithin(expression.NewLiteral(p1, types.PolygonType{}), expression.NewLiteral(mp, types.PointType{})) 1095 v, err := f.Eval(sql.NewEmptyContext(), nil) 1096 require.NoError(err) 1097 require.Equal(false, v) 1098 }) 1099 1100 // Polygon vs GeometryCollection 1101 t.Run("polygon within empty geometry collection returns null", func(t *testing.T) { 1102 require := require.New(t) 1103 1104 g := types.GeomColl{} 1105 1106 f := NewWithin(expression.NewLiteral(emptyPolygon, types.PolygonType{}), expression.NewLiteral(g, types.GeomCollType{})) 1107 v, err := f.Eval(sql.NewEmptyContext(), nil) 1108 require.NoError(err) 1109 require.Equal(nil, v) 1110 }) 1111 1112 t.Run("empty polygon within geometry collection", func(t *testing.T) { 1113 require := require.New(t) 1114 g := types.GeomColl{Geoms: []types.GeometryValue{square}} 1115 f := NewWithin(expression.NewLiteral(emptyPolygon, types.PolygonType{}), expression.NewLiteral(g, types.GeomCollType{})) 1116 v, err := f.Eval(sql.NewEmptyContext(), nil) 1117 require.NoError(err) 1118 require.Equal(true, v) 1119 }) 1120 1121 // MultiPoint vs Point 1122 t.Run("multipoint within point", func(t *testing.T) { 1123 require := require.New(t) 1124 p1 := types.Point{} 1125 mp := types.MultiPoint{Points: []types.Point{p1, p1, p1}} 1126 1127 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(p1, types.PointType{})) 1128 v, err := f.Eval(sql.NewEmptyContext(), nil) 1129 require.NoError(err) 1130 require.Equal(true, v) 1131 }) 1132 1133 t.Run("multipoint not within point", func(t *testing.T) { 1134 require := require.New(t) 1135 p1 := types.Point{} 1136 p2 := types.Point{X: 1, Y: 2} 1137 mp := types.MultiPoint{Points: []types.Point{p1, p2}} 1138 1139 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(p1, types.PointType{})) 1140 v, err := f.Eval(sql.NewEmptyContext(), nil) 1141 require.NoError(err) 1142 require.Equal(false, v) 1143 }) 1144 1145 // MultiPoint vs LineString 1146 t.Run("multipoint terminal points within empty linestring", func(t *testing.T) { 1147 require := require.New(t) 1148 p := types.Point{} 1149 mp := types.MultiPoint{Points: []types.Point{p, p}} 1150 l := types.LineString{Points: []types.Point{p, p}} 1151 1152 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(l, types.LineStringType{})) 1153 v, err := f.Eval(sql.NewEmptyContext(), nil) 1154 require.NoError(err) 1155 require.Equal(true, v) 1156 }) 1157 1158 t.Run("multipoint within linestring", func(t *testing.T) { 1159 require := require.New(t) 1160 a := types.Point{} 1161 b := types.Point{X: 2, Y: 2} 1162 p := types.Point{X: 1, Y: 1} 1163 mp := types.MultiPoint{Points: []types.Point{p}} 1164 ab := types.LineString{Points: []types.Point{a, b}} 1165 1166 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(ab, types.LineStringType{})) 1167 v, err := f.Eval(sql.NewEmptyContext(), nil) 1168 require.NoError(err) 1169 require.Equal(true, v) 1170 }) 1171 1172 t.Run("multipoint some within linestring", func(t *testing.T) { 1173 require := require.New(t) 1174 a := types.Point{} 1175 b := types.Point{X: 2, Y: 2} 1176 p := types.Point{X: 1, Y: 1} 1177 mp := types.MultiPoint{Points: []types.Point{a, p, b}} 1178 ab := types.LineString{Points: []types.Point{a, b}} 1179 1180 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(ab, types.LineStringType{})) 1181 v, err := f.Eval(sql.NewEmptyContext(), nil) 1182 require.NoError(err) 1183 require.Equal(false, v) 1184 }) 1185 1186 t.Run("multipoint terminal points not within linestring", func(t *testing.T) { 1187 require := require.New(t) 1188 a := types.Point{X: 1, Y: 1} 1189 b := types.Point{X: 2, Y: 2} 1190 mp := types.MultiPoint{Points: []types.Point{a, b}} 1191 ab := types.LineString{Points: []types.Point{a, b}} 1192 1193 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(ab, types.LineStringType{})) 1194 v, err := f.Eval(sql.NewEmptyContext(), nil) 1195 require.NoError(err) 1196 require.Equal(false, v) 1197 }) 1198 1199 // MultiPoint vs Polygon 1200 t.Run("multipoint within polygon", func(t *testing.T) { 1201 require := require.New(t) 1202 mp := types.MultiPoint{Points: []types.Point{{}}} 1203 a := types.Point{X: -1, Y: 1} 1204 b := types.Point{X: 1, Y: 1} 1205 c := types.Point{X: 1, Y: -1} 1206 d := types.Point{X: -1, Y: -1} 1207 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 1208 1209 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(poly, types.PolygonType{})) 1210 v, err := f.Eval(sql.NewEmptyContext(), nil) 1211 require.NoError(err) 1212 require.Equal(true, v) 1213 }) 1214 1215 t.Run("multipoint origin and vertexes within polygon with", func(t *testing.T) { 1216 require := require.New(t) 1217 1218 a := types.Point{X: -1, Y: 1} 1219 b := types.Point{X: 1, Y: 1} 1220 c := types.Point{X: 1, Y: -1} 1221 d := types.Point{X: -1, Y: -1} 1222 mp := types.MultiPoint{Points: []types.Point{a, b, c, d, {}}} 1223 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 1224 1225 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(poly, types.PolygonType{})) 1226 v, err := f.Eval(sql.NewEmptyContext(), nil) 1227 require.NoError(err) 1228 require.Equal(true, v) 1229 }) 1230 1231 t.Run("multipoint vertexes not within polygon", func(t *testing.T) { 1232 require := require.New(t) 1233 1234 a := types.Point{X: -1, Y: 1} 1235 b := types.Point{X: 1, Y: 1} 1236 c := types.Point{X: 1, Y: -1} 1237 d := types.Point{X: -1, Y: -1} 1238 mp := types.MultiPoint{Points: []types.Point{a, b, c, d}} 1239 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 1240 1241 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(poly, types.PolygonType{})) 1242 v, err := f.Eval(sql.NewEmptyContext(), nil) 1243 require.NoError(err) 1244 require.Equal(false, v) 1245 }) 1246 1247 t.Run("multipoint points on interior, boundary, and exterior not within polygon", func(t *testing.T) { 1248 require := require.New(t) 1249 1250 a := types.Point{X: -1, Y: 1} 1251 b := types.Point{X: 1, Y: 1} 1252 c := types.Point{X: 1, Y: -1} 1253 d := types.Point{X: -1, Y: -1} 1254 mp := types.MultiPoint{Points: []types.Point{a, {}, types.Point{X: 100, Y: 100}}} 1255 poly := types.Polygon{Lines: []types.LineString{{Points: []types.Point{a, b, c, d, a}}}} 1256 1257 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(poly, types.PolygonType{})) 1258 v, err := f.Eval(sql.NewEmptyContext(), nil) 1259 require.NoError(err) 1260 require.Equal(false, v) 1261 }) 1262 1263 t.Run("multipoint terminal points not within empty polygon", func(t *testing.T) { 1264 require := require.New(t) 1265 mp := types.MultiPoint{Points: []types.Point{{}}} 1266 poly := types.Polygon{Lines: []types.LineString{{}, {}, {}, {}}} 1267 1268 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(poly, types.PolygonType{})) 1269 v, err := f.Eval(sql.NewEmptyContext(), nil) 1270 require.NoError(err) 1271 require.Equal(false, v) 1272 }) 1273 1274 // MultiPoint vs MultiPoint 1275 1276 // MultiPoint vs MultiLineString 1277 1278 // MultiPoint vs MultiPolygon 1279 1280 // MultiPoint vs GeometryCollection 1281 t.Run("multipoint within empty geometrycollection returns null", func(t *testing.T) { 1282 require := require.New(t) 1283 mp := types.MultiPoint{Points: []types.Point{{}, {}}} 1284 gc := types.GeomColl{} 1285 1286 f := NewWithin(expression.NewLiteral(mp, types.MultiPointType{}), expression.NewLiteral(gc, types.GeomCollType{})) 1287 v, err := f.Eval(sql.NewEmptyContext(), nil) 1288 require.NoError(err) 1289 require.Equal(nil, v) 1290 }) 1291 1292 // MultiLineString vs Point 1293 t.Run("multilinestring never within point", func(t *testing.T) { 1294 require := require.New(t) 1295 p := types.Point{X: 0, Y: 0} 1296 l := types.LineString{Points: []types.Point{p, p}} 1297 ml := types.MultiLineString{Lines: []types.LineString{l}} 1298 1299 f := NewWithin(expression.NewLiteral(ml, types.LineStringType{}), expression.NewLiteral(p, types.PointType{})) 1300 v, err := f.Eval(sql.NewEmptyContext(), nil) 1301 require.NoError(err) 1302 require.Equal(false, v) 1303 }) 1304 1305 // MultiLineString vs LineString 1306 1307 // MultiLineString vs Polygon 1308 1309 // MultiLineString vs MultiPoint 1310 1311 // MultiLineString vs MultiLineString 1312 1313 // MultiLineString vs MultiPolygon 1314 1315 // MultiLineString vs GeometryCollection 1316 t.Run("multilinestring within empty geometrycollection returns null", func(t *testing.T) { 1317 require := require.New(t) 1318 l := types.LineString{Points: []types.Point{{}, {}}} 1319 ml := types.MultiLineString{Lines: []types.LineString{l, l}} 1320 gc := types.GeomColl{} 1321 1322 f := NewWithin(expression.NewLiteral(ml, types.MultiLineStringType{}), expression.NewLiteral(gc, types.GeomCollType{})) 1323 v, err := f.Eval(sql.NewEmptyContext(), nil) 1324 require.NoError(err) 1325 require.Equal(nil, v) 1326 }) 1327 1328 // MultiPolygon vs Point 1329 t.Run("multipolygon never within point", func(t *testing.T) { 1330 require := require.New(t) 1331 p := types.Point{X: 0, Y: 0} 1332 l := types.LineString{Points: []types.Point{p, p}} 1333 poly := types.Polygon{Lines: []types.LineString{l}} 1334 mpoly := types.MultiPolygon{Polygons: []types.Polygon{poly}} 1335 1336 f := NewWithin(expression.NewLiteral(mpoly, types.MultiPolygonType{}), expression.NewLiteral(p, types.PointType{})) 1337 v, err := f.Eval(sql.NewEmptyContext(), nil) 1338 require.NoError(err) 1339 require.Equal(false, v) 1340 }) 1341 1342 // MultiPolygon vs LineString 1343 t.Run("multipolygon never within linestring", func(t *testing.T) { 1344 require := require.New(t) 1345 p := types.Point{X: 0, Y: 0} 1346 l := types.LineString{Points: []types.Point{p, p}} 1347 poly := types.Polygon{Lines: []types.LineString{l}} 1348 mpoly := types.MultiPolygon{Polygons: []types.Polygon{poly}} 1349 1350 f := NewWithin(expression.NewLiteral(mpoly, types.MultiPolygonType{}), expression.NewLiteral(l, types.LineStringType{})) 1351 v, err := f.Eval(sql.NewEmptyContext(), nil) 1352 require.NoError(err) 1353 require.Equal(false, v) 1354 }) 1355 1356 // MultiPolygon vs Polygon 1357 1358 // MultiPolygon vs MultiPoint 1359 1360 // MultiPolygon vs MultiLineString 1361 1362 // MultiPolygon vs MultiPolygon 1363 1364 // MultiPolygon vs GeometryCollection 1365 t.Run("multipolygon within empty geometrycollection returns null", func(t *testing.T) { 1366 require := require.New(t) 1367 l := types.LineString{Points: []types.Point{{}, {}, {}, {}}} 1368 p := types.Polygon{Lines: []types.LineString{l}} 1369 mp := types.MultiPolygon{Polygons: []types.Polygon{p, p}} 1370 gc := types.GeomColl{} 1371 1372 f := NewWithin(expression.NewLiteral(mp, types.MultiPolygonType{}), expression.NewLiteral(gc, types.GeomCollType{})) 1373 v, err := f.Eval(sql.NewEmptyContext(), nil) 1374 require.NoError(err) 1375 require.Equal(nil, v) 1376 }) 1377 1378 // GeometryCollection vs Point 1379 t.Run("geometrycollection within point", func(t *testing.T) { 1380 require := require.New(t) 1381 p := types.Point{} 1382 gc := types.GeomColl{Geoms: []types.GeometryValue{p}} 1383 f := NewWithin(expression.NewLiteral(gc, types.GeomCollType{}), expression.NewLiteral(p, types.PointType{})) 1384 v, err := f.Eval(sql.NewEmptyContext(), nil) 1385 require.NoError(err) 1386 require.Equal(true, v) 1387 }) 1388 1389 // GeometryCollection vs LineString 1390 t.Run("geometrycollection within linestring", func(t *testing.T) { 1391 require := require.New(t) 1392 a := types.Point{X: 0, Y: 0} 1393 b := types.Point{X: 1, Y: 1} 1394 c := types.Point{X: -5, Y: -5} 1395 d := types.Point{X: 5, Y: 5} 1396 ab := types.LineString{Points: []types.Point{a, b}} 1397 cd := types.LineString{Points: []types.Point{c, d}} 1398 gc := types.GeomColl{Geoms: []types.GeometryValue{cd}} 1399 f := NewWithin(expression.NewLiteral(ab, types.GeomCollType{}), expression.NewLiteral(gc, types.LineStringType{})) 1400 v, err := f.Eval(sql.NewEmptyContext(), nil) 1401 require.NoError(err) 1402 require.Equal(true, v) 1403 }) 1404 1405 // GeometryCollection vs Polygon 1406 t.Run("geometrycollection within polygon", func(t *testing.T) { 1407 require := require.New(t) 1408 1409 p1 := types.Polygon{Lines: []types.LineString{{Points: []types.Point{{}, {}, {}, {}}}}} 1410 gc := types.GeomColl{Geoms: []types.GeometryValue{p1}} 1411 1412 a := types.Point{X: -1, Y: 1} 1413 b := types.Point{X: 1, Y: 1} 1414 c := types.Point{X: 1, Y: -1} 1415 d := types.Point{X: -1, Y: -1} 1416 l := types.LineString{Points: []types.Point{a, b, c, d, a}} 1417 p2 := types.Polygon{Lines: []types.LineString{l}} 1418 1419 f := NewWithin(expression.NewLiteral(gc, types.GeomCollType{}), expression.NewLiteral(p2, types.PolygonType{})) 1420 v, err := f.Eval(sql.NewEmptyContext(), nil) 1421 require.NoError(err) 1422 require.Equal(true, v) 1423 }) 1424 1425 // GeometryCollection vs MultiPoint 1426 1427 // GeometryCollection vs MultiLineString 1428 1429 // GeometryCollection vs MultiPolygon 1430 1431 // GeometryCollection vs GeometryCollection 1432 t.Run("empty geometry collection within empty geometrycollection returns null", func(t *testing.T) { 1433 require := require.New(t) 1434 gc := types.GeomColl{} 1435 1436 f := NewWithin(expression.NewLiteral(gc, types.GeomCollType{}), expression.NewLiteral(gc, types.GeomCollType{})) 1437 v, err := f.Eval(sql.NewEmptyContext(), nil) 1438 require.NoError(err) 1439 require.Equal(nil, v) 1440 }) 1441 1442 t.Run("geometry collection within empty geometrycollection returns null", func(t *testing.T) { 1443 require := require.New(t) 1444 gc1 := types.GeomColl{Geoms: []types.GeometryValue{types.Point{}}} 1445 gc2 := types.GeomColl{} 1446 1447 f := NewWithin(expression.NewLiteral(gc1, types.GeomCollType{}), expression.NewLiteral(gc2, types.GeomCollType{})) 1448 v, err := f.Eval(sql.NewEmptyContext(), nil) 1449 require.NoError(err) 1450 require.Equal(nil, v) 1451 }) 1452 }