项目RFC 4:远程访问网格和GeoTIFF网格

作者

即使是鲁奥,霍华德巴特勒

联系

即使是鲁奥@空间分析网站, howard@hobu.co

状态

采用

实施目标

项目7

最后更新

2020-01-10

动机

项目6通过依赖和应用项目数据库中的可用信息,在管理基准之间的坐标转换方面取得了不可否认的进步。PROJ从一个具有一点大地测量能力的地图投影库快速发展到一个完整的大地测量转换和描述环境,突出了支持数据的重要性。以尽可能少的占用空间、尽可能少的占用空间来交付用户所希望的软件。为了获得最高精度的结果,通常需要一个网格文件来定义提供尺寸偏移的模型。projdatumgrid项目将开放数据许可证下可用的网格集中起来,并将它们捆绑在沿世界主要地理区域划分的不同档案中。

假设PROJ用户下载并安装了PROJ数据库中引用的网格文件。这些文件的总量可能相当大,主要发行渠道对打包的支持有些不均衡,这是由于它们的大小、有时模棱两可的许可情况以及难以跟踪版本控制和沿袭。用户,尤其是那些不太熟悉大地测量操作的用户并不总是清楚,如果没有网格数据,最高精度的转换可能并不总是适用。用户既希望方便又希望正确,对轮班文件的管理对那些可能没有意识到其对流程重要性的人来说是一个挑战。

PROJ所处的计算环境也在发生变化。由于shift数据可能非常大(当前未压缩的数据超过700mb,而且还在增长),因此由于部署大小的限制(例如,无服务器操作),高精度操作的部署可能会受到限制。更改为支持通过网络进行增量访问以及方便的访问和压缩的传递格式,将减轻shift文件的资源负担,同时允许项目以测量组织提供的最高已知精度传递转换能力。

调整网格也倾向于以许多不同的格式提供,这取决于生成它们的组织和国家。在PROJ中,随着时间的推移,我们已经“标准化”使用水平移动网格作为NTv2,使用GTX使用垂直移动网格。两者都缺乏通用的支持,比如专用格式、有限的元数据功能,而且它们都不一定为跨网络的增量访问进行“云优化”。

本RFC计划的工作总结

  • 网格将由一个或多个内容交付网络(CDN)托管

  • 网格加载机制将被重新设计,以便能够从在线存储库下载网格或部分网格。当用户选择加入时,就不再需要手动获取网格文件并将它们放在PROJ_LIB中。软件的完整而准确的功能将不再需要预先准备数百兆字节的网格移位文件,即使用户所做的转换只需要其中的几兆字节。

  • 本地缓存网格文件,甚至部分文件,这样用户就可以镜像他们实际使用的内容。

  • 将为水平和垂直移动网格(以及在未来可能的步骤中,为其他需要,如变形模型)实施网格移动格式。

使用本地可用的网格当然仍然可用,并且将是默认行为。

电网接入

curl将是PROJ的可选构建依赖项,添加到autoconf和cmake构建系统中。可以在生成时禁用它,但这必须是configure/cmake的显式设置,因为生成的功能较少。当在构建时启用curl时,默认情况下在运行时不会启用网格本身的下载。它需要用户的明确同意,或者通过API (proj_context_set_enable_network() )通过PROJ_NETWORK=ON环境变量,或 network = on 设置项目ini.

关于所需的libcurl的最低版本,考虑到GDAL经验可以使用相当古老的libcurl构建类似的功能,我们可以将libcurl>=7.29.0作为目标(在rhel7中可用)。

如果没有内置对libcurl的支持,或者如果为了所需的使用环境,用户希望提供网络实现(典型的用例可能是QGIS,它将使用其基于Qt的网络设施来解决与SSL、代理、身份验证等有关的问题),则用户也可以设置替代的可插拔网络接口。

A text configuration file, installed in ${installation_prefix}/share/proj/proj.ini (or ${PROJ_LIB}/proj.ini) will contain the URL of the CDN that will be used. The user may also override this setting with the proj_context_set_url_endpoint() or through the PROJ_NETWORK_ENDPOINT environment variable.

