Skip to main content

Tile matrix sets and the gpkg_tile_matrix_set table

While vector features represent discrete geographic entities like buildings and roads, raster data represents continuous phenomena or imagery. GeoPackage handles raster data through a tile-based approach, organizing imagery and gridded data into pyramid structures for efficient display and analysis. Understanding tile matrix sets is essential for working with aerial photography, elevation models, and base maps in Danish municipal applications.

Understanding Raster Tiles

Why Tiles?

Storing and displaying large raster datasets presents significant challenges:

File size - A high-resolution aerial photograph of a municipality can be many gigabytes in size.

Memory constraints - Loading an entire large image into memory is often impractical or impossible.

Network efficiency - Transmitting large images over networks is slow, especially for web applications.

Display performance - Rendering massive images at full resolution is computationally expensive.

Solution: Tiling breaks large raster datasets into small, manageable pieces (tiles) organized in a pyramid structure with multiple zoom levels.

Example: An aerial photograph of Aarhus Kommune at 10cm resolution might be:

  • Original image: 50,000 × 40,000 pixels = 2 billion pixels
  • Divided into tiles: 256 × 256 pixel tiles = ~30,500 tiles at full resolution
  • With pyramid: Additional tiles at zoom levels 0-18 for efficient display

Tile Pyramid Concept

A tile pyramid organizes raster data into multiple zoom levels:

Zoom level 0 - Entire coverage area in a single tile (or small number of tiles)

Zoom level 1 - Coverage divided into 4 tiles (2×2)

Zoom level 2 - Coverage divided into 16 tiles (4×4)

...and so on - Each level has 4× the tiles of the previous level

Example visualization:

Zoom 0: [    Single tile    ]

Zoom 1: [  ][  ]
        [  ][  ]

Zoom 2: [ ][ ][ ][ ]
        [ ][ ][ ][ ]
        [ ][ ][ ][ ]
        [ ][ ][ ][ ]

Each zoom level doubles the resolution in each dimension

Key characteristics:

  • Each zoom level has a specific scale and resolution
  • Higher zoom levels show more detail but cover less area per tile
  • Adjacent tiles at the same zoom level fit together seamlessly
  • Four tiles at level N are covered by one tile at level N-1

Tile Coordinates

Each tile is identified by three coordinates:

Zoom level (z) - Which level in the pyramid (0 = most zoomed out)

Column (x) - Horizontal position in the tile grid (0 = leftmost)

Row (y) - Vertical position in the tile grid (0 = topmost)

Example: Tile (z=12, x=2145, y=1342) means:

  • Zoom level 12
  • Column 2145 from the left
  • Row 1342 from the top

The gpkg_tile_matrix_set Table

The gpkg_tile_matrix_set table defines the overall parameters for a tile pyramid, including its geographic extent and coordinate reference system.

Table Structure

CREATE TABLE gpkg_tile_matrix_set (
  table_name TEXT NOT NULL PRIMARY KEY,
  srs_id INTEGER NOT NULL,
  min_x DOUBLE NOT NULL,
  min_y DOUBLE NOT NULL,
  max_x DOUBLE NOT NULL,
  max_y DOUBLE NOT NULL,
  CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name),
  CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)
);

Column Definitions

table_name - The name of the tile pyramid table (references gpkg_contents)

srs_id - Spatial reference system identifier (references gpkg_spatial_ref_sys)

min_x, min_y - Minimum bounding coordinates (southwest corner)

max_x, max_y - Maximum bounding coordinates (northeast corner)

The bounding box defines the geographic extent covered by the tile pyramid.

Example Tile Matrix Set

Danish national orthophotos:

-- First, register in gpkg_contents
INSERT INTO gpkg_contents (
    table_name, 
    data_type, 
    identifier, 
    description,
    last_change,
    min_x, min_y, max_x, max_y,
    srs_id
) VALUES (
    'aerial_photos',
    'tiles',
    'aerial_photos',
    'Aerial photography of Aarhus Kommune, 10cm resolution, 2024',
    datetime('now'),
    541000, 6205000, 592000, 6262000,  -- Bounding box in EPSG:25832
    25832
);

