github.com/liucxer/courier@v1.7.1/h3/h3api_test.go (about)

     1  package h3
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"io/ioutil"
     7  	"math"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"testing"
    12  	"text/scanner"
    13  
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestH3Api(t *testing.T) {
    18  	t.Run("geoToH3_res", func(t *testing.T) {
    19  		anywhere := GeoCoord{0, 0}
    20  		require.True(t, geoToH3(&anywhere, -1) == 0, "resolution below 0 is invalid")
    21  		require.True(t, geoToH3(&anywhere, 16) == 0, "resolution above 15 is invalid")
    22  	})
    23  
    24  	t.Run("geoToH3_coord", func(t *testing.T) {
    25  		invalidLat := GeoCoord{math.NaN(), 0}
    26  		invalidLon := GeoCoord{0, math.NaN()}
    27  		invalidLatLon := GeoCoord{math.Inf(1), math.Inf(-1)}
    28  		require.True(t, geoToH3(&invalidLat, 1) == 0, "invalid latitude is rejected")
    29  		require.True(t, geoToH3(&invalidLon, 1) == 0, "invalid longitude is rejected")
    30  		require.True(t, geoToH3(&invalidLatLon, 1) == 0, "coordinates with infinity are rejected")
    31  	})
    32  
    33  	t.Run("h3ToGeoBoundary_classIIIEdgeVertex", func(t *testing.T) {
    34  		// Bug test for https://github.com/uber/h3/issues/45
    35  		hexes := []string{
    36  			"894cc5349b7ffff", "894cc534d97ffff", "894cc53682bffff",
    37  			"894cc536b17ffff", "894cc53688bffff", "894cead92cbffff",
    38  			"894cc536537ffff", "894cc5acbabffff", "894cc536597ffff",
    39  		}
    40  		numHexes := len(hexes)
    41  		var h3 H3Index
    42  		for i := 0; i < numHexes; i++ {
    43  			h3 = stringToH3(hexes[i])
    44  			var b GeoBoundary
    45  			h3ToGeoBoundary(h3, &b)
    46  			require.True(t, b.numVerts == 7, "got expected vertex count")
    47  		}
    48  	})
    49  
    50  	t.Run("h3ToGeoBoundary_classIIIEdgeVertex_exact", func(t *testing.T) {
    51  		// Bug test for https://github.com/uber/h3/issues/45
    52  		h3 := stringToH3("894cc536537ffff")
    53  		var boundary GeoBoundary
    54  		boundary.numVerts = 7
    55  		boundary.Verts = make([]GeoCoord, 7)
    56  
    57  		setGeoDegs(&boundary.Verts[0], 18.043333154, -66.27836523500002)
    58  		setGeoDegs(&boundary.Verts[1], 18.042238363, -66.27929062800001)
    59  		setGeoDegs(&boundary.Verts[2], 18.040818259, -66.27854193899998)
    60  		setGeoDegs(&boundary.Verts[3], 18.040492975, -66.27686786700002)
    61  		setGeoDegs(&boundary.Verts[4], 18.041040385, -66.27640518300001)
    62  		setGeoDegs(&boundary.Verts[5], 18.041757122, -66.27596711500001)
    63  		setGeoDegs(&boundary.Verts[6], 18.043007860, -66.27669118199998)
    64  		assertBoundary(t, h3, &boundary)
    65  	})
    66  
    67  	t.Run("h3ToGeoBoundary_coslonConstrain", func(t *testing.T) {
    68  		// Bug test for https://github.com/uber/h3/issues/212
    69  		h3 := H3Index(0x87dc6d364ffffff)
    70  		var boundary GeoBoundary
    71  		boundary.numVerts = 6
    72  		boundary.Verts = make([]GeoCoord, 6)
    73  
    74  		setGeoDegs(&boundary.Verts[0], -52.0130533678236091, -34.6232931343713091)
    75  		setGeoDegs(&boundary.Verts[1], -52.0041156384652012, -34.6096733160584549)
    76  		setGeoDegs(&boundary.Verts[2], -51.9929610229502472, -34.6165157145896387)
    77  		setGeoDegs(&boundary.Verts[3], -51.9907410568096608, -34.6369680004259877)
    78  		setGeoDegs(&boundary.Verts[4], -51.9996738734672377, -34.6505896528323660)
    79  		setGeoDegs(&boundary.Verts[5], -52.0108315681413629, -34.6437571897165668)
    80  		assertBoundary(t, h3, &boundary)
    81  	})
    82  
    83  }
    84  
    85  var centerFiles []string
    86  var cellFiles []string
    87  
    88  func init() {
    89  	fileList, err := ioutil.ReadDir("./testdata")
    90  	if err != nil {
    91  		panic(err)
    92  	}
    93  
    94  	for _, f := range fileList {
    95  		name := f.Name()
    96  
    97  		if strings.Contains(name, "centers") {
    98  			centerFiles = append(centerFiles, "./testdata/"+f.Name())
    99  		}
   100  
   101  		if strings.Contains(name, "cells") {
   102  			cellFiles = append(cellFiles, "./testdata/"+f.Name())
   103  		}
   104  	}
   105  }
   106  
   107  func _Test_testdata(t *testing.T) {
   108  	t.Run("centers", func(t *testing.T) {
   109  		for _, f := range centerFiles {
   110  			data := loadData(f)
   111  
   112  			for i, coords := range data {
   113  				h := i
   114  
   115  				if len(coords) == 1 {
   116  					expectG := &coords[0]
   117  
   118  					g := GeoCoord{}
   119  					h3ToGeo(h, &g)
   120  
   121  					require.True(t, geoDegreeEqual(&g, expectG), "h3ToGeo %x %d %v %v", h, h, expectG.AsDegrees(), g.AsDegrees())
   122  					require.Equal(t, h, geoToH3(expectG, h3GetResolution(h)), "h3ToGeo %x %d", h, h)
   123  				}
   124  			}
   125  		}
   126  	})
   127  
   128  	t.Run("cells", func(t *testing.T) {
   129  		for _, f := range cellFiles {
   130  			data := loadData(f)
   131  
   132  			for i, coords := range data {
   133  				h := i
   134  
   135  				if len(coords) > 0 {
   136  					expectGB := &GeoBoundary{numVerts: len(coords), Verts: coords}
   137  
   138  					assertBoundary(t, h, expectGB)
   139  				}
   140  			}
   141  		}
   142  	})
   143  }
   144  
   145  func assertBoundary(t *testing.T, h H3Index, expectGB *GeoBoundary) {
   146  	gb := GeoBoundary{}
   147  	h3ToGeoBoundary(h, &gb)
   148  
   149  	require.Equal(t, expectGB.numVerts, gb.numVerts, "h3ToGeoBoundary %x %v %v", h, gb.AsDegrees(), expectGB.AsDegrees())
   150  
   151  	for i := 0; i < expectGB.numVerts; i++ {
   152  		require.True(t, geoDegreeEqual(&expectGB.Verts[i], &gb.Verts[i]), "h3ToGeoBoundary %x &v &v", h, expectGB.Verts[i].AsDegrees(), gb.Verts[i].AsDegrees())
   153  	}
   154  }
   155  
   156  func geoDegreeEqual(p1 *GeoCoord, p2 *GeoCoord) bool {
   157  	return geoAlmostEqualThreshold(p1.AsDegrees(), p2.AsDegrees(), 0.000001)
   158  }
   159  
   160  type expects map[H3Index][]GeoCoord
   161  
   162  func loadData(filename string) expects {
   163  	f, err := os.Open(filename)
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  	defer f.Close()
   168  	return parseInputs(f)
   169  }
   170  
   171  func parseInputs(reader io.Reader) expects {
   172  	set := expects{}
   173  
   174  	var s scanner.Scanner
   175  	s.Init(reader)
   176  
   177  	tmp := bytes.NewBuffer(nil)
   178  
   179  	clearTmp := func() {
   180  		tmp = bytes.NewBuffer(nil)
   181  	}
   182  
   183  	var h uint64
   184  	var coord *GeoCoord
   185  	var inCell bool
   186  
   187  	for tok := s.Scan(); tok != scanner.EOF; tok = s.Next() {
   188  		switch tok {
   189  		case '\n', ' ':
   190  			if tmp.Len() == 0 {
   191  				break
   192  			}
   193  
   194  			if h == 0 {
   195  				h, _ = strconv.ParseUint(tmp.String(), 16, 64)
   196  				clearTmp()
   197  				set[H3Index(h)] = []GeoCoord{}
   198  				break
   199  			}
   200  
   201  			if coord == nil {
   202  				coord = &GeoCoord{}
   203  			}
   204  
   205  			if coord.Lat == 0 {
   206  				f, _ := strconv.ParseFloat(tmp.String(), 64)
   207  				clearTmp()
   208  				coord.Lat = f * deg2rad
   209  				break
   210  			}
   211  
   212  			if coord.Lon == 0 {
   213  				f, _ := strconv.ParseFloat(tmp.String(), 64)
   214  				clearTmp()
   215  				coord.Lon = f * deg2rad
   216  
   217  				set[H3Index(h)] = append(set[H3Index(h)], *coord)
   218  
   219  				// clear
   220  				coord = nil
   221  
   222  				if !inCell {
   223  					h = 0
   224  				}
   225  			}
   226  		case '{':
   227  			inCell = true
   228  		case '}':
   229  			inCell = false
   230  			h = 0
   231  		default:
   232  			tmp.WriteRune(tok)
   233  		}
   234  	}
   235  
   236  	return set
   237  }