/src/gdal/ogr/ogrsf_frmts/pmtiles/ogrpmtilesdriver.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implementation of PMTiles |
5 | | * Author: Even Rouault <even.rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2023, Planet Labs |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogr_pmtiles.h" |
14 | | |
15 | | #include "vsipmtiles.h" |
16 | | |
17 | | #include "ogrpmtilesfrommbtiles.h" |
18 | | |
19 | | #ifdef HAVE_MVT_WRITE_SUPPORT |
20 | | #include "mvtutils.h" |
21 | | #endif |
22 | | |
23 | | /************************************************************************/ |
24 | | /* OGRPMTilesDriverIdentify() */ |
25 | | /************************************************************************/ |
26 | | |
27 | | static int OGRPMTilesDriverIdentify(GDALOpenInfo *poOpenInfo) |
28 | 79.9k | { |
29 | 79.9k | if (poOpenInfo->nHeaderBytes < 127 || !poOpenInfo->fpL) |
30 | 45.0k | return FALSE; |
31 | 34.9k | return memcmp(poOpenInfo->pabyHeader, "PMTiles\x03", 8) == 0; |
32 | 79.9k | } |
33 | | |
34 | | /************************************************************************/ |
35 | | /* OGRPMTilesDriverOpen() */ |
36 | | /************************************************************************/ |
37 | | |
38 | | static GDALDataset *OGRPMTilesDriverOpen(GDALOpenInfo *poOpenInfo) |
39 | 137 | { |
40 | 137 | if (!OGRPMTilesDriverIdentify(poOpenInfo)) |
41 | 0 | return nullptr; |
42 | 137 | auto poDS = std::make_unique<OGRPMTilesDataset>(); |
43 | 137 | if (!poDS->Open(poOpenInfo)) |
44 | 115 | return nullptr; |
45 | 22 | return poDS.release(); |
46 | 137 | } |
47 | | |
48 | | /************************************************************************/ |
49 | | /* OGRPMTilesDriverCanVectorTranslateFrom() */ |
50 | | /************************************************************************/ |
51 | | |
52 | | static bool OGRPMTilesDriverCanVectorTranslateFrom( |
53 | | const char * /*pszDestName*/, GDALDataset *poSourceDS, |
54 | | CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons) |
55 | 0 | { |
56 | 0 | auto poSrcDriver = poSourceDS->GetDriver(); |
57 | 0 | if (!(poSrcDriver && EQUAL(poSrcDriver->GetDescription(), "MBTiles"))) |
58 | 0 | { |
59 | 0 | if (ppapszFailureReasons) |
60 | 0 | *ppapszFailureReasons = CSLAddString( |
61 | 0 | *ppapszFailureReasons, "Source driver is not MBTiles"); |
62 | 0 | return false; |
63 | 0 | } |
64 | | |
65 | 0 | if (papszVectorTranslateArguments) |
66 | 0 | { |
67 | 0 | const int nArgs = CSLCount(papszVectorTranslateArguments); |
68 | 0 | for (int i = 0; i < nArgs; ++i) |
69 | 0 | { |
70 | 0 | if (i + 1 < nArgs && |
71 | 0 | (strcmp(papszVectorTranslateArguments[i], "-f") == 0 || |
72 | 0 | strcmp(papszVectorTranslateArguments[i], "-of") == 0)) |
73 | 0 | { |
74 | 0 | ++i; |
75 | 0 | } |
76 | 0 | else |
77 | 0 | { |
78 | 0 | if (ppapszFailureReasons) |
79 | 0 | *ppapszFailureReasons = |
80 | 0 | CSLAddString(*ppapszFailureReasons, |
81 | 0 | "Direct copy from MBTiles does not " |
82 | 0 | "support GDALVectorTranslate() options"); |
83 | 0 | return false; |
84 | 0 | } |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | 0 | return true; |
89 | 0 | } |
90 | | |
91 | | /************************************************************************/ |
92 | | /* OGRPMTilesDriverVectorTranslateFrom() */ |
93 | | /************************************************************************/ |
94 | | |
95 | | static GDALDataset *OGRPMTilesDriverVectorTranslateFrom( |
96 | | const char *pszDestName, GDALDataset *poSourceDS, |
97 | | CSLConstList papszVectorTranslateArguments, |
98 | | GDALProgressFunc /* pfnProgress */, void * /* pProgressData */) |
99 | 0 | { |
100 | 0 | if (!OGRPMTilesDriverCanVectorTranslateFrom( |
101 | 0 | pszDestName, poSourceDS, papszVectorTranslateArguments, nullptr)) |
102 | 0 | { |
103 | 0 | return nullptr; |
104 | 0 | } |
105 | | |
106 | 0 | if (!OGRPMTilesConvertFromMBTiles(pszDestName, |
107 | 0 | poSourceDS->GetDescription())) |
108 | 0 | { |
109 | 0 | return nullptr; |
110 | 0 | } |
111 | | |
112 | 0 | GDALOpenInfo oOpenInfo(pszDestName, GA_ReadOnly); |
113 | 0 | return OGRPMTilesDriverOpen(&oOpenInfo); |
114 | 0 | } |
115 | | |
116 | | #ifdef HAVE_MVT_WRITE_SUPPORT |
117 | | /************************************************************************/ |
118 | | /* Create() */ |
119 | | /************************************************************************/ |
120 | | |
121 | | static GDALDataset *OGRPMTilesDriverCreate(const char *pszFilename, int nXSize, |
122 | | int nYSize, int nBandsIn, |
123 | | GDALDataType eDT, |
124 | | CSLConstList papszOptions) |
125 | | { |
126 | | if (nXSize == 0 && nYSize == 0 && nBandsIn == 0 && eDT == GDT_Unknown) |
127 | | { |
128 | | auto poDS = std::make_unique<OGRPMTilesWriterDataset>(); |
129 | | if (!poDS->Create(pszFilename, papszOptions)) |
130 | | return nullptr; |
131 | | return poDS.release(); |
132 | | } |
133 | | return nullptr; |
134 | | } |
135 | | #endif |
136 | | |
137 | | /************************************************************************/ |
138 | | /* RegisterOGRPMTiles() */ |
139 | | /************************************************************************/ |
140 | | |
141 | | void RegisterOGRPMTiles() |
142 | 22 | { |
143 | 22 | if (GDALGetDriverByName("PMTiles") != nullptr) |
144 | 0 | return; |
145 | | |
146 | 22 | VSIPMTilesRegister(); |
147 | | |
148 | 22 | GDALDriver *poDriver = new GDALDriver(); |
149 | | |
150 | 22 | poDriver->SetDescription("PMTiles"); |
151 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); |
152 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ProtoMap Tiles"); |
153 | 22 | poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "pmtiles"); |
154 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, |
155 | 22 | "drivers/vector/pmtiles.html"); |
156 | | |
157 | 22 | poDriver->SetMetadataItem( |
158 | 22 | GDAL_DMD_OPENOPTIONLIST, |
159 | 22 | "<OpenOptionList>" |
160 | 22 | " <Option name='ZOOM_LEVEL' type='integer' " |
161 | 22 | "description='Zoom level of full resolution. If not specified, maximum " |
162 | 22 | "non-empty zoom level'/>" |
163 | 22 | " <Option name='CLIP' type='boolean' " |
164 | 22 | "description='Whether to clip geometries to tile extent' " |
165 | 22 | "default='YES'/>" |
166 | 22 | " <Option name='ZOOM_LEVEL_AUTO' type='boolean' " |
167 | 22 | "description='Whether to auto-select the zoom level for vector layers " |
168 | 22 | "according to spatial filter extent. Only for display purpose' " |
169 | 22 | "default='NO'/>" |
170 | 22 | " <Option name='JSON_FIELD' type='boolean' " |
171 | 22 | "description='For vector layers, " |
172 | 22 | "whether to put all attributes as a serialized JSon dictionary'/>" |
173 | 22 | "</OpenOptionList>"); |
174 | | |
175 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
176 | | |
177 | 22 | poDriver->pfnOpen = OGRPMTilesDriverOpen; |
178 | 22 | poDriver->pfnIdentify = OGRPMTilesDriverIdentify; |
179 | 22 | poDriver->pfnCanVectorTranslateFrom = |
180 | 22 | OGRPMTilesDriverCanVectorTranslateFrom; |
181 | 22 | poDriver->pfnVectorTranslateFrom = OGRPMTilesDriverVectorTranslateFrom; |
182 | | |
183 | | #ifdef HAVE_MVT_WRITE_SUPPORT |
184 | | poDriver->SetMetadataItem( |
185 | | GDAL_DMD_CREATIONOPTIONLIST, |
186 | | "<CreationOptionList>" |
187 | | " <Option name='NAME' scope='raster,vector' type='string' " |
188 | | "description='Tileset name'/>" |
189 | | " <Option name='DESCRIPTION' scope='raster,vector' type='string' " |
190 | | "description='A description of the layer'/>" |
191 | | " <Option name='TYPE' scope='raster,vector' type='string-select' " |
192 | | "description='Layer type' default='overlay'>" |
193 | | " <Value>overlay</Value>" |
194 | | " <Value>baselayer</Value>" |
195 | | " </Option>" MVT_MBTILES_PMTILES_COMMON_DSCO "</CreationOptionList>"); |
196 | | |
197 | | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); |
198 | | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); |
199 | | poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, |
200 | | "Integer Integer64 Real String"); |
201 | | poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, |
202 | | "Boolean Float32"); |
203 | | |
204 | | poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, MVT_LCO); |
205 | | |
206 | | poDriver->pfnCreate = OGRPMTilesDriverCreate; |
207 | | #endif |
208 | | |
209 | 22 | GetGDALDriverManager()->RegisterDriver(poDriver); |
210 | 22 | } |