-- Define the tile matrix set
INSERT INTO gpkg_tile_matrix_set (
    table_name,
    srs_id,
    min_x, min_y, max_x, max_y
) VALUES (
    'aerial_photos',
    25832,
    541000, 6205000,  -- Southwest corner (min_x, min_y)
    592000, 6262000   -- Northeast corner (max_x, max_y)
);

Web Mercator base map:

-- Web Mercator (EPSG:3857) for web mapping applications
INSERT INTO gpkg_contents (
    table_name,
    data_type,
    identifier,
    description,
    last_change,
    min_x, min_y, max_x, max_y,
    srs_id
) VALUES (
    'osm_basemap',
    'tiles',
    'osm_basemap',
    'OpenStreetMap base map for Denmark',
    datetime('now'),
    1113195, 7361866, 1484158, 7699000,  -- Denmark extent in EPSG:3857
    3857
);

INSERT INTO gpkg_tile_matrix_set (
    table_name,
    srs_id,
    min_x, min_y, max_x, max_y
) VALUES (
    'osm_basemap',
    3857,
    1113195, 7361866, 1484158, 7699000
);

Understanding the Bounding Box

The bounding box in gpkg_tile_matrix_set defines the maximum possible extent of the tile pyramid.

Important considerations:

  • Coordinates must be in the units of the specified SRS
  • For EPSG:25832 (UTM), coordinates are in meters
  • For EPSG:4326 (WGS84), coordinates are in degrees
  • For EPSG:3857 (Web Mercator), coordinates are in meters

Example: Calculating bounding box for a municipality

-- If you have a municipal boundary polygon
SELECT 
    ST_MinX(geom) AS min_x,
    ST_MinY(geom) AS min_y,
    ST_MaxX(geom) AS max_x,
    ST_MaxY(geom) AS max_y
FROM municipal_boundary
WHERE municipality_name = 'Aarhus';

-- Results (in EPSG:25832):
-- min_x: 541234.56
-- min_y: 6205678.90
-- max_x: 591876.54
-- max_y: 6261234.56

-- Round to nice numbers for tile matrix set:
-- min_x: 541000
-- min_y: 6205000
-- max_x: 592000
-- max_y: 6262000

The gpkg_tile_matrix Table

While gpkg_tile_matrix_set defines the overall extent, the gpkg_tile_matrix table defines the individual zoom levels within the pyramid.

Table Structure

CREATE TABLE gpkg_tile_matrix (
  table_name TEXT NOT NULL,
  zoom_level INTEGER NOT NULL,
  matrix_width INTEGER NOT NULL,
  matrix_height INTEGER NOT NULL,
  tile_width INTEGER NOT NULL,
  tile_height INTEGER NOT NULL,
  pixel_x_size DOUBLE NOT NULL,
  pixel_y_size DOUBLE NOT NULL,
  CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level),
  CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name)
);

Column Definitions

table_name - The tile pyramid table name

zoom_level - The zoom level (typically 0 = most zoomed out)

matrix_width - Number of tile columns at this zoom level

matrix_height - Number of tile rows at this zoom level

tile_width - Width of each tile in pixels (typically 256 or 512)

tile_height - Height of each tile in pixels (typically 256 or 512)

pixel_x_size - Ground distance represented by one pixel in X direction (in SRS units)

pixel_y_size - Ground distance represented by one pixel in Y direction (in SRS units)

Calculating Tile Matrix Parameters

The relationship between zoom levels follows mathematical rules:

Matrix dimensions at each level:

For a standard web map pyramid starting with 1 tile at zoom 0:
Zoom 0: 1 × 1 tile    (matrix_width=1, matrix_height=1)
Zoom 1: 2 × 2 tiles   (matrix_width=2, matrix_height=2)
Zoom 2: 4 × 4 tiles   (matrix_width=4, matrix_height=4)
Zoom N: 2^N × 2^N tiles

