The default in BitmapMaps is using a 'relief shading' technique with the sun coming from South-South-West, while the traditional approach is to use light from the North-West. For people who are used to reading relief-shaded maps, light from the North-West would make the mountains pop out more easily. Light not from North-West might even cause some to see 'landscape inversion'. We don't believe that convention is particularly strong in Norway, where so many are used to reading topographic lines.
Reading contour lines also takes practice. Together with a familiarly spaced grid, experienced readers can see absolute steepness so as to decide on path choices. This requires a familiar grid and familiar vertical distances between topographic lines.
run_bitmapmap_pipeline()
. So if you modify topographic lines, at least delete or edit 'Toporelief.png'.We will change the hard-coded light direction now. It's easy when you know how, and the method can be used to do other customizations.
From the README file, we know that the relief is made in a function called topo_relief
. You could type
using BitmapMaps
smb = define_builder();
sb = smb[1, 1]
@edit topo_relief(sb)
This would open an editor with the function from the module BitmapMaps [1]. This is the original:
function topo_relief(sb::SheetBuilder)
# This function determines the color of the light source for a cell (a pixel in a raster)
# The color varies with elevation above sea and light source number
f_hypso = func_directional_pallette()
# This function determines how much of that color is reflected, given light source number,
# the surface normal vector and elevation above sea
f_reflect = func_reflection_coefficient()
#
topo_relief(full_folder_path(sb), sb.cell_iter, cell_to_utm_factor(sb), f_hypso, f_reflect)
end
There's no need to modify the BitmapMaps module; we'll make a modified my_topo_relief
in the current Main module instead. It's going to call functions from BitmapMaps, so we load those functions into Main:
using BitmapMaps: func_directional_pallette, func_reflection_coefficient
using BitmapMaps: topo_relief, cell_to_utm_factor, full_folder_path, TOPORELIEF_FNAM
Let's define my_topo_relief
, but with additional keyword arguments:
function my_topo_relief(sb::SheetBuilder;
sun_deg::Int = 156,
fna = "Toporelief_" * lpad(string(sun_deg), 3, '0') * "°.png")
#
# The name of the (already created) image file
ffna_source = joinpath(full_folder_path(sb), TOPORELIEF_FNAM)
# We must delete the old file, or `topo_relief` file will simply exit early so
# as to re-use previous work
if isfile(ffna_source)
rm(ffna_source; force=true)
end
# These are function closures.
f_hypso = func_directional_pallette()
f_reflect = func_reflection_coefficient(; sun_deg) # Conveniently, that keyword exists...
# Do the rendering, but now with our small modification
topo_relief(full_folder_path(sb), sb.cell_iter, cell_to_utm_factor(sb), f_hypso, f_reflect)
# We take a copy of `toporelief.png`, and change the name
@show fna
ffna_dest = joinpath(full_folder_path(sb), fna)
cp(ffna_source, ffna_dest; force = true)
end
...and render a bunch of sun angles:
for sun_deg in 0:4:359
my_topo_relief(sb; sun_deg)
end;
# Cleanup: restore the original `Toporelief.png`:
rm(joinpath(full_folder_path(sb), TOPORELIEF_FNAM))
topo_relief(sb);
From studying the image files, we prefer a sun azimuth angle of 156°. We did not change the elevation, 9° above horizon. A solar calculator tells us the sun shines from there at 10:30 AM on each 15th of February.
Let's add the other layers and have a look:
# We have only one sheet in our SheetMatrixBuilder. Still,
# looping over all sheets is a good habit.
for sb in smb
# Decide on this variant
my_topo_relief(sb; sun_deg = 156)
end
# Rerun the pipeline to composite this layer under lakes, ridges etc.
run_bitmapmap_pipeline()
A cropped version:
The above doesn't do the mountain justice. Although photo-realism is pointless for people not used to the satelite point-of-view, we should be able to make the mountain more recognizable.
Some goals for a nice map may be:
presents the mountain in a recognizable way
gives the impression of a photo at a cursory glance
includes enough artificial detail for making rough route choices
shows ridge lines not discernable from horizontal contour lines
makes you want to go there
The unrealistic snow cover is the most obvious fix here. Much of the mountain is too steep for snow to stick. We'll try and remedy that in the next section.
[1] | The function is loaded in your Main module because it is one of the exported functions. List the exported functions by typing varinfo(BitmapMaps) . Other functions must be loaded with: using BitmapMaps: funcname . |