提出项目ini在这个位置上,它是PROJ用户熟知的地方,现有的PROJu LIB机制适用于运行时硬编码路径通常不可用的Windows等系统。

计算机辅助编程接口

上述初步C API为:

/** Enable or disable network access.
*
* @param ctx PROJ context, or NULL
* @return TRUE if network access is possible. That is either libcurl is
*         available, or an alternate interface has been set.
*/
int proj_context_set_enable_network(PJ_CONTEXT* ctx, int enable);

/** Define URL endpoint to query for remote grids.
*
* This overrides the default endpoint in the PROJ configuration file or with
* the PROJ_NETWORK_ENDPOINT environment variable.
*
* @param ctx PROJ context, or NULL
* @param url Endpoint URL. Must NOT be NULL.
*/
void proj_context_set_url_endpoint(PJ_CONTEXT* ctx, const char* url);

/** Opaque structure for PROJ. Implementations might cast it to their
 * structure/class of choice. */
typedef struct PROJ_NETWORK_HANDLE PROJ_NETWORK_HANDLE;

/** Network access: open callback
*
* Should try to read the size_to_read first bytes at the specified offset of
* the file given by URL url,
* and write them to buffer. *out_size_read should be updated with the actual
* amount of bytes read (== size_to_read if the file is larger than size_to_read).
* During this read, the implementation should make sure to store the HTTP
* headers from the server response to be able to respond to
* proj_network_get_header_value_cbk_type callback.
*
* error_string_max_size should be the maximum size that can be written into
* the out_error_string buffer (including terminating nul character).
*
* @return a non-NULL opaque handle in case of success.
*/
typedef PROJ_NETWORK_HANDLE* (*proj_network_open_cbk_type)(
                                                    PJ_CONTEXT* ctx,
                                                    const char* url,
                                                    unsigned long long offset,
                                                    size_t size_to_read,
                                                    void* buffer,
                                                    size_t* out_size_read,
                                                    size_t error_string_max_size,
                                                    char* out_error_string,
                                                    void* user_data);

/** Network access: close callback */
typedef void (*proj_network_close_cbk_type)(PJ_CONTEXT* ctx,
                                            PROJ_NETWORK_HANDLE* handle,
                                            void* user_data);

/** Network access: get HTTP headers */
typedef const char* (*proj_network_get_header_value_cbk_type)(
                                            PJ_CONTEXT* ctx,
                                            PROJ_NETWORK_HANDLE* handle,
                                            const char* header_name,
                                            void* user_data);

/** Network access: read range
*
* Read size_to_read bytes from handle, starting at offset, into
* buffer.
* During this read, the implementation should make sure to store the HTTP
* headers from the server response to be able to respond to
* proj_network_get_header_value_cbk_type callback.
*
* error_string_max_size should be the maximum size that can be written into
* the out_error_string buffer (including terminating nul character).
*
* @return the number of bytes actually read (0 in case of error)
*/
typedef size_t (*proj_network_read_range_type)(
                                            PJ_CONTEXT* ctx,
                                            PROJ_NETWORK_HANDLE* handle,
                                            unsigned long long offset,
                                            size_t size_to_read,
                                            void* buffer,
                                            size_t error_string_max_size,
                                            char* out_error_string,
                                            void* user_data);

/** Define a custom set of callbacks for network access.
*
* All callbacks should be provided (non NULL pointers).
*
* @param ctx PROJ context, or NULL
* @param open_cbk Callback to open a remote file given its URL
* @param close_cbk Callback to close a remote file.
* @param get_header_value_cbk Callback to get HTTP headers
* @param read_range_cbk Callback to read a range of bytes inside a remote file.
* @param user_data Arbitrary pointer provided by the user, and passed to the
* above callbacks. May be NULL.
* @return TRUE in case of success.
*/
int proj_context_set_network_callbacks(
    PJ_CONTEXT* ctx,
    proj_network_open_cbk_type open_cbk,
    proj_network_close_cbk_type close_cbk,
    proj_network_get_header_value_cbk_type get_header_value_cbk,
    proj_network_read_range_type read_range_cbk,
    void* user_data);

