自從Google Earth 無法訪問后,作為開發者的我感同身受,非常理解那么同行們的感受。
好在我已經下載了全國的地圖數據,抱着一顆數據來源於網絡服務於網絡的心態,我把
我手上的全國Google Earth 19級數據免費的開放給大家,旨在能盡一點綿薄之力,避免
被那些不法之徒用來獲取暴利。
數據我已經上傳到百度雲盤:目前已經把全國33個省、直轄市、特別行政區數據已經完全
傳到網盤,總量約10T左右。
需要的朋友,可以通過微信搜索“JingWeiKuaiTu”微信號,獲取地圖。
當然如果有朋友特別急着用,也可以通過郵寄硬盤給到我這邊,我會把全國的數據一並copy到硬盤
在回寄回去。
關於文件格式
通常我們在工作中下載谷歌衛星影像數據時,輕則幾百M,重則幾百個G甚至上TB級。影像數據太大,是大家經常會遇到的一個問題,
尤其是向下載一個省以上數據的時候該問題尤為突出。那么該問題是否有一個比較好的解決方案呢?
以全球為例,我們以19級為例,共有2^18 * 2^17 張瓦片,如此多的瓦片會讓磁盤愈來愈慢,同時也無法維護。花費時間越來越長,最后不了了之。
當影像下載范圍比較大時,我們可以采用金字塔分塊下載的方式進行下載,系統會自動將大范圍分成若干個塊,且塊與塊之間是可以無縫拼接的。
一般情況我們選擇全球前10級別作為基礎級別,因數據量不大(越1G)左右,后續以10級作為基礎級別,
全球19級別數據被划分為 2^8 * 2^7(512 * 256)個塊。每個塊中包含了512 * 256 張小瓦片。
采用高效的索引方式進行存儲,全球前10級別的數據存儲成一個文件(.fepk),11-19級別存儲為n個文件。
例如全球第10級一共有 512 * 256 張瓦片(從第0級別開始計算),那么全球11-19級別會有512 * 256 個文件(.fepk)
文件格式開放
作為開發者深知每一家的地圖格式都不盡相同,都有自己的規則,我這里把文件的存儲格式開發給大家,起到拋磚引玉的左右
期待有更好的存儲格式出現,共同提升國內GIS水平。
1 FEPK文件格式說明
我們一般不會直接采用瓦片作為管理單元,會把一個塊作為管理單元,把數據划分為索引文件與數據文件,如下所示:
數據文件:world.fepk
索引文件:world.fepk.idx
1.1 索引文件
表 1字段說明
文件頭 |
字段 |
值 |
文件頭 |
char szMagic[20] |
fe.tile.store.data20字節 |
uint version |
版本號4字節 |
|
uint typeId |
數據類型 enumPKType { PK_IMAGE , PK_DEM, PK_VEC, PK_QXSY, PK_USER, };4字節 |
|
uint wgs84 |
是否是wgs84經緯投影4字節 |
|
uint flag |
4字節 |
|
uint64 timestamp |
時間戳8字節 |
|
real2 vStart |
經緯度最小范圍8*2字節 |
|
real2 vEnd |
經緯度最大范圍 8*2字節 |
|
LevSnaplevOff[24] |
級別索引,8 * 24 字節 |
|
char _reserve[240] |
保留 |
|
級別1 |
int2 _start |
2 * 4字節,瓦片最小行列號 |
int2 _end |
2 * 4字節,瓦片最大行列號 |
|
uint64 _offset |
8字節 |
|
uint64 _dataSize |
8字節 |
|
uint _lev |
4字節 |
|
char _reserve[216] |
216字節 |
|
瓦片數據索引矩陣數據PKTLHeader |
N * PKTLHeader N = (_end.x - _start.x + 1) * (_end.y - _start.y + 1) |
|
|
PKTLHeader |
|
級別2 |
|
|
級別3 |
|
|
級別… |
|
|
PKTLHeader定義:
struct PKTLHeader
{
/// 有無數據標記,即服務器上是否有該數據 0,無,1,有
uint64 _data:2;
/// 在本文件中是否已經存儲 0,無,1,有
uint64 _stored:2;
/// 狀態,
uint64 _state :6;
/// 數據地址,使用50個bit最大 2^54
/// 單個文件最大16 K T
uint64 _offset : 54;
/// 如果該值!= 0xFFFF,則有效,否則無效,
/// 使用該字段的意義在於解決網絡讀取問題,比如在雲盤上
/// 先讀取索引,如果沒有數據大小,或者數據大小存儲在數據文件中,則需要
/// 再次訪問數據文件,才可以得大小,增加額外的IO,同時兼顧大小,該變量最大可以存儲64K
/// 如果超過了64K,那么一樣的需要訪問數據文件獲取大小
ushort _dataSize;
};
共計10自字節
LevSnap定義:
struct LevSnap
{
uint64 _lev:8;
uint64 _offset:56;
};
共計8字節
1.2 數據文件文件
文件頭 |
字段 |
值 |
文件頭 |
char szMagic[20] |
fe.tile.store.data20字節 |
uint version |
版本號4字節 |
|
uint typeId |
數據類型 enumPKType { PK_IMAGE , PK_DEM, PK_VEC, PK_QXSY, PK_USER, };4字節 |
|
uint wgs84 |
是否是wgs84經緯投影4字節 |
|
uint flag |
4字節 |
|
uint64 timestamp |
時間戳8字節 |
|
real2 vStart |
經緯度最小范圍8*2字節 |
|
real2 vEnd |
經緯度最大范圍 8*2字節 |
|
LevSnaplevOff[24] |
級別索引,8 * 24 字節 |
|
char _reserve[240] |
保留 |
|
數據0 |
Int4 |
4*4字節,行號,列號,級別,大小 |
數據 |
|
|
數據1 |
Int4 |
4*4字節,行號,列號,級別,大小 |
數據 |
|
|
數據… |
Int4 |
4*4字節,行號,列號,級別,大小 |
數據 |
|
1.3 訪問SDK
為了方便大家使用數據,提供了C語言版本的SDK(x86/x64)兩個版本
#pragma once typedef void* FEPKFile; #pragma pack (push,1) /// 該文件不可以被修改 typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned __int64 uint64; struct FEPHHeader { /// 有無數據標記,即服務器上是否有該數據 0,無,1,有 uint64 _data : 2; /// 在本文件中是否已經存儲 0,無,1,有 uint64 _stored : 2; /// 狀態, uint64 _state : 6; /// 數據地址,使用50個bit最大 2^54 /// 單個文件最大16 K T uint64 _offset : 54; /// 如果該值!= 0xFFFF,則有效,否則無效, /// 使用該字段的意義在於解決網絡讀取問題,比如在雲盤上 /// 先讀取索引,如果沒有數據大小,或者數據大小存儲在數據文件中,則需要 /// 再次訪問數據文件,才可以得大小,增加額外的IO,同時兼顧大小,該變量最大可以存儲64K /// 如果超過了64K,那么一樣的需要訪問數據文件獲取大小 ushort _dataSize; }; #pragma pack(pop) extern "C" { /// <summary> /// 打開文件函數,可以打開索引也可以打開數據文件 /// </summary> /// <param name = "fileName">文件名稱</param> /// <return>0:失敗,否則成功</return> FEPKFile fepkOpenFile(const char* fileName); /// <summary> /// 讀取索引數據函數 /// </summary> /// <param name = "file">索引文件指針</param> /// <param name = "x">列號</param> /// <param name = "y">行號</param> /// <param name = "z">級別</param> /// <param name = "header">返回文件頭信息</param> /// <return>true:false</return> bool fepkReadHeader(FEPKFile file,int x,int y,int z,FEPHHeader* header); /// <summary> /// 根據文件頭信息讀取文件大小(瓦片數據大小) /// </summary> /// <param name = "file">索引文件指針</param> /// <param name = "header">文件頭信息</param> /// <param name = "pSize">輸出文件大小</param> /// <return>true:false</return> bool fepkReadDataSize(FEPKFile file,const FEPHHeader* header,uint* pSize); /// <summary> /// 讀取瓦片數據函數 /// </summary> /// <param name = "file">索引文件指針</param> /// <param name = "header">文件頭信息</param> /// <param name = "pBuf">輸入緩沖區大小</param> /// <param name = "nBufLen">緩沖區長度</param> /// <return> -1:失敗,0:無數據,>0 數據的真實大小</return> int fepkReadData(FEPKFile file,const FEPHHeader* header,void* pBuf,uint nBufLen); /// <summary> /// 關閉文件 /// </summary> void fepkCloseFile(FEPKFile file); /// <summary> /// 導出文件 /// </summary> /// <param name = "fileName">輸入緩沖區大小</param> /// <param name = "dir">目標文件夾</param> bool fepkExport(const char* fileName,const char* dir); /// <summary> /// 導出文件 /// </summary> /// <param name = "fileName">輸入緩沖區大小</param> /// <param name = "dir">目標文件夾</param> bool fepkExportWithLevs(const char* fileName, const char* dir,const unsigned* levs,unsigned levSize); } /// <summary> /// 使用說明 /// FEPKFile file = fepkOpenFile("x:/xx/yy/abc/world0-8.fepk"); /// if (file == nullptr) /// { /// return; /// } /// FEPHHeader header; /// uint nSize = 0; /// if(!fepkReadHeader(file,0,0,0,&header)) /// { /// return; /// } /// /// if(!fepkReadDataSize(file,&header,&nSize)) /// { /// return; /// } /// char* pBuf = new char[nSize]; /// if(!fepkReadData(file,&header,pBuf,nSize)) /// { /// delete []pBuf; /// } /// </summary>
1.4數據解包工具,即將.fepk數據解壓成標准的瓦片
上述文件文檔等數據都可以在QQ群中獲取
QQ群號(600975169)
二維碼:
掃碼分享到朋友圈: