FE 'tkGooies'

'MAPtools' group

Tk GUI script
'tkMakePNGmapFromOSMtiles_
aroundLatLon_
OneZoomLevel_
NxMtiles'

(A script to make a map in a PNG file --
from OSM tiles around a specified latitude-longitude
-- at One OSM 'zoom level' --- using NxM OSM tiles.)
(OSM = Open Street Map)
(FE = Freedom Environment)

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'MAPtools' Page >

This
'tkMakePNGmapFromOSMtiles_
aroundLatLon_ OneZoomLevel_ NxMtiles'
Code Page

INTRODUCTION to Tcl-Tk script
'tkMakePNGmapFromOSMtiles_ aroundLatLon_ OneZoomLevel_ NxMtiles'

For several years (circa 2014-2016), I had been planning to make various 'map making' Tk GUI's that make

  • 'vector' (outline) maps
    (drawn with line-segments)

    and

  • image-pixels maps
    (assembled from image 'tiles').

And, eventually, I intend to provide additional map utility GUI's that allow for reading a 'marker-locations' file and then apply markers (and text notes) to a previously created map image (vector-map or tiles-map).

On the page

'tkReadOutlineFile_ drawOutlineOnCanvas',

I presented my first map-making 'tkGooie' script --- to make 'vector' maps from outline-data files of a very simple format.

Each line of the 'outline' input file contains x,y coordinates (which may be a longitude-latitude pair, in decimal degrees).

Soon after making that outline-map-drawing 'tkGooie', I made a

'tkFetchOSMtiles_ atLatLon_ oneTileAtVariousZoomLevels'

Tk GUI script, which was meant to be an aid to a PNG-file map-maker 'tkGooie' script --- to help determine the 'zoom-level' to use for the tiles.

This 'tkGooie' page is intended to present that 'tkGooie' script --- that maker of PNG-file maps --- maps which are composed of NxM columns and rows of OSM 256x256-pixel image 'tiles'.

On the

'tkFetchOSMtiles_ atLatLon_ oneTileAtVariousZoomLevels',

page, I pointed out that an OSM 'slippy map tiles' page, explains OSM 'zoom-levels', where OSM = Open Street Map.

I also pointed out on that 'tkGooie' page many of the properties of OSM 'tiles'.

See that page for many details --- in a 'Nature of the slippy tiles' section.

For this 'tkMakePNGmapFromOSMtiles' utility, the plan is/was to use the 'wget' command (on Linux) to retrieve tiles for triplets of integers 'zoom/x/y' --- where 'zoom' is an integer between 0 and 18 --- and 'x' and 'y' are determined based around a user-specified latitude and longitude (in decimal degrees).


Basic Goals of the Tk Script:

My purpose for this Tk GUI script is/was to accept

  • a latitude-longitude location (in decimal degrees) of a 'central' tile,

  • 4 integers to indicate number of tiles west, east, south, and north of a 'central' tile (say, integers N1, N2, M1, M2) , and

  • a zoom-level integer (between 0 and 18)

from the user.

For the specified zoom level (and for the specified latitude-longitude), the Tk script will use the OSM computation-method to determine the 'zoom/x/y' integers that specify the 'central' OSM tile.

Then the script will use the 'wget' command to fetch the 'central' tile and the tiles around it (where each tile is a 256x256 pixel PNG file) and join the rows and columns of tiles into a single PNG file.

The size of the PNG file will be

(N x 256) pixels by (M x 256) pixels

where

N = N1 + 1 + N2

and

M = M1 + 1 + M2

where the one (1) is representing the 'central' tile.

After the tiles are joined, the resulting joined PNG file is displayed in a user-specifiable image viewer.


PLANNED LAYOUT OF THE GUI:

As I have done with other Tk scripts that I have written in the past year or so, I laid out a 'text image' of the GUI --- to aid me as I coded the frames and widgets.

