========================================= == met.no Map Data File type=triangles == == Specification, 2006-10-25 == ========================================= 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 integer by storing the first word (lsw) and the second word (msw) in separate short integers. Look out for lsw/msw in desc. below. 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: 1. pure polygon-vertices, sorted by size and polygon-type (0=coastline, 1=lakes, 2=islands_in_lakes, etc) 2. triangle-vertices. == Useful values == nwrec=1024 // recordsize 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 ================================================== 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)