===== Triangle Map Format ===== This document is an editable version of the [[http://diana.met.no/triangle.txt|met.no Map Data File type=triangles Specification, 2006-10-25]] document. === Intro: === This describes the structure of a binary file format for map data - polygons describing geographic element and precalculated triangles that tesselates these polygons. The data is ordered in tiles and tilegroups. The world is divided into equal sized rectangular lat/lon-tiles (described by bounding box), and to accomodate larger tile-sets (larger than MAX_SHORT_INT), tiles are ordered into groups of tiles (with its own super bounding box). Each tile is populated with the set of polygons p, belonging to a possibly larger **closed and simple** polygon P that describes a geographic element (continent, island, lake, island_in_lake, etc.) that is strictly within a tiles bounding box. In addition you find the subset of triangles t, from the full tessallation T of P, that falls within the tiles bounding box. === Binary format: === * Contents of file interpreted as short integer (2 byte integers). Each record 1024 short integers * Some groups of data must not be split across record boundaries, see the specification below for these. * Values that are bigger than MAX_SHORT_INT are represented as 4 byte integers by storing the first word (lsw) and the second word (msw) in separate short integers. Look out for lsw/msw in desc. below. * //These seem to be reversed in the files supplied with diana.// The file has a variable-sized header and a data-section. All data is ordered in tile groups and tiles. The header has lookup-tables for tile-data. You will typically check the bounding boxes for each tile, decide which tiles you will need data from, and use the tables to look up which file-records and offsets you need to access. Data consists of: - pure polygon-vertices, sorted by size and polygon-type (0=coastline, 1=lakes, 2=islands_in_lakes, etc) - triangle-vertices. === Useful values === * nwrec = 1024 (record size in 2-byte integers) * delta_lat = latitude_size_of_tile_bounding box (degrees) * delta_lon = longitude_size_of_tile_bounding box (degrees) === Scaling values === All floating point data is scaled to fit into a short integer: scale= 64000 / max( delta_lat,delta_lon ) * iscale2= %%max ( ceil(log10( scale / 32000 )), 0 )%% * iscale1= %%scale * (10**-iscale2)%% * itscale= 2 * tscale= %%10**itscale%% When reading file, scale is calculated with: scale = iscale1 * (10**iscale2) === The actual file content === Data separated by %%//%% must not be split over record boundary. //What this means is that groups of related data, such as the general description of a tile containing the numbers of constituent parts and the bounding box, must be stored together. If the group of data would cross a record boundary, the data is written at the start of the next record. The bytes from the offset in the file where the data should have started and the start of the next record are undefined.// === Heading: === rec[ 0]= (('p' << 8) | 'm'); // identifier rec[ 1]= 4; // version number rec[ 2]= 2*nwrec // record length in unit bytes rec[ 3]= iscale1 // scaling value 1 rec[ 4]= iscale2 // scaling value 2 rec[ 5]= itscale // scaling value 3 rec[ 6]= numgroups // number of tilegroups n=7 # Starts at rec[n] with heading data for first tilegroup (tilegrouploop) rec[n+0]= number_of_tiles_in_group rec[n+1]= group_boundingbox_west * tscale rec[n+2]= group_boundingbox_east * tscale rec[n+3]= group_boundingbox_south * tscale rec[n+4]= group_boundingbox_north * tscale // n+=5 (tile loop - tiles in current group) rec[n+0]= record number, start of data rec[n+1]= offset in record, start of data rec[n+2]= tile_boundingbox_west * tscale rec[n+3]= tile_boundingbox_east * tscale rec[n+4]= tile_boundingbox_north * tscale rec[n+5]= tile_boundingbox_south * tscale // n+=6 (end of tile loop) (end of group loop) === Data: === # Starts at rec[n] with data for first tilegroup (tilegrouploop) (tile loop - tiles in current group) rec[n+ 0]= number_of_polygons lsw rec[n+ 1]= number_of_polygons msw rec[n+ 2]= total number_of_polygon_vertices lsw rec[n+ 3]= total number_of_polygon_vertices msw rec[n+ 4]= total number_of_triangle_vertices lsw rec[n+ 5]= total number_of_triangle_vertices msw rec[n+ 6]= number_of_polygon_types (max 10) rec[n+ 7]= record number, start of data for polygon type 0 rec[n+ 8]= offset in record, start of data for polygon type 0 rec[n+ 9]= record number, start of data for polygon type 1 rec[n+10]= offset in record, start of data for polygon type 1 .. rec[n+25]= record number, start of data for polygon type 9 rec[n+26]= offset in record, start of data for polygon type 9 // n+=27 (polygon type loop) rec[n+ 0]= number_of_polygons_this_type // n+=1 (polygon loop [P]) rec[n+ 0]= polygon_boundingbox_west * scale rec[n+ 1]= polygon_boundingbox_east * scale rec[n+ 2]= polygon_boundingbox_south * scale rec[n+ 3]= polygon_boundingbox_north * scale rec[n+ 4]= number_of_polygons [p] // 1 or # subparts of P rec[n+ 5]= number_of_triangles lsw rec[n+ 6]= number_of_triangles msw // n+=6 (polygon loop [p]) rec[n+ 0]= number_of_vertices lsw rec[n+ 1]= number_of_vertices msw // n+=2 (polygon vertices loop) rec[n+ 0]= x_offset_from_tile_midpoint * scale rec[n+ 1]= y_offset_from_tile_midpoint * scale // n+=2 (end of polygon vertices loop) (end of polygon loop [p]) (triangle loop) rec[n+ 0]= x1_offset_from_tile_midpoint * scale rec[n+ 1]= y1_offset_from_tile_midpoint * scale rec[n+ 2]= x2_offset_from_tile_midpoint * scale rec[n+ 3]= y2_offset_from_tile_midpoint * scale rec[n+ 4]= x3_offset_from_tile_midpoint * scale rec[n+ 5]= y3_offset_from_tile_midpoint * scale // n+=6 (end of triangle loop) (end of polygon loop [P]) (end of polygon type loop) (end of tile loop) (end of group loop)