I used the following conventions to make the sketch, with a text editor.


  SQUARE-BRACKETS indicate a comment (not to be placed on the GUI).
  BRACES          indicate a Tk 'button' widget.
  A COLON         indicates that the text before the colon is on a 'label' widget.
  <---O--->       indicates a Tk 'scale' widget (if any).
  CAPITAL-X       indicates a Tk 'checkbutton' widget (if any).
  CAPITAL-O       indicates a Tk 'radiobutton' widget (if any).
  UNDERSCORES     indicate a Tk 'entry' widget (if any).

According to those conventions, I created the following 'text sketch'.


 FrameNames
 VVVVVVVVVV
             ------------------------------------------------------------------------------------
             Make a PNG-file MAP - from OSM Tiles (256x256 PNG files) - for a Latitude-Longitude & OSM Zoom-Level
             [window title]
             ------------------------------------------------------------------------------------
  
 .fRbuttons  {Exit} {Help} {GetLatLon} {MakePNGfileMAP}  ZoomLevel (0 to 18): -__+
  
 .fRlatlon   Central Tile Location in decimal degrees - Latitude: ___________ Longitude: __________

 .fRcols     Number of Columns of tiles - To Left: -__+  To Right: -__+  of a central tile.

 .fRrows     Number of Rows of tiles - Above: -___+  Below: -__+  a central tile.

 .fRmsg      [---------- a message line goes here in a label widget -------------------------]
  

From the diagram above, I could see that this GUI will contain about:

  • 4 LARGE button widgets
    plus 10 SMALL minus (-) and plus (+) buttons
    on either side of five small entry fields
    for integers (up to 2 digits each)
  • 10 label widgets
  • 7 entry widgets
  • 0 radiobutton widgets
  • 0 checkbutton widgets
  • 0 scale widgets
  • 0 listbox widgets
  • 0 canvas widgets
  • 0 text widgets

Assembling the pieces   (The GUI)

Now it was a matter of putting the pieces together.

I took 'code-pieces' from the

'tkFetchOSMtiles_ atLatLon_ oneTileAtVariousZoomLevels' script

--- which also used 'button' and 'label' and 'entry' widgets.

I ended up with the following GUI as an initial display, when the GUI is started up.

The message area (in red) indicates that the first step for the user is to choose a latitude and longitude to enter --- and a zoom-level to enter --- as well as the 4 integers referred to as N1, N2, M1, and M2.

For initial values in the entry fields of this GUI, I looked up the latitude,longitude location of the capital city of the island of Tenerife in the Canary Islands and found (via Wikipedia) that

'Santa Cruz de Tenerife'

is located at Latitude 28.466667, Longitude -16.25.

    (On the Wikipedia page, I clicked on the coordinates in degrees-minutes-seconds and was taken to a page that showed the latitude and longitude in decimal-degrees.)

To make a map of the entire island of Tenerife, I found (by some experimentation with values for N1, N2, M1, M2) that for a zoom-level of 12 and the latitude-longitude of the capital city, the integers 8, 1, 6, and 1 for N1 (left), N2 (right), M1 (below), and M2 (above) were appropriate.

Those integers are the initial values in those 4 entry fields when the GUI comes up --- along with zoom-level 12 and the latitude and longitude values for 'Santa Cruz de Tenerife'.

    You can change the initial latitude and longitude, the initial zoom level, and the initial four integers (N1, N2, M1, and M2) by editing the proc 'reset_parms' in this 'tkMakePNGmapFromOSMtiles' script.

I simply clicked on the 'Fetch' button and the following PNG file was created from N x M tiles that were fetched from an OSM server
---
where N = N1 + 1 + N2 = 8 + 1 + 1 = 10
and
where M = M1 + 1 + M2 = 6 + 1 + 1 = 8.

The size of the resulting joined PNG file was

(10 x 256) x (8 x 256) = 2560 x 2048 pixels.


Poke this image to see the 2560x2048 pixel image
in a separate browser window or tab.

Fetch-and-Join Processing

During the time that the tiles are being fetched and being joined into a single large PNG file, a 'FETCH-and-JOIN PROCESSING IS STARTING' message is shown in the red message area --- along with the number of tiles being fetched and an estimate of the number of seconds required for the fetch-and-join --- roughly 2 seconds per tile.

    (There is more on execution-time in a section below.)

