BitmapMaps doc

Change the time of day

  1. What we'll do
  2. Find the function to customize
  3. Make an alternative function
  4. Update the map with the selected angle
  5. Targets for a better map

What we'll do

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.

The sun azimuth angle is not one of the parameters easily editable with BitmapMaps.ini. I suggest you first try editing other parameters in the .ini file or changing text in the .csv files. You would also need to delete the affected files before calling 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.

Find the function to customize

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

Make an alternative function

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.

Update the map with the selected angle

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: Sun azimuth 156° cropped

Targets for a better map

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:

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.

Previous page Next page

[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.
CC BY-SA 4.0 hustf. Last modified: April 18, 2025. Website built with Franklin.jl and the Julia programming language.