General formula:
matrix_width = matrix_height = 2^zoom_level

Pixel size calculation:

pixel_x_size = (max_x - min_x) / (matrix_width × tile_width)
pixel_y_size = (max_y - min_y) / (matrix_height × tile_height)

Example for zoom level 10 with 256×256 tiles and 50km × 50km extent:
matrix_width = matrix_height = 2^10 = 1024 tiles
pixel_x_size = 50000 / (1024 × 256) = 0.19 meters/pixel
pixel_y_size = 50000 / (1024 × 256) = 0.19 meters/pixel

Example Tile Matrix

Standard web map pyramid (Web Mercator):

-- Zoom level 0: World in single 256×256 tile
INSERT INTO gpkg_tile_matrix (
    table_name, zoom_level,
    matrix_width, matrix_height,
    tile_width, tile_height,
    pixel_x_size, pixel_y_size
) VALUES (
    'osm_basemap', 0,
    1, 1,                    -- 1×1 tile
    256, 256,                -- 256×256 pixels per tile
    156543.03392804097,      -- ~156km per pixel
    156543.03392804097
);

-- Zoom level 1: 2×2 tiles
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_basemap', 1,
    2, 2,
    256, 256,
    78271.51696402048,       -- Half the previous pixel size
    78271.51696402048
);

-- Zoom level 2: 4×4 tiles
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_basemap', 2,
    4, 4,
    256, 256,
    39135.75848201024,
    39135.75848201024
);

-- ...continue through zoom level 18 for detailed street-level mapping

Danish UTM-based pyramid for aerial photos:

-- Calculate parameters for custom extent in EPSG:25832
-- Extent: 541000 to 592000 (51km wide), 6205000 to 6262000 (57km high)

-- Zoom level 8: Reasonable starting point for overview
-- Choose matrix size to cover extent efficiently
-- If using 256×256 tiles: need 8×9 tiles at level 8

INSERT INTO gpkg_tile_matrix (
    table_name, zoom_level,
    matrix_width, matrix_height,
    tile_width, tile_height,
    pixel_x_size, pixel_y_size
) VALUES (
    'aerial_photos', 8,
    8, 9,                    -- 8 columns × 9 rows
    256, 256,
    24.90,                   -- 51000m / (8 × 256) ≈ 24.90m per pixel
    24.56                    -- 57000m / (9 × 256) ≈ 24.56m per pixel
);

-- Zoom level 9: Double the resolution
INSERT INTO gpkg_tile_matrix VALUES (
    'aerial_photos', 9,
    16, 18,                  -- 2× matrix dimensions
    256, 256,
    12.45,                   -- Half the previous pixel size
    12.28
);

-- Zoom level 10: Continue doubling
INSERT INTO gpkg_tile_matrix VALUES (
    'aerial_photos', 10,
    32, 36,
    256, 256,
    6.225,
    6.14
);

-- Zoom level 11: Fine detail
INSERT INTO gpkg_tile_matrix VALUES (
    'aerial_photos', 11,
    64, 72,
    256, 256,
    3.1125,
    3.07
);

-- Zoom level 12: 10cm aerial photo resolution
INSERT INTO gpkg_tile_matrix VALUES (
    'aerial_photos', 12,
    128, 144,
    256, 256,
    1.556,                   -- ~1.5m per pixel
    1.535
);

-- Continue to zoom level 16 for 10cm resolution
INSERT INTO gpkg_tile_matrix VALUES (
    'aerial_photos', 16,
    2048, 2304,
    256, 256,
    0.0973,                  -- ~10cm per pixel
    0.0960
);

Tile Numbering and Coordinate Systems

Row/Column Numbering Convention

GeoPackage follows a specific convention for tile numbering:

Column (x) numbering:

  • Column 0 is at min_x (leftmost)
  • Columns increase eastward (to the right)

Row (y) numbering:

  • Row 0 is at max_y (topmost)
  • Rows increase southward (downward)