If your internet connection is not 'up', you will get a reminder message in a popup window.

The joined PNG file is put in the file

/tmp/userid_FINAL_MAP.png

You can move the file to a 'permanent' directory if you plan to use it --- and rename the file there.

---

Note that you may go through quite a few runs with various values of N1,N2,M1,M2 (and zoom-level and latitude-longitude) before creating a joined PNG file that suits your needs.

    A section below indicates how you can change the directory location and filename for the output PNG file.

    But note that use of the '/tmp' directory is advantageous --- because, if you leave the various files used for the join operations in the '/tmp' directory, the files will all be automatically removed in a shutdown or reboot of a Linux machine.


Execution time:
(for the Tenerife island map)

It is gratifying that the fetch of the 256x256 pixel 'tile' files, using 'wget', proceeds very quickly --- about half a second per file (or less).

But more time-consuming, is the join process --- in which tiles are joined into row-images --- and then the row-images are joined into the final PNG file image.

The joins are done with the ImageMagick 'convert' program.

    (You can change the command used to perform the joins by changing the 'set CONVERTpgm' statement near the bottom of the Tk script.

    I probably should have used the variable name JOINpgm.)

The fetch-AND-join ('wget' and 'convert') processing takes, on average, roughly 1.5 to 2 seconds per tile.

Hence, for this Tenerife-island map consisting of about 8 rows and 10 columns of tiles (2560 x 2048 pixels in a large PNG file), the fetch-AND-join of the 10 x 8 = 80 tiles takes on the order of

80 x 1.5 ~ 120 seconds

roughly 2 minutes --- on my medium-powered desktop computer.


On the accuracy needed for
the latitude-longitude specification :

On the 'tkFetchOSMtiles_ atLatLon_ oneTileAtVariousZoomLevels' script page, it was pointed out how many decimal places you will need in your latitude-longitude specification to accurately 'pinpoint' a location of interest.

It was pointed out that, at the equator (zero degrees latitude):

  • 1.0 degree is roughly 100 kilometers

  • 0.1 degrees is about 10 kilometers

  • 0.01 degrees is about 1 kilometer

  • 0.001 degrees is about 100 meters
    (about a football/fusbol/soccer field)

  • 0.0001 degrees is about 10 meters
    (about the width of a house)

    A note on that 'tkGooie' script page and at the OSM 'slippy map' page indicates that at a latitude of 60 degrees, you would need to halve these distance values.

As a consequence of these considerations:

  • If you want to specify a city,
    you may need about 2 decimal places in the longitude and latitude degrees values.

  • If you want to specify a city neighborhood,
    you may need about 3 decimal places in the longitude and latitude degrees values.

  • If you want to specify a street address,
    you may need about 4 decimal places in the longitude and latitude degrees values.

So a specification of 28.4667 for the latitude of the capital city of Tenerife was actually more precise than was needed for a map of the island --- a value of 28.47 would have been sufficient.


On the image-viewer program :

The Tk script can use almost any GUI image viewer for the output PNG file.

    (You will find it best to use a 'light-weight', quick-starting viewer --- NOT like slow-starting GIMP.)

You can edit the script to change the 'set IMGviewer' command near the bottom of the Tk script, to use a different viewer.

I ended up using the 'mtpaint' image editor, after trying the 'eog' = 'Eye of Gnome' image viewer (a year-2009 version).

'mtpaint' is a 'light-weight' image editor that starts up quickly.


On the location and name of
the fetched OSM tile-files :

In addition to changing factors like the image-viewer program and the image-joiner command, one can edit the script to change the name of the directory to which the tile (PNG) files are fetched.

This Tk script is released with the 'target' directory set to '/tmp' in a 'set DIRtemp' statement near the bottom of the Tk script.

Edit that statement if you want to change the target directory.

The fetched-tile filenames are built in the form

$env(USER)_tile_zoom_x_y.png

where 'zoom' and 'x' and 'y' are integers that were calculated by the Tk script to fetch the several tiles.