为了提高网络访问的效率,Proj将在内部拥有一个文件范围的内存缓存,以便只发出16KB或更多的块的网络请求,以限制HTTP GET请求的数量,并将网络访问造成的延迟降至最低。这与GDAL的行为非常相似 /vsicurl/ I/O层。该计划主要是在Proj中复制GDAL的vsicurl实现,并对其进行必要的调整和适当的命名空间。

将添加重试策略(通常是具有指数后退和一些随机抖动的延迟)来说明间歇性网络或服务器端故障。

URL生成

项目数据库有一个 grid_transformation 网格的列 grid_name (可能的话) grid2_name )包含已注册转换的机构(通常是EPSG)指示的网格名称。由于PROJ通常不能直接使用这些网格名称,因此PROJ数据库也有一个 grid_alternatives 将原始网格名称链接到项目使用的网格名称的表。当由于缺少本地网格而需要网络访问时,完整的URL将是配置中的端点或用户设置的端点、项目可用文件名的基名称和“tif”后缀。所以如果CDN在http://example.com和名字来自 grid_alternatives 如果是egm96_.gtx,则URL将是http://example.com/egm96_.tif

网格加载

以下文件将以某种方式受到上述更改的影响:nad_cvt.cpp公司,北美_内部cpp,北美_初始化.cpp,网格_信息.cpp,网格_列表.cpp,应用_gridshift.cpp文件,应用_vgridshift.cpp文件.

尤其是当前的逻辑,包括在ct->cvs数组中摄取一个网格/子网格的所有值,将被完全修改,以允许在指定的(x,y)位置访问网格值。

proju create u crs u to u crs()/proju create u operations()影响

一旦网络接入可用,在计算两个CR之间的潜在管道时,将假定项目数据库(网格转换+网格替代表)已知的所有网格都可用。

具体来说,这将相当于调用 proj_operation_factory_context_set_grid_availability_use()use 参数设置为新的枚举值

/** Results will be presented as if grids known to PROJ (that is
* registered in the grid_alternatives table of its database) were
* available. Used typically when networking is enabled.
*/
PROJ_GRID_AVAILABILITY_KNOWN_AVAILABLE

远程网格的本地磁盘缓存

由于许多工作流将倾向于反复使用相同的网格,因此将添加远程网格的本地磁盘缓存。缓存将是一个SQLite3数据库,位于所有使用PROJ的应用程序共享的用户可写目录中。

它的总大小是可配置的,默认最大大小为100MB项目ini. 缓存还将保留上次检查文件的各种全局属性(大小、上次修改和ETag头)的时间戳。生存时间参数,默认值为1天项目ini,将用于确定是否应命中CDN以验证缓存中的信息是否仍然是最新的。

/** Enable or disable the local cache of grid chunks
*
* This overrides the setting in the PROJ configuration file.
*
* @param ctx PROJ context, or NULL
* @param enabled TRUE if the cache is enabled.
*/
void proj_grid_cache_set_enable(PJ_CONTEXT *ctx, int enabled);

/** Override, for the considered context, the path and file of the local
* cache of grid chunks.
*
* @param ctx PROJ context, or NULL
* @param fullname Full name to the cache (encoded in UTF-8). If set to NULL,
*                 caching will be disabled.
*/
void proj_grid_cache_set_filename(PJ_CONTEXT* ctx, const char* fullname);

/** Override, for the considered context, the maximum size of the local
* cache of grid chunks.
*
* @param ctx PROJ context, or NULL
* @param max_size_MB Maximum size, in mega-bytes (1024*1024 bytes), or
*                    negative value to set unlimited size.
*/
void proj_grid_cache_set_max_size(PJ_CONTEXT* ctx, int max_size_MB);

/** Override, for the considered context, the time-to-live delay for
* re-checking if the cached properties of files are still up-to-date.
*
* @param ctx PROJ context, or NULL
* @param ttl_seconds Delay in seconds. Use negative value for no expiration.
*/
void proj_grid_cache_set_ttl(PJ_CONTEXT* ctx, int ttl_seconds);

/** Clear the local cache of grid chunks.
 *
 * @param ctx PROJ context, or NULL.
 */
void proj_grid_cache_clear(PJ_CONTEXT* ctx);

计划的数据库结构是:

