1
2 ///////////////////////////////////////////////////////////
3 // //
4 // SAGA //
5 // //
6 // System for Automated Geoscientific Analyses //
7 // //
8 // Tool Library //
9 // //
10 // io_gdal //
11 // //
12 //-------------------------------------------------------//
13 // //
14 // gdal_import_wms.cpp //
15 // //
16 // Copyright (C) 2016 O. Conrad //
17 // //
18 //-------------------------------------------------------//
19 // //
20 // This file is part of 'SAGA - System for Automated //
21 // Geoscientific Analyses'. SAGA is free software; you //
22 // can redistribute it and/or modify it under the terms //
23 // of the GNU General Public License as published by the //
24 // Free Software Foundation, either version 2 of the //
25 // License, or (at your option) any later version. //
26 // //
27 // SAGA is distributed in the hope that it will be //
28 // useful, but WITHOUT ANY WARRANTY; without even the //
29 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
30 // PARTICULAR PURPOSE. See the GNU General Public //
31 // License for more details. //
32 // //
33 // You should have received a copy of the GNU General //
34 // Public License along with this program; if not, see //
35 // <http://www.gnu.org/licenses/>. //
36 // //
37 //-------------------------------------------------------//
38 // //
39 // e-mail: oconrad@saga-gis.de //
40 // //
41 // contact: Olaf Conrad //
42 // Institute of Geography //
43 // University of Hamburg //
44 // Germany //
45 // //
46 ///////////////////////////////////////////////////////////
47
48 //---------------------------------------------------------
49 #include "gdal_import_wms.h"
50
51
52 ///////////////////////////////////////////////////////////
53 // //
54 // //
55 // //
56 ///////////////////////////////////////////////////////////
57
58 //---------------------------------------------------------
CGDAL_Import_WMS(void)59 CGDAL_Import_WMS::CGDAL_Import_WMS(void)
60 {
61 //-----------------------------------------------------
62 Set_Name (_TL("Import TMS Image"));
63
64 Set_Author ("O.Conrad (c) 2016");
65
66 CSG_String Description;
67
68 Description = _TW(
69 "The \"Import TMS Image\" tool imports a map image from a Tile Mapping Service (TMS) using the "
70 "\"Geospatial Data Abstraction Library\" (GDAL) by Frank Warmerdam. "
71 );
72
73 Description += CSG_String::Format("\nGDAL %s:%s\n\n", _TL("Version"), SG_Get_GDAL_Drivers().Get_Version().c_str());
74
75 Set_Description(Description);
76
77 Add_Reference("GDAL/OGR contributors", "2019",
78 "GDAL/OGR Geospatial Data Abstraction software Library",
79 "A translator library for raster and vector geospatial data formats. Open Source Geospatial Foundation.",
80 SG_T("https://gdal.org"), SG_T("Link")
81 );
82
83 //-----------------------------------------------------
84 Parameters.Add_Grid("",
85 "TARGET" , _TL("Target System"),
86 _TL(""),
87 PARAMETER_INPUT_OPTIONAL
88 )->Get_Parent();
89
90 Parameters.Add_Grid("TARGET",
91 "TARGET_MAP" , _TL("Target Map"),
92 _TL(""),
93 PARAMETER_OUTPUT
94 );
95
96 Parameters.Add_Grid_Output("",
97 "MAP" , _TL("Map"),
98 _TL("")
99 );
100
101 //-----------------------------------------------------
102 Parameters.Add_Choice("",
103 "SERVER" , _TL("Server"),
104 _TL(""),
105 CSG_String::Format("%s|%s|%s|%s|%s|%s|%s|%s|%s",
106 _TL("Open Street Map"),
107 _TL("Google Map"),
108 _TL("Google Satellite"),
109 _TL("Google Hybrid"),
110 _TL("Google Terrain"),
111 _TL("Google Terrain, Streets and Water"),
112 _TL("ArcGIS MapServer Tiles"),
113 _TL("TopPlusOpen"),
114 _TL("user defined")
115 ), 0
116 );
117
118 Parameters.Add_Int("SERVER",
119 "BLOCKSIZE" , _TL("Block Size"),
120 _TL(""),
121 256, 32, true
122 );
123
124 Parameters.Add_String("SERVER",
125 "SERVER_USER", _TL("Server"),
126 _TL(""),
127 "tile.openstreetmap.org/${z}/${x}/${y}.png"
128 );
129
130 Parameters.Add_Bool("",
131 "CACHE" , _TL("Cache"),
132 _TL("Enable local disk cache. Allows for offline operation."),
133 false
134 );
135
136 Parameters.Add_FilePath("CACHE",
137 "CACHE_DIR" , _TL("Cache Directory"),
138 _TL("If not specified the cache will be created in the current user's temporary directory."),
139 NULL, NULL, false, true
140 );
141
142 Parameters.Add_Bool("",
143 "GRAYSCALE" , _TL("Gray Scale Image"),
144 _TL(""),
145 false
146 );
147
148 //-----------------------------------------------------
149 Parameters.Add_Node("", "TARGET_NODE", _TL("Target Grid"), _TL(""));
150
151 Parameters.Add_Double("TARGET_NODE", "XMIN", _TL("West" ), _TL(""), -20037508.34, -20037508.34, true, 20037508.34, true);
152 Parameters.Add_Double("TARGET_NODE", "YMIN", _TL("South" ), _TL(""), -20037508.34, -20037508.34, true, 20037508.34, true);
153 Parameters.Add_Double("TARGET_NODE", "XMAX", _TL("East" ), _TL(""), 20037508.34, -20037508.34, true, 20037508.34, true);
154 Parameters.Add_Double("TARGET_NODE", "YMAX", _TL("North" ), _TL(""), 20037508.34, -20037508.34, true, 20037508.34, true);
155 Parameters.Add_Int ("TARGET_NODE", "NX" , _TL("Columns"), _TL(""), 600, 1, true);
156 Parameters.Add_Int ("TARGET_NODE", "NY" , _TL("Rows" ), _TL(""), 600, 1, true);
157 }
158
159
160 ///////////////////////////////////////////////////////////
161 // //
162 ///////////////////////////////////////////////////////////
163
164 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter)165 int CGDAL_Import_WMS::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
166 {
167 CSG_Parameter *pXMin = pParameters->Get_Parameter("XMIN");
168 CSG_Parameter *pYMin = pParameters->Get_Parameter("YMIN");
169 CSG_Parameter *pXMax = pParameters->Get_Parameter("XMAX");
170 CSG_Parameter *pYMax = pParameters->Get_Parameter("YMAX");
171 CSG_Parameter *pNX = pParameters->Get_Parameter("NX" );
172 CSG_Parameter *pNY = pParameters->Get_Parameter("NY" );
173
174 if( pParameter->Cmp_Identifier("NX") )
175 {
176 double d = fabs(pXMax->asDouble() - pXMin->asDouble()) / pNX->asDouble();
177 pNY ->Set_Value(fabs(pYMax->asDouble() - pYMin->asDouble()) / d);
178 pYMax->Set_Value(pYMin->asDouble() + d * pNY->asDouble());
179 }
180
181 if( pParameter->Cmp_Identifier("NY") )
182 {
183 double d = fabs(pYMax->asDouble() - pYMin->asDouble()) / pNY->asDouble();
184 pNX ->Set_Value(fabs(pXMax->asDouble() - pXMin->asDouble()) / d);
185 pXMax->Set_Value(pXMin->asDouble() + d * pNX->asDouble());
186 }
187
188 if( pParameter->Cmp_Identifier("XMIN") )
189 {
190 double d = fabs(pYMax->asDouble() - pYMin->asDouble()) / pNY->asDouble();
191 pNX ->Set_Value(fabs(pXMax->asDouble() - pXMin->asDouble()) / d);
192 pXMax->Set_Value(pXMin->asDouble() + d * pNX->asDouble());
193 }
194
195 if( pParameter->Cmp_Identifier("YMIN") )
196 {
197 double d = fabs(pXMax->asDouble() - pXMin->asDouble()) / pNX->asDouble();
198 pNY ->Set_Value(fabs(pYMax->asDouble() - pYMin->asDouble()) / d);
199 pYMax->Set_Value(pYMin->asDouble() + d * pNY->asDouble());
200 }
201
202 if( pParameter->Cmp_Identifier("XMAX") )
203 {
204 double d = fabs(pYMax->asDouble() - pYMin->asDouble()) / pNY->asDouble();
205 pNX ->Set_Value(fabs(pXMax->asDouble() - pXMin->asDouble()) / d);
206 pYMax->Set_Value(pYMax->asDouble() - d * pNY->asDouble());
207 }
208
209 if( pParameter->Cmp_Identifier("YMAX") )
210 {
211 double d = fabs(pXMax->asDouble() - pXMin->asDouble()) / pNX->asDouble();
212 pNY ->Set_Value(fabs(pYMax->asDouble() - pYMin->asDouble()) / d);
213 pXMax->Set_Value(pXMax->asDouble() - d * pNX->asDouble());
214 }
215
216 return( CSG_Tool::On_Parameter_Changed(pParameters, pParameter) );
217 }
218
219 //---------------------------------------------------------
On_Parameters_Enable(CSG_Parameters * pParameters,CSG_Parameter * pParameter)220 int CGDAL_Import_WMS::On_Parameters_Enable(CSG_Parameters *pParameters, CSG_Parameter *pParameter)
221 {
222 if( pParameter->Cmp_Identifier("TARGET") )
223 {
224 pParameters->Set_Enabled("TARGET_MAP" , pParameter->asPointer() != NULL);
225 pParameters->Set_Enabled("TARGET_NODE", pParameter->asPointer() == NULL);
226 }
227
228 if( pParameter->Cmp_Identifier("SERVER") )
229 {
230 pParameters->Set_Enabled("SERVER_USER", pParameter->asInt() >= pParameter->asChoice()->Get_Count() - 1);
231 }
232
233 if( pParameter->Cmp_Identifier("CACHE") )
234 {
235 pParameters->Set_Enabled("CACHE_DIR", pParameter->asBool());
236 }
237
238 return( CSG_Tool::On_Parameters_Enable(pParameters, pParameter) );
239 }
240
241
242 ///////////////////////////////////////////////////////////
243 // //
244 ///////////////////////////////////////////////////////////
245
246 //---------------------------------------------------------
On_Execute(void)247 bool CGDAL_Import_WMS::On_Execute(void)
248 {
249 //-----------------------------------------------------
250 CSG_Grid_System System;
251
252 if( !Get_System(System, Parameters("TARGET")->asGrid()) )
253 {
254 return( false );
255 }
256
257 //-----------------------------------------------------
258 CSG_Grid *pBands[3];
259
260 if( !Get_Bands(pBands, System) )
261 {
262 Error_Set(_TL("failed to retrieve map image data"));
263
264 return( false );
265 }
266
267 //-----------------------------------------------------
268 if( Parameters("TARGET")->asGrid() )
269 {
270 Get_Projected(pBands, Parameters("TARGET")->asGrid());
271 }
272
273 //-----------------------------------------------------
274 return( Set_Image(pBands) );
275 }
276
277
278 ///////////////////////////////////////////////////////////
279 // //
280 ///////////////////////////////////////////////////////////
281
282 //---------------------------------------------------------
Get_System(CSG_Grid_System & System,CSG_Grid * pTarget)283 bool CGDAL_Import_WMS::Get_System(CSG_Grid_System &System, CSG_Grid *pTarget)
284 {
285 //-----------------------------------------------------
286 if( !pTarget )
287 {
288 CSG_Rect Extent(
289 Parameters("XMIN")->asDouble(), Parameters("YMIN")->asDouble(),
290 Parameters("XMAX")->asDouble(), Parameters("YMAX")->asDouble()
291 );
292
293 double Cellsize = Extent.Get_XRange() / Parameters("NX")->asDouble();
294
295 return( System.Assign(Cellsize, Extent) );
296 }
297
298 //-----------------------------------------------------
299 if( !pTarget->Get_Projection().is_Okay() )
300 {
301 return( false );
302 }
303
304 CSG_Shapes rTarget(SHAPE_TYPE_Point), rSource;
305
306 rTarget.Get_Projection() = pTarget->Get_Projection();
307
308 CSG_Rect Extent = pTarget->Get_Extent(true);
309
310 rTarget.Add_Shape()->Add_Point(Extent.Get_XMin (), Extent.Get_YMin ());
311 rTarget.Add_Shape()->Add_Point(Extent.Get_XMin (), Extent.Get_YCenter());
312 rTarget.Add_Shape()->Add_Point(Extent.Get_XMin (), Extent.Get_YMax ());
313 rTarget.Add_Shape()->Add_Point(Extent.Get_XCenter(), Extent.Get_YMax ());
314 rTarget.Add_Shape()->Add_Point(Extent.Get_XMax (), Extent.Get_YMax ());
315 rTarget.Add_Shape()->Add_Point(Extent.Get_XMax (), Extent.Get_YCenter());
316 rTarget.Add_Shape()->Add_Point(Extent.Get_XMax (), Extent.Get_YMin ());
317 rTarget.Add_Shape()->Add_Point(Extent.Get_XCenter(), Extent.Get_YMin ());
318
319 //-----------------------------------------------------
320 CSG_Tool *pTool = SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 2); // Coordinate Transformation (Shapes);
321
322 if( !pTool )
323 {
324 return( false );
325 }
326
327 pTool->Set_Manager(NULL);
328
329 if( SG_TOOL_PARAMETER_SET("CRS_PROJ4", SG_T("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +k=1.0"))
330 && SG_TOOL_PARAMETER_SET("SOURCE" , &rTarget)
331 && SG_TOOL_PARAMETER_SET("TARGET" , &rSource)
332 && pTool->Execute() )
333 {
334 Extent = rSource.Get_Extent();
335
336 double Cellsize = Extent.Get_XRange() / pTarget->Get_NX() < Extent.Get_YRange() / pTarget->Get_NY()
337 ? Extent.Get_XRange() / pTarget->Get_NX() : Extent.Get_YRange() / pTarget->Get_NY();
338
339 System.Assign(Cellsize, Extent);
340
341 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
342
343 return( true );
344 }
345
346 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
347
348 return( false );
349 }
350
351
352 ///////////////////////////////////////////////////////////
353 // //
354 ///////////////////////////////////////////////////////////
355
356 //---------------------------------------------------------
Get_Projected(CSG_Grid * pBands[3],CSG_Grid * pTarget)357 bool CGDAL_Import_WMS::Get_Projected(CSG_Grid *pBands[3], CSG_Grid *pTarget)
358 {
359 CSG_Tool *pTool = SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 3); // Coordinate Transformation (Grid List);
360
361 if( !pTool )
362 {
363 return( false );
364 }
365
366 //-----------------------------------------------------
367 pTool->Set_Manager(NULL);
368
369 if( SG_TOOL_PARAMETER_SET("CRS_PROJ4" , pTarget->Get_Projection().Get_Proj4())
370 && SG_TOOL_PARAMETER_SET("RESAMPLING" , 3)
371 && SG_TOOL_PARAMETER_SET("KEEP_TYPE" , true)
372 && SG_TOOL_PARAMLIST_ADD("SOURCE" , pBands[0])
373 && SG_TOOL_PARAMLIST_ADD("SOURCE" , pBands[1])
374 && SG_TOOL_PARAMLIST_ADD("SOURCE" , pBands[2])
375 && SG_TOOL_PARAMETER_SET("TARGET_DEFINITION", 1)
376 && SG_TOOL_PARAMETER_SET("TARGET_SYSTEM" , (void *)&pTarget->Get_System())
377 && pTool->Execute() )
378 {
379 CSG_Parameter_Grid_List *pGrids = pTool->Get_Parameters()->Get_Parameter("GRIDS")->asGridList();
380
381 delete(pBands[0]); pBands[0] = pGrids->Get_Grid(0);
382 delete(pBands[1]); pBands[1] = pGrids->Get_Grid(1);
383 delete(pBands[2]); pBands[2] = pGrids->Get_Grid(2);
384
385 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
386
387 return( true );
388 }
389
390 SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
391
392 return( false );
393 }
394
395
396 ///////////////////////////////////////////////////////////
397 // //
398 ///////////////////////////////////////////////////////////
399
400 //---------------------------------------------------------
Set_Image(CSG_Grid * pBands[3])401 bool CGDAL_Import_WMS::Set_Image(CSG_Grid *pBands[3])
402 {
403 //-----------------------------------------------------
404 CSG_Grid *pMap = Parameters("TARGET_MAP")->asGrid();
405
406 if( !pMap )
407 {
408 pMap = SG_Create_Grid();
409 }
410
411 if( !pMap->Get_System().is_Equal(pBands[0]->Get_System()) )
412 {
413 pMap->Create(pBands[0]->Get_System(), SG_DATATYPE_Int);
414 }
415
416 pMap->Set_Name(_TL("Open Street Map"));
417
418 pMap->Get_Projection() = pBands[0]->Get_Projection();
419
420 //-----------------------------------------------------
421 bool bGrayscale = Parameters("GRAYSCALE")->asBool();
422
423 #pragma omp parallel for
424 for(int y=0; y<pMap->Get_NY(); y++) for(int x=0; x<pMap->Get_NX(); x++)
425 {
426 if( bGrayscale )
427 {
428 double z = (pBands[0]->asInt(x, y) + pBands[1]->asInt(x, y) + pBands[2]->asInt(x, y)) / 3.0;
429
430 pMap->Set_Value(x, y, SG_GET_RGB(z, z, z));
431 }
432 else
433 {
434 pMap->Set_Value(x, y, SG_GET_RGB(pBands[0]->asInt(x, y), pBands[1]->asInt(x, y), pBands[2]->asInt(x, y)));
435 }
436 }
437
438 delete(pBands[0]);
439 delete(pBands[1]);
440 delete(pBands[2]);
441
442 Parameters("MAP")->Set_Value(pMap);
443
444 DataObject_Add(pMap);
445 DataObject_Set_Parameter(pMap, "COLORS_TYPE", 5); // Color Classification Type: RGB Coded Values
446
447 return( true );
448 }
449
450
451 ///////////////////////////////////////////////////////////
452 // //
453 ///////////////////////////////////////////////////////////
454
455 //---------------------------------------------------------
Get_Bands(CSG_Grid * pBands[3],const CSG_Grid_System & System)456 bool CGDAL_Import_WMS::Get_Bands(CSG_Grid *pBands[3], const CSG_Grid_System &System)
457 {
458 //-----------------------------------------------------
459 CSG_GDAL_DataSet DataSet;
460
461 if( DataSet.Open_Read(Get_Request(), System) == false || DataSet.Get_Count() != 3 )
462 {
463 return( false );
464 }
465
466 Message_Add("\n", false);
467 Message_Fmt("\n%s: %s", _TL("Driver" ), DataSet.Get_DriverID().c_str());
468 Message_Fmt("\n%s: %d", _TL("Bands" ), DataSet.Get_Count() );
469 Message_Fmt("\n%s: %d", _TL("Rows" ), DataSet.Get_NX() );
470 Message_Fmt("\n%s: %d", _TL("Columns"), DataSet.Get_NY() );
471 Message_Add("\n", false);
472
473 //-----------------------------------------------------
474 SG_UI_Progress_Lock(true);
475
476 pBands[0] = DataSet.Read(0);
477 pBands[1] = DataSet.Read(1);
478 pBands[2] = DataSet.Read(2);
479
480 SG_UI_Progress_Lock(false);
481
482 //-----------------------------------------------------
483 if( !pBands[0] || !pBands[1] || !pBands[2] )
484 {
485 if( pBands[0] ) delete(pBands[0]);
486 if( pBands[1] ) delete(pBands[1]);
487 if( pBands[2] ) delete(pBands[2]);
488
489 return( false );
490 }
491
492 return( true );
493 }
494
495
496 ///////////////////////////////////////////////////////////
497 // //
498 ///////////////////////////////////////////////////////////
499
500 //---------------------------------------------------------
Get_Request(void)501 CSG_String CGDAL_Import_WMS::Get_Request(void)
502 {
503 CSG_String Server, Projection = "EPSG:3857";
504
505 switch( Parameters("SERVER")->asInt() )
506 {
507 default: Server = "tile.openstreetmap.org/${z}/${x}/${y}.png" ; break; // Open Street Map
508 case 1: Server = "mt.google.com/vt/lyrs=m&x=${x}&y=${y}&z=${z}" ; break; // Google Map
509 case 2: Server = "mt.google.com/vt/lyrs=s&x=${x}&y=${y}&z=${z}" ; break; // Google Satellite
510 case 3: Server = "mt.google.com/vt/lyrs=y&x=${x}&y=${y}&z=${z}" ; break; // Google Hybrid
511 case 4: Server = "mt.google.com/vt/lyrs=t&x=${x}&y=${y}&z=${z}" ; break; // Google Terrain
512 case 5: Server = "mt.google.com/vt/lyrs=p&x=${x}&y=${y}&z=${z}" ; break; // Google Terrain, Streets and Water
513 case 6: Server = "services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/${z}/${y}/${x}" ; break; // ArcGIS MapServer Tiles
514 case 7: Server = "sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/web/default/WEBMERCATOR/${z}/${y}/${x}.png"; break; // TopPlusOpen
515 case 8: Server = Parameters("SERVER_USER")->asString() ; break; // user defined
516 // case x: Server = "s3.amazonaws.com/com.modestmaps.bluemarble/${z}-r${y}-c${x}.jpg" ; break; // Blue Marble
517 }
518
519 //-----------------------------------------------------
520 CSG_MetaData XML, *pEntry;
521
522 XML.Set_Name("GDAL_WMS");
523
524 //-----------------------------------------------------
525 pEntry = XML.Add_Child("Service"); pEntry->Add_Property("name", "TMS");
526
527 pEntry->Add_Child("ServerUrl" , "http://" + Server);
528
529 //-----------------------------------------------------
530 pEntry = XML.Add_Child("DataWindow"); // Define size and extents of the data. (required, except for TiledWMS and VirtualEarth)
531
532 pEntry->Add_Child("UpperLeftX" , -20037508.34); // X (longitude) coordinate of upper-left corner. (optional, defaults to -180.0, except for VirtualEarth)
533 pEntry->Add_Child("UpperLeftY" , 20037508.34); // Y (latitude) coordinate of upper-left corner. (optional, defaults to 90.0, except for VirtualEarth)
534 pEntry->Add_Child("LowerRightX", 20037508.34); // X (longitude) coordinate of lower-right corner. (optional, defaults to 180.0, except for VirtualEarth)
535 pEntry->Add_Child("LowerRightY", -20037508.34); // Y (latitude) coordinate of lower-right corner. (optional, defaults to -90.0, except for VirtualEarth)
536 pEntry->Add_Child("TileLevel" , 18); // Tile level at highest resolution. (tiled image sources only, optional, defaults to 0)
537 pEntry->Add_Child("TileCountX" , 1); // Can be used to define image size, SizeX = TileCountX * BlockSizeX * 2TileLevel. (tiled image sources only, optional, defaults to 0)
538 pEntry->Add_Child("TileCountY" , 1); // Can be used to define image size, SizeY = TileCountY * BlockSizeY * 2TileLevel. (tiled image sources only, optional, defaults to 0)
539 pEntry->Add_Child("YOrigin" , "top"); // Can be used to define the position of the Y origin with respect to the tile grid. Possible values are 'top', 'bottom', and 'default', where the default behavior is mini-driver-specific. (TMS mini-driver only, optional, defaults to 'bottom' for TMS)
540
541 //-----------------------------------------------------
542 if( !Projection.is_Empty() )
543 {
544 pEntry = XML.Add_Child("Projection", Projection); // Image projection (optional, defaults to value reported by mini-driver or EPSG:4326)
545 }
546
547 pEntry = XML.Add_Child("BandsCount", 3); // Number of bands/channels, 1 for grayscale data, 3 for RGB, 4 for RGBA. (optional, defaults to 3)
548
549 int Blocksize = Parameters("BLOCKSIZE")->asInt();
550 pEntry = XML.Add_Child("BlockSizeX", Blocksize); // Block size in pixels. (optional, defaults to 1024, except for VirtualEarth)
551 pEntry = XML.Add_Child("BlockSizeY", Blocksize);
552
553 //-----------------------------------------------------
554 if( Parameters("CACHE")->asBool() )
555 {
556 pEntry = XML.Add_Child("Cache");
557
558 CSG_String Path = Parameters("CACHE_DIR")->asString();
559
560 if( !SG_Dir_Exists(Path) )
561 {
562 Path = SG_Dir_Get_Temp();
563 }
564
565 pEntry->Add_Child("Path", SG_File_Make_Path(Path, SG_T("gdalwmscache")));
566 }
567
568 //-----------------------------------------------------
569 return( XML.asText(2) );
570 }
571
572
573 ///////////////////////////////////////////////////////////
574 // //
575 // //
576 // //
577 ///////////////////////////////////////////////////////////
578
579 //---------------------------------------------------------
580