-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtileset.go
141 lines (129 loc) · 3.32 KB
/
tileset.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package main
import (
"fmt"
"sort"
"strconv"
"strings"
)
type TilesetDescriptor struct {
MaxZ int
MinZ int
Backend StorageBackend
Tiles map[int][]TileDescriptor // <zoom, []tiles> mapping
}
func (t TilesetDescriptor) GetTiles() []TileDescriptor {
// Copy and sort keys of map
keys := make([]int, len(t.Tiles))
i := 0
for k := range t.Tiles {
keys[i] = k
i += 1
}
sort.Ints(keys)
// Extract all tiles to a sorted slice
var result []TileDescriptor
for _, k := range keys {
tileset := t.Tiles[k]
for _, s := range tileset {
result = append(result, s)
}
}
return result
}
func (t TilesetDescriptor) String() string {
return fmt.Sprintf("%d-%d", t.MaxZ, t.MinZ)
}
func discoverTilesets(paths []string, target TilesetDescriptor, bestEffort bool, timeout int) ([]TilesetDescriptor, []error) {
var tilesets []TilesetDescriptor
var errors []error
for _, path := range paths {
backend, err := stringToBackend(path, true, timeout)
if err != nil {
errors = append(errors, err)
continue
}
tileset, err := discoverTileset(backend, target.MinZ, target.MaxZ)
if err != nil {
errors = append(errors, fmt.Errorf("could not discover tileset: %v in %s", err, path))
continue
}
if len(tilesets) > 0 && (target.MaxZ != tileset.MaxZ || target.MinZ != tileset.MinZ) {
errors = append(errors, fmt.Errorf("zoom level mismatch for target and source %s", path))
if !bestEffort {
continue
}
}
tilesets = append(tilesets, tileset)
}
return tilesets, errors
}
func discoverTileset(backend StorageBackend, minZ int, maxZ int) (TilesetDescriptor, error) {
files, err := backend.GetFilesRecursive("")
if err != nil {
return TilesetDescriptor{}, err
}
result := TilesetDescriptor{
MinZ: minZ,
MaxZ: maxZ,
Backend: backend,
}
err = buildTilesetStructure(files, &result)
if err != nil {
return TilesetDescriptor{}, fmt.Errorf("invalid or empty tileset: %w", err)
}
return result, nil
}
// Assumes the passed list of files is already sorted alphabetically.
// Returns the respective Z/X/Y.png structure.
func buildTilesetStructure(files []string, tileset *TilesetDescriptor) error {
var currentZoomLevel string
var tiles []TileDescriptor
tileset.Tiles = map[int][]TileDescriptor{}
for _, f := range files {
pathParts := strings.Split(f, "/")
if len(pathParts) != 3 {
return fmt.Errorf("invalid file path %s, expected format {z}/{x}/{y}.<ext>", f)
}
z := pathParts[0]
zNum, err := strconv.Atoi(z)
if err != nil {
return err
}
x := pathParts[1]
xNum, _ := strconv.Atoi(x)
if err != nil {
return err
}
y := pathParts[2]
// Get format
fileParts := strings.Split(y, ".")
if len(fileParts) != 2 {
return fmt.Errorf("invalid file path %s, expected format {z}/{x}/{y}.<ext>", f)
}
yNum, _ := strconv.Atoi(fileParts[0])
if err != nil {
return err
}
format := fileParts[1]
// Check zoom level
if z != currentZoomLevel {
// New zoom level
if zNum < tileset.MinZ || (tileset.MaxZ > 0 && zNum > tileset.MaxZ) {
// Filter out file based on specified zoom level boundaries
continue
}
currentZoomLevel = z
tiles = []TileDescriptor{}
}
// Add Z/X/Y (file)
tiles = append(tiles, TileDescriptor{
X: xNum,
Y: yNum,
Z: zNum,
Format: format,
TileSet: tileset,
})
tileset.Tiles[zNum] = tiles
}
return nil
}