package quadkey_test import ( "fmt" "testing" "fiskerinc.com/modules/utils/quadkey" "github.com/stretchr/testify/assert" ) func TestLatLongToQuadkey(t *testing.T) { tests := map[string]struct { lat float64 long float64 expectedQuadkeyStr string expectedQuadkeyInt uint64 }{ "lapalma": { lat: 33.86219399999999, long: -118.029596, expectedQuadkeyStr: "02301320022100032301331202320110", expectedQuadkeyInt: 3204356230721449492, }, "london": { lat: 51.507822, long: -0.162069, expectedQuadkeyStr: "03131313113000100311131122203023", expectedQuadkeyInt: 3996764367461132491, }, "null": { lat: 0.0, long: 0.0, expectedQuadkeyStr: "30000000000000000000000000000000", expectedQuadkeyInt: 0xC000000000000000, }, "invalid": { lat: -2000.0, long: -2000.0, expectedQuadkeyStr: "22222222222222222222222222222222", expectedQuadkeyInt: 0xAAAAAAAAAAAAAAAA, }, } for tname, tt := range tests { t.Run(tname, func(t *testing.T) { qkey := quadkey.LatLongToQuadKey(tt.lat, tt.long) qkeyStr := quadkey.QuadkeyStr(qkey) assert.Equal(t, tt.expectedQuadkeyInt, qkey) assert.Equal(t, tt.expectedQuadkeyStr, qkeyStr) }) } } func TestQuadkeySearchBuckets(t *testing.T) { tests := map[string]struct { lat float64 long float64 radius float64 coarseness float64 expectedKeys map[uint64]bool expectedBuckets map[uint64]quadkey.QuadkeyBucket absentKeys map[uint64]bool //set of keys that should not show up }{ "invalid": { lat: -2000.0, long: -2000.0, radius: 100.0, //100m coarseness: 600000.0, // 600km expectedKeys: map[uint64]bool{}, //an invalid quad is generated, and fails every intersect check }, "null": { lat: 0.0, long: 0.0, radius: 100.0, //100m coarseness: 600000.0, // 600km expectedKeys: map[uint64]bool{ 0x3FF0000000000000: true, //033333 0xC000000000000000: true, //300000 0x6AA0000000000000: true, //122222 0x9550000000000000: true, //211111 }, }, "london": { lat: 51.507822, long: -0.162069, radius: 8, //8 meters radius coarseness: 8, expectedKeys: map[uint64]bool{ 0x37775C0435400000: true, //0313131311300010031110 0x37775C0435500000: true, //0313131311300010031111 0x37775C0460000000: true, //0313131311300010120000 0x37775C0435600000: true, //0313131311300010031112 0x37775C0435700000: true, //0313131311300010031113 0x37775C0460200000: true, //0313131311300010120002 0x37775C0435C00000: true, //0313131311300010031130 0x37775C0435D00000: true, //0313131311300010031131 0x37775C0460800000: true, //0313131311300010120020 }, absentKeys: map[uint64]bool{ 0x2C782903B1D00000: true, 0x2C782903B1DC8000: true, 0x2C782903B4000000: true, 0x2C782903B4080000: true, 0x2C782903B00C0000: true, 0x2C782903B4800000: true, 0x2C78290000000000: true, }, }, //lapalma test cases use quadkeys from visually inspecting mapbox maps "lapalma": { lat: 33.86219399999999, long: -118.029596, radius: 8, //8 meters radius coarseness: 4, //looking for buckets with width of 4 meters expectedKeys: map[uint64]bool{ 0x2C782903B1D80000: true, 0x2C782903B1DC0000: true, 0x2C782903B4A00000: true, 0x2C782903B4A80000: true, 0x2C782903B1EC0000: true, 0x2C782903B1F00000: true, 0x2C782903B1F40000: true, 0x2C782903B3540000: true, 0x2C782903B6000000: true, 0x2C782903B1CC0000: true, 0x2C782903B1E40000: true, 0x2C782903B1FC0000: true, 0x2C782903B3440000: true, 0x2C782903B4880000: true, 0x2C782903B1F80000: true, 0x2C782903B3500000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B1D00000: true, 0x2C782903B1DC8000: true, 0x2C782903B4000000: true, 0x2C782903B4080000: true, 0x2C782903B00C0000: true, 0x2C782903B4800000: true, 0x2C78290000000000: true, }, }, "lapalma_2": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 8, expectedKeys: map[uint64]bool{ 0x2C782903B1C00000: true, 0x2C782903B1D00000: true, 0x2C782903B4800000: true, 0x2C782903B1E00000: true, 0x2C782903B1F00000: true, 0x2C782903B4A00000: true, 0x2C782903B3400000: true, 0x2C782903B3500000: true, 0x2C782903B6000000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B3440000: true, 0x2C782903B4880000: true, 0x2C782903B1F80000: true, 0x2C78290000000000: true, 0x2C782903B3000000: true, }, }, "lapalma_3": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 32, expectedKeys: map[uint64]bool{ 0x2C782903B1000000: true, 0x2C782903B4000000: true, 0x2C782903B3000000: true, 0x2C782903B6000000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B3400000: true, 0x2C782903B3500000: true, 0x2C782903B0000000: true, 0x2C78290000000000: true, }, }, "lapalma_4": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 128, //looking for 128m width nodes expectedKeys: map[uint64]bool{ 0x2C782903B0000000: true, //corresponds to 023013200221000323, ~127m width node }, absentKeys: map[uint64]bool{ 0x2C78000000000000: true, 0x2C782903B4000000: true, 0x2C782903B3000000: true, 0x2C78290000000000: true, }, }, "lapalma_5": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 100000, //looking for 100km width nodes expectedKeys: map[uint64]bool{ 0x2C78000000000000: true, //corresponds to 02301320, ~130km width node }, absentKeys: map[uint64]bool{ 0x2C782903B0000000: true, 0x2C782903B1F00000: true, 0x2C782903B4A00000: true, 0x2C78290000000000: true, }, expectedBuckets: map[uint64]quadkey.QuadkeyBucket{ 0x2C78000000000000: { 0x2C78000000000000, 7, 0x2C78000000000000, 0x2C78FFFFFFFFFFFF, }, }, }, } for tname, tt := range tests { t.Run(tname, func(t *testing.T) { buckets := quadkey.QuadkeySearchBuckets(tt.lat, tt.long, tt.radius, tt.coarseness) assert.Equal(t, len(tt.expectedKeys), len(buckets)) for key := range buckets { assert.Contains(t, tt.expectedKeys, key) } for key, bucket := range tt.expectedBuckets { assert.Contains(t, buckets, key) actualBucket, ok := buckets[key] if !ok { continue } assert.Equal(t, bucket.Quadkey, actualBucket.Quadkey) assert.Equal(t, bucket.Depth, actualBucket.Depth) assert.Equal(t, bucket.Start, actualBucket.Start) assert.Equal(t, bucket.End, actualBucket.End) } for key := range tt.absentKeys { assert.NotContains(t, buckets, key) } }) } } func TestQuadkeyGridBuckets(t *testing.T) { tests := map[string]struct { lat float64 long float64 radius float64 coarseness float64 expectedKeys map[uint64]bool absentKeys map[uint64]bool //set of keys that should not show up }{ "invalid": { lat: -2000.0, long: -2000.0, radius: 100.0, //100m coarseness: 600000.0, // 600km expectedKeys: map[uint64]bool{ 0x0000000000000000: true, //clamped lat long. 90, -180 0xAAA0000000000000: true, //clamped lat long -90, -180 0xFFF0000000000000: true, //clamped lat long, -90, +180 0x5550000000000000: true, //clamped lat long, +90, +180 }, }, "null": { lat: 0.0, long: 0.0, radius: 100.0, //1km coarseness: 600000.0, // 600km expectedKeys: map[uint64]bool{ 0x3FF0000000000000: true, //033333 0xC000000000000000: true, //300000 0x6AA0000000000000: true, //122222 0x9550000000000000: true, //211111 }, }, "london": { lat: 51.507822, long: -0.162069, radius: 8, //8 meters radius coarseness: 8, expectedKeys: map[uint64]bool{ 0x37775C0435400000: true, //0313131311300010031110 0x37775C0435500000: true, //0313131311300010031111 0x37775C0460000000: true, //0313131311300010120000 0x37775C0435600000: true, //0313131311300010031112 0x37775C0435700000: true, //0313131311300010031113 0x37775C0460200000: true, //0313131311300010120002 0x37775C0435C00000: true, //0313131311300010031130 0x37775C0435D00000: true, //0313131311300010031131 0x37775C0460800000: true, //0313131311300010120020 }, absentKeys: map[uint64]bool{ 0x2C782903B1D00000: true, 0x2C782903B1DC8000: true, 0x2C782903B4000000: true, 0x2C782903B4080000: true, 0x2C782903B00C0000: true, 0x2C782903B4800000: true, 0x2C78290000000000: true, }, }, //lapalma test cases use quadkeys from visually inspecting mapbox maps "lapalma": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 4, expectedKeys: map[uint64]bool{ 0x2C782903B1D80000: true, 0x2C782903B1DC0000: true, 0x2C782903B4A00000: true, 0x2C782903B4A80000: true, 0x2C782903B1EC0000: true, 0x2C782903B1F00000: true, 0x2C782903B1F40000: true, 0x2C782903B3540000: true, 0x2C782903B6000000: true, 0x2C782903B1CC0000: true, 0x2C782903B1E40000: true, 0x2C782903B1FC0000: true, 0x2C782903B3440000: true, 0x2C782903B4880000: true, 0x2C782903B1F80000: true, 0x2C782903B3500000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B3400000: true, 0x2C782903B1000000: true, 0x2C782903B0000000: true, 0x2C78290000000000: true, }, }, "lapalma_2": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 8, expectedKeys: map[uint64]bool{ 0x2C782903B1C00000: true, 0x2C782903B1D00000: true, 0x2C782903B4800000: true, 0x2C782903B1E00000: true, 0x2C782903B1F00000: true, 0x2C782903B4A00000: true, 0x2C782903B3400000: true, 0x2C782903B3500000: true, 0x2C782903B6000000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B1000000: true, 0x2C782903B0000000: true, 0x2C78290000000000: true, 0x2c782903B4000000: true, }, }, "lapalma_3": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 32, expectedKeys: map[uint64]bool{ 0x2C782903B1000000: true, 0x2c782903B3000000: true, 0x2c782903B4000000: true, 0x2c782903B6000000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B1F00000: true, 0x2C782903B4A00000: true, 0x2C782903B0000000: true, 0x2C78290000000000: true, }, }, "lapalma_4": { lat: 33.86219399999999, long: -118.029596, radius: 8, coarseness: 128, expectedKeys: map[uint64]bool{ 0x2C782903B0000000: true, }, absentKeys: map[uint64]bool{ 0x2C782903B1000000: true, 0x2C782903B1D00000: true, 0x2C782903B4800000: true, 0x2C782903B1CC0000: true, 0x2C782903B1E40000: true, 0x2C78290000000000: true, }, }, } for tname, tt := range tests { t.Run(tname, func(t *testing.T) { fmt.Println(tname) buckets := quadkey.QuadkeyGridBuckets(tt.lat, tt.long, tt.radius, tt.coarseness) assert.Equal(t, len(tt.expectedKeys), len(buckets)) for key := range buckets { assert.Contains(t, tt.expectedKeys, key) } for key := range tt.absentKeys { assert.NotContains(t, buckets, key) } }) } }