This is the TMS (Tile Map Service) convention, which differs from some other tiling schemes.

Important: This differs from XYZ/Google tile numbering where row 0 is at the bottom (min_y).

Calculating Tile Coordinates

Given a geographic coordinate, find which tile it falls in:

-- Function to calculate tile column
-- tile_col = floor((x - min_x) / (pixel_x_size × tile_width))

-- Example: Find tile for coordinate (570000, 6230000) at zoom 10
-- Using aerial_photos example above:
-- min_x = 541000, pixel_x_size = 6.225, tile_width = 256

SELECT 
    CAST((570000 - 541000) / (6.225 * 256) AS INTEGER) AS tile_column,
    CAST((6262000 - 6230000) / (6.14 * 256) AS INTEGER) AS tile_row;
-- Returns: tile_column = 18, tile_row = 20

Calculate geographic extent of a specific tile:

-- Given tile (zoom=10, column=18, row=20)
-- min_x = 541000, min_y = 6205000
-- pixel_x_size = 6.225, pixel_y_size = 6.14
-- tile_width = tile_height = 256

SELECT 
    541000 + (18 * 256 * 6.225) AS tile_min_x,
    6262000 - ((20 + 1) * 256 * 6.14) AS tile_min_y,
    541000 + ((18 + 1) * 256 * 6.225) AS tile_max_x,
    6262000 - (20 * 256 * 6.14) AS tile_max_y;
    
-- Returns the bounding box of this specific tile

Common Tile Pyramid Schemes

Web Mercator (EPSG:3857)

The most common tiling scheme for web maps.

Characteristics:

  • Origin at (-20037508.34, 20037508.34) in meters
  • Covers approximately -85° to +85° latitude
  • Square tiles (256×256 or 512×512 pixels)
  • Fixed number of zoom levels (typically 0-18 or 0-22)
  • Each zoom level doubles the resolution

Advantages:

  • Universal standard for web mapping
  • Supported by all major web mapping libraries
  • Tiles from different providers can be mixed

Disadvantages:

  • Distortion increases toward poles
  • Not suitable for area calculations
  • Not suitable for polar regions

Danish context:

  • Suitable for general web map applications
  • Not ideal for precise municipal mapping
  • Use for base maps and context

Custom UTM-based Pyramids (EPSG:25832)

For Danish municipal applications, UTM-based pyramids are often more appropriate.

Characteristics:

  • Based on EPSG:25832 (ETRS89 / UTM zone 32N)
  • Coordinates in meters
  • No distortion within Denmark
  • Custom extent matching municipal boundaries
  • Custom zoom levels based on data resolution

Advantages:

  • Accurate measurements and areas
  • Aligns with national coordinate system
  • Matches existing municipal data
  • Compatible with GeoDanmark and other Danish datasets

Disadvantages:

  • Not directly compatible with standard web maps
  • Requires transformation for web display
  • Custom implementation needed

Best practices:

-- Choose extent to cover municipality with some buffer
-- Round to nice numbers (e.g., 1000m increments)
-- Calculate zoom levels based on target resolutions:
--   Zoom 8:  ~25m per pixel (overview)
--   Zoom 12: ~1.5m per pixel (planning)
--   Zoom 16: ~0.1m per pixel (10cm orthophotos)

EPSG:4326 (Geographic WGS84)

Less common for tiles but sometimes used.