-- General properties on a file
CREATE TABLE properties(
 url          TEXT PRIMARY KEY NOT NULL,
 lastChecked  TIMESTAMP NOT NULL,
 fileSize     INTEGER NOT NULL,
 lastModified TEXT,
 etag         TEXT
);

-- Store chunks of data. To avoid any potential fragmentation of the
-- cache, the data BLOB is always set to the maximum chunk size of 16 KB
-- (right padded with 0-byte)
-- The actual size is stored in chunks.data_size
CREATE TABLE chunk_data(
 id        INTEGER PRIMARY KEY AUTOINCREMENT CHECK (id > 0),
 data      BLOB NOT NULL
);

-- Record chunks of data by (url, offset)
CREATE TABLE chunks(
 id        INTEGER PRIMARY KEY AUTOINCREMENT CHECK (id > 0),
 url       TEXT NOT NULL,
 offset    INTEGER NOT NULL,
 data_id   INTEGER NOT NULL,
 data_size INTEGER NOT NULL,
 CONSTRAINT fk_chunks_url FOREIGN KEY (url) REFERENCES properties(url),
 CONSTRAINT fk_chunks_data FOREIGN KEY (data_id) REFERENCES chunk_data(id)
);
CREATE INDEX idx_chunks ON chunks(url, offset);

-- Doubly linked list of chunks. The next link is to go to the least-recently
-- used entries.
CREATE TABLE linked_chunks(
 id        INTEGER PRIMARY KEY AUTOINCREMENT CHECK (id > 0),
 chunk_id  INTEGER NOT NULL,
 prev      INTEGER,
 next      INTEGER,
 CONSTRAINT fk_links_chunkid FOREIGN KEY (chunk_id) REFERENCES chunks(id),
 CONSTRAINT fk_links_prev FOREIGN KEY (prev) REFERENCES linked_chunks(id),
 CONSTRAINT fk_links_next FOREIGN KEY (next) REFERENCES linked_chunks(id)
);
CREATE INDEX idx_linked_chunks_chunk_id ON linked_chunks(chunk_id);

-- Head and tail pointers of the linked_chunks. The head pointer is for
-- the most-recently used chunk.
-- There should be just one row in this table.
CREATE TABLE linked_chunks_head_tail(
  head       INTEGER,
  tail       INTEGER,
  CONSTRAINT lht_head FOREIGN KEY (head) REFERENCES linked_chunks(id),
  CONSTRAINT lht_tail FOREIGN KEY (tail) REFERENCES linked_chunks(id)
);
INSERT INTO linked_chunks_head_tail VALUES (NULL, NULL);

chunks表将存储16kb的块(或更少的终止块)。链接的u块和链接的u块u头u尾表swill充当块的双链接列表,最近使用最少的块位于列表的末尾,当缓存饱和时,这些块将被逐出。

