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
|
# File 'lib/nswtopo/tiled_web_map.rb', line 5
def tiled_web_map(temp_dir, extension:, zoom: [DEFAULT_ZOOM], **options, &block)
web_mercator_bounds = @cutline.reproject_to(Projection.new("EPSG:3857")).bounds
wgs84_bounds = @cutline.reproject_to_wgs84.bounds
png_path = nil
max_zoom, min_zoom = *zoom.sort.reverse
max_zoom.downto(0).map do |zoom|
indices, ts = web_mercator_bounds.map do |lower, upper|
(2**zoom * (lower + HALF) / HALF / 2).floor ... (2**zoom * (upper + HALF) / HALF / 2).ceil
end.map do |indices|
[indices, indices.size * TILE_SIZE]
end.transpose
te = [*indices.map(&:begin), *indices.map(&:end)].map do |index|
index * 2 * HALF / 2**zoom - HALF
end
resolution = 2 * HALF / TILE_SIZE / 2**zoom
tif_path = temp_dir / "tile.#{zoom}.tif"
OpenStruct.new resolution: resolution, ts: ts, te: te, tif_path: tif_path, indices: indices, zoom: zoom
end.select do |level|
next true if level.zoom == max_zoom
next level.zoom >= min_zoom if min_zoom
!level.indices.all?(&:one?)
end.tap do |max_level, *|
png_path = yield(resolution: max_level.resolution)
end.tap do |levels|
log_update "#{extension}: creating zoom levels %s" % levels.map(&:zoom).minmax.uniq.join(?-)
end.inject(ThreadPool.new, &:<<).each do |level|
OS.gdalwarp "-t_srs", "EPSG:3857", "-ts", *level.ts, "-te", *level.te, "-r", "cubic", "-dstalpha", png_path, level.tif_path
end.flat_map do |level|
cols, rows = level.indices
[cols.each, rows.reverse_each].map(&:with_index).map(&:entries).inject(&:product).map do |(col, j), (row, i)|
row ^= 2**level.zoom - 1 if extension == "gemf"
path = temp_dir / "tile.#{level.zoom}.#{col}.#{row}.png"
args = ["-srcwin", j * TILE_SIZE, i * TILE_SIZE, TILE_SIZE, TILE_SIZE, level.tif_path, path]
OpenStruct.new zoom: level.zoom, row: row, col: col, path: path, args: args
end
end.tap do |tiles|
log_update "#{extension}: creating %i tiles" % tiles.length
end.inject(ThreadPool.new, &:<<).each do |tile|
OS.gdal_translate *tile.args
end.entries.tap do |tiles|
log_update "#{extension}: optimising %i tiles" % tiles.length
tiles.map(&:path).inject(ThreadPool.new, &:<<).in_groups do |*paths|
dither *paths
rescue Dither::Missing
end
end
end
|