Characteristics:

  • Coordinates in degrees
  • Simple latitude/longitude grid
  • Non-square pixels (degrees don't equal meters)

Considerations:

-- Pixel sizes differ in X and Y
-- Example at 56° latitude (Denmark):
-- pixel_x_size in degrees ≠ pixel_y_size in degrees
-- 1° longitude ≈ 62km at 56° latitude
-- 1° latitude ≈ 111km everywhere

Practical Examples

Example 1: Municipal Aerial Photography

-- Setup for Aalborg Kommune aerial photography
-- Extent: 9.8° to 10.2° E, 56.9° to 57.2° N
-- Convert to EPSG:25832: approximately (544000, 6305000) to (582000, 6338000)

-- Register in contents
INSERT INTO gpkg_contents (
    table_name, data_type, identifier, description,
    last_change, min_x, min_y, max_x, max_y, srs_id
) VALUES (
    'aalborg_ortho_2024',
    'tiles',
    'Aalborg Orthophotos 2024',
    'Aerial photography, 10cm resolution, collected Spring 2024',
    datetime('now'),
    544000, 6305000, 582000, 6338000,
    25832
);

-- Define tile matrix set
INSERT INTO gpkg_tile_matrix_set (
    table_name, srs_id, min_x, min_y, max_x, max_y
) VALUES (
    'aalborg_ortho_2024',
    25832,
    544000, 6305000, 582000, 6338000
);

-- Define zoom levels (showing key levels)
-- Zoom 8: Overview (~25m/pixel)
INSERT INTO gpkg_tile_matrix VALUES (
    'aalborg_ortho_2024', 8,
    6, 6,           -- 6×6 tiles covers the extent
    256, 256,
    24.74,          -- (582000-544000)/(6*256) 
    21.35           -- (6338000-6305000)/(6*256)
);

-- Zoom 12: Planning detail (~1.5m/pixel)
INSERT INTO gpkg_tile_matrix VALUES (
    'aalborg_ortho_2024', 12,
    96, 96,
    256, 256,
    1.546,
    1.335
);

-- Zoom 16: Full resolution (~10cm/pixel)
INSERT INTO gpkg_tile_matrix VALUES (
    'aalborg_ortho_2024', 16,
    1536, 1536,
    256, 256,
    0.0967,
    0.0835
);

Example 2: Elevation Model (DTM)

-- Digital Terrain Model for Odense Kommune
-- 0.4m resolution elevation data

INSERT INTO gpkg_contents (
    table_name, data_type, identifier, description,
    last_change, min_x, min_y, max_x, max_y, srs_id
) VALUES (
    'odense_dtm',
    'tiles',
    'Odense DTM',
    'Digital Terrain Model, 0.4m grid resolution',
    datetime('now'),
    572000, 6134000, 598000, 6158000,
    25832
);

INSERT INTO gpkg_tile_matrix_set VALUES (
    'odense_dtm',
    25832,
    572000, 6134000, 598000, 6158000
);

-- Zoom levels appropriate for elevation data
-- Fewer zoom levels than imagery (elevation changes gradually)

-- Zoom 10: 6m per pixel
INSERT INTO gpkg_tile_matrix VALUES (
    'odense_dtm', 10,
    17, 16,
    256, 256,
    5.956,
    5.859
);

-- Zoom 12: 1.5m per pixel
INSERT INTO gpkg_tile_matrix VALUES (
    'odense_dtm', 12,
    68, 64,
    256, 256,
    1.489,
    1.465
);

-- Zoom 14: 0.4m per pixel (matches source resolution)
INSERT INTO gpkg_tile_matrix VALUES (
    'odense_dtm', 14,
    272, 256,
    256, 256,
    0.372,
    0.366
);

Example 3: Base Map with Standard Web Tiles

-- OpenStreetMap tiles for Denmark in Web Mercator
-- Standard zoom levels 0-16

INSERT INTO gpkg_contents (
    table_name, data_type, identifier, description,
    last_change, min_x, min_y, max_x, max_y, srs_id
) VALUES (
    'osm_denmark',
    'tiles',
    'OSM Denmark',
    'OpenStreetMap base map tiles for Denmark',
    datetime('now'),
    1113195, 7361866, 1484158, 7699000,  -- Denmark in EPSG:3857
    3857
);

INSERT INTO gpkg_tile_matrix_set VALUES (
    'osm_denmark',
    3857,
    1113195, 7361866, 1484158, 7699000
);

-- Standard Web Mercator zoom levels
-- Each zoom level doubles resolution
-- Zoom 0: entire world
-- Zoom 18: street-level detail

-- Define all zoom levels (showing pattern)
-- Zoom 0
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_denmark', 0, 1, 1, 256, 256,
    156543.033928041, 156543.033928041
);

