diff --git a/src/3d-map.jl b/src/3d-map.jl index 8ecb56fb..4fc3b2c0 100644 --- a/src/3d-map.jl +++ b/src/3d-map.jl @@ -112,46 +112,10 @@ function frustrum_plane_intersection(cam::Camera, camc::Camera3D) end end - function to_rect(extent::Extent) - return Rect2f(extent.X[1], extent.Y[1], extent.X[2] - extent.X[1], extent.Y[2] - extent.Y[1]) -end - -function optimal_zoom(m::Map, diagonal) - diagonal_res = norm(get_resolution(m)) * 0.7 - zoomrange = min_zoom(m):max_zoom(m) - optimal_zoom(m.crs, diagonal, diagonal_res, zoomrange, m.zoom[]) + return Rect2(extent.X[1], extent.Y[1], extent.X[2] - extent.X[1], extent.Y[2] - extent.Y[1]) end -function optimal_zoom(crs, diagonal, diagonal_resolution, zoom_range, old_zoom) - # Some provider only support one zoom level - length(zoom_range) == 1 && return zoom_range[1] - # TODO, this should come from provider - tile_diag_res = norm((255,255)) - target_ntiles = diagonal_resolution / tile_diag_res - canditates_dict = Dict{Int, Float64}() - candidates = @NamedTuple{z::Int, ntiles::Float64}[] - for z in zoom_range - ext = Extents.extent(Tile(0, 0, z), crs) - mini, maxi = Point2.(ext.X, ext.Y) - diag = norm(maxi .- mini) - ntiles = diagonal / diag - canditates_dict[z] = ntiles - push!(candidates, (; z, ntiles)) - end - if haskey(canditates_dict, old_zoom) # for the first invokation, old_zoom is 0, which is not a candidate - old_ntiles = canditates_dict[old_zoom] - # If the old zoom level is close to the target number of tiles, return it - # to change the zoom level less often - if old_ntiles > (target_ntiles - 1) && old_ntiles < (target_ntiles + 1) - return old_zoom - end - end - dist, idx = findmin(x -> abs(x.ntiles - target_ntiles), candidates) - return candidates[idx].z -end - - function tiles_from_poly(m::Map, points) mini = minimum(points) points_s = sort(points, by=(x -> norm(x .- mini))) diff --git a/src/map.jl b/src/map.jl index ca3f3086..acb98e3b 100644 --- a/src/map.jl +++ b/src/map.jl @@ -28,7 +28,7 @@ When layering providers over each other with `Map(map::Map; ...)`, you can use ` -`cache_size_gb`: limits the cache for storing tiles, with a default of `5`. -`fetching_scheme=Halo2DTiling()`: The tile fetching scheme. Can be SimpleTiling(), Halo2DTiling(), or Tiling3D(). -`scale`: a tile scaling factor. Low number decrease the downloads but reduce the resolution. - The default is `1.0`. + The default is `0.5`. -`plot_config`: A `PlotConfig` object to change the way tiles are plotted. -`max_zoom`: The maximum zoom level to display, with a default of `TileProviders.max_zoom(provider)`. -`max_plots=400:` The maximum number of plots to keep displayed at the same time. @@ -55,6 +55,7 @@ struct Map{Ax<:Makie.AbstractAxis} <: AbstractMap fetching_scheme::FetchingScheme max_zoom::Int max_plots::Int + scale::Float64 end setup_axis!(::Makie.AbstractAxis, ext_target, crs) = nothing @@ -121,7 +122,8 @@ function Map(extent, extent_crs=wgs84; max_parallel_downloads=min(1, Threads.nthreads(:default) รท 3), fetching_scheme=Halo2DTiling(), max_zoom=TileProviders.max_zoom(provider), - max_plots=400) + max_plots=400, + scale=0.5) # Extent # if extent input is a HyperRectangle then convert to type Extent @@ -152,7 +154,7 @@ function Map(extent, extent_crs=wgs84; should_be_plotted, display_task, crs, Observable(1), - fetching_scheme, max_zoom, max_plots + fetching_scheme, max_zoom, max_plots, Float64(scale) ) map.zoom[] = 0 @@ -194,7 +196,8 @@ function Base.wait(map::AbstractMap) screen = Makie.getscreen(map.figure.scene) isnothing(screen) && error("No screen after display. Wrong backend? Only WGLMakie and GLMakie are supported.") - return wait(map.tiles) + wait(map.tiles) + return map end function tile_reloader(map::Map{Axis}) diff --git a/src/provider/interpolations.jl b/src/provider/interpolations.jl index b60bee58..6d07c47d 100644 --- a/src/provider/interpolations.jl +++ b/src/provider/interpolations.jl @@ -18,6 +18,9 @@ end Interpolator(f; colormap=:thermal, options=Dict(:minzoom=>1, :maxzoom=>19)) = Interpolator(f, Makie.to_colormap(colormap), options) +function TileProviders.geturl(::Interpolator, x::Integer, y::Integer, z::Integer) + return "$x,$y,$z" +end get_downloader(::Interpolator) = NoDownload() diff --git a/src/tile-fetching.jl b/src/tile-fetching.jl index da3a56ea..a564496d 100644 --- a/src/tile-fetching.jl +++ b/src/tile-fetching.jl @@ -55,7 +55,7 @@ function get_tiles_for_area(m::Map{Axis}, scheme::Halo2DTiling, area::Union{Rect depth = scheme.depth # Calculate the zoom level - zoom = calculate_optimal_zoom(m, area) + zoom = optimal_zoom(m, norm(widths(to_rect(area)))) m.zoom[] = zoom # And the z layers we will plot @@ -137,22 +137,6 @@ function get_resolution(map::Map) return isnothing(screen) ? size(map.axis.scene) .* 1.5 : size(screen) end -function calculate_optimal_zoom(map::Map, area) - screen = Makie.getscreen(map.axis.scene) - res = isnothing(screen) ? size(map.axis.scene) : size(screen) - return clamp(z_index(area, res, map.crs), min_zoom(map), max_zoom(map)) -end - -function z_index(extent::Union{Rect,Extent}, res::Tuple, crs) - # Calculate the number of tiles at each z and get the one - # closest to the resolution `res` - target_ntiles = prod(map(r -> r / 256, res)) - tiles_at_z = map(1:24) do z - length(TileGrid(extent, z, crs)) - end - return findmin(x -> abs(x - target_ntiles), tiles_at_z)[2] -end - function grow_extent(area::Union{Rect,Extent}, factor) Extent(map(Extents.bounds(area)) do axis_bounds span = axis_bounds[2] - axis_bounds[1] @@ -160,3 +144,37 @@ function grow_extent(area::Union{Rect,Extent}, factor) return (axis_bounds[1] - pad, axis_bounds[2] + pad) end) end + +function optimal_zoom(m::Map, diagonal) + diagonal_res = norm(get_resolution(m)) * m.scale + zoomrange = min_zoom(m):max_zoom(m) + optimal_zoom(m.crs, diagonal, diagonal_res, zoomrange, m.zoom[]) +end + +function optimal_zoom(crs, diagonal, diagonal_resolution, zoom_range, old_zoom) + # Some provider only support one zoom level + length(zoom_range) == 1 && return zoom_range[1] + # TODO, this should come from provider + tile_diag_res = norm((255, 255)) + target_ntiles = diagonal_resolution / tile_diag_res + canditates_dict = Dict{Int,Float64}() + candidates = @NamedTuple{z::Int, ntiles::Float64}[] + for z in zoom_range + ext = Extents.extent(Tile(0, 0, z), crs) + mini, maxi = Point2.(ext.X, ext.Y) + diag = norm(maxi .- mini) + ntiles = diagonal / diag + canditates_dict[z] = ntiles + push!(candidates, (; z, ntiles)) + end + if haskey(canditates_dict, old_zoom) # for the first invokation, old_zoom is 0, which is not a candidate + old_ntiles = canditates_dict[old_zoom] + # If the old zoom level is close to the target number of tiles, return it + # to change the zoom level less often + if old_ntiles > (target_ntiles - 1) && old_ntiles < (target_ntiles + 1) + return old_zoom + end + end + dist, idx = findmin(x -> abs(x.ntiles - target_ntiles), candidates) + return candidates[idx].z +end