The joined-into-rows filenames are built with filenames of the form

$env(USER)_row__y.png

where 'y' is a row-number.

The final (joined-rows) PNG filename is built in the form

$env(USER)_FINAL_MAP.png

If you do not like those names, you can simply edit the Tk script to change the filename format.

    The userid is put in the filenames in case the computer being used is in a multi-user environment.


DESCRIPTION OF THE CODE

Below, I provide the Tk script code for this
'tkMakePNGmapFromOSMtiles_aroundLatLon_ OneZoomLevel_ NxMtiles' 'app'.

I follow my usual 'canonical' structure for Tk code, for this Tk script:



  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.


This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This Tk coding structure makes it easy for me to find code sections --- while generating and testing this script, and when looking for code snippets to include in other scripts (code re-use).


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus Tk scripts, so far), I provide the four main 'pack' parameters

  • '-side'
  • '-anchor'
  • '-fill'
  • '-expand'

on all the 'pack' commands for the frames and widgets.

I think I have found a good setting of the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets of this GUI.

In particular ...

The latitude and longitude 'entry' widgets will expand/contract suitably when the GUI window size is changed --- and 'button' and 'label' widgets stay fixed in size and relative-location if the window size is changed.

If anyone wants to change the way the GUI configures itself as the main (top-level) window size is changed, they can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets --- to get the widget behavior that they want.

---

Additional experimentation with the GUI:

You could change the fonts used for the various GUI widgets.

For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'.

Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

Furthermore, there are variables used to set geometry parameters of widgets --- parameters such as border-widths and padding.

And you could change the '-relief' values for frames and widgets.

Feel free to experiment with those 'appearance' parameters as well.


Some features of the code

There are plenty of comments in the code to describe what most of the code-sections are doing.

See the top of the 'PROCS' section of the script for a list of the procs used in this Tk script.

See comments in the procs for details on the purpose of each proc and for details on the methods by which each proc was implemented.

Here is a quick overview of the procs --- to give an idea of the 'guts' of this utility:



  'get_lat_lon'              - called by the 'Sites-LatLon' button

  'z_lat_lon_TO_col_row'     - called by proc 'make_PNG_map'

  'make_PNG_map'             - called by the 'MakePNGfileMAP' button.

  'advise_user'              - called by the 'make_PNG_map' proc and in
                               the 'Additional GUI Initialization' section
                               at the bottom of the script.

  'zlevel_increment'         - called via the zoom-level '+' button
  'zlevel_decrement'         - called via the zoom-level '-' button

  'colsleft_increment'       - called via the cols-left '+' button
  'colsleft_decrement'       - called via the cols-left '-' button

  'colsright_increment'       - called via the cols-right '+' button
  'colsright_decrement'       - called via the cols-right '-' button

  'rowsvert1_increment'       - called via the rows-above '+' button
  'rowsvert1_decrement'       - called via the rows-above '-' button

  'rowsvert2_increment'       - called via the rows-below '+' button
  'rowsvert2_decrement'       - called via the rows-below '-' button

  'popup_msgVarWithScroll'   - called by the 'Help' button, to show $HELPtext var
                               and to popup warning messages from the 'make_PNG_map' proc.


A fervent hope

It is my hope that the copious comments in the code might help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments --- especially in the 'z_lat_lon_TO_col_row' and 'make_PNG_map' procs, and in most of the other procs --- the code might look much more cryptic.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to look for videos of TV 'news' (opinion?) organizations interviewing politicians and their 'surrogates' and their 'experts' --- and asking them questions, which are invariably answered (nowadays) starting with the word 'LOOK' --- even though they REALLY want us to 'LISTEN'.

    (Or are they trying to say 'Look at me, The Great.'?)

Potential Tclers:

When you get tired of looking at (and listening at) TV-interviews-with-politicians-and-the-like, try installing-using-changing-enhancing the following Tk GUI script.