-- Zoom 5: Country level
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_denmark', 5, 32, 32, 256, 256,
    4891.969810251, 4891.969810251
);

-- Zoom 10: City level
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_denmark', 10, 1024, 1024, 256, 256,
    152.874055594, 152.874055594
);

-- Zoom 15: Street level
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_denmark', 15, 32768, 32768, 256, 256,
    4.777314424, 4.777314424
);

-- Zoom 18: Building level
INSERT INTO gpkg_tile_matrix VALUES (
    'osm_denmark', 18, 262144, 262144, 256, 256,
    0.597164303, 0.597164303
);

Best Practices for Tile Matrix Sets

1. Choose Appropriate Coordinate System

For Danish municipal applications:

  • Use EPSG:25832 for operational data (planning, analysis)
  • Use EPSG:3857 for web visualization and public portals
  • Consider maintaining both if needed for different use cases

2. Define Sensible Extents

-- Good: Extent matches actual data coverage with small buffer
min_x = 541000, max_x = 592000  -- 51km wide

-- Avoid: Unnecessarily large extent
min_x = 400000, max_x = 700000  -- 300km wide (wastes tiles)

-- Avoid: Extent smaller than actual data
-- (Data will be clipped)

3. Choose Appropriate Zoom Levels

Don't create more zoom levels than necessary:

-- For 10cm aerial photos:
-- Need zoom levels that span from overview to 10cm/pixel
-- Zoom 8: 25m/pixel (overview)
-- Zoom 12: 1.5m/pixel (planning)
-- Zoom 16: 0.1m/pixel (full resolution)
-- Don't create zoom 20 (0.006m/pixel) - beyond source resolution

-- For base maps:
-- Zoom 0-5: Continental/country level
-- Zoom 6-10: Regional/city level
-- Zoom 11-16: Street/building level
-- Zoom 17-18: Detailed street level

4. Use Standard Tile Sizes

-- Standard and recommended:
tile_width = 256, tile_height = 256

-- Also acceptable:
tile_width = 512, tile_height = 512

-- Avoid non-standard sizes:
tile_width = 300, tile_height = 200  -- Incompatible with standards

5. Calculate Pixel Sizes Accurately

-- Ensure pixel size matches the relationship:
-- extent_width = matrix_width × tile_width × pixel_x_size
-- extent_height = matrix_height × tile_height × pixel_y_size

-- Example verification:
-- extent_width = 51000m
-- matrix_width = 8 tiles
-- tile_width = 256 pixels
-- pixel_x_size should be: 51000 / (8 × 256) = 24.90

-- Check your calculation:
SELECT 8 * 256 * 24.90;  -- Should equal 51004.8 (close to 51000)

6. Document Your Tile Matrix

-- Add helpful description to gpkg_contents
INSERT INTO gpkg_contents (
    table_name, data_type, identifier, description, ...
) VALUES (
    'my_tiles',
    'tiles',
    'My Tiles',
    'Aerial photography 2024, 10cm resolution, EPSG:25832, zoom levels 8-16. Zoom 8: overview (25m/px), Zoom 12: planning (1.5m/px), Zoom 16: full res (0.1m/px). Coverage: Aarhus Kommune.',
    ...
);

7. Validate Tile Matrix Configuration

-- Query to check tile matrix configuration
SELECT 
    tm.table_name,
    tm.zoom_level,
    tm.matrix_width,
    tm.matrix_height,
    tm.tile_width,
    tm.tile_height,
    tm.pixel_x_size,
    tm.pixel_y_size,
    -- Calculate total extent coverage
    tm.matrix_width * tm.tile_width * tm.pixel_x_size AS calculated_width,
    tm.matrix_height * tm.tile_height * tm.pixel_y_size AS calculated_height,
    -- Compare with actual extent
    tms.max_x - tms.min_x AS actual_width,
    tms.max_y - tms.min_y AS actual_height
