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  }