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 15 : 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 15 : GDALDataset* poTmpDataset = NULL;
62 15 : GDALRasterBand* alphaBand = NULL;
63 :
64 15 : GByte* pafScanline = new GByte[dxsize];
65 15 : bool* hadnoData = new bool[dxsize];
66 :
67 15 : if (isJpegDriver && bands == 4)
68 1 : bands = 3;
69 :
70 15 : poTmpDataset = poMemDriver->Create("", dxsize, dysize, bands, GDT_Byte, NULL);
71 :
72 15 : if (isJpegDriver == false)//Jpeg dataset only has one or three bands
73 : {
74 1 : if (bands < 4)//add transparency to files with one band or three bands
75 : {
76 1 : poTmpDataset->AddBand(GDT_Byte);
77 1 : alphaBand = poTmpDataset->GetRasterBand(poTmpDataset->GetRasterCount());
78 : }
79 : }
80 :
81 15 : int rowOffset = rysize/dysize;
82 15 : int loopCount = rysize/rowOffset;
83 545 : for (int row = 0; row < loopCount; row++)
84 : {
85 530 : if (isJpegDriver == false)
86 : {
87 80200 : for (int i = 0; i < dxsize; i++)
88 : {
89 80000 : hadnoData[i] = false;
90 : }
91 : }
92 :
93 1900 : for (int band = 1; band <= bands; band++)
94 : {
95 1370 : GDALRasterBand* poBand = poSrcDs->GetRasterBand(band);
96 :
97 1370 : int hasNoData = 0;
98 1370 : bool isSigned = false;
99 1370 : double noDataValue = poBand->GetNoDataValue(&hasNoData);
100 1370 : const char* pixelType = poBand->GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
101 1370 : if (pixelType)
102 : {
103 0 : if (strcmp(pixelType, "SIGNEDBYTE") == 0)
104 : {
105 0 : isSigned = true;
106 : }
107 : }
108 :
109 1370 : GDALRasterBand* poBandtmp = NULL;
110 1370 : if (poTmpDataset)
111 : {
112 1370 : poBandtmp = poTmpDataset->GetRasterBand(band);
113 : }
114 :
115 1370 : int yOffset = ry + row * rowOffset;
116 1370 : bool bReadFailed = false;
117 1370 : if (poBand)
118 : {
119 : CPLErr errTest =
120 1370 : poBand->RasterIO( GF_Read, rx, yOffset, rxsize, rowOffset, pafScanline, dxsize, 1, GDT_Byte, 0, 0);
121 :
122 1370 : 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 1370 : if (isJpegDriver == false)
132 : {
133 600 : 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 1370 : if (poBandtmp && bReadFailed == false)
152 : {
153 : poBandtmp->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte,
154 1370 : 0, 0);
155 : }
156 : }
157 :
158 : //fill the values for alpha band
159 530 : if (isJpegDriver == false)
160 : {
161 200 : if (alphaBand)
162 : {
163 80200 : for (int i = 0; i < dxsize; i++)
164 : {
165 80000 : if (hadnoData[i] == true)
166 : {
167 0 : pafScanline[i] = 0;
168 : }
169 : else
170 : {
171 80000 : pafScanline[i] = 255;
172 : }
173 : }
174 :
175 : alphaBand->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte,
176 200 : 0, 0);
177 : }
178 : }
179 : }
180 :
181 15 : delete [] pafScanline;
182 15 : delete [] hadnoData;
183 :
184 15 : GDALDataset* outDs = poOutputTileDriver->CreateCopy(filename.c_str(), poTmpDataset, FALSE, NULL, NULL, NULL);
185 :
186 15 : GDALClose(poTmpDataset);
187 15 : if (outDs)
188 15 : GDALClose(outDs);
189 15 : }
190 :
191 : /************************************************************************/
192 : /* GenerateRootKml() */
193 : /************************************************************************/
194 :
195 : static
196 15 : 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 15 : VSILFILE* fp = VSIFOpenL(filename, "wb");
205 15 : if (fp == NULL)
206 : {
207 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
208 0 : filename);
209 0 : return FALSE;
210 : }
211 15 : int minlodpixels = tilesize/2;
212 :
213 15 : const char* tmpfilename = CPLGetBasename(kmlfilename);
214 : // If we haven't writen any features yet, output the layer's schema
215 15 : VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n");
216 15 : VSIFPrintfL(fp, "\t<Document>\n");
217 15 : VSIFPrintfL(fp, "\t\t<name>%s</name>\n", tmpfilename);
218 15 : VSIFPrintfL(fp, "\t\t<description></description>\n");
219 15 : VSIFPrintfL(fp, "\t\t<Style>\n");
220 15 : VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
221 15 : VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
222 15 : VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
223 15 : VSIFPrintfL(fp, "\t\t</Style>\n");
224 15 : VSIFPrintfL(fp, "\t\t<Region>\n \t\t<LatLonAltBox>\n");
225 15 : VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", north);
226 15 : VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", south);
227 15 : VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", east);
228 15 : VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", west);
229 15 : VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
230 15 : VSIFPrintfL(fp, "\t\t</Region>\n");
231 15 : VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
232 15 : VSIFPrintfL(fp, "\t\t\t<open>1</open>\n");
233 15 : VSIFPrintfL(fp, "\t\t\t<Region>\n");
234 15 : VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
235 15 : VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>%d</minLodPixels>\n", minlodpixels);
236 15 : VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
237 15 : VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
238 15 : VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
239 15 : VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", north);
240 15 : VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", south);
241 15 : VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", east);
242 15 : VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", west);
243 15 : VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
244 15 : VSIFPrintfL(fp, "\t\t\t</Region>\n");
245 15 : VSIFPrintfL(fp, "\t\t\t<Link>\n");
246 15 : VSIFPrintfL(fp, "\t\t\t\t<href>0/0/0.kml</href>\n");
247 15 : VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
248 15 : VSIFPrintfL(fp, "\t\t\t</Link>\n");
249 15 : VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
250 15 : VSIFPrintfL(fp, "\t</Document>\n");
251 15 : VSIFPrintfL(fp, "</kml>\n");
252 :
253 15 : VSIFCloseL(fp);
254 15 : return TRUE;
255 : }
256 :
257 : /************************************************************************/
258 : /* GenerateChildKml() */
259 : /************************************************************************/
260 :
261 : static
262 15 : 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 15 : double tnorth = south + zoomypixel *((iy + 1)*dysize);
271 15 : double tsouth = south + zoomypixel *(iy*dysize);
272 15 : double teast = west + zoomxpixel*((ix+1)*dxsize);
273 15 : double twest = west + zoomxpixel*ix*dxsize;
274 :
275 15 : double upperleftT = twest;
276 15 : double lowerleftT = twest;
277 :
278 15 : double rightbottomT = tsouth;
279 15 : double leftbottomT = tsouth;
280 :
281 15 : double lefttopT = tnorth;
282 15 : double righttopT = tnorth;
283 :
284 15 : double lowerrightT = teast;
285 15 : double upperrightT = teast;
286 :
287 15 : if (poTransform)
288 : {
289 0 : poTransform->Transform(1, &twest, &tsouth);
290 0 : poTransform->Transform(1, &teast, &tnorth);
291 :
292 0 : poTransform->Transform(1, &upperleftT, &lefttopT);
293 0 : poTransform->Transform(1, &upperrightT, &righttopT);
294 0 : poTransform->Transform(1, &lowerrightT, &rightbottomT);
295 0 : poTransform->Transform(1, &lowerleftT, &leftbottomT);
296 : }
297 :
298 15 : std::vector<int> xchildren;
299 15 : std::vector<int> ychildern;
300 :
301 15 : int maxLodPix = -1;
302 15 : if ( zoom < maxzoom )
303 : {
304 0 : double zareasize = pow(2.0, (maxzoom - zoom - 1))*dxsize;
305 0 : double zareasize1 = pow(2.0, (maxzoom - zoom - 1))*dysize;
306 0 : xchildren.push_back(ix*2);
307 0 : int tmp = ix*2 + 1;
308 0 : int tmp1 = (int)ceil(xsize / zareasize);
309 0 : if (tmp < tmp1)
310 : {
311 0 : xchildren.push_back(ix*2+1);
312 : }
313 0 : ychildern.push_back(iy*2);
314 0 : tmp = iy*2 + 1;
315 0 : tmp1 = (int)ceil(ysize / zareasize1);
316 0 : if (tmp < tmp1)
317 : {
318 0 : ychildern.push_back(iy*2+1);
319 : }
320 0 : maxLodPix = 2048;
321 : }
322 :
323 15 : VSILFILE* fp = VSIFOpenL(filename.c_str(), "wb");
324 15 : 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 15 : VSIFPrintfL(fp, "<kml xmlns=\"http://earth.google.com/kml/2.1\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\">\n");
332 15 : VSIFPrintfL(fp, "\t<Document>\n");
333 15 : VSIFPrintfL(fp, "\t\t<name>%d/%d/%d.kml</name>\n", zoom, ix, iy);
334 15 : VSIFPrintfL(fp, "\t\t<Style>\n");
335 15 : VSIFPrintfL(fp, "\t\t\t<ListStyle id=\"hideChildren\">\n");
336 15 : VSIFPrintfL(fp, "\t\t\t\t<listItemType>checkHideChildren</listItemType>\n");
337 15 : VSIFPrintfL(fp, "\t\t\t</ListStyle>\n");
338 15 : VSIFPrintfL(fp, "\t\t</Style>\n");
339 15 : VSIFPrintfL(fp, "\t\t<Region>\n");
340 15 : VSIFPrintfL(fp, "\t\t\t<Lod>\n");
341 15 : VSIFPrintfL(fp, "\t\t\t\t<minLodPixels>%d</minLodPixels>\n", 128);
342 15 : VSIFPrintfL(fp, "\t\t\t\t<maxLodPixels>%d</maxLodPixels>\n", maxLodPix);
343 15 : VSIFPrintfL(fp, "\t\t\t</Lod>\n");
344 15 : VSIFPrintfL(fp, "\t\t\t<LatLonAltBox>\n");
345 15 : VSIFPrintfL(fp, "\t\t\t\t<north>%f</north>\n", tnorth);
346 15 : VSIFPrintfL(fp, "\t\t\t\t<south>%f</south>\n", tsouth);
347 15 : VSIFPrintfL(fp, "\t\t\t\t<east>%f</east>\n", teast);
348 15 : VSIFPrintfL(fp, "\t\t\t\t<west>%f</west>\n", twest);
349 15 : VSIFPrintfL(fp, "\t\t\t</LatLonAltBox>\n");
350 15 : VSIFPrintfL(fp, "\t\t</Region>\n");
351 15 : VSIFPrintfL(fp, "\t\t<GroundOverlay>\n");
352 15 : VSIFPrintfL(fp, "\t\t\t<drawOrder>%d</drawOrder>\n", zoom);
353 15 : VSIFPrintfL(fp, "\t\t\t<Icon>\n");
354 15 : VSIFPrintfL(fp, "\t\t\t\t<href>%d%s</href>\n", iy, fileExt.c_str());
355 15 : VSIFPrintfL(fp, "\t\t\t</Icon>\n");
356 15 : VSIFPrintfL(fp, "\t\t\t<gx:LatLonQuad>\n");
357 15 : VSIFPrintfL(fp, "\t\t\t\t<coordinates>\n");
358 15 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerleftT, leftbottomT);
359 15 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", lowerrightT, rightbottomT);
360 15 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperrightT, righttopT);
361 15 : VSIFPrintfL(fp, "\t\t\t\t\t%f,%f,0\n", upperleftT, lefttopT);
362 15 : VSIFPrintfL(fp, "\t\t\t\t</coordinates>\n");
363 15 : VSIFPrintfL(fp, "\t\t\t</gx:LatLonQuad>\n");
364 15 : VSIFPrintfL(fp, "\t\t</GroundOverlay>\n");
365 :
366 15 : for (unsigned int i = 0; i < xchildren.size(); i++)
367 : {
368 0 : int cx = xchildren[i];
369 0 : for (unsigned int j = 0; j < ychildern.size(); j++)
370 : {
371 0 : int cy = ychildern[j];
372 :
373 0 : double cnorth = south + zoomypixel/2 *((cy + 1)*dysize);
374 0 : double csouth = south + zoomypixel/2 *(cy*dysize);
375 0 : double ceast = west + zoomxpixel/2*((cx+1)*dxsize);
376 0 : double cwest = west + zoomxpixel/2*cx*dxsize;
377 :
378 0 : if (poTransform)
379 : {
380 0 : poTransform->Transform(1, &cwest, &csouth);
381 0 : poTransform->Transform(1, &ceast, &cnorth);
382 : }
383 :
384 0 : VSIFPrintfL(fp, "\t\t<NetworkLink>\n");
385 0 : VSIFPrintfL(fp, "\t\t\t<name>%d/%d/%d%s</name>\n", zoom+1, cx, cy, fileExt.c_str());
386 0 : VSIFPrintfL(fp, "\t\t\t<Region>\n");
387 0 : VSIFPrintfL(fp, "\t\t\t\t<Lod>\n");
388 0 : VSIFPrintfL(fp, "\t\t\t\t\t<minLodPixels>128</minLodPixels>\n");
389 0 : VSIFPrintfL(fp, "\t\t\t\t\t<maxLodPixels>-1</maxLodPixels>\n");
390 0 : VSIFPrintfL(fp, "\t\t\t\t</Lod>\n");
391 0 : VSIFPrintfL(fp, "\t\t\t\t<LatLonAltBox>\n");
392 0 : VSIFPrintfL(fp, "\t\t\t\t\t<north>%f</north>\n", cnorth);
393 0 : VSIFPrintfL(fp, "\t\t\t\t\t<south>%f</south>\n", csouth);
394 0 : VSIFPrintfL(fp, "\t\t\t\t\t<east>%f</east>\n", ceast);
395 0 : VSIFPrintfL(fp, "\t\t\t\t\t<west>%f</west>\n", cwest);
396 0 : VSIFPrintfL(fp, "\t\t\t\t</LatLonAltBox>\n");
397 0 : VSIFPrintfL(fp, "\t\t\t</Region>\n");
398 0 : VSIFPrintfL(fp, "\t\t\t<Link>\n");
399 0 : VSIFPrintfL(fp, "\t\t\t\t<href>../../%d/%d/%d.kml</href>\n", zoom+1, cx, cy);
400 0 : VSIFPrintfL(fp, "\t\t\t\t<viewRefreshMode>onRegion</viewRefreshMode>\n");
401 0 : VSIFPrintfL(fp, "\t\t\t\t<viewFormat/>\n");
402 0 : VSIFPrintfL(fp, "\t\t\t</Link>\n");
403 0 : VSIFPrintfL(fp, "\t\t</NetworkLink>\n");
404 : }
405 : }
406 :
407 15 : VSIFPrintfL(fp, "\t</Document>\n");
408 15 : VSIFPrintfL(fp, "</kml>\n");
409 15 : VSIFCloseL(fp);
410 :
411 15 : return TRUE;
412 : }
413 :
414 : /************************************************************************/
415 : /* zipWithMinizip() */
416 : /************************************************************************/
417 14 : bool zipWithMinizip(std::vector<std::string> srcFiles, std::string srcDirectory, std::string targetFile)
418 : {
419 14 : void *zipfile = CPLCreateZip(targetFile.c_str(), NULL);
420 14 : if (!zipfile)
421 : {
422 : CPLError( CE_Failure, CPLE_FileIO,
423 0 : "Unable to open target zip file.." );
424 0 : return false;
425 : }
426 :
427 14 : std::vector <std::string>::iterator v1_Iter;
428 14 : for(v1_Iter = srcFiles.begin(); v1_Iter != srcFiles.end(); v1_Iter++)
429 : {
430 42 : std::string fileRead = *v1_Iter;
431 :
432 : // Find relative path and open new file with zip file
433 42 : std::string relativeFileReadPath = fileRead;
434 42 : int remNumChars = srcDirectory.size();
435 42 : if(remNumChars > 0)
436 : {
437 42 : int f = fileRead.find(srcDirectory);
438 42 : if( f >= 0 )
439 : {
440 42 : relativeFileReadPath.erase(f, remNumChars + 1); // 1 added for backslash at the end
441 : }
442 : }
443 :
444 42 : std::basic_string<char>::iterator iter1;
445 84 : for (iter1 = relativeFileReadPath.begin(); iter1 != relativeFileReadPath.end(); iter1++)
446 : {
447 42 : int f = relativeFileReadPath.find("\\");
448 42 : if (f >= 0)
449 : {
450 0 : relativeFileReadPath.replace(f, 1, "/");
451 : }
452 : else
453 : {
454 42 : break;
455 : }
456 : }
457 42 : 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 42 : VSILFILE* fp = VSIFOpenL(fileRead.c_str(), "rb");
466 42 : 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 42 : std::string fileData;
475 42 : const unsigned int bufSize = 1024;
476 : char buf[bufSize];
477 : int nRead;
478 215 : while((nRead = VSIFReadL(buf, 1, bufSize, fp)) != 0)
479 : {
480 131 : 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 42 : VSIFCloseL(fp);
492 :
493 : // Close one src file zipped completely
494 42 : 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 14 : CPLCloseZip(zipfile);
504 :
505 14 : return true;
506 : }
507 :
508 : /************************************************************************/
509 : /* KmlSuperOverlayDataset() */
510 : /************************************************************************/
511 :
512 17 : KmlSuperOverlayDataset::KmlSuperOverlayDataset()
513 :
514 : {
515 17 : bGeoTransformSet = FALSE;
516 17 : }
517 :
518 : /************************************************************************/
519 : /* ~KmlSuperOverlayDataset() */
520 : /************************************************************************/
521 :
522 17 : KmlSuperOverlayDataset::~KmlSuperOverlayDataset()
523 :
524 : {
525 17 : FlushCache();
526 17 : }
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 42 : static void KMLSuperOverlayRecursiveUnlink( const char *pszName )
543 :
544 : {
545 : char **papszFileList;
546 : int i;
547 :
548 42 : papszFileList = CPLReadDir( pszName );
549 :
550 112 : for( i = 0; papszFileList != NULL && papszFileList[i] != NULL; i++ )
551 : {
552 : VSIStatBufL sStatBuf;
553 :
554 148 : if( EQUAL(papszFileList[i],".") || EQUAL(papszFileList[i],"..") )
555 78 : continue;
556 :
557 : CPLString osFullFilename =
558 70 : CPLFormFilename( pszName, papszFileList[i], NULL );
559 :
560 70 : VSIStatL( osFullFilename, &sStatBuf );
561 :
562 70 : if( VSI_ISREG( sStatBuf.st_mode ) )
563 : {
564 42 : VSIUnlink( osFullFilename );
565 : }
566 28 : else if( VSI_ISDIR( sStatBuf.st_mode ) )
567 : {
568 28 : KMLSuperOverlayRecursiveUnlink( osFullFilename );
569 : }
570 : }
571 :
572 42 : CSLDestroy( papszFileList );
573 :
574 42 : VSIRmdir( pszName );
575 42 : }
576 :
577 : /************************************************************************/
578 : /* CreateCopy() */
579 : /************************************************************************/
580 :
581 20 : GDALDataset *KmlSuperOverlayDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
582 : int bStrict, char ** papszOptions, GDALProgressFunc pfnProgress, void * pProgressData)
583 : {
584 20 : bool isKmz = false;
585 :
586 20 : int bands = poSrcDS->GetRasterCount();
587 20 : if (bands != 1 && bands != 3 && bands != 4)
588 3 : return NULL;
589 :
590 : //correct the file and get the directory
591 17 : char* output_dir = NULL;
592 17 : if (pszFilename == NULL)
593 : {
594 0 : output_dir = CPLGetCurrentDir();
595 0 : pszFilename = CPLFormFilename(output_dir, "doc", "kml");
596 : }
597 : else
598 : {
599 17 : const char* extension = CPLGetExtension(pszFilename);
600 17 : 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 17 : if (EQUAL(extension,"kmz"))
607 : {
608 16 : isKmz = true;
609 : }
610 :
611 17 : output_dir = CPLStrdup(CPLGetPath(pszFilename));
612 17 : if (strcmp(output_dir, "") == 0)
613 : {
614 0 : CPLFree(output_dir);
615 0 : output_dir = CPLGetCurrentDir();
616 : }
617 : }
618 17 : CPLString outDir = output_dir;
619 17 : CPLFree(output_dir);
620 17 : output_dir = NULL;
621 :
622 17 : KmlSuperOverlayDataset *poDsDummy = new KmlSuperOverlayDataset();
623 :
624 17 : if (isKmz)
625 : {
626 16 : outDir = CPLFormFilename(outDir, CPLSPrintf("kmlsuperoverlaytmp_%p", poDsDummy) , NULL);
627 16 : if (VSIMkdir(outDir, 0755) != 0)
628 : {
629 : CPLError( CE_Failure, CPLE_None,
630 2 : "Cannot create %s", outDir.c_str() );
631 2 : delete poDsDummy;
632 2 : return NULL;
633 : }
634 : }
635 :
636 15 : GDALDriver* poOutputTileDriver = NULL;
637 15 : bool isJpegDriver = true;
638 :
639 15 : const char* pszFormat = CSLFetchNameValueDef(papszOptions, "FORMAT", "JPEG");
640 15 : if (EQUAL(pszFormat, "PNG"))
641 : {
642 1 : isJpegDriver = false;
643 : }
644 :
645 15 : GDALDriver* poMemDriver = GetGDALDriverManager()->GetDriverByName("MEM");
646 15 : poOutputTileDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
647 :
648 15 : 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 15 : int xsize = poSrcDS->GetRasterXSize();
659 15 : int ysize = poSrcDS->GetRasterYSize();
660 :
661 15 : double north = 0.0;
662 15 : double south = 0.0;
663 15 : double east = 0.0;
664 15 : double west = 0.0;
665 :
666 : double adfGeoTransform[6];
667 :
668 15 : if( poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None )
669 : {
670 15 : north = adfGeoTransform[3];
671 15 : south = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
672 15 : east = adfGeoTransform[0] + adfGeoTransform[1]*xsize;
673 15 : west = adfGeoTransform[0];
674 : }
675 :
676 15 : OGRCoordinateTransformation * poTransform = NULL;
677 15 : if (poSrcDS->GetProjectionRef() != NULL)
678 : {
679 15 : OGRSpatialReference poDsUTM;
680 :
681 15 : char* projStr = (char*)poSrcDS->GetProjectionRef();
682 :
683 15 : if (poDsUTM.importFromWkt(&projStr) == OGRERR_NONE)
684 : {
685 15 : if (poDsUTM.IsProjected())
686 : {
687 0 : OGRSpatialReference poLatLong;
688 0 : poLatLong.SetWellKnownGeogCS( "WGS84" );
689 :
690 0 : poTransform = OGRCreateCoordinateTransformation( &poDsUTM, &poLatLong );
691 0 : if( poTransform != NULL )
692 : {
693 0 : poTransform->Transform(1, &west, &south);
694 0 : poTransform->Transform(1, &east, &north);
695 0 : }
696 : }
697 15 : }
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 15 : if ( xsize >= ysize )
706 : {
707 15 : double dtilexsize = xsize;
708 30 : while (dtilexsize > 400) //calculate x tile size
709 : {
710 0 : dtilexsize = dtilexsize/2;
711 : }
712 :
713 15 : maxzoom = static_cast<int>(log( (double)xsize / dtilexsize ) / log(2.0));
714 15 : tilexsize = (int)dtilexsize;
715 15 : 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 15 : maxzoom = 0;
730 :
731 15 : std::vector<double> zoomxpixels;
732 15 : std::vector<double> zoomypixels;
733 30 : for (int zoom = 0; zoom < maxzoom + 1; zoom++)
734 : {
735 15 : zoomxpixels.push_back(adfGeoTransform[1] * pow(2.0, (maxzoom - zoom)));
736 : // zoomypixels.push_back(abs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
737 15 : zoomypixels.push_back(fabs(adfGeoTransform[5]) * pow(2.0, (maxzoom - zoom)));
738 : }
739 :
740 15 : std::string tmpFileName;
741 15 : std::vector<std::string> fileVector;
742 : int nRet;
743 15 : if (isKmz)
744 : {
745 14 : tmpFileName = CPLFormFilename(outDir, "tmp.kml", NULL);
746 14 : nRet = GenerateRootKml(tmpFileName.c_str(), pszFilename, north, south, east, west, (int)tilexsize);
747 14 : fileVector.push_back(tmpFileName);
748 : }
749 : else
750 : {
751 1 : nRet = GenerateRootKml(pszFilename, pszFilename, north, south, east, west, (int)tilexsize);
752 : }
753 :
754 15 : if (nRet == FALSE)
755 : {
756 0 : OGRCoordinateTransformation::DestroyCT( poTransform );
757 0 : delete poDsDummy;
758 0 : if (isKmz)
759 0 : KMLSuperOverlayRecursiveUnlink(outDir);
760 0 : return NULL;
761 : }
762 :
763 30 : for (int zoom = maxzoom; zoom >= 0; --zoom)
764 : {
765 15 : int rmaxxsize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tilexsize);
766 15 : int rmaxysize = static_cast<int>(pow(2.0, (maxzoom-zoom)) * tileysize);
767 :
768 15 : int xloop = (int)xsize/rmaxxsize;
769 15 : int yloop = (int)ysize/rmaxysize;
770 :
771 15 : xloop = xloop>0 ? xloop : 1;
772 15 : yloop = yloop>0 ? yloop : 1;
773 30 : for (int ix = 0; ix < xloop; ix++)
774 : {
775 15 : int rxsize = (int)(rmaxxsize);
776 15 : int rx = (int)(ix * rmaxxsize);
777 :
778 30 : for (int iy = 0; iy < yloop; iy++)
779 : {
780 15 : int rysize = (int)(rmaxysize);
781 15 : int ry = (int)(ysize - (iy * rmaxysize)) - rysize;
782 :
783 15 : int dxsize = (int)(rxsize/rmaxxsize * tilexsize);
784 15 : int dysize = (int)(rysize/rmaxysize * tileysize);
785 :
786 15 : std::stringstream zoomStr;
787 15 : std::stringstream ixStr;
788 15 : std::stringstream iyStr;
789 :
790 15 : zoomStr << zoom;
791 15 : ixStr << ix;
792 15 : iyStr << iy;
793 :
794 15 : std::string zoomDir = outDir;
795 15 : zoomDir+= "/" + zoomStr.str();
796 15 : VSIMkdir(zoomDir.c_str(), 0775);
797 :
798 :
799 15 : zoomDir = zoomDir + "/" + ixStr.str();
800 15 : VSIMkdir(zoomDir.c_str(), 0775);
801 :
802 15 : std::string fileExt = ".jpg";
803 15 : if (isJpegDriver == false)
804 : {
805 1 : fileExt = ".png";
806 : }
807 15 : std::string filename = zoomDir + "/" + iyStr.str() + fileExt;
808 15 : if (isKmz)
809 : {
810 14 : fileVector.push_back(filename);
811 : }
812 :
813 : GenerateTiles(filename, zoom, rxsize, rysize, ix, iy, rx, ry, dxsize,
814 15 : dysize, bands, poSrcDS, poOutputTileDriver, poMemDriver, isJpegDriver);
815 15 : std::string childKmlfile = zoomDir + "/" + iyStr.str() + ".kml";
816 15 : if (isKmz)
817 : {
818 14 : fileVector.push_back(childKmlfile);
819 : }
820 :
821 15 : double tmpSouth = adfGeoTransform[3] + adfGeoTransform[5]*ysize;
822 15 : double zoomxpix = zoomxpixels[zoom];
823 15 : double zoomypix = zoomypixels[zoom];
824 15 : if (zoomxpix == 0)
825 : {
826 0 : zoomxpix = 1;
827 : }
828 :
829 15 : if (zoomypix == 0)
830 : {
831 0 : zoomypix = 1;
832 : }
833 :
834 : GenerateChildKml(childKmlfile, zoom, ix, iy, zoomxpix, zoomypix,
835 15 : dxsize, dysize, tmpSouth, adfGeoTransform[0], xsize, ysize, maxzoom, poTransform, fileExt);
836 : }
837 : }
838 : }
839 :
840 15 : OGRCoordinateTransformation::DestroyCT( poTransform );
841 15 : poTransform = NULL;
842 :
843 15 : if (isKmz)
844 : {
845 14 : std::string outputfile = pszFilename;
846 14 : bool zipDone = true;
847 28 : if (zipWithMinizip(fileVector, outDir, outputfile) == false)
848 : {
849 : CPLError( CE_Failure, CPLE_FileIO,
850 0 : "Unable to do zip.." );
851 0 : zipDone = false;
852 : }
853 :
854 14 : KMLSuperOverlayRecursiveUnlink(outDir);
855 :
856 14 : if (zipDone == false)
857 : {
858 0 : delete poDsDummy;
859 0 : return NULL;
860 0 : }
861 : }
862 :
863 15 : return poDsDummy;
864 : }
865 :
866 : /************************************************************************/
867 : /* Open() */
868 : /************************************************************************/
869 :
870 10546 : GDALDataset *KmlSuperOverlayDataset::Open(GDALOpenInfo *)
871 :
872 : {
873 10546 : return NULL;
874 : }
875 :
876 : /************************************************************************/
877 : /* KmlSuperOverlayDatasetDelete() */
878 : /************************************************************************/
879 :
880 0 : static CPLErr KmlSuperOverlayDatasetDelete(const char* fileName)
881 : {
882 : /* Null implementation, so that people can Delete("MEM:::") */
883 0 : return CE_None;
884 : }
885 :
886 : /************************************************************************/
887 : /* GDALRegister_KMLSUPEROVERLAY() */
888 : /************************************************************************/
889 :
890 558 : void GDALRegister_KMLSUPEROVERLAY()
891 :
892 : {
893 : GDALDriver *poDriver;
894 :
895 558 : if( GDALGetDriverByName( "KMLSUPEROVERLAY" ) == NULL )
896 : {
897 537 : poDriver = new GDALDriver();
898 :
899 537 : poDriver->SetDescription( "KMLSUPEROVERLAY" );
900 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
901 537 : "Kml Super Overlay" );
902 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
903 537 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64" );
904 :
905 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
906 : "<CreationOptionList>"
907 : " <Option name='FORMAT' type='string-select' default='JPEG' description='Force of the tiles'>"
908 : " <Value>PNG</Value>"
909 : " <Value>JPEG</Value>"
910 : " </Option>"
911 537 : "</CreationOptionList>" );
912 :
913 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
914 :
915 537 : poDriver->pfnOpen = KmlSuperOverlayDataset::Open;
916 537 : poDriver->pfnCreateCopy = KmlSuperOverlayDataset::CreateCopy;
917 537 : poDriver->pfnDelete = KmlSuperOverlayDatasetDelete;
918 :
919 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
920 : }
921 2505 : }
922 :
|