FROM gpkg_tile_matrix tm
JOIN gpkg_tile_matrix_set tms ON tm.table_name = tms.table_name
ORDER BY tm.table_name, tm.zoom_level;

Querying Tile Matrix Information

Get all tile pyramids in a GeoPackage

SELECT 
    c.table_name,
    c.identifier,
    c.description,
    tms.srs_id,
    tms.min_x, tms.min_y, tms.max_x, tms.max_y,
    COUNT(tm.zoom_level) AS num_zoom_levels,
    MIN(tm.zoom_level) AS min_zoom,
    MAX(tm.zoom_level) AS max_zoom
FROM gpkg_contents c
JOIN gpkg_tile_matrix_set tms ON c.table_name = tms.table_name
LEFT JOIN gpkg_tile_matrix tm ON c.table_name = tm.table_name
WHERE c.data_type = 'tiles'
GROUP BY c.table_name;

Get details for a specific tile pyramid

SELECT 
    zoom_level,
    matrix_width,
    matrix_height,
    matrix_width * matrix_height AS total_tiles,
    tile_width,
    tile_height,
    ROUND(pixel_x_size, 4) AS pixel_x_size,
    ROUND(pixel_y_size, 4) AS pixel_y_size,
    ROUND(pixel_x_size, 4) || 'm/pixel' AS resolution
FROM gpkg_tile_matrix
WHERE table_name = 'aerial_photos'
ORDER BY zoom_level;

Calculate storage requirements

SELECT 
    table_name,
    zoom_level,
    matrix_width * matrix_height AS tile_count,
    matrix_width * matrix_height * tile_width * tile_height * 3 / 1024 / 1024 AS estimated_mb_rgb
FROM gpkg_tile_matrix
WHERE table_name = 'aerial_photos'
ORDER BY zoom_level;

Summary

Tile matrix sets provide the organizational framework for storing and accessing raster data in GeoPackage. The gpkg_tile_matrix_set table defines the overall geographic extent and coordinate system, while the gpkg_tile_matrix table defines each zoom level's parameters. Understanding how to properly configure tile pyramids—including choosing appropriate coordinate systems, extents, zoom levels, and pixel sizes—is essential for efficient raster data management in Danish municipal GIS applications. Well-designed tile pyramids enable fast display and analysis of large imagery and gridded datasets while maintaining data quality and accessibility.


Knowledge Check Quiz

Test your understanding of tile matrix sets and the gpkg_tile_matrix_set table:

Question 1: What is the primary purpose of organizing raster data into tiles?

a) To reduce file size through compression
b) To make large datasets more manageable for display and transmission
c) To improve spatial accuracy
d) To convert raster data to vector format

Question 2: In a tile pyramid, how does the number of tiles change from one zoom level to the next?

a) Doubles
b) Triples
c) Quadruples (4×)
d) Depends on the coordinate system

Question 3: What do the min_x, min_y, max_x, max_y values in gpkg_tile_matrix_set represent?

a) The size of each individual tile
b) The geographic extent covered by the entire tile pyramid
c) The pixel dimensions of the images
d) The number of zoom levels

Question 4: In GeoPackage tile numbering, where is row 0 located?

a) At the bottom (min_y)
b) At the top (max_y)
c) At the left (min_x)d) At the center

Question 5: Which coordinate system is most appropriate for precise municipal mapping in Denmark?

a) EPSG:3857 (Web Mercator)
b) EPSG:4326 (WGS 84)
c) EPSG:25832 (ETRS89 / UTM zone 32N)
d) EPSG:900913 (Google Mercator)

Question 6: What does pixel_x_size represent in the gpkg_tile_matrix table?

a) The width of each tile in pixels
b) The ground distance represented by one pixel in the X direction
c) The number of pixels in the X direction
d) The tile column number