用于定位此数据库的目录将是${XDGu DATAu HOME}/proj(perhttps://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)其中${XDGu DATAu HOME}在Unix版本上默认为${HOME}/.local/share,在Windows版本上默认为${LOCALAPPDATA}。具体细节有待理清,但https://github.com/ActiveState/appdirs/blob/a54ea98feed0a7593475b94de3a359e9e1fe8fdb/appdirs.py#L45-L97可以作为一个很好的参考。

由于该数据库可能同时被多个线程或进程访问,因此访问该数据库的代码将仔细考虑与锁有关的SQLite3错误,以便在另一个线程/进程当前锁定该数据库时进行适当的重试。需要修改数据库的访问将从BEGIN IMMEDIATE事务开始,以便获得写锁定。

备注

此数据库应托管在本地磁盘上,而不是网络磁盘上。否则,SQLite3锁定问题是意料之中的。

CDN提供商

Amazon Public Datasets 已提出成为存储和CDN提供商。

该计划涵盖存储和出口(带宽)的数据。他们通常不允许将CloudFront(他们的CDN)作为程序的一部分使用(我们通常会希望它包含在credits中),但在这种情况下,他们可以提供它。“cloudd”只要求用户在最前面的位置查看数据。他们的条件可以在https://aws.amazon.com/service-terms/CloudFront有自己的小部分。这些术语可能会不时发生一些变化,以作细微的改动。服务条款的重大变化被认为是不常见的。还有公共数据集程序术语http://aws.amazon.com/public datasets/terms/。这些也不会随着时间的推移而有效地改变,而是在2年的基础上更新。

网格托管标准

承载在CDN上的网格将完全是当前和将来由 proj-datumgrid 主动权。特别是,只要新网格是根据与 Open Source Definition 网格的来源是明确的和可验证的。合适的许可证包括:

  • 公共领域

  • X/麻省理工学院

  • BSD 2/3/4条款

  • 立方厘米

  • CC-BY(v3.0或更高版本)

  • CC-BY-SA(v3.0或更高版本)

为了让proju createu crsu to u crs()机制透明地使用新网格,必须在proj数据库中注册它们(项目数据库)在 grid_transformationgrid_alternatives 桌子。在gridu转换中有一个新记录的标称路径是在EPSG数据集中注册一个转换(如果没有现有的转换),该转换随后将导入PROJ数据库。

版本控制,网格的历史保存

与此相关的政策应与适用于 proj-datumgrid ,即使没有正式化,也有以下几行:

  • 大地测量机构定期发布新版网格。通常在美国,NOAA发布了GEOID99、GEOID03、GEOID06、GEOID09、GEOID12A、GEOID12B、GEOID18,用于NAVD88至NAD83/NAD83(2011)垂直调整。每个网格都由EPSG考虑,PROJ有一个单独的对象,具有不同的文件名。新版本的发布不会导致旧网格被自动删除。这就是说,由于EPSG数据集的广为人知的精度和替换规则,如果用户使用proj_create_CRS_to_CRS(),则最新的网格通常将用于CRS->CRS转换(如果VERT_CRS WKT包括proj已知的大地水准面模型,则将使用网格的旧版本)。如果用户用一个显式的网格名称指定了一个完整的管道,那么它当然会得到严格遵守。随着时间的推移,projdatumgrid管理的数据集的大小将不断增加,我们将不得不探索我们为distributed.zip/管理的数据集。焦油.gz档案。这不应该是CDN托管内容的问题。

  • 如果发生从原始网格格式到PROJ使用的网格格式(无论是GTX、NTv2还是GeoTIFF)的软件相关转换错误,数据集的先前错误版本将替换为已更正的版本。在这种情况下,这可能会对远程网格的本地磁盘缓存产生影响。我们必须看看CDN提供者是否可以使用例如客户端上的ETAGHTTP头来检测更改,以便旧的缓存内容不会被错误地重用(如果不可能,我们必须使用一些文本文件列出网格名称和它们当前的md5sum)

GeoTIFF格式的栅格

当前格式的限制

根据原始数据生产者的特殊需要和想法,存在几种格式。最好集中在一个能够处理不同用例的通用格式上。

  • 没有平铺。平铺对于云友好地访问大型文件来说是一个很好的特性。

  • 不支持压缩

  • NTv2结构大致为:主网格头、主网格头、子网格头1、子网格头1、子网格头2、子网格头2、子网格头2、子网格头1、子网格头1、子网格头1、子网格头1、子网格头1、子网格头2、子网格头2、子网格头1、子网格头1、子网格头2、子网格头2,到期等对于分散在文件中的头,不可能用一个httpget请求来检索所有头信息。

  • GTX格式除了网格的最小地理参考之外,没有存储元数据的规定。NTv2有点丰富,但是没有可扩展的元数据。

论格式的选择

我们最近了解到,业界还提出了其他倡议,要求采用一种通用格式来存储大地测量平差数据。OGC CRS工作组最近进行了一些讨论。过去的工作包括Esri提出的大地测量数据网格交换格式GGXF,在第86页(共页)中简要提及https://iag.dgfi.tum.de/fileadmin/iag-docs/Travaux2015/01u Travauxu Templateu Commu 1u tvd.pdf和第66页ftp://ftp.iaspei.org/pub/meetings/2010-2019/2015-Prague/IAG-geomethy.pdf这些作品目前的趋势是使用netCDF/HDF5容器。

因此,为了完整性,我们在下面列出一些潜在的候选格式及其优缺点。

TIFF/地理TIFF

优点:

  • TIFF是一种广为人知的格式。

  • GeoTIFF编码是一种广泛支持的编码地理参考的方案。它现在是一个 OGC standard

  • 有一些独立的计划将网格作为GeoTIFF共享,比如 that one

  • TIFF可以包含链接在一起的多个图像(IFD:Image File Directory)。这是用于多页扫描TIFF文件的机制,或在地理空间字段中用于存储多分辨率/棱锥栅格。因此,它可以与NTv2格式的子网格一起使用。

  • 对TIFF格式有丰富的经验,以及它对网络访问的适当性,特别是通过 Cloud Optimized GeoTIFF initiative 它的布局可以从网络访问的角度有效地利用子网格,因为网格头可以放在文件的开头,因此可以在单个httpget请求中检索。

  • TIFF可以平铺。

  • 可以压缩TIFF。常见的压缩格式是DEFALATE、LZW和差分整数或浮点预测器

  • TIFF图像可以包含可配置数量的通道/波段/样本。在文档的其余部分,我们将使用这个概念的示例术语。

  • 可以配置TIFF样本组织:将不同样本的值打包在一起 (PlanarConfiguration =Contig),或放在单独的瓷砖/条带中(平面配置=单独)

  • libtiff是PROJ所属的“生态系统”的二进制分布中常见的依赖项

  • libtiff得益于多年来提高其安全性的努力,例如被集成到oss fuzz计划中。考虑到网格的潜在获取,使用经过安全测试的组件是一个重要的问题。

  • 浏览器端:浏览器中有libtiff/libgeotiff的“端口”,如https://geotiffjs.github.io/这可能会使港口项目更容易。

弱点:

  • 我们不能使用libgeotiff,因为它依赖于PROJ(从EPSG代码中解析CRS或CRS的组件)。也就是说,对于PROJ的预期用途,我们只需要解码ModelTiepointTag和ModelPixelScaleTag TIFF标记,这样就可以“在手边”完成

  • TIFF基线的元数据功能是有限的。TIFF格式附带了一组预定义的元数据项,这些元数据项的键具有数值。也就是说,GDAL在过去的20年左右使用了一个专用标签, GDAL_METADATA 一种代码42112,它包含一个XML格式的字符串,能够存储任意的密钥对值。

netCDF第3版

优点:

  • 中给出的二进制格式说明 OGC 10-092r3 是相对简单的,但是可能仍然需要使用libnetcdf-c来访问它

  • 元数据可以很容易地存储在netCDF属性中

弱点:

  • netCDF v3中没有压缩

  • netCDF v3中没有平铺

  • 多个样本变量位于文件的不同部分(对应于TIFF PlanarConfiguration=Separate)

  • 没有一种自然的方式拥有分层/多网格。它们必须编码为单独的变量

  • netCDF中的地理参考比TIFF/GeoTIFF标准化程度要低一些。通常使用的模型是 the conventions for CF (Climate and Forecast) metadata 但是对于用左上角像素的坐标和分辨率进行简单的地理参考,它们并没有什么真正有用的。实践是用网格获取的所有值编写显式lon和lat变量。GDAL多年来一直支持使用GeoTransform属性的更简单语法。

  • 从格式描述来看,它的布局可能相对云友好,只是libnetcdf没有用于插入备用I/O层的API。

  • 现在大多数netCDF的二进制发行版都基于libnetcdf4,这意味着HDF5依赖性。

  • 根据几年前我们发现的一些关于损坏数据集崩溃的问题,我们联系了libnetcdf upstream,但他们似乎对解决这些安全问题不感兴趣。

netCDF v4/HDF5

注:netcdf4格式是HDF5文件格式的一个配置文件。

优点:

  • 支持压缩(ZLIB和SZIP预定义)

  • 支持平铺(分块)

  • 通过使用复合数据类型,可以将多个样本变量的值交错在一起(类似于TIFF PlanarConfiguration=Contig)。

  • 带组的层级组织

  • 虽然netcdfapi不提供备用I/O层,但hdf5api也可以这样做。

  • 网格可以索引超过2个维度(对于当前的需要,我们不需要超过2D的支持)

弱点:

  • 这个 HDF 5 File format 比NetCDFv3更复杂,也可能比TIFF更复杂。我们没有深入的it专业知识来评估它的云友好性。

  • netcdf3中提到的关于地理参考和安全性的内容适用。

GeoPackage

由于PROJ已经有了一个SQLite3依赖项,GeoPackage可以作为一个潜在的解决方案进行检查。

优点:

  • SQLite3依赖项

  • OGC标准

  • 多网格功能

  • 平铺

  • 压缩

  • 元数据功能

弱点:

  • GeoPackage主要处理RGB(A)字节用例,或者通过tile网格数据扩展,处理单样本非字节数据。本机不支持多样本非字节数据:每个样本应放在单独的栅格表中。

  • 经验表明,SQLite3布局(至少是使用标准libsqlite3时采用的布局)不是云友好的。索引可能分散在文件的不同位置。

结论

关于我们的目标和限制的两个主要竞争者是GeoTIFF和HDF5。鉴于过去的积极经验和悠久的历史,GeoTIFF仍然是我们的首选。

格式说明

格式说明以专用格式提供 大地TIFF网格(GTG) 文件。

工装

将开发一个脚本,以接受单个网格的列表,将其组合到一个文件中。

一个ntv2到_gtiff.py公司将创建便利脚本,将NTv2网格(包括其子网格)转换为上述GeoTIFF布局。

将创建一个验证Python脚本来检查文件是否满足上述要求和建议。

生成要求

libtiff的最低版本是4.0(rhel7附带libtiff 4.0.3)。为了能够读取存储在CDN上的网格,libtiff需要在zlib的基础上构建DEFLATE和LZW支持,这是libtiff的所有已知二进制发行版所能满足的。

可以在生成时禁用libtiff依赖项,但这必须是configure/cmake的显式设置,因为生成的功能较少。

删除网格目录功能

在挖掘现有代码时,我或多或少地发现PROJ代码库有网格目录的概念。这显然是由使用+目录触发的特性=somefilename.csv文件名在PROJ字符串中,CSV文件列出了网格名称、它们的范围、优先级和日期。它似乎是对多个网格使用+nadgrids的一种替代方法,如果提供了+date参数并且网格目录中提到了每个网格的日期,那么它还具有在多个网格之间插入移位值的额外能力。2012年6月根据 commit fcb186942ec8532655ff6cf4cc990e5da669a3bc

大多数用户可能不知道此功能,因为没有已知的文档(既不在当前文档中,也不在中) historic one ). 它既没有经过PROJ测试,也没有经过PROJ测试,因此其工作状态未知。如果将其删除,可能会使RFC的实现更容易。这将导致网格目录.cpp和gc_阅读器.cpp文件、它们的调用位置以及PJ结构中的catalogu name和datumu date参数。

