View Single Post
Posts: 66 | Thanked: 145 times | Joined on Jan 2008
#20
quick update. i haven't had much time to look at this but have more info on
the file structure and some features (poi, labels).

obvious things to do:

- figure out the projection/coordinate system in use - it should be easy but
it's not obvious to me just yet...

- figure out how the compressed (relative?) coordinates work

- figure out how the quad coordinates relate to each quad in the quadtree

- figure out the geometry files

i also have some code for dumping out the known features but it's a bit much
to post in here. i'm hoping someone with more time than me can pick this up
and run with it then integrate it into navit... PM me if you want more info.

Code:
/*****************************************************************
 * OcDb file structures
 *****************************************************************/

/* OC maps consist of a number of layer qt files for different
   features, eg water, roads, rail etc.  A single .reg file lists the
   relevant qt files giving low and hi visibility thresholds so there
   may be some duplication between files - eg wa.qt is coarse global
   water view while wa3.qt will be more detailed.  There are also
   non-layer qt files such as a7 (address) and pc (postcode).  .bin
   files not yet investigated.

   These structures derived from uk map set.  Navicore users may
   download map sets may be from:
   
http://www.navicoretech.com/Consumer/Support/Downloads/tablet/en_GB/wfnavigator 

*/

typedef uint8_t uint24_t[3];

static const uint32_t OC_SIMPLE_MAGIC = 'O'|'C'<<8|'Q'<<16|'T'<<24;

#pragma pack(push,1)

/* qt files are in oc "simple" db format.  213 byte header as below.
   Many fields remain unknown at this point.  The actual data is tile
   based with a quadtree index immediately following the header and of
   a length specified in the header.  The quadtree index is followed
   by a tile index and then the tile blocks. */
typedef struct __OcSimpleHeader {
  uint32_t  magic;              //+0x00 'OCQT'
  uint16_t  unknown_mapyear;    //+0x04 06 ?? 
  uint16_t  unknown_mapmonth;   //+0x06 01 ??
  uint16_t  unknown_mapday;     //+0x08 03 ??
  uint16_t  unknown1;           //+0x0a zero
  uint16_t  unknown2;           //+0x0c ??
  uint16_t  unknown3;           //+0x0e zero
  uint32_t  quadtablelength;    //+0x10 length of quad table following 
header
  uint32_t  unknown5;           //+0x14 offset/length???
  uint32_t  coords[2];          //+0x18 coords lat,long? [0x00533189, 0x000d97a1]
  uint8_t   unknown6;           //+0x20
  uint8_t   unknown7;           //+0x21
  uint8_t   unknown8;           //+0x22 61-67
  uint32_t  unknown9;           //+0x23 zero
  uint8_t   unknown10;          //+0x27 00 or 01 
  uint8_t   unknown11;          //+0x28 02 or 50 or 69
  uint8_t   unknown12;          //+0x29 always 02
  uint8_t   unknown13;          //+0x2a 00/03/04

  struct {
    uint8_t unkn_idx;           //block number??
    uint8_t unkn_flags;         //??
  } unknown_table[64];          //+0x2b

  uint32_t  featuretype;        //+0xab eg: 'wa3\0' 'a7\0\0'
  uint8_t   unknown20[18];      //+0xaf zeros
  uint8_t   unknown21[3];       //+0xc1 ??
  uint8_t   unknown22[17];      //+0xc4 [6a 18 c4 77 05 00 00 00 01 00 
00 00 14 fc 12 00 08]
} OcSimpleHeader;               //size=213

/* Quad tree nodes are indexed 0-(N-1) where
   N=header.quadtablelength/sizeof(OcBlockQuadEntry).  The first node
   should cover the entire map.  Subblock indexes are into the quadtree
   table.  If the index is greater than the number of quadtree entries
   then it is used to index into the tile index (i-N).  Zero indicates
   an invalid subblock.  Subblock relationships to lat and lon not yet
   determined. */
typedef struct __OcBlockQuadEntry {
    uint8_t  unknown[6];        //+0x00 zero
    uint24_t lon1;              //+0x0c longitude
    uint24_t lon2;              //+0x0f lon2 often == lon1
    uint24_t lat1;              //+0x06 latitude
    uint24_t lat2;              //+0x09 lat2 often == lat1
    uint16_t subblocks[4];      //+0x12 subblock indexes
} OcBlockQuadEntry;             //size=26 0x1a


/* Following the quadtree node table is an index of tile blocks which
   basically just give pos and size in the file.  Note offset may be 0
   for null entries. */
typedef struct __OcBlockIndexEntry {
  uint32_t offset;            //+0x00 offset from start of file
  uint16_t length;            //+0x04
  uint8_t  unknown1;          //+0x06 incrementing
  uint8_t  unknown2;          //+0x07 zero
} OcBlockIndexEntry;          //size=8

#define ASSERT_STRUCTURE_SIZE(_s,_n) \
  int _check_##_size[(sizeof(_s)==_n)-1]