To help out in making scripts like this, here is a page that provides sources of Tcl-Tk code snippets by providing links to various 'tkGooies' scripts that can make it relatively quick work to compose

  • widget definitions,
  • bind statements, and
  • procedure code.

And when you get to the testing-and-debugging phase in development of a script, here is a page that describes the wonderfulness of the 'wish' 'stack trace' facility, which can make the testing-and-debugging go relatively quickly and painlessly.


The Tk Script CODE

Here is a link to CODE for the Tk script<

'tkMakePNGmapFromOSMtiles_ aroundLatLon_ OneZoomLevel_ NxMtiles.tk'.

With your web browser, you can 'right-click' on this link --- and in the menu that pops up, select an item like 'Save Link Target As ...' --- to save this file to your local computer.

Then you can rename the file to remove the '.txt' suffix.

Make sure that you have execute permission set on the file --- in order to execute the script.

Some possible FUTURE ENHANCEMENTS

There are some enhancements that could be considered for this script, such as:

  1. Allow for specifying the image-viewer to use --- on the GUI :

    An entry field could be added to the GUI, to allow the user to enter a command-name --- to use an image viewer or editor of the user's choice --- and to allow for easily switching between different viewers.

    An initial default could be provided in the 'entry' field --- such as '/usr/bin/mtpaint'.

  2. Allow for specifying an output directory --- on the GUI :

    An entry field could be added to the GUI, to allow the user to enter a (fully-qualified) directory name to use for the fetched files --- with an initial default such as '/tmp'.

The bottom line here is that there are almost always enhancements that could be made to (or 'forks' that could be made from) a Tk GUI 'app' like this.

One advantage of this Tk script is that it is 'open' code --- available to anyone for enhancement.

So if you would like to take a different approach to implementing this script, you are welcome to take this code and build on it (or reconstruct it).


NOTE: (2018 May 24)
In some usage of this utility, it has come to my attention that it needs to be improved in at least two ways:

  • Allow for slowing down the retrieval of tiles from the OSM tile server (which may stop the downloads if it thinks it is being abused).

    A 'pause-seconds' entry field could be added to the GUI --- with an initial default of one or two seconds.

    The 'pause-seconds' would be used to wait that long between the calls to 'wget', to get another tile.

  • Make the retrieval of the tiles 'less hidden'.

    For example, provide a popup 'xterm' window to show messages from the fetching of tiles (by 'wget') --- and also show messages from the making of the PNG file (by 'convert'), which can take many seconds, in all.

These improvements are to be made in a future release. In addition . . .

To augment this PNG-map-making utility, I plan to make a separate 'tkGooie' utility that puts 'markers' on a map image, by reading a file of marker-location information, with associated information (such as a date and a note for each location).

The 'put-markers-on-image' utility will be a general utility that is both a tkGooie 'MAPtools' utility and an 'IMAGEtools' utility.

This utility will be able to put markers on any kind of image.

For example, it could put markers on a medical image (such as an X-ray or cat-scan image) or a photo image of a person's face or body.

OR, this utility could be used to mark 'crime hot-spots' on a city map.


IN CONCLUSION

As I have said on other code-donation pages on this site ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.

Bottom of a web page that
presents Code for
'tkMakePNGmapFromOSMtiles_ aroundLatLon_ OneZoomLevel_ NxMtiles'
--- a Tk script 'app'
in the FE 'tkGooies' system,
in the 'MAPtools' group.

To return to a previously visited web page location, click on the Back button of your web browser a sufficient number of times. OR, use the History-list option of your web browser.
OR ...

< Go to Top of Page, above. >

Page history:

This FE web page was created 2016 Dec 01.

Page was changed 2018 May 24.
(Added the 2018may24 NOTE.)

Page was changed 2019 Feb 22.
(Added css and javascript to try to handle text-size for smartphones, esp. in portrait orientation.)

Page was changed 2019 Jun 27.
(Specified image widths in percents to size the images according to width of the browser window.)


NOTE:
This code may someday be posted in a page on the Tcler's Wiki --- wiki.tcl-lang.org --- formerly wiki.tcl.tk. If I do that, I intend to put a link to the page here.