github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geomfn/unary_operators_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 geomfn
    12  
    13  import (
    14  	"testing"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/geo"
    17  	"github.com/stretchr/testify/require"
    18  	"github.com/twpayne/go-geom"
    19  )
    20  
    21  func TestCentroid(t *testing.T) {
    22  	testCases := []struct {
    23  		wkt      string
    24  		expected string
    25  	}{
    26  		{"POINT(1.0 1.0)", "POINT (1.0 1.0)"},
    27  		{"SRID=4326;POINT(1.0 1.0)", "SRID=4326;POINT (1.0 1.0)"},
    28  		{"LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", "POINT (2.0 2.0)"},
    29  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))", "POINT (0.666666666666667 0.333333333333333)"},
    30  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))", "POINT (0.671717171717172 0.335353535353535)"},
    31  		{"MULTIPOINT((1.0 1.0), (2.0 2.0))", "POINT (1.5 1.5)"},
    32  		{"MULTILINESTRING((1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))", "POINT (3.17541743733684 3.04481549985497)"},
    33  		{"MULTIPOLYGON(((3.0 3.0, 4.0 3.0, 4.0 4.0, 3.0 3.0)), ((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)))", "POINT (2.17671691792295 1.84187604690117)"},
    34  		{"GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))", "POINT (35 38.3333333333333)"},
    35  	}
    36  
    37  	for _, tc := range testCases {
    38  		t.Run(tc.wkt, func(t *testing.T) {
    39  			g, err := geo.ParseGeometry(tc.wkt)
    40  			require.NoError(t, err)
    41  			ret, err := Centroid(g)
    42  			require.NoError(t, err)
    43  
    44  			retAsGeomT, err := ret.AsGeomT()
    45  			require.NoError(t, err)
    46  
    47  			expected, err := geo.ParseGeometry(tc.expected)
    48  			require.NoError(t, err)
    49  			expectedAsGeomT, err := expected.AsGeomT()
    50  			require.NoError(t, err)
    51  
    52  			// Ensure points are close in terms of precision.
    53  			require.InEpsilon(t, expectedAsGeomT.(*geom.Point).X(), retAsGeomT.(*geom.Point).X(), 2e-10)
    54  			require.InEpsilon(t, expectedAsGeomT.(*geom.Point).Y(), retAsGeomT.(*geom.Point).Y(), 2e-10)
    55  			require.Equal(t, expected.SRID(), ret.SRID())
    56  		})
    57  	}
    58  }
    59  
    60  func TestLength(t *testing.T) {
    61  	testCases := []struct {
    62  		wkt      string
    63  		expected float64
    64  	}{
    65  		{"POINT(1.0 1.0)", 0},
    66  		{"LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", 2.8284271247461903},
    67  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))", 0},
    68  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))", 0},
    69  		{"MULTIPOINT((1.0 1.0), (2.0 2.0))", 0},
    70  		{"MULTILINESTRING((1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))", 3.8284271247461903},
    71  		{"MULTIPOLYGON(((3.0 3.0, 4.0 3.0, 4.0 4.0, 3.0 3.0)), ((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)))", 0},
    72  		{"GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))", 36.50281539872885},
    73  	}
    74  
    75  	for _, tc := range testCases {
    76  		t.Run(tc.wkt, func(t *testing.T) {
    77  			g, err := geo.ParseGeometry(tc.wkt)
    78  			require.NoError(t, err)
    79  			ret, err := Length(g)
    80  			require.NoError(t, err)
    81  			require.Equal(t, tc.expected, ret)
    82  		})
    83  	}
    84  }
    85  
    86  func TestPerimeter(t *testing.T) {
    87  	testCases := []struct {
    88  		wkt      string
    89  		expected float64
    90  	}{
    91  		{"POINT(1.0 1.0)", 0},
    92  		{"LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", 0},
    93  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))", 3.414213562373095},
    94  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))", 3.7556349186104043},
    95  		{"MULTIPOINT((1.0 1.0), (2.0 2.0))", 0},
    96  		{"MULTILINESTRING((1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))", 0},
    97  		{"MULTIPOLYGON(((3.0 3.0, 4.0 3.0, 4.0 4.0, 3.0 3.0)), ((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)))", 7.169848480983499},
    98  		{"GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))", 60.950627489813755},
    99  	}
   100  
   101  	for _, tc := range testCases {
   102  		t.Run(tc.wkt, func(t *testing.T) {
   103  			g, err := geo.ParseGeometry(tc.wkt)
   104  			require.NoError(t, err)
   105  			ret, err := Perimeter(g)
   106  			require.NoError(t, err)
   107  			require.Equal(t, tc.expected, ret)
   108  		})
   109  	}
   110  }
   111  
   112  func TestArea(t *testing.T) {
   113  	testCases := []struct {
   114  		wkt      string
   115  		expected float64
   116  	}{
   117  		{"POINT(1.0 1.0)", 0},
   118  		{"LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", 0},
   119  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))", 0.5},
   120  		{"POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))", 0.495},
   121  		{"MULTIPOINT((1.0 1.0), (2.0 2.0))", 0},
   122  		{"MULTILINESTRING((1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))", 0},
   123  		{"MULTIPOLYGON(((3.0 3.0, 4.0 3.0, 4.0 4.0, 3.0 3.0)), ((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)))", 0.995},
   124  		{"GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))", 87.5},
   125  	}
   126  
   127  	for _, tc := range testCases {
   128  		t.Run(tc.wkt, func(t *testing.T) {
   129  			g, err := geo.ParseGeometry(tc.wkt)
   130  			require.NoError(t, err)
   131  			ret, err := Area(g)
   132  			require.NoError(t, err)
   133  			require.Equal(t, tc.expected, ret)
   134  		})
   135  	}
   136  }