Line data Source code
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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "ogr_pmtiles.h"
30 :
31 : #include "vsipmtiles.h"
32 :
33 : #include "ogrpmtilesfrommbtiles.h"
34 :
35 : #ifdef HAVE_MVT_WRITE_SUPPORT
36 : #include "mvtutils.h"
37 : #endif
38 :
39 : /************************************************************************/
40 : /* OGRPMTilesDriverIdentify() */
41 : /************************************************************************/
42 :
43 40495 : static int OGRPMTilesDriverIdentify(GDALOpenInfo *poOpenInfo)
44 : {
45 40495 : if (poOpenInfo->nHeaderBytes < 127 || !poOpenInfo->fpL)
46 39853 : return FALSE;
47 642 : return memcmp(poOpenInfo->pabyHeader, "PMTiles\x03", 8) == 0;
48 : }
49 :
50 : /************************************************************************/
51 : /* OGRPMTilesDriverOpen() */
52 : /************************************************************************/
53 :
54 42 : static GDALDataset *OGRPMTilesDriverOpen(GDALOpenInfo *poOpenInfo)
55 : {
56 42 : if (!OGRPMTilesDriverIdentify(poOpenInfo))
57 0 : return nullptr;
58 84 : auto poDS = std::make_unique<OGRPMTilesDataset>();
59 42 : if (!poDS->Open(poOpenInfo))
60 8 : return nullptr;
61 34 : return poDS.release();
62 : }
63 :
64 : /************************************************************************/
65 : /* OGRPMTilesDriverCanVectorTranslateFrom() */
66 : /************************************************************************/
67 :
68 5 : static bool OGRPMTilesDriverCanVectorTranslateFrom(
69 : const char * /*pszDestName*/, GDALDataset *poSourceDS,
70 : CSLConstList papszVectorTranslateArguments, char ***ppapszFailureReasons)
71 : {
72 5 : auto poSrcDriver = poSourceDS->GetDriver();
73 5 : if (!(poSrcDriver && EQUAL(poSrcDriver->GetDescription(), "MBTiles")))
74 : {
75 1 : if (ppapszFailureReasons)
76 1 : *ppapszFailureReasons = CSLAddString(
77 : *ppapszFailureReasons, "Source driver is not MBTiles");
78 1 : return false;
79 : }
80 :
81 4 : if (papszVectorTranslateArguments)
82 : {
83 2 : const int nArgs = CSLCount(papszVectorTranslateArguments);
84 4 : for (int i = 0; i < nArgs; ++i)
85 : {
86 2 : if (i + 1 < nArgs &&
87 2 : (strcmp(papszVectorTranslateArguments[i], "-f") == 0 ||
88 0 : strcmp(papszVectorTranslateArguments[i], "-of") == 0))
89 : {
90 2 : ++i;
91 : }
92 : else
93 : {
94 0 : if (ppapszFailureReasons)
95 0 : *ppapszFailureReasons =
96 0 : CSLAddString(*ppapszFailureReasons,
97 : "Direct copy from MBTiles does not "
98 : "support GDALVectorTranslate() options");
99 0 : return false;
100 : }
101 : }
102 : }
103 :
104 4 : return true;
105 : }
106 :
107 : /************************************************************************/
108 : /* OGRPMTilesDriverVectorTranslateFrom() */
109 : /************************************************************************/
110 :
111 2 : static GDALDataset *OGRPMTilesDriverVectorTranslateFrom(
112 : const char *pszDestName, GDALDataset *poSourceDS,
113 : CSLConstList papszVectorTranslateArguments,
114 : GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
115 : {
116 2 : if (!OGRPMTilesDriverCanVectorTranslateFrom(
117 : pszDestName, poSourceDS, papszVectorTranslateArguments, nullptr))
118 : {
119 0 : return nullptr;
120 : }
121 :
122 2 : if (!OGRPMTilesConvertFromMBTiles(pszDestName,
123 2 : poSourceDS->GetDescription()))
124 : {
125 0 : return nullptr;
126 : }
127 :
128 4 : GDALOpenInfo oOpenInfo(pszDestName, GA_ReadOnly);
129 2 : return OGRPMTilesDriverOpen(&oOpenInfo);
130 : }
131 :
132 : #ifdef HAVE_MVT_WRITE_SUPPORT
133 : /************************************************************************/
134 : /* Create() */
135 : /************************************************************************/
136 :
137 34 : static GDALDataset *OGRPMTilesDriverCreate(const char *pszFilename, int nXSize,
138 : int nYSize, int nBandsIn,
139 : GDALDataType eDT,
140 : char **papszOptions)
141 : {
142 34 : if (nXSize == 0 && nYSize == 0 && nBandsIn == 0 && eDT == GDT_Unknown)
143 : {
144 68 : auto poDS = std::make_unique<OGRPMTilesWriterDataset>();
145 34 : if (!poDS->Create(pszFilename, papszOptions))
146 1 : return nullptr;
147 33 : return poDS.release();
148 : }
149 0 : return nullptr;
150 : }
151 : #endif
152 :
153 : /************************************************************************/
154 : /* RegisterOGRPMTiles() */
155 : /************************************************************************/
156 :
157 1522 : void RegisterOGRPMTiles()
158 : {
159 1522 : if (GDALGetDriverByName("PMTiles") != nullptr)
160 301 : return;
161 :
162 1221 : VSIPMTilesRegister();
163 :
164 1221 : GDALDriver *poDriver = new GDALDriver();
165 :
166 1221 : poDriver->SetDescription("PMTiles");
167 1221 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
168 1221 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ProtoMap Tiles");
169 1221 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "pmtiles");
170 1221 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
171 1221 : "drivers/vector/pmtiles.html");
172 :
173 1221 : poDriver->SetMetadataItem(
174 : GDAL_DMD_OPENOPTIONLIST,
175 : "<OpenOptionList>"
176 : " <Option name='ZOOM_LEVEL' type='integer' "
177 : "description='Zoom level of full resolution. If not specified, maximum "
178 : "non-empty zoom level'/>"
179 : " <Option name='CLIP' type='boolean' "
180 : "description='Whether to clip geometries to tile extent' "
181 : "default='YES'/>"
182 : " <Option name='ZOOM_LEVEL_AUTO' type='boolean' "
183 : "description='Whether to auto-select the zoom level for vector layers "
184 : "according to spatial filter extent. Only for display purpose' "
185 : "default='NO'/>"
186 : " <Option name='JSON_FIELD' type='boolean' "
187 : "description='For vector layers, "
188 : "whether to put all attributes as a serialized JSon dictionary'/>"
189 1221 : "</OpenOptionList>");
190 :
191 1221 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
192 :
193 1221 : poDriver->pfnOpen = OGRPMTilesDriverOpen;
194 1221 : poDriver->pfnIdentify = OGRPMTilesDriverIdentify;
195 1221 : poDriver->pfnCanVectorTranslateFrom =
196 : OGRPMTilesDriverCanVectorTranslateFrom;
197 1221 : poDriver->pfnVectorTranslateFrom = OGRPMTilesDriverVectorTranslateFrom;
198 :
199 : #ifdef HAVE_MVT_WRITE_SUPPORT
200 1221 : poDriver->SetMetadataItem(
201 : GDAL_DMD_CREATIONOPTIONLIST,
202 : "<CreationOptionList>"
203 : " <Option name='NAME' scope='raster,vector' type='string' "
204 : "description='Tileset name'/>"
205 : " <Option name='DESCRIPTION' scope='raster,vector' type='string' "
206 : "description='A description of the layer'/>"
207 : " <Option name='TYPE' scope='raster,vector' type='string-select' "
208 : "description='Layer type' default='overlay'>"
209 : " <Value>overlay</Value>"
210 : " <Value>baselayer</Value>"
211 1221 : " </Option>" MVT_MBTILES_PMTILES_COMMON_DSCO "</CreationOptionList>");
212 :
213 1221 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
214 1221 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
215 1221 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
216 1221 : "Integer Integer64 Real String");
217 1221 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES,
218 1221 : "Boolean Float32");
219 :
220 1221 : poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, MVT_LCO);
221 :
222 1221 : poDriver->pfnCreate = OGRPMTilesDriverCreate;
223 : #endif
224 :
225 1221 : GetGDALDriverManager()->RegisterDriver(poDriver);
226 : }
|