ASSERT_STRUCTURE_SIZE(OcSimpleHeader,213);
ASSERT_STRUCTURE_SIZE(OcBlockQuadEntry,26);
ASSERT_STRUCTURE_SIZE(OcBlockIndexEntry,8);


// a block is a zlib compressed tile
typedef struct __OcDbBlock {
  uint16_t     uncompressedLength;
  uint8_t      zdata[1];  // 78 da .. 
} OcDbBlock;


//first byte of a point, line or poly
typedef uint8_t OcFeatureProps;
// relative coords in uint16_t,uint16_t (relative to quad??)
// full coords in uint24_t,uint24_t
#define OC_PROP_RELATIVE_COORDS 0x80
// importance indicator, eg london 1, wigan 7
#define OC_PROP_ORDER_MASK      0x0f

typedef struct __OcRelativeCoord {
  OcFeatureProps  props;
  uint16_t        lat, lon;
} OcRelativeCoord;

typedef struct __OcCoord {
  OcFeatureProps  props;
  uint24_t        lat, lon;
} OcCoord;

typedef struct __OcDbGeomTile {
  uint16_t     polygonDataLength;
  //polygon data
  //polyline data
} OcDbGeomTile;

/* poi record - description has a number of tab separated fields:
   description, phone number */
typedef struct __OcDbPoiRecord {
  uint8_t      poiType;     //OcDbPoiType
  uint24_t     lat;
  uint24_t     lon;
  char         description[1]; //null terminated string
} OcDbPoiRecord;

// poi types are listed in poi.reg
enum __OcDbPoiType {
  OC_POI_PETROL_STATION = 0,
  OC_POI_RENT_A_CAR_FACILITY = 1,
  OC_POI_PARKING_GARAGE = 2,
  OC_POI_HOTEL_OR_MOTEL = 3,
  OC_POI_MUSEUM = 4,
  OC_POI_THEATRE = 5,
  OC_POI_SPORTS_CENTRE = 6,
  OC_POI_HOSPITAL_OR_POLYCLINIC = 7,
  OC_POI_POLICE_STATION = 8,
  OC_POI_PLACE_OF_WORSHIP = 9,
  OC_POI_FERRY_TERMINAL = 10,
  OC_POI_CAMPING_GROUND = 11,
  OC_POI_AIRLINE_ACCESS = 12,
  OC_POI_OPEN_PARKING__AREA = 13,
  OC_POI_SHOPPING_CENTER = 14,
  OC_POI_COLLEGE_OR_UNIVERSITY = 15,
  OC_POI_RAILWAY_STATION = 16,
  OC_POI_EXHIBITION_CENTER = 17,
  OC_POI_REST_AREA = 18,
  OC_POI_AIRPORT = 19,
  OC_POI_CONCERT_HALL = 20,
  OC_POI_CAR_DEALER = 21,
  OC_POI_COMPANY = 22,
  OC_POI_AMUSEMENT_PARK = 23,
  OC_POI_OPERA = 24,
  OC_POI_GOLF_COURSE = 25,
  OC_POI_ENTRY_POINT = 26,
  OC_POI_ZOO = 27,
  OC_POI_CAR_REPAIR_FACILITY = 28,
  OC_POI_CASINO = 29,
  OC_POI_CONVENTION_CENTRE = 31,
  OC_POI_COURTHOUSE = 32,
  OC_POI_DENTIST = 33,
  OC_POI_DOCTOR = 34,
  OC_POI_EMBASSY = 35,
  OC_POI_FRONTIER_CROSSING = 36,
  OC_POI_GOVERMENT_OFFICE = 37,
  OC_POI_IMPORTANT_TOURIST_ATTRACTION = 38,
  OC_POI_LEISURE_CENTRE = 39,
  OC_POI_LIBRARY = 40,
  OC_POI_NIGHTLIFE = 41,
  OC_POI_PARK_AND_RECREATION_AREA = 42,
  OC_POI_PHARMACY = 43,
  OC_POI_POST_OFFICE = 44,
  OC_POI_RENT_A_CAR_PARKING = 45,
  OC_POI_RESTAURANT = 46,
  OC_POI_RESTAURANT_AREA = 47,
  OC_POI_SHOP = 48,
  OC_POI_STADIUM = 49,
  OC_POI_TOURIST_INFORMATION_OFFICE = 50,
  OC_POI_MY_FAVOURITES = 94
};

typedef struct __OcDbPoiTile {
  uint16_t     unknownLength;  //zero
  //poi records
} OcDbPoiTile;


/* Maptxt tiles are just a series of coord, null-terminated string
pairs (like a poi but without the type field).  The string has a 
number of tab separated fields: place, region. */

typedef struct __OcDbMaptxtRelativeRecord {
  char             description[1]; //null terminated string
} OcDbMaptxtRelativeRecord;

typedef struct __OcDbMaptxtRecord {
  OcCoord          coord;
  char             description[1]; //null terminated string
} OcDbMaptxtRecord;

typedef struct __OcDbMaptxtTile {
  OcDbMaptxtRecord firstrecord;  
  //more maptxt records
} OcDbMaptxtTile;


#pragma pack(pop)