Question 7: For a tile matrix with matrix_width=16, tile_width=256, and an extent width of 51,200 meters, what is the pixel_x_size?

a) 0.2 meters
b) 2.0 meters
c) 12.5 meters
d) 20.0 meters

Question 8: What is the standard tile size most commonly used in GeoPackage?

a) 128×128 pixels
b) 256×256 pixels
c) 512×512 pixels
d) 1024×1024 pixels

Question 9: If a tile pyramid starts at zoom level 0 with 1×1 tiles, how many tiles are at zoom level 3?

a) 3×3 tiles (9 total)
b) 4×4 tiles (16 total)
c) 8×8 tiles (64 total)
d) 16×16 tiles (256 total)

Question 10: Which table stores the parameters for individual zoom levels?

a) gpkg_tile_matrix_set
b) gpkg_tile_matrix
c) gpkg_contents
d) gpkg_spatial_ref_sys

Question 11: For aerial photography with 10cm ground resolution, which pixel_x_size value would be appropriate at the highest zoom level?

a) 0.001 meters (1mm)
b) 0.1 meters (10cm)
c) 1.0 meters
d) 10.0 meters

Question 12: What happens if you define zoom levels beyond the resolution of your source data?

a) The tiles automatically increase in quality
b) You create tiles with interpolated data but no additional real detail
c) The GeoPackage becomes invalid
d) The tiles are automatically removed

Question 13: In Web Mercator (EPSG:3857), pixel_x_size and pixel_y_size are:

a) Always different because of distortion
b) Always the same (square pixels in projected space)
c) Only the same at the equator
d) Measured in degrees

Question 14: Which tile numbering convention does GeoPackage use?

a) XYZ (Google)
b) TMS (Tile Map Service)
c) WMTS
d) QuadTree

Question 15: For a municipality that is 51km wide and 57km high, using 256×256 pixel tiles, approximately how many tiles would you need at a zoom level where each tile represents 1.5km × 1.5km of ground?

a) 34 × 38 tiles (1,292 total)
b) 51 × 57 tiles (2,907 total)
c) 200 × 225 tiles (45,000 total)
d) 256 × 256 tiles (65,536 total)


Answer Key

  1. b) To make large datasets more manageable for display and transmission - Tiling breaks large rasters into small, manageable pieces that can be loaded on demand.
  2. c) Quadruples (4×) - Each zoom level has 2× the width and 2× the height, resulting in 4× the total number of tiles.
  3. b) The geographic extent covered by the entire tile pyramid - These values define the bounding box of the maximum possible coverage area.
  4. b) At the top (max_y) - GeoPackage follows TMS convention where row 0 is at the top (max_y) and rows increase downward.
  5. c) EPSG:25832 (ETRS89 / UTM zone 32N) - This is the standard Danish coordinate system with no distortion and measurements in meters.
  6. b) The ground distance represented by one pixel in the X direction - pixel_x_size is the ground resolution in the coordinate system's units (e.g., meters).
  7. c) 12.5 meters - pixel_x_size = 51,200 / (16 × 256) = 12.5 meters per pixel.
  8. b) 256×256 pixels - This is the most common standard tile size, though 512×512 is also used.
  9. c) 8×8 tiles (64 total) - At zoom 3: 2^3 × 2^3 = 8×8 tiles.
  10. b) gpkg_tile_matrix - This table stores the detailed parameters for each zoom level.
  11. b) 0.1 meters (10cm) - The pixel size should match the source data resolution of 10cm.
  12. b) You create tiles with interpolated data but no additional real detail - Creating zoom levels beyond source resolution wastes storage without adding information.
  13. b) Always the same (square pixels in projected space) - Web Mercator uses square pixels in the projected coordinate system.
  14. b) TMS (Tile Map Service) - GeoPackage uses TMS convention with row 0 at the top.
  15. a) 34 × 38 tiles (1,292 total) - Width: 51km / 1.5km ≈ 34 tiles; Height: 57km / 1.5km ≈ 38 tiles.
Updated on Jan 19, 2026