如果需要类似的功能,以后可能会将其作为一种额外的功能模式重新引入 水平网格移动 ,或使用专用转换方法,类似于 利用变形模型进行动态基准移动 一个,可能是将几个网格组合在一起,在同一个文件中插入一个日期元数据项。

向后兼容性问题

除了删除(可能很少使用)网格目录功能之外,没有人预料到。

文档

  • 将记录新的API函数。

  • 将创建一个专用的文档页来解释基于网络的访问的工作原理。

  • 将创建一个专用文档页来描述基于GeoTIFF的网格格式。主要是重复使用上述材料。

测试

将测试GeoTIFF配方的数量(平铺与未平铺、平面配置单独与重叠、数据类型、比例+偏移与否等)。

对于网络能力的测试,将使用对CDN的真实点击和使用备用可插拔网络接口来测试边缘情况的混合。

拟议实施

建议的实施可在https://github.com/OSGeo/PROJ/pull/1817

工具脚本当前可在https://github.com/rouault/sampleu proju gtiffu grids/(最终将存储在项目存储库中)

收养状况

RFC于2020年1月10日通过,由以下PSC成员提供+1

  • 克里斯蒂安·埃弗斯

  • 甚至鲁奥

  • 托马斯·克努森

  • 霍华德巴特勒

  • 库尔特·施韦尔