github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/geo/geogfn/segmentize_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  	"github.com/twpayne/go-geom"
    20  )
    21  
    22  func TestSegmentize(t *testing.T) {
    23  	segmentizeTestCases := []struct {
    24  		wkt              string
    25  		maxSegmentLength float64
    26  		expectedWKT      string
    27  	}{
    28  		{
    29  			wkt:              "POINT(1.0 1.0)",
    30  			maxSegmentLength: 10000.0,
    31  			expectedWKT:      "POINT(1.0 1.0)",
    32  		},
    33  		{
    34  			wkt:              "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)",
    35  			maxSegmentLength: 100000.0,
    36  			expectedWKT:      "LINESTRING (1 1, 1.4998857365616758 1.5000570914791973, 2 2, 2.4998094835255658 2.500095075163195, 3 3)",
    37  		},
    38  		{
    39  			wkt:              "LINESTRING EMPTY",
    40  			maxSegmentLength: 10000.0,
    41  			expectedWKT:      "LINESTRING EMPTY",
    42  		},
    43  		{
    44  			wkt:              "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)",
    45  			maxSegmentLength: 500000.0,
    46  			expectedWKT:      "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)",
    47  		},
    48  		{
    49  			wkt:              "POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, 0.0 0.0))",
    50  			maxSegmentLength: 100000.0,
    51  			expectedWKT:      "POLYGON ((0 0, 0.5 0, 1 0, 1 0.4999999999999999, 1 1, 0.4999619199226218 0.5000190382261059, 0 0))",
    52  		},
    53  		{
    54  			wkt:              "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))",
    55  			maxSegmentLength: 50000.0,
    56  			expectedWKT:      "POLYGON ((0 0, 0.25 0, 0.5 0, 0.75 0, 1 0, 0.9999999999999998 0.25, 1 0.4999999999999999, 0.9999999999999998 0.7499999999999999, 1 1, 0.7499666792978344 0.7500166590029188, 0.4999619199226218 0.5000190382261059, 0.24997620022356357 0.2500118986534327, 0 0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1))",
    57  		},
    58  		{
    59  			wkt:              "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))",
    60  			maxSegmentLength: 1000000.0,
    61  			expectedWKT:      "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))",
    62  		},
    63  		{
    64  			wkt:              "POLYGON EMPTY",
    65  			maxSegmentLength: 10000.0,
    66  			expectedWKT:      "POLYGON EMPTY",
    67  		},
    68  		{
    69  			wkt:              "MULTIPOINT((1.0 1.0), (2.0 2.0))",
    70  			maxSegmentLength: 100000.0,
    71  			expectedWKT:      "MULTIPOINT((1.0 1.0), (2.0 2.0))",
    72  		},
    73  		{
    74  			wkt:              "MULTILINESTRING((1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))",
    75  			maxSegmentLength: 100000.0,
    76  			expectedWKT:      "MULTILINESTRING ((1 1, 1.4998857365616758 1.5000570914791973, 2 2, 2.4998094835255658 2.500095075163195, 3 3), (6 6, 6.5 6.000226803574719, 7 6))",
    77  		},
    78  		{
    79  			wkt:              "MULTILINESTRING (EMPTY, (1.0 1.0, 2.0 2.0, 3.0 3.0), (6.0 6.0, 7.0 6.0))",
    80  			maxSegmentLength: 100000.0,
    81  			expectedWKT:      "MULTILINESTRING (EMPTY, (1 1, 1.4998857365616758 1.5000570914791973, 2 2, 2.4998094835255658 2.500095075163195, 3 3), (6 6, 6.5 6.000226803574719, 7 6))",
    82  		},
    83  		{
    84  			wkt:              "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)))",
    85  			maxSegmentLength: 100000.0,
    86  			expectedWKT:      "MULTIPOLYGON (((3 3, 3.500000000000001 3.0001140264716564, 4 3, 3.999999999999999 3.5, 4 4, 3.4997331141752333 3.5001329429928956, 3 3)), ((0 0, 0.5 0, 1 0, 1 0.4999999999999999, 1 1, 0.4999619199226218 0.5000190382261059, 0 0), (0.1 0.1, 0.2 0.1, 0.2 0.2, 0.1 0.1)))",
    87  		},
    88  		{
    89  			wkt:              "GEOMETRYCOLLECTION (POINT (40 10),LINESTRING (10 10, 20 20, 10 40),POLYGON ((40 40, 20 45, 45 30, 40 40)))",
    90  			maxSegmentLength: 1000000.0,
    91  			expectedWKT:      "GEOMETRYCOLLECTION (POINT (40 10), LINESTRING (10 10, 14.88248913028353 15.054670903122675, 20 20, 17.84783705611024 25.063693381403255, 15.510294720403053 30.09369304154877, 12.922758839587525 35.07789165618019, 10 40), POLYGON ((40 40, 30.404184608679003 42.93646050008845, 20 45, 27.258698904670663 41.785178536245354, 33.78296512799812 38.158856049677816, 39.6629587979805 34.20684491196235, 45 30, 42.6532474552537 35.02554212454631, 40 40)))",
    92  		},
    93  		{
    94  			wkt:              "MULTIPOINT((0 0), (1 1))",
    95  			maxSegmentLength: -1,
    96  			expectedWKT:      "MULTIPOINT((0 0), (1 1))",
    97  		},
    98  	}
    99  	for _, test := range segmentizeTestCases {
   100  		t.Run(fmt.Sprintf("%s, maximum segment length: %v", test.wkt, test.maxSegmentLength), func(t *testing.T) {
   101  			geog, err := geo.ParseGeography(test.wkt)
   102  			require.NoError(t, err)
   103  			modifiedGeog, err := Segmentize(geog, test.maxSegmentLength)
   104  			require.NoError(t, err)
   105  			expectedGeog, err := geo.ParseGeography(test.expectedWKT)
   106  			require.NoError(t, err)
   107  			require.Equal(t, expectedGeog, modifiedGeog)
   108  		})
   109  	}
   110  	// Test for segment maximum length as negative for geometry collection.
   111  	t.Run(fmt.Sprintf("%s, maximum segment length: %v", segmentizeTestCases[9].wkt, 0.0), func(t *testing.T) {
   112  		geog, err := geo.ParseGeography(segmentizeTestCases[9].wkt)
   113  		require.NoError(t, err)
   114  		_, err = Segmentize(geog, 0)
   115  		require.EqualError(t, err, "maximum segment length must be positive")
   116  	})
   117  }
   118  
   119  func TestSegmentizeCoords(t *testing.T) {
   120  	testCases := []struct {
   121  		desc                 string
   122  		a                    geom.Coord
   123  		b                    geom.Coord
   124  		segmentMaxLength     float64
   125  		resultantCoordinates []float64
   126  	}{
   127  		{
   128  			desc:                 `Coordinate(0, 0) to Coordinate(85, 85), 0.781600222084459`,
   129  			a:                    geom.Coord{0, 0},
   130  			b:                    geom.Coord{85, 85},
   131  			segmentMaxLength:     0.781600222084459,
   132  			resultantCoordinates: []float64{0, 0, 4.924985039227315, 44.568038920632105},
   133  		},
   134  		{
   135  			desc:                 `Coordinate(0, 0) to Coordinate(85, 85), 0.7816000651234446`,
   136  			a:                    geom.Coord{0, 0},
   137  			b:                    geom.Coord{85, 85},
   138  			segmentMaxLength:     0.7816000651234446,
   139  			resultantCoordinates: []float64{0, 0, 2.0486953806277866, 22.302074138733936, 4.924985039227315, 44.568038920632105, 11.655816669136822, 66.66485041602017},
   140  		},
   141  		{
   142  			desc:                 `Coordinate(85, 85) to Coordinate(0, 0), 0.29502092024628396`,
   143  			a:                    geom.Coord{85, 85},
   144  			b:                    geom.Coord{0, 0},
   145  			segmentMaxLength:     0.29502092024628396,
   146  			resultantCoordinates: []float64{85, 85, 22.871662720021178, 77.3609628116894, 11.655816669136824, 66.66485041602017, 7.329091976767396, 55.658764687902504, 4.924985039227315, 44.56803892063211, 3.299940624127866, 33.443216802941045, 2.048695380627787, 22.302074138733943, 0.9845421446758968, 11.1527721155093},
   147  		},
   148  		{
   149  			desc:                 `Coordinate(85, 85) to Coordinate(0, 0), -1`,
   150  			a:                    geom.Coord{85, 85},
   151  			b:                    geom.Coord{0, 0},
   152  			segmentMaxLength:     -1,
   153  			resultantCoordinates: []float64{85, 85},
   154  		},
   155  	}
   156  	for _, test := range testCases {
   157  		t.Run(test.desc, func(t *testing.T) {
   158  			convertedPoints := segmentizeCoords(test.a, test.b, test.segmentMaxLength)
   159  			require.Equal(t, test.resultantCoordinates, convertedPoints)
   160  		})
   161  	}
   162  }