diff --git a/scripts/tile/tile_index.py b/scripts/tile/tile_index.py index b67ef199..6b70e1ec 100644 --- a/scripts/tile/tile_index.py +++ b/scripts/tile/tile_index.py @@ -1,16 +1,21 @@ from typing import NamedTuple, Union -SHEET_WIDTH = 24_000 # The width of a 1:50k sheet in metres -SHEET_HEIGHT = 36_000 # The height of a 1:50k sheet in metres -SHEET_ORIGIN_LEFT = 988_000 # The NZTM x coordinate of the left edge of 1:50k sheet which would be at column position 00 -SHEET_ORIGIN_TOP = 6_234_000 # The NZTM y coordinate of the top edge of sheets in row AS (the northernmost row) -SHEET_MIN_X = SHEET_ORIGIN_LEFT + (4 * SHEET_WIDTH) # The minimum x coordinate of a valid sheet / tile -SHEET_MAX_X = SHEET_ORIGIN_LEFT + (46 * SHEET_WIDTH) # The maximum x coordinate of a valid sheet / tile -SHEET_MIN_Y = SHEET_ORIGIN_TOP - (41 * SHEET_HEIGHT) # The minimum y coordinate of a valid sheet / tile -SHEET_MAX_Y = SHEET_ORIGIN_TOP # The maximum y coordinate of a valid sheet / tile -# Ranges of valid sheet columns for each sheet row. Keys are the row names, and values are ranges -# between which there are valid rows. For example `"AS": [(21, 22), (24, 24)]` means the valid -# sheets in row AS are AS21, AS22, and AS24. +SHEET_WIDTH = 24_000 +""" Width of Topo 1:50k mapsheets (meters) """ +SHEET_HEIGHT = 36_000 +""" Height of Topo 1:50k mapsheets (meters) """ +SHEET_ORIGIN_LEFT = 988_000 +""" The NZTM x coordinate of the left edge of 1:50k mapsheets which would be at column position 00 """ +SHEET_ORIGIN_TOP = 6_234_000 +""" The NZTM y coordinate of the top edge of 1:50k mapsheets in row AS (the northernmost row) """ +SHEET_MIN_X = SHEET_ORIGIN_LEFT + (4 * SHEET_WIDTH) +""" The minimum x coordinate of a valid sheet / tile """ +SHEET_MAX_X = SHEET_ORIGIN_LEFT + (46 * SHEET_WIDTH) +""" The maximum x coordinate of a valid sheet / tile """ +SHEET_MIN_Y = SHEET_ORIGIN_TOP - (41 * SHEET_HEIGHT) +""" The minimum y coordinate of a valid sheet / tile """ +SHEET_MAX_Y = SHEET_ORIGIN_TOP +""" The maximum y coordinate of a valid sheet / tile """ SHEET_RANGES = { "AS": [(21, 22), (24, 24)], "AT": [(23, 26)], @@ -55,10 +60,19 @@ "CJ": [(7, 11)], "CK": [(7, 9)], } +""" Ranges of valid sheet columns for each sheet row. +Keys are the row names, and values are ranges between which there are valid rows. +For example `"AS": [(21, 22), (24, 24)]` means the valid sheets in row AS are AS21, AS22, and AS24. +See `sheet index diagram` at +https://www.linz.govt.nz/products-services/maps/new-zealand-topographic-maps/topo50-map-chooser/topo50-sheet-index """ + + GRID_SIZES = [10_000, 5_000, 2_000, 1_000, 500] +""" Allowed grid sized, these should exist in the LINZ Data service (meters) """ GRID_SIZE_MAX = 50_000 -# Correction is set to 1 centimeter +""" Base scale Topo 1:50k mapsheets (meters) """ ROUND_CORRECTION = 0.01 +""" Correction set to `1` centimer """ class TileIndexException(Exception): @@ -75,14 +89,22 @@ class Point(NamedTuple): def round_with_correction(value: Union[int, float]) -> int | float: """Round a value to the next or previous unit ROUND_CORRECTION. Python round() can be 'inaccurate', note that: - round(0.015) == 0.01 - round(0.985) == 0.99 + >>> round(0.015) + 0.01 + >>> round(0.985) + 0.99 Args: - value (Union[int, float]): the value to round with correction. + value: the value to round with correction. Returns: - int | float: the rounded and (maybe) corrected value. + the rounded and (maybe) corrected value. + + Examples: + >>> round_with_correction(1643679.969) + 1643679.97 + >>> round_with_correction(5444160.015) + 5444160 """ if isinstance(value, int): return value @@ -90,9 +112,12 @@ def round_with_correction(value: Union[int, float]) -> int | float: # Round to centimeter precision correction = rounded_value = round(value, 2) + # The rounded value is not an integer if not rounded_value.is_integer(): + # Try to get an integer by adding the `ROUND_CORRECTION` if (rounded_value + ROUND_CORRECTION).is_integer(): correction = rounded_value + ROUND_CORRECTION + # Try to get an integer by substracting the `ROUND_CORRECTION` elif (rounded_value - ROUND_CORRECTION).is_integer(): correction = rounded_value - ROUND_CORRECTION @@ -106,14 +131,18 @@ def get_tile_name(origin: Point, grid_size: int) -> str: """Get the tile name from an origin point and the grid size (or scale). Args: - origin (Point): The origin point of the tile to get the name for. - grid_size (int): The size of the grid (or scale). + origin: The origin point of the tile to get the name for. + grid_size: The size of the grid (or scale). Raises: TileIndexException: If the input data don't allow to get the tile. Returns: str: The generated tile name ('sheetCode_gridSize_tileId'). + + Example: + >>> get_tile_name(Point(1236640, 4837560), 500) + "CG10_500_080037.tiff" """ # pylint: disable-msg=too-many-locals if not grid_size in GRID_SIZES: @@ -122,7 +151,7 @@ def get_tile_name(origin: Point, grid_size: int) -> str: origin_x = round_with_correction(origin[0]) origin_y = round_with_correction(origin[1]) - # If x or y is not a round number, the origin is not valid + # If x or y is not a round number after being corrected, the origin is not valid if not isinstance(origin_x, int) or not isinstance(origin_y, int): raise TileIndexException(f"The origin is invalid x = {origin_x}, y = {origin_y}") @@ -131,7 +160,7 @@ def get_tile_name(origin: Point, grid_size: int) -> str: tile_height = SHEET_HEIGHT // scale nb_digits = 2 if grid_size == 500: - nb_digits = 3 + nb_digits = 3 # 1:500 X/Y is 3 digits not 2 if not SHEET_MIN_X <= origin_x <= SHEET_MAX_X: raise TileIndexException(f"x must be between {SHEET_MIN_X} and {SHEET_MAX_X}, was {origin_x}")