1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: KmlSuperOverlay
5 : * Purpose: Implements write support for KML superoverlay - KMZ.
6 : * Author: Harsh Govind, harsh.govind@spadac.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, SPADAC Inc. <harsh.govind@spadac.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "kmlsuperoverlaydataset.h"
31 :
32 : #include <cmath> /* fabs */
33 : #include <cstring> /* strdup */
34 : #include <iostream>
35 : #include <sstream>
36 : #include <math.h>
37 : #include <algorithm>
38 : #include <fstream>
39 :
40 : #include "cpl_error.h"
41 : #include "cpl_string.h"
42 : #include "cpl_conv.h"
43 : #include "cpl_vsi.h"
44 : #include "ogr_spatialref.h"
45 :
46 : using namespace std;
47 :
48 : /************************************************************************/
49 : /* GenerateTiles() */
50 : /************************************************************************/
51 38 : void GenerateTiles(std::string filename,
52 : int zoom, int rxsize,
53 : int rysize, int ix, int iy,
54 : int rx, int ry, int dxsize,
55 : int dysize, int bands,
56 : GDALDataset* poSrcDs,
57 : GDALDriver* poOutputTileDriver,
58 : GDALDriver* poMemDriver,
59 : bool isJpegDriver)
60 : {
61 38 : GDALDataset* poTmpDataset = NULL;
62 38 : GDALRasterBand* alphaBand = NULL;
63 :
64 38 : GByte* pafScanline = new GByte[dxsize];
65 38 : bool* hadnoData = new bool[dxsize];
66 :
67 38 : if (isJpegDriver && bands == 4)
68 2 : bands = 3;
69 :
70 38 : poTmpDataset = poMemDriver->Create("", dxsize, dysize, bands, GDT_Byte, NULL);
71 :
72 38 : if (isJpegDriver == false)//Jpeg dataset only has one or three bands
73 : {
74 2 : if (bands < 4)//add transparency to files with one band or three bands
75 : {
76 2 : poTmpDataset->AddBand(GDT_Byte);
77 2 : alphaBand = poTmpDataset->GetRasterBand(poTmpDataset->GetRasterCount());
78 : }
79 : }
80 :
81 38 : int rowOffset = rysize/dysize;
82 38 : int loopCount = rysize/rowOffset;
83 3258 : for (int row = 0; row < loopCount; row++)
84 : {
85 3220 : if (isJpegDriver == false)
86 : {
87 160400 : for (int i = 0; i < dxsize; i++)
88 : {
89 160000 : hadnoData[i] = false;
90 : }
91 : }
92 :
93 7320 : for (int band = 1; band <= bands; band++)
94 : {
95 4100 : GDALRasterBand* poBand = poSrcDs->GetRasterBand(band);
96 :
97 4100 : int hasNoData = 0;
98 4100 : bool isSigned = false;
99 4100 : double noDataValue = poBand->GetNoDataValue(&hasNoData);
100 4100 : const char* pixelType = poBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
101 4100 : if (pixelType)
102 : {
103 0 : if (strcmp(pixelType, "SIGNEDBYTE") == 0)
104 : {
105 0 : isSigned = true;
106 : }
107 : }
108 :
109 4100 : GDALRasterBand* poBandtmp = NULL;
110 4100 : if (poTmpDataset)
111 : {
112 4100 : poBandtmp = poTmpDataset->GetRasterBand(band);
113 : }
114 :
115 4100 : int yOffset = ry + row * rowOffset;
116 4100 : bool bReadFailed = false;
117 4100 : if (poBand)
118 : {
119 : CPLErr errTest =
120 4100 : poBand->RasterIO( GF_Read, rx, yOffset, rxsize, rowOffset, pafScanline, dxsize, 1, GDT_Byte, 0, 0);
121 :
122 4100 : if ( errTest == CE_Failure )
123 : {
124 0 : hasNoData = 1;
125 0 : bReadFailed = true;
126 : }
127 : }
128 :
129 :
130 : //fill the true or false for hadnoData array if the source data has nodata value
131 4100 : if (isJpegDriver == false)
132 : {
133 1200 : if (hasNoData == 1)
134 : {
135 0 : for (int j = 0; j < dxsize; j++)
136 : {
137 0 : double v = pafScanline[j];
138 0 : double tmpv = v;
139 0 : if (isSigned)
140 : {
141 0 : tmpv -= 128;
142 : }
143 0 : if (tmpv == noDataValue || bReadFailed == true)
144 : {
145 0 : hadnoData[j] = true;
146 : }
147 : }
148 : }
149 : }
150 :
151 4100 : if (poBandtmp && bReadFailed == false)
152 : {
153 : poBandtmp->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte,
154 4100 : 0, 0);
155 : }
156 : }
157 :
158 : //fill the values for alpha band
159 3220 : if (isJpegDriver == false)
160 : {
161 400 : if (alphaBand)
162 : {
163 160400 : for (int i = 0; i < dxsize; i++)
164 : {
165 160000 : if (hadnoData[i] == true)
166 : {
167 0 : pafScanline[i] = 0;
168 : }
169 : else
170 : {
171 160000 : pafScanline[i] = 255;
172 : }
173 : }
174 :
175 : alphaBand->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte,
176 400 : 0, 0);
177 : }
178 : }
179 : }
180 :
181 38 : delete [] pafScanline;
182 38 : delete [] hadnoData;
183 :
184 38 : GDALDataset* outDs = poOutputTileDriver->CreateCopy(filename.c_str(), poTmpDataset, FALSE, NULL, NULL, NULL);
185 :
186 38 : GDALClose(poTmpDataset);
187 38 : if (outDs)
188 38 : GDALClose(outDs);
189 38 : }
190 :
191 : /************************************************************************/
192 : /* GenerateRootKml() */
193 : /************************************************************************/
194 :
195 : static
196 30 : int GenerateRootKml(const char* filename,
197 : const char* kmlfilename,
198 : double north,
199 : double south,
200 : double east,
201 : double west,
202 : int tilesize)
203 : {
204 30 : VSILFILE* fp = VSIFOpenL(filename, "wb");
205 30 : if (fp == NULL)
206 : {
207 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
208 0 : filename);
209 0 : return FALSE;
210 : }
211 30 : int minlodpixels = tilesize/2;
212 :
213 30 : const char* tmpfilename = CPLGetBasename(kmlfilename);
214 : // If we haven't writen any features yet, output the layer's schema
215 30 : VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
216 30 : VSIFPrintfL(fp, "\t<Document>\n");
217 30 : VSIFPrintfL(fp, "\t\t<name>%s</name>\n", tmpfilename);
218 30 : VSIFPrintfL(fp, "\t\t<description></description>\n");
219 30 : VSIFPrintfL(fp, "\t\t<Style>\n");
220 30 : VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
221 30 : VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
222 30 : VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
223 30 : VSIFPrintfL(fp, "\t\t</Style>\n");
224 30 : VSIFPrintfL(fp, "\t\t<Region>\n \t\t<LatLonAltBox>\n");
225 30 : VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", north);
226 30 : VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", south);
227 30 : VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", east);
228 30 : VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", west);
229 30 : VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
230 30 : VSIFPrintfL(fp, "\t\t</Region>\n");
231 30 : VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
232 30 : VSIFPrintfL(fp, "\t\t\t<open>1</open>\n");
233 30 : VSIFPrintfL(fp, "\t\t\t<Region>\n");
234 30 : VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
235 30 : VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>%d</minLodPixels>\n", minlodpixels);
236 30 : VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
237 30 : VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
238 30 : VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
239 30 : VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", north);
240 30 : VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", south);
241 30 : VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", east);
242 30 : VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", west);
243 30 : VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
244 30 : VSIFPrintfL(fp, "\t\t\t</Region>\n");
245 30 : VSIFPrintfL(fp, "\t\t\t<Link>\n");
246 30 : VSIFPrintfL(fp, "\t\t\t\t<href>0/0/0.kml</href>\n");
247 30 : VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
248 30 : VSIFPrintfL(fp, "\t\t\t</Link>\n");
249 30 : VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
250 30 : VSIFPrintfL(fp, "\t</Document>\n");
251 30 : VSIFPrintfL(fp, "</kml>\n");
252 :
253 30 : VSIFCloseL(fp);
254 30 : return TRUE;
255 : }
256 :
257 : /************************************************************************/
258 : /* GenerateChildKml() */
259 : /************************************************************************/
260 :
261 : static
262 38 : int GenerateChildKml(std::string filename,
263 : int zoom, int ix, int iy,
264 : double zoomxpixel, double zoomypixel, int dxsize, int dysize,
265 : double south, double west, int xsize,
266 : int ysize, int maxzoom,
267 : OGRCoordinateTransformation * poTransform,
268 : std::string fileExt)
269 : {
270 38 : double tnorth = south + zoomypixel *((iy + 1)*dysize);
271 38 : double tsouth = south + zoomypixel *(iy*dysize);
272 38 : double teast = west + zoomxpixel*((ix+1)*dxsize);
273 38 : double twest = west + zoomxpixel*ix*dxsize;
274 :
275 38 : double upperleftT = twest;
276 38 : double lowerleftT = twest;
277 :
278 38 : double rightbottomT = tsouth;
279 38 : double leftbottomT = tsouth;
280 :
281 38 : double lefttopT = tnorth;
282 38 : double righttopT = tnorth;
283 :
284 38 : double lowerrightT = teast;
285 38 : double upperrightT = teast;
286 :
287 38 : if (poTransform)
288 : {
289 10 : poTransform->Transform(1, &twest, &tsouth);
290 10 : poTransform->Transform(1, &teast, &tnorth);
291 :
292 10 : poTransform->Transform(1, &upperleftT, &lefttopT);
293 10 : poTransform->Transform(1, &upperrightT, &righttopT);
294 10 : poTransform->Transform(1, &lowerrightT, &rightbottomT);
295 10 : poTransform->Transform(1, &lowerleftT, &leftbottomT);
296 : }
297 :
298 38 : std::vector<int> xchildren;
299 38 : std::vector<int> ychildern;
300 :
301 38 : int maxLodPix = -1;
302 38 : if ( zoom < maxzoom )
303 : {
304 2 : double zareasize = pow(2.0, (maxzoom - zoom - 1))*dxsize;
305 2 : double zareasize1 = pow(2.0, (maxzoom - zoom - 1))*dysize;
306 2 : xchildren.push_back(ix*2);
307 2 : int tmp = ix*2 + 1;
308 2 : int tmp1 = (int)ceil(xsize / zareasize);
309 2 : if (tmp < tmp1)
310 : {
311 2 : xchildren.push_back(ix*2+1);
312 : }
313 2 : ychildern.push_back(iy*2);
314 2 : tmp = iy*2 + 1;
315 2 : tmp1 = (int)ceil(ysize / zareasize1);
316 2 : if (tmp < tmp1)
317 : {
318 2 : ychildern.push_back(iy*2+1);
319 : }
320 2 : maxLodPix = 2048;
321 : }
322 :
323 38 : VSILFILE* fp = VSIFOpenL(filename.c_str(), "wb");
324 38 : if (fp == NULL)
325 : {
326 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
327 0 : filename.c_str());
328 0 : return FALSE;
329 : }
330 :
331 38 : VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\">\n");
332 38 : VSIFPrintfL(fp, "\t<Document>\n");
333 38 : VSIFPrintfL(fp, "\t\t<name>%d/%d/%d.kml</name>\n", zoom, ix, iy);
334 38 : VSIFPrintfL(fp, "\t\t<Style>\n");
335 38 : VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
336 38 : VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
337 38 : VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
338 38 : VSIFPrintfL(fp, "\t\t</Style>\n");
339 38 : VSIFPrintfL(fp, "\t\t<Region>\n");
340 38 : VSIFPrintfL(fp, "\t\t\t<Lod>\n");
341 38 : VSIFPrintfL(fp, "\t\t\t\t<minLodPixels>%d</minLodPixels>\n", 128);
342 38 : VSIFPrintfL(fp, "\t\t\t\t<maxLodPixels>%d</maxLodPixels>\n", maxLodPix);
343 38 : VSIFPrintfL(fp, "\t\t\t</Lod>\n");
344 38 : VSIFPrintfL(fp, "\t\t\t<LatLonAltBox>\n");
345 38 : VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", tnorth);
346 38 : VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", tsouth);
347 38 : VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", teast);
348 38 : VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", twest);
349 38 : VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
350 38 : VSIFPrintfL(fp, "\t\t</Region>\n");
351 38 : VSIFPrintfL(fp, "\t\t<GroundOverlay>\n");
352 38 : VSIFPrintfL(fp, "\t\t\t<drawOrder>%d</drawOrder>\n", zoom);
353 38 : VSIFPrintfL(fp, "\t\t\t<Icon>\n");
354 38 : VSIFPrintfL(fp, "\t\t\t\t<href>%d%s</href>\n", iy, fileExt.c_str());
355 38 : VSIFPrintfL(fp, "\t\t\t</Icon>\n");
356 38 : VSIFPrintfL(fp, "\t\t\t<gx:LatLonQuad>\n");
357 38 : VSIFPrintfL(fp, "\t\t\t\t<coordinates>\n");
358 38 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerleftT, leftbottomT);
359 38 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerrightT, rightbottomT);
360 38 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperrightT, righttopT);
361 38 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperleftT, lefttopT);
362 38 : VSIFPrintfL(fp, "\t\t\t\t</coordinates>\n");
363 38 : VSIFPrintfL(fp, "\t\t\t</gx:LatLonQuad>\n");
364 38 : VSIFPrintfL(fp, "\t\t</GroundOverlay>\n");
365 :
366 42 : for (unsigned int i = 0; i < xchildren.size(); i++)
367 : {
368 4 : int cx = xchildren[i];
369 12 : for (unsigned int j = 0; j < ychildern.size(); j++)
370 : {
371 8 : int cy = ychildern[j];
372 :
373 8 : double cnorth = south + zoomypixel/2 *((cy + 1)*dysize);
374 8 : double csouth = south + zoomypixel/2 *(cy*dysize);
375 8 : double ceast = west + zoomxpixel/2*((cx+1)*dxsize);
376 8 : double cwest = west + zoomxpixel/2*cx*dxsize;
377 :
378 8 : if (poTransform)
379 : {
380 8 : poTransform->Transform(1, &cwest, &csouth);
381 8 : poTransform->Transform(1, &ceast, &cnorth);
382 : }
383 :
384 8 : VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
385 8 : VSIFPrintfL(fp, "\t\t\t<name>%d/%d/%d%s</name>\n", zoom+1, cx, cy, fileExt.c_str());
386 8 : VSIFPrintfL(fp, "\t\t\t<Region>\n");
387 8 : VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
388 8 : VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>128</minLodPixels>\n");
389 8 : VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
390 8 : VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
391 8 : VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
392 8 : VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", cnorth);
393 8 : VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", csouth);
394 8 : VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", ceast);
395 8 : VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", cwest);
396 8 : VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
397 8 : VSIFPrintfL(fp, "\t\t\t</Region>\n");
398 8 : VSIFPrintfL(fp, "\t\t\t<Link>\n");
399 8 : VSIFPrintfL(fp, "\t\t\t\t<href>../../%d/%d/%d.kml</href>\n", zoom+1, cx, cy);
400 8 : VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
401 8 : VSIFPrintfL(fp, "\t\t\t\t<viewFormat/>\n");
402 8 : VSIFPrintfL(fp, "\t\t\t</Link>\n");
403 8 : VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
404 : }
405 : }
406 :
407 38 : VSIFPrintfL(fp, "\t</Document>\n");
408 38 : VSIFPrintfL(fp, "</kml>\n");
409 38 : VSIFCloseL(fp);
410 :
411 38 : return TRUE;
412 : }
413 :
414 : /************************************************************************/
415 : /* zipWithMinizip() */
416 : /************************************************************************/
417 28 : bool zipWithMinizip(std::vector<std::string> srcFiles, std::string srcDirectory, std::string targetFile)
418 : {
419 28 : void *zipfile = CPLCreateZip(targetFile.c_str(), NULL);
420 28 : if (!zipfile)
421 : {
422 : CPLError( CE_Failure, CPLE_FileIO,
423 0 : "Unable to open target zip file.." );
424 0 : return false;
425 : }
426 :
427 28 : std::vector <std::string>::iterator v1_Iter;
428 28 : for(v1_Iter = srcFiles.begin(); v1_Iter != srcFiles.end(); v1_Iter++)
429 : {
430 84 : std::string fileRead = *v1_Iter;
431 :
432 : // Find relative path and open new file with zip file
433 84 : std::string relativeFileReadPath = fileRead;
434 84 : int remNumChars = srcDirectory.size();
435 84 : if(remNumChars > 0)
436 : {
437 84 : int f = fileRead.find(srcDirectory);
438 84 : if( f >= 0 )
439 : {
440 84 : relativeFileReadPath.erase(f, remNumChars + 1); // 1 added for backslash at the end
441 : }
442 : }
443 :
444 84 : std::basic_string<char>::iterator iter1;
445 168 : for (iter1 = relativeFileReadPath.begin(); iter1 != relativeFileReadPath.end(); iter1++)
446 : {
447 84 : int f = relativeFileReadPath.find("\\");
448 84 : if (f >= 0)
449 : {
450 0 : relativeFileReadPath.replace(f, 1, "/");
451 : }
452 : else
453 : {
454 84 : break;
455 : }
456 : }
457 84 : if (CPLCreateFileInZip(zipfile, relativeFileReadPath.c_str(), NULL) != CE_None)
458 : {
459 : CPLError( CE_Failure, CPLE_FileIO,
460 0 : "Unable to create file within the zip file.." );
461 0 : return false;
462 : }
463 :
464 : // Read source file and write to zip file
465 84 : VSILFILE* fp = VSIFOpenL(fileRead.c_str(), "rb");
466 84 : if (fp == NULL)
467 : {
468 : CPLError( CE_Failure, CPLE_FileIO,
469 0 : "Could not open source file.." );
470 0 : return false;
471 : }
472 :
473 : // Read file in buffer
474 84 : std::string fileData;
475 84 : const unsigned int bufSize = 1024;
476 : char buf[bufSize];
477 : int nRead;
478 430 : while((nRead = VSIFReadL(buf, 1, bufSize, fp)) != 0)
479 : {
480 262 : if ( CPLWriteFileInZip(zipfile, buf, nRead) != CE_None )
481 : {
482 : CPLError( CE_Failure, CPLE_FileIO,
483 0 : "Could not write to file within zip file.." );
484 0 : CPLCloseFileInZip(zipfile);
485 0 : CPLCloseZip(zipfile);
486 0 : VSIFCloseL(fp);
487 0 : return false;
488 : }
489 : }
490 :
491 84 : VSIFCloseL(fp);
492 :
493 : // Close one src file zipped completely
494 84 : if ( CPLCloseFileInZip(zipfile) != CE_None )
495 : {
496 : CPLError( CE_Failure, CPLE_FileIO,
497 0 : "Could not close file written within zip file.." );
498 0 : CPLCloseZip(zipfile);
499 0 : return false;
500 : }
501 : }
502 :
503 28 : CPLCloseZip(zipfile);
504 :
505 28 : return true;
506 : }
507 :
508 : /************************************************************************/
509 : /* KmlSuperOverlayDataset() */
510 : /************************************************************************/
511 :
512 34 : KmlSuperOverlayDataset::KmlSuperOverlayDataset()
513 :
514 : {
515 34 : bGeoTransformSet = FALSE;
516 34 : }
517 :
518 : /************************************************************************/
519 : /* ~KmlSuperOverlayDataset() */
520 : /************************************************************************/
521 :
522 34 : KmlSuperOverlayDataset::~KmlSuperOverlayDataset()
523 :
524 : {
525 34 : FlushCache();
526 34 : }
527 :
528 : /************************************************************************/
529 : /* GetProjectionRef() */
530 : /************************************************************************/
531 :
532 0 : const char *KmlSuperOverlayDataset::GetProjectionRef()
533 :
534 : {
535 0 : return SRS_WKT_WGS84;
536 : }
537 :
538 : /************************************************************************/
539 : /* KMLSuperOverlayRecursiveUnlink() */
540 : /************************************************************************/
541 :
542 84 : static void KMLSuperOverlayRecursiveUnlink( const char *pszName )
543 :
544 : {
545 : char **papszFileList;
546 : int i;
547 :
548 84 : papszFileList = CPLReadDir( pszName );
549 :
550 224 : for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
551 : {
552 : VSIStatBufL sStatBuf;
553 :
554 296 : if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
555 156 : continue;
556 :
557 : CPLString osFullFilename =
558 140 : CPLFormFilename( pszName, papszFileList[i], NULL );
559 :
560 140 : VSIStatL( osFullFilename, &sStatBuf );
561 :
562 140 : if( VSI_ISREG( sStatBuf.st_mode ) )
563 : {
564 84 : VSIUnlink( osFullFilename );
565 : }
566 56 : else if( VSI_ISDIR( sStatBuf.st_mode ) )
567 : {
568 56 : KMLSuperOverlayRecursiveUnlink( osFullFilename );
569 : }
570 : }
571 :
572 84 : CSLDestroy( papszFileList );
573 :
574 84 : VSIRmdir( pszName );
575 84 : }
576 :
577 : /************************************************************************/
578 : /* CreateCopy() */
579 : /************************************************************************/
580 :
581 40 : GDALDataset *KmlSuperOverlayDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
582 : int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData)
583 : {
584 40 : bool isKmz = false;
585 :
586 40 : int bands = poSrcDS->GetRasterCount();
587 40 : if (bands != 1 && bands != 3 && bands != 4)
588 6 : return NULL;
589 :
590 : //correct the file and get the directory
591 34 : char* output_dir = NULL;
592 34 : if (pszFilename == NULL)
593 : {
594 0 : output_dir = CPLGetCurrentDir();
595 0 : pszFilename = CPLFormFilename(output_dir, "doc", "kml");
596 : }
597 : else
598 : {
599 34 : const char* extension = CPLGetExtension(pszFilename);
600 34 : if (!EQUAL(extension,"kml") && !EQUAL(extension,"kmz"))
601 : {
602 : CPLError( CE_Failure, CPLE_None,
603 0 : "File extension should be kml or kmz." );
604 0 : return NULL;
605 : }
606 34 : if (EQUAL(extension,"kmz"))
607 : {
608 32 : isKmz = true;
609 : }
610 :
611 34 : output_dir = CPLStrdup(CPLGetPath(pszFilename));
612 34 : if (strcmp(output_dir, "") == 0)
613 : {
614 0 : CPLFree(output_dir);
615 0 : output_dir = CPLGetCurrentDir();
616 : }
617 : }
618 34 : CPLString outDir = output_dir;
619 34 : CPLFree(output_dir);
620 34 : output_dir = NULL;
621 :
622 34 : KmlSuperOverlayDataset *poDsDummy = new KmlSuperOverlayDataset();
623 :
624 34 : if (isKmz)
625 : {
626 32 : outDir = CPLFormFilename(outDir, CPLSPrintf("kmlsuperoverlaytmp_%p", poDsDummy) , NULL);
627 32 : if (VSIMkdir(outDir, 0755) != 0)
628 : {
629 : CPLError( CE_Failure, CPLE_None,
630 4 : "Cannot create %s", outDir.c_str() );
631 4 : delete poDsDummy;
632 4 : return NULL;
633 : }
634 : }
635 :
636 30 : GDALDriver* poOutputTileDriver = NULL;
637 30 : bool isJpegDriver = true;
638 :
639 30 : const char* pszFormat = CSLFetchNameValueDef(papszOptions, "FORMAT", "JPEG");
640 30 : if (EQUAL(pszFormat, "PNG"))
641 : {
642 2 : isJpegDriver = false;
643 : }
644 :
645 30 : GDALDriver* poMemDriver = GetGDALDriverManager()->GetDriverByName("MEM");
646 30 : poOutputTileDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
647 :
648 30 : if( poMemDriver == NULL || poOutputTileDriver == NULL)
649 : {
650 : CPLError( CE_Failure, CPLE_None,
651 0 : "Image export driver was not found.." );
652 0 : delete poDsDummy;
653 0 : if (isKmz)
654 0 : KMLSuperOverlayRecursiveUnlink(outDir);
655 0 : return NULL;
656 : }
657 :
658 30 : int xsize = poSrcDS->GetRasterXSize();
659 30 : int ysize = poSrcDS->GetRasterYSize();
660 :
661 30 : double north = 0.0;
662 30 : double south = 0.0;
663 30 : double east = 0.0;
664 30 : double west = 0.0;
665 :
666 : double adfGeoTransform[6];
667 :
668 30 : if( poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None )
669 : {
670 30 : north = adfGeoTransform[3];
671 30 : south = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
672 30 : east = adfGeoTransform[0] + adfGeoTransform[1]*xsize;
673 30 : west = adfGeoTransform[0];
674 : }
675 :
676 30 : OGRCoordinateTransformation * poTransform = NULL;
677 30 : if (poSrcDS->GetProjectionRef() != NULL)
678 : {
679 30 : OGRSpatialReference poDsUTM;
680 :
681 30 : char* projStr = (char*)poSrcDS->GetProjectionRef();
682 :
683 30 : if (poDsUTM.importFromWkt(&projStr) == OGRERR_NONE)
684 : {
685 30 : if (poDsUTM.IsProjected())
686 : {
687 2 : OGRSpatialReference poLatLong;
688 2 : poLatLong.SetWellKnownGeogCS( "WGS84" );
689 :
690 2 : poTransform = OGRCreateCoordinateTransformation( &poDsUTM, &poLatLong );
691 2 : if( poTransform != NULL )
692 : {
693 2 : poTransform->Transform(1, &west, &south);
694 2 : poTransform->Transform(1, &east, &north);
695 2 : }
696 : }
697 30 : }
698 : }
699 :
700 : //Zoom levels of the pyramid.
701 : int maxzoom;
702 : int tilexsize;
703 : int tileysize;
704 : // Let the longer side determine the max zoom level and x/y tilesizes.
705 30 : if ( xsize >= ysize )
706 : {
707 30 : double dtilexsize = xsize;
708 62 : while (dtilexsize > 400) //calculate x tile size
709 : {
710 2 : dtilexsize = dtilexsize/2;
711 : }
712 :
713 30 : maxzoom = static_cast<int>(log( (double)xsize / dtilexsize ) / log(2.0));
714 30 : tilexsize = (int)dtilexsize;
715 30 : tileysize = (int)( (double)(dtilexsize * ysize) / xsize );
716 : }
717 : else
718 : {
719 0 : double dtileysize = ysize;
720 0 : while (dtileysize > 400) //calculate y tile size
721 : {
722 0 : dtileysize = dtileysize/2;
723 : }
724 :
725 0 : maxzoom = static_cast<int>(log( (double)ysize / dtileysize ) / log(2.0));
726 0 : tileysize = (int)dtileysize;
727 0 : tilexsize = (int)( (double)(dtileysize * xsize) / ysize );
728 : }
729 :
730 30 : std::vector<double> zoomxpixels;
731 30 : std::vector<double> zoomypixels;
732 62 : for (int zoom = 0; zoom < maxzoom + 1; zoom++)
733 : {
734 32 : zoomxpixels.push_back(adfGeoTransform[1] * pow(2.0, (maxzoom - zoom)));
735 : // zoomypixels.push_back(abs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
736 32 : zoomypixels.push_back(fabs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
737 : }
738 :
739 30 : std::string tmpFileName;
740 30 : std::vector<std::string> fileVector;
741 : int nRet;
742 30 : if (isKmz)
743 : {
744 28 : tmpFileName = CPLFormFilename(outDir, "tmp.kml", NULL);
745 28 : nRet = GenerateRootKml(tmpFileName.c_str(), pszFilename, north, south, east, west, (int)tilexsize);
746 28 : fileVector.push_back(tmpFileName);
747 : }
748 : else
749 : {
750 2 : nRet = GenerateRootKml(pszFilename, pszFilename, north, south, east, west, (int)tilexsize);
751 : }
752 :
753 30 : if (nRet == FALSE)
754 : {
755 0 : OGRCoordinateTransformation::DestroyCT( poTransform );
756 0 : delete poDsDummy;
757 0 : if (isKmz)
758 0 : KMLSuperOverlayRecursiveUnlink(outDir);
759 0 : return NULL;
760 : }
761 :
762 62 : for (int zoom = maxzoom; zoom >= 0; --zoom)
763 : {
764 32 : int rmaxxsize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tilexsize);
765 32 : int rmaxysize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tileysize);
766 :
767 32 : int xloop = (int)xsize/rmaxxsize;
768 32 : int yloop = (int)ysize/rmaxysize;
769 :
770 32 : xloop = xloop>0 ? xloop : 1;
771 32 : yloop = yloop>0 ? yloop : 1;
772 66 : for (int ix = 0; ix < xloop; ix++)
773 : {
774 34 : int rxsize = (int)(rmaxxsize);
775 34 : int rx = (int)(ix * rmaxxsize);
776 :
777 72 : for (int iy = 0; iy < yloop; iy++)
778 : {
779 38 : int rysize = (int)(rmaxysize);
780 38 : int ry = (int)(ysize - (iy * rmaxysize)) - rysize;
781 :
782 38 : int dxsize = (int)(rxsize/rmaxxsize * tilexsize);
783 38 : int dysize = (int)(rysize/rmaxysize * tileysize);
784 :
785 38 : std::stringstream zoomStr;
786 38 : std::stringstream ixStr;
787 38 : std::stringstream iyStr;
788 :
789 38 : zoomStr << zoom;
790 38 : ixStr << ix;
791 38 : iyStr << iy;
792 :
793 38 : std::string zoomDir = outDir;
794 38 : zoomDir+= "/" + zoomStr.str();
795 38 : VSIMkdir(zoomDir.c_str(), 0775);
796 :
797 :
798 38 : zoomDir = zoomDir + "/" + ixStr.str();
799 38 : VSIMkdir(zoomDir.c_str(), 0775);
800 :
801 38 : std::string fileExt = ".jpg";
802 38 : if (isJpegDriver == false)
803 : {
804 2 : fileExt = ".png";
805 : }
806 38 : std::string filename = zoomDir + "/" + iyStr.str() + fileExt;
807 38 : if (isKmz)
808 : {
809 28 : fileVector.push_back(filename);
810 : }
811 :
812 : GenerateTiles(filename, zoom, rxsize, rysize, ix, iy, rx, ry, dxsize,
813 38 : dysize, bands, poSrcDS, poOutputTileDriver, poMemDriver, isJpegDriver);
814 38 : std::string childKmlfile = zoomDir + "/" + iyStr.str() + ".kml";
815 38 : if (isKmz)
816 : {
817 28 : fileVector.push_back(childKmlfile);
818 : }
819 :
820 38 : double tmpSouth = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
821 38 : double zoomxpix = zoomxpixels[zoom];
822 38 : double zoomypix = zoomypixels[zoom];
823 38 : if (zoomxpix == 0)
824 : {
825 0 : zoomxpix = 1;
826 : }
827 :
828 38 : if (zoomypix == 0)
829 : {
830 0 : zoomypix = 1;
831 : }
832 :
833 : GenerateChildKml(childKmlfile, zoom, ix, iy, zoomxpix, zoomypix,
834 38 : dxsize, dysize, tmpSouth, adfGeoTransform[0], xsize, ysize, maxzoom, poTransform, fileExt);
835 : }
836 : }
837 : }
838 :
839 30 : OGRCoordinateTransformation::DestroyCT( poTransform );
840 30 : poTransform = NULL;
841 :
842 30 : if (isKmz)
843 : {
844 28 : std::string outputfile = pszFilename;
845 28 : bool zipDone = true;
846 56 : if (zipWithMinizip(fileVector, outDir, outputfile) == false)
847 : {
848 : CPLError( CE_Failure, CPLE_FileIO,
849 0 : "Unable to do zip.." );
850 0 : zipDone = false;
851 : }
852 :
853 28 : KMLSuperOverlayRecursiveUnlink(outDir);
854 :
855 28 : if (zipDone == false)
856 : {
857 0 : delete poDsDummy;
858 0 : return NULL;
859 0 : }
860 : }
861 :
862 30 : return poDsDummy;
863 : }
864 :
865 : /************************************************************************/
866 : /* Open() */
867 : /************************************************************************/
868 :
869 21904 : GDALDataset *KmlSuperOverlayDataset::Open(GDALOpenInfo *)
870 :
871 : {
872 21904 : return NULL;
873 : }
874 :
875 : /************************************************************************/
876 : /* KmlSuperOverlayDatasetDelete() */
877 : /************************************************************************/
878 :
879 0 : static CPLErr KmlSuperOverlayDatasetDelete(const char* fileName)
880 : {
881 : /* Null implementation, so that people can Delete("MEM:::") */
882 0 : return CE_None;
883 : }
884 :
885 : /************************************************************************/
886 : /* GDALRegister_KMLSUPEROVERLAY() */
887 : /************************************************************************/
888 :
889 1135 : void GDALRegister_KMLSUPEROVERLAY()
890 :
891 : {
892 : GDALDriver *poDriver;
893 :
894 1135 : if( GDALGetDriverByName( "KMLSUPEROVERLAY" ) == NULL )
895 : {
896 1093 : poDriver = new GDALDriver();
897 :
898 1093 : poDriver->SetDescription( "KMLSUPEROVERLAY" );
899 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
900 1093 : "Kml Super Overlay" );
901 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
902 1093 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64" );
903 :
904 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
905 : "<CreationOptionList>"
906 : " <Option name='FORMAT' type='string-select' default='JPEG' description='Force of the tiles'>"
907 : " <Value>PNG</Value>"
908 : " <Value>JPEG</Value>"
909 : " </Option>"
910 1093 : "</CreationOptionList>" );
911 :
912 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
913 :
914 1093 : poDriver->pfnOpen = KmlSuperOverlayDataset::Open;
915 1093 : poDriver->pfnCreateCopy = KmlSuperOverlayDataset::CreateCopy;
916 1093 : poDriver->pfnDelete = KmlSuperOverlayDatasetDelete;
917 :
918 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
919 : }
920 5164 : }
921 :
|