Python Scripting [3A]: Layer Fractional Segments for NZ Rail Maps 1

This is a technical description of the scripting project which is for dividing a large layer into segments for NZ Rail Maps. As discussed in some previous posts I am taking for example a 0.4 metre resolution tile and scaling it to 0.1 metre resolution making it 16 times the area of the original. Then because Qgis is difficult to use with tiles of this size I am cutting it into 16 segments with a suffix added to describe where they fit in a row-column grid on the original layer. Making up these grids and images in Gimp is relatively simple, the hard part is working out the coordinates of where to position each new tile segment in Qgis which I am doing by a calculation based on existing layer data.

The project is to carry out the following

  1. The script is to read in the following arguments passed on the command line:
    1. The base layer name (the original layer that has been divided into segments)
    2. The layer name to the immediate right (or left) – first version will only use right
    3. The layer name immediately below (or above) – first version will only use below
    4. The divisor (how many segments across or down the base layer is divided into)
    5. The pixel size of each segment in metres.
  2. The script carries out the following steps:
    1. Using the base layer name find the .jgw file for the base layer.
    2. From the base layer read the 5th and 6th lines which are respectively the x and y coordinates of the top left corner of the base layer.
    3. Repeat these steps for the layer to the right and the layer to the bottom.
    4. Calculate the coordinates for each segment using the formulas worked out in the spreadsheet.
    5. Work out which layers need .jgw files produced for them.
    6. Create and write the .jgw files for these layers – 6 lines of text data in each file.

I am making this a top priority for NZ Rail Maps at the moment because I have about 10 new tiles to work out, each of which has multiple segments to generate, and doing this for each one individually is very tedious and error prone because of all the manual steps needed.

The first requirement is to work out how to collect command line arguments. Python provides a library called argparse which can be used to interpret the command line. By looking at that I would probably set up the command line arguments as follows:
  • -b | –base  : base layer name (excluding the extension that will be automatically added)
  • -r | –right : right most layer name
  • -d | –down : lower most layer name
  • -c | –count : counter (divisor)
  • -p | –pixelsize : pixel size
argparse does all the dirty work for us in grabbing the arguments and letting us know if any are missing. These ones are generally mandatory so if any of them are omitted the intention is the script will complain. However I decided to make only the first three mandatory to be passed in and put in default values for the other two making them optional.
Our development editor is KDevelop which is part of KDE. We can write the script in the editor with the advantage of full syntax parsing, and run it in a bash shell using the python command.
So this first step is about as far as I expect to get with this today. I have written the following code into KDevelop as follows:
import argparse
parser = argparse.ArgumentParser(prog=’segments’)
parser.add_argument(‘-b’, ‘–base’, required = True)
parser.add_argument(‘-r’, ‘–right’
, required = True)
parser.add_argument(‘-d’, ‘–down’
, required = True)
parser.add_argument(‘-c’, ‘–counter’
, type=int, default=4)
parser.add_argument(‘-p’, ‘–pixelsize’
, type=float, default=0.1)
args = parser.parse_args()
The required=True bit on each add_argument statement makes sure the switches are mandatory.
Running that script ( and passing -h as the only parameter returns the help text that looks like this:
usage: segments [-h] -b BASE -r RIGHT -d DOWN [-c COUNTER] [-p PIXELSIZE]
optional arguments:
-h, –help                  show this help message and exit
-b BASE, –base BASE
-r RIGHT, –right RIGHT
-d DOWN, –down DOWN
-c COUNTER, –counter COUNTER
So all of that help text is generated automatically by argparse. The name of the variable that the argument gets stored in is parsed automatically (a default action) by add_argument  from the positional parameters passed into it. In the format I have called add_argument as above, it will look for the long form switch (with — in front of it) and use that, if there is no — it will look for the short form switch with – in front of it and use that. However you can actually explicitly define this by passing dest= as a parameter to add_argument.
If you fail to pass any of the mandatory parameters it will stop with a message flagging the missing parameter, but only the first missing one will actually be flagged. Essentially it prints out the usage: line as shown above, stating what arguments need to be provided. The default variable type is string, but as you can see there are two add_argument calls that provide type= parameters, which define the variable type as both of these variables are numeric values (one is integer and the other is real). For both of these I have omitted the required parameter and substituted a default value, so those two are optional.
Anyway that is the first bit completed. Having collected arguments the next step is to use them. So part 2 is going to cover the steps of finding and reading the contents of the three files that are